Tizen 2.0 Release 2.0_release
authorHyungKyu Song <hk76.song@samsung.com>
Thu, 14 Feb 2013 13:08:02 +0000 (22:08 +0900)
committerHyungKyu Song <hk76.song@samsung.com>
Thu, 14 Feb 2013 13:08:02 +0000 (22:08 +0900)
1533 files changed:
CODING_STYLE
Changelog
HACKING
MAINTAINERS
Makefile
Makefile.hw
Makefile.objs
Makefile.target [changed mode: 0644->0755]
Makefile.user
QMP/qmp-shell [changed mode: 0644->0755]
QMP/qmp.py
VERSION
a.out.h
acl.c
aio.c
alpha-dis.c
arch_init.c
arch_init.h
arm-semi.c
arm.ld
async.c
audio/alsaaudio.c
audio/audio.c
audio/audio_pt_int.c
audio/audio_template.h
audio/coreaudio.c
audio/esdaudio.c
audio/fmodaudio.c
audio/mixeng.c
audio/mixeng_template.h
audio/noaudio.c
audio/ossaudio.c
audio/paaudio.c
audio/sdlaudio.c
audio/spiceaudio.c
audio/wavaudio.c
audio/wavcapture.c
audio/winwaveaudio.c
balloon.c
balloon.h
bitmap.c [new file with mode: 0644]
bitmap.h [new file with mode: 0644]
bitops.c [new file with mode: 0644]
bitops.h [new file with mode: 0644]
block-migration.c
block.c
block.h
block/blkdebug.c
block/blkverify.c
block/bochs.c
block/cloop.c
block/cow.c
block/curl.c
block/dmg.c
block/iscsi.c [new file with mode: 0644]
block/nbd.c
block/parallels.c
block/qcow.c
block/qcow2-cache.c
block/qcow2-cluster.c
block/qcow2-refcount.c
block/qcow2-snapshot.c
block/qcow2.c
block/qcow2.h
block/qed-check.c
block/qed-cluster.c
block/qed-gencb.c
block/qed-l2-cache.c
block/qed-table.c
block/qed.c
block/qed.h
block/raw-posix.c
block/raw-win32.c
block/raw.c
block/rbd.c
block/sheepdog.c
block/vdi.c
block/vmdk.c
block/vpc.c
block/vvfat.c
block_int.h
blockdev.c
blockdev.h
bsd-user/main.c
bsd-user/mmap.c
bsd-user/qemu.h
bsd-user/syscall.c
bswap.h
bt-host.c
bt-vhci.c
buffered_file.c
check-qdict.c
check-qfloat.c
check-qint.c
check-qjson.c
check-qlist.c
check-qstring.c
cmd.c
compatfd.c
compatfd.h
compiler.h [new file with mode: 0644]
config.h
configure
console.c
console.h
coroutine-gthread.c [new file with mode: 0644]
coroutine-ucontext.c [new file with mode: 0644]
coroutine-win32.c [new file with mode: 0644]
cpu-all.h
cpu-common.h
cpu-defs.h
cpu-exec.c
cpus.c
cpus.h
cris-dis.c
cursor.c
cutils.c
darwin-user/commpage.c
darwin-user/machload.c
darwin-user/main.c
darwin-user/signal.c
darwin-user/syscall.c
default-configs/alpha-softmmu.mak [new file with mode: 0644]
default-configs/i386-softmmu.mak
default-configs/lm32-softmmu.mak [new file with mode: 0644]
default-configs/microblaze-softmmu.mak
default-configs/microblazeel-linux-user.mak [new file with mode: 0644]
default-configs/microblazeel-softmmu.mak [new file with mode: 0644]
default-configs/mips-softmmu.mak
default-configs/mips64-softmmu.mak
default-configs/mips64el-softmmu.mak
default-configs/mipsel-softmmu.mak
default-configs/pci.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/s390x-linux-user.mak [new file with mode: 0644]
default-configs/unicore32-linux-user.mak [new file with mode: 0644]
default-configs/x86_64-softmmu.mak
default-configs/xtensa-softmmu.mak [new file with mode: 0644]
default-configs/xtensaeb-softmmu.mak [new file with mode: 0644]
device_tree.c
device_tree.h
dis-asm.h
disas.c
dma-helpers.c
dma.h
docs/ccid.txt [new file with mode: 0644]
docs/ich9-ehci-uhci.cfg [new file with mode: 0644]
docs/libcacard.txt [new file with mode: 0644]
docs/memory.txt [new file with mode: 0644]
docs/qapi-code-gen.txt [new file with mode: 0644]
docs/qdev-device-use.txt
docs/specs/qcow2.txt [new file with mode: 0644]
docs/specs/qed_spec.txt
docs/tracing.txt
docs/usb2.txt [new file with mode: 0644]
dyngen-exec.h
elf.h
error.c [new file with mode: 0644]
error.h [new file with mode: 0644]
error_int.h [new file with mode: 0644]
event_notifier.c [new file with mode: 0644]
event_notifier.h [new file with mode: 0644]
exec-all.h
exec-memory.h [new file with mode: 0644]
exec.c
fpu/softfloat-macros.h
fpu/softfloat-specialize.h
fpu/softfloat.c
fpu/softfloat.h
fsdev/file-op-9p.h [new file with mode: 0644]
fsdev/qemu-fsdev-dummy.c [new file with mode: 0644]
fsdev/qemu-fsdev.c
fsdev/qemu-fsdev.h
gdbstub.c
gen-icount.h
hax.h [new file with mode: 0644]
hmp-commands.hx
hmp.c [new file with mode: 0644]
hmp.h [new file with mode: 0644]
host-utils.h
hppa-dis.c
hppa.ld
hw/9pfs/codir.c [new file with mode: 0644]
hw/9pfs/cofile.c [new file with mode: 0644]
hw/9pfs/cofs.c [new file with mode: 0644]
hw/9pfs/coxattr.c [new file with mode: 0644]
hw/9pfs/virtio-9p-coth.c [new file with mode: 0644]
hw/9pfs/virtio-9p-coth.h [new file with mode: 0644]
hw/9pfs/virtio-9p-device.c [new file with mode: 0644]
hw/9pfs/virtio-9p-handle.c [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-synth.c [new file with mode: 0644]
hw/9pfs/virtio-9p-synth.h [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/a9mpcore.c
hw/ac97.c
hw/acpi.c
hw/acpi.h
hw/acpi_piix4.c
hw/adb.c
hw/adb.h [new file with mode: 0644]
hw/adlib.c
hw/ads7846.c
hw/alpha_dp264.c [new file with mode: 0644]
hw/alpha_pci.c [new file with mode: 0644]
hw/alpha_sys.h [new file with mode: 0644]
hw/alpha_typhoon.c [new file with mode: 0644]
hw/an5206.c
hw/apb_pci.c
hw/apic.c
hw/apic.h
hw/applesmc.c
hw/arm-misc.h
hw/arm11mpcore.c
hw/arm_boot.c
hw/arm_gic.c
hw/arm_pic.c
hw/arm_sysctl.c
hw/arm_timer.c
hw/armv7m.c
hw/armv7m_nvic.c
hw/audiodev.h
hw/axis_dev88.c
hw/baum.c
hw/baum.h
hw/bitbang_i2c.c
hw/blizzard.c
hw/boards.h
hw/bonito.c
hw/bt-hci-csr.c
hw/bt-hci.c
hw/bt-hid.c
hw/bt-l2cap.c
hw/bt-sdp.c
hw/bt.c
hw/bt.h
hw/cbus.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/cirrus_vga.c
hw/collie.c [new file with mode: 0644]
hw/cris-boot.c
hw/cris_pic_cpu.c
hw/cs4231a.c
hw/cuda.c
hw/debugcon.c
hw/dec_pci.c
hw/devices.h
hw/dma.c
hw/dp8393x.c
hw/ds1225y.c
hw/ds1338.c
hw/dummy_m68k.c
hw/e1000.c
hw/e1000_hw.h
hw/eepro100.c
hw/eeprom93xx.c
hw/elf_ops.h
hw/empty_slot.c
hw/es1370.c
hw/escc.c
hw/escc.h
hw/esp.c
hw/etraxfs.h
hw/etraxfs_dma.c
hw/etraxfs_eth.c
hw/etraxfs_pic.c
hw/etraxfs_ser.c
hw/etraxfs_timer.c
hw/fdc.c
hw/fdc.h
hw/flash.h
hw/fmopl.c
hw/framebuffer.c
hw/fw_cfg.c
hw/g364fb.c
hw/grackle_pci.c
hw/grlib_apbuart.c
hw/grlib_gptimer.c
hw/grlib_irqmp.c
hw/gt64xxx.c
hw/gumstix.c
hw/gus.c
hw/hda-audio.c
hw/heathrow_pic.c
hw/hid.c [new file with mode: 0644]
hw/hid.h [new file with mode: 0644]
hw/hpet.c
hw/hpet_emul.h
hw/hw.h
hw/i2c.c
hw/i2c.h
hw/i8254.c
hw/i8259.c
hw/ide.h
hw/ide/ahci.c
hw/ide/ahci.h
hw/ide/atapi.c [new file with mode: 0644]
hw/ide/cmd646.c
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/ide/pci.h
hw/ide/piix.c
hw/ide/qdev.c
hw/ide/via.c
hw/integratorcp.c
hw/intel-hda.c
hw/intel-hda.h
hw/ioapic.c
hw/ioapic.h
hw/ioh3420.c
hw/irq.c
hw/irq.h
hw/isa-bus.c
hw/isa.h
hw/isa_mmio.c
hw/ivshmem.c
hw/jazz_led.c
hw/kvmclock.c [new file with mode: 0644]
hw/kvmclock.h [new file with mode: 0644]
hw/lan9118.c
hw/lance.c
hw/leon3.c
hw/lm32.h [new file with mode: 0644]
hw/lm32_boards.c [new file with mode: 0644]
hw/lm32_hwsetup.h [new file with mode: 0644]
hw/lm32_juart.c [new file with mode: 0644]
hw/lm32_juart.h [new file with mode: 0644]
hw/lm32_pic.c [new file with mode: 0644]
hw/lm32_pic.h [new file with mode: 0644]
hw/lm32_sys.c [new file with mode: 0644]
hw/lm32_timer.c [new file with mode: 0644]
hw/lm32_uart.c [new file with mode: 0644]
hw/lm4549.c [new file with mode: 0644]
hw/lm4549.h [new file with mode: 0644]
hw/lm832x.c
hw/loader.c
hw/loader.h
hw/lsi53c895a.c
hw/m48t59.c
hw/mac_dbdma.c
hw/mac_dbdma.h
hw/mac_nvram.c
hw/macio.c
hw/mainstone.c
hw/marvell_88w8618_audio.c
hw/max111x.c
hw/max7310.c
hw/mc146818rtc.c
hw/mcf5206.c
hw/mcf5208.c
hw/mcf_fec.c
hw/mcf_intc.c
hw/mcf_uart.c
hw/microblaze_pic_cpu.c
hw/microblaze_pic_cpu.h [new file with mode: 0644]
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.h
hw/mips_fulong2e.c
hw/mips_jazz.c
hw/mips_malta.c
hw/mips_mipssim.c
hw/mips_r4k.c
hw/mips_timer.c
hw/mipsnet.c
hw/mpc8544_guts.c [new file with mode: 0644]
hw/mpcore.c
hw/msi.c
hw/msix.c
hw/msix.h
hw/msmouse.c
hw/msmouse.h
hw/mst_fpga.c
hw/multiboot.c
hw/musicpal.c
hw/nand.c
hw/ne2000-isa.c
hw/ne2000.c
hw/ne2000.h
hw/nseries.c
hw/omap.h
hw/omap1.c
hw/omap2.c
hw/omap_clk.c
hw/omap_dma.c
hw/omap_dss.c
hw/omap_gpio.c
hw/omap_gpmc.c
hw/omap_gptimer.c
hw/omap_i2c.c
hw/omap_intc.c
hw/omap_l4.c
hw/omap_lcdc.c
hw/omap_mmc.c
hw/omap_sdrc.c
hw/omap_spi.c
hw/omap_sx1.c
hw/omap_synctimer.c
hw/omap_uart.c
hw/onenand.c
hw/opencores_eth.c [new file with mode: 0644]
hw/openpic.c
hw/openpic.h
hw/palm.c
hw/parallel.c
hw/pc.c
hw/pc.h [changed mode: 0755->0644]
hw/pc_piix.c
hw/pci-hotplug.c
hw/pci-stub.c
hw/pci.c
hw/pci.h
hw/pci_bridge.c
hw/pci_host.c
hw/pci_host.h
hw/pci_ids.h
hw/pci_internals.h
hw/pci_regs.h
hw/pcie.c
hw/pcie.h
hw/pcie_aer.c
hw/pcie_host.c
hw/pcie_host.h
hw/pcie_port.c
hw/pckbd.c
hw/pcnet-pci.c
hw/pcnet.c
hw/pcnet.h
hw/pcspk.c
hw/petalogix_ml605_mmu.c [new file with mode: 0644]
hw/petalogix_s3adsp1800_mmu.c
hw/pflash_cfi01.c
hw/pflash_cfi02.c
hw/piix4.c
hw/piix_pci.c
hw/pl011.c
hw/pl022.c
hw/pl031.c
hw/pl041.c [new file with mode: 0644]
hw/pl041.h [new file with mode: 0644]
hw/pl041.hx [new file with mode: 0644]
hw/pl050.c
hw/pl061.c
hw/pl080.c
hw/pl110.c
hw/pl110_template.h
hw/pl181.c
hw/pl190.c
hw/ppc-viosrp.h [new file with mode: 0644]
hw/ppc.c
hw/ppc.h
hw/ppc405.h
hw/ppc405_boards.c
hw/ppc405_uc.c
hw/ppc440.c
hw/ppc440.h
hw/ppc440_bamboo.c
hw/ppc4xx.h
hw/ppc4xx_devs.c
hw/ppc4xx_pci.c
hw/ppc_booke.c [new file with mode: 0644]
hw/ppc_mac.h
hw/ppc_newworld.c
hw/ppc_oldworld.c
hw/ppc_prep.c
hw/ppce500_mpc8544ds.c
hw/ppce500_pci.c
hw/ppce500_spin.c [new file with mode: 0644]
hw/prep_pci.c
hw/prep_pci.h
hw/primecell.h
hw/ps2.c
hw/ptimer.c
hw/pxa.h
hw/pxa2xx.c
hw/pxa2xx_dma.c
hw/pxa2xx_gpio.c
hw/pxa2xx_keypad.c
hw/pxa2xx_lcd.c
hw/pxa2xx_mmci.c
hw/pxa2xx_pcmcia.c
hw/pxa2xx_pic.c
hw/pxa2xx_timer.c
hw/qdev-properties.c
hw/qdev.c
hw/qdev.h
hw/qxl-logger.c
hw/qxl-render.c
hw/qxl.c
hw/qxl.h
hw/r2d.c
hw/rc4030.c
hw/realview.c
hw/realview_gic.c
hw/rtl8139.c
hw/s390-virtio-bus.c
hw/s390-virtio-bus.h
hw/s390-virtio.c
hw/sb16.c
hw/scsi-bus.c
hw/scsi-defs.h
hw/scsi-disk.c
hw/scsi-generic.c
hw/scsi.h
hw/sd.c
hw/serial.c
hw/sga.c [new file with mode: 0644]
hw/sh7750.c
hw/sh7750_regs.h
hw/sh_intc.c
hw/sh_pci.c
hw/sh_serial.c
hw/sh_timer.c
hw/shix.c
hw/slavio_intctl.c
hw/slavio_misc.c
hw/slavio_timer.c
hw/sm501.c
hw/sm501_template.h
hw/smbios.c
hw/smbios.h
hw/smbus.c
hw/smbus.h
hw/smbus_eeprom.c
hw/smc91c111.c
hw/soc_dma.c
hw/soc_dma.h
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_pci.c [new file with mode: 0644]
hw/spapr_pci.h [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/spitz.c
hw/srp.h [new file with mode: 0644]
hw/ssd0303.c
hw/ssd0323.c
hw/ssi-sd.c
hw/ssi.c
hw/stellaris.c
hw/stellaris_enet.c
hw/stellaris_input.c
hw/strongarm.c [new file with mode: 0644]
hw/strongarm.h [new file with mode: 0644]
hw/sun4m.c
hw/sun4m.h
hw/sun4m_iommu.c
hw/sun4u.c
hw/syborg.c
hw/syborg_fb.c
hw/syborg_interrupt.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/sysbus.h
hw/tc58128.c
hw/tc6393xb.c
hw/tcx.c
hw/tosa.c
hw/tsc2005.c
hw/tsc210x.c
hw/tusb6010.c
hw/twl92230.c
hw/unin_pci.c
hw/usb-bt.c
hw/usb-bus.c
hw/usb-ccid.c [new file with mode: 0644]
hw/usb-desc.c
hw/usb-desc.h
hw/usb-ehci.c
hw/usb-hid.c
hw/usb-hub.c
hw/usb-libhw.c [new file with mode: 0644]
hw/usb-msd.c
hw/usb-musb.c
hw/usb-net.c
hw/usb-ohci.c
hw/usb-serial.c
hw/usb-uhci.c
hw/usb-wacom.c
hw/usb.c
hw/usb.h
hw/versatile_pci.c
hw/versatilepb.c
hw/vexpress.c [new file with mode: 0644]
hw/vga-isa-mm.c
hw/vga-isa.c
hw/vga-pci.c
hw/vga.c [changed mode: 0755->0644]
hw/vga_int.h
hw/vhost.c
hw/vhost.h
hw/vhost_net.c
hw/virtex_ml507.c
hw/virtio-balloon.c
hw/virtio-balloon.h
hw/virtio-blk.c
hw/virtio-blk.h
hw/virtio-console.c
hw/virtio-net.c
hw/virtio-net.h
hw/virtio-pci.c
hw/virtio-pci.h [new file with mode: 0644]
hw/virtio-serial-bus.c
hw/virtio-serial.h
hw/virtio.c
hw/virtio.h
hw/vmmouse.c
hw/vmport.c
hw/vmware_vga.c
hw/vmware_vga.h
hw/vt82c686.c
hw/watchdog.c
hw/wdt_i6300esb.c
hw/wdt_ib700.c
hw/wm8750.c
hw/xen.h
hw/xen_backend.c
hw/xen_backend.h
hw/xen_common.h
hw/xen_console.c
hw/xen_devconfig.c
hw/xen_disk.c
hw/xen_domainbuild.c
hw/xen_machine_pv.c
hw/xen_nic.c
hw/xen_platform.c [new file with mode: 0644]
hw/xenfb.c
hw/xics.c [new file with mode: 0644]
hw/xics.h [new file with mode: 0644]
hw/xilinx.h
hw/xilinx_axidma.c [new file with mode: 0644]
hw/xilinx_axidma.h [new file with mode: 0644]
hw/xilinx_axienet.c [new file with mode: 0644]
hw/xilinx_ethlite.c
hw/xilinx_intc.c
hw/xilinx_timer.c
hw/xilinx_uartlite.c
hw/xio3130_downstream.c
hw/xio3130_upstream.c
hw/xtensa_bootparam.h [new file with mode: 0644]
hw/xtensa_lx60.c [new file with mode: 0644]
hw/xtensa_pic.c [new file with mode: 0644]
hw/xtensa_sim.c [new file with mode: 0644]
hw/z2.c [new file with mode: 0644]
hw/zaurus.c
i386.ld
ia64-dis.c
input.c
int128.h [new file with mode: 0644]
iohandler.c [new file with mode: 0644]
ioport.c
ioport.h
iov.c
iov.h
json-lexer.c
json-lexer.h
json-parser.c
json-parser.h
json-streamer.c
json-streamer.h
kvm-all.c
kvm-stub.c
kvm.h
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/libcacard.pc.in [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]
libfdt_env.h
linux-aio.c
linux-headers/COPYING [new file with mode: 0644]
linux-headers/README [new file with mode: 0644]
linux-headers/asm-powerpc/kvm.h [new file with mode: 0644]
linux-headers/asm-powerpc/kvm_para.h [new file with mode: 0644]
linux-headers/asm-s390/kvm.h [new file with mode: 0644]
linux-headers/asm-s390/kvm_para.h [new file with mode: 0644]
linux-headers/asm-x86/hyperv.h [new file with mode: 0644]
linux-headers/asm-x86/kvm.h [new file with mode: 0644]
linux-headers/asm-x86/kvm_para.h [new file with mode: 0644]
linux-headers/linux/kvm.h [new file with mode: 0644]
linux-headers/linux/kvm_para.h [new file with mode: 0644]
linux-headers/linux/vhost.h [new file with mode: 0644]
linux-headers/linux/virtio_config.h [new file with mode: 0644]
linux-headers/linux/virtio_ring.h [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/arm/nwfpe/fpopcode.c
linux-user/arm/syscall_nr.h
linux-user/cris/syscall_nr.h
linux-user/elfload.c
linux-user/flatload.c
linux-user/i386/syscall_nr.h
linux-user/ioctls.h
linux-user/linuxload.c
linux-user/m68k/syscall_nr.h
linux-user/main.c
linux-user/microblaze/syscall_nr.h
linux-user/mips/syscall_nr.h
linux-user/mips64/syscall_nr.h
linux-user/mipsn32/syscall_nr.h
linux-user/mmap.c
linux-user/ppc/syscall_nr.h
linux-user/qemu-types.h
linux-user/qemu.h
linux-user/s390x/syscall.h [new file with mode: 0644]
linux-user/s390x/syscall_nr.h [new file with mode: 0644]
linux-user/s390x/target_signal.h [new file with mode: 0644]
linux-user/s390x/termbits.h [new file with mode: 0644]
linux-user/sh4/syscall_nr.h
linux-user/signal.c
linux-user/sparc/syscall_nr.h
linux-user/sparc64/syscall_nr.h
linux-user/strace.c
linux-user/strace.list
linux-user/syscall.c
linux-user/syscall_defs.h
linux-user/syscall_types.h
linux-user/target_flat.h [new file with mode: 0644]
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]
linux-user/vm86.c
linux-user/x86_64/syscall_nr.h
m68k-semi.c
main-loop.c [new file with mode: 0644]
main-loop.h [new file with mode: 0644]
memory.c [new file with mode: 0644]
memory.h [new file with mode: 0644]
migration-exec.c
migration-fd.c
migration-tcp.c
migration-unix.c
migration.c
migration.h
mips-dis.c
mips.ld
module.c
module.h
monitor.c
monitor.h
nbd.c
nbd.h
net.c
net.h
net/dump.c
net/queue.c
net/slirp.c
net/socket.c
net/tap-bsd.c
net/tap-linux.c
net/tap-win32.c
net/tap.c
net/vde.c
new_emulator_project [new file with mode: 0644]
notify.c
notify.h
os-posix.c
os-win32.c
osdep.c
osdep.h
oslib-posix.c
oslib-win32.c
package/build.linux
package/build.windows
package/pkginfo.manifest
path.c
pc-bios/README
pc-bios/bios.bin
pc-bios/linuxboot.bin [changed mode: 0755->0644]
pc-bios/mpc8544ds.dtb
pc-bios/mpc8544ds.dts
pc-bios/multiboot.bin
pc-bios/openbios-ppc
pc-bios/openbios-sparc32
pc-bios/openbios-sparc64
pc-bios/optionrom/multiboot.S
pc-bios/optionrom/optionrom.h
pc-bios/palcode-clipper [new file with mode: 0755]
pc-bios/petalogix-ml605.dtb [new file with mode: 0644]
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.rom [new file with mode: 0644]
pc-bios/pxe-pcnet.rom [new file with mode: 0644]
pc-bios/pxe-rtl8139.rom [new file with mode: 0644]
pc-bios/pxe-virtio.rom [new file with mode: 0644]
pc-bios/s390-zipl.rom
pc-bios/sgabios.bin [new file with mode: 0755]
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]
pc-bios/vgabios-maruvga.bin [new file with mode: 0644]
pflib.c
poison.h
posix-aio-compat.c
ppc.ld
ppc64.ld
qapi-schema-guest.json [new file with mode: 0644]
qapi-schema-test.json [new file with mode: 0644]
qapi-schema.json [new file with mode: 0644]
qapi/qapi-dealloc-visitor.c [new file with mode: 0644]
qapi/qapi-dealloc-visitor.h [new file with mode: 0644]
qapi/qapi-types-core.h [new file with mode: 0644]
qapi/qapi-visit-core.c [new file with mode: 0644]
qapi/qapi-visit-core.h [new file with mode: 0644]
qapi/qmp-core.h [new file with mode: 0644]
qapi/qmp-dispatch.c [new file with mode: 0644]
qapi/qmp-input-visitor.c [new file with mode: 0644]
qapi/qmp-input-visitor.h [new file with mode: 0644]
qapi/qmp-output-visitor.c [new file with mode: 0644]
qapi/qmp-output-visitor.h [new file with mode: 0644]
qapi/qmp-registry.c [new file with mode: 0644]
qbool.c
qdict.c
qemu-barrier.h
qemu-char.c
qemu-char.h
qemu-common.h
qemu-config.c
qemu-coroutine-int.h [new file with mode: 0644]
qemu-coroutine-lock.c [new file with mode: 0644]
qemu-coroutine.c [new file with mode: 0644]
qemu-coroutine.h [new file with mode: 0644]
qemu-doc.texi
qemu-error.c
qemu-ga.c [new file with mode: 0644]
qemu-img-cmds.hx
qemu-img.c
qemu-img.texi
qemu-io.c
qemu-lock.h
qemu-nbd.c
qemu-option.c
qemu-option.h
qemu-options.hx
qemu-os-posix.h
qemu-os-win32.h
qemu-progress.c [new file with mode: 0644]
qemu-queue.h
qemu-sockets.c
qemu-tech.texi
qemu-thread-posix.c [new file with mode: 0644]
qemu-thread-posix.h [new file with mode: 0644]
qemu-thread-win32.c [new file with mode: 0644]
qemu-thread-win32.h [new file with mode: 0644]
qemu-thread.h
qemu-timer.c
qemu-timer.h
qemu-tls.h [new file with mode: 0644]
qemu-tool.c
qemu-xattr.h [new file with mode: 0644]
qemu_socket.h
qerror.c
qerror.h
qfloat.c
qga/guest-agent-command-state.c [new file with mode: 0644]
qga/guest-agent-commands.c [new file with mode: 0644]
qga/guest-agent-core.h [new file with mode: 0644]
qint.c
qlist.c
qlist.h
qmp-commands.hx
qmp.c [new file with mode: 0644]
qstring.c
readline.c
rules.mak
savevm.c
scripts/analyse-9p-simpletrace.py [new file with mode: 0755]
scripts/checkpatch.pl [changed mode: 0644->0755]
scripts/create_config [changed mode: 0644->0755]
scripts/get_maintainer.pl [new file with mode: 0755]
scripts/kvm/kvm_stat [new file with mode: 0755]
scripts/kvm/vmxcap [new file with mode: 0755]
scripts/ordereddict.py [new file with mode: 0644]
scripts/qapi-commands.py [new file with mode: 0644]
scripts/qapi-types.py [new file with mode: 0644]
scripts/qapi-visit.py [new file with mode: 0644]
scripts/qapi.py [new file with mode: 0644]
scripts/qemu-binfmt-conf.sh
scripts/refresh-pxe-roms.sh [new file with mode: 0755]
scripts/signrom.sh [changed mode: 0644->0755]
scripts/simpletrace.py [changed mode: 0644->0755]
scripts/texi2pod.pl [changed mode: 0644->0755]
scripts/tracetool [changed mode: 0644->0755]
scripts/update-linux-headers.sh [new file with mode: 0755]
slirp/arp_table.c [new file with mode: 0644]
slirp/bootp.c
slirp/if.c
slirp/ip.h
slirp/ip_icmp.c
slirp/ip_icmp.h
slirp/ip_input.c
slirp/ip_output.c
slirp/libslirp.h
slirp/main.h
slirp/mbuf.c
slirp/mbuf.h
slirp/misc.c
slirp/slirp.c
slirp/slirp.h
slirp/socket.c
slirp/tcp.h
slirp/tcp_input.c
slirp/tcp_subr.c
slirp/tftp.c
slirp/tftp.h
slirp/udp.c
softmmu-semi.h
softmmu_defs.h
softmmu_exec.h
softmmu_header.h
softmmu_template.h
sparc.ld
spice-qemu-char.c
sysemu.h
target-alpha/cpu.h
target-alpha/helper.c
target-alpha/helper.h
target-alpha/machine.c [new file with mode: 0644]
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/iwmmxt_helper.c
target-arm/machine.c
target-arm/neon_helper.c
target-arm/op_addsub.h
target-arm/op_helper.c
target-arm/translate.c
target-cris/cpu.h
target-cris/helper.c
target-cris/mmu.c
target-cris/op_helper.c
target-cris/opcode-cris.h
target-cris/translate.c
target-cris/translate_v10.c
target-i386/cpu.h
target-i386/cpuid.c
target-i386/hax-all.c [new file with mode: 0644]
target-i386/hax-i386.h [new file with mode: 0644]
target-i386/hax-interface.h [new file with mode: 0644]
target-i386/hax-windows.c [new file with mode: 0644]
target-i386/hax-windows.h [new file with mode: 0644]
target-i386/helper.c
target-i386/helper.h
target-i386/kvm.c
target-i386/machine.c
target-i386/ops_sse.h
target-i386/svm.h
target-i386/translate.c
target-lm32/README [new file with mode: 0644]
target-lm32/TODO [new file with mode: 0644]
target-lm32/cpu.h [new file with mode: 0644]
target-lm32/helper.c [new file with mode: 0644]
target-lm32/helper.h [new file with mode: 0644]
target-lm32/machine.c [new file with mode: 0644]
target-lm32/op_helper.c [new file with mode: 0644]
target-lm32/translate.c [new file with mode: 0644]
target-m68k/cpu.h
target-m68k/helper.c
target-m68k/op_helper.c
target-m68k/translate.c
target-microblaze/cpu.h
target-microblaze/helper.c
target-microblaze/helper.h
target-microblaze/microblaze-decode.h
target-microblaze/mmu.c
target-microblaze/op_helper.c
target-microblaze/translate.c
target-mips/cpu.h
target-mips/helper.c
target-mips/helper.h
target-mips/machine.c
target-mips/op_helper.c
target-mips/translate.c
target-mips/translate_init.c
target-ppc/STATUS
target-ppc/cpu.h
target-ppc/helper.c
target-ppc/helper.h
target-ppc/kvm.c
target-ppc/kvm_ppc.c
target-ppc/kvm_ppc.h
target-ppc/machine.c
target-ppc/op_helper.c
target-ppc/translate.c
target-ppc/translate_init.c
target-s390x/cpu.h
target-s390x/helper.c
target-s390x/helpers.h [new file with mode: 0644]
target-s390x/kvm.c
target-s390x/op_helper.c
target-s390x/translate.c
target-sh4/cpu.h
target-sh4/helper.c
target-sh4/helper.h
target-sh4/op_helper.c
target-sh4/translate.c
target-sparc/cc_helper.c [new file with mode: 0644]
target-sparc/cpu.h
target-sparc/cpu_init.c [new file with mode: 0644]
target-sparc/fop_helper.c [new file with mode: 0644]
target-sparc/helper.c
target-sparc/helper.h
target-sparc/int32_helper.c [new file with mode: 0644]
target-sparc/int64_helper.c [new file with mode: 0644]
target-sparc/ldst_helper.c [new file with mode: 0644]
target-sparc/machine.c
target-sparc/mmu_helper.c [new file with mode: 0644]
target-sparc/op_helper.c
target-sparc/translate.c
target-sparc/vis_helper.c [new file with mode: 0644]
target-sparc/win_helper.c [new file with mode: 0644]
target-unicore32/cpu.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]
target-xtensa/core-dc232b.c [new file with mode: 0644]
target-xtensa/core-dc232b/core-isa.h [new file with mode: 0644]
target-xtensa/core-dc232b/gdb-config.c [new file with mode: 0644]
target-xtensa/core-fsf.c [new file with mode: 0644]
target-xtensa/core-fsf/core-isa.h [new file with mode: 0644]
target-xtensa/cpu.h [new file with mode: 0644]
target-xtensa/helper.c [new file with mode: 0644]
target-xtensa/helpers.h [new file with mode: 0644]
target-xtensa/machine.c [new file with mode: 0644]
target-xtensa/op_helper.c [new file with mode: 0644]
target-xtensa/overlay_tool.h [new file with mode: 0644]
target-xtensa/translate.c [new file with mode: 0644]
tcg/README
tcg/arm/tcg-target.c
tcg/arm/tcg-target.h
tcg/hppa/tcg-target.c
tcg/hppa/tcg-target.h
tcg/i386/tcg-target.c
tcg/i386/tcg-target.h
tcg/ia64/tcg-target.c
tcg/ia64/tcg-target.h
tcg/mips/tcg-target.c
tcg/mips/tcg-target.h
tcg/optimize.c
tcg/ppc/tcg-target.c
tcg/ppc/tcg-target.h
tcg/ppc64/tcg-target.c
tcg/ppc64/tcg-target.h
tcg/s390/tcg-target.c
tcg/s390/tcg-target.h
tcg/sparc/tcg-target.c
tcg/sparc/tcg-target.h
tcg/tcg-op.h
tcg/tcg-opc.h
tcg/tcg.c
tcg/tcg.h
tcg/tci/README [new file with mode: 0644]
tcg/tci/tcg-target.c [new file with mode: 0644]
tcg/tci/tcg-target.h [new file with mode: 0644]
tci-dis.c [new file with mode: 0644]
tci.c [new file with mode: 0644]
test-coroutine.c [new file with mode: 0644]
test-qmp-commands.c [new file with mode: 0644]
test-visitor.c [new file with mode: 0644]
tests/Makefile
tests/cris/.gdbinit [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/linux-test.c
tests/lm32/Makefile [new file with mode: 0644]
tests/lm32/crt.S [new file with mode: 0644]
tests/lm32/linker.ld [new file with mode: 0644]
tests/lm32/macros.inc [new file with mode: 0644]
tests/lm32/test_add.S [new file with mode: 0644]
tests/lm32/test_addi.S [new file with mode: 0644]
tests/lm32/test_and.S [new file with mode: 0644]
tests/lm32/test_andhi.S [new file with mode: 0644]
tests/lm32/test_andi.S [new file with mode: 0644]
tests/lm32/test_b.S [new file with mode: 0644]
tests/lm32/test_be.S [new file with mode: 0644]
tests/lm32/test_bg.S [new file with mode: 0644]
tests/lm32/test_bge.S [new file with mode: 0644]
tests/lm32/test_bgeu.S [new file with mode: 0644]
tests/lm32/test_bgu.S [new file with mode: 0644]
tests/lm32/test_bi.S [new file with mode: 0644]
tests/lm32/test_bne.S [new file with mode: 0644]
tests/lm32/test_break.S [new file with mode: 0644]
tests/lm32/test_bret.S [new file with mode: 0644]
tests/lm32/test_call.S [new file with mode: 0644]
tests/lm32/test_calli.S [new file with mode: 0644]
tests/lm32/test_cmpe.S [new file with mode: 0644]
tests/lm32/test_cmpei.S [new file with mode: 0644]
tests/lm32/test_cmpg.S [new file with mode: 0644]
tests/lm32/test_cmpge.S [new file with mode: 0644]
tests/lm32/test_cmpgei.S [new file with mode: 0644]
tests/lm32/test_cmpgeu.S [new file with mode: 0644]
tests/lm32/test_cmpgeui.S [new file with mode: 0644]
tests/lm32/test_cmpgi.S [new file with mode: 0644]
tests/lm32/test_cmpgu.S [new file with mode: 0644]
tests/lm32/test_cmpgui.S [new file with mode: 0644]
tests/lm32/test_cmpne.S [new file with mode: 0644]
tests/lm32/test_cmpnei.S [new file with mode: 0644]
tests/lm32/test_divu.S [new file with mode: 0644]
tests/lm32/test_eret.S [new file with mode: 0644]
tests/lm32/test_lb.S [new file with mode: 0644]
tests/lm32/test_lbu.S [new file with mode: 0644]
tests/lm32/test_lh.S [new file with mode: 0644]
tests/lm32/test_lhu.S [new file with mode: 0644]
tests/lm32/test_lw.S [new file with mode: 0644]
tests/lm32/test_modu.S [new file with mode: 0644]
tests/lm32/test_mul.S [new file with mode: 0644]
tests/lm32/test_muli.S [new file with mode: 0644]
tests/lm32/test_nor.S [new file with mode: 0644]
tests/lm32/test_nori.S [new file with mode: 0644]
tests/lm32/test_or.S [new file with mode: 0644]
tests/lm32/test_orhi.S [new file with mode: 0644]
tests/lm32/test_ori.S [new file with mode: 0644]
tests/lm32/test_ret.S [new file with mode: 0644]
tests/lm32/test_sb.S [new file with mode: 0644]
tests/lm32/test_scall.S [new file with mode: 0644]
tests/lm32/test_sextb.S [new file with mode: 0644]
tests/lm32/test_sexth.S [new file with mode: 0644]
tests/lm32/test_sh.S [new file with mode: 0644]
tests/lm32/test_sl.S [new file with mode: 0644]
tests/lm32/test_sli.S [new file with mode: 0644]
tests/lm32/test_sr.S [new file with mode: 0644]
tests/lm32/test_sri.S [new file with mode: 0644]
tests/lm32/test_sru.S [new file with mode: 0644]
tests/lm32/test_srui.S [new file with mode: 0644]
tests/lm32/test_sub.S [new file with mode: 0644]
tests/lm32/test_sw.S [new file with mode: 0644]
tests/lm32/test_xnor.S [new file with mode: 0644]
tests/lm32/test_xnori.S [new file with mode: 0644]
tests/lm32/test_xor.S [new file with mode: 0644]
tests/lm32/test_xori.S [new file with mode: 0644]
tests/qruncom.c
tests/test-i386.c
tests/test-mmap.c
tests/test_path.c
tests/xtensa/Makefile [new file with mode: 0644]
tests/xtensa/crt.S [new file with mode: 0644]
tests/xtensa/linker.ld [new file with mode: 0644]
tests/xtensa/macros.inc [new file with mode: 0644]
tests/xtensa/test_b.S [new file with mode: 0644]
tests/xtensa/test_bi.S [new file with mode: 0644]
tests/xtensa/test_boolean.S [new file with mode: 0644]
tests/xtensa/test_bz.S [new file with mode: 0644]
tests/xtensa/test_clamps.S [new file with mode: 0644]
tests/xtensa/test_fail.S [new file with mode: 0644]
tests/xtensa/test_interrupt.S [new file with mode: 0644]
tests/xtensa/test_loop.S [new file with mode: 0644]
tests/xtensa/test_mac16.S [new file with mode: 0644]
tests/xtensa/test_max.S [new file with mode: 0644]
tests/xtensa/test_min.S [new file with mode: 0644]
tests/xtensa/test_mmu.S [new file with mode: 0644]
tests/xtensa/test_mul16.S [new file with mode: 0644]
tests/xtensa/test_mul32.S [new file with mode: 0644]
tests/xtensa/test_nsa.S [new file with mode: 0644]
tests/xtensa/test_pipeline.S [new file with mode: 0644]
tests/xtensa/test_quo.S [new file with mode: 0644]
tests/xtensa/test_rem.S [new file with mode: 0644]
tests/xtensa/test_rst0.S [new file with mode: 0644]
tests/xtensa/test_sar.S [new file with mode: 0644]
tests/xtensa/test_sext.S [new file with mode: 0644]
tests/xtensa/test_shift.S [new file with mode: 0644]
tests/xtensa/test_timer.S [new file with mode: 0644]
tests/xtensa/test_windowed.S [new file with mode: 0644]
tests/xtensa/vectors.S [new file with mode: 0644]
tizen/Makefile [new file with mode: 0644]
tizen/build.sh
tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avcodec-52.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avcodec-52.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avcodec.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avcodec.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avdevice-52.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avdevice-52.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avdevice.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avdevice.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avformat-52.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avformat-52.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avformat.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avformat.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avutil-50.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avutil-50.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/bin/avutil.dll [new file with mode: 0755]
tizen/distrib/ffmpeg/bin/avutil.lib [new file with mode: 0644]
tizen/distrib/ffmpeg/include/libavutil/pixfmt.h
tizen/distrib/ffmpeg/lib/libavcodec.a
tizen/distrib/ffmpeg/lib/libavcodec.dll.a
tizen/distrib/ffmpeg/lib/libavdevice.a
tizen/distrib/ffmpeg/lib/libavdevice.dll.a
tizen/distrib/ffmpeg/lib/libavformat.a
tizen/distrib/ffmpeg/lib/libavformat.dll.a
tizen/distrib/ffmpeg/lib/libavutil.a
tizen/distrib/ffmpeg/lib/libavutil.dll.a
tizen/distrib/ffmpeg/libavutil/pixfmt.h
tizen/distrib/ffmpeg/tizen_configure
tizen/qemu_configure.sh [new file with mode: 0755]
tizen/src/Makefile [new file with mode: 0755]
tizen/src/Makefile.tizen [new file with mode: 0755]
tizen/src/VERSION
tizen/src/check_hax.c [new file with mode: 0644]
tizen/src/debug_ch.c
tizen/src/debug_ch.h
tizen/src/emul_state.c [new file with mode: 0644]
tizen/src/emul_state.h [new file with mode: 0644]
tizen/src/emulator.c
tizen/src/emulator.h
tizen/src/guest_server.c [new file with mode: 0644]
tizen/src/guest_server.h [new file with mode: 0644]
tizen/src/hw/beginend_funcs.sh [new file with mode: 0755]
tizen/src/hw/gl_func_perso.h [new file with mode: 0755]
tizen/src/hw/gloffscreen.h [new file with mode: 0755]
tizen/src/hw/gloffscreen_common.c [new file with mode: 0755]
tizen/src/hw/gloffscreen_glx.c [new file with mode: 0755]
tizen/src/hw/gloffscreen_test.c [new file with mode: 0755]
tizen/src/hw/gloffscreen_wgl.c [new file with mode: 0755]
tizen/src/hw/gloffscreen_xcomposite.c [new file with mode: 0755]
tizen/src/hw/helper_opengl.c [new file with mode: 0755]
tizen/src/hw/maru_board.c [new file with mode: 0644]
tizen/src/hw/maru_brightness.c [new file with mode: 0644]
tizen/src/hw/maru_brightness.h [new file with mode: 0644]
tizen/src/hw/maru_camera_common.h [new file with mode: 0644]
tizen/src/hw/maru_camera_common_pci.c [new file with mode: 0644]
tizen/src/hw/maru_camera_linux_pci.c [new file with mode: 0644]
tizen/src/hw/maru_camera_win32_interface.h [new file with mode: 0644]
tizen/src/hw/maru_camera_win32_pci.c [new file with mode: 0644]
tizen/src/hw/maru_codec.c
tizen/src/hw/maru_codec.h
tizen/src/hw/maru_overlay.c [new file with mode: 0644]
tizen/src/hw/maru_overlay.h [new file with mode: 0644]
tizen/src/hw/maru_pci_ids.h [new file with mode: 0644]
tizen/src/hw/maru_pm.c
tizen/src/hw/maru_pm.h
tizen/src/hw/maru_touchscreen.c
tizen/src/hw/maru_touchscreen.h [new file with mode: 0644]
tizen/src/hw/maru_vga.c [new file with mode: 0644]
tizen/src/hw/maru_vga_int.h [new file with mode: 0644]
tizen/src/hw/maru_vga_template.h [new file with mode: 0644]
tizen/src/hw/mesa_gl.h [new file with mode: 0755]
tizen/src/hw/mesa_glext.h [new file with mode: 0755]
tizen/src/hw/mesa_glu.h [new file with mode: 0755]
tizen/src/hw/mesa_mipmap.c [new file with mode: 0755]
tizen/src/hw/mesa_mipmap.h [new file with mode: 0755]
tizen/src/hw/op_helper.c [new file with mode: 0755]
tizen/src/hw/opengl_exec.c [new file with mode: 0755]
tizen/src/hw/opengl_exec.h [new file with mode: 0755]
tizen/src/hw/opengl_func.h [new file with mode: 0755]
tizen/src/hw/opengl_process.h [new file with mode: 0755]
tizen/src/hw/parse_gl_h.c [new file with mode: 0755]
tizen/src/hw/range_alloc.h [new file with mode: 0755]
tizen/src/hw/virtio-gl.c [new file with mode: 0755]
tizen/src/maru_common.h [new file with mode: 0644]
tizen/src/maru_finger.c [new file with mode: 0644]
tizen/src/maru_finger.h [new file with mode: 0644]
tizen/src/maru_sdl.c [new file with mode: 0644]
tizen/src/maru_sdl.h [new file with mode: 0644]
tizen/src/mloop_event.c [new file with mode: 0644]
tizen/src/mloop_event.h [new file with mode: 0644]
tizen/src/option.c
tizen/src/option.h
tizen/src/sdb.c [new file with mode: 0644]
tizen/src/sdb.h [new file with mode: 0644]
tizen/src/sdl_rotate.c [new file with mode: 0644]
tizen/src/sdl_rotate.h [new file with mode: 0644]
tizen/src/sdl_zoom.c [new file with mode: 0644]
tizen/src/sdl_zoom.h [new file with mode: 0644]
tizen/src/sdl_zoom_template.h [new file with mode: 0644]
tizen/src/skin/client/.classpath [new file with mode: 0644]
tizen/src/skin/client/.project [new file with mode: 0644]
tizen/src/skin/client/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
tizen/src/skin/client/build.xml [new file with mode: 0644]
tizen/src/skin/client/dev/.skin.properties [new file with mode: 0644]
tizen/src/skin/client/dev/.skinconfig.properties [new file with mode: 0644]
tizen/src/skin/client/dev/dbi-sample.xml [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ColorsType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EmulatorUI.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EventInfoType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ImageListType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapListType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/LcdType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ObjectFactory.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RegionType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RgbType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationNameType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationsType.java [new file with mode: 0644]
tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/package-info.java [new file with mode: 0644]
tizen/src/skin/client/lib/swt/cocoa-macosx/src.zip [new file with mode: 0644]
tizen/src/skin/client/lib/swt/cocoa-macosx/swt-debug.jar [new file with mode: 0644]
tizen/src/skin/client/lib/swt/cocoa-macosx/swt.jar [new file with mode: 0644]
tizen/src/skin/client/lib/swt/gtk-linux/src.zip [new file with mode: 0644]
tizen/src/skin/client/lib/swt/gtk-linux/swt-debug.jar [new file with mode: 0644]
tizen/src/skin/client/lib/swt/gtk-linux/swt.jar [new file with mode: 0644]
tizen/src/skin/client/lib/swt/win32-win32/src.zip [new file with mode: 0644]
tizen/src/skin/client/lib/swt/win32-win32/swt-debug.jar [new file with mode: 0644]
tizen/src/skin/client/lib/swt/win32-win32/swt.jar [new file with mode: 0644]
tizen/src/skin/client/resource/icons/Emulator.ico [new file with mode: 0644]
tizen/src/skin/client/resource/icons/Emulator_20x20.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/about.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/advanced.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/close.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/copy_screenshot_dialog.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/detail_info.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/refresh_screenshot_dialog.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/rotate.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/save_screenshot_dialog.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/scale.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/screenshot.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/shell.png [new file with mode: 0644]
tizen/src/skin/client/resource/icons/usb_keyboard.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_320x480/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_320x480/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_480x800/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_480x800/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_600x1024/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default.dbi [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_0.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_0_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_180.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_180_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_L90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_L90_p.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_R90.png [new file with mode: 0644]
tizen/src/skin/client/skins/emul_720x1280/default_R90_p.png [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorShutdownhook.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkin.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkinMain.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/ICommunicator.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/AbstractSendData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/BooleanData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/ISendData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/KeyEventData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/LcdStateData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/MouseEventData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/StartData.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/config/EmulatorConfig.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/AboutDialog.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/LicenseDialog.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/SkinDialog.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ConfigException.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/exception/EmulatorException.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/exception/JaxbException.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ScreenShotException.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/image/ImageRegistry.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/IOUtil.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/JaxbUtil.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRegion.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRotation.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinUtil.java [new file with mode: 0644]
tizen/src/skin/client/src/org/tizen/emulator/skin/util/StringUtil.java [new file with mode: 0644]
tizen/src/skin/client/xsd/dbi.xsd [new file with mode: 0644]
tizen/src/skin/maruskin_client.c [new file with mode: 0644]
tizen/src/skin/maruskin_client.h [new file with mode: 0644]
tizen/src/skin/maruskin_keymap.c [new file with mode: 0644]
tizen/src/skin/maruskin_keymap.h [new file with mode: 0644]
tizen/src/skin/maruskin_operation.c [new file with mode: 0644]
tizen/src/skin/maruskin_operation.h [new file with mode: 0644]
tizen/src/skin/maruskin_server.c [new file with mode: 0644]
tizen/src/skin/maruskin_server.h [new file with mode: 0644]
trace-events
trace/control.c [new file with mode: 0644]
trace/control.h [new file with mode: 0644]
trace/default.c [new file with mode: 0644]
trace/simple.c [new file with mode: 0644]
trace/simple.h [new file with mode: 0644]
trace/stderr.c [new file with mode: 0644]
trace/stderr.h [new file with mode: 0644]
translate-all.c
ui/cocoa.m
ui/curses.c
ui/keymaps.c
ui/qemu-spice.h
ui/sdl.c
ui/sdl_keysym.h
ui/spice-core.c
ui/spice-display.c
ui/spice-display.h
ui/spice-input.c
ui/vnc-auth-sasl.c
ui/vnc-auth-vencrypt.c
ui/vnc-enc-hextile.c
ui/vnc-enc-tight.c
ui/vnc-enc-zlib.c
ui/vnc-enc-zrle-template.c [new file with mode: 0644]
ui/vnc-enc-zrle.c [new file with mode: 0644]
ui/vnc-enc-zrle.h [new file with mode: 0644]
ui/vnc-enc-zywrle-template.c [new file with mode: 0644]
ui/vnc-enc-zywrle.h [new file with mode: 0644]
ui/vnc-jobs-async.c
ui/vnc-palette.c
ui/vnc-palette.h
ui/vnc-tls.c
ui/vnc.c
ui/vnc.h
ui/vnc_keysym.h
usb-bsd.c
usb-linux.c
usb-redir.c [new file with mode: 0644]
user-exec.c [new file with mode: 0644]
vl.c
x86_64.ld
xen-all.c [new file with mode: 0644]
xen-mapcache.c [new file with mode: 0644]
xen-mapcache.h [new file with mode: 0644]
xen-stub.c [new file with mode: 0644]
xtensa-semi.c [new file with mode: 0644]

index 5ecfa2216109963cb646b5fcf00a10c85d3d0655..6e61c490894e244e7b8bc3c8553de9cae8cc9ead 100644 (file)
@@ -68,6 +68,10 @@ keyword.  Example:
         printf("a was something else entirely.\n");
     }
 
+Note that 'else if' is considered a single statement; otherwise a long if/
+else if/else if/.../else sequence would need an indent for every else
+statement.
+
 An exception is the opening brace for a function; for reasons of tradition
 and clarity it comes on a line by itself:
 
index 152feaacb559cffd88eb5ea8a0eb2ec7c73a7d45..28a69afa0b7f136b48b474c3b846ee6da53c5c2c 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,9 @@
+This file documents changes for QEMU releases 0.12 and earlier.
+For changelog information for later releases, see
+http://wiki.qemu.org/ChangeLog or look at the git history for
+more detailed information.
+
+
 version 0.12.0:
 
   - Update to SeaBIOS 0.5.0
@@ -525,7 +531,7 @@ version 0.1.5:
 
  - ppc64 support + personality() patch (Rusty Russell)
  - first Alpha CPU patches (Falk Hueffner)
- - removed bfd.h dependancy
+ - removed bfd.h dependency
  - fixed shrd, shld, idivl and divl on PowerPC.
  - fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
 
diff --git a/HACKING b/HACKING
index 6ba9d7e7402718d3a042e0026fd7b275e8dd6b1c..733eab2dacff10210a5e5140b096b4d91db33dec 100644 (file)
--- a/HACKING
+++ b/HACKING
@@ -77,11 +77,11 @@ avoided.
 
 Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
 APIs is not allowed in the QEMU codebase. Instead of these routines,
-use the replacement qemu_malloc/qemu_mallocz/qemu_realloc/qemu_free or
+use the replacement g_malloc/g_malloc0/g_realloc/g_free or
 qemu_vmalloc/qemu_memalign/qemu_vfree APIs.
 
-Please note that NULL check for the qemu_malloc result is redundant and
-that qemu_malloc() call with zero size is not allowed.
+Please note that NULL check for the g_malloc result is redundant and
+that g_malloc() call with zero size is not allowed.
 
 Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
 qemu_vfree, since breaking this will cause problems on Win32 and user
@@ -108,7 +108,7 @@ int qemu_strnlen(const char *s, int max_len)
 There are also replacement character processing macros for isxyz and toxyz,
 so instead of e.g. isalnum you should use qemu_isalnum.
 
-Because of the memory management rules, you must use qemu_strdup/qemu_strndup
+Because of the memory management rules, you must use g_strdup/g_strndup
 instead of plain strdup/strndup.
 
 5. Printf-style functions
@@ -120,6 +120,3 @@ gcc's printf attribute directive in the prototype.
 This makes it so gcc's -Wformat and -Wformat-security options can do
 their jobs and cross-check format strings with the number and types
 of arguments.
-
-Currently many functions in QEMU are not following this rule but
-patches to add the attribute would be very much appreciated.
index ab48380058d0967196be0b11cdc480528734fcbd..06df70ca8960733a6700e561d0be661c21e4dabf 100644 (file)
@@ -56,12 +56,13 @@ M: Paul Brook <paul@codesourcery.com>
 Guest CPU cores (TCG):
 ----------------------
 Alpha
-M: qemu-devel@nongnu.org
-S: Orphan
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
 F: target-alpha/
 
 ARM
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: target-arm/
 
@@ -70,6 +71,11 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: target-cris/
 
+LM32
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: target-lm32/
+
 M68K
 M: Paul Brook <paul@codesourcery.com>
 S: Maintained
@@ -110,6 +116,12 @@ M: qemu-devel@nongnu.org
 S: Odd Fixes
 F: target-i386/
 
+Xtensa
+M: Max Filippov <jcmvbkbc@gmail.com>
+W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
+S: Maintained
+F: target-xtensa/
+
 Guest CPU Cores (KVM):
 ----------------------
 
@@ -138,6 +150,16 @@ L: kvm@vger.kernel.org
 S: Supported
 F: target-i386/kvm.c
 
+Guest CPU Cores (Xen):
+----------------------
+
+X86
+M: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+L: xen-devel@lists.xensource.com
+S: Supported
+F: xen-*
+F: */xen*
+
 ARM Machines
 ------------
 Gumstix
@@ -147,6 +169,7 @@ F: hw/gumstix.c
 
 Integrator CP
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/integratorcp.c
 
@@ -172,6 +195,7 @@ F: hw/palm.c
 
 Real View
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/realview*
 
@@ -182,11 +206,13 @@ F: hw/spitz.c
 
 Stellaris
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/stellaris.c
 
 Versatile PB
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/versatilepb.c
 
@@ -202,6 +228,18 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: hw/etraxfs.c
 
+LM32 Machines
+-------------
+EVR32 and uclinux BSP
+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
@@ -265,9 +303,9 @@ M: Alexander Graf <agraf@suse.de>
 S: Maintained
 F: hw/ppc_oldworld.c
 
-Prep
-M: qemu-devel@nongnu.org
-S: Orphan
+PReP
+M: Andreas Färber <andreas.faerber@web.de>
+S: Odd Fixes
 F: hw/ppc_prep.c
 
 SH4 Machines
@@ -308,6 +346,18 @@ M: Anthony Liguori <aliguori@us.ibm.com>
 S: Supported
 F: hw/pc.[ch] hw/pc_piix.c
 
+Xtensa Machines
+---------------
+sim
+M: Max Filippov <jcmvbkbc@gmail.com>
+S: Maintained
+F: hw/xtensa_sim.c
+
+Avnet LX60
+M: Max Filippov <jcmvbkbc@gmail.com>
+S: Maintained
+F: hw/xtensa_lx60.c
+
 Devices
 -------
 IDE
@@ -315,6 +365,11 @@ M: Kevin Wolf <kwolf@redhat.com>
 S: Odd Fixes
 F: hw/ide/
 
+OMAP
+M: Peter Maydell <peter.maydell@linaro.org>
+S: Maintained
+F: hw/omap*
+
 PCI
 M: Michael S. Tsirkin <mst@redhat.com>
 S: Supported
@@ -396,6 +451,11 @@ M: Anthony Liguori <aliguori@us.ibm.com>
 S: Maintained
 F: ui/
 
+Cocoa graphics
+M: Andreas Färber <andreas.faerber@web.de>
+S: Odd Fixes
+F: ui/cocoa.m
+
 Main loop
 M: Anthony Liguori <aliguori@us.ibm.com>
 S: Supported
@@ -414,9 +474,21 @@ S: Maintained
 F: net/
 
 SLIRP
-M: qemu-devel@nongnu.org
-S: Orphan
+M: Jan Kiszka <jan.kiszka@siemens.com>
+S: Maintained
 F: slirp/
+T: git://git.kiszka.org/qemu.git queues/slirp
+
+Tracing
+M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+S: Maintained
+F: trace/
+T: git://repo.or.cz/qemu/stefanha.git tracing
+
+Checkpatch
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Odd Fixes
+F: scripts/checkpatch.pl
 
 Usermode Emulation
 ------------------
@@ -463,7 +535,7 @@ S: Maintained
 F: tcg/ia64/
 
 MIPS target
-M: Aurelien Jarno <aurelien@aurel32.ne>
+M: Aurelien Jarno <aurelien@aurel32.net>
 S: Maintained
 F: tcg/mips/
 
@@ -487,3 +559,8 @@ SPARC target
 M: Blue Swirl <blauwirbel@gmail.com>
 S: Maintained
 F: tcg/sparc/
+
+TCI target
+M: Stefan Weil <sw@weilnetz.de>
+S: Maintained
+F: tcg/tci
index 37f22ea948f3633fcd1dc6046648f886d33aefd7..301c75e7e51cdbe2a6470a78cddc71cdaa28e6b4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,14 @@
 # Makefile for QEMU.
 
+# Always point to the root of the build tree (needs GNU make).
+BUILD_DIR=$(CURDIR)
+
 GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 ifeq ($(TRACE_BACKEND),dtrace)
 GENERATED_HEADERS += trace-dtrace.h
 endif
+GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
+GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -37,7 +42,7 @@ else
 DOCS=
 endif
 
-SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
+SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
 SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
 SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 
@@ -71,7 +76,7 @@ defconfig:
 
 -include config-all-devices.mak
 
-build-all: $(DOCS) $(TOOLS) recurse-all
+build-all: $(DOCS) $(TOOLS) $(CHECKS) recurse-all
 
 config-host.h: config-host.h-timestamp
 config-host.h-timestamp: config-host.mak
@@ -88,6 +93,8 @@ include $(SRC_PATH)/Makefile.objs
 endif
 
 $(common-obj-y): $(GENERATED_HEADERS)
+subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
+
 $(filter %-softmmu,$(SUBDIR_RULES)): $(trace-obj-y) $(common-obj-y) subdir-libdis
 
 $(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) $(trace-obj-y) subdir-libdis-user subdir-libuser
@@ -104,87 +111,128 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
 ui/cocoa.o: ui/cocoa.m
 
-ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o ui/sdl_rotate.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 
 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
+version.o: $(SRC_PATH)/version.rc config-host.h
+       $(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
-trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
-       $(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+version-obj-$(CONFIG_WIN32) += version.o
+######################################################################
+# Support building shared library libcacard
 
-simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
+.PHONY: libcacard.la install-libcacard
+ifeq ($(LIBTOOL),)
+libcacard.la:
+       @echo "libtool is missing, please install and rerun configure"; exit 1
 
-version.o: $(SRC_PATH)/version.rc config-host.mak
-       $(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
+install-libcacard:
+       @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(GENERATED_HEADERS) $(oslib-obj-y) qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
+       $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
 
-version-obj-$(CONFIG_WIN32) += version.o
+install-libcacard: libcacard.la
+       $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
+endif
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
-
-qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
 
-qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+tools-obj-y = qemu-tool.o $(oslib-obj-y) $(trace-obj-y) \
+       qemu-timer-common.o cutils.o
 
-qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
+qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
 
-check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
-
-CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
-
-check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
-check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
-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)
+check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
+
+check-qint: check-qint.o qint.o $(tools-obj-y)
+check-qstring: check-qstring.o qstring.o $(tools-obj-y)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
+check-qlist: check-qlist.o qlist.o qint.o $(tools-obj-y)
+check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
+check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
+test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
+
+$(qapi-obj-y): $(GENERATED_HEADERS)
+qapi-dir := $(BUILD_DIR)/qapi-generated
+test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
+
+$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
+           $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+
+$(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+$(qapi-dir)/qga-qapi-visit.c $(qapi-dir)/qga-qapi-visit.h :\
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+$(qapi-dir)/qga-qmp-commands.h $(qapi-dir)/qga-qmp-marshal.c :\
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+
+qapi-types.c qapi-types.h :\
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "." < $<, "  GEN   $@")
+qapi-visit.c qapi-visit.h :\
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "."  < $<, "  GEN   $@")
+qmp-commands.h qmp-marshal.c :\
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, "  GEN   $@")
+
+test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-visitor: test-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
+test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
+test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+
+QGALIB_OBJ=$(addprefix $(qapi-dir)/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o)
+QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
+$(QGALIB_OBJ): $(QGALIB_GEN) $(GENERATED_HEADERS)
+$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) $(GENERATED_HEADERS)
+
+qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ)
+
+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
        rm -f qemu-options.def
-       rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
-       rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
+       rm -f *.o *.d *.a *.lo $(TOOLS) $(CHECKS) qemu-ga TAGS cscope.* *.pod *~ */*~
+       rm -Rf .libs
+       rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
        rm -f qemu-img-cmds.h
+       rm -f trace/*.o trace/*.d
        rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
        rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
        rm -f trace-dtrace.h trace-dtrace.h-timestamp
+       rm -f $(GENERATED_SOURCES)
+       rm -rf $(qapi-dir)
        $(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 +241,13 @@ 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 config.log
        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
 
@@ -204,16 +256,17 @@ ar      de     en-us  fi  fr-be  hr     it  lv  nl         pl  ru     th \
 common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 
 ifdef INSTALL_BLOBS
-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
+BLOBS=bios.bin sgabios.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 \
-bamboo.dtb petalogix-s3adsp1800.dtb \
+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 \
+mpc8544ds.dtb \
 multiboot.bin linuxboot.bin \
-s390-zipl.rom
+s390-zipl.rom \
+spapr-rtas.bin slof.bin \
+palcode-clipper
 else
 BLOBS=
 endif
@@ -255,13 +308,19 @@ endif
 test speed: all
        $(MAKE) -C tests $@
 
+.PHONY: check
+check: $(patsubst %,run-check-%,$(CHECKS))
+
+run-check-%: %
+       ./$<
+
 .PHONY: TAGS
 TAGS:
        find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
 
 cscope:
        rm -f ./cscope.*
-       find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
+       find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
        cscope -b
 
 # documentation
@@ -330,40 +389,5 @@ tar:
        cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
        rm -rf /tmp/$(FILE)
 
-SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS))
-SYSTEM_PROGS=$(patsubst qemu-system-i386,qemu, \
-             $(patsubst %-softmmu,qemu-system-%, \
-             $(SYSTEM_TARGETS)))
-
-USER_TARGETS=$(filter %-user,$(TARGET_DIRS))
-USER_PROGS=$(patsubst %-bsd-user,qemu-%, \
-           $(patsubst %-darwin-user,qemu-%, \
-           $(patsubst %-linux-user,qemu-%, \
-           $(USER_TARGETS))))
-
-# generate a binary distribution
-tarbin:
-       cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
-       $(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \
-       $(patsubst %,$(bindir)/%, $(USER_PROGS)) \
-       $(bindir)/qemu-img \
-       $(bindir)/qemu-nbd \
-       $(datadir)/bios.bin \
-       $(datadir)/vgabios.bin \
-       $(datadir)/vgabios-cirrus.bin \
-       $(datadir)/ppc_rom.bin \
-       $(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 \
-       $(docdir)/qemu-doc.html \
-       $(docdir)/qemu-tech.html \
-       $(mandir)/man1/qemu.1 \
-       $(mandir)/man1/qemu-img.1 \
-       $(mandir)/man8/qemu-nbd.8
-
 # Include automatically generated dependency files
--include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
+-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
index f2e63b42ed25167adf810a7742e18ddbefd1e714..63eb7e40be7264268cbed33567b54f80f96bb2aa 100644 (file)
@@ -7,9 +7,10 @@ include $(SRC_PATH)/rules.mak
 
 .PHONY: all
 
-$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/tizen/src/hw)
+$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 
-QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu -I$(SRC_PATH)/hw
+QEMU_CFLAGS+=-I..
+QEMU_CFLAGS += $(GLIB_CFLAGS)
 
 include $(SRC_PATH)/Makefile.objs
 
index 3b52e3363dfc6cfb9be96338cd1ad431e628fd77..3a699ee7d8a33152e1e38024d5331486d0d917b7 100644 (file)
@@ -2,19 +2,30 @@
 # QObject
 qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
-qobject-obj-y += qerror.o
+qobject-obj-y += qerror.o error.o qemu-error.o
 
 #######################################################################
 # oslib-obj-y is code depending on the OS (win32 vs posix)
 oslib-obj-y = osdep.o
-oslib-obj-$(CONFIG_WIN32) += oslib-win32.o
-oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
+oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
+oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
+
+#######################################################################
+# coroutines
+coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o
+ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
+coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
+else
+coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
+endif
+coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.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
-block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o
+block-obj-y = cutils.o cache-utils.o qemu-option.o module.o async.o
+block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
+block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -25,6 +36,7 @@ block-nested-y += qed-check.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
+block-nested-$(CONFIG_LIBISCSI) += iscsi.o
 block-nested-$(CONFIG_CURL) += curl.o
 block-nested-$(CONFIG_RBD) += rbd.o
 
@@ -45,12 +57,14 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
 net-nested-$(CONFIG_VDE) += vde.o
 net-obj-y += $(addprefix net/, $(net-nested-y))
 
-ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
 # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
 # only pull in the actual virtio-9p device if we also enabled virtio.
 CONFIG_REALLY_VIRTFS=y
+fsdev-nested-y = qemu-fsdev.o
+else
+fsdev-nested-y = qemu-fsdev-dummy.o
 endif
-fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
 fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
 
 ######################################################################
@@ -63,13 +77,13 @@ common-obj-y = $(block-obj-y) blockdev.o
 common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
-common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
+common-obj-y += readline.o console.o cursor.o
 common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
 
-common-obj-y += tcg-runtime.o host-utils.o
-common-obj-y += irq.o ioport.o input.o
+common-obj-y += tcg-runtime.o host-utils.o main-loop.o
+common-obj-y += irq.o input.o
 common-obj-$(CONFIG_PTIMER) += ptimer.o
 common-obj-$(CONFIG_MAX7310) += max7310.o
 common-obj-$(CONFIG_WM8750) += wm8750.o
@@ -87,6 +101,7 @@ common-obj-y += i2c.o smbus.o smbus_eeprom.o
 common-obj-y += eeprom93xx.o
 common-obj-y += scsi-disk.o cdrom.o
 common-obj-y += scsi-generic.o scsi-bus.o
+common-obj-y += hid.o
 common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
 common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
 common-obj-$(CONFIG_SSI) += ssi.o
@@ -94,12 +109,13 @@ 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
 
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
@@ -124,35 +140,36 @@ audio-obj-y += wavcapture.o
 common-obj-y += $(addprefix audio/, $(audio-obj-y))
 
 ui-obj-y += keymaps.o
-ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o sdl_rotate.o x_keymap.o
-ui-obj-$(CONFIG_CURSES) += curses.o
-ui-obj-y += vnc.o d3des.o
-ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
-ui-obj-y += vnc-enc-tight.o vnc-palette.o
-ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
-ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
+ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 ui-obj-$(CONFIG_COCOA) += cocoa.o
+ui-obj-$(CONFIG_CURSES) += curses.o
+vnc-obj-y += vnc.o d3des.o
+vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
+vnc-obj-y += vnc-enc-tight.o vnc-palette.o
+vnc-obj-y += vnc-enc-zrle.o
+vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
+vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 ifdef CONFIG_VNC_THREAD
-ui-obj-y += vnc-jobs-async.o
+vnc-obj-y += vnc-jobs-async.o
 else
-ui-obj-y += vnc-jobs-sync.o
+vnc-obj-y += vnc-jobs-sync.o
 endif
 common-obj-y += $(addprefix ui/, $(ui-obj-y))
+common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y))
 
 common-obj-y += iov.o acl.o
-common-obj-$(CONFIG_THREAD) += qemu-thread.o
-common-obj-$(CONFIG_IOTHREAD) += compatfd.o
+common-obj-$(CONFIG_POSIX) += compatfd.o
 common-obj-y += notify.o event_notifier.o
 common-obj-y += qemu-timer.o qemu-timer-common.o
 
 slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
 slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
+slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
 common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
 
 # xen backend driver support
-common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
-common-obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o
 
 ######################################################################
 # libuser
@@ -161,13 +178,16 @@ user-obj-y =
 user-obj-y += envlist.o path.o
 user-obj-y += tcg-runtime.o host-utils.o
 user-obj-y += cutils.o cache-utils.o
+user-obj-y += $(trace-obj-y)
 
 ######################################################################
 # libhw
 
 hw-obj-y =
 hw-obj-y += vl.o loader.o
-hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
+hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
+hw-obj-y += usb-libhw.o
+hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 hw-obj-y += fw_cfg.o
 hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
 hw-obj-$(CONFIG_PCI) += msix.o msi.o
@@ -191,13 +211,19 @@ hw-obj-$(CONFIG_PCSPK) += pcspk.o
 hw-obj-$(CONFIG_PCKBD) += pckbd.o
 hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
 hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
+hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
 hw-obj-$(CONFIG_FDC) += fdc.o
 hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 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
+hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
+hw-obj-$(CONFIG_I8259) += i8259.o
 
 # PPC devices
-hw-obj-$(CONFIG_OPENPIC) += openpic.o
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
 # Mac shared devices
 hw-obj-$(CONFIG_MACIO) += macio.o
@@ -216,6 +242,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 
 # MIPS devices
 hw-obj-$(CONFIG_PIIX4) += piix4.o
+hw-obj-$(CONFIG_G364FB) += g364fb.o
 
 # PCI watchdog devices
 hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -233,9 +260,10 @@ hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
 hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 hw-obj-$(CONFIG_LAN9118) += lan9118.o
 hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
+hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.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
@@ -258,6 +286,7 @@ hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
+hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 
 hw-obj-$(CONFIG_RC4030) += rc4030.o
 hw-obj-$(CONFIG_DP8393X) += dp8393x.o
@@ -273,17 +302,20 @@ sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
 sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
 sound-obj-$(CONFIG_CS4231A) += cs4231a.o
 sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
-# Haptic
-hw-obj-$(CONFIG_SVIBE) += svibe.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_VIRTFS)  = virtio-9p.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
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
+9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
+9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) +=  virtio-9p-handle.o
+
+hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
+$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
 
 ######################################################################
 # libdis
@@ -308,16 +340,90 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 # trace
 
 ifeq ($(TRACE_BACKEND),dtrace)
-trace-obj-y = trace-dtrace.o
+trace.h: trace.h-timestamp trace-dtrace.h
 else
-trace-obj-y = trace.o
-ifeq ($(TRACE_BACKEND),simple)
-trace-obj-y += simpletrace.o
-user-obj-y += qemu-timer-common.o
+trace.h: trace.h-timestamp
+endif
+trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/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 $(BUILD_DIR)/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 dependency
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/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")
+
+ifeq ($(LIBTOOL),)
+trace-dtrace.lo: trace-dtrace.dtrace
+       @echo "missing libtool. please install and rerun configure."; exit 1
+else
+trace-dtrace.lo: trace-dtrace.dtrace
+       $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, "  lt GEN trace-dtrace.o")
 endif
+
+trace/simple.o: trace/simple.c $(GENERATED_HEADERS)
+
+trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o
+ifneq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace.o
 endif
 
+trace-nested-$(CONFIG_TRACE_DEFAULT) += default.o
+
+trace-nested-$(CONFIG_TRACE_SIMPLE) += simple.o
+trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o
+
+trace-nested-$(CONFIG_TRACE_STDERR) += stderr.o
+
+trace-nested-y += control.o
+
+trace-obj-y += $(addprefix trace/, $(trace-nested-y))
+
+$(trace-obj-y): $(GENERATED_HEADERS)
+
+######################################################################
+# smartcard
+
+libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
+
+######################################################################
+# qapi
+
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
+common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y)
+common-obj-y += qmp.o hmp.o
+
+######################################################################
+# guest agent
+
+qga-nested-y = guest-agent-commands.o guest-agent-command-state.o
+qga-obj-y = $(addprefix qga/, $(qga-nested-y))
+qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
+qga-obj-$(CONFIG_WIN32) += oslib-win32.o
+qga-obj-$(CONFIG_POSIX) += oslib-posix.o
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
old mode 100644 (file)
new mode 100755 (executable)
index 9791d4c..b19e96e
@@ -3,6 +3,7 @@
 GENERATED_HEADERS = config-target.h
 CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
 CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
+CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
 
 include ../config-host.mak
 include config-devices.mak
@@ -13,8 +14,12 @@ include $(HWDIR)/config.mak
 endif
 
 TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
-$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/tizen/src/hw)
-QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -I$(SRC_PATH)/hw -DNEED_CPU_H
+$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw)
+
+ifdef CONFIG_LINUX
+QEMU_CFLAGS += -I../linux-headers
+endif
+QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 
 include $(SRC_PATH)/Makefile.objs
 
@@ -23,13 +28,7 @@ ifdef CONFIG_USER_ONLY
 QEMU_PROG=qemu-$(TARGET_ARCH2)
 else
 # system emulator name
-ifeq ($(TARGET_ARCH), i386)
-QEMU_PROG=qemu$(EXESUF)
-GUEST_GL_LIB=$(TARGET_PATH)/libGL.so.1
-else
 QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
-GUEST_GL_LIB=
-endif
 endif
 
 PROGS=$(QEMU_PROG)
@@ -39,12 +38,10 @@ ifndef CONFIG_HAIKU
 LIBS+=-lm
 endif
 
-kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
-
 config-target.h: config-target.h-timestamp
 config-target.h-timestamp: config-target.mak
 
-ifdef CONFIG_SYSTEMTAP_TRACE
+ifdef CONFIG_TRACE_SYSTEMTAP
 stap: $(QEMU_PROG).stp
 
 ifdef CONFIG_USER_ONLY
@@ -64,8 +61,7 @@ else
 stap:
 endif
 
-#all: $(PROGS) $(GUEST_GL_LIB) stap
-all: libccc.a $(GUEST_GL_LIB)
+all: $(PROGS) stap
 
 # Dummy command so that make thinks it has done something
        @true
@@ -74,16 +70,26 @@ all: libccc.a $(GUEST_GL_LIB)
 # cpu emulator library
 libobj-y = exec.o translate-all.o cpu-exec.o translate.o
 libobj-y += tcg/tcg.o tcg/optimize.o
-libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
-libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
+libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
+libobj-y += fpu/softfloat.o
 libobj-y += op_helper.o helper.o
 ifeq ($(TARGET_BASE_ARCH), i386)
 libobj-y += cpuid.o
 endif
+libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
+ifeq ($(TARGET_BASE_ARCH), sparc)
+libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
+libobj-y += cpu_init.o
+endif
+libobj-$(TARGET_SPARC) += int32_helper.o
+libobj-$(TARGET_SPARC64) += int64_helper.o
 
 libobj-y += disas.o
+libobj-$(CONFIG_TCI_DIS) += tci-dis.o
+
+tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
 
 $(libobj-y): $(GENERATED_HEADERS)
 
@@ -97,10 +103,10 @@ 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)
+op_helper.o ldst_helper.o user-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.
+# cpu_signal_handler() in user-exec.c.
 signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
 #########################################################
@@ -110,10 +116,10 @@ ifdef CONFIG_LINUX_USER
 
 $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR))
 
-QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
+QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
 obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
       elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
-      qemu-malloc.o $(oslib-obj-y)
+      user-exec.o $(oslib-obj-y)
 
 obj-$(TARGET_HAS_BFLT) += flatload.o
 
@@ -151,7 +157,7 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
 LIBS+=-lmx
 
 obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
-        gdbstub.o
+        gdbstub.o user-exec.o
 
 obj-i386-y += ioport-user.o
 
@@ -173,7 +179,7 @@ $(call set-vpath, $(SRC_PATH)/bsd-user)
 QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
 
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-        gdbstub.o uaccess.o
+        gdbstub.o uaccess.o user-exec.o
 
 obj-i386-y += ioport-user.o
 
@@ -189,71 +195,86 @@ endif #CONFIG_BSD_USER
 # System emulator target
 ifdef CONFIG_SOFTMMU
 
-obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
+obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-$(CONFIG_NO_PCI) += pci-stub.o
-obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o virtio-gpi.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
+obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
-obj-y += rwhandler.o
-obj-y += sdb.o
+obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
+obj-y += memory.o
 LIBS+=-lz
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
+
+# xen support
+obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
+obj-$(CONFIG_NO_XEN) += xen-stub.o
+
+obj-i386-$(CONFIG_XEN) += xen_platform.o
 
-# xen backend driver support
-obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+
+# HAX support
+ifeq ($(TARGET_ARCH), i386)
+ifdef CONFIG_WIN32
+obj-$(CONFIG_HAX) += \
+       hax-all.o       \
+       hax-windows.o
+endif
+endif
 
 # 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
-obj-i386-y += mc146818rtc.o i8259.o pc.o
-obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
-obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
+obj-i386-y += mc146818rtc.o pc.o
+obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
+obj-i386-$(CONFIG_KVM) += kvmclock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
-##########################################################
-# opengl library for i386 
-obj-i386-y += helper_opengl.o opengl_exec.o opengl_server.o
-##########################################################
-
-##########################################################
-# general purpose interface for i386 
-obj-i386-y += helper_gpi.o
-##########################################################
-
 # shared objects
-obj-ppc-y = ppc.o
+obj-ppc-y = ppc.o ppc_booke.o
 obj-ppc-y += vga.o
 # PREP target
-obj-ppc-y += i8259.o mc146818rtc.o
+obj-ppc-y += mc146818rtc.o
 obj-ppc-y += ppc_prep.o
 # OldWorld PowerMac
 obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
+# IBM pSeries (sPAPR)
+obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
+obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
+obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
 # 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
 # PowerPC E500 boards
-obj-ppc-y += ppce500_mpc8544ds.o
+obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-ppc-y += virtex_ml507.o
 obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
 obj-ppc-$(CONFIG_FDT) += device_tree.o
+# PowerPC OpenPIC
+obj-ppc-y += openpic.o
 
 # Xilinx PPC peripherals
 obj-ppc-y += xilinx_intc.o
@@ -261,28 +282,52 @@ obj-ppc-y += xilinx_timer.o
 obj-ppc-y += xilinx_uartlite.o
 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
+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
-obj-mips-y += vga.o i8259.o
-obj-mips-y += g364fb.o jazz_led.o
+obj-mips-y += vga.o
+obj-mips-y += jazz_led.o
 obj-mips-y += gt64xxx.o mc146818rtc.o
 obj-mips-y += cirrus_vga.o
 obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
 
 obj-microblaze-y = petalogix_s3adsp1800_mmu.o
+obj-microblaze-y += petalogix_ml605_mmu.o
 
 obj-microblaze-y += microblaze_pic_cpu.o
 obj-microblaze-y += xilinx_intc.o
 obj-microblaze-y += xilinx_timer.o
 obj-microblaze-y += xilinx_uartlite.o
 obj-microblaze-y += xilinx_ethlite.o
+obj-microblaze-y += xilinx_axidma.o
+obj-microblaze-y += xilinx_axienet.o
 
 obj-microblaze-$(CONFIG_FDT) += device_tree.o
 
 # Boards
 obj-cris-y = cris_pic_cpu.o
 obj-cris-y += cris-boot.o
-obj-cris-y += etraxfs.o axis_dev88.o
 obj-cris-y += axis_dev88.o
 
 # IO blocks
@@ -324,11 +369,16 @@ obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
 obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 obj-arm-y += mst_fpga.o mainstone.o
+obj-arm-y += z2.o
 obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
 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-arm-y += pl041.o lm4549.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
@@ -339,37 +389,20 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
 
 obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 
-obj-alpha-y = alpha_palcode.o
-
-#
-# TIZEN hw
-#
-
-# x86
-obj-i386-y += tizen-board.o
-obj-i386-y += tizen-ac97.o
-obj-i386-y += overlay.o
-obj-i386-y += brightness.o
-obj-i386-y += maru_touchscreen.o
-obj-i386-y += maru_pm.o
-obj-i386-$(CONFIG_PCI) += svcamera_pci.o
-obj-i386-$(CONFIG_LINUX) += svcamera_linux.o
-obj-i386-$(CONFIG_WIN32) += svcamera_win32.o
-
-ifdef CONFIG_FFMPEG
-obj-i386-y += maru_codec.o
-LIBS+=-lavformat -lavcodec -lavutil -lswscale -lbz2
-CFLAGS+=$(FFMPEG_CFLAGS)
-endif
-
-# arm
-# common
-
+obj-alpha-y = mc146818rtc.o
+obj-alpha-y += vga.o cirrus_vga.o
+obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
 
+obj-xtensa-y += xtensa_pic.o
+obj-xtensa-y += xtensa_sim.o
+obj-xtensa-y += xtensa_lx60.o
+obj-xtensa-y += xtensa-semi.o
+obj-xtensa-y += core-dc232b.o
+obj-xtensa-y += core-fsf.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
-monitor.o: hmp-commands.h qmp-commands.h
+monitor.o: hmp-commands.h qmp-commands-old.h
 
 $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
 
@@ -377,19 +410,28 @@ obj-y += $(addprefix ../, $(common-obj-y))
 obj-y += $(addprefix ../libdis/, $(libdis-y))
 obj-y += $(libobj-y)
 obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
+obj-y += $(addprefix ../, $(trace-obj-y))
 
-endif # CONFIG_SOFTMMU
+# Makefile for TIZEN-maru
+ifdef CONFIG_MARU
+include $(SRC_PATH)/tizen/src/Makefile.tizen
+endif
+##
 
-obj-y += $(addprefix ../, $(trace-obj-y))
-obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
+endif # CONFIG_SOFTMMU
 
-#$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
-#      $(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
+ifndef CONFIG_LINUX_USER
+ifndef CONFIG_BSD_USER
+# libcacard needs qemu-thread support, and besides is only needed by devices
+# so not requires with linux-user / bsd-user targets
+obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
+endif # CONFIG_BSD_USER
+endif # CONFIG_LINUX_USER
 
-libccc.a: $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
-       rm -f libccc.a-$(TARGET_ARCH2)
-       @$(AR) rcs libccc.a $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) 
+obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
+$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+       $(call LINK,$^)
 
 
 gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
@@ -398,40 +440,14 @@ gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
 hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 
-qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
+qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
-##########################################################
-# Build openGL
-# i386
-ifeq ($(TARGET_ARCH), i386)
-parse_gl_h: $(TARGET_PATH)/parse_gl_h.c
-       $(CC) -Wall -O2 -g $< -o $@
-
-client_stub.c server_stub.c gl_func.h: parse_gl_h
-       ./parse_gl_h
-
-opengl_exec.o: opengl_exec.c server_stub.c gl_func.h
-
-opengl_server.o: opengl_server.c opengl_exec.c
-
-helper_opengl.o: gl_func.h
-
-$(TARGET_PATH)/libGL.so.1: opengl_client.c gl_func.h
-       $(CC) -I$(TARGET_PATH) -I. -Wall -g -O2 $< -shared -o $@
-endif
-
-# arm
-#gles1_calls.o: gles1_calls.c gles2.h gles2_calls.h
-#gles2_calls.o: gles2_calls.c gles2.h gles2_calls.h
-#gles2.o: gles2.c gles2.h gles2_calls.h
-
-##########################################################
 
 clean:
        rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
-       rm -f *.d */*.d tcg/*.o ide/*.o
-       rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
-ifdef CONFIG_SYSTEMTAP_TRACE
+       rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+       rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
+ifdef CONFIG_TRACE_SYSTEMTAP
        rm -f *.stp
 endif
 
@@ -442,7 +458,7 @@ ifneq ($(STRIP),)
        $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
 endif
 endif
-ifdef CONFIG_SYSTEMTAP_TRACE
+ifdef CONFIG_TRACE_SYSTEMTAP
        $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
        $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
 endif
index 024b7736b936b9a790716a2ebfeb26ac5cd8f554..2b1e4d154e7debc46735cc0ced165651cc7f336d 100644 (file)
@@ -17,7 +17,9 @@ all: $(user-obj-y)
        @true
 
 clean:
-       rm -f *.o *.d *.a *~
+       for d in . trace; do \
+       rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \
+       done
 
 # Include automatically generated dependency files
 -include $(wildcard *.d */*.d)
old mode 100644 (file)
new mode 100755 (executable)
index 14ce8b0d0505cb361a11df5eaeba29584c0e6f4d..c7dbea076da6a6afe16dc71d6293489302e9defe 100644 (file)
@@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
     pass
 
 class QEMUMonitorProtocol:
-    def __init__(self, address):
+    def __init__(self, address, server=False):
         """
         Create a QEMUMonitorProtocol class.
 
         @param address: QEMU address, can be either a unix socket path (string)
                         or a tuple in the form ( address, port ) for a TCP
                         connection
-        @note No connection is established, this is done by the connect() method
+        @param server: server mode listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
         """
         self.__events = []
         self.__address = address
         self.__sock = self.__get_sock()
-        self.__sockfile = self.__sock.makefile()
+        if server:
+            self.__sock.bind(self.__address)
+            self.__sock.listen(1)
 
     def __get_sock(self):
         if isinstance(self.__address, tuple):
@@ -43,7 +48,18 @@ class QEMUMonitorProtocol:
             family = socket.AF_UNIX
         return socket.socket(family, socket.SOCK_STREAM)
 
-    def __json_read(self):
+    def __negotiate_capabilities(self):
+        self.__sockfile = self.__sock.makefile()
+        greeting = self.__json_read()
+        if greeting is None or not greeting.has_key('QMP'):
+            raise QMPConnectError
+        # Greeting seems ok, negotiate capabilities
+        resp = self.cmd('qmp_capabilities')
+        if "return" in resp:
+            return greeting
+        raise QMPCapabilitiesError
+
+    def __json_read(self, only_event=False):
         while True:
             data = self.__sockfile.readline()
             if not data:
@@ -51,7 +67,8 @@ class QEMUMonitorProtocol:
             resp = json.loads(data)
             if 'event' in resp:
                 self.__events.append(resp)
-                continue
+                if not only_event:
+                    continue
             return resp
 
     error = socket.error
@@ -66,14 +83,19 @@ class QEMUMonitorProtocol:
         @raise QMPCapabilitiesError if fails to negotiate capabilities
         """
         self.__sock.connect(self.__address)
-        greeting = self.__json_read()
-        if greeting is None or not greeting.has_key('QMP'):
-            raise QMPConnectError
-        # Greeting seems ok, negotiate capabilities
-        resp = self.cmd('qmp_capabilities')
-        if "return" in resp:
-            return greeting
-        raise QMPCapabilitiesError
+        return self.__negotiate_capabilities()
+
+    def accept(self):
+        """
+        Await connection from QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock, _ = self.__sock.accept()
+        return self.__negotiate_capabilities()
 
     def cmd_obj(self, qmp_cmd):
         """
@@ -106,9 +128,11 @@ class QEMUMonitorProtocol:
             qmp_cmd['id'] = id
         return self.cmd_obj(qmp_cmd)
 
-    def get_events(self):
+    def get_events(self, wait=False):
         """
         Get a list of available QMP events.
+
+        @param wait: block until an event is available (bool)
         """
         self.__sock.setblocking(0)
         try:
@@ -118,6 +142,8 @@ class QEMUMonitorProtocol:
                 # No data available
                 pass
         self.__sock.setblocking(1)
+        if not self.__events and wait:
+            self.__json_read(only_event=True)
         return self.__events
 
     def clear_events(self):
diff --git a/VERSION b/VERSION
index 930e3000bdc9aaa03a5a26831c271dd32d494f61..7dea76edb3dc51b6e5e8223e9f941a35c1e364d6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.14.1
+1.0.1
diff --git a/a.out.h b/a.out.h
index dfc104e606d9730c8f978f6b3d3da91dd85addad..33ca7f77eae0afc2f778b9f98d352743554ba294 100644 (file)
--- a/a.out.h
+++ b/a.out.h
@@ -151,7 +151,7 @@ struct external_lineno {
 #define E_FILNMLEN     14      /* # characters in a file name          */
 #define E_DIMNUM       4       /* # array dimensions in auxiliary entry */
 
-struct __attribute__((packed)) external_syment
+struct QEMU_PACKED external_syment
 {
   union {
     char e_name[E_SYMNMLEN];
diff --git a/acl.c b/acl.c
index 311dade4e25d517e371a67712741c62206321d78..e840b9b6339a635e13a8d5b4038eba7b9601ba92 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
@@ -56,8 +55,8 @@ qemu_acl *qemu_acl_init(const char *aclname)
     if (acl)
         return acl;
 
-    acl = qemu_malloc(sizeof(*acl));
-    acl->aclname = qemu_strdup(aclname);
+    acl = g_malloc(sizeof(*acl));
+    acl->aclname = g_strdup(aclname);
     /* Deny by default, so there is no window of "open
      * access" between QEMU starting, and the user setting
      * up ACLs in the monitor */
@@ -66,7 +65,7 @@ qemu_acl *qemu_acl_init(const char *aclname)
     acl->nentries = 0;
     QTAILQ_INIT(&acl->entries);
 
-    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
+    acls = g_realloc(acls, sizeof(*acls) * (nacls +1));
     acls[nacls] = acl;
     nacls++;
 
@@ -96,13 +95,13 @@ int qemu_acl_party_is_allowed(qemu_acl *acl,
 
 void qemu_acl_reset(qemu_acl *acl)
 {
-    qemu_acl_entry *entry;
+    qemu_acl_entry *entry, *next_entry;
 
     /* Put back to deny by default, so there is no window
      * of "open access" while the user re-initializes the
      * access control list */
     acl->defaultDeny = 1;
-    QTAILQ_FOREACH(entry, &acl->entries, next) {
+    QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
         QTAILQ_REMOVE(&acl->entries, entry, next);
         free(entry->match);
         free(entry);
@@ -117,8 +116,8 @@ int qemu_acl_append(qemu_acl *acl,
 {
     qemu_acl_entry *entry;
 
-    entry = qemu_malloc(sizeof(*entry));
-    entry->match = qemu_strdup(match);
+    entry = g_malloc(sizeof(*entry));
+    entry->match = g_strdup(match);
     entry->deny = deny;
 
     QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
@@ -143,8 +142,8 @@ int qemu_acl_insert(qemu_acl *acl,
         return qemu_acl_append(acl, deny, match);
 
 
-    entry = qemu_malloc(sizeof(*entry));
-    entry->match = qemu_strdup(match);
+    entry = g_malloc(sizeof(*entry));
+    entry->match = g_strdup(match);
     entry->deny = deny;
 
     QTAILQ_FOREACH(tmp, &acl->entries, next) {
diff --git a/aio.c b/aio.c
index 2f086557b6673fd1a6d8b7fe8ff322c9a53bbf18..1239ca7bd2ad37bed6b51d33d7f35f60571d8552 100644 (file)
--- a/aio.c
+++ b/aio.c
@@ -75,13 +75,13 @@ int qemu_aio_set_fd_handler(int fd,
                  * releasing the walking_handlers lock.
                  */
                 QLIST_REMOVE(node, node);
-                qemu_free(node);
+                g_free(node);
             }
         }
     } else {
         if (node == NULL) {
             /* Alloc and insert if it's not already there */
-            node = qemu_mallocz(sizeof(AioHandler));
+            node = g_malloc0(sizeof(AioHandler));
             node->fd = fd;
             QLIST_INSERT_HEAD(&aio_handlers, node, node);
         }
@@ -220,7 +220,7 @@ void qemu_aio_wait(void)
 
                 if (tmp->deleted) {
                     QLIST_REMOVE(tmp, node);
-                    qemu_free(tmp);
+                    g_free(tmp);
                 }
             }
 
index 8a2411e4d56d9e6ef90ea4db972a48d79da113bd..ae331b35b8f0836be907e59affbb94abebb44e67 100644 (file)
@@ -238,10 +238,6 @@ extern const unsigned alpha_num_operands;
 #define AXP_REG_SP     30
 #define AXP_REG_ZERO   31
 
-#define bfd_mach_alpha_ev4  0x10
-#define bfd_mach_alpha_ev5  0x20
-#define bfd_mach_alpha_ev6  0x30
-
 enum bfd_reloc_code_real {
     BFD_RELOC_23_PCREL_S2,
     BFD_RELOC_ALPHA_HINT
index ba59a61379a26f3d2e3f04e517a15546947936fa..7995c27de6526cb5bc90db6a74b5b08054e419cd 100644 (file)
@@ -64,6 +64,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_I386
 #elif defined(TARGET_M68K)
 #define QEMU_ARCH QEMU_ARCH_M68K
+#elif defined(TARGET_LM32)
+#define QEMU_ARCH QEMU_ARCH_LM32
 #elif defined(TARGET_MICROBLAZE)
 #define QEMU_ARCH QEMU_ARCH_MICROBLAZE
 #elif defined(TARGET_MIPS)
@@ -76,6 +78,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XTENSA)
+#define QEMU_ARCH QEMU_ARCH_XTENSA
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
@@ -233,7 +237,7 @@ static void sort_ram_list(void)
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         ++n;
     }
-    blocks = qemu_malloc(n * sizeof *blocks);
+    blocks = g_malloc(n * sizeof *blocks);
     n = 0;
     QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
         blocks[n++] = block;
@@ -243,7 +247,7 @@ static void sort_ram_list(void)
     while (--n >= 0) {
         QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
     }
-    qemu_free(blocks);
+    g_free(blocks);
 }
 
 int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
@@ -252,6 +256,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
     uint64_t bytes_transferred_last;
     double bwidth = 0;
     uint64_t expected_time = 0;
+    int ret;
 
     if (stage < 0) {
         cpu_physical_memory_set_dirty_tracking(0);
@@ -259,8 +264,8 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
     }
 
     if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
-        qemu_file_set_error(f);
-        return 0;
+        qemu_file_set_error(f, -EINVAL);
+        return -EINVAL;
     }
 
     if (stage == 1) {
@@ -296,17 +301,20 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
     bytes_transferred_last = bytes_transferred;
     bwidth = qemu_get_clock_ns(rt_clock);
 
-    while (!qemu_file_rate_limit(f)) {
+    while ((ret = qemu_file_rate_limit(f)) == 0) {
         int bytes_sent;
 
         bytes_sent = ram_save_block(f);
         bytes_transferred += bytes_sent;
-               monitor_printf(mon, "Completed=%f\n",(float)bytes_transferred/(float)ram_bytes_total());
         if (bytes_sent == 0) { /* no more blocks */
             break;
         }
     }
 
+    if (ret < 0) {
+        return ret;
+    }
+
     bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
     bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
 
@@ -368,6 +376,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
 {
     ram_addr_t addr;
     int flags;
+    int error;
 
     if (version_id < 3 || version_id > 4) {
         return -EINVAL;
@@ -448,19 +457,15 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
 
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
         }
-        if (qemu_file_has_error(f)) {
-            return -EIO;
+        error = qemu_file_get_error(f);
+        if (error) {
+            return error;
         }
     } while (!(flags & RAM_SAVE_FLAG_EOS));
 
     return 0;
 }
 
-void qemu_service_io(void)
-{
-    qemu_notify_event();
-}
-
 #ifdef HAS_AUDIO
 struct soundhw {
     const char *name;
@@ -708,6 +713,11 @@ int audio_available(void)
 #endif
 }
 
+int tcg_available(void)
+{
+    return 1;
+}
+
 int kvm_available(void)
 {
 #ifdef CONFIG_KVM
@@ -725,3 +735,12 @@ int xen_available(void)
     return 0;
 #endif
 }
+
+int hax_available(void)
+{
+#ifdef CONFIG_HAX
+    return 1;
+#else
+    return 0;
+#endif
+}
index 17c9164d394bbb64fb91103eb546ceb57a853d83..f5387585148784f3283239b0400913d4fa56cf00 100644 (file)
@@ -10,25 +10,26 @@ enum {
     QEMU_ARCH_CRIS = 4,
     QEMU_ARCH_I386 = 8,
     QEMU_ARCH_M68K = 16,
-    QEMU_ARCH_MICROBLAZE = 32,
-    QEMU_ARCH_MIPS = 64,
-    QEMU_ARCH_PPC = 128,
-    QEMU_ARCH_S390X = 256,
-    QEMU_ARCH_SH4 = 512,
-    QEMU_ARCH_SPARC = 1024,
+    QEMU_ARCH_LM32 = 32,
+    QEMU_ARCH_MICROBLAZE = 64,
+    QEMU_ARCH_MIPS = 128,
+    QEMU_ARCH_PPC = 256,
+    QEMU_ARCH_S390X = 512,
+    QEMU_ARCH_SH4 = 1024,
+    QEMU_ARCH_SPARC = 2048,
+    QEMU_ARCH_XTENSA = 4096,
 };
 
 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);
 int audio_available(void);
 void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus);
+int tcg_available(void);
 int kvm_available(void);
 int xen_available(void);
-
+int hax_available(void);
 #endif
index 1d5179b601e7419a80213612bb28c6f85727fcac..873518a20e9fb7c500f245e095d638c553363429 100644 (file)
@@ -33,8 +33,8 @@
 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "gdbstub.h"
+#include "hw/arm-misc.h"
 #endif
 
 #define SYS_OPEN        0x01
@@ -370,68 +370,88 @@ uint32_t do_arm_semihosting(CPUState *env)
         return syscall_err;
 #endif
     case SYS_GET_CMDLINE:
-#ifdef CONFIG_USER_ONLY
-        /* Build a commandline from the original argv.  */
         {
-            char *arm_cmdline_buffer;
-            const char *host_cmdline_buffer;
+            /* Build a command-line from the original argv.
+             *
+             * The inputs are:
+             *     * ARG(0), pointer to a buffer of at least the size
+             *               specified in ARG(1).
+             *     * ARG(1), size of the buffer pointed to by ARG(0) in
+             *               bytes.
+             *
+             * The outputs are:
+             *     * ARG(0), pointer to null-terminated string of the
+             *               command line.
+             *     * ARG(1), length of the string pointed to by ARG(0).
+             */
 
-            unsigned int i;
-            unsigned int arm_cmdline_len = ARG(1);
-            unsigned int host_cmdline_len =
-                ts->info->arg_end-ts->info->arg_start;
+            char *output_buffer;
+            size_t input_size = ARG(1);
+            size_t output_size;
+            int status = 0;
 
-            if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
-                return -1; /* not enough space to store command line */
-            }
+            /* Compute the size of the output string.  */
+#if !defined(CONFIG_USER_ONLY)
+            output_size = strlen(ts->boot_info->kernel_filename)
+                        + 1  /* Separating space.  */
+                        + strlen(ts->boot_info->kernel_cmdline)
+                        + 1; /* Terminating null byte.  */
+#else
+            unsigned int i;
 
-            if (!host_cmdline_len) {
+            output_size = ts->info->arg_end - ts->info->arg_start;
+            if (!output_size) {
                 /* We special-case the "empty command line" case (argc==0).
                    Just provide the terminating 0. */
-                arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
-                arm_cmdline_buffer[0] = 0;
-                unlock_user(arm_cmdline_buffer, ARG(0), 1);
+                output_size = 1;
+            }
+#endif
 
-                /* Adjust the commandline length argument. */
-                SET_ARG(1, 0);
-                return 0;
+            if (output_size > input_size) {
+                 /* Not enough space to store command-line arguments.  */
+                return -1;
             }
 
-            /* lock the buffers on the ARM side */
-            arm_cmdline_buffer =
-                lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0);
-            host_cmdline_buffer =
-                lock_user(VERIFY_READ, ts->info->arg_start,
-                                       host_cmdline_len, 1);
+            /* Adjust the command-line length.  */
+            SET_ARG(1, output_size - 1);
 
-            if (arm_cmdline_buffer && host_cmdline_buffer)
-            {
-                /* the last argument is zero-terminated;
-                   no need for additional termination */
-                memcpy(arm_cmdline_buffer, host_cmdline_buffer,
-                       host_cmdline_len);
+            /* Lock the buffer on the ARM side.  */
+            output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0);
+            if (!output_buffer) {
+                return -1;
+            }
 
-                /* separate arguments by white spaces */
-                for (i = 0; i < host_cmdline_len-1; i++) {
-                    if (arm_cmdline_buffer[i] == 0) {
-                        arm_cmdline_buffer[i] = ' ';
-                    }
-                }
+            /* Copy the command-line arguments.  */
+#if !defined(CONFIG_USER_ONLY)
+            pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
+            pstrcat(output_buffer, output_size, " ");
+            pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
+#else
+            if (output_size == 1) {
+                /* Empty command-line.  */
+                output_buffer[0] = '\0';
+                goto out;
+            }
 
-                /* Adjust the commandline length argument. */
-                SET_ARG(1, host_cmdline_len-1);
+            if (copy_from_user(output_buffer, ts->info->arg_start,
+                               output_size)) {
+                status = -1;
+                goto out;
             }
 
-            /* Unlock the buffers on the ARM side.  */
-            unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len);
-            unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0);
+            /* Separate arguments by white spaces.  */
+            for (i = 0; i < output_size - 1; i++) {
+                if (output_buffer[i] == 0) {
+                    output_buffer[i] = ' ';
+                }
+            }
+        out:
+#endif
+            /* Unlock the buffer on the ARM side.  */
+            unlock_user(output_buffer, ARG(0), output_size);
 
-            /* Return success if we could return a commandline.  */
-            return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1;
+            return status;
         }
-#else
-        return -1;
-#endif
     case SYS_HEAPINFO:
         {
             uint32_t *ptr;
@@ -441,15 +461,16 @@ uint32_t do_arm_semihosting(CPUState *env)
             /* Some C libraries assume the heap immediately follows .bss, so
                allocate it using sbrk.  */
             if (!ts->heap_limit) {
-                long ret;
+                abi_ulong ret;
 
                 ts->heap_base = do_brk(0);
                 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
                 /* Try a big heap, and reduce the size if that fails.  */
                 for (;;) {
                     ret = do_brk(limit);
-                    if (ret != -1)
+                    if (ret >= limit) {
                         break;
+                    }
                     limit = (ts->heap_base >> 1) + (limit >> 1);
                 }
                 ts->heap_limit = limit;
diff --git a/arm.ld b/arm.ld
index 12b3edb5bbe66ea94f96678eb92807cf2253de93..7f13da9ebbc6bd8ec2de1c4319fb7ad4f10829a9 100644 (file)
--- a/arm.ld
+++ b/arm.ld
@@ -71,23 +71,23 @@ SECTIONS
   .data1   : { *(.data1) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors         :
   {
diff --git a/async.c b/async.c
index 57ac3a818032811ecccf2e3adbec63b4afc71596..332d511ed5e138fd27a7cecc0ee42ba1450a9605 100644 (file)
--- a/async.c
+++ b/async.c
 
 #include "qemu-common.h"
 #include "qemu-aio.h"
+#include "main-loop.h"
 
-/*
- * An AsyncContext protects the callbacks of AIO requests and Bottom Halves
- * against interfering with each other. A typical example is qcow2 that accepts
- * asynchronous requests, but relies for manipulation of its metadata on
- * synchronous bdrv_read/write that doesn't trigger any callbacks.
- *
- * However, these functions are often emulated using AIO which means that AIO
- * callbacks must be run - but at the same time we must not run callbacks of
- * other requests as they might start to modify metadata and corrupt the
- * internal state of the caller of bdrv_read/write.
- *
- * To achieve the desired semantics we switch into a new AsyncContext.
- * Callbacks must only be run if they belong to the current AsyncContext.
- * Otherwise they need to be queued until their own context is active again.
- * This is how you can make qemu_aio_wait() wait only for your own callbacks.
- *
- * The AsyncContexts form a stack. When you leave a AsyncContexts, you always
- * return to the old ("parent") context.
- */
-struct AsyncContext {
-    /* Consecutive number of the AsyncContext (position in the stack) */
-    int id;
-
-    /* Anchor of the list of Bottom Halves belonging to the context */
-    struct QEMUBH *first_bh;
-
-    /* Link to parent context */
-    struct AsyncContext *parent;
-};
-
-/* The currently active AsyncContext */
-static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
-
-/*
- * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
- * won't be called until this context is left again.
- */
-void async_context_push(void)
-{
-    struct AsyncContext *new = qemu_mallocz(sizeof(*new));
-    new->parent = async_context;
-    new->id = async_context->id + 1;
-    async_context = new;
-}
-
-/* Run queued AIO completions and destroy Bottom Half */
-static void bh_run_aio_completions(void *opaque)
-{
-    QEMUBH **bh = opaque;
-    qemu_bh_delete(*bh);
-    qemu_free(bh);
-    qemu_aio_process_queue();
-}
-/*
- * Leave the currently active AsyncContext. All Bottom Halves belonging to the
- * old context are executed before changing the context.
- */
-void async_context_pop(void)
-{
-    struct AsyncContext *old = async_context;
-    QEMUBH **bh;
-
-    /* Flush the bottom halves, we don't want to lose them */
-    while (qemu_bh_poll());
-
-    /* Switch back to the parent context */
-    async_context = async_context->parent;
-    qemu_free(old);
-
-    if (async_context == NULL) {
-        abort();
-    }
-
-    /* Schedule BH to run any queued AIO completions as soon as possible */
-    bh = qemu_malloc(sizeof(*bh));
-    *bh = qemu_bh_new(bh_run_aio_completions, bh);
-    qemu_bh_schedule(*bh);
-}
-
-/*
- * Returns the ID of the currently active AsyncContext
- */
-int get_async_context_id(void)
-{
-    return async_context->id;
-}
+/* Anchor of the list of Bottom Halves belonging to the context */
+static struct QEMUBH *first_bh;
 
 /***********************************************************/
 /* bottom halves (can be seen as timers which expire ASAP) */
@@ -127,21 +44,25 @@ struct QEMUBH {
 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
 {
     QEMUBH *bh;
-    bh = qemu_mallocz(sizeof(QEMUBH));
+    bh = g_malloc0(sizeof(QEMUBH));
     bh->cb = cb;
     bh->opaque = opaque;
-    bh->next = async_context->first_bh;
-    async_context->first_bh = bh;
+    bh->next = first_bh;
+    first_bh = bh;
     return bh;
 }
 
 int qemu_bh_poll(void)
 {
-    QEMUBH *bh, **bhp;
+    QEMUBH *bh, **bhp, *next;
     int ret;
+    static int nesting = 0;
+
+    nesting++;
 
     ret = 0;
-    for (bh = async_context->first_bh; bh; bh = bh->next) {
+    for (bh = first_bh; bh; bh = next) {
+        next = bh->next;
         if (!bh->deleted && bh->scheduled) {
             bh->scheduled = 0;
             if (!bh->idle)
@@ -151,15 +72,20 @@ int qemu_bh_poll(void)
         }
     }
 
+    nesting--;
+
     /* remove deleted bhs */
-    bhp = &async_context->first_bh;
-    while (*bhp) {
-        bh = *bhp;
-        if (bh->deleted) {
-            *bhp = bh->next;
-            qemu_free(bh);
-        } else
-            bhp = &bh->next;
+    if (!nesting) {
+        bhp = &first_bh;
+        while (*bhp) {
+            bh = *bhp;
+            if (bh->deleted) {
+                *bhp = bh->next;
+                g_free(bh);
+            } else {
+                bhp = &bh->next;
+            }
+        }
     }
 
     return ret;
@@ -198,7 +124,7 @@ void qemu_bh_update_timeout(int *timeout)
 {
     QEMUBH *bh;
 
-    for (bh = async_context->first_bh; bh; bh = bh->next) {
+    for (bh = first_bh; bh; bh = bh->next) {
         if (!bh->deleted && bh->scheduled) {
             if (bh->idle) {
                 /* idle bottom halves will be polled at least
index 4d720146df02ad22700b53e4bd04e5436566edaf..cb45b49c2ae44cbf5087c14da59bee64311bfab4 100644 (file)
@@ -136,7 +136,7 @@ static void alsa_fini_poll (struct pollhlp *hlp)
         for (i = 0; i < hlp->count; ++i) {
             qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
         }
-        qemu_free (pfds);
+        g_free (pfds);
     }
     hlp->pfds = NULL;
     hlp->count = 0;
@@ -260,7 +260,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
     if (err < 0) {
         alsa_logerr (err, "Could not initialize poll mode\n"
                      "Could not obtain poll descriptors\n");
-        qemu_free (pfds);
+        g_free (pfds);
         return -1;
     }
 
@@ -288,7 +288,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
             while (i--) {
                 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
             }
-            qemu_free (pfds);
+            g_free (pfds);
             return -1;
         }
     }
@@ -816,7 +816,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 
     if (alsa->pcm_buf) {
-        qemu_free (alsa->pcm_buf);
+        g_free (alsa->pcm_buf);
         alsa->pcm_buf = NULL;
     }
 }
@@ -979,7 +979,7 @@ static void alsa_fini_in (HWVoiceIn *hw)
     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 
     if (alsa->pcm_buf) {
-        qemu_free (alsa->pcm_buf);
+        g_free (alsa->pcm_buf);
         alsa->pcm_buf = NULL;
     }
 }
index 1729c0be2c989f43c9d40cdcd7d04150b47a13cf..cf1a30e074ea1fe0e6ad292a389aa49309f27500 100644 (file)
 #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
 
 
+#ifdef CONFIG_MARU
+#include "../tizen/src/debug_ch.h"
+MULTI_DEBUG_CHANNEL(tizen, qemu_audio);
+#endif
+
 /* Order of CONFIG_AUDIO_DRIVERS is import.
    The 1st one is the one used by default, that is the reason
     that we generate the list.
@@ -196,7 +201,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
         return NULL;
     }
 
-    return qemu_mallocz (len);
+    return g_malloc0 (len);
 }
 
 static char *audio_alloc_prefix (const char *s)
@@ -210,7 +215,7 @@ static char *audio_alloc_prefix (const char *s)
     }
 
     len = strlen (s);
-    r = qemu_malloc (len + sizeof (qemu_prefix));
+    r = g_malloc (len + sizeof (qemu_prefix));
 
     u = r + sizeof (qemu_prefix) - 1;
 
@@ -339,11 +344,15 @@ void AUD_vlog (const char *cap, const char *fmt, va_list ap)
         monitor_vprintf(default_mon, fmt, ap);
     }
     else {
+#ifdef CONFIG_MARU
+        TRACE(fmt, ap);
+#else
         if (cap) {
             fprintf (stderr, "%s: ", cap);
         }
 
         vfprintf (stderr, fmt, ap);
+#endif
     }
 }
 
@@ -425,7 +434,7 @@ static void audio_print_options (const char *prefix,
         printf ("    %s\n", opt->descr);
     }
 
-    qemu_free (uprefix);
+    g_free (uprefix);
 }
 
 static void audio_process_options (const char *prefix,
@@ -462,7 +471,7 @@ static void audio_process_options (const char *prefix,
          * (includes trailing zero) + zero + underscore (on behalf of
          * sizeof) */
         optlen = len + preflen + sizeof (qemu_prefix) + 1;
-        optname = qemu_malloc (optlen);
+        optname = g_malloc (optlen);
 
         pstrcpy (optname, optlen, qemu_prefix);
 
@@ -507,7 +516,7 @@ static void audio_process_options (const char *prefix,
             opt->overriddenp = &opt->overridden;
         }
         *opt->overriddenp = !def;
-        qemu_free (optname);
+        g_free (optname);
     }
 }
 
@@ -778,7 +787,7 @@ static void audio_detach_capture (HWVoiceOut *hw)
 
         QLIST_REMOVE (sw, entries);
         QLIST_REMOVE (sc, entries);
-        qemu_free (sc);
+        g_free (sc);
         if (was_active) {
             /* We have removed soft voice from the capture:
                this might have changed the overall status of the capture
@@ -818,7 +827,7 @@ static int audio_attach_capture (HWVoiceOut *hw)
         sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
         if (!sw->rate) {
             dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
-            qemu_free (sw);
+            g_free (sw);
             return -1;
         }
         QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
@@ -1114,7 +1123,7 @@ static int audio_is_timer_needed (void)
 static void audio_reset_timer (AudioState *s)
 {
     if (audio_is_timer_needed ()) {
-        qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
+        qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1);
     }
     else {
         qemu_del_timer (s->ts);
@@ -1743,7 +1752,7 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
 }
 
 static void audio_vm_change_state_handler (void *opaque, int running,
-                                           int reason)
+                                           RunState state)
 {
     AudioState *s = opaque;
     HWVoiceOut *hwo = NULL;
@@ -1820,7 +1829,7 @@ static void audio_init (void)
     QLIST_INIT (&s->cap_head);
     atexit (audio_atexit);
 
-    s->ts = qemu_new_timer (vm_clock, audio_timer, s);
+    s->ts = qemu_new_timer_ns (vm_clock, audio_timer, s);
     if (!s->ts) {
         hw_error("Could not create audio timer\n");
     }
@@ -1872,6 +1881,31 @@ static void audio_init (void)
         }
     }
 
+#ifdef CONFIG_MARU
+// Try to avoid certain wave out locking action in recent Windows...
+// If wave out is locked (because nothing is wired to output jack, ...),
+// QEMU can find voice out device, but open will failed. And it will cause guest audio lock-up.
+// So, we test whether opening is success or not.
+// It can not prevent lock-up caused by runtime voice out lock.
+// To prevent it, QEMU audio backend structure must be changed.
+// We should do it, but now we used simple fix temporarily.
+    HWVoiceOut* hw = audio_calloc(AUDIO_FUNC, 1, s->drv->voice_size_out);
+    if (!hw) {
+        dolog ("Can not allocate voice `%s' size %d\n",
+               s->drv->name, s->drv->voice_size_out);
+    }
+    if(s->drv->pcm_ops->init_out(hw, &conf.fixed_out.settings)) {
+        INFO("Host audio out [%s] is malfunction. Change to noaudio driver\n",
+                s->drv->name);
+        done = 0;
+    }
+    else {
+        INFO("Host audio out [%s] is normal.\n", s->drv->name);
+        s->drv->pcm_ops->fini_out(hw);
+    }
+    g_free(hw);
+#endif
+
     if (!done) {
         done = !audio_driver_init (s, &no_audio_driver);
         if (!done) {
@@ -1907,7 +1941,7 @@ static void audio_init (void)
 void AUD_register_card (const char *name, QEMUSoundCard *card)
 {
     audio_init ();
-    card->name = qemu_strdup (name);
+    card->name = g_strdup (name);
     memset (&card->entries, 0, sizeof (card->entries));
     QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
 }
@@ -1915,7 +1949,7 @@ void AUD_register_card (const char *name, QEMUSoundCard *card)
 void AUD_remove_card (QEMUSoundCard *card)
 {
     QLIST_REMOVE (card, entries);
-    qemu_free (card->name);
+    g_free (card->name);
 }
 
 
@@ -2000,11 +2034,11 @@ CaptureVoiceOut *AUD_add_capture (
         return cap;
 
     err3:
-        qemu_free (cap->hw.mix_buf);
+        g_free (cap->hw.mix_buf);
     err2:
-        qemu_free (cap);
+        g_free (cap);
     err1:
-        qemu_free (cb);
+        g_free (cb);
     err0:
         return NULL;
     }
@@ -2018,7 +2052,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
         if (cb->opaque == cb_opaque) {
             cb->ops.destroy (cb_opaque);
             QLIST_REMOVE (cb, entries);
-            qemu_free (cb);
+            g_free (cb);
 
             if (!cap->cb_head.lh_first) {
                 SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
@@ -2036,11 +2070,11 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
                     }
                     QLIST_REMOVE (sw, entries);
                     QLIST_REMOVE (sc, entries);
-                    qemu_free (sc);
+                    g_free (sc);
                     sw = sw1;
                 }
                 QLIST_REMOVE (cap, entries);
-                qemu_free (cap);
+                g_free (cap);
             }
             return;
         }
index 908c569a92031398d0e8150239c18fd47982f108..9a9c306a9cd52d8de6ef1e9f7ee9548d7dfa0b65 100644 (file)
@@ -6,8 +6,6 @@
 #include "audio_int.h"
 #include "audio_pt_int.h"
 
-#include <signal.h>
-
 static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
                                        const char *fmt, ...)
 {
index fd4469e6380ddd131d63d8393f46f9b54951d5db..e62a71345e4b72a04defc8dafbf46390f78233e1 100644 (file)
@@ -72,7 +72,7 @@ static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
 static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
 {
     if (HWBUF) {
-        qemu_free (HWBUF);
+        g_free (HWBUF);
     }
 
     HWBUF = NULL;
@@ -93,7 +93,7 @@ static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
 static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 {
     if (sw->buf) {
-        qemu_free (sw->buf);
+        g_free (sw->buf);
     }
 
     if (sw->rate) {
@@ -123,7 +123,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
     sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
 #endif
     if (!sw->rate) {
-        qemu_free (sw->buf);
+        g_free (sw->buf);
         sw->buf = NULL;
         return -1;
     }
@@ -160,10 +160,10 @@ static int glue (audio_pcm_sw_init_, TYPE) (
         [sw->info.swap_endianness]
         [audio_bits_to_index (sw->info.bits)];
 
-    sw->name = qemu_strdup (name);
+    sw->name = g_strdup (name);
     err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
     if (err) {
-        qemu_free (sw->name);
+        g_free (sw->name);
         sw->name = NULL;
     }
     return err;
@@ -173,7 +173,7 @@ static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
 {
     glue (audio_pcm_sw_free_resources_, TYPE) (sw);
     if (sw->name) {
-        qemu_free (sw->name);
+        g_free (sw->name);
         sw->name = NULL;
     }
 }
@@ -201,7 +201,7 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
         glue (s->nb_hw_voices_, TYPE) += 1;
         glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
         glue (hw->pcm_ops->fini_, TYPE) (hw);
-        qemu_free (hw);
+        g_free (hw);
         *hwp = NULL;
     }
 }
@@ -300,7 +300,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
  err1:
     glue (hw->pcm_ops->fini_, TYPE) (hw);
  err0:
-    qemu_free (hw);
+    g_free (hw);
     return NULL;
 }
 
@@ -368,7 +368,7 @@ err3:
     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
     glue (audio_pcm_hw_gc_, TYPE) (&hw);
 err2:
-    qemu_free (sw);
+    g_free (sw);
 err1:
     return NULL;
 }
@@ -378,7 +378,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
     glue (audio_pcm_sw_fini_, TYPE) (sw);
     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
     glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
-    qemu_free (sw);
+    g_free (sw);
 }
 
 void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
index 0a26413d75d012bb095cf23e1cb4c90009b5236c..5964c62eafc6d8b7a5325d467faeb66448eb178d 100644 (file)
@@ -56,7 +56,7 @@ typedef struct coreaudioVoiceOut {
 
 static void coreaudio_logstatus (OSStatus status)
 {
-    char *str = "BUG";
+    const char *str = "BUG";
 
     switch(status) {
     case kAudioHardwareNoError:
@@ -104,7 +104,7 @@ static void coreaudio_logstatus (OSStatus status)
         break;
 
     default:
-        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+        AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
         return;
     }
 
@@ -360,8 +360,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
         &core->audioDevicePropertyBufferFrameSize);
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ,
-                           "Could not set device buffer frame size %ld\n",
-                           core->audioDevicePropertyBufferFrameSize);
+                           "Could not set device buffer frame size %" PRIu32 "\n",
+                           (uint32_t)core->audioDevicePropertyBufferFrameSize);
         return -1;
     }
 
index ff97b397d20038a5e41fca5ff6fa4b584a665026..bd6e1cc19b1148a3bfd48bf3479f290418779d45 100644 (file)
@@ -246,7 +246,7 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
     esd->fd = -1;
 
  fail1:
-    qemu_free (esd->pcm_buf);
+    g_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
     return -1;
 }
@@ -270,7 +270,7 @@ static void qesd_fini_out (HWVoiceOut *hw)
 
     audio_pt_fini (&esd->pt, AUDIO_FUNC);
 
-    qemu_free (esd->pcm_buf);
+    g_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
 }
 
@@ -453,7 +453,7 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
     esd->fd = -1;
 
  fail1:
-    qemu_free (esd->pcm_buf);
+    g_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
     return -1;
 }
@@ -477,7 +477,7 @@ static void qesd_fini_in (HWVoiceIn *hw)
 
     audio_pt_fini (&esd->pt, AUDIO_FUNC);
 
-    qemu_free (esd->pcm_buf);
+    g_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
 }
 
index c34cf535674abee262859bcf675b16ccfdebbb44..fabf84dd3b89e2e30a7fac139a600e965fd4f9be 100644 (file)
@@ -343,7 +343,7 @@ static void fmod_fini_out (HWVoiceOut *hw)
 
 static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
-    int bits16, mode, channel;
+    int mode, channel;
     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
     struct audsettings obt_as = *as;
 
@@ -374,7 +374,6 @@ static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
     /* FMOD always operates on little endian frames? */
     obt_as.endianness = 0;
     audio_pcm_init_info (&hw->info, &obt_as);
-    bits16 = (mode & FSOUND_16BITS) != 0;
     hw->samples = conf.nb_samples;
     return 0;
 }
@@ -405,7 +404,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
 
 static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
-    int bits16, mode;
+    int mode;
     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
     struct audsettings obt_as = *as;
 
@@ -432,7 +431,6 @@ static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
     /* FMOD always operates on little endian frames? */
     obt_as.endianness = 0;
     audio_pcm_init_info (&hw->info, &obt_as);
-    bits16 = (mode & FSOUND_16BITS) != 0;
     hw->samples = conf.nb_samples;
     return 0;
 }
index 4a9e8ebe2afe75cb941f9787975f26422563f12c..5446be674f9149c9695687d2d73005f5b4f473d9 100644 (file)
@@ -326,7 +326,7 @@ void *st_rate_start (int inrate, int outrate)
 
 void st_rate_stop (void *opaque)
 {
-    qemu_free (opaque);
+    g_free (opaque);
 }
 
 void mixeng_clear (struct st_sample *buf, int len)
index a2d0ef84fd86d892d89b5338e822f7de36a2e0e2..e644c231ada9e762f7262471b494cfb7893dfa1b 100644 (file)
@@ -46,7 +46,7 @@ static mixeng_real inline glue (conv_, ET) (IN_T v)
 #endif
 #else  /* !RECIPROCAL */
 #ifdef SIGNED
-    return nv / (mixeng_real) (IN_MAX - IN_MIN);
+    return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
 #else
     return (nv - HALF) / (mixeng_real) IN_MAX;
 #endif
@@ -63,7 +63,7 @@ static IN_T inline glue (clip_, ET) (mixeng_real v)
     }
 
 #ifdef SIGNED
-    return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
+    return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
 #else
     return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
 #endif
index 0304094a6ed3bb5cbca04158afa84fd4080d439d..54958f8623f18590758fb304e2db5e3bd2280234 100644 (file)
@@ -46,7 +46,7 @@ static int no_run_out (HWVoiceOut *hw, int live)
     int64_t ticks;
     int64_t bytes;
 
-    now = qemu_get_clock (vm_clock);
+    now = qemu_get_clock_ns (vm_clock);
     ticks = now - no->old_ticks;
     bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
     bytes = audio_MIN (bytes, INT_MAX);
@@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
     int samples = 0;
 
     if (dead) {
-        int64_t now = qemu_get_clock (vm_clock);
+        int64_t now = qemu_get_clock_ns (vm_clock);
         int64_t ticks = now - no->old_ticks;
         int64_t bytes =
             muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
index b49e102747737f05db7fca6347bf927df66fb28b..df51b7cc5871ffeb2974362f352c390d9e298eec 100644 (file)
@@ -508,7 +508,7 @@ static void oss_fini_out (HWVoiceOut *hw)
             }
         }
         else {
-            qemu_free (oss->pcm_buf);
+            g_free (oss->pcm_buf);
         }
         oss->pcm_buf = NULL;
     }
@@ -741,7 +741,7 @@ static void oss_fini_in (HWVoiceIn *hw)
     oss_anal_close (&oss->fd);
 
     if (oss->pcm_buf) {
-        qemu_free (oss->pcm_buf);
+        g_free (oss->pcm_buf);
         oss->pcm_buf = NULL;
     }
 }
index fb4510e426cbe8fe4e46121147497a11465845ba..d1f3912cee3d1de76fd969965b15ce4a401d4c6d 100644 (file)
@@ -339,7 +339,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
     return 0;
 
  fail3:
-    qemu_free (pa->pcm_buf);
+    g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
  fail2:
     pa_simple_free (pa->s);
@@ -394,7 +394,7 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
     return 0;
 
  fail3:
-    qemu_free (pa->pcm_buf);
+    g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
  fail2:
     pa_simple_free (pa->s);
@@ -419,7 +419,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
     }
 
     audio_pt_fini (&pa->pt, AUDIO_FUNC);
-    qemu_free (pa->pcm_buf);
+    g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
 }
 
@@ -439,7 +439,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
     }
 
     audio_pt_fini (&pa->pt, AUDIO_FUNC);
-    qemu_free (pa->pcm_buf);
+    g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
 }
 
index b74dcfa73470c9ad28097303a4b34344319d259e..d24daa5ead5eb0b813fd368a90031468777f5c18 100644 (file)
@@ -32,7 +32,6 @@
 #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
 #include <pthread.h>
 #endif
-#include <signal.h>
 #endif
 
 #define AUDIO_CAP "sdl"
@@ -139,36 +138,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 +337,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 +353,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 +362,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 a5c0d6bc660b17289c73af3d47b1a4b3b9792ca5..f972110e05c8a193dbca3c638f54f6b09efd9239 100644 (file)
@@ -81,7 +81,7 @@ static void spice_audio_fini (void *opaque)
 static void rate_start (SpiceRateCtl *rate)
 {
     memset (rate, 0, sizeof (*rate));
-    rate->start_ticks = qemu_get_clock (vm_clock);
+    rate->start_ticks = qemu_get_clock_ns (vm_clock);
 }
 
 static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
@@ -91,7 +91,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
     int64_t bytes;
     int64_t samples;
 
-    now = qemu_get_clock (vm_clock);
+    now = qemu_get_clock_ns (vm_clock);
     ticks = now - rate->start_ticks;
     bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
     samples = (bytes - rate->bytes_sent) >> info->shift;
index c522be4531f2831b44b00cf88596a59afcaad04a..a449b5127e0ade1c7aef037a1dd7b792ebc539f7 100644 (file)
@@ -30,7 +30,7 @@
 
 typedef struct WAVVoiceOut {
     HWVoiceOut hw;
-    QEMUFile *f;
+    FILE *f;
     int64_t old_ticks;
     void *pcm_buf;
     int total_samples;
@@ -52,7 +52,7 @@ static int wav_run_out (HWVoiceOut *hw, int live)
     int rpos, decr, samples;
     uint8_t *dst;
     struct st_sample *src;
-    int64_t now = qemu_get_clock (vm_clock);
+    int64_t now = qemu_get_clock_ns (vm_clock);
     int64_t ticks = now - wav->old_ticks;
     int64_t bytes =
         muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
@@ -76,7 +76,10 @@ static int wav_run_out (HWVoiceOut *hw, int live)
         dst = advance (wav->pcm_buf, rpos << hw->info.shift);
 
         hw->clip (dst, src, convert_samples);
-        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
+        if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
+            dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
+                   convert_samples << hw->info.shift, strerror (errno));
+        }
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
@@ -152,16 +155,20 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
     le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
     le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 
-    wav->f = qemu_fopen (conf.wav_path, "wb");
+    wav->f = fopen (conf.wav_path, "wb");
     if (!wav->f) {
         dolog ("Failed to open wave file `%s'\nReason: %s\n",
                conf.wav_path, strerror (errno));
-        qemu_free (wav->pcm_buf);
+        g_free (wav->pcm_buf);
         wav->pcm_buf = NULL;
         return -1;
     }
 
-    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
+        dolog ("wav_init_out: failed to write header\nReason: %s\n",
+               strerror(errno));
+        return -1;
+    }
     return 0;
 }
 
@@ -180,16 +187,35 @@ static void wav_fini_out (HWVoiceOut *hw)
     le_store (rlen, rifflen, 4);
     le_store (dlen, datalen, 4);
 
-    qemu_fseek (wav->f, 4, SEEK_SET);
-    qemu_put_buffer (wav->f, rlen, 4);
-
-    qemu_fseek (wav->f, 32, SEEK_CUR);
-    qemu_put_buffer (wav->f, dlen, 4);
+    if (fseek (wav->f, 4, SEEK_SET)) {
+        dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
+               strerror(errno));
+        goto doclose;
+    }
+    if (fwrite (rlen, 4, 1, wav->f) != 1) {
+        dolog ("wav_fini_out: failed to write rlen\nReason: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
+    if (fseek (wav->f, 32, SEEK_CUR)) {
+        dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
+    if (fwrite (dlen, 4, 1, wav->f) != 1) {
+        dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
 
-    qemu_fclose (wav->f);
+ doclose:
+    if (fclose (wav->f))  {
+        dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
+               wav->f, strerror (errno));
+    }
     wav->f = NULL;
 
-    qemu_free (wav->pcm_buf);
+    g_free (wav->pcm_buf);
     wav->pcm_buf = NULL;
 }
 
index 1f49cd1fecf0aff360a19b35130056709863c596..4f785f5f49e01e8fe3fc2913d29998d360cfd5ff 100644 (file)
@@ -3,7 +3,7 @@
 #include "audio.h"
 
 typedef struct {
-    QEMUFile *f;
+    FILE *f;
     int bytes;
     char *path;
     int freq;
@@ -35,27 +35,50 @@ static void wav_destroy (void *opaque)
     uint8_t dlen[4];
     uint32_t datalen = wav->bytes;
     uint32_t rifflen = datalen + 36;
+    Monitor *mon = cur_mon;
 
     if (wav->f) {
         le_store (rlen, rifflen, 4);
         le_store (dlen, datalen, 4);
 
-        qemu_fseek (wav->f, 4, SEEK_SET);
-        qemu_put_buffer (wav->f, rlen, 4);
-
-        qemu_fseek (wav->f, 32, SEEK_CUR);
-        qemu_put_buffer (wav->f, dlen, 4);
-        qemu_fclose (wav->f);
+        if (fseek (wav->f, 4, SEEK_SET)) {
+            monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fwrite (rlen, 4, 1, wav->f) != 1) {
+            monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fseek (wav->f, 32, SEEK_CUR)) {
+            monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fwrite (dlen, 1, 4, wav->f) != 4) {
+            monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+    doclose:
+        if (fclose (wav->f)) {
+            fprintf (stderr, "wav_destroy: fclose failed: %s",
+                     strerror (errno));
+        }
     }
 
-    qemu_free (wav->path);
+    g_free (wav->path);
 }
 
 static void wav_capture (void *opaque, void *buf, int size)
 {
     WAVState *wav = opaque;
 
-    qemu_put_buffer (wav->f, buf, size);
+    if (fwrite (buf, size, 1, wav->f) != 1) {
+        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
+                        strerror (errno));
+    }
     wav->bytes += size;
 }
 
@@ -71,9 +94,9 @@ static void wav_capture_info (void *opaque)
     WAVState *wav = opaque;
     char *path = wav->path;
 
-    monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
-                   wav->freq, wav->bits, wav->nchannels,
-                   path ? path : "<not available>", wav->bytes);
+    monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
+                    wav->freq, wav->bits, wav->nchannels,
+                    path ? path : "<not available>", wav->bytes);
 }
 
 static struct capture_ops wav_capture_ops = {
@@ -98,13 +121,13 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     CaptureVoiceOut *cap;
 
     if (bits != 8 && bits != 16) {
-        monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
+        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
         return -1;
     }
 
     if (nchannels != 1 && nchannels != 2) {
-        monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
-                       nchannels);
+        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
+                        nchannels);
         return -1;
     }
 
@@ -120,7 +143,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     ops.capture = wav_capture;
     ops.destroy = wav_destroy;
 
-    wav = qemu_mallocz (sizeof (*wav));
+    wav = g_malloc0 (sizeof (*wav));
 
     shift = bits16 + stereo;
     hdr[34] = bits16 ? 0x10 : 0x08;
@@ -130,32 +153,42 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     le_store (hdr + 28, freq << shift, 4);
     le_store (hdr + 32, 1 << shift, 2);
 
-    wav->f = qemu_fopen (path, "wb");
+    wav->f = fopen (path, "wb");
     if (!wav->f) {
-        monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
-                       path, strerror (errno));
-        qemu_free (wav);
+        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
+                        path, strerror (errno));
+        g_free (wav);
         return -1;
     }
 
-    wav->path = qemu_strdup (path);
+    wav->path = g_strdup (path);
     wav->bits = bits;
     wav->nchannels = nchannels;
     wav->freq = freq;
 
-    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
+        monitor_printf (mon, "Failed to write header\nReason: %s\n",
+                        strerror (errno));
+        goto error_free;
+    }
 
     cap = AUD_add_capture (&as, &ops, wav);
     if (!cap) {
-        monitor_printf(mon, "Failed to add audio capture\n");
-        qemu_free (wav->path);
-        qemu_fclose (wav->f);
-        qemu_free (wav);
-        return -1;
+        monitor_printf (mon, "Failed to add audio capture\n");
+        goto error_free;
     }
 
     wav->cap = cap;
     s->opaque = wav;
     s->ops = wav_capture_ops;
     return 0;
+
+error_free:
+    g_free (wav->path);
+    if (fclose (wav->f)) {
+        monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
+                        strerror (errno));
+    }
+    g_free (wav);
+    return -1;
 }
index e5ad3c66047005364ce889be6f82daf3a50eb0cf..87e7493270e541011823e759e55c19ba37a5fb3d 100644 (file)
@@ -222,9 +222,9 @@ static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
     return 0;
 
  err4:
-    qemu_free (wave->pcm_buf);
+    g_free (wave->pcm_buf);
  err3:
-    qemu_free (wave->hdrs);
+    g_free (wave->hdrs);
  err2:
     winwave_anal_close_out (wave);
  err1:
@@ -310,10 +310,10 @@ static void winwave_fini_out (HWVoiceOut *hw)
         wave->event = NULL;
     }
 
-    qemu_free (wave->pcm_buf);
+    g_free (wave->pcm_buf);
     wave->pcm_buf = NULL;
 
-    qemu_free (wave->hdrs);
+    g_free (wave->hdrs);
     wave->hdrs = NULL;
 }
 
@@ -511,9 +511,9 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
     return 0;
 
  err4:
-    qemu_free (wave->pcm_buf);
+    g_free (wave->pcm_buf);
  err3:
-    qemu_free (wave->hdrs);
+    g_free (wave->hdrs);
  err2:
     winwave_anal_close_in (wave);
  err1:
@@ -550,10 +550,10 @@ static void winwave_fini_in (HWVoiceIn *hw)
         wave->event = NULL;
     }
 
-    qemu_free (wave->pcm_buf);
+    g_free (wave->pcm_buf);
     wave->pcm_buf = NULL;
 
-    qemu_free (wave->hdrs);
+    g_free (wave->hdrs);
     wave->hdrs = NULL;
 }
 
index 0021fef4b83182c0e113f3f1b6e87138ac010e8f..e1cd5fac4c292ae1bf504926ee77ddc7dffde810 100644 (file)
--- a/balloon.c
+++ b/balloon.c
@@ -1,7 +1,9 @@
 /*
- * QEMU System Emulator
+ * Generic Balloon handlers and management
  *
  * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah@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
  * THE SOFTWARE.
  */
 
-#include "sysemu.h"
 #include "monitor.h"
-#include "qjson.h"
-#include "qint.h"
 #include "cpu-common.h"
 #include "kvm.h"
 #include "balloon.h"
 #include "trace.h"
+#include "qmp-commands.h"
 
+static QEMUBalloonEvent *balloon_event_fn;
+static QEMUBalloonStatus *balloon_stat_fn;
+static void *balloon_opaque;
 
-static QEMUBalloonEvent *qemu_balloon_event;
-void *qemu_balloon_event_opaque;
-
-void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                             QEMUBalloonStatus *stat_func, void *opaque)
 {
-    qemu_balloon_event = func;
-    qemu_balloon_event_opaque = opaque;
+    if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
+        /* We're already registered one balloon handler.  How many can
+         * a guest really have?
+         */
+        error_report("Another balloon device already registered");
+        return -1;
+    }
+    balloon_event_fn = event_func;
+    balloon_stat_fn = stat_func;
+    balloon_opaque = opaque;
+    return 0;
 }
 
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
+void qemu_remove_balloon_handler(void *opaque)
 {
-    if (qemu_balloon_event) {
-        trace_balloon_event(qemu_balloon_event_opaque, target);
-        qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
-        return 1;
-    } else {
-        return 0;
+    if (balloon_opaque != opaque) {
+        return;
     }
+    balloon_event_fn = NULL;
+    balloon_stat_fn = NULL;
+    balloon_opaque = NULL;
 }
 
-int qemu_balloon_status(MonitorCompletion cb, void *opaque)
+static int qemu_balloon(ram_addr_t target)
 {
-    if (qemu_balloon_event) {
-        qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
-        return 1;
-    } else {
+    if (!balloon_event_fn) {
         return 0;
     }
+    trace_balloon_event(balloon_opaque, target);
+    balloon_event_fn(balloon_opaque, target);
+    return 1;
 }
 
-static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
+static int qemu_balloon_status(BalloonInfo *info)
 {
-    Monitor *mon = opaque;
-
-    if (strcmp(key, "actual"))
-        monitor_printf(mon, ",%s=%" PRId64, key,
-                       qint_get_int(qobject_to_qint(obj)));
-}
-
-void monitor_print_balloon(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-    if (!qdict_haskey(qdict, "actual"))
-        return;
-
-    monitor_printf(mon, "balloon: actual=%" PRId64,
-                   qdict_get_int(qdict, "actual") >> 20);
-    qdict_iter(qdict, print_balloon_stat, mon);
-    monitor_printf(mon, "\n");
+    if (!balloon_stat_fn) {
+        return 0;
+    }
+    balloon_stat_fn(balloon_opaque, info);
+    return 1;
 }
 
-/**
- * do_info_balloon(): Balloon information
- *
- * Make an asynchronous request for balloon info.  When the request completes
- * a QDict will be returned according to the following specification:
- *
- * - "actual": current balloon value in bytes
- * The following fields may or may not be present:
- * - "mem_swapped_in": Amount of memory swapped in (bytes)
- * - "mem_swapped_out": Amount of memory swapped out (bytes)
- * - "major_page_faults": Number of major faults
- * - "minor_page_faults": Number of minor faults
- * - "free_mem": Total amount of free and unused memory (bytes)
- * - "total_mem": Total amount of available memory (bytes)
- *
- * Example:
- *
- * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
- *   "major_page_faults": 142, "minor_page_faults": 239245,
- *   "free_mem": 1014185984, "total_mem": 1044668416 }
- */
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
+BalloonInfo *qmp_query_balloon(Error **errp)
 {
-    int ret;
+    BalloonInfo *info;
 
     if (kvm_enabled() && !kvm_has_sync_mmu()) {
-        qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
-        return -1;
+        error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+        return NULL;
     }
 
-    ret = qemu_balloon_status(cb, opaque);
-    if (!ret) {
-        qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
-        return -1;
+    info = g_malloc0(sizeof(*info));
+
+    if (qemu_balloon_status(info) == 0) {
+        error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
+        qapi_free_BalloonInfo(info);
+        return NULL;
     }
 
-    return 0;
+    return info;
 }
 
 /**
@@ -130,6 +106,7 @@ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
 int do_balloon(Monitor *mon, const QDict *params,
               MonitorCompletion cb, void *opaque)
 {
+    int64_t target;
     int ret;
 
     if (kvm_enabled() && !kvm_has_sync_mmu()) {
@@ -137,7 +114,12 @@ int do_balloon(Monitor *mon, const QDict *params,
         return -1;
     }
 
-    ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
+    target = qdict_get_int(params, "value");
+    if (target <= 0) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
+        return -1;
+    }
+    ret = qemu_balloon(target);
     if (ret == 0) {
         qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
         return -1;
index d478e2847503a2ebff8757a812497c9d87eb77e5..b36abeadf0547931b8e035b2b0ea4ffd66168244 100644 (file)
--- a/balloon.h
+++ b/balloon.h
 #define _QEMU_BALLOON_H
 
 #include "monitor.h"
+#include "qapi-types.h"
 
-typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
-                                MonitorCompletion cb, void *cb_data);
+typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
+typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
 
-void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                            QEMUBalloonStatus *stat_func, void *opaque);
+void qemu_remove_balloon_handler(void *opaque);
 
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
-
-int qemu_balloon_status(MonitorCompletion cb, void *opaque);
-
-void monitor_print_balloon(Monitor *mon, const QObject *data);
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
 int do_balloon(Monitor *mon, const QDict *params,
                MonitorCompletion cb, void *opaque);
 
diff --git a/bitmap.c b/bitmap.c
new file mode 100644 (file)
index 0000000..a62c8ba
--- /dev/null
+++ b/bitmap.c
@@ -0,0 +1,256 @@
+/*
+ * Bitmap Module
+ *
+ * Stolen from linux/src/lib/bitmap.c
+ *
+ * Copyright (C) 2010 Corentin Chary
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.
+ */
+
+#include "bitops.h"
+#include "bitmap.h"
+
+/*
+ * bitmaps provide an array of bits, implemented using an an
+ * array of unsigned longs.  The number of valid bits in a
+ * given bitmap does _not_ need to be an exact multiple of
+ * BITS_PER_LONG.
+ *
+ * The possible unused bits in the last, partially used word
+ * of a bitmap are 'don't care'.  The implementation makes
+ * no particular effort to keep them zero.  It ensures that
+ * their value will not affect the results of any operation.
+ * The bitmap operations that return Boolean (bitmap_empty,
+ * for example) or scalar (bitmap_weight, for example) results
+ * carefully filter out these unused bits from impacting their
+ * results.
+ *
+ * These operations actually hold to a slightly stronger rule:
+ * if you don't input any bitmaps to these ops that have some
+ * unused bits set, then they won't output any set unused bits
+ * in output bitmaps.
+ *
+ * The byte ordering of bitmaps is more natural on little
+ * endian architectures.
+ */
+
+int slow_bitmap_empty(const unsigned long *bitmap, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap[k]) {
+            return 0;
+        }
+    }
+    if (bits % BITS_PER_LONG) {
+        if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int slow_bitmap_full(const unsigned long *bitmap, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (~bitmap[k]) {
+            return 0;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int slow_bitmap_equal(const unsigned long *bitmap1,
+                      const unsigned long *bitmap2, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap1[k] != bitmap2[k]) {
+            return 0;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
+                            int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        dst[k] = ~src[k];
+    }
+
+    if (bits % BITS_PER_LONG) {
+        dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
+    }
+}
+
+int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+    unsigned long result = 0;
+
+    for (k = 0; k < nr; k++) {
+        result |= (dst[k] = bitmap1[k] & bitmap2[k]);
+    }
+    return result != 0;
+}
+
+void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+
+    for (k = 0; k < nr; k++) {
+        dst[k] = bitmap1[k] | bitmap2[k];
+    }
+}
+
+void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                     const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+
+    for (k = 0; k < nr; k++) {
+        dst[k] = bitmap1[k] ^ bitmap2[k];
+    }
+}
+
+int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+    unsigned long result = 0;
+
+    for (k = 0; k < nr; k++) {
+        result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
+    }
+    return result != 0;
+}
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
+
+void bitmap_set(unsigned long *map, int start, int nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const int size = start + nr;
+    int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+    while (nr - bits_to_set >= 0) {
+        *p |= mask_to_set;
+        nr -= bits_to_set;
+        bits_to_set = BITS_PER_LONG;
+        mask_to_set = ~0UL;
+        p++;
+    }
+    if (nr) {
+        mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+        *p |= mask_to_set;
+    }
+}
+
+void bitmap_clear(unsigned long *map, int start, int nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const int size = start + nr;
+    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+
+    while (nr - bits_to_clear >= 0) {
+        *p &= ~mask_to_clear;
+        nr -= bits_to_clear;
+        bits_to_clear = BITS_PER_LONG;
+        mask_to_clear = ~0UL;
+        p++;
+    }
+    if (nr) {
+        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+        *p &= ~mask_to_clear;
+    }
+}
+
+#define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
+
+/**
+ * bitmap_find_next_zero_area - find a contiguous aligned zero area
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @align_mask: Alignment mask for zero area
+ *
+ * The @align_mask should be one less than a power of 2; the effect is that
+ * the bit offset of all zero areas this function finds is multiples of that
+ * power of 2. A @align_mask of 0 means no alignment is required.
+ */
+unsigned long bitmap_find_next_zero_area(unsigned long *map,
+                                        unsigned long size,
+                                        unsigned long start,
+                                        unsigned int nr,
+                                        unsigned long align_mask)
+{
+    unsigned long index, end, i;
+again:
+    index = find_next_zero_bit(map, size, start);
+
+    /* Align allocation */
+    index = ALIGN_MASK(index, align_mask);
+
+    end = index + nr;
+    if (end > size) {
+        return end;
+    }
+    i = find_next_bit(map, end, index);
+    if (i < end) {
+        start = i + 1;
+        goto again;
+    }
+    return index;
+}
+
+int slow_bitmap_intersects(const unsigned long *bitmap1,
+                           const unsigned long *bitmap2, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap1[k] & bitmap2[k]) {
+            return 1;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
+            return 1;
+        }
+    }
+    return 0;
+}
diff --git a/bitmap.h b/bitmap.h
new file mode 100644 (file)
index 0000000..08755eb
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,222 @@
+/*
+ * Bitmap Module
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
+ *
+ * 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 BITMAP_H
+#define BITMAP_H
+
+#include "qemu-common.h"
+#include "bitops.h"
+
+/*
+ * The available bitmap operations and their rough meaning in the
+ * case that the bitmap is a single unsigned long are thus:
+ *
+ * Note that nbits should be always a compile time evaluable constant.
+ * Otherwise many inlines will generate horrible code.
+ *
+ * bitmap_zero(dst, nbits)                     *dst = 0UL
+ * bitmap_fill(dst, nbits)                     *dst = ~0UL
+ * bitmap_copy(dst, src, nbits)                        *dst = *src
+ * bitmap_and(dst, src1, src2, nbits)          *dst = *src1 & *src2
+ * bitmap_or(dst, src1, src2, nbits)           *dst = *src1 | *src2
+ * bitmap_xor(dst, src1, src2, nbits)          *dst = *src1 ^ *src2
+ * bitmap_andnot(dst, src1, src2, nbits)       *dst = *src1 & ~(*src2)
+ * bitmap_complement(dst, src, nbits)          *dst = ~(*src)
+ * bitmap_equal(src1, src2, nbits)             Are *src1 and *src2 equal?
+ * bitmap_intersects(src1, src2, nbits)        Do *src1 and *src2 overlap?
+ * bitmap_empty(src, nbits)                    Are all bits zero in *src?
+ * bitmap_full(src, nbits)                     Are all bits set in *src?
+ * bitmap_set(dst, pos, nbits)                 Set specified bit area
+ * bitmap_clear(dst, pos, nbits)               Clear specified bit area
+ * bitmap_find_next_zero_area(buf, len, pos, n, mask)  Find bit free area
+ */
+
+/*
+ * Also the following operations apply to bitmaps.
+ *
+ * set_bit(bit, addr)                  *addr |= bit
+ * clear_bit(bit, addr)                        *addr &= ~bit
+ * change_bit(bit, addr)               *addr ^= bit
+ * test_bit(bit, addr)                 Is bit set in *addr?
+ * test_and_set_bit(bit, addr)         Set bit and return old value
+ * test_and_clear_bit(bit, addr)       Clear bit and return old value
+ * test_and_change_bit(bit, addr)      Change bit and return old value
+ * find_first_zero_bit(addr, nbits)    Position first zero bit in *addr
+ * find_first_bit(addr, nbits)         Position first set bit in *addr
+ * find_next_zero_bit(addr, nbits, bit)        Position next zero bit in *addr >= bit
+ * find_next_bit(addr, nbits, bit)     Position next set bit in *addr >= bit
+ */
+
+#define BITMAP_LAST_WORD_MASK(nbits)                                    \
+    (                                                                   \
+        ((nbits) % BITS_PER_LONG) ?                                     \
+        (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL                       \
+        )
+
+#define DECLARE_BITMAP(name,bits)                  \
+       unsigned long name[BITS_TO_LONGS(bits)]
+
+#define small_nbits(nbits)                      \
+       ((nbits) <= BITS_PER_LONG)
+
+int slow_bitmap_empty(const unsigned long *bitmap, int bits);
+int slow_bitmap_full(const unsigned long *bitmap, int bits);
+int slow_bitmap_equal(const unsigned long *bitmap1,
+                   const unsigned long *bitmap2, int bits);
+void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
+                         int bits);
+void slow_bitmap_shift_right(unsigned long *dst,
+                          const unsigned long *src, int shift, int bits);
+void slow_bitmap_shift_left(unsigned long *dst,
+                         const unsigned long *src, int shift, int bits);
+int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                 const unsigned long *bitmap2, int bits);
+void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                 const unsigned long *bitmap2, int bits);
+void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                  const unsigned long *bitmap2, int bits);
+int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits);
+int slow_bitmap_intersects(const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+
+static inline unsigned long *bitmap_new(int nbits)
+{
+    int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+    return g_malloc0(len);
+}
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = 0UL;
+    } else {
+        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+        memset(dst, 0, len);
+    }
+}
+
+static inline void bitmap_fill(unsigned long *dst, int nbits)
+{
+    size_t nlongs = BITS_TO_LONGS(nbits);
+    if (!small_nbits(nbits)) {
+        int len = (nlongs - 1) * sizeof(unsigned long);
+        memset(dst, 0xff,  len);
+    }
+    dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
+                               int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src;
+    } else {
+        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+        memcpy(dst, src, len);
+    }
+}
+
+static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
+                             const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return (*dst = *src1 & *src2) != 0;
+    }
+    return slow_bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src1 | *src2;
+    } else {
+        slow_bitmap_or(dst, src1, src2, nbits);
+    }
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src1 ^ *src2;
+    } else {
+        slow_bitmap_xor(dst, src1, src2, nbits);
+    }
+}
+
+static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return (*dst = *src1 & ~(*src2)) != 0;
+    }
+    return slow_bitmap_andnot(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
+                       int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
+    } else {
+        slow_bitmap_complement(dst, src, nbits);
+    }
+}
+
+static inline int bitmap_equal(const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_equal(src1, src2, nbits);
+    }
+}
+
+static inline int bitmap_empty(const unsigned long *src, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_empty(src, nbits);
+    }
+}
+
+static inline int bitmap_full(const unsigned long *src, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_full(src, nbits);
+    }
+}
+
+static inline int bitmap_intersects(const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+    } else {
+        return slow_bitmap_intersects(src1, src2, nbits);
+    }
+}
+
+void bitmap_set(unsigned long *map, int i, int len);
+void bitmap_clear(unsigned long *map, int start, int nr);
+unsigned long bitmap_find_next_zero_area(unsigned long *map,
+                                        unsigned long size,
+                                        unsigned long start,
+                                        unsigned int nr,
+                                        unsigned long align_mask);
+
+#endif /* BITMAP_H */
diff --git a/bitops.c b/bitops.c
new file mode 100644 (file)
index 0000000..d9de71f
--- /dev/null
+++ b/bitops.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ * Copyright (C) 2008 IBM Corporation
+ * Written by Rusty Russell <rusty@rustcorp.com.au>
+ * (Inspired by David Howell's find_next_bit implementation)
+ *
+ * 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.
+ */
+
+#include "bitops.h"
+
+#define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
+
+/*
+ * Find the next set bit in a memory region.
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+                           unsigned long offset)
+{
+    const unsigned long *p = addr + BITOP_WORD(offset);
+    unsigned long result = offset & ~(BITS_PER_LONG-1);
+    unsigned long tmp;
+
+    if (offset >= size) {
+        return size;
+    }
+    size -= result;
+    offset %= BITS_PER_LONG;
+    if (offset) {
+        tmp = *(p++);
+        tmp &= (~0UL << offset);
+        if (size < BITS_PER_LONG) {
+            goto found_first;
+        }
+        if (tmp) {
+            goto found_middle;
+        }
+        size -= BITS_PER_LONG;
+        result += BITS_PER_LONG;
+    }
+    while (size & ~(BITS_PER_LONG-1)) {
+        if ((tmp = *(p++))) {
+            goto found_middle;
+        }
+        result += BITS_PER_LONG;
+        size -= BITS_PER_LONG;
+    }
+    if (!size) {
+        return result;
+    }
+    tmp = *p;
+
+found_first:
+    tmp &= (~0UL >> (BITS_PER_LONG - size));
+    if (tmp == 0UL) {          /* Are any bits set? */
+        return result + size;  /* Nope. */
+    }
+found_middle:
+    return result + bitops_ffsl(tmp);
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+                                unsigned long offset)
+{
+    const unsigned long *p = addr + BITOP_WORD(offset);
+    unsigned long result = offset & ~(BITS_PER_LONG-1);
+    unsigned long tmp;
+
+    if (offset >= size) {
+        return size;
+    }
+    size -= result;
+    offset %= BITS_PER_LONG;
+    if (offset) {
+        tmp = *(p++);
+        tmp |= ~0UL >> (BITS_PER_LONG - offset);
+        if (size < BITS_PER_LONG) {
+            goto found_first;
+        }
+        if (~tmp) {
+            goto found_middle;
+        }
+        size -= BITS_PER_LONG;
+        result += BITS_PER_LONG;
+    }
+    while (size & ~(BITS_PER_LONG-1)) {
+        if (~(tmp = *(p++))) {
+            goto found_middle;
+        }
+        result += BITS_PER_LONG;
+        size -= BITS_PER_LONG;
+    }
+    if (!size) {
+        return result;
+    }
+    tmp = *p;
+
+found_first:
+    tmp |= ~0UL << size;
+    if (tmp == ~0UL) { /* Are any bits zero? */
+        return result + size;  /* Nope. */
+    }
+found_middle:
+    return result + ffz(tmp);
+}
+
+unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
+{
+    unsigned long words;
+    unsigned long tmp;
+
+    /* Start at final word. */
+    words = size / BITS_PER_LONG;
+
+    /* Partial final word? */
+    if (size & (BITS_PER_LONG-1)) {
+        tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
+                                       - (size & (BITS_PER_LONG-1)))));
+        if (tmp) {
+            goto found;
+        }
+    }
+
+    while (words) {
+        tmp = addr[--words];
+        if (tmp) {
+        found:
+            return words * BITS_PER_LONG + bitops_flsl(tmp);
+        }
+    }
+
+    /* Not found */
+    return size;
+}
diff --git a/bitops.h b/bitops.h
new file mode 100644 (file)
index 0000000..07d1a06
--- /dev/null
+++ b/bitops.h
@@ -0,0 +1,272 @@
+/*
+ * Bitops Module
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
+ *
+ * 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 BITOPS_H
+#define BITOPS_H
+
+#include "qemu-common.h"
+
+#define BITS_PER_BYTE           CHAR_BIT
+#define BITS_PER_LONG           (sizeof (unsigned long) * BITS_PER_BYTE)
+
+#define BIT(nr)                        (1UL << (nr))
+#define BIT_MASK(nr)           (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)           ((nr) / BITS_PER_LONG)
+#define BITS_TO_LONGS(nr)      DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+
+/**
+ * bitops_ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static unsigned long bitops_ffsl(unsigned long word)
+{
+       int num = 0;
+
+#if LONG_MAX > 0x7FFFFFFF
+       if ((word & 0xffffffff) == 0) {
+               num += 32;
+               word >>= 32;
+       }
+#endif
+       if ((word & 0xffff) == 0) {
+               num += 16;
+               word >>= 16;
+       }
+       if ((word & 0xff) == 0) {
+               num += 8;
+               word >>= 8;
+       }
+       if ((word & 0xf) == 0) {
+               num += 4;
+               word >>= 4;
+       }
+       if ((word & 0x3) == 0) {
+               num += 2;
+               word >>= 2;
+       }
+       if ((word & 0x1) == 0) {
+               num += 1;
+        }
+       return num;
+}
+
+/**
+ * bitops_fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long bitops_flsl(unsigned long word)
+{
+       int num = BITS_PER_LONG - 1;
+
+#if LONG_MAX > 0x7FFFFFFF
+       if (!(word & (~0ul << 32))) {
+               num -= 32;
+               word <<= 32;
+       }
+#endif
+       if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
+               num -= 16;
+               word <<= 16;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
+               num -= 8;
+               word <<= 8;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
+               num -= 4;
+               word <<= 4;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
+               num -= 2;
+
+               word <<= 2;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-1))))
+               num -= 1;
+       return num;
+}
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+    return bitops_ffsl(~word);
+}
+
+/**
+ * set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static inline void set_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       *p  |= mask;
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ */
+static inline void clear_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       *p &= ~mask;
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ */
+static inline void change_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       *p ^= mask;
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+       unsigned long old = *p;
+
+       *p = old | mask;
+       return (old & mask) != 0;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ */
+static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+       unsigned long old = *p;
+
+       *p = old & ~mask;
+       return (old & mask) != 0;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ */
+static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+       unsigned long old = *p;
+
+       *p = old ^ mask;
+       return (old & mask) != 0;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+       return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+/**
+ * find_last_bit - find the last set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit, or size.
+ */
+unsigned long find_last_bit(const unsigned long *addr,
+                            unsigned long size);
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+unsigned long find_next_bit(const unsigned long *addr,
+                                  unsigned long size, unsigned long offset);
+
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+
+unsigned long find_next_zero_bit(const unsigned long *addr,
+                                 unsigned long size,
+                                 unsigned long offset);
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit.
+ */
+static inline unsigned long find_first_bit(const unsigned long *addr,
+                                           unsigned long size)
+{
+    return find_next_bit(addr, size, 0);
+}
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first cleared bit.
+ */
+static inline unsigned long find_first_zero_bit(const unsigned long *addr,
+                                                unsigned long size)
+{
+    return find_next_zero_bit(addr, size, 0);
+}
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+    unsigned long count;
+
+    for (count = 0; w; w >>= 1) {
+        count += w & 1;
+    }
+    return count;
+}
+
+#endif
index 8218bac09c6cd30286a4ce5b826ac378700036da..5f10486416689d2c3da340d9ea85f39596c1ca7f 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)
@@ -186,18 +180,19 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
             BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
     bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
 
-    bmds->aio_bitmap = qemu_mallocz(bitmap_size);
+    bmds->aio_bitmap = g_malloc0(bitmap_size);
 }
 
 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);
@@ -240,8 +235,8 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
         nr_sectors = total_sectors - cur_sector;
     }
 
-    blk = qemu_malloc(sizeof(BlkMigBlock));
-    blk->buf = qemu_malloc(BLOCK_SIZE);
+    blk = g_malloc(sizeof(BlkMigBlock));
+    blk->buf = g_malloc(BLOCK_SIZE);
     blk->bmds = bmds;
     blk->sector = cur_sector;
     blk->nr_sectors = nr_sectors;
@@ -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);
@@ -266,9 +263,9 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
 
 error:
     monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
-    qemu_file_set_error(f);
-    qemu_free(blk->buf);
-    qemu_free(blk);
+    qemu_file_set_error(f, -EIO);
+    g_free(blk->buf);
+    g_free(blk);
     return 0;
 }
 
@@ -293,7 +290,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
             return;
         }
 
-        bmds = qemu_mallocz(sizeof(BlkMigDevState));
+        bmds = g_malloc0(sizeof(BlkMigDevState));
         bmds->bs = bs;
         bmds->bulk_completed = 0;
         bmds->total_sectors = sectors;
@@ -386,6 +383,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
     int64_t total_sectors = bmds->total_sectors;
     int64_t sector;
     int nr_sectors;
+    int ret = -EIO;
 
     for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
         if (bmds_aio_inflight(bmds, sector)) {
@@ -398,8 +396,8 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
             } else {
                 nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
             }
-            blk = qemu_malloc(sizeof(BlkMigBlock));
-            blk->buf = qemu_malloc(BLOCK_SIZE);
+            blk = g_malloc(sizeof(BlkMigBlock));
+            blk->buf = g_malloc(BLOCK_SIZE);
             blk->bmds = bmds;
             blk->sector = sector;
             blk->nr_sectors = nr_sectors;
@@ -409,7 +407,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);
@@ -419,14 +419,14 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
                 block_mig_state.submitted++;
                 bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
             } else {
-                if (bdrv_read(bmds->bs, sector, blk->buf,
-                              nr_sectors) < 0) {
+                ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
+                if (ret < 0) {
                     goto error;
                 }
                 blk_send(f, blk);
 
-                qemu_free(blk->buf);
-                qemu_free(blk);
+                g_free(blk->buf);
+                g_free(blk);
             }
 
             bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
@@ -440,9 +440,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
 
 error:
     monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
-    qemu_file_set_error(f);
-    qemu_free(blk->buf);
-    qemu_free(blk);
+    qemu_file_set_error(f, ret);
+    g_free(blk->buf);
+    g_free(blk);
     return 0;
 }
 
@@ -474,14 +474,14 @@ static void flush_blks(QEMUFile* f)
             break;
         }
         if (blk->ret < 0) {
-            qemu_file_set_error(f);
+            qemu_file_set_error(f, blk->ret);
             break;
         }
         blk_send(f, blk);
 
         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
-        qemu_free(blk->buf);
-        qemu_free(blk);
+        g_free(blk->buf);
+        g_free(blk);
 
         block_mig_state.read_done--;
         block_mig_state.transferred++;
@@ -521,7 +521,7 @@ static int is_stage2_completed(void)
 
         if ((remaining_dirty / bwidth) <=
             migrate_max_downtime()) {
-            /* finish stage2 because we think that we can finish remaing work
+            /* finish stage2 because we think that we can finish remaining work
                below max_downtime */
 
             return 1;
@@ -542,14 +542,14 @@ static void blk_mig_cleanup(Monitor *mon)
         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
         bdrv_set_in_use(bmds->bs, 0);
         drive_put_ref(drive_get_by_blockdev(bmds->bs));
-        qemu_free(bmds->aio_bitmap);
-        qemu_free(bmds);
+        g_free(bmds->aio_bitmap);
+        g_free(bmds);
     }
 
     while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
-        qemu_free(blk->buf);
-        qemu_free(blk);
+        g_free(blk->buf);
+        g_free(blk);
     }
 
     monitor_printf(mon, "\n");
@@ -557,6 +557,8 @@ static void blk_mig_cleanup(Monitor *mon)
 
 static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 {
+    int ret;
+
     DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
             stage, block_mig_state.submitted, block_mig_state.transferred);
 
@@ -580,9 +582,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 
     flush_blks(f);
 
-    if (qemu_file_has_error(f)) {
+    ret = qemu_file_get_error(f);
+    if (ret) {
         blk_mig_cleanup(mon);
-        return 0;
+        return ret;
     }
 
     blk_mig_reset_dirty_cursor();
@@ -608,9 +611,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 
         flush_blks(f);
 
-        if (qemu_file_has_error(f)) {
+        ret = qemu_file_get_error(f);
+        if (ret) {
             blk_mig_cleanup(mon);
-            return 0;
+            return ret;
         }
     }
 
@@ -625,8 +629,9 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
         /* report completion */
         qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
 
-        if (qemu_file_has_error(f)) {
-            return 0;
+        ret = qemu_file_get_error(f);
+        if (ret) {
+            return ret;
         }
 
         monitor_printf(mon, "Block migration completed\n");
@@ -647,6 +652,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
     uint8_t *buf;
     int64_t total_sectors = 0;
     int nr_sectors;
+    int ret;
 
     do {
         addr = qemu_get_be64(f);
@@ -655,7 +661,6 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
         addr >>= BDRV_SECTOR_BITS;
 
         if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
-            int ret;
             /* get device name */
             len = qemu_get_byte(f);
             qemu_get_buffer(f, (uint8_t *)device_name, len);
@@ -672,7 +677,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
                 bs_prev = bs;
                 total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
                 if (total_sectors <= 0) {
-                    error_report("Error getting length of block device %s\n",
+                    error_report("Error getting length of block device %s",
                                  device_name);
                     return -EINVAL;
                 }
@@ -684,12 +689,12 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
                 nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
             }
 
-            buf = qemu_malloc(BLOCK_SIZE);
+            buf = g_malloc(BLOCK_SIZE);
 
             qemu_get_buffer(f, buf, BLOCK_SIZE);
             ret = bdrv_write(bs, addr, buf, nr_sectors);
 
-            qemu_free(buf);
+            g_free(buf);
             if (ret < 0) {
                 return ret;
             }
@@ -705,8 +710,9 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
             fprintf(stderr, "Unknown flags\n");
             return -EINVAL;
         }
-        if (qemu_file_has_error(f)) {
-            return -EIO;
+        ret = qemu_file_get_error(f);
+        if (ret != 0) {
+            return ret;
         }
     } while (!(flags & BLK_MIG_FLAG_EOS));
 
diff --git a/block.c b/block.c
index b203875be6220d11913b58001d0094fd4e92d26b..d0158877d662c47598f0c8e55290a186d15a8945 100644 (file)
--- a/block.c
+++ b/block.c
@@ -27,7 +27,9 @@
 #include "monitor.h"
 #include "block_int.h"
 #include "module.h"
-#include "qemu-objects.h"
+#include "qjson.h"
+#include "qemu-coroutine.h"
+#include "qmp-commands.h"
 
 #ifdef CONFIG_BSD
 #include <sys/types.h>
 #include <windows.h>
 #endif
 
+#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
+
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
 static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
-static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
-                        uint8_t *buf, int nb_sectors);
-static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
-                         const uint8_t *buf, int nb_sectors);
+static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov);
+static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov);
+static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
+                                               int64_t sector_num,
+                                               QEMUIOVector *qiov,
+                                               int nb_sectors,
+                                               BlockDriverCompletionFunc *cb,
+                                               void *opaque,
+                                               bool is_write);
+static void coroutine_fn bdrv_co_do_rw(void *opaque);
 
 static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
     QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -169,19 +184,21 @@ void path_combine(char *dest, int dest_size,
 
 void bdrv_register(BlockDriver *bdrv)
 {
-    if (!bdrv->bdrv_aio_readv) {
-        /* add AIO emulation layer */
-        bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
-        bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
-    } else if (!bdrv->bdrv_read) {
-        /* add synchronous IO emulation layer */
-        bdrv->bdrv_read = bdrv_read_em;
-        bdrv->bdrv_write = bdrv_write_em;
+    /* Block drivers without coroutine functions need emulation */
+    if (!bdrv->bdrv_co_readv) {
+        bdrv->bdrv_co_readv = bdrv_co_readv_em;
+        bdrv->bdrv_co_writev = bdrv_co_writev_em;
+
+        /* bdrv_co_readv_em()/brdv_co_writev_em() work in terms of aio, so if
+         * the block driver lacks aio we need to emulate that too.
+         */
+        if (!bdrv->bdrv_aio_readv) {
+            /* add AIO emulation layer */
+            bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
+            bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
+        }
     }
 
-    if (!bdrv->bdrv_aio_flush)
-        bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
-
     QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
 }
 
@@ -190,11 +207,12 @@ BlockDriverState *bdrv_new(const char *device_name)
 {
     BlockDriverState *bs;
 
-    bs = qemu_mallocz(sizeof(BlockDriverState));
+    bs = g_malloc0(sizeof(BlockDriverState));
     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
     if (device_name[0] != '\0') {
         QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
     }
+    bdrv_iostatus_disable(bs);
     return bs;
 }
 
@@ -412,6 +430,33 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
     return 0;
 }
 
+/**
+ * Set open flags for a given cache mode
+ *
+ * Return 0 on success, -1 if the cache mode was invalid.
+ */
+int bdrv_parse_cache_flags(const char *mode, int *flags)
+{
+    *flags &= ~BDRV_O_CACHE_MASK;
+
+    if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
+        *flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+    } else if (!strcmp(mode, "directsync")) {
+        *flags |= BDRV_O_NOCACHE;
+    } else if (!strcmp(mode, "writeback")) {
+        *flags |= BDRV_O_CACHE_WB;
+    } else if (!strcmp(mode, "unsafe")) {
+        *flags |= BDRV_O_CACHE_WB;
+        *flags |= BDRV_O_NO_FLUSH;
+    } else if (!strcmp(mode, "writethrough")) {
+        /* this is the default */
+    } else {
+        return -1;
+    }
+
+    return 0;
+}
+
 /*
  * Common part for opening disk images and files
  */
@@ -422,31 +467,28 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
 
     assert(drv != NULL);
 
+    trace_bdrv_open_common(bs, filename, flags, drv->format_name);
+
     bs->file = NULL;
     bs->total_sectors = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
+    bs->sg = 0;
     bs->open_flags = flags;
-    /* buffer_alignment defaulted to 512, drivers can change this value */
+    bs->growable = 0;
     bs->buffer_alignment = 512;
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
+    bs->backing_file[0] = '\0';
 
     if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
         return -ENOTSUP;
     }
 
     bs->drv = drv;
-    bs->opaque = qemu_mallocz(drv->instance_size);
+    bs->opaque = g_malloc0(drv->instance_size);
 
-    /*
-     * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
-     * write cache to the guest.  We do need the fdatasync to flush
-     * out transactions for block allocations, and we maybe have a
-     * volatile write cache in our backing device to deal with.
-     */
-    if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
-        bs->enable_write_cache = 1;
+    bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
 
     /*
      * Clear flags that are internal to the block layer before opening the
@@ -455,12 +497,14 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
 
     /*
-     * Snapshots should be writeable.
+     * Snapshots should be writable.
      */
     if (bs->is_temporary) {
         open_flags |= BDRV_O_RDWR;
     }
 
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
+
     /* Open the image, either directly or using a protocol */
     if (drv->bdrv_file_open) {
         ret = drv->bdrv_file_open(bs, filename, open_flags);
@@ -475,8 +519,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
         goto free_and_fail;
     }
 
-    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
-
     ret = refresh_total_sectors(bs, bs->total_sectors);
     if (ret < 0) {
         goto free_and_fail;
@@ -494,7 +536,7 @@ free_and_fail:
         bdrv_delete(bs->file);
         bs->file = NULL;
     }
-    qemu_free(bs->opaque);
+    g_free(bs->opaque);
     bs->opaque = NULL;
     bs->drv = NULL;
     return ret;
@@ -532,6 +574,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
               BlockDriver *drv)
 {
     int ret;
+    char tmp_filename[PATH_MAX];
 
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
@@ -539,7 +582,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         int is_protocol = 0;
         BlockDriver *bdrv_qcow2;
         QEMUOptionParameter *options;
-        char tmp_filename[PATH_MAX];
         char backing_filename[PATH_MAX];
 
         /* if snapshot, we create a temporary backing file and open it
@@ -642,10 +684,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
     }
 
     if (!bdrv_key_required(bs)) {
-        /* call the change callback */
-        bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs, true);
     }
 
     return 0;
@@ -668,7 +707,7 @@ void bdrv_close(BlockDriverState *bs)
             bs->backing_hd = NULL;
         }
         bs->drv->bdrv_close(bs);
-        qemu_free(bs->opaque);
+        g_free(bs->opaque);
 #ifdef _WIN32
         if (bs->is_temporary) {
             unlink(bs->filename);
@@ -681,10 +720,7 @@ void bdrv_close(BlockDriverState *bs)
             bdrv_close(bs->file);
         }
 
-        /* call the change callback */
-        bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs, false);
     }
 }
 
@@ -709,7 +745,7 @@ void bdrv_make_anon(BlockDriverState *bs)
 
 void bdrv_delete(BlockDriverState *bs)
 {
-    assert(!bs->peer);
+    assert(!bs->dev);
 
     /* remove from list, if necessary */
     bdrv_make_anon(bs);
@@ -720,34 +756,101 @@ void bdrv_delete(BlockDriverState *bs)
     }
 
     assert(bs != bs_snapshots);
-    qemu_free(bs);
+    g_free(bs);
 }
 
-int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
+int bdrv_attach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
 {
-    if (bs->peer) {
+    if (bs->dev) {
         return -EBUSY;
     }
-    bs->peer = qdev;
+    bs->dev = dev;
+    bdrv_iostatus_reset(bs);
     return 0;
 }
 
-void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
+/* TODO qdevified devices don't use this, remove when devices are qdevified */
+void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
+{
+    if (bdrv_attach_dev(bs, dev) < 0) {
+        abort();
+    }
+}
+
+void bdrv_detach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
+{
+    assert(bs->dev == dev);
+    bs->dev = NULL;
+    bs->dev_ops = NULL;
+    bs->dev_opaque = NULL;
+    bs->buffer_alignment = 512;
+}
+
+/* TODO change to return DeviceState * when all users are qdevified */
+void *bdrv_get_attached_dev(BlockDriverState *bs)
+{
+    return bs->dev;
+}
+
+void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
+                      void *opaque)
+{
+    bs->dev_ops = ops;
+    bs->dev_opaque = opaque;
+    if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) {
+        bs_snapshots = NULL;
+    }
+}
+
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
+{
+    if (bs->dev_ops && bs->dev_ops->change_media_cb) {
+        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
+    }
+}
+
+bool bdrv_dev_has_removable_media(BlockDriverState *bs)
+{
+    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
+}
+
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
+{
+    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
+        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
+    }
+}
+
+bool bdrv_dev_is_tray_open(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
+        return bs->dev_ops->is_tray_open(bs->dev_opaque);
+    }
+    return false;
+}
+
+static void bdrv_dev_resize_cb(BlockDriverState *bs)
 {
-    assert(bs->peer == qdev);
-    bs->peer = NULL;
+    if (bs->dev_ops && bs->dev_ops->resize_cb) {
+        bs->dev_ops->resize_cb(bs->dev_opaque);
+    }
 }
 
-DeviceState *bdrv_get_attached(BlockDriverState *bs)
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
 {
-    return bs->peer;
+    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
+        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
+    }
+    return false;
 }
 
 /*
  * Run consistency checks on an image
  *
  * Returns 0 if the check could be completed (it doesn't mean that the image is
- * free of errors) or -errno when an internal error occured. The results of the
+ * free of errors) or -errno when an internal error occurred. The results of the
  * check are stored in res.
  */
 int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
@@ -816,7 +919,7 @@ int bdrv_commit(BlockDriverState *bs)
     }
 
     total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
-    buf = qemu_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
+    buf = g_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
 
     for (sector = 0; sector < total_sectors; sector += n) {
         if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
@@ -846,7 +949,7 @@ int bdrv_commit(BlockDriverState *bs)
         bdrv_flush(bs->backing_hd);
 
 ro_cleanup:
-    qemu_free(buf);
+    g_free(buf);
 
     if (ro) {
         /* re-open as RO */
@@ -926,18 +1029,69 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
                                    nb_sectors * BDRV_SECTOR_SIZE);
 }
 
+typedef struct RwCo {
+    BlockDriverState *bs;
+    int64_t sector_num;
+    int nb_sectors;
+    QEMUIOVector *qiov;
+    bool is_write;
+    int ret;
+} RwCo;
+
+static void coroutine_fn bdrv_rw_co_entry(void *opaque)
+{
+    RwCo *rwco = opaque;
+
+    if (!rwco->is_write) {
+        rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
+                                     rwco->nb_sectors, rwco->qiov);
+    } else {
+        rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
+                                      rwco->nb_sectors, rwco->qiov);
+    }
+}
+
+/*
+ * Process a synchronous request using coroutines
+ */
+static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
+                      int nb_sectors, bool is_write)
+{
+    QEMUIOVector qiov;
+    struct iovec iov = {
+        .iov_base = (void *)buf,
+        .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
+    };
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .sector_num = sector_num,
+        .nb_sectors = nb_sectors,
+        .qiov = &qiov,
+        .is_write = is_write,
+        .ret = NOT_DONE,
+    };
+
+    qemu_iovec_init_external(&qiov, &iov, 1);
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_rw_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_rw_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+    return rwco.ret;
+}
+
 /* return < 0 if error. See bdrv_write() for the return codes */
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors)
 {
-    BlockDriver *drv = bs->drv;
-
-    if (!drv)
-        return -ENOMEDIUM;
-    if (bdrv_check_request(bs, sector_num, nb_sectors))
-        return -EIO;
-
-    return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
+    return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
 }
 
 static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
@@ -977,23 +1131,7 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
                const uint8_t *buf, int nb_sectors)
 {
-    BlockDriver *drv = bs->drv;
-    if (!bs->drv)
-        return -ENOMEDIUM;
-    if (bs->read_only)
-        return -EACCES;
-    if (bdrv_check_request(bs, sector_num, nb_sectors))
-        return -EIO;
-
-    if (bs->dirty_bitmap) {
-        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
-    }
-
-    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
-        bs->wr_highest_sector = sector_num + nb_sectors - 1;
-    }
-
-    return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
+    return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
 }
 
 int bdrv_pread(BlockDriverState *bs, int64_t offset,
@@ -1106,8 +1244,8 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
         return ret;
     }
 
-    /* No flush needed for cache=writethrough, it uses O_DSYNC */
-    if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
+    /* No flush needed for cache modes that use O_DSYNC */
+    if ((bs->open_flags & BDRV_O_CACHE_WB) != 0) {
         bdrv_flush(bs);
     }
 
@@ -1115,16 +1253,69 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
 }
 
 /*
- * Writes to the file and ensures that no writes are reordered across this
- * request (acts as a barrier)
- *
- * Returns 0 on success, -errno in error cases.
+ * Handle a read request in coroutine context
+ */
+static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    }
+
+    return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+}
+
+int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov)
+{
+    trace_bdrv_co_readv(bs, sector_num, nb_sectors);
+
+    return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
+}
+
+/*
+ * Handle a write request in coroutine context
  */
-int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
-    const uint8_t *buf, int nb_sectors)
+static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    }
+    if (bs->read_only) {
+        return -EACCES;
+    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    }
+
+    ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+
+    if (bs->dirty_bitmap) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+
+    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+        bs->wr_highest_sector = sector_num + nb_sectors - 1;
+    }
+
+    return ret;
+}
+
+int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov)
 {
-    return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
-        buf, BDRV_SECTOR_SIZE * nb_sectors);
+    trace_bdrv_co_writev(bs, sector_num, nb_sectors);
+
+    return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov);
 }
 
 /**
@@ -1145,13 +1336,30 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
-        if (bs->change_cb) {
-            bs->change_cb(bs->change_opaque, CHANGE_SIZE);
-        }
+        bdrv_dev_resize_cb(bs);
     }
     return ret;
 }
 
+/**
+ * Length of a allocated file in bytes. Sparse files are counted by actual
+ * allocated space. Return < 0 if error or unknown.
+ */
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (drv->bdrv_get_allocated_file_size) {
+        return drv->bdrv_get_allocated_file_size(bs);
+    }
+    if (bs->file) {
+        return bdrv_get_allocated_file_size(bs->file);
+    }
+    return -ENOTSUP;
+}
+
 /**
  * Length of a file in bytes. Return < 0 if error or unknown.
  */
@@ -1161,14 +1369,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 || bdrv_dev_has_removable_media(bs)) {
+        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 */
@@ -1194,7 +1400,7 @@ struct partition {
         uint8_t end_cyl;            /* end cylinder */
         uint32_t start_sect;        /* starting sector counting from 0 */
         uint32_t nr_sects;          /* nr of sectors in partition */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
 static int guess_disk_lchs(BlockDriverState *bs,
@@ -1307,13 +1513,6 @@ void bdrv_set_geometry_hint(BlockDriverState *bs,
     bs->secs = secs;
 }
 
-void bdrv_set_type_hint(BlockDriverState *bs, int type)
-{
-    bs->type = type;
-    bs->removable = ((type == BDRV_TYPE_CDROM ||
-                      type == BDRV_TYPE_FLOPPY));
-}
-
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
 {
     bs->translation = translation;
@@ -1327,9 +1526,107 @@ void bdrv_get_geometry_hint(BlockDriverState *bs,
     *psecs = bs->secs;
 }
 
-int bdrv_get_type_hint(BlockDriverState *bs)
+/* Recognize floppy formats */
+typedef struct FDFormat {
+    FDriveType drive;
+    uint8_t last_sect;
+    uint8_t max_track;
+    uint8_t max_head;
+} FDFormat;
+
+static const FDFormat fd_formats[] = {
+    /* First entry is default format */
+    /* 1.44 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144, 18, 80, 1, },
+    { FDRIVE_DRV_144, 20, 80, 1, },
+    { FDRIVE_DRV_144, 21, 80, 1, },
+    { FDRIVE_DRV_144, 21, 82, 1, },
+    { FDRIVE_DRV_144, 21, 83, 1, },
+    { FDRIVE_DRV_144, 22, 80, 1, },
+    { FDRIVE_DRV_144, 23, 80, 1, },
+    { FDRIVE_DRV_144, 24, 80, 1, },
+    /* 2.88 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_288, 36, 80, 1, },
+    { FDRIVE_DRV_288, 39, 80, 1, },
+    { FDRIVE_DRV_288, 40, 80, 1, },
+    { FDRIVE_DRV_288, 44, 80, 1, },
+    { FDRIVE_DRV_288, 48, 80, 1, },
+    /* 720 kB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144,  9, 80, 1, },
+    { FDRIVE_DRV_144, 10, 80, 1, },
+    { FDRIVE_DRV_144, 10, 82, 1, },
+    { FDRIVE_DRV_144, 10, 83, 1, },
+    { FDRIVE_DRV_144, 13, 80, 1, },
+    { FDRIVE_DRV_144, 14, 80, 1, },
+    /* 1.2 MB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, 15, 80, 1, },
+    { FDRIVE_DRV_120, 18, 80, 1, },
+    { FDRIVE_DRV_120, 18, 82, 1, },
+    { FDRIVE_DRV_120, 18, 83, 1, },
+    { FDRIVE_DRV_120, 20, 80, 1, },
+    /* 720 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 80, 1, },
+    { FDRIVE_DRV_120, 11, 80, 1, },
+    /* 360 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 40, 1, },
+    { FDRIVE_DRV_120,  9, 40, 0, },
+    { FDRIVE_DRV_120, 10, 41, 1, },
+    { FDRIVE_DRV_120, 10, 42, 1, },
+    /* 320 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  8, 40, 1, },
+    { FDRIVE_DRV_120,  8, 40, 0, },
+    /* 360 kB must match 5"1/4 better than 3"1/2... */
+    { FDRIVE_DRV_144,  9, 80, 0, },
+    /* end */
+    { FDRIVE_DRV_NONE, -1, -1, 0, },
+};
+
+void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
+                                   int *max_track, int *last_sect,
+                                   FDriveType drive_in, FDriveType *drive)
 {
-    return bs->type;
+    const FDFormat *parse;
+    uint64_t nb_sectors, size;
+    int i, first_match, match;
+
+    bdrv_get_geometry_hint(bs, nb_heads, max_track, last_sect);
+    if (*nb_heads != 0 && *max_track != 0 && *last_sect != 0) {
+        /* User defined disk */
+    } else {
+        bdrv_get_geometry(bs, &nb_sectors);
+        match = -1;
+        first_match = -1;
+        for (i = 0; ; i++) {
+            parse = &fd_formats[i];
+            if (parse->drive == FDRIVE_DRV_NONE) {
+                break;
+            }
+            if (drive_in == parse->drive ||
+                drive_in == FDRIVE_DRV_NONE) {
+                size = (parse->max_head + 1) * parse->max_track *
+                    parse->last_sect;
+                if (nb_sectors == size) {
+                    match = i;
+                    break;
+                }
+                if (first_match == -1) {
+                    first_match = i;
+                }
+            }
+        }
+        if (match == -1) {
+            if (first_match == -1) {
+                match = 1;
+            } else {
+                match = first_match;
+            }
+            parse = &fd_formats[match];
+        }
+        *nb_heads = parse->max_head + 1;
+        *max_track = parse->max_track;
+        *last_sect = parse->last_sect;
+        *drive = parse->drive;
+    }
 }
 
 int bdrv_get_translation_hint(BlockDriverState *bs)
@@ -1349,19 +1646,6 @@ BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
     return is_read ? bs->on_read_error : bs->on_write_error;
 }
 
-void bdrv_set_removable(BlockDriverState *bs, int removable)
-{
-    bs->removable = removable;
-    if (removable && bs == bs_snapshots) {
-        bs_snapshots = NULL;
-    }
-}
-
-int bdrv_is_removable(BlockDriverState *bs)
-{
-    return bs->removable;
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
     return bs->read_only;
@@ -1377,15 +1661,6 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
     return bs->enable_write_cache;
 }
 
-/* XXX: no longer used */
-void bdrv_set_change_cb(BlockDriverState *bs,
-                        void (*change_cb)(void *opaque, int reason),
-                        void *opaque)
-{
-    bs->change_cb = change_cb;
-    bs->change_opaque = opaque;
-}
-
 int bdrv_is_encrypted(BlockDriverState *bs)
 {
     if (bs->backing_hd && bs->backing_hd->encrypted)
@@ -1423,9 +1698,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
     } else if (!bs->valid_key) {
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
-        bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs, true);
     }
     return ret;
 }
@@ -1483,36 +1756,12 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
     return bs->device_name;
 }
 
-int bdrv_flush(BlockDriverState *bs)
-{
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return 0;
-    }
-
-    if (bs->drv && bs->drv->bdrv_flush) {
-        return bs->drv->bdrv_flush(bs);
-    }
-
-    /*
-     * Some block drivers always operate in either writethrough or unsafe mode
-     * and don't support bdrv_flush therefore. Usually qemu doesn't know how
-     * the server works (because the behaviour is hardcoded or depends on
-     * server-side configuration), so we can't ensure that everything is safe
-     * on disk. Returning an error doesn't work because that would break guests
-     * even if the server operates in writethrough mode.
-     *
-     * Let's hope the user knows what he's doing.
-     */
-    return 0;
-}
-
 void bdrv_flush_all(void)
 {
     BlockDriverState *bs;
 
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        if (bs->drv && !bdrv_is_read_only(bs) &&
-            (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) {
+        if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
             bdrv_flush(bs);
         }
     }
@@ -1529,17 +1778,6 @@ int bdrv_has_zero_init(BlockDriverState *bs)
     return 1;
 }
 
-int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
-{
-    if (!bs->drv) {
-        return -ENOMEDIUM;
-    }
-    if (!bs->drv->bdrv_discard) {
-        return 0;
-    }
-    return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
-}
-
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
@@ -1596,167 +1834,105 @@ void bdrv_mon_event(const BlockDriverState *bdrv,
     qobject_decref(data);
 }
 
-static void bdrv_print_dict(QObject *obj, void *opaque)
+BlockInfoList *qmp_query_block(Error **errp)
 {
-    QDict *bs_dict;
-    Monitor *mon = opaque;
-
-    bs_dict = qobject_to_qdict(obj);
-
-    monitor_printf(mon, "%s: type=%s removable=%d",
-                        qdict_get_str(bs_dict, "device"),
-                        qdict_get_str(bs_dict, "type"),
-                        qdict_get_bool(bs_dict, "removable"));
+    BlockInfoList *head = NULL, *cur_item = NULL;
+    BlockDriverState *bs;
 
-    if (qdict_get_bool(bs_dict, "removable")) {
-        monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
-    }
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        BlockInfoList *info = g_malloc0(sizeof(*info));
 
-    if (qdict_haskey(bs_dict, "inserted")) {
-        QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->device = g_strdup(bs->device_name);
+        info->value->type = g_strdup("unknown");
+        info->value->locked = bdrv_dev_is_medium_locked(bs);
+        info->value->removable = bdrv_dev_has_removable_media(bs);
 
-        monitor_printf(mon, " file=");
-        monitor_print_filename(mon, qdict_get_str(qdict, "file"));
-        if (qdict_haskey(qdict, "backing_file")) {
-            monitor_printf(mon, " backing_file=");
-            monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
+        if (bdrv_dev_has_removable_media(bs)) {
+            info->value->has_tray_open = true;
+            info->value->tray_open = bdrv_dev_is_tray_open(bs);
         }
-        monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
-                            qdict_get_bool(qdict, "ro"),
-                            qdict_get_str(qdict, "drv"),
-                            qdict_get_bool(qdict, "encrypted"));
-    } else {
-        monitor_printf(mon, " [not inserted]");
-    }
-
-    monitor_printf(mon, "\n");
-}
-
-void bdrv_info_print(Monitor *mon, const QObject *data)
-{
-    qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
-}
-
-void bdrv_info(Monitor *mon, QObject **ret_data)
-{
-    QList *bs_list;
-    BlockDriverState *bs;
-
-    bs_list = qlist_new();
 
-    QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        QObject *bs_obj;
-        const char *type = "unknown";
-
-        switch(bs->type) {
-        case BDRV_TYPE_HD:
-            type = "hd";
-            break;
-        case BDRV_TYPE_CDROM:
-            type = "cdrom";
-            break;
-        case BDRV_TYPE_FLOPPY:
-            type = "floppy";
-            break;
-        }
-
-        bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, "
-                                    "'removable': %i, 'locked': %i }",
-                                    bs->device_name, type, bs->removable,
-                                    bs->locked);
+        if (bdrv_iostatus_is_enabled(bs)) {
+            info->value->has_io_status = true;
+            info->value->io_status = bs->iostatus;
+        }
 
         if (bs->drv) {
-            QObject *obj;
-            QDict *bs_dict = qobject_to_qdict(bs_obj);
-
-            obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
-                                     "'encrypted': %i }",
-                                     bs->filename, bs->read_only,
-                                     bs->drv->format_name,
-                                     bdrv_is_encrypted(bs));
-            if (bs->backing_file[0] != '\0') {
-                QDict *qdict = qobject_to_qdict(obj);
-                qdict_put(qdict, "backing_file",
-                          qstring_from_str(bs->backing_file));
+            info->value->has_inserted = true;
+            info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
+            info->value->inserted->file = g_strdup(bs->filename);
+            info->value->inserted->ro = bs->read_only;
+            info->value->inserted->drv = g_strdup(bs->drv->format_name);
+            info->value->inserted->encrypted = bs->encrypted;
+            if (bs->backing_file[0]) {
+                info->value->inserted->has_backing_file = true;
+                info->value->inserted->backing_file = g_strdup(bs->backing_file);
             }
+        }
 
-            qdict_put_obj(bs_dict, "inserted", obj);
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
         }
-        qlist_append_obj(bs_list, bs_obj);
     }
 
-    *ret_data = QOBJECT(bs_list);
-}
-
-static void bdrv_stats_iter(QObject *data, void *opaque)
-{
-    QDict *qdict;
-    Monitor *mon = opaque;
-
-    qdict = qobject_to_qdict(data);
-    monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
-
-    qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
-    monitor_printf(mon, " rd_bytes=%" PRId64
-                        " wr_bytes=%" PRId64
-                        " rd_operations=%" PRId64
-                        " wr_operations=%" PRId64
-                        "\n",
-                        qdict_get_int(qdict, "rd_bytes"),
-                        qdict_get_int(qdict, "wr_bytes"),
-                        qdict_get_int(qdict, "rd_operations"),
-                        qdict_get_int(qdict, "wr_operations"));
-}
-
-void bdrv_stats_print(Monitor *mon, const QObject *data)
-{
-    qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
+    return head;
 }
 
-static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
+/* Consider exposing this as a full fledged QMP command */
+static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
 {
-    QObject *res;
-    QDict *dict;
+    BlockStats *s;
 
-    res = qobject_from_jsonf("{ 'stats': {"
-                             "'rd_bytes': %" PRId64 ","
-                             "'wr_bytes': %" PRId64 ","
-                             "'rd_operations': %" PRId64 ","
-                             "'wr_operations': %" PRId64 ","
-                             "'wr_highest_offset': %" PRId64
-                             "} }",
-                             bs->rd_bytes, bs->wr_bytes,
-                             bs->rd_ops, bs->wr_ops,
-                             bs->wr_highest_sector *
-                             (uint64_t)BDRV_SECTOR_SIZE);
-    dict  = qobject_to_qdict(res);
+    s = g_malloc0(sizeof(*s));
 
-    if (*bs->device_name) {
-        qdict_put(dict, "device", qstring_from_str(bs->device_name));
+    if (bs->device_name[0]) {
+        s->has_device = true;
+        s->device = g_strdup(bs->device_name);
     }
 
+    s->stats = g_malloc0(sizeof(*s->stats));
+    s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
+    s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
+    s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
+    s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
+    s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
+    s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
+    s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
+    s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
+    s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
+
     if (bs->file) {
-        QObject *parent = bdrv_info_stats_bs(bs->file);
-        qdict_put_obj(dict, "parent", parent);
+        s->has_parent = true;
+        s->parent = qmp_query_blockstat(bs->file, NULL);
     }
 
-    return res;
+    return s;
 }
 
-void bdrv_info_stats(Monitor *mon, QObject **ret_data)
+BlockStatsList *qmp_query_blockstats(Error **errp)
 {
-    QObject *obj;
-    QList *devices;
+    BlockStatsList *head = NULL, *cur_item = NULL;
     BlockDriverState *bs;
 
-    devices = qlist_new();
-
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        obj = bdrv_info_stats_bs(bs);
-        qlist_append_obj(devices, obj);
+        BlockStatsList *info = g_malloc0(sizeof(*info));
+        info->value = qmp_query_blockstat(bs, NULL);
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
+        }
     }
 
-    *ret_data = QOBJECT(devices);
+    return head;
 }
 
 const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
@@ -1772,11 +1948,7 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
 void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size)
 {
-    if (!bs->backing_file) {
-        pstrcpy(filename, filename_size, "");
-    } else {
-        pstrcpy(filename, filename_size, bs->backing_file);
-    }
+    pstrcpy(filename, filename_size, bs->backing_file);
 }
 
 int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
@@ -1852,7 +2024,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 int bdrv_can_snapshot(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+    if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
         return 0;
     }
 
@@ -2042,7 +2214,6 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
     return buf;
 }
 
-
 /**************************************************************/
 /* async I/Os */
 
@@ -2050,101 +2221,20 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
                                  QEMUIOVector *qiov, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriver *drv = bs->drv;
-    BlockDriverAIOCB *ret;
-
     trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
 
-    if (!drv)
-        return NULL;
-    if (bdrv_check_request(bs, sector_num, nb_sectors))
-        return NULL;
-
-    ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
-                              cb, opaque);
-
-    if (ret) {
-       /* Update stats even though technically transfer has not happened. */
-       bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
-       bs->rd_ops ++;
-    }
-
-    return ret;
-}
-
-typedef struct BlockCompleteData {
-    BlockDriverCompletionFunc *cb;
-    void *opaque;
-    BlockDriverState *bs;
-    int64_t sector_num;
-    int nb_sectors;
-} BlockCompleteData;
-
-static void block_complete_cb(void *opaque, int ret)
-{
-    BlockCompleteData *b = opaque;
-
-    if (b->bs->dirty_bitmap) {
-        set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
-    }
-    b->cb(b->opaque, ret);
-    qemu_free(b);
-}
-
-static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
-                                             int64_t sector_num,
-                                             int nb_sectors,
-                                             BlockDriverCompletionFunc *cb,
-                                             void *opaque)
-{
-    BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
-
-    blkdata->bs = bs;
-    blkdata->cb = cb;
-    blkdata->opaque = opaque;
-    blkdata->sector_num = sector_num;
-    blkdata->nb_sectors = nb_sectors;
-
-    return blkdata;
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
+                                 cb, opaque, false);
 }
 
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *qiov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriver *drv = bs->drv;
-    BlockDriverAIOCB *ret;
-    BlockCompleteData *blk_cb_data;
-
     trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
 
-    if (!drv)
-        return NULL;
-    if (bs->read_only)
-        return NULL;
-    if (bdrv_check_request(bs, sector_num, nb_sectors))
-        return NULL;
-
-    if (bs->dirty_bitmap) {
-        blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
-                                         opaque);
-        cb = &block_complete_cb;
-        opaque = blk_cb_data;
-    }
-
-    ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
-                               cb, opaque);
-
-    if (ret) {
-        /* Update stats even though technically transfer has not happened. */
-        bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
-        bs->wr_ops ++;
-        if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
-            bs->wr_highest_sector = sector_num + nb_sectors - 1;
-        }
-    }
-
-    return ret;
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
+                                 cb, opaque, true);
 }
 
 
@@ -2169,7 +2259,7 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
         if (mcb->callbacks[i].free_qiov) {
             qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
         }
-        qemu_free(mcb->callbacks[i].free_qiov);
+        g_free(mcb->callbacks[i].free_qiov);
         qemu_vfree(mcb->callbacks[i].free_buf);
     }
 }
@@ -2187,7 +2277,7 @@ static void multiwrite_cb(void *opaque, int ret)
     mcb->num_requests--;
     if (mcb->num_requests == 0) {
         multiwrite_user_cb(mcb);
-        qemu_free(mcb);
+        g_free(mcb);
     }
 }
 
@@ -2247,7 +2337,7 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
 
         if (merge) {
             size_t size;
-            QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
+            QEMUIOVector *qiov = g_malloc0(sizeof(*qiov));
             qemu_iovec_init(qiov,
                 reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
 
@@ -2316,7 +2406,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
     }
 
     // Create MultiwriteCB structure
-    mcb = qemu_mallocz(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
+    mcb = g_malloc0(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
     mcb->num_requests = 0;
     mcb->num_callbacks = num_reqs;
 
@@ -2381,24 +2471,10 @@ fail:
     for (i = 0; i < mcb->num_callbacks; i++) {
         reqs[i].error = -EIO;
     }
-    qemu_free(mcb);
+    g_free(mcb);
     return -1;
 }
 
-BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BlockDriver *drv = bs->drv;
-
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return bdrv_aio_noop_em(bs, cb, opaque);
-    }
-
-    if (!drv)
-        return NULL;
-    return drv->bdrv_aio_flush(bs, cb, opaque);
-}
-
 void bdrv_aio_cancel(BlockDriverAIOCB *acb)
 {
     acb->pool->cancel(acb);
@@ -2466,9 +2542,9 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
 
     if (is_write) {
         qemu_iovec_to_buffer(acb->qiov, acb->bounce);
-        acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
+        acb->ret = bs->drv->bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
     } else {
-        acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
+        acb->ret = bs->drv->bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
     }
 
     qemu_bh_schedule(acb->bh);
@@ -2490,112 +2566,125 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
     return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
+
+typedef struct BlockDriverAIOCBCoroutine {
+    BlockDriverAIOCB common;
+    BlockRequest req;
+    bool is_write;
+    QEMUBH* bh;
+} BlockDriverAIOCBCoroutine;
+
+static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
 {
-    BlockDriverAIOCBSync *acb;
+    qemu_aio_flush();
+}
 
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion hadler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
+static AIOPool bdrv_em_co_aio_pool = {
+    .aiocb_size         = sizeof(BlockDriverAIOCBCoroutine),
+    .cancel             = bdrv_aio_co_cancel_em,
+};
 
-    if (!acb->bh)
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+static void bdrv_co_em_bh(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
 
-    bdrv_flush(bs);
-    qemu_bh_schedule(acb->bh);
-    return &acb->common;
+    acb->common.cb(acb->common.opaque, acb->req.error);
+    qemu_bh_delete(acb->bh);
+    qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
+/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
+static void coroutine_fn bdrv_co_do_rw(void *opaque)
 {
-    BlockDriverAIOCBSync *acb;
-
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion handler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
 
-    if (!acb->bh) {
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    if (!acb->is_write) {
+        acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
+            acb->req.nb_sectors, acb->req.qiov);
+    } else {
+        acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
+            acb->req.nb_sectors, acb->req.qiov);
     }
 
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
     qemu_bh_schedule(acb->bh);
-    return &acb->common;
 }
 
-/**************************************************************/
-/* sync block device emulation */
-
-static void bdrv_rw_em_cb(void *opaque, int ret)
+static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
+                                               int64_t sector_num,
+                                               QEMUIOVector *qiov,
+                                               int nb_sectors,
+                                               BlockDriverCompletionFunc *cb,
+                                               void *opaque,
+                                               bool is_write)
 {
-    *(int *)opaque = ret;
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
+
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    acb->req.sector = sector_num;
+    acb->req.nb_sectors = nb_sectors;
+    acb->req.qiov = qiov;
+    acb->is_write = is_write;
+
+    co = qemu_coroutine_create(bdrv_co_do_rw);
+    qemu_coroutine_enter(co, acb);
+
+    return &acb->common;
 }
 
-#define NOT_DONE 0x7fffffff
+static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+
+    acb->req.error = bdrv_co_flush(bs);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
+    qemu_bh_schedule(acb->bh);
+}
 
-static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
-                        uint8_t *buf, int nb_sectors)
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
 {
-    int async_ret;
-    BlockDriverAIOCB *acb;
-    struct iovec iov;
-    QEMUIOVector qiov;
+    trace_bdrv_aio_flush(bs, opaque);
 
-    async_context_push();
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
 
-    async_ret = NOT_DONE;
-    iov.iov_base = (void *)buf;
-    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
-    qemu_iovec_init_external(&qiov, &iov, 1);
-    acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
-        bdrv_rw_em_cb, &async_ret);
-    if (acb == NULL) {
-        async_ret = -1;
-        goto fail;
-    }
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
+    qemu_coroutine_enter(co, acb);
 
-    while (async_ret == NOT_DONE) {
-        qemu_aio_wait();
-    }
+    return &acb->common;
+}
 
+static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
 
-fail:
-    async_context_pop();
-    return async_ret;
+    acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
+    qemu_bh_schedule(acb->bh);
 }
 
-static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
-                         const uint8_t *buf, int nb_sectors)
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
 {
-    int async_ret;
-    BlockDriverAIOCB *acb;
-    struct iovec iov;
-    QEMUIOVector qiov;
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
 
-    async_context_push();
+    trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
 
-    async_ret = NOT_DONE;
-    iov.iov_base = (void *)buf;
-    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
-    qemu_iovec_init_external(&qiov, &iov, 1);
-    acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
-        bdrv_rw_em_cb, &async_ret);
-    if (acb == NULL) {
-        async_ret = -1;
-        goto fail;
-    }
-    while (async_ret == NOT_DONE) {
-        qemu_aio_wait();
-    }
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    acb->req.sector = sector_num;
+    acb->req.nb_sectors = nb_sectors;
+    co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
+    qemu_coroutine_enter(co, acb);
 
-fail:
-    async_context_pop();
-    return async_ret;
+    return &acb->common;
 }
 
 void bdrv_init(void)
@@ -2618,7 +2707,7 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
         acb = pool->free_aiocb;
         pool->free_aiocb = acb->next;
     } else {
-        acb = qemu_mallocz(pool->aiocb_size);
+        acb = g_malloc0(pool->aiocb_size);
         acb->pool = pool;
     }
     acb->bs = bs;
@@ -2635,6 +2724,220 @@ void qemu_aio_release(void *p)
     pool->free_aiocb = acb;
 }
 
+/**************************************************************/
+/* Coroutine block device emulation */
+
+typedef struct CoroutineIOCompletion {
+    Coroutine *coroutine;
+    int ret;
+} CoroutineIOCompletion;
+
+static void bdrv_co_io_em_complete(void *opaque, int ret)
+{
+    CoroutineIOCompletion *co = opaque;
+
+    co->ret = ret;
+    qemu_coroutine_enter(co->coroutine, NULL);
+}
+
+static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
+                                      int nb_sectors, QEMUIOVector *iov,
+                                      bool is_write)
+{
+    CoroutineIOCompletion co = {
+        .coroutine = qemu_coroutine_self(),
+    };
+    BlockDriverAIOCB *acb;
+
+    if (is_write) {
+        acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
+                                       bdrv_co_io_em_complete, &co);
+    } else {
+        acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
+                                      bdrv_co_io_em_complete, &co);
+    }
+
+    trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
+    if (!acb) {
+        return -EIO;
+    }
+    qemu_coroutine_yield();
+
+    return co.ret;
+}
+
+static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov)
+{
+    return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, false);
+}
+
+static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov)
+{
+    return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
+}
+
+static void coroutine_fn bdrv_flush_co_entry(void *opaque)
+{
+    RwCo *rwco = opaque;
+
+    rwco->ret = bdrv_co_flush(rwco->bs);
+}
+
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
+{
+    int ret;
+
+    if (!bs->drv) {
+        return 0;
+    }
+
+    /* Write back cached data to the OS even with cache=unsafe */
+    if (bs->drv->bdrv_co_flush_to_os) {
+        ret = bs->drv->bdrv_co_flush_to_os(bs);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    /* But don't actually force it to the disk with cache=unsafe */
+    if (bs->open_flags & BDRV_O_NO_FLUSH) {
+        return 0;
+    }
+
+    if (bs->drv->bdrv_co_flush_to_disk) {
+        return bs->drv->bdrv_co_flush_to_disk(bs);
+    } else if (bs->drv->bdrv_aio_flush) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else {
+        /*
+         * Some block drivers always operate in either writethrough or unsafe
+         * mode and don't support bdrv_flush therefore. Usually qemu doesn't
+         * know how the server works (because the behaviour is hardcoded or
+         * depends on server-side configuration), so we can't ensure that
+         * everything is safe on disk. Returning an error doesn't work because
+         * that would break guests even if the server operates in writethrough
+         * mode.
+         *
+         * Let's hope the user knows what he's doing.
+         */
+        return 0;
+    }
+}
+
+void bdrv_invalidate_cache(BlockDriverState *bs)
+{
+    if (bs->drv && bs->drv->bdrv_invalidate_cache) {
+        bs->drv->bdrv_invalidate_cache(bs);
+    }
+}
+
+void bdrv_invalidate_cache_all(void)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        bdrv_invalidate_cache(bs);
+    }
+}
+
+int bdrv_flush(BlockDriverState *bs)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .ret = NOT_DONE,
+    };
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_flush_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_flush_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+
+    return rwco.ret;
+}
+
+static void coroutine_fn bdrv_discard_co_entry(void *opaque)
+{
+    RwCo *rwco = opaque;
+
+    rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors);
+}
+
+int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
+                                 int nb_sectors)
+{
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    } else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    } else if (bs->read_only) {
+        return -EROFS;
+    } else if (bs->drv->bdrv_co_discard) {
+        return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
+    } else if (bs->drv->bdrv_aio_discard) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
+                                        bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else {
+        return 0;
+    }
+}
+
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .sector_num = sector_num,
+        .nb_sectors = nb_sectors,
+        .ret = NOT_DONE,
+    };
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_discard_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_discard_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+
+    return rwco.ret;
+}
+
 /**************************************************************/
 /* removable device support */
 
@@ -2644,77 +2947,52 @@ void qemu_aio_release(void *p)
 int bdrv_is_inserted(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
+
     if (!drv)
         return 0;
     if (!drv->bdrv_is_inserted)
-        return !bs->tray_open;
-    ret = drv->bdrv_is_inserted(bs);
-    return ret;
+        return 1;
+    return drv->bdrv_is_inserted(bs);
 }
 
 /**
- * Return TRUE if the media changed since the last call to this
- * function. It is currently only used for floppy disks
+ * Return whether the media changed since the last call to this
+ * function, or -ENOTSUP if we don't know.  Most drivers don't know.
  */
 int bdrv_media_changed(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
 
-    if (!drv || !drv->bdrv_media_changed)
-        ret = -ENOTSUP;
-    else
-        ret = drv->bdrv_media_changed(bs);
-    if (ret == -ENOTSUP)
-        ret = bs->media_changed;
-    bs->media_changed = 0;
-    return ret;
+    if (drv && drv->bdrv_media_changed) {
+        return drv->bdrv_media_changed(bs);
+    }
+    return -ENOTSUP;
 }
 
 /**
  * If eject_flag is TRUE, eject the media. Otherwise, close the tray
  */
-int bdrv_eject(BlockDriverState *bs, int eject_flag)
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
 
-    if (bs->locked) {
-        return -EBUSY;
-    }
-
-    if (!drv || !drv->bdrv_eject) {
-        ret = -ENOTSUP;
-    } else {
-        ret = drv->bdrv_eject(bs, eject_flag);
+    if (drv && drv->bdrv_eject) {
+        drv->bdrv_eject(bs, eject_flag);
     }
-    if (ret == -ENOTSUP) {
-        ret = 0;
-    }
-    if (ret >= 0) {
-        bs->tray_open = eject_flag;
-    }
-
-    return ret;
-}
-
-int bdrv_is_locked(BlockDriverState *bs)
-{
-    return bs->locked;
 }
 
 /**
  * Lock or unlock the media (if it is locked, the user won't be able
  * to eject it manually).
  */
-void bdrv_set_locked(BlockDriverState *bs, int locked)
+void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 {
     BlockDriver *drv = bs->drv;
 
-    bs->locked = locked;
-    if (drv && drv->bdrv_set_locked) {
-        drv->bdrv_set_locked(bs, locked);
+    trace_bdrv_lock_medium(bs, locked);
+
+    if (drv && drv->bdrv_lock_medium) {
+        drv->bdrv_lock_medium(bs, locked);
     }
 }
 
@@ -2740,7 +3018,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
     return NULL;
 }
 
-
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align)
+{
+    bs->buffer_alignment = align;
+}
 
 void *qemu_blockalign(BlockDriverState *bs, size_t size)
 {
@@ -2758,11 +3039,11 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
                     BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
             bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
 
-            bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+            bs->dirty_bitmap = g_malloc0(bitmap_size);
         }
     } else {
         if (bs->dirty_bitmap) {
-            qemu_free(bs->dirty_bitmap);
+            g_free(bs->dirty_bitmap);
             bs->dirty_bitmap = NULL;
         }
     }
@@ -2803,12 +3084,74 @@ int bdrv_in_use(BlockDriverState *bs)
     return bs->in_use;
 }
 
+void bdrv_iostatus_enable(BlockDriverState *bs)
+{
+    bs->iostatus_enabled = true;
+    bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
+}
+
+/* The I/O status is only enabled if the drive explicitly
+ * enables it _and_ the VM is configured to stop on errors */
+bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
+{
+    return (bs->iostatus_enabled &&
+           (bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
+            bs->on_write_error == BLOCK_ERR_STOP_ANY    ||
+            bs->on_read_error == BLOCK_ERR_STOP_ANY));
+}
+
+void bdrv_iostatus_disable(BlockDriverState *bs)
+{
+    bs->iostatus_enabled = false;
+}
+
+void bdrv_iostatus_reset(BlockDriverState *bs)
+{
+    if (bdrv_iostatus_is_enabled(bs)) {
+        bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
+    }
+}
+
+/* XXX: Today this is set by device models because it makes the implementation
+   quite simple. However, the block layer knows about the error, so it's
+   possible to implement this without device models being involved */
+void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
+{
+    if (bdrv_iostatus_is_enabled(bs) &&
+        bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
+        assert(error >= 0);
+        bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
+                                         BLOCK_DEVICE_IO_STATUS_FAILED;
+    }
+}
+
+void
+bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
+        enum BlockAcctType type)
+{
+    assert(type < BDRV_MAX_IOTYPE);
+
+    cookie->bytes = bytes;
+    cookie->start_time_ns = get_clock();
+    cookie->type = type;
+}
+
+void
+bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
+{
+    assert(cookie->type < BDRV_MAX_IOTYPE);
+
+    bs->nr_bytes[cookie->type] += cookie->bytes;
+    bs->nr_ops[cookie->type]++;
+    bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
+}
+
 int bdrv_img_create(const char *filename, const char *fmt,
                     const char *base_filename, const char *base_fmt,
                     char *options, uint64_t img_size, int flags)
 {
     QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *backing_fmt, *backing_file;
+    QEMUOptionParameter *backing_fmt, *backing_file, *size;
     BlockDriverState *bs = NULL;
     BlockDriver *drv, *proto_drv;
     BlockDriver *backing_drv = NULL;
@@ -2891,7 +3234,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
 
     // The size for the image must always be specified, with one exception:
     // If we are using a backing file, we can obtain the size from there
-    if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
+    size = get_option_parameter(param, BLOCK_OPT_SIZE);
+    if (size && size->value.n == -1) {
         if (backing_file && backing_file->value.s) {
             uint64_t size;
             char buf[32];
diff --git a/block.h b/block.h
index 097b78975df937782afe2ca82ce9498a63e8807a..a826059897ef47cdcc4355cf77bf1f9f20d7dfaf 100644 (file)
--- a/block.h
+++ b/block.h
@@ -4,6 +4,7 @@
 #include "qemu-aio.h"
 #include "qemu-common.h"
 #include "qemu-option.h"
+#include "qemu-coroutine.h"
 #include "qobject.h"
 
 /* block.c */
@@ -27,6 +28,41 @@ typedef struct QEMUSnapshotInfo {
     uint64_t vm_clock_nsec; /* VM clock relative to boot */
 } QEMUSnapshotInfo;
 
+/* Callbacks for block device models */
+typedef struct BlockDevOps {
+    /*
+     * Runs when virtual media changed (monitor commands eject, change)
+     * Argument load is true on load and false on eject.
+     * Beware: doesn't run when a host device's physical media
+     * changes.  Sure would be useful if it did.
+     * Device models with removable media must implement this callback.
+     */
+    void (*change_media_cb)(void *opaque, bool load);
+    /*
+     * Runs when an eject request is issued from the monitor, the tray
+     * is closed, and the medium is locked.
+     * Device models that do not implement is_medium_locked will not need
+     * this callback.  Device models that can lock the medium or tray might
+     * want to implement the callback and unlock the tray when "force" is
+     * true, even if they do not support eject requests.
+     */
+    void (*eject_request_cb)(void *opaque, bool force);
+    /*
+     * Is the virtual tray open?
+     * Device models implement this only when the device has a tray.
+     */
+    bool (*is_tray_open)(void *opaque);
+    /*
+     * Is the virtual medium locked into the device?
+     * Device models implement this only when device has such a lock.
+     */
+    bool (*is_medium_locked)(void *opaque);
+    /*
+     * Runs when the size changed (e.g. monitor command block_resize)
+     */
+    void (*resize_cb)(void *opaque);
+} BlockDevOps;
+
 #define BDRV_O_RDWR        0x0002
 #define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes in a snapshot */
 #define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */
@@ -50,6 +86,11 @@ typedef enum {
     BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
 } BlockMonEventAction;
 
+void bdrv_iostatus_enable(BlockDriverState *bs);
+void bdrv_iostatus_reset(BlockDriverState *bs);
+void bdrv_iostatus_disable(BlockDriverState *bs);
+bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
+void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
 void bdrv_mon_event(const BlockDriverState *bdrv,
                     BlockMonEventAction action, int is_read);
 void bdrv_info_print(Monitor *mon, const QObject *data);
@@ -68,13 +109,21 @@ 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_parse_cache_flags(const char *mode, int *flags);
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
               BlockDriver *drv);
 void bdrv_close(BlockDriverState *bs);
-int bdrv_attach(BlockDriverState *bs, DeviceState *qdev);
-void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
-DeviceState *bdrv_get_attached(BlockDriverState *bs);
+int bdrv_attach_dev(BlockDriverState *bs, void *dev);
+void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
+void bdrv_detach_dev(BlockDriverState *bs, void *dev);
+void *bdrv_get_attached_dev(BlockDriverState *bs);
+void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
+                      void *opaque);
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
+bool bdrv_dev_has_removable_media(BlockDriverState *bs);
+bool bdrv_dev_is_tray_open(BlockDriverState *bs);
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
@@ -85,10 +134,13 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
 int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     const void *buf, int count);
-int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
-    const uint8_t *buf, int nb_sectors);
+int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov);
+int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
 void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 int bdrv_commit(BlockDriverState *bs);
@@ -110,7 +162,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
 typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 typedef void BlockDriverCompletionFunc(void *opaque, int ret);
 typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
-                                    int sector_num);
+                                     int sector_num);
 BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
                                  QEMUIOVector *iov, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque);
@@ -118,7 +170,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *iov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
-                                BlockDriverCompletionFunc *cb, void *opaque);
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+                                   int64_t sector_num, int nb_sectors,
+                                   BlockDriverCompletionFunc *cb, void *opaque);
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
 typedef struct BlockRequest {
@@ -142,19 +197,22 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
         unsigned long int req, void *buf,
         BlockDriverCompletionFunc *cb, void *opaque);
 
+/* Invalidate any cached metadata used by image formats */
+void bdrv_invalidate_cache(BlockDriverState *bs);
+void bdrv_invalidate_cache_all(void);
+
 /* Ensure contents are flushed to disk.  */
 int bdrv_flush(BlockDriverState *bs);
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
 int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
+int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
-       int *pnum);
+                      int *pnum);
 
-#define BDRV_TYPE_HD     0
-#define BDRV_TYPE_CDROM  1
-#define BDRV_TYPE_FLOPPY 2
 #define BIOS_ATA_TRANSLATION_AUTO   0
 #define BIOS_ATA_TRANSLATION_NONE   1
 #define BIOS_ATA_TRANSLATION_LBA    2
@@ -163,28 +221,30 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 
 void bdrv_set_geometry_hint(BlockDriverState *bs,
                             int cyls, int heads, int secs);
-void bdrv_set_type_hint(BlockDriverState *bs, int type);
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
 void bdrv_get_geometry_hint(BlockDriverState *bs,
                             int *pcyls, int *pheads, int *psecs);
-int bdrv_get_type_hint(BlockDriverState *bs);
+typedef enum FDriveType {
+    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
+    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
+    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
+    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
+} FDriveType;
+
+void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
+                                   int *max_track, int *last_sect,
+                                   FDriveType drive_in, FDriveType *drive);
 int bdrv_get_translation_hint(BlockDriverState *bs);
 void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
                        BlockErrorAction on_write_error);
 BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
-void bdrv_set_removable(BlockDriverState *bs, int removable);
-int bdrv_is_removable(BlockDriverState *bs);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
-int bdrv_is_locked(BlockDriverState *bs);
-void bdrv_set_locked(BlockDriverState *bs, int locked);
-int bdrv_eject(BlockDriverState *bs, int eject_flag);
-void bdrv_set_change_cb(BlockDriverState *bs,
-                        void (*change_cb)(void *opaque, int reason),
-                        void *opaque);
+void bdrv_lock_medium(BlockDriverState *bs, bool locked);
+void bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
 BlockDriverState *bdrv_next(BlockDriverState *bs);
@@ -234,6 +294,9 @@ int bdrv_img_create(const char *filename, const char *fmt,
                     const char *base_filename, const char *base_fmt,
                     char *options, uint64_t img_size, int flags);
 
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
+void *qemu_blockalign(BlockDriverState *bs, size_t size);
+
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 
 void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
@@ -245,6 +308,23 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs);
 void bdrv_set_in_use(BlockDriverState *bs, int in_use);
 int bdrv_in_use(BlockDriverState *bs);
 
+enum BlockAcctType {
+    BDRV_ACCT_READ,
+    BDRV_ACCT_WRITE,
+    BDRV_ACCT_FLUSH,
+    BDRV_MAX_IOTYPE,
+};
+
+typedef struct BlockAcctCookie {
+    int64_t bytes;
+    int64_t start_time_ns;
+    enum BlockAcctType type;
+} BlockAcctCookie;
+
+void bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
+        int64_t bytes, enum BlockAcctType type);
+void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie);
+
 typedef enum {
     BLKDBG_L1_UPDATE,
 
@@ -296,4 +376,43 @@ typedef enum {
 #define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 
+
+/* Convenience for block device models */
+
+typedef struct BlockConf {
+    BlockDriverState *bs;
+    uint16_t physical_block_size;
+    uint16_t logical_block_size;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+    int32_t bootindex;
+    uint32_t discard_granularity;
+} BlockConf;
+
+static inline unsigned int get_physical_block_exp(BlockConf *conf)
+{
+    unsigned int exp = 0, size;
+
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
+        exp++;
+    }
+
+    return exp;
+}
+
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
+    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
+    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
+                       _conf.logical_block_size, 512),                  \
+    DEFINE_PROP_UINT16("physical_block_size", _state,                   \
+                       _conf.physical_block_size, 512),                 \
+    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
+    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, 0)
+
 #endif
+
index cd9eb8006a1e781628e5a013bafeeae099cbdf96..9b885359e4a320ae8b0bee4931bb1fb3d2b71857 100644 (file)
@@ -214,7 +214,7 @@ static int add_rule(QemuOpts *opts, void *opaque)
     }
 
     /* Set attributes common for all actions */
-    rule = qemu_mallocz(sizeof(*rule));
+    rule = g_malloc0(sizeof(*rule));
     *rule = (struct BlkdebugRule) {
         .event  = event,
         .action = d->action,
@@ -392,16 +392,11 @@ static void blkdebug_close(BlockDriverState *bs)
     for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
         QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
             QLIST_REMOVE(rule, next);
-            qemu_free(rule);
+            g_free(rule);
         }
     }
 }
 
-static int blkdebug_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -454,7 +449,6 @@ static BlockDriver bdrv_blkdebug = {
 
     .bdrv_file_open     = blkdebug_open,
     .bdrv_close         = blkdebug_close,
-    .bdrv_flush         = blkdebug_flush,
 
     .bdrv_aio_readv     = blkdebug_aio_readv,
     .bdrv_aio_writev    = blkdebug_aio_writev,
index c7522b4093c8c2486575e549d2ba095e7b1bf9b5..483f3b3cfe7b13afcc1f3a2c06f8dc3e4e40d742 100644 (file)
@@ -116,14 +116,6 @@ static void blkverify_close(BlockDriverState *bs)
     s->test_file = NULL;
 }
 
-static int blkverify_flush(BlockDriverState *bs)
-{
-    BDRVBlkverifyState *s = bs->opaque;
-
-    /* Only flush test file, the raw file is not important */
-    return bdrv_flush(s->test_file);
-}
-
 static int64_t blkverify_getlength(BlockDriverState *bs)
 {
     BDRVBlkverifyState *s = bs->opaque;
@@ -368,7 +360,6 @@ static BlockDriver bdrv_blkverify = {
 
     .bdrv_file_open     = blkverify_open,
     .bdrv_close         = blkverify_close,
-    .bdrv_flush         = blkverify_flush,
 
     .bdrv_aio_readv     = blkverify_aio_readv,
     .bdrv_aio_writev    = blkverify_aio_writev,
index 5fe2fa35804d32cbb0a2934a077875fcca13ada9..ab7944dc43dfc82b52d8686eb47c521ba6cc07a9 100644 (file)
@@ -80,6 +80,7 @@ struct bochs_header {
 };
 
 typedef struct BDRVBochsState {
+    CoMutex lock;
     uint32_t *catalog_bitmap;
     int catalog_size;
 
@@ -136,7 +137,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
     }
 
     s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
-    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
+    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
     if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
                    s->catalog_size * 4) != s->catalog_size * 4)
        goto fail;
@@ -150,6 +151,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
 
     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
@@ -207,10 +209,21 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVBochsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = bochs_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void bochs_close(BlockDriverState *bs)
 {
     BDRVBochsState *s = bs->opaque;
-    qemu_free(s->catalog_bitmap);
+    g_free(s->catalog_bitmap);
 }
 
 static BlockDriver bdrv_bochs = {
@@ -218,7 +231,7 @@ static BlockDriver bdrv_bochs = {
     .instance_size     = sizeof(BDRVBochsState),
     .bdrv_probe                = bochs_probe,
     .bdrv_open         = bochs_open,
-    .bdrv_read         = bochs_read,
+    .bdrv_read          = bochs_co_read,
     .bdrv_close                = bochs_close,
 };
 
index fe015c4255e7fdf0f8fd0d7faae2f061a96500f1..7570eb8e74585b305acad77c4d18aebb88179e7a 100644 (file)
 #include <zlib.h>
 
 typedef struct BDRVCloopState {
+    CoMutex lock;
     uint32_t block_size;
     uint32_t n_blocks;
-    uint64_toffsets;
+    uint64_t *offsets;
     uint32_t sectors_per_block;
     uint32_t current_block;
     uint8_t *compressed_block;
@@ -39,21 +40,23 @@ typedef struct BDRVCloopState {
 
 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
-    const char* magic_version_2_0="#!/bin/sh\n"
-       "#V2.0 Format\n"
-       "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
-    int length=strlen(magic_version_2_0);
-    if(length>buf_size)
-       length=buf_size;
-    if(!memcmp(magic_version_2_0,buf,length))
-       return 2;
+    const char *magic_version_2_0 = "#!/bin/sh\n"
+        "#V2.0 Format\n"
+        "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
+    int length = strlen(magic_version_2_0);
+    if (length > buf_size) {
+        length = buf_size;
+    }
+    if (!memcmp(magic_version_2_0, buf, length)) {
+        return 2;
+    }
     return 0;
 }
 
 static int cloop_open(BlockDriverState *bs, int flags)
 {
     BDRVCloopState *s = bs->opaque;
-    uint32_t offsets_size,max_compressed_block_size=1,i;
+    uint32_t offsets_size, max_compressed_block_size = 1, i;
 
     bs->read_only = 1;
 
@@ -70,29 +73,32 @@ static int cloop_open(BlockDriverState *bs, int flags)
 
     /* read offsets */
     offsets_size = s->n_blocks * sizeof(uint64_t);
-    s->offsets = qemu_malloc(offsets_size);
+    s->offsets = g_malloc(offsets_size);
     if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
             offsets_size) {
-       goto cloop_close;
+        goto cloop_close;
     }
     for(i=0;i<s->n_blocks;i++) {
-       s->offsets[i]=be64_to_cpu(s->offsets[i]);
-       if(i>0) {
-           uint32_t size=s->offsets[i]-s->offsets[i-1];
-           if(size>max_compressed_block_size)
-               max_compressed_block_size=size;
-       }
+        s->offsets[i] = be64_to_cpu(s->offsets[i]);
+        if (i > 0) {
+            uint32_t size = s->offsets[i] - s->offsets[i - 1];
+            if (size > max_compressed_block_size) {
+                max_compressed_block_size = size;
+            }
+        }
     }
 
     /* initialize zlib engine */
-    s->compressed_block = qemu_malloc(max_compressed_block_size+1);
-    s->uncompressed_block = qemu_malloc(s->block_size);
-    if(inflateInit(&s->zstream) != Z_OK)
-       goto cloop_close;
-    s->current_block=s->n_blocks;
+    s->compressed_block = g_malloc(max_compressed_block_size + 1);
+    s->uncompressed_block = g_malloc(s->block_size);
+    if (inflateInit(&s->zstream) != Z_OK) {
+        goto cloop_close;
+    }
+    s->current_block = s->n_blocks;
 
     s->sectors_per_block = s->block_size/512;
-    bs->total_sectors = s->n_blocks*s->sectors_per_block;
+    bs->total_sectors = s->n_blocks * s->sectors_per_block;
+    qemu_co_mutex_init(&s->lock);
     return 0;
 
 cloop_close:
@@ -103,27 +109,30 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
 {
     BDRVCloopState *s = bs->opaque;
 
-    if(s->current_block != block_num) {
-       int ret;
-        uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
+    if (s->current_block != block_num) {
+        int ret;
+        uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
 
         ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
                          bytes);
-        if (ret != bytes)
+        if (ret != bytes) {
+            return -1;
+        }
+
+        s->zstream.next_in = s->compressed_block;
+        s->zstream.avail_in = bytes;
+        s->zstream.next_out = s->uncompressed_block;
+        s->zstream.avail_out = s->block_size;
+        ret = inflateReset(&s->zstream);
+        if (ret != Z_OK) {
+            return -1;
+        }
+        ret = inflate(&s->zstream, Z_FINISH);
+        if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
             return -1;
+        }
 
-       s->zstream.next_in = s->compressed_block;
-       s->zstream.avail_in = bytes;
-       s->zstream.next_out = s->uncompressed_block;
-       s->zstream.avail_out = s->block_size;
-       ret = inflateReset(&s->zstream);
-       if(ret != Z_OK)
-           return -1;
-       ret = inflate(&s->zstream, Z_FINISH);
-       if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
-           return -1;
-
-       s->current_block = block_num;
+        s->current_block = block_num;
     }
     return 0;
 }
@@ -134,33 +143,48 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
     BDRVCloopState *s = bs->opaque;
     int i;
 
-    for(i=0;i<nb_sectors;i++) {
-       uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
-           block_num=(sector_num+i)/s->sectors_per_block;
-       if(cloop_read_block(bs, block_num) != 0)
-           return -1;
-       memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
+    for (i = 0; i < nb_sectors; i++) {
+        uint32_t sector_offset_in_block =
+            ((sector_num + i) % s->sectors_per_block),
+            block_num = (sector_num + i) / s->sectors_per_block;
+        if (cloop_read_block(bs, block_num) != 0) {
+            return -1;
+        }
+        memcpy(buf + i * 512,
+            s->uncompressed_block + sector_offset_in_block * 512, 512);
     }
     return 0;
 }
 
+static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCloopState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cloop_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cloop_close(BlockDriverState *bs)
 {
     BDRVCloopState *s = bs->opaque;
-    if(s->n_blocks>0)
-       free(s->offsets);
-    free(s->compressed_block);
-    free(s->uncompressed_block);
+    if (s->n_blocks > 0) {
+        g_free(s->offsets);
+    }
+    g_free(s->compressed_block);
+    g_free(s->uncompressed_block);
     inflateEnd(&s->zstream);
 }
 
 static BlockDriver bdrv_cloop = {
-    .format_name       = "cloop",
-    .instance_size     = sizeof(BDRVCloopState),
-    .bdrv_probe                = cloop_probe,
-    .bdrv_open         = cloop_open,
-    .bdrv_read         = cloop_read,
-    .bdrv_close                = cloop_close,
+    .format_name    = "cloop",
+    .instance_size  = sizeof(BDRVCloopState),
+    .bdrv_probe     = cloop_probe,
+    .bdrv_open      = cloop_open,
+    .bdrv_read      = cloop_co_read,
+    .bdrv_close     = cloop_close,
 };
 
 static void bdrv_cloop_init(void)
index 4cf543c8327d79743fb102e668e49e69c9103409..089d395c40490440b2d3afb34fb0fdb03e9ad508 100644 (file)
@@ -42,6 +42,7 @@ struct cow_header_v2 {
 };
 
 typedef struct BDRVCowState {
+    CoMutex lock;
     int64_t cow_sectors_offset;
 } BDRVCowState;
 
@@ -84,6 +85,7 @@ static int cow_open(BlockDriverState *bs, int flags)
 
     bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
     s->cow_sectors_offset = (bitmap_size + 511) & ~511;
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
@@ -199,6 +201,17 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int cow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
@@ -213,6 +226,17 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
     return cow_update_bitmap(bs, sector_num, nb_sectors);
 }
 
+static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cow_close(BlockDriverState *bs)
 {
 }
@@ -282,9 +306,9 @@ exit:
     return ret;
 }
 
-static int cow_flush(BlockDriverState *bs)
+static coroutine_fn int cow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 static QEMUOptionParameter cow_create_options[] = {
@@ -302,16 +326,18 @@ static QEMUOptionParameter cow_create_options[] = {
 };
 
 static BlockDriver bdrv_cow = {
-    .format_name       = "cow",
-    .instance_size     = sizeof(BDRVCowState),
-    .bdrv_probe                = cow_probe,
-    .bdrv_open         = cow_open,
-    .bdrv_read         = cow_read,
-    .bdrv_write                = cow_write,
-    .bdrv_close                = cow_close,
-    .bdrv_create       = cow_create,
-    .bdrv_flush                = cow_flush,
-    .bdrv_is_allocated = cow_is_allocated,
+    .format_name    = "cow",
+    .instance_size  = sizeof(BDRVCowState),
+
+    .bdrv_probe     = cow_probe,
+    .bdrv_open      = cow_open,
+    .bdrv_close     = cow_close,
+    .bdrv_create    = cow_create,
+
+    .bdrv_read              = cow_co_read,
+    .bdrv_write             = cow_co_write,
+    .bdrv_co_flush_to_disk  = cow_co_flush,
+    .bdrv_is_allocated      = cow_is_allocated,
 
     .create_options = cow_create_options,
 };
index 407f0955a39198c216c5e651d2b41836175e5897..4209ac88cefc1eb46465bf6b3fe19020f70c8fe0 100644 (file)
@@ -47,7 +47,12 @@ struct BDRVCURLState;
 
 typedef struct CURLAIOCB {
     BlockDriverAIOCB common;
+    QEMUBH *bh;
     QEMUIOVector *qiov;
+
+    int64_t sector_num;
+    int nb_sectors;
+
     size_t start;
     size_t end;
 } CURLAIOCB;
@@ -76,6 +81,7 @@ typedef struct BDRVCURLState {
 
 static void curl_clean_state(CURLState *s);
 static void curl_multi_do(void *arg);
+static int curl_aio_flush(void *opaque);
 
 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
                         void *s, void *sp)
@@ -83,14 +89,16 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
     DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
     switch (action) {
         case CURL_POLL_IN:
-            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
+                                    NULL, s);
             break;
         case CURL_POLL_OUT:
-            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
+                                    NULL, s);
             break;
         case CURL_POLL_INOUT:
-            qemu_aio_set_fd_handler(fd, curl_multi_do,
-                                    curl_multi_do, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
+                                    curl_aio_flush, NULL, s);
             break;
         case CURL_POLL_REMOVE:
             qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
@@ -229,6 +237,23 @@ static void curl_multi_do(void *arg)
             {
                 CURLState *state = NULL;
                 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
+
+                /* ACBs for successful messages get completed in curl_read_cb */
+                if (msg->data.result != CURLE_OK) {
+                    int i;
+                    for (i = 0; i < CURL_NUM_ACB; i++) {
+                        CURLAIOCB *acb = state->acb[i];
+
+                        if (acb == NULL) {
+                            continue;
+                        }
+
+                        acb->common.cb(acb->common.opaque, -EIO);
+                        qemu_aio_release(acb);
+                        state->acb[i] = NULL;
+                    }
+                }
+
                 curl_clean_state(state);
                 break;
             }
@@ -277,7 +302,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
     curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
     curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
     curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
-    
+    curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
+
 #ifdef DEBUG_VERBOSE
     curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
 #endif
@@ -310,7 +336,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 
     static int inited = 0;
 
-    file = qemu_strdup(filename);
+    file = g_strdup(filename);
     s->readahead_size = READ_AHEAD_SIZE;
 
     /* Parse a trailing ":readahead=#:" param, if present. */
@@ -390,10 +416,25 @@ out:
     curl_easy_cleanup(state->curl);
     state->curl = NULL;
 out_noclean:
-    qemu_free(file);
+    g_free(file);
     return -EINVAL;
 }
 
+static int curl_aio_flush(void *opaque)
+{
+    BDRVCURLState *s = opaque;
+    int i, j;
+
+    for (i=0; i < CURL_NUM_STATES; i++) {
+        for(j=0; j < CURL_NUM_ACB; j++) {
+            if (s->states[i].acb[j]) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
 static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     // Do we have to implement canceling? Seems to work without...
@@ -404,61 +445,86 @@ static AIOPool curl_aio_pool = {
     .cancel             = curl_aio_cancel,
 };
 
-static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+
+static void curl_readv_bh_cb(void *p)
 {
-    BDRVCURLState *s = bs->opaque;
-    CURLAIOCB *acb;
-    size_t start = sector_num * SECTOR_SIZE;
-    size_t end;
     CURLState *state;
 
-    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
+    CURLAIOCB *acb = p;
+    BDRVCURLState *s = acb->common.bs->opaque;
 
-    acb->qiov = qiov;
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    size_t start = acb->sector_num * SECTOR_SIZE;
+    size_t end;
 
     // In case we have the requested data already (e.g. read-ahead),
     // we can just call the callback and be done.
-
-    switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
+    switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
         case FIND_RET_OK:
             qemu_aio_release(acb);
             // fall through
         case FIND_RET_WAIT:
-            return &acb->common;
+            return;
         default:
             break;
     }
 
     // No cache found, so let's start a new request
-
     state = curl_init_state(s);
-    if (!state)
-        return NULL;
+    if (!state) {
+        acb->common.cb(acb->common.opaque, -EIO);
+        qemu_aio_release(acb);
+        return;
+    }
 
     acb->start = 0;
-    acb->end = (nb_sectors * SECTOR_SIZE);
+    acb->end = (acb->nb_sectors * SECTOR_SIZE);
 
     state->buf_off = 0;
     if (state->orig_buf)
-        qemu_free(state->orig_buf);
+        g_free(state->orig_buf);
     state->buf_start = start;
     state->buf_len = acb->end + s->readahead_size;
     end = MIN(start + state->buf_len, s->len) - 1;
-    state->orig_buf = qemu_malloc(state->buf_len);
+    state->orig_buf = g_malloc(state->buf_len);
     state->acb[0] = acb;
 
     snprintf(state->range, 127, "%zd-%zd", start, end);
     DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
-            (nb_sectors * SECTOR_SIZE), start, state->range);
+            (acb->nb_sectors * SECTOR_SIZE), start, state->range);
     curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
 
     curl_multi_add_handle(s->multi, state->curl);
     curl_multi_do(s);
 
+}
+
+static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    CURLAIOCB *acb;
+
+    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
+
+    if (!acb) {
+        return NULL;
+    }
+
+    acb->qiov = qiov;
+    acb->sector_num = sector_num;
+    acb->nb_sectors = nb_sectors;
+
+    acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
+
+    if (!acb->bh) {
+        DPRINTF("CURL: qemu_bh_new failed\n");
+        return NULL;
+    }
+
+    qemu_bh_schedule(acb->bh);
     return &acb->common;
 }
 
@@ -476,7 +542,7 @@ static void curl_close(BlockDriverState *bs)
             s->states[i].curl = NULL;
         }
         if (s->states[i].orig_buf) {
-            qemu_free(s->states[i].orig_buf);
+            g_free(s->states[i].orig_buf);
             s->states[i].orig_buf = NULL;
         }
     }
index a3c815b862c6600eb68be4d112feaab4fb28b596..37902a4347ae579fb3ad17be838b3224354e9a84 100644 (file)
@@ -28,6 +28,7 @@
 #include <zlib.h>
 
 typedef struct BDRVDMGState {
+    CoMutex lock;
     /* each chunk contains a certain number of sectors,
      * offsets[i] is the offset in the .dmg file,
      * lengths[i] is the length of the compressed chunk,
@@ -127,11 +128,11 @@ static int dmg_open(BlockDriverState *bs, int flags)
 
            chunk_count = (count-204)/40;
            new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
-           s->types = qemu_realloc(s->types, new_size/2);
-           s->offsets = qemu_realloc(s->offsets, new_size);
-           s->lengths = qemu_realloc(s->lengths, new_size);
-           s->sectors = qemu_realloc(s->sectors, new_size);
-           s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
+           s->types = g_realloc(s->types, new_size/2);
+           s->offsets = g_realloc(s->offsets, new_size);
+           s->lengths = g_realloc(s->lengths, new_size);
+           s->sectors = g_realloc(s->sectors, new_size);
+           s->sectorcounts = g_realloc(s->sectorcounts, new_size);
 
            for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
                s->types[i] = read_uint32(bs, offset);
@@ -170,13 +171,14 @@ static int dmg_open(BlockDriverState *bs, int flags)
     }
 
     /* initialize zlib engine */
-    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
-    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
+    s->compressed_chunk = g_malloc(max_compressed_size+1);
+    s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
     if(inflateInit(&s->zstream) != Z_OK)
        goto fail;
 
     s->current_chunk = s->n_chunks;
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     return -1;
@@ -280,6 +282,17 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVDMGState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = dmg_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void dmg_close(BlockDriverState *bs)
 {
     BDRVDMGState *s = bs->opaque;
@@ -300,7 +313,7 @@ static BlockDriver bdrv_dmg = {
     .instance_size     = sizeof(BDRVDMGState),
     .bdrv_probe                = dmg_probe,
     .bdrv_open         = dmg_open,
-    .bdrv_read         = dmg_read,
+    .bdrv_read          = dmg_co_read,
     .bdrv_close                = dmg_close,
 };
 
diff --git a/block/iscsi.c b/block/iscsi.c
new file mode 100644 (file)
index 0000000..938c568
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * QEMU Block driver for iSCSI images
+ *
+ * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.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 "config-host.h"
+
+#include <poll.h>
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "block_int.h"
+#include "trace.h"
+
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+
+
+typedef struct IscsiLun {
+    struct iscsi_context *iscsi;
+    int lun;
+    int block_size;
+    unsigned long num_blocks;
+} IscsiLun;
+
+typedef struct IscsiAIOCB {
+    BlockDriverAIOCB common;
+    QEMUIOVector *qiov;
+    QEMUBH *bh;
+    IscsiLun *iscsilun;
+    struct scsi_task *task;
+    uint8_t *buf;
+    int status;
+    int canceled;
+    size_t read_size;
+    size_t read_offset;
+} IscsiAIOCB;
+
+struct IscsiTask {
+    IscsiLun *iscsilun;
+    BlockDriverState *bs;
+    int status;
+    int complete;
+};
+
+static void
+iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
+                    void *private_data)
+{
+}
+
+static void
+iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
+    IscsiLun *iscsilun = acb->iscsilun;
+
+    acb->common.cb(acb->common.opaque, -ECANCELED);
+    acb->canceled = 1;
+
+    /* send a task mgmt call to the target to cancel the task on the target */
+    iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
+                                     iscsi_abort_task_cb, NULL);
+
+    /* then also cancel the task locally in libiscsi */
+    iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
+}
+
+static AIOPool iscsi_aio_pool = {
+    .aiocb_size         = sizeof(IscsiAIOCB),
+    .cancel             = iscsi_aio_cancel,
+};
+
+
+static void iscsi_process_read(void *arg);
+static void iscsi_process_write(void *arg);
+
+static int iscsi_process_flush(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+
+    return iscsi_queue_length(iscsilun->iscsi) > 0;
+}
+
+static void
+iscsi_set_events(IscsiLun *iscsilun)
+{
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
+                           (iscsi_which_events(iscsi) & POLLOUT)
+                           ? iscsi_process_write : NULL,
+                           iscsi_process_flush, NULL, iscsilun);
+}
+
+static void
+iscsi_process_read(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    iscsi_service(iscsi, POLLIN);
+    iscsi_set_events(iscsilun);
+}
+
+static void
+iscsi_process_write(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    iscsi_service(iscsi, POLLOUT);
+    iscsi_set_events(iscsilun);
+}
+
+
+static int
+iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
+{
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh) {
+        error_report("oom: could not create iscsi bh");
+        return -EIO;
+    }
+
+    qemu_bh_schedule(acb->bh);
+    return 0;
+}
+
+static void
+iscsi_readv_writev_bh_cb(void *p)
+{
+    IscsiAIOCB *acb = p;
+
+    qemu_bh_delete(acb->bh);
+
+    if (acb->canceled == 0) {
+        acb->common.cb(acb->common.opaque, acb->status);
+    }
+
+    qemu_aio_release(acb);
+}
+
+
+static void
+iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
+                     void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
+
+    g_free(acb->buf);
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status < 0) {
+        error_report("Failed to write10 data to iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
+{
+    return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                 QEMUIOVector *qiov, int nb_sectors,
+                 BlockDriverCompletionFunc *cb,
+                 void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+    size_t size;
+    int fua = 0;
+
+    /* set FUA on writes when cache mode is write through */
+    if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
+        fua = 1;
+    }
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+    trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
+
+    acb->iscsilun = iscsilun;
+    acb->qiov     = qiov;
+
+    acb->canceled   = 0;
+
+    /* XXX we should pass the iovec to write10 to avoid the extra copy */
+    /* this will allow us to get rid of 'buf' completely */
+    size = nb_sectors * BDRV_SECTOR_SIZE;
+    acb->buf = g_malloc(size);
+    qemu_iovec_to_buffer(acb->qiov, acb->buf);
+    acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
+                              sector_qemu2lun(sector_num, iscsilun),
+                              fua, 0, iscsilun->block_size,
+                              iscsi_aio_write10_cb, acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send write10 command. %s",
+                     iscsi_get_error(iscsi));
+        g_free(acb->buf);
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+static void
+iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
+                    void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status != 0) {
+        error_report("Failed to read10 data from iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                QEMUIOVector *qiov, int nb_sectors,
+                BlockDriverCompletionFunc *cb,
+                void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+    size_t qemu_read_size, lun_read_size;
+    int i;
+
+    qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+    trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
+
+    acb->iscsilun = iscsilun;
+    acb->qiov     = qiov;
+
+    acb->canceled    = 0;
+    acb->read_size   = qemu_read_size;
+    acb->buf         = NULL;
+
+    /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
+     * may be misaligned to the LUN, so we may need to read some extra
+     * data.
+     */
+    acb->read_offset = 0;
+    if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
+        uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
+
+        acb->read_offset  = bdrv_offset % iscsilun->block_size;
+    }
+
+    lun_read_size  = (qemu_read_size + iscsilun->block_size
+                     + acb->read_offset - 1)
+                     / iscsilun->block_size * iscsilun->block_size;
+    acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
+                             sector_qemu2lun(sector_num, iscsilun),
+                             lun_read_size, iscsilun->block_size,
+                             iscsi_aio_read10_cb, acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send read10 command. %s",
+                     iscsi_get_error(iscsi));
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    for (i = 0; i < acb->qiov->niov; i++) {
+        scsi_task_add_data_in_buffer(acb->task,
+                acb->qiov->iov[i].iov_len,
+                acb->qiov->iov[i].iov_base);
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+
+static void
+iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
+                     void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status < 0) {
+        error_report("Failed to sync10 data on iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_flush(BlockDriverState *bs,
+                BlockDriverCompletionFunc *cb, void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+
+    acb->iscsilun = iscsilun;
+    acb->canceled   = 0;
+
+    acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
+                                         0, 0, 0, 0,
+                                         iscsi_synccache10_cb,
+                                         acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send synchronizecache10 command. %s",
+                     iscsi_get_error(iscsi));
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+static int64_t
+iscsi_getlength(BlockDriverState *bs)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    int64_t len;
+
+    len  = iscsilun->num_blocks;
+    len *= iscsilun->block_size;
+
+    return len;
+}
+
+static void
+iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
+                        void *command_data, void *opaque)
+{
+    struct IscsiTask *itask = opaque;
+    struct scsi_readcapacity10 *rc10;
+    struct scsi_task *task = command_data;
+
+    if (status != 0) {
+        error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        itask->status   = 1;
+        itask->complete = 1;
+        scsi_free_scsi_task(task);
+        return;
+    }
+
+    rc10 = scsi_datain_unmarshall(task);
+    if (rc10 == NULL) {
+        error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
+        itask->status   = 1;
+        itask->complete = 1;
+        scsi_free_scsi_task(task);
+        return;
+    }
+
+    itask->iscsilun->block_size = rc10->block_size;
+    itask->iscsilun->num_blocks = rc10->lba;
+    itask->bs->total_sectors = (uint64_t)rc10->lba *
+                               rc10->block_size / BDRV_SECTOR_SIZE ;
+
+    itask->status   = 0;
+    itask->complete = 1;
+    scsi_free_scsi_task(task);
+}
+
+
+static void
+iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
+                 void *opaque)
+{
+    struct IscsiTask *itask = opaque;
+    struct scsi_task *task;
+
+    if (status != 0) {
+        itask->status   = 1;
+        itask->complete = 1;
+        return;
+    }
+
+    task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
+                                   iscsi_readcapacity10_cb, opaque);
+    if (task == NULL) {
+        error_report("iSCSI: failed to send readcapacity command.");
+        itask->status   = 1;
+        itask->complete = 1;
+        return;
+    }
+}
+
+/*
+ * We support iscsi url's on the form
+ * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
+ */
+static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = NULL;
+    struct iscsi_url *iscsi_url = NULL;
+    struct IscsiTask task;
+    int ret;
+
+    if ((BDRV_SECTOR_SIZE % 512) != 0) {
+        error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
+                     "BDRV_SECTOR_SIZE(%lld) is not a multiple "
+                     "of 512", BDRV_SECTOR_SIZE);
+        return -EINVAL;
+    }
+
+    memset(iscsilun, 0, sizeof(IscsiLun));
+
+    /* Should really append the KVM name after the ':' here */
+    iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
+    if (iscsi == NULL) {
+        error_report("iSCSI: Failed to create iSCSI context.");
+        ret = -ENOMEM;
+        goto failed;
+    }
+
+    iscsi_url = iscsi_parse_full_url(iscsi, filename);
+    if (iscsi_url == NULL) {
+        error_report("Failed to parse URL : %s %s", filename,
+                     iscsi_get_error(iscsi));
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
+        error_report("iSCSI: Failed to set target name.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_url->user != NULL) {
+        ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
+                                              iscsi_url->passwd);
+        if (ret != 0) {
+            error_report("Failed to set initiator username and password");
+            ret = -EINVAL;
+            goto failed;
+        }
+    }
+    if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
+        error_report("iSCSI: Failed to set session type to normal.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+    task.iscsilun = iscsilun;
+    task.status = 0;
+    task.complete = 0;
+    task.bs = bs;
+
+    iscsilun->iscsi = iscsi;
+    iscsilun->lun   = iscsi_url->lun;
+
+    if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
+                                 iscsi_connect_cb, &task)
+        != 0) {
+        error_report("iSCSI: Failed to start async connect.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    while (!task.complete) {
+        iscsi_set_events(iscsilun);
+        qemu_aio_wait();
+    }
+    if (task.status != 0) {
+        error_report("iSCSI: Failed to connect to LUN : %s",
+                     iscsi_get_error(iscsi));
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_url != NULL) {
+        iscsi_destroy_url(iscsi_url);
+    }
+    return 0;
+
+failed:
+    if (iscsi_url != NULL) {
+        iscsi_destroy_url(iscsi_url);
+    }
+    if (iscsi != NULL) {
+        iscsi_destroy_context(iscsi);
+    }
+    memset(iscsilun, 0, sizeof(IscsiLun));
+    return ret;
+}
+
+static void iscsi_close(BlockDriverState *bs)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
+    iscsi_destroy_context(iscsi);
+    memset(iscsilun, 0, sizeof(IscsiLun));
+}
+
+static BlockDriver bdrv_iscsi = {
+    .format_name     = "iscsi",
+    .protocol_name   = "iscsi",
+
+    .instance_size   = sizeof(IscsiLun),
+    .bdrv_file_open  = iscsi_open,
+    .bdrv_close      = iscsi_close,
+
+    .bdrv_getlength  = iscsi_getlength,
+
+    .bdrv_aio_readv  = iscsi_aio_readv,
+    .bdrv_aio_writev = iscsi_aio_writev,
+    .bdrv_aio_flush  = iscsi_aio_flush,
+};
+
+static void iscsi_block_init(void)
+{
+    bdrv_register(&bdrv_iscsi);
+}
+
+block_init(iscsi_block_init);
index c8dc763c6bb4dd5d7f21258de1fac7edeeb9b54a..882b2dc84ae1e5149ac2b0524aea7e87c81fd538 100644 (file)
 
 #include "qemu-common.h"
 #include "nbd.h"
+#include "block_int.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 {
+    CoMutex lock;
     int sock;
+    uint32_t nbdflags;
     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);
+    file = g_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 = g_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 = g_strdup(unixpath);
     } else {
-        uint16_t port = NBD_DEFAULT_PORT;
-        char *p, *r;
-        char hostname[128];
+        s->host_spec = g_strdup(host_spec);
+    }
 
-        pstrcpy(hostname, 128, host);
+    err = 0;
 
-        p = strchr(hostname, ':');
-        if (p != NULL) {
-            *p = '\0';
-            p++;
+out:
+    g_free(file);
+    if (err != 0) {
+        g_free(s->export_name);
+        g_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;
 
-        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, &s->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);
+
+    qemu_co_mutex_init(&s->lock);
+    return result;
 }
 
 static int nbd_read(BlockDriverState *bs, int64_t sector_num,
@@ -181,18 +240,35 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static void nbd_close(BlockDriverState *bs)
+static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
 {
+    int ret;
     BDRVNBDState *s = bs->opaque;
-    struct nbd_request request;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
 
-    request.type = NBD_CMD_DISC;
-    request.handle = (uint64_t)(intptr_t)bs;
-    request.from = 0;
-    request.len = 0;
-    nbd_send_request(s->sock, &request);
+static coroutine_fn int nbd_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVNBDState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
+static void nbd_close(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    g_free(s->export_name);
+    g_free(s->host_spec);
 
-    close(s->sock);
+    nbd_teardown_connection(bs);
 }
 
 static int64_t nbd_getlength(BlockDriverState *bs)
@@ -206,8 +282,8 @@ static BlockDriver bdrv_nbd = {
     .format_name       = "nbd",
     .instance_size     = sizeof(BDRVNBDState),
     .bdrv_file_open    = nbd_open,
-    .bdrv_read         = nbd_read,
-    .bdrv_write                = nbd_write,
+    .bdrv_read          = nbd_co_read,
+    .bdrv_write         = nbd_co_write,
     .bdrv_close                = nbd_close,
     .bdrv_getlength    = nbd_getlength,
     .protocol_name     = "nbd",
index 35a14aa4224ae379b8a15579fbb3c8abed69e717..d30f0ecf7775346e0b8f330a7f9f1cd13fd71f64 100644 (file)
@@ -43,9 +43,10 @@ struct parallels_header {
     uint32_t catalog_entries;
     uint32_t nb_sectors;
     char padding[24];
-} __attribute__((packed));
+} QEMU_PACKED;
 
 typedef struct BDRVParallelsState {
+    CoMutex lock;
 
     uint32_t *catalog_bitmap;
     int catalog_size;
@@ -88,17 +89,18 @@ static int parallels_open(BlockDriverState *bs, int flags)
     s->tracks = le32_to_cpu(ph.tracks);
 
     s->catalog_size = le32_to_cpu(ph.catalog_entries);
-    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
+    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
     if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
        s->catalog_size * 4)
        goto fail;
     for (i = 0; i < s->catalog_size; i++)
        le32_to_cpus(&s->catalog_bitmap[i]);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     if (s->catalog_bitmap)
-       qemu_free(s->catalog_bitmap);
+       g_free(s->catalog_bitmap);
     return -1;
 }
 
@@ -134,10 +136,21 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num,
+                                          uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVParallelsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = parallels_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
-    qemu_free(s->catalog_bitmap);
+    g_free(s->catalog_bitmap);
 }
 
 static BlockDriver bdrv_parallels = {
@@ -145,7 +158,7 @@ static BlockDriver bdrv_parallels = {
     .instance_size     = sizeof(BDRVParallelsState),
     .bdrv_probe                = parallels_probe,
     .bdrv_open         = parallels_open,
-    .bdrv_read         = parallels_read,
+    .bdrv_read          = parallels_co_read,
     .bdrv_close                = parallels_close,
 };
 
index f67d3d39f261806e85d8b162ee5ad9ec617a10df..4814ed0ced7d7d347719a0969931ef51a07a6a50 100644 (file)
@@ -26,6 +26,7 @@
 #include "module.h"
 #include <zlib.h>
 #include "aes.h"
+#include "migration.h"
 
 /**************************************************************/
 /* QEMU COW block driver with compression and encryption support */
@@ -73,6 +74,8 @@ typedef struct BDRVQcowState {
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
     AES_KEY aes_decrypt_key;
+    CoMutex lock;
+    Error *migration_blocker;
 } BDRVQcowState;
 
 static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
@@ -128,7 +131,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
     s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
 
     s->l1_table_offset = header.l1_table_offset;
-    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
     if (!s->l1_table)
         goto fail;
     if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
@@ -138,13 +141,13 @@ static int qcow_open(BlockDriverState *bs, int flags)
         be64_to_cpus(&s->l1_table[i]);
     }
     /* alloc L2 cache */
-    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
     if (!s->l2_cache)
         goto fail;
-    s->cluster_cache = qemu_malloc(s->cluster_size);
+    s->cluster_cache = g_malloc(s->cluster_size);
     if (!s->cluster_cache)
         goto fail;
-    s->cluster_data = qemu_malloc(s->cluster_size);
+    s->cluster_data = g_malloc(s->cluster_size);
     if (!s->cluster_data)
         goto fail;
     s->cluster_cache_offset = -1;
@@ -158,13 +161,21 @@ static int qcow_open(BlockDriverState *bs, int flags)
             goto fail;
         bs->backing_file[len] = '\0';
     }
+
+    /* Disable migration when qcow images are used */
+    error_set(&s->migration_blocker,
+              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+              "qcow", bs->device_name, "live migration");
+    migrate_add_blocker(s->migration_blocker);
+
+    qemu_co_mutex_init(&s->lock);
     return 0;
 
  fail:
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
+    g_free(s->l1_table);
+    g_free(s->l2_cache);
+    g_free(s->cluster_cache);
+    g_free(s->cluster_data);
     return -1;
 }
 
@@ -189,24 +200,6 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
         return -1;
     if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
         return -1;
-#if 0
-    /* test */
-    {
-        uint8_t in[16];
-        uint8_t out[16];
-        uint8_t tmp[16];
-        for(i=0;i<16;i++)
-            in[i] = i;
-        AES_encrypt(in, tmp, &s->aes_encrypt_key);
-        AES_decrypt(tmp, out, &s->aes_decrypt_key);
-        for(i = 0; i < 16; i++)
-            printf(" %02x", tmp[i]);
-        printf("\n");
-        for(i = 0; i < 16; i++)
-            printf(" %02x", out[i]);
-        printf("\n");
-    }
-#endif
     return 0;
 }
 
@@ -440,302 +433,193 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
     return 0;
 }
 
-#if 0
-
-static int qcow_read(BlockDriverState *bs, int64_t sector_num,
-                     uint8_t *buf, int nb_sectors)
+static int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
+                         int nb_sectors, QEMUIOVector *qiov)
 {
     BDRVQcowState *s = bs->opaque;
-    int ret, index_in_cluster, n;
+    int index_in_cluster;
+    int ret = 0, n;
     uint64_t cluster_offset;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
+    uint8_t *buf;
+    void *orig_buf;
+
+    if (qiov->niov > 1) {
+        buf = orig_buf = qemu_blockalign(bs, qiov->size);
+    } else {
+        orig_buf = NULL;
+        buf = (uint8_t *)qiov->iov->iov_base;
+    }
+
+    qemu_co_mutex_lock(&s->lock);
 
-    while (nb_sectors > 0) {
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+    while (nb_sectors != 0) {
+        /* prepare next request */
+        cluster_offset = get_cluster_offset(bs, sector_num << 9,
+                                                 0, 0, 0, 0);
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
         n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
+        if (n > nb_sectors) {
             n = nb_sectors;
+        }
+
         if (!cluster_offset) {
             if (bs->backing_hd) {
                 /* read from the base image */
-                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
-                if (ret < 0)
-                    return -1;
+                hd_iov.iov_base = (void *)buf;
+                hd_iov.iov_len = n * 512;
+                qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+                qemu_co_mutex_unlock(&s->lock);
+                ret = bdrv_co_readv(bs->backing_hd, sector_num,
+                                    n, &hd_qiov);
+                qemu_co_mutex_lock(&s->lock);
+                if (ret < 0) {
+                    goto fail;
+                }
             } else {
+                /* Note: in this case, no need to wait */
                 memset(buf, 0, 512 * n);
             }
         } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
-            if (decompress_cluster(bs, cluster_offset) < 0)
-                return -1;
-            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
+            /* add AIO support for compressed blocks ? */
+            if (decompress_cluster(bs, cluster_offset) < 0) {
+                goto fail;
+            }
+            memcpy(buf,
+                   s->cluster_cache + index_in_cluster * 512, 512 * n);
         } else {
-            ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512);
-            if (ret != n * 512)
-                return -1;
+            if ((cluster_offset & 511) != 0) {
+                goto fail;
+            }
+            hd_iov.iov_base = (void *)buf;
+            hd_iov.iov_len = n * 512;
+            qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+            qemu_co_mutex_unlock(&s->lock);
+            ret = bdrv_co_readv(bs->file,
+                                (cluster_offset >> 9) + index_in_cluster,
+                                n, &hd_qiov);
+            qemu_co_mutex_lock(&s->lock);
+            if (ret < 0) {
+                break;
+            }
             if (s->crypt_method) {
-                encrypt_sectors(s, sector_num, buf, buf, n, 0,
+                encrypt_sectors(s, sector_num, buf, buf,
+                                n, 0,
                                 &s->aes_decrypt_key);
             }
         }
+        ret = 0;
+
         nb_sectors -= n;
         sector_num += n;
         buf += n * 512;
     }
-    return 0;
-}
-#endif
-
-typedef struct QCowAIOCB {
-    BlockDriverAIOCB common;
-    int64_t sector_num;
-    QEMUIOVector *qiov;
-    uint8_t *buf;
-    void *orig_buf;
-    int nb_sectors;
-    int n;
-    uint64_t cluster_offset;
-    uint8_t *cluster_data;
-    struct iovec hd_iov;
-    QEMUIOVector hd_qiov;
-    BlockDriverAIOCB *hd_aiocb;
-} QCowAIOCB;
-
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
-    if (acb->hd_aiocb)
-        bdrv_aio_cancel(acb->hd_aiocb);
-    qemu_aio_release(acb);
-}
 
-static AIOPool qcow_aio_pool = {
-    .aiocb_size         = sizeof(QCowAIOCB),
-    .cancel             = qcow_aio_cancel,
-};
+done:
+    qemu_co_mutex_unlock(&s->lock);
 
-static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
-{
-    QCowAIOCB *acb;
-
-    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->hd_aiocb = NULL;
-    acb->sector_num = sector_num;
-    acb->qiov = qiov;
     if (qiov->niov > 1) {
-        acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
-        if (is_write)
-            qemu_iovec_to_buffer(qiov, acb->buf);
-    } else {
-        acb->buf = (uint8_t *)qiov->iov->iov_base;
+        qemu_iovec_from_buffer(qiov, orig_buf, qiov->size);
+        qemu_vfree(orig_buf);
     }
-    acb->nb_sectors = nb_sectors;
-    acb->n = 0;
-    acb->cluster_offset = 0;
-    return acb;
+
+    return ret;
+
+fail:
+    ret = -EIO;
+    goto done;
 }
 
-static void qcow_aio_read_cb(void *opaque, int ret)
+static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
+                          int nb_sectors, QEMUIOVector *qiov)
 {
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster;
+    uint64_t cluster_offset;
+    const uint8_t *src_buf;
+    int ret = 0, n;
+    uint8_t *cluster_data = NULL;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
+    uint8_t *buf;
+    void *orig_buf;
 
-    acb->hd_aiocb = NULL;
-    if (ret < 0)
-        goto done;
-
- redo:
-    /* post process the read buffer */
-    if (!acb->cluster_offset) {
-        /* nothing to do */
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* nothing to do */
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    if (qiov->niov > 1) {
+        buf = orig_buf = qemu_blockalign(bs, qiov->size);
+        qemu_iovec_to_buffer(qiov, buf);
     } else {
-        if (s->crypt_method) {
-            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
-                            acb->n, 0,
-                            &s->aes_decrypt_key);
-        }
+        orig_buf = NULL;
+        buf = (uint8_t *)qiov->iov->iov_base;
     }
 
-    acb->nb_sectors -= acb->n;
-    acb->sector_num += acb->n;
-    acb->buf += acb->n * 512;
+    qemu_co_mutex_lock(&s->lock);
 
-    if (acb->nb_sectors == 0) {
-        /* request completed */
-        ret = 0;
-        goto done;
-    }
+    while (nb_sectors != 0) {
 
-    /* prepare next AIO request */
-    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
-                                             0, 0, 0, 0);
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-    acb->n = s->cluster_sectors - index_in_cluster;
-    if (acb->n > acb->nb_sectors)
-        acb->n = acb->nb_sectors;
-
-    if (!acb->cluster_offset) {
-        if (bs->backing_hd) {
-            /* read from the base image */
-            acb->hd_iov.iov_base = (void *)acb->buf;
-            acb->hd_iov.iov_len = acb->n * 512;
-            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
-                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
-            if (acb->hd_aiocb == NULL)
-                goto done;
-        } else {
-            /* Note: in this case, no need to wait */
-            memset(acb->buf, 0, 512 * acb->n);
-            goto redo;
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        n = s->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
+            n = nb_sectors;
         }
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* add AIO support for compressed blocks ? */
-        if (decompress_cluster(bs, acb->cluster_offset) < 0)
-            goto done;
-        memcpy(acb->buf,
-               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
-        goto redo;
-    } else {
-        if ((acb->cluster_offset & 511) != 0) {
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
+                                            index_in_cluster,
+                                            index_in_cluster + n);
+        if (!cluster_offset || (cluster_offset & 511) != 0) {
             ret = -EIO;
-            goto done;
+            break;
+        }
+        if (s->crypt_method) {
+            if (!cluster_data) {
+                cluster_data = g_malloc0(s->cluster_size);
+            }
+            encrypt_sectors(s, sector_num, cluster_data, buf,
+                            n, 1, &s->aes_encrypt_key);
+            src_buf = cluster_data;
+        } else {
+            src_buf = buf;
         }
-        acb->hd_iov.iov_base = (void *)acb->buf;
-        acb->hd_iov.iov_len = acb->n * 512;
-        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-        acb->hd_aiocb = bdrv_aio_readv(bs->file,
-                            (acb->cluster_offset >> 9) + index_in_cluster,
-                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
-        if (acb->hd_aiocb == NULL)
-            goto done;
-    }
-
-    return;
-
-done:
-    if (acb->qiov->niov > 1) {
-        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
-        qemu_vfree(acb->orig_buf);
-    }
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_aio_release(acb);
-}
-
-static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    QCowAIOCB *acb;
-
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-    if (!acb)
-        return NULL;
-
-    qcow_aio_read_cb(acb, 0);
-    return &acb->common;
-}
-
-static void qcow_aio_write_cb(void *opaque, int ret)
-{
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
-    BDRVQcowState *s = bs->opaque;
-    int index_in_cluster;
-    uint64_t cluster_offset;
-    const uint8_t *src_buf;
-
-    acb->hd_aiocb = NULL;
-
-    if (ret < 0)
-        goto done;
-
-    acb->nb_sectors -= acb->n;
-    acb->sector_num += acb->n;
-    acb->buf += acb->n * 512;
 
-    if (acb->nb_sectors == 0) {
-        /* request completed */
+        hd_iov.iov_base = (void *)src_buf;
+        hd_iov.iov_len = n * 512;
+        qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+        qemu_co_mutex_unlock(&s->lock);
+        ret = bdrv_co_writev(bs->file,
+                             (cluster_offset >> 9) + index_in_cluster,
+                             n, &hd_qiov);
+        qemu_co_mutex_lock(&s->lock);
+        if (ret < 0) {
+            break;
+        }
         ret = 0;
-        goto done;
-    }
 
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-    acb->n = s->cluster_sectors - index_in_cluster;
-    if (acb->n > acb->nb_sectors)
-        acb->n = acb->nb_sectors;
-    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
-                                        index_in_cluster,
-                                        index_in_cluster + acb->n);
-    if (!cluster_offset || (cluster_offset & 511) != 0) {
-        ret = -EIO;
-        goto done;
-    }
-    if (s->crypt_method) {
-        if (!acb->cluster_data) {
-            acb->cluster_data = qemu_mallocz(s->cluster_size);
-            if (!acb->cluster_data) {
-                ret = -ENOMEM;
-                goto done;
-            }
-        }
-        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
-                        acb->n, 1, &s->aes_encrypt_key);
-        src_buf = acb->cluster_data;
-    } else {
-        src_buf = acb->buf;
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
     }
+    qemu_co_mutex_unlock(&s->lock);
 
-    acb->hd_iov.iov_base = (void *)src_buf;
-    acb->hd_iov.iov_len = acb->n * 512;
-    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-    acb->hd_aiocb = bdrv_aio_writev(bs->file,
-                                    (cluster_offset >> 9) + index_in_cluster,
-                                    &acb->hd_qiov, acb->n,
-                                    qcow_aio_write_cb, acb);
-    if (acb->hd_aiocb == NULL)
-        goto done;
-    return;
+    if (qiov->niov > 1) {
+        qemu_vfree(orig_buf);
+    }
+    g_free(cluster_data);
 
-done:
-    if (acb->qiov->niov > 1)
-        qemu_vfree(acb->orig_buf);
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_aio_release(acb);
+    return ret;
 }
 
-static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static void qcow_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
-    QCowAIOCB *acb;
 
-    s->cluster_cache_offset = -1; /* disable compressed cache */
+    g_free(s->l1_table);
+    g_free(s->l2_cache);
+    g_free(s->cluster_cache);
+    g_free(s->cluster_data);
 
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-    if (!acb)
-        return NULL;
-
-
-    qcow_aio_write_cb(acb, 0);
-    return &acb->common;
-}
-
-static void qcow_close(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
 }
 
 static int qcow_create(const char *filename, QEMUOptionParameter *options)
@@ -863,9 +747,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
     if (nb_sectors != s->cluster_sectors)
         return -EINVAL;
 
-    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
-    if (!out_buf)
-        return -1;
+    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
 
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
@@ -873,8 +755,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
                        Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
-        qemu_free(out_buf);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
 
     strm.avail_in = s->cluster_size;
@@ -884,9 +766,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     ret = deflate(&strm, Z_FINISH);
     if (ret != Z_STREAM_END && ret != Z_OK) {
-        qemu_free(out_buf);
         deflateEnd(&strm);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
     out_len = strm.next_out - out_buf;
 
@@ -894,30 +776,34 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        if (ret < 0) {
+            goto fail;
+        }
     } else {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
                                             out_len, 0, 0);
+        if (cluster_offset == 0) {
+            ret = -EIO;
+            goto fail;
+        }
+
         cluster_offset &= s->cluster_offset_mask;
-        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
-            qemu_free(out_buf);
-            return -1;
+        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        if (ret < 0) {
+            goto fail;
         }
     }
 
-    qemu_free(out_buf);
-    return 0;
-}
-
-static int qcow_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
+    ret = 0;
+fail:
+    g_free(out_buf);
+    return ret;
 }
 
-static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static coroutine_fn int qcow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@@ -954,15 +840,16 @@ static BlockDriver bdrv_qcow = {
     .bdrv_open         = qcow_open,
     .bdrv_close                = qcow_close,
     .bdrv_create       = qcow_create,
-    .bdrv_flush                = qcow_flush,
-    .bdrv_is_allocated = qcow_is_allocated,
-    .bdrv_set_key      = qcow_set_key,
-    .bdrv_make_empty   = qcow_make_empty,
-    .bdrv_aio_readv    = qcow_aio_readv,
-    .bdrv_aio_writev   = qcow_aio_writev,
-    .bdrv_aio_flush    = qcow_aio_flush,
-    .bdrv_write_compressed = qcow_write_compressed,
-    .bdrv_get_info     = qcow_get_info,
+
+    .bdrv_co_readv          = qcow_co_readv,
+    .bdrv_co_writev         = qcow_co_writev,
+    .bdrv_co_flush_to_disk  = qcow_co_flush,
+    .bdrv_is_allocated      = qcow_is_allocated,
+
+    .bdrv_set_key           = qcow_set_key,
+    .bdrv_make_empty        = qcow_make_empty,
+    .bdrv_write_compressed  = qcow_write_compressed,
+    .bdrv_get_info          = qcow_get_info,
 
     .create_options = qcow_create_options,
 };
index 382473933c8490111e6066aff3b89c938955061b..340a6f2b26ea63d1310218445e96ec590f23b6bd 100644 (file)
@@ -49,9 +49,9 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
     Qcow2Cache *c;
     int i;
 
-    c = qemu_mallocz(sizeof(*c));
+    c = g_malloc0(sizeof(*c));
     c->size = num_tables;
-    c->entries = qemu_mallocz(sizeof(*c->entries) * num_tables);
+    c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
     c->writethrough = writethrough;
 
     for (i = 0; i < c->size; i++) {
@@ -70,8 +70,8 @@ int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
         qemu_vfree(c->entries[i].table);
     }
 
-    qemu_free(c->entries);
-    qemu_free(c);
+    g_free(c->entries);
+    g_free(c);
 
     return 0;
 }
@@ -312,3 +312,15 @@ found:
     c->entries[i].dirty = true;
 }
 
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable)
+{
+    bool old = c->writethrough;
+
+    if (!old && enable) {
+        qcow2_cache_flush(bs, c);
+    }
+
+    c->writethrough = enable;
+    return old;
+}
index 750abe37d4bb7a1a0e7e63f79f71037a8c2b6a86..f4e049fa90fc852b1e3639ec899d294f2a1e0f7e 100644 (file)
@@ -53,24 +53,24 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
     }
 
 #ifdef DEBUG_ALLOC2
-    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
+    fprintf(stderr, "grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
 #endif
 
     new_l1_size2 = sizeof(uint64_t) * new_l1_size;
-    new_l1_table = qemu_mallocz(align_offset(new_l1_size2, 512));
+    new_l1_table = g_malloc0(align_offset(new_l1_size2, 512));
     memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
 
     /* write new table (align to cluster) */
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
     new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
     if (new_l1_table_offset < 0) {
-        qemu_free(new_l1_table);
+        g_free(new_l1_table);
         return new_l1_table_offset;
     }
 
     ret = qcow2_cache_flush(bs, s->refcount_block_cache);
     if (ret < 0) {
-        return ret;
+        goto fail;
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
@@ -90,14 +90,14 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
     if (ret < 0) {
         goto fail;
     }
-    qemu_free(s->l1_table);
+    g_free(s->l1_table);
     qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
     s->l1_table_offset = new_l1_table_offset;
     s->l1_table = new_l1_table;
     s->l1_size = new_l1_size;
     return 0;
  fail:
-    qemu_free(new_l1_table);
+    g_free(new_l1_table);
     qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
     return ret;
 }
@@ -381,10 +381,10 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
  * For a given offset of the disk image, find the cluster offset in
  * qcow2 file. The offset is stored in *cluster_offset.
  *
- * on entry, *num is the number of contiguous clusters we'd like to
+ * on entry, *num is the number of contiguous sectors we'd like to
  * access following offset.
  *
- * on exit, *num is the number of contiguous clusters we can read.
+ * on exit, *num is the number of contiguous sectors we can read.
  *
  * Return 0, if the offset is found
  * Return -errno, otherwise.
@@ -568,8 +568,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
     }
 
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (cluster_offset & QCOW_OFLAG_COPIED)
-        return cluster_offset & ~QCOW_OFLAG_COPIED;
+    if (cluster_offset & QCOW_OFLAG_COPIED) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        return 0;
+    }
 
     if (cluster_offset)
         qcow2_free_any_clusters(bs, cluster_offset, 1);
@@ -612,7 +614,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
     if (m->nb_clusters == 0)
         return 0;
 
-    old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t));
+    old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t));
 
     /* copy content of unmodified sectors */
     start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
@@ -683,7 +685,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
 
     ret = 0;
 err:
-    qemu_free(old_cluster);
+    g_free(old_cluster);
     return ret;
  }
 
@@ -694,15 +696,15 @@ err:
  * If the offset is not found, allocate a new cluster.
  *
  * If the cluster was already allocated, m->nb_clusters is set to 0,
- * m->depends_on is set to NULL and the other fields in m are meaningless.
+ * other fields in m are meaningless.
  *
  * If the cluster is newly allocated, m->nb_clusters is set to the number of
- * contiguous clusters that have been allocated. This may be 0 if the request
- * conflict with another write request in flight; in this case, m->depends_on
- * is set and the remaining fields of m are meaningless.
+ * contiguous clusters that have been allocated. In this case, the other
+ * fields of m are valid and contain information about the first allocated
+ * cluster.
  *
- * If m->nb_clusters is non-zero, the other fields of m are valid and contain
- * information about the first allocated cluster.
+ * If the request conflicts with another write request in flight, the coroutine
+ * is queued and will be reentered when the dependency has completed.
  *
  * Return 0 on success and -errno in error cases
  */
@@ -721,6 +723,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
         return ret;
     }
 
+again:
     nb_clusters = size_to_clusters(s, n_end << 9);
 
     nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
@@ -735,7 +738,6 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 
         cluster_offset &= ~QCOW_OFLAG_COPIED;
         m->nb_clusters = 0;
-        m->depends_on = NULL;
 
         goto out;
     }
@@ -776,28 +778,28 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
      */
     QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
 
-        uint64_t end_offset = offset + nb_clusters * s->cluster_size;
-        uint64_t old_offset = old_alloc->offset;
-        uint64_t old_end_offset = old_alloc->offset +
-            old_alloc->nb_clusters * s->cluster_size;
+        uint64_t start = offset >> s->cluster_bits;
+        uint64_t end = start + nb_clusters;
+        uint64_t old_start = old_alloc->offset >> s->cluster_bits;
+        uint64_t old_end = old_start + old_alloc->nb_clusters;
 
-        if (end_offset < old_offset || offset > old_end_offset) {
+        if (end < old_start || start > old_end) {
             /* No intersection */
         } else {
-            if (offset < old_offset) {
+            if (start < old_start) {
                 /* Stop at the start of a running allocation */
-                nb_clusters = (old_offset - offset) >> s->cluster_bits;
+                nb_clusters = old_start - start;
             } else {
                 nb_clusters = 0;
             }
 
             if (nb_clusters == 0) {
-                /* Set dependency and wait for a callback */
-                m->depends_on = old_alloc;
-                m->nb_clusters = 0;
-                *num = 0;
-                ret = 0;
-                goto fail;
+                /* Wait for the dependency to complete. We need to recheck
+                 * the free/allocated clusters when we continue. */
+                qemu_co_mutex_unlock(&s->lock);
+                qemu_co_queue_wait(&old_alloc->dependent_requests);
+                qemu_co_mutex_lock(&s->lock);
+                goto again;
             }
         }
     }
@@ -806,26 +808,25 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
         abort();
     }
 
+    /* save info needed for meta data update */
+    m->offset = offset;
+    m->n_start = n_start;
+    m->nb_clusters = nb_clusters;
+
     QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
 
     /* allocate a new cluster */
 
     cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
     if (cluster_offset < 0) {
-        QLIST_REMOVE(m, next_in_flight);
         ret = cluster_offset;
         goto fail;
     }
 
-    /* save info needed for meta data update */
-    m->offset = offset;
-    m->n_start = n_start;
-    m->nb_clusters = nb_clusters;
-
 out:
     ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
     if (ret < 0) {
-        return ret;
+        goto fail_put;
     }
 
     m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
@@ -837,6 +838,8 @@ out:
 
 fail:
     qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+fail_put:
+    QLIST_REMOVE(m, next_in_flight);
     return ret;
 }
 
index 915d85acbfdf988cc79600a4d6319ab030648de8..9605367777bd6e856bb139e8e9a1c205d68de3b1 100644 (file)
@@ -41,7 +41,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
     int ret, refcount_table_size2, i;
 
     refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
-    s->refcount_table = qemu_malloc(refcount_table_size2);
+    s->refcount_table = g_malloc(refcount_table_size2);
     if (s->refcount_table_size > 0) {
         BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
         ret = bdrv_pread(bs->file, s->refcount_table_offset,
@@ -59,7 +59,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
 void qcow2_refcount_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
-    qemu_free(s->refcount_table);
+    g_free(s->refcount_table);
 }
 
 
@@ -323,8 +323,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
     uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
         s->cluster_size;
     uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
-    uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size);
-    uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t));
+    uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
+    uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
 
     assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
 
@@ -349,7 +349,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
     ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
         blocks_clusters * s->cluster_size);
-    qemu_free(new_blocks);
+    g_free(new_blocks);
     if (ret < 0) {
         goto fail_table;
     }
@@ -385,7 +385,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
     uint64_t old_table_offset = s->refcount_table_offset;
     uint64_t old_table_size = s->refcount_table_size;
 
-    qemu_free(s->refcount_table);
+    g_free(s->refcount_table);
     s->refcount_table = new_table;
     s->refcount_table_size = table_size;
     s->refcount_table_offset = table_offset;
@@ -403,7 +403,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
     return new_block;
 
 fail_table:
-    qemu_free(new_table);
+    g_free(new_table);
 fail_block:
     if (*refcount_block != NULL) {
         qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
@@ -422,7 +422,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
     int ret;
 
 #ifdef DEBUG_ALLOC2
-    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
+    fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
            offset, length, addend);
 #endif
     if (length < 0) {
@@ -556,7 +556,7 @@ retry:
         }
     }
 #ifdef DEBUG_ALLOC2
-    printf("alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
+    fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
             size,
             (s->free_cluster_index - nb_clusters) << s->cluster_bits);
 #endif
@@ -680,24 +680,6 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
 
 
 
-void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
-    int64_t size)
-{
-    int refcount;
-    int64_t start, last, cluster_offset;
-    uint16_t *p;
-
-    start = offset & ~(s->cluster_size - 1);
-    last = (offset + size - 1)  & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last;
-        cluster_offset += s->cluster_size) {
-        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
-        refcount = be16_to_cpu(*p);
-        refcount++;
-        *p = cpu_to_be16(refcount);
-    }
-}
-
 /* update the refcounts of snapshots and the copied flag */
 int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     int64_t l1_table_offset, int l1_size, int addend)
@@ -705,22 +687,33 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
     int64_t old_offset, old_l2_offset;
-    int i, j, l1_modified, nb_csectors, refcount;
+    int i, j, l1_modified = 0, nb_csectors, refcount;
     int ret;
+    bool old_l2_writethrough, old_refcount_writethrough;
+
+    /* Switch caches to writeback mode during update */
+    old_l2_writethrough =
+        qcow2_cache_set_writethrough(bs, s->l2_table_cache, false);
+    old_refcount_writethrough =
+        qcow2_cache_set_writethrough(bs, s->refcount_block_cache, false);
 
     l2_table = NULL;
     l1_table = NULL;
     l1_size2 = l1_size * sizeof(uint64_t);
     if (l1_table_offset != s->l1_table_offset) {
         if (l1_size2 != 0) {
-            l1_table = qemu_mallocz(align_offset(l1_size2, 512));
+            l1_table = g_malloc0(align_offset(l1_size2, 512));
         } else {
             l1_table = NULL;
         }
         l1_allocated = 1;
         if (bdrv_pread(bs->file, l1_table_offset,
                        l1_table, l1_size2) != l1_size2)
+        {
+            ret = -EIO;
             goto fail;
+        }
+
         for(i = 0;i < l1_size; i++)
             be64_to_cpus(&l1_table[i]);
     } else {
@@ -729,7 +722,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
         l1_allocated = 0;
     }
 
-    l1_modified = 0;
     for(i = 0; i < l1_size; i++) {
         l2_offset = l1_table[i];
         if (l2_offset) {
@@ -773,6 +765,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                         }
 
                         if (refcount < 0) {
+                            ret = -EIO;
                             goto fail;
                         }
                     }
@@ -803,6 +796,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
             }
             if (refcount < 0) {
+                ret = -EIO;
                 goto fail;
             } else if (refcount == 1) {
                 l2_offset |= QCOW_OFLAG_COPIED;
@@ -813,6 +807,18 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
             }
         }
     }
+
+    ret = 0;
+fail:
+    if (l2_table) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    }
+
+    /* Enable writethrough cache mode again */
+    qcow2_cache_set_writethrough(bs, s->l2_table_cache, old_l2_writethrough);
+    qcow2_cache_set_writethrough(bs, s->refcount_block_cache,
+        old_refcount_writethrough);
+
     if (l1_modified) {
         for(i = 0; i < l1_size; i++)
             cpu_to_be64s(&l1_table[i]);
@@ -823,16 +829,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
             be64_to_cpus(&l1_table[i]);
     }
     if (l1_allocated)
-        qemu_free(l1_table);
-    return 0;
- fail:
-    if (l2_table) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
-    }
-
-    if (l1_allocated)
-        qemu_free(l1_table);
-    return -EIO;
+        g_free(l1_table);
+    return ret;
 }
 
 
@@ -905,7 +903,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
 
     /* Read L2 table from disk */
     l2_size = s->l2_size * sizeof(uint64_t);
-    l2_table = qemu_malloc(l2_size);
+    l2_table = g_malloc(l2_size);
 
     if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size)
         goto fail;
@@ -963,12 +961,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
         }
     }
 
-    qemu_free(l2_table);
+    g_free(l2_table);
     return 0;
 
 fail:
     fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
-    qemu_free(l2_table);
+    g_free(l2_table);
     return -EIO;
 }
 
@@ -1001,7 +999,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
     if (l1_size2 == 0) {
         l1_table = NULL;
     } else {
-        l1_table = qemu_malloc(l1_size2);
+        l1_table = g_malloc(l1_size2);
         if (bdrv_pread(bs->file, l1_table_offset,
                        l1_table, l1_size2) != l1_size2)
             goto fail;
@@ -1049,13 +1047,13 @@ static int check_refcounts_l1(BlockDriverState *bs,
             }
         }
     }
-    qemu_free(l1_table);
+    g_free(l1_table);
     return 0;
 
 fail:
     fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
     res->check_errors++;
-    qemu_free(l1_table);
+    g_free(l1_table);
     return -EIO;
 }
 
@@ -1063,7 +1061,7 @@ fail:
  * Checks an image for refcount consistency.
  *
  * Returns 0 if no errors are found, the number of errors in case the image is
- * detected as corrupted, and -errno when an internal error occured.
+ * detected as corrupted, and -errno when an internal error occurred.
  */
 int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
 {
@@ -1076,7 +1074,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
 
     size = bdrv_getlength(bs->file);
     nb_clusters = size_to_clusters(s, size);
-    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
+    refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
 
     /* header */
     inc_refcounts(bs, res, refcount_table, nb_clusters,
@@ -1086,7 +1084,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
     ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
                        s->l1_table_offset, s->l1_size, 1);
     if (ret < 0) {
-        return ret;
+        goto fail;
     }
 
     /* snapshots */
@@ -1095,7 +1093,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
         ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
             sn->l1_table_offset, sn->l1_size, 0);
         if (ret < 0) {
-            return ret;
+            goto fail;
         }
     }
     inc_refcounts(bs, res, refcount_table, nb_clusters,
@@ -1159,8 +1157,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
         }
     }
 
-    qemu_free(refcount_table);
+    ret = 0;
 
-    return 0;
+fail:
+    g_free(refcount_table);
+
+    return ret;
 }
 
index 74823a5ebfc2d47efe5d4429f8a447a46ca9cdf3..bdc33ba94c3f31535f698b85cf33b81aa8c32f8e 100644 (file)
@@ -26,7 +26,7 @@
 #include "block_int.h"
 #include "block/qcow2.h"
 
-typedef struct __attribute__((packed)) QCowSnapshotHeader {
+typedef struct QEMU_PACKED QCowSnapshotHeader {
     /* header is 8 byte aligned */
     uint64_t l1_table_offset;
 
@@ -52,10 +52,10 @@ void qcow2_free_snapshots(BlockDriverState *bs)
     int i;
 
     for(i = 0; i < s->nb_snapshots; i++) {
-        qemu_free(s->snapshots[i].name);
-        qemu_free(s->snapshots[i].id_str);
+        g_free(s->snapshots[i].name);
+        g_free(s->snapshots[i].id_str);
     }
-    qemu_free(s->snapshots);
+    g_free(s->snapshots);
     s->snapshots = NULL;
     s->nb_snapshots = 0;
 }
@@ -76,7 +76,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
     }
 
     offset = s->snapshots_offset;
-    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
+    s->snapshots = g_malloc0(s->nb_snapshots * sizeof(QCowSnapshot));
     for(i = 0; i < s->nb_snapshots; i++) {
         offset = align_offset(offset, 8);
         if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h))
@@ -96,13 +96,13 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 
         offset += extra_data_size;
 
-        sn->id_str = qemu_malloc(id_str_size + 1);
+        sn->id_str = g_malloc(id_str_size + 1);
         if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
             goto fail;
         offset += id_str_size;
         sn->id_str[id_str_size] = '\0';
 
-        sn->name = qemu_malloc(name_size + 1);
+        sn->name = g_malloc(name_size + 1);
         if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size)
             goto fail;
         offset += name_size;
@@ -252,10 +252,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
         return -ENOENT;
 
-    sn->id_str = qemu_strdup(sn_info->id_str);
+    sn->id_str = g_strdup(sn_info->id_str);
     if (!sn->id_str)
         goto fail;
-    sn->name = qemu_strdup(sn_info->name);
+    sn->name = g_strdup(sn_info->name);
     if (!sn->name)
         goto fail;
     sn->vm_state_size = sn_info->vm_state_size;
@@ -278,7 +278,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     sn->l1_size = s->l1_size;
 
     if (s->l1_size != 0) {
-        l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+        l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
     } else {
         l1_table = NULL;
     }
@@ -289,13 +289,13 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
                     l1_table, s->l1_size * sizeof(uint64_t)) < 0)
         goto fail;
-    qemu_free(l1_table);
+    g_free(l1_table);
     l1_table = NULL;
 
-    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
+    snapshots1 = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
     if (s->snapshots) {
         memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
-        qemu_free(s->snapshots);
+        g_free(s->snapshots);
     }
     s->snapshots = snapshots1;
     s->snapshots[s->nb_snapshots++] = *sn;
@@ -303,12 +303,15 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     if (qcow2_write_snapshots(bs) < 0)
         goto fail;
 #ifdef DEBUG_ALLOC
-    qcow2_check_refcounts(bs);
+    {
+      BdrvCheckResult result = {0};
+      qcow2_check_refcounts(bs, &result);
+    }
 #endif
     return 0;
  fail:
-    qemu_free(sn->name);
-    qemu_free(l1_table);
+    g_free(sn->name);
+    g_free(l1_table);
     return -1;
 }
 
@@ -317,7 +320,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *sn;
-    int i, snapshot_index, l1_size2;
+    int i, snapshot_index;
+    int cur_l1_bytes, sn_l1_bytes;
 
     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
     if (snapshot_index < 0)
@@ -330,14 +334,19 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
         goto fail;
 
-    s->l1_size = sn->l1_size;
-    l1_size2 = s->l1_size * sizeof(uint64_t);
+    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
+    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
+
+    if (cur_l1_bytes > sn_l1_bytes) {
+        memset(s->l1_table + sn->l1_size, 0, cur_l1_bytes - sn_l1_bytes);
+    }
+
     /* copy the snapshot l1 table to the current l1 table */
     if (bdrv_pread(bs->file, sn->l1_table_offset,
-                   s->l1_table, l1_size2) != l1_size2)
+                   s->l1_table, sn_l1_bytes) < 0)
         goto fail;
     if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
-                    s->l1_table, l1_size2) < 0)
+                    s->l1_table, cur_l1_bytes) < 0)
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
         be64_to_cpus(&s->l1_table[i]);
@@ -347,7 +356,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
         goto fail;
 
 #ifdef DEBUG_ALLOC
-    qcow2_check_refcounts(bs);
+    {
+        BdrvCheckResult result = {0};
+        qcow2_check_refcounts(bs, &result);
+    }
 #endif
     return 0;
  fail:
@@ -374,8 +386,8 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
         return ret;
     qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
 
-    qemu_free(sn->id_str);
-    qemu_free(sn->name);
+    g_free(sn->id_str);
+    g_free(sn->name);
     memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
     s->nb_snapshots--;
     ret = qcow2_write_snapshots(bs);
@@ -384,7 +396,10 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
         return ret;
     }
 #ifdef DEBUG_ALLOC
-    qcow2_check_refcounts(bs);
+    {
+        BdrvCheckResult result = {0};
+        qcow2_check_refcounts(bs, &result);
+    }
 #endif
     return 0;
 }
@@ -401,7 +416,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
         return s->nb_snapshots;
     }
 
-    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
+    sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
     for(i = 0; i < s->nb_snapshots; i++) {
         sn_info = sn_tab + i;
         sn = s->snapshots + i;
@@ -433,11 +448,11 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
     s->l1_size = sn->l1_size;
     l1_size2 = s->l1_size * sizeof(uint64_t);
     if (s->l1_table != NULL) {
-        qemu_free(s->l1_table);
+        g_free(s->l1_table);
     }
 
     s->l1_table_offset = sn->l1_table_offset;
-    s->l1_table = qemu_mallocz(align_offset(l1_size2, 512));
+    s->l1_table = g_malloc0(align_offset(l1_size2, 512));
 
     if (bdrv_pread(bs->file, sn->l1_table_offset,
                    s->l1_table, l1_size2) != l1_size2) {
index 75b8becc0ab2f68db5dbbae9e0d325f12a36797f..d7805ce9433116f54438da40020c857787894f04 100644 (file)
@@ -87,6 +87,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
     while (offset < end_offset) {
 
 #ifdef DEBUG_EXT
+        BDRVQcowState *s = bs->opaque;
         /* Sanity check */
         if (offset > s->cluster_size)
             printf("qcow2_read_extension: suspicious offset %lu\n", offset);
@@ -216,7 +217,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     }
     s->l1_table_offset = header.l1_table_offset;
     if (s->l1_size > 0) {
-        s->l1_table = qemu_mallocz(
+        s->l1_table = g_malloc0(
             align_offset(s->l1_size * sizeof(uint64_t), 512));
         ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
                          s->l1_size * sizeof(uint64_t));
@@ -229,16 +230,17 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     }
 
     /* alloc L2 table/refcount block cache */
-    writethrough = ((flags & BDRV_O_CACHE_MASK) == 0);
+    writethrough = ((flags & BDRV_O_CACHE_WB) == 0);
     s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE, writethrough);
     s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE,
         writethrough);
 
-    s->cluster_cache = qemu_malloc(s->cluster_size);
+    s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
-    s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+    s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
                                   + 512);
     s->cluster_cache_offset = -1;
+    s->flags = flags;
 
     ret = qcow2_refcount_init(bs);
     if (ret != 0) {
@@ -276,20 +278,26 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         goto fail;
     }
 
+    /* Initialise locks */
+    qemu_co_mutex_init(&s->lock);
+
 #ifdef DEBUG_ALLOC
-    qcow2_check_refcounts(bs);
+    {
+        BdrvCheckResult result = {0};
+        qcow2_check_refcounts(bs, &result);
+    }
 #endif
     return ret;
 
  fail:
     qcow2_free_snapshots(bs);
     qcow2_refcount_close(bs);
-    qemu_free(s->l1_table);
+    g_free(s->l1_table);
     if (s->l2_table_cache) {
         qcow2_cache_destroy(bs, s->l2_table_cache);
     }
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
+    g_free(s->cluster_cache);
+    qemu_vfree(s->cluster_data);
     return ret;
 }
 
@@ -369,376 +377,250 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
     return n1;
 }
 
-typedef struct QCowAIOCB {
-    BlockDriverAIOCB common;
-    int64_t sector_num;
-    QEMUIOVector *qiov;
-    int remaining_sectors;
-    int cur_nr_sectors;        /* number of sectors in current iteration */
-    uint64_t bytes_done;
-    uint64_t cluster_offset;
-    uint8_t *cluster_data;
-    BlockDriverAIOCB *hd_aiocb;
-    QEMUIOVector hd_qiov;
-    QEMUBH *bh;
-    QCowL2Meta l2meta;
-    QLIST_ENTRY(QCowAIOCB) next_depend;
-} QCowAIOCB;
-
-static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
-    if (acb->hd_aiocb)
-        bdrv_aio_cancel(acb->hd_aiocb);
-    qemu_aio_release(acb);
-}
-
-static AIOPool qcow2_aio_pool = {
-    .aiocb_size         = sizeof(QCowAIOCB),
-    .cancel             = qcow2_aio_cancel,
-};
-
-static void qcow2_aio_read_cb(void *opaque, int ret);
-static void qcow2_aio_read_bh(void *opaque)
-{
-    QCowAIOCB *acb = opaque;
-    qemu_bh_delete(acb->bh);
-    acb->bh = NULL;
-    qcow2_aio_read_cb(opaque, 0);
-}
-
-static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
-{
-    if (acb->bh)
-        return -EIO;
-
-    acb->bh = qemu_bh_new(cb, acb);
-    if (!acb->bh)
-        return -EIO;
-
-    qemu_bh_schedule(acb->bh);
-
-    return 0;
-}
-
-static void qcow2_aio_read_cb(void *opaque, int ret)
+static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
+                          int remaining_sectors, QEMUIOVector *qiov)
 {
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster, n1;
+    int ret;
+    int cur_nr_sectors; /* number of sectors in current iteration */
+    uint64_t cluster_offset = 0;
+    uint64_t bytes_done = 0;
+    QEMUIOVector hd_qiov;
+    uint8_t *cluster_data = NULL;
 
-    acb->hd_aiocb = NULL;
-    if (ret < 0)
-        goto done;
+    qemu_iovec_init(&hd_qiov, qiov->niov);
 
-    /* post process the read buffer */
-    if (!acb->cluster_offset) {
-        /* nothing to do */
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* nothing to do */
-    } else {
-        if (s->crypt_method) {
-            qcow2_encrypt_sectors(s, acb->sector_num,  acb->cluster_data,
-                acb->cluster_data, acb->cur_nr_sectors, 0, &s->aes_decrypt_key);
-            qemu_iovec_reset(&acb->hd_qiov);
-            qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
-                acb->cur_nr_sectors * 512);
-            qemu_iovec_from_buffer(&acb->hd_qiov, acb->cluster_data,
-                512 * acb->cur_nr_sectors);
-        }
-    }
+    qemu_co_mutex_lock(&s->lock);
 
-    acb->remaining_sectors -= acb->cur_nr_sectors;
-    acb->sector_num += acb->cur_nr_sectors;
-    acb->bytes_done += acb->cur_nr_sectors * 512;
+    while (remaining_sectors != 0) {
 
-    if (acb->remaining_sectors == 0) {
-        /* request completed */
-        ret = 0;
-        goto done;
-    }
-
-    /* prepare next AIO request */
-    acb->cur_nr_sectors = acb->remaining_sectors;
-    if (s->crypt_method) {
-        acb->cur_nr_sectors = MIN(acb->cur_nr_sectors,
-            QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
-    }
+        /* prepare next request */
+        cur_nr_sectors = remaining_sectors;
+        if (s->crypt_method) {
+            cur_nr_sectors = MIN(cur_nr_sectors,
+                QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
+        }
 
-    ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
-        &acb->cur_nr_sectors, &acb->cluster_offset);
-    if (ret < 0) {
-        goto done;
-    }
+        ret = qcow2_get_cluster_offset(bs, sector_num << 9,
+            &cur_nr_sectors, &cluster_offset);
+        if (ret < 0) {
+            goto fail;
+        }
 
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-
-    qemu_iovec_reset(&acb->hd_qiov);
-    qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
-        acb->cur_nr_sectors * 512);
-
-    if (!acb->cluster_offset) {
-
-        if (bs->backing_hd) {
-            /* read from the base image */
-            n1 = qcow2_backing_read1(bs->backing_hd, &acb->hd_qiov,
-                acb->sector_num, acb->cur_nr_sectors);
-            if (n1 > 0) {
-                BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
-                acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
-                                    &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
-                if (acb->hd_aiocb == NULL) {
-                    ret = -EIO;
-                    goto done;
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+
+        qemu_iovec_reset(&hd_qiov);
+        qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
+            cur_nr_sectors * 512);
+
+        if (!cluster_offset) {
+
+            if (bs->backing_hd) {
+                /* read from the base image */
+                n1 = qcow2_backing_read1(bs->backing_hd, &hd_qiov,
+                    sector_num, cur_nr_sectors);
+                if (n1 > 0) {
+                    BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+                    qemu_co_mutex_unlock(&s->lock);
+                    ret = bdrv_co_readv(bs->backing_hd, sector_num,
+                                        n1, &hd_qiov);
+                    qemu_co_mutex_lock(&s->lock);
+                    if (ret < 0) {
+                        goto fail;
+                    }
                 }
             } else {
-                ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
-                if (ret < 0)
-                    goto done;
+                /* Note: in this case, no need to wait */
+                qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
+            }
+        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            /* add AIO support for compressed blocks ? */
+            ret = qcow2_decompress_cluster(bs, cluster_offset);
+            if (ret < 0) {
+                goto fail;
             }
-        } else {
-            /* Note: in this case, no need to wait */
-            qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
-            ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
-            if (ret < 0)
-                goto done;
-        }
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* add AIO support for compressed blocks ? */
-        ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
-        if (ret < 0) {
-            goto done;
-        }
 
-        qemu_iovec_from_buffer(&acb->hd_qiov,
-            s->cluster_cache + index_in_cluster * 512,
-            512 * acb->cur_nr_sectors);
+            qemu_iovec_from_buffer(&hd_qiov,
+                s->cluster_cache + index_in_cluster * 512,
+                512 * cur_nr_sectors);
+        } else {
+            if ((cluster_offset & 511) != 0) {
+                ret = -EIO;
+                goto fail;
+            }
 
-        ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
-        if (ret < 0)
-            goto done;
-    } else {
-        if ((acb->cluster_offset & 511) != 0) {
-            ret = -EIO;
-            goto done;
-        }
+            if (s->crypt_method) {
+                /*
+                 * For encrypted images, read everything into a temporary
+                 * contiguous buffer on which the AES functions can work.
+                 */
+                if (!cluster_data) {
+                    cluster_data =
+                        qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+                }
 
-        if (s->crypt_method) {
-            /*
-             * For encrypted images, read everything into a temporary
-             * contiguous buffer on which the AES functions can work.
-             */
-            if (!acb->cluster_data) {
-                acb->cluster_data =
-                    qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+                assert(cur_nr_sectors <=
+                    QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
+                qemu_iovec_reset(&hd_qiov);
+                qemu_iovec_add(&hd_qiov, cluster_data,
+                    512 * cur_nr_sectors);
             }
 
-            assert(acb->cur_nr_sectors <=
-                QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
-            qemu_iovec_reset(&acb->hd_qiov);
-            qemu_iovec_add(&acb->hd_qiov, acb->cluster_data,
-                512 * acb->cur_nr_sectors);
+            BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+            qemu_co_mutex_unlock(&s->lock);
+            ret = bdrv_co_readv(bs->file,
+                                (cluster_offset >> 9) + index_in_cluster,
+                                cur_nr_sectors, &hd_qiov);
+            qemu_co_mutex_lock(&s->lock);
+            if (ret < 0) {
+                goto fail;
+            }
+            if (s->crypt_method) {
+                qcow2_encrypt_sectors(s, sector_num,  cluster_data,
+                    cluster_data, cur_nr_sectors, 0, &s->aes_decrypt_key);
+                qemu_iovec_reset(&hd_qiov);
+                qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
+                    cur_nr_sectors * 512);
+                qemu_iovec_from_buffer(&hd_qiov, cluster_data,
+                    512 * cur_nr_sectors);
+            }
         }
 
-        BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
-        acb->hd_aiocb = bdrv_aio_readv(bs->file,
-                            (acb->cluster_offset >> 9) + index_in_cluster,
-                            &acb->hd_qiov, acb->cur_nr_sectors,
-                            qcow2_aio_read_cb, acb);
-        if (acb->hd_aiocb == NULL) {
-            ret = -EIO;
-            goto done;
-        }
+        remaining_sectors -= cur_nr_sectors;
+        sector_num += cur_nr_sectors;
+        bytes_done += cur_nr_sectors * 512;
     }
+    ret = 0;
 
-    return;
-done:
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_iovec_destroy(&acb->hd_qiov);
-    qemu_aio_release(acb);
-}
-
-static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
-                                  QEMUIOVector *qiov, int nb_sectors,
-                                  BlockDriverCompletionFunc *cb,
-                                  void *opaque, int is_write)
-{
-    QCowAIOCB *acb;
-
-    acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->hd_aiocb = NULL;
-    acb->sector_num = sector_num;
-    acb->qiov = qiov;
-
-    qemu_iovec_init(&acb->hd_qiov, qiov->niov);
-
-    acb->bytes_done = 0;
-    acb->remaining_sectors = nb_sectors;
-    acb->cur_nr_sectors = 0;
-    acb->cluster_offset = 0;
-    acb->l2meta.nb_clusters = 0;
-    QLIST_INIT(&acb->l2meta.dependent_requests);
-    return acb;
-}
-
-static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
-                                         int64_t sector_num,
-                                         QEMUIOVector *qiov, int nb_sectors,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
-{
-    QCowAIOCB *acb;
+fail:
+    qemu_co_mutex_unlock(&s->lock);
 
-    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-    if (!acb)
-        return NULL;
+    qemu_iovec_destroy(&hd_qiov);
+    qemu_vfree(cluster_data);
 
-    qcow2_aio_read_cb(acb, 0);
-    return &acb->common;
+    return ret;
 }
 
-static void qcow2_aio_write_cb(void *opaque, int ret);
-
-static void run_dependent_requests(QCowL2Meta *m)
+static void run_dependent_requests(BDRVQcowState *s, QCowL2Meta *m)
 {
-    QCowAIOCB *req;
-    QCowAIOCB *next;
-
     /* Take the request off the list of running requests */
     if (m->nb_clusters != 0) {
         QLIST_REMOVE(m, next_in_flight);
     }
 
     /* Restart all dependent requests */
-    QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
-        qcow2_aio_write_cb(req, 0);
+    if (!qemu_co_queue_empty(&m->dependent_requests)) {
+        qemu_co_mutex_unlock(&s->lock);
+        while(qemu_co_queue_next(&m->dependent_requests));
+        qemu_co_mutex_lock(&s->lock);
     }
-
-    /* Empty the list for the next part of the request */
-    QLIST_INIT(&m->dependent_requests);
 }
 
-static void qcow2_aio_write_cb(void *opaque, int ret)
+static int qcow2_co_writev(BlockDriverState *bs,
+                           int64_t sector_num,
+                           int remaining_sectors,
+                           QEMUIOVector *qiov)
 {
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster;
     int n_end;
+    int ret;
+    int cur_nr_sectors; /* number of sectors in current iteration */
+    uint64_t cluster_offset;
+    QEMUIOVector hd_qiov;
+    uint64_t bytes_done = 0;
+    uint8_t *cluster_data = NULL;
+    QCowL2Meta l2meta = {
+        .nb_clusters = 0,
+    };
 
-    acb->hd_aiocb = NULL;
+    qemu_co_queue_init(&l2meta.dependent_requests);
 
-    if (ret >= 0) {
-        ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
-    }
+    qemu_iovec_init(&hd_qiov, qiov->niov);
 
-    run_dependent_requests(&acb->l2meta);
+    s->cluster_cache_offset = -1; /* disable compressed cache */
 
-    if (ret < 0)
-        goto done;
+    qemu_co_mutex_lock(&s->lock);
 
-    acb->remaining_sectors -= acb->cur_nr_sectors;
-    acb->sector_num += acb->cur_nr_sectors;
-    acb->bytes_done += acb->cur_nr_sectors * 512;
+    while (remaining_sectors != 0) {
 
-    if (acb->remaining_sectors == 0) {
-        /* request completed */
-        ret = 0;
-        goto done;
-    }
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        n_end = index_in_cluster + remaining_sectors;
+        if (s->crypt_method &&
+            n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) {
+            n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
+        }
 
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-    n_end = index_in_cluster + acb->remaining_sectors;
-    if (s->crypt_method &&
-        n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
-        n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
+        ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
+            index_in_cluster, n_end, &cur_nr_sectors, &l2meta);
+        if (ret < 0) {
+            goto fail;
+        }
 
-    ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
-        index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta);
-    if (ret < 0) {
-        goto done;
-    }
+        cluster_offset = l2meta.cluster_offset;
+        assert((cluster_offset & 511) == 0);
 
-    acb->cluster_offset = acb->l2meta.cluster_offset;
+        qemu_iovec_reset(&hd_qiov);
+        qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
+            cur_nr_sectors * 512);
 
-    /* Need to wait for another request? If so, we are done for now. */
-    if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
-        QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
-            acb, next_depend);
-        return;
-    }
+        if (s->crypt_method) {
+            if (!cluster_data) {
+                cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *
+                                                 s->cluster_size);
+            }
 
-    assert((acb->cluster_offset & 511) == 0);
+            assert(hd_qiov.size <=
+                   QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+            qemu_iovec_to_buffer(&hd_qiov, cluster_data);
 
-    qemu_iovec_reset(&acb->hd_qiov);
-    qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
-        acb->cur_nr_sectors * 512);
+            qcow2_encrypt_sectors(s, sector_num, cluster_data,
+                cluster_data, cur_nr_sectors, 1, &s->aes_encrypt_key);
 
-    if (s->crypt_method) {
-        if (!acb->cluster_data) {
-            acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
-                                             s->cluster_size);
+            qemu_iovec_reset(&hd_qiov);
+            qemu_iovec_add(&hd_qiov, cluster_data,
+                cur_nr_sectors * 512);
         }
 
-        assert(acb->hd_qiov.size <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
-        qemu_iovec_to_buffer(&acb->hd_qiov, acb->cluster_data);
+        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+        qemu_co_mutex_unlock(&s->lock);
+        ret = bdrv_co_writev(bs->file,
+                             (cluster_offset >> 9) + index_in_cluster,
+                             cur_nr_sectors, &hd_qiov);
+        qemu_co_mutex_lock(&s->lock);
+        if (ret < 0) {
+            goto fail;
+        }
 
-        qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data,
-            acb->cluster_data, acb->cur_nr_sectors, 1, &s->aes_encrypt_key);
+        ret = qcow2_alloc_cluster_link_l2(bs, &l2meta);
+        if (ret < 0) {
+            goto fail;
+        }
 
-        qemu_iovec_reset(&acb->hd_qiov);
-        qemu_iovec_add(&acb->hd_qiov, acb->cluster_data,
-            acb->cur_nr_sectors * 512);
-    }
+        run_dependent_requests(s, &l2meta);
 
-    BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
-    acb->hd_aiocb = bdrv_aio_writev(bs->file,
-                                    (acb->cluster_offset >> 9) + index_in_cluster,
-                                    &acb->hd_qiov, acb->cur_nr_sectors,
-                                    qcow2_aio_write_cb, acb);
-    if (acb->hd_aiocb == NULL) {
-        ret = -EIO;
-        goto fail;
+        remaining_sectors -= cur_nr_sectors;
+        sector_num += cur_nr_sectors;
+        bytes_done += cur_nr_sectors * 512;
     }
-
-    return;
+    ret = 0;
 
 fail:
-    if (acb->l2meta.nb_clusters != 0) {
-        QLIST_REMOVE(&acb->l2meta, next_in_flight);
-    }
-done:
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_iovec_destroy(&acb->hd_qiov);
-    qemu_aio_release(acb);
-}
-
-static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
-                                          int64_t sector_num,
-                                          QEMUIOVector *qiov, int nb_sectors,
-                                          BlockDriverCompletionFunc *cb,
-                                          void *opaque)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowAIOCB *acb;
+    run_dependent_requests(s, &l2meta);
 
-    s->cluster_cache_offset = -1; /* disable compressed cache */
+    qemu_co_mutex_unlock(&s->lock);
 
-    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-    if (!acb)
-        return NULL;
+    qemu_iovec_destroy(&hd_qiov);
+    qemu_vfree(cluster_data);
 
-    qcow2_aio_write_cb(acb, 0);
-    return &acb->common;
+    return ret;
 }
 
 static void qcow2_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
-    qemu_free(s->l1_table);
+    g_free(s->l1_table);
 
     qcow2_cache_flush(bs, s->l2_table_cache);
     qcow2_cache_flush(bs, s->refcount_block_cache);
@@ -746,11 +628,42 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
+    g_free(s->cluster_cache);
+    qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
 }
 
+static void qcow2_invalidate_cache(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int flags = s->flags;
+    AES_KEY aes_encrypt_key;
+    AES_KEY aes_decrypt_key;
+    uint32_t crypt_method = 0;
+
+    /*
+     * Backing files are read-only which makes all of their metadata immutable,
+     * that means we don't have to worry about reopening them here.
+     */
+
+    if (s->crypt_method) {
+        crypt_method = s->crypt_method;
+        memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
+        memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
+    }
+
+    qcow2_close(bs);
+
+    memset(s, 0, sizeof(BDRVQcowState));
+    qcow2_open(bs, flags);
+
+    if (crypt_method) {
+        s->crypt_method = crypt_method;
+        memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
+        memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
+    }
+}
+
 /*
  * Updates the variable length parts of the qcow2 header, i.e. the backing file
  * name and all extensions. qcow2 was not designed to allow such changes, so if
@@ -860,7 +773,7 @@ static int preallocate(BlockDriverState *bs)
 
     nb_sectors = bdrv_getlength(bs) >> 9;
     offset = 0;
-    QLIST_INIT(&meta.dependent_requests);
+    qemu_co_queue_init(&meta.dependent_requests);
     meta.cluster_offset = 0;
 
     while (nb_sectors) {
@@ -878,7 +791,7 @@ static int preallocate(BlockDriverState *bs)
 
         /* There are no dependent requests, but we need to remove our request
          * from the list of in-flight requests */
-        run_dependent_requests(&meta);
+        run_dependent_requests(bs->opaque, &meta);
 
         /* TODO Preallocate data if requested */
 
@@ -915,7 +828,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
         (1 << cluster_bits) != cluster_size)
     {
         error_report(
-            "Cluster size must be a power of two between %d and %dk\n",
+            "Cluster size must be a power of two between %d and %dk",
             1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
         return -EINVAL;
     }
@@ -970,9 +883,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
     }
 
     /* Write an empty refcount table */
-    refcount_table = qemu_mallocz(cluster_size);
+    refcount_table = g_malloc0(cluster_size);
     ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
-    qemu_free(refcount_table);
+    g_free(refcount_table);
 
     if (ret < 0) {
         goto out;
@@ -1036,7 +949,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
     const char *backing_fmt = NULL;
     uint64_t sectors = 0;
     int flags = 0;
-    size_t cluster_size = 65536;
+    size_t cluster_size = DEFAULT_CLUSTER_SIZE;
     int prealloc = 0;
 
     /* Read out options */
@@ -1097,11 +1010,17 @@ static int qcow2_make_empty(BlockDriverState *bs)
     return 0;
 }
 
-static int qcow2_discard(BlockDriverState *bs, int64_t sector_num,
-    int nb_sectors)
+static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
-    return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+    int ret;
+    BDRVQcowState *s = bs->opaque;
+
+    qemu_co_mutex_lock(&s->lock);
+    ret = qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
         nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
 }
 
 static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
@@ -1164,7 +1083,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
     if (nb_sectors != s->cluster_sectors)
         return -EINVAL;
 
-    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
 
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
@@ -1172,8 +1091,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
                        Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
-        qemu_free(out_buf);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
 
     strm.avail_in = s->cluster_size;
@@ -1183,9 +1102,9 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     ret = deflate(&strm, Z_FINISH);
     if (ret != Z_STREAM_END && ret != Z_OK) {
-        qemu_free(out_buf);
         deflateEnd(&strm);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
     out_len = strm.next_out - out_buf;
 
@@ -1193,60 +1112,56 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        if (ret < 0) {
+            goto fail;
+        }
     } else {
         cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
             sector_num << 9, out_len);
-        if (!cluster_offset)
-            return -1;
+        if (!cluster_offset) {
+            ret = -EIO;
+            goto fail;
+        }
         cluster_offset &= s->cluster_offset_mask;
         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
-        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
-            qemu_free(out_buf);
-            return -1;
+        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        if (ret < 0) {
+            goto fail;
         }
     }
 
-    qemu_free(out_buf);
-    return 0;
+    ret = 0;
+fail:
+    g_free(out_buf);
+    return ret;
 }
 
-static int qcow2_flush(BlockDriverState *bs)
+static int qcow2_co_flush_to_os(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     int ret;
 
+    qemu_co_mutex_lock(&s->lock);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
+        qemu_co_mutex_unlock(&s->lock);
         return ret;
     }
 
     ret = qcow2_cache_flush(bs, s->refcount_block_cache);
     if (ret < 0) {
+        qemu_co_mutex_unlock(&s->lock);
         return ret;
     }
+    qemu_co_mutex_unlock(&s->lock);
 
-    return bdrv_flush(bs->file);
+    return 0;
 }
 
-static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
+static int qcow2_co_flush_to_disk(BlockDriverState *bs)
 {
-    BDRVQcowState *s = bs->opaque;
-    int ret;
-
-    ret = qcow2_cache_flush(bs, s->l2_table_cache);
-    if (ret < 0) {
-        return NULL;
-    }
-
-    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
-    if (ret < 0) {
-        return NULL;
-    }
-
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
@@ -1343,7 +1258,8 @@ static QEMUOptionParameter qcow2_create_options[] = {
     {
         .name = BLOCK_OPT_CLUSTER_SIZE,
         .type = OPT_SIZE,
-        .help = "qcow2 cluster size"
+        .help = "qcow2 cluster size",
+        .value = { .n = DEFAULT_CLUSTER_SIZE },
     },
     {
         .name = BLOCK_OPT_PREALLOC,
@@ -1360,16 +1276,16 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_open          = qcow2_open,
     .bdrv_close         = qcow2_close,
     .bdrv_create        = qcow2_create,
-    .bdrv_flush         = qcow2_flush,
     .bdrv_is_allocated  = qcow2_is_allocated,
     .bdrv_set_key       = qcow2_set_key,
     .bdrv_make_empty    = qcow2_make_empty,
 
-    .bdrv_aio_readv     = qcow2_aio_readv,
-    .bdrv_aio_writev    = qcow2_aio_writev,
-    .bdrv_aio_flush     = qcow2_aio_flush,
+    .bdrv_co_readv          = qcow2_co_readv,
+    .bdrv_co_writev         = qcow2_co_writev,
+    .bdrv_co_flush_to_os    = qcow2_co_flush_to_os,
+    .bdrv_co_flush_to_disk  = qcow2_co_flush_to_disk,
 
-    .bdrv_discard           = qcow2_discard,
+    .bdrv_co_discard        = qcow2_co_discard,
     .bdrv_truncate          = qcow2_truncate,
     .bdrv_write_compressed  = qcow2_write_compressed,
 
@@ -1385,6 +1301,8 @@ static BlockDriver bdrv_qcow2 = {
 
     .bdrv_change_backing_file   = qcow2_change_backing_file,
 
+    .bdrv_invalidate_cache      = qcow2_invalidate_cache,
+
     .create_options = qcow2_create_options,
     .bdrv_check = qcow2_check,
 };
index a019831838e231fad92a3c5225fb28df3a208f49..4e44eea5efddec608d64385c43f2ca410c05f405 100644 (file)
@@ -26,6 +26,7 @@
 #define BLOCK_QCOW2_H
 
 #include "aes.h"
+#include "qemu-coroutine.h"
 
 //#define DEBUG_ALLOC
 //#define DEBUG_ALLOC2
@@ -54,6 +55,8 @@
 /* Must be at least 4 to cover all cases of refcount table growth */
 #define REFCOUNT_CACHE_SIZE 4
 
+#define DEFAULT_CLUSTER_SIZE 65536
+
 typedef struct QCowHeader {
     uint32_t magic;
     uint32_t version;
@@ -112,6 +115,8 @@ typedef struct BDRVQcowState {
     int64_t free_cluster_index;
     int64_t free_byte_offset;
 
+    CoMutex lock;
+
     uint32_t crypt_method; /* current crypt method, 0 if no key yet */
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
@@ -120,6 +125,8 @@ typedef struct BDRVQcowState {
     int snapshots_size;
     int nb_snapshots;
     QCowSnapshot *snapshots;
+
+    int flags;
 } BDRVQcowState;
 
 /* XXX: use std qcow open function ? */
@@ -143,8 +150,7 @@ typedef struct QCowL2Meta
     int n_start;
     int nb_available;
     int nb_clusters;
-    struct QCowL2Meta *depends_on;
-    QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
+    CoQueue dependent_requests;
 
     QLIST_ENTRY(QCowL2Meta) next_in_flight;
 } QCowL2Meta;
@@ -184,8 +190,6 @@ void qcow2_free_clusters(BlockDriverState *bs,
 void qcow2_free_any_clusters(BlockDriverState *bs,
     uint64_t cluster_offset, int nb_clusters);
 
-void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
-    int64_t size);
 int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     int64_t l1_table_offset, int l1_size, int addend);
 
@@ -226,6 +230,8 @@ int qcow2_read_snapshots(BlockDriverState *bs);
 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
     bool writethrough);
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable);
 
 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
index 474c847d18203a3d3c2136c30d5987c2dca4532e..e4a49ce72cb7ff92afeb9ed27220a1ede440fa7f 100644 (file)
@@ -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;
         }
 
@@ -196,7 +197,7 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
     };
     int ret;
 
-    check.used_clusters = qemu_mallocz(((check.nclusters + 31) / 32) *
+    check.used_clusters = g_malloc0(((check.nclusters + 31) / 32) *
                                        sizeof(check.used_clusters[0]));
 
     ret = qed_check_l1_table(&check, s->l1_table);
@@ -205,6 +206,6 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
         qed_check_for_leaks(&check);
     }
 
-    qemu_free(check.used_clusters);
+    g_free(check.used_clusters);
     return ret;
 }
index 0ec864b14cda0f9cc6b3821fac0a10fc58b7039a..f64b2af8f7ef7127956359cff9bb7486f1dea344 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,17 +93,22 @@ 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);
+    g_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;
     }
@@ -141,7 +152,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
         return;
     }
 
-    find_cluster_cb = qemu_malloc(sizeof(*find_cluster_cb));
+    find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
     find_cluster_cb->s = s;
     find_cluster_cb->pos = pos;
     find_cluster_cb->len = len;
index 1513dc6f79e1eb1b7c607276930fdad8857f1b8f..7d7ac1ffc8e0a1497c76519c04be383d1d8ad3af 100644 (file)
@@ -15,7 +15,7 @@
 
 void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
 {
-    GenericCB *gencb = qemu_malloc(len);
+    GenericCB *gencb = g_malloc(len);
     gencb->cb = cb;
     gencb->opaque = opaque;
     return gencb;
@@ -27,6 +27,6 @@ void gencb_complete(void *opaque, int ret)
     BlockDriverCompletionFunc *cb = gencb->cb;
     void *user_opaque = gencb->opaque;
 
-    qemu_free(gencb);
+    g_free(gencb);
     cb(user_opaque, ret);
 }
index 57518a4e7fe8f6b8e89954d99ceb0b652f3ca91c..02b81a2e33c2b25c6dab746861103cf8593e2908 100644 (file)
@@ -74,7 +74,7 @@ void qed_free_l2_cache(L2TableCache *l2_cache)
 
     QTAILQ_FOREACH_SAFE(entry, &l2_cache->entries, node, next_entry) {
         qemu_vfree(entry->table);
-        qemu_free(entry);
+        g_free(entry);
     }
 }
 
@@ -89,7 +89,7 @@ CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache)
 {
     CachedL2Table *entry;
 
-    entry = qemu_mallocz(sizeof(*entry));
+    entry = g_malloc0(sizeof(*entry));
     entry->ref++;
 
     trace_qed_alloc_l2_cache_entry(l2_cache, entry);
@@ -111,7 +111,7 @@ void qed_unref_l2_cache_entry(CachedL2Table *entry)
     trace_qed_unref_l2_cache_entry(entry, entry->ref);
     if (entry->ref == 0) {
         qemu_vfree(entry->table);
-        qemu_free(entry);
+        g_free(entry);
     }
 }
 
index d38c673547e32368fa3a52615e98ba08f52967cc..f31f9ff069af747658016d6ef2b1c7b613124423 100644 (file)
@@ -179,16 +179,12 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_read_table(s, s->header.l1_table_offset,
                    s->l1_table, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     return ret;
 }
 
@@ -205,15 +201,11 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     return ret;
 }
 
@@ -230,21 +222,21 @@ static void qed_read_l2_table_cb(void *opaque, int ret)
     QEDRequest *request = read_l2_table_cb->request;
     BDRVQEDState *s = read_l2_table_cb->s;
     CachedL2Table *l2_table = request->l2_table;
+    uint64_t l2_offset = read_l2_table_cb->l2_offset;
 
     if (ret) {
         /* can't trust loaded L2 table anymore */
         qed_unref_l2_cache_entry(l2_table);
         request->l2_table = NULL;
     } else {
-        l2_table->offset = read_l2_table_cb->l2_offset;
+        l2_table->offset = l2_offset;
 
         qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
 
         /* This is guaranteed to succeed because we just committed the entry
          * to the cache.
          */
-        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache,
-                                                    l2_table->offset);
+        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
         assert(request->l2_table != NULL);
     }
 
@@ -282,14 +274,11 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
     return ret;
 }
 
@@ -307,13 +296,10 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
     return ret;
 }
index 75ae2440ee44ce7c9a69b1fc3095ae112cb21a1d..7e22e77b9d16597b786a66f3172334280f8bb790 100644 (file)
  *
  */
 
+#include "qemu-timer.h"
 #include "trace.h"
 #include "qed.h"
 #include "qerror.h"
+#include "migration.h"
 
 static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
 {
@@ -291,6 +293,88 @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
 
 static void qed_aio_next_io(void *opaque, int ret);
 
+static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
+{
+    assert(!s->allocating_write_reqs_plugged);
+
+    s->allocating_write_reqs_plugged = true;
+}
+
+static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
+{
+    QEDAIOCB *acb;
+
+    assert(s->allocating_write_reqs_plugged);
+
+    s->allocating_write_reqs_plugged = false;
+
+    acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
+    if (acb) {
+        qed_aio_next_io(acb, 0);
+    }
+}
+
+static void qed_finish_clear_need_check(void *opaque, int ret)
+{
+    /* Do nothing */
+}
+
+static void qed_flush_after_clear_need_check(void *opaque, int ret)
+{
+    BDRVQEDState *s = opaque;
+
+    bdrv_aio_flush(s->bs, qed_finish_clear_need_check, s);
+
+    /* No need to wait until flush completes */
+    qed_unplug_allocating_write_reqs(s);
+}
+
+static void qed_clear_need_check(void *opaque, int ret)
+{
+    BDRVQEDState *s = opaque;
+
+    if (ret) {
+        qed_unplug_allocating_write_reqs(s);
+        return;
+    }
+
+    s->header.features &= ~QED_F_NEED_CHECK;
+    qed_write_header(s, qed_flush_after_clear_need_check, s);
+}
+
+static void qed_need_check_timer_cb(void *opaque)
+{
+    BDRVQEDState *s = opaque;
+
+    /* The timer should only fire when allocating writes have drained */
+    assert(!QSIMPLEQ_FIRST(&s->allocating_write_reqs));
+
+    trace_qed_need_check_timer_cb(s);
+
+    qed_plug_allocating_write_reqs(s);
+
+    /* Ensure writes are on disk before clearing flag */
+    bdrv_aio_flush(s->bs, qed_clear_need_check, s);
+}
+
+static void qed_start_need_check_timer(BDRVQEDState *s)
+{
+    trace_qed_start_need_check_timer(s);
+
+    /* Use vm_clock so we don't alter the image file while suspended for
+     * migration.
+     */
+    qemu_mod_timer(s->need_check_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() * QED_NEED_CHECK_TIMEOUT);
+}
+
+/* It's okay to call this multiple times or when no timer is started */
+static void qed_cancel_need_check_timer(BDRVQEDState *s)
+{
+    trace_qed_cancel_need_check_timer(s);
+    qemu_del_timer(s->need_check_timer);
+}
+
 static int bdrv_qed_open(BlockDriverState *bs, int flags)
 {
     BDRVQEDState *s = bs->opaque;
@@ -305,7 +389,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
     if (ret < 0) {
         return ret;
     }
-    ret = 0; /* ret should always be 0 or -errno */
     qed_header_le_to_cpu(&le_header, &s->header);
 
     if (s->header.magic != QED_MAGIC) {
@@ -406,7 +489,10 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
             BdrvCheckResult result = {0};
 
             ret = qed_check(s, &result, true);
-            if (!ret && !result.corruptions && !result.check_errors) {
+            if (ret) {
+                goto out;
+            }
+            if (!result.corruptions && !result.check_errors) {
                 /* Ensure fixes reach storage before clearing check bit */
                 bdrv_flush(s->bs);
 
@@ -416,6 +502,15 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
         }
     }
 
+    s->need_check_timer = qemu_new_timer_ns(vm_clock,
+                                            qed_need_check_timer_cb, s);
+
+    error_set(&s->migration_blocker,
+              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+              "qed", bs->device_name, "live migration");
+    migrate_add_blocker(s->migration_blocker);
+
+
 out:
     if (ret) {
         qed_free_l2_cache(&s->l2_cache);
@@ -428,6 +523,12 @@ static void bdrv_qed_close(BlockDriverState *bs)
 {
     BDRVQEDState *s = bs->opaque;
 
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
+
+    qed_cancel_need_check_timer(s);
+    qemu_free_timer(s->need_check_timer);
+
     /* Ensure writes reach stable storage */
     bdrv_flush(bs->file);
 
@@ -441,11 +542,6 @@ static void bdrv_qed_close(BlockDriverState *bs)
     qemu_vfree(s->l1_table);
 }
 
-static int bdrv_qed_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static int qed_create(const char *filename, uint32_t cluster_size,
                       uint64_t image_size, uint32_t table_size,
                       const char *backing_file, const char *backing_fmt)
@@ -503,7 +599,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
         goto out;
     }
 
-    l1_table = qemu_mallocz(l1_size);
+    l1_table = g_malloc0(l1_size);
     ret = bdrv_pwrite(bs, header.l1_table_offset, l1_table, l1_size);
     if (ret < 0) {
         goto out;
@@ -511,7 +607,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
 
     ret = 0; /* success */
 out:
-    qemu_free(l1_table);
+    g_free(l1_table);
     bdrv_delete(bs);
     return ret;
 }
@@ -573,7 +669,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,
@@ -588,16 +684,12 @@ static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
     };
     QEDRequest request = { .l2_table = NULL };
 
-    async_context_push();
-
     qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb);
 
     while (cb.is_allocated == -1) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     qed_unref_l2_cache_entry(request.l2_table);
 
     return cb.is_allocated;
@@ -745,7 +837,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 +848,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;
+        }
     }
 }
 
@@ -803,6 +901,8 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
         acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
         if (acb) {
             qed_aio_next_io(acb, 0);
+        } else if (s->header.features & QED_F_NEED_CHECK) {
+            qed_start_need_check_timer(s);
         }
     }
 }
@@ -815,14 +915,14 @@ static void qed_commit_l2_update(void *opaque, int ret)
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
     CachedL2Table *l2_table = acb->request.l2_table;
+    uint64_t l2_offset = l2_table->offset;
 
     qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
 
     /* This is guaranteed to succeed because we just committed the entry to the
      * cache.
      */
-    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache,
-                                                    l2_table->offset);
+    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
     assert(acb->request.l2_table != NULL);
 
     qed_aio_next_io(opaque, ret);
@@ -1008,11 +1108,17 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
 {
     BDRVQEDState *s = acb_to_s(acb);
 
+    /* Cancel timer when the first allocating request comes in */
+    if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
+        qed_cancel_need_check_timer(s);
+    }
+
     /* Freeze this request if another allocating write is in progress */
     if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
         QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);
     }
-    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
+        s->allocating_write_reqs_plugged) {
         return; /* wait for existing request to finish */
     }
 
@@ -1075,6 +1181,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 +1221,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;
@@ -1222,7 +1333,27 @@ static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
 
 static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
 {
-    return -ENOTSUP;
+    BDRVQEDState *s = bs->opaque;
+    uint64_t old_image_size;
+    int ret;
+
+    if (!qed_is_image_size_valid(offset, s->header.cluster_size,
+                                 s->header.table_size)) {
+        return -EINVAL;
+    }
+
+    /* Shrinking is currently not supported */
+    if ((uint64_t)offset < s->header.image_size) {
+        return -ENOTSUP;
+    }
+
+    old_image_size = s->header.image_size;
+    s->header.image_size = offset;
+    ret = qed_write_header_sync(s);
+    if (ret < 0) {
+        s->header.image_size = old_image_size;
+    }
+    return ret;
 }
 
 static int64_t bdrv_qed_getlength(BlockDriverState *bs)
@@ -1292,18 +1423,20 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
     }
 
     /* Prepare new header */
-    buffer = qemu_malloc(buffer_len);
+    buffer = g_malloc(buffer_len);
 
     qed_header_cpu_to_le(&new_header, &le_header);
     memcpy(buffer, &le_header, sizeof(le_header));
     buffer_len = sizeof(le_header);
 
-    memcpy(buffer + buffer_len, backing_file, backing_file_len);
-    buffer_len += backing_file_len;
+    if (backing_file) {
+        memcpy(buffer + buffer_len, backing_file, backing_file_len);
+        buffer_len += backing_file_len;
+    }
 
     /* Write new header */
     ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
-    qemu_free(buffer);
+    g_free(buffer);
     if (ret == 0) {
         memcpy(&s->header, &new_header, sizeof(new_header));
     }
@@ -1333,7 +1466,8 @@ static QEMUOptionParameter qed_create_options[] = {
     }, {
         .name = BLOCK_OPT_CLUSTER_SIZE,
         .type = OPT_SIZE,
-        .help = "Cluster size (in bytes)"
+        .help = "Cluster size (in bytes)",
+        .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
     }, {
         .name = BLOCK_OPT_TABLE_SIZE,
         .type = OPT_SIZE,
@@ -1351,7 +1485,6 @@ static BlockDriver bdrv_qed = {
     .bdrv_open                = bdrv_qed_open,
     .bdrv_close               = bdrv_qed_close,
     .bdrv_create              = bdrv_qed_create,
-    .bdrv_flush               = bdrv_qed_flush,
     .bdrv_is_allocated        = bdrv_qed_is_allocated,
     .bdrv_make_empty          = bdrv_qed_make_empty,
     .bdrv_aio_readv           = bdrv_qed_aio_readv,
index 9f72ad5499fbd3a6b6e9d20458f654b90c040303..62cbd3b8996162525756ba9280e652d13c191d68 100644 (file)
@@ -78,6 +78,9 @@ enum {
     QED_MIN_TABLE_SIZE = 1,        /* in clusters */
     QED_MAX_TABLE_SIZE = 16,
     QED_DEFAULT_TABLE_SIZE = 4,
+
+    /* Delay to flush and clean image after last allocating write completes */
+    QED_NEED_CHECK_TIMEOUT = 5,    /* in seconds */
 };
 
 typedef struct {
@@ -157,10 +160,17 @@ typedef struct {
 
     /* Allocating write request queue */
     QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
+    bool allocating_write_reqs_plugged;
+
+    /* Periodic flush and clear need check flag */
+    QEMUTimer *need_check_timer;
+
+    Error *migration_blocker;
 } BDRVQEDState;
 
 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 */
 };
@@ -298,4 +308,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 6b724705994d0600c471fb4c897c8a3c16d05910..a3de373586a8750e3ec357ac4a4b60215ec2514c 100644 (file)
 
 #ifdef __sun__
 #define _POSIX_PTHREAD_SEMANTICS 1
-#include <signal.h>
 #include <sys/dkio.h>
 #endif
 #ifdef __linux__
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #include <linux/cdrom.h>
 #include <linux/fd.h>
 #endif
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <signal.h>
 #include <sys/disk.h>
 #include <sys/cdio.h>
 #endif
 #include <sys/dkio.h>
 #endif
 
+#ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/disk.h>
+#endif
+
 #ifdef __DragonFly__
 #include <sys/ioctl.h>
 #include <sys/diskslice.h>
@@ -136,12 +143,55 @@ static int64_t raw_getlength(BlockDriverState *bs);
 static int cdrom_reopen(BlockDriverState *bs);
 #endif
 
+#if defined(__NetBSD__)
+static int raw_normalize_devicepath(const char **filename)
+{
+    static char namebuf[PATH_MAX];
+    const char *dp, *fname;
+    struct stat sb;
+
+    fname = *filename;
+    dp = strrchr(fname, '/');
+    if (lstat(fname, &sb) < 0) {
+        fprintf(stderr, "%s: stat failed: %s\n",
+            fname, strerror(errno));
+        return -errno;
+    }
+
+    if (!S_ISBLK(sb.st_mode)) {
+        return 0;
+    }
+
+    if (dp == NULL) {
+        snprintf(namebuf, PATH_MAX, "r%s", fname);
+    } else {
+        snprintf(namebuf, PATH_MAX, "%.*s/r%s",
+            (int)(dp - fname), fname, dp + 1);
+    }
+    fprintf(stderr, "%s is a block device", fname);
+    *filename = namebuf;
+    fprintf(stderr, ", using %s\n", *filename);
+
+    return 0;
+}
+#else
+static int raw_normalize_devicepath(const char **filename)
+{
+    return 0;
+}
+#endif
+
 static int raw_open_common(BlockDriverState *bs, const char *filename,
                            int bdrv_flags, int open_flags)
 {
     BDRVRawState *s = bs->opaque;
     int fd, ret;
 
+    ret = raw_normalize_devicepath(&filename);
+    if (ret != 0) {
+        return ret;
+    }
+
     s->open_flags = open_flags | O_BINARY;
     s->open_flags &= ~O_ACCMODE;
     if (bdrv_flags & BDRV_O_RDWR) {
@@ -154,7 +204,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
      * and O_DIRECT for no caching. */
     if ((bdrv_flags & BDRV_O_NOCACHE))
         s->open_flags |= O_DIRECT;
-    else if (!(bdrv_flags & BDRV_O_CACHE_WB))
+    if (!(bdrv_flags & BDRV_O_CACHE_WB))
         s->open_flags |= O_DSYNC;
 
     s->fd = -1;
@@ -180,13 +230,19 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
         }
     }
 
+    /* We're falling back to POSIX AIO in some cases so init always */
+    if (paio_init() < 0) {
+        goto out_free_buf;
+    }
+
 #ifdef CONFIG_LINUX_AIO
+    /*
+     * Currently Linux do AIO only for files opened with O_DIRECT
+     * specified so check NOCACHE flag too
+     */
     if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
                       (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
 
-        /* We're falling back to POSIX AIO in some cases */
-        paio_init();
-
         s->aio_ctx = laio_init();
         if (!s->aio_ctx) {
             goto out_free_buf;
@@ -195,9 +251,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     } else
 #endif
     {
-        if (paio_init() < 0) {
-            goto out_free_buf;
-        }
 #ifdef CONFIG_LINUX_AIO
         s->use_aio = 0;
 #endif
@@ -243,273 +296,6 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 #endif
 */
 
-/*
- * offset and count are in bytes, but must be multiples of 512 for files
- * opened with O_DIRECT. buf must be aligned to 512 bytes then.
- *
- * This function may be called without alignment if the caller ensures
- * that O_DIRECT is not in effect.
- */
-static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
-                     uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = fd_open(bs);
-    if (ret < 0)
-        return ret;
-
-    ret = pread(s->fd, buf, count, offset);
-    if (ret == count)
-        return ret;
-
-    /* Allow reads beyond the end (needed for pwrite) */
-    if ((ret == 0) && bs->growable) {
-        int64_t size = raw_getlength(bs);
-        if (offset >= size) {
-            memset(buf, 0, count);
-            return count;
-        }
-    }
-
-    DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                      "] read failed %d : %d = %s\n",
-                      s->fd, bs->filename, offset, buf, count,
-                      bs->total_sectors, ret, errno, strerror(errno));
-
-    /* Try harder for CDrom. */
-    if (s->type != FTYPE_FILE) {
-        ret = pread(s->fd, buf, count, offset);
-        if (ret == count)
-            return ret;
-        ret = pread(s->fd, buf, count, offset);
-        if (ret == count)
-            return ret;
-
-        DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                          "] retry read failed %d : %d = %s\n",
-                          s->fd, bs->filename, offset, buf, count,
-                          bs->total_sectors, ret, errno, strerror(errno));
-    }
-
-    return  (ret < 0) ? -errno : ret;
-}
-
-/*
- * offset and count are in bytes, but must be multiples of the sector size
- * for files opened with O_DIRECT. buf must be aligned to sector size bytes
- * then.
- *
- * This function may be called without alignment if the caller ensures
- * that O_DIRECT is not in effect.
- */
-static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
-                      const uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = fd_open(bs);
-    if (ret < 0)
-        return -errno;
-
-    ret = pwrite(s->fd, buf, count, offset);
-    if (ret == count)
-        return ret;
-
-    DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                      "] write failed %d : %d = %s\n",
-                      s->fd, bs->filename, offset, buf, count,
-                      bs->total_sectors, ret, errno, strerror(errno));
-
-    return  (ret < 0) ? -errno : ret;
-}
-
-
-/*
- * offset and count are in bytes and possibly not aligned. For files opened
- * with O_DIRECT, necessary alignments are ensured before calling
- * raw_pread_aligned to do the actual read.
- */
-static int raw_pread(BlockDriverState *bs, int64_t offset,
-                     uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    unsigned sector_mask = bs->buffer_alignment - 1;
-    int size, ret, shift, sum;
-
-    sum = 0;
-
-    if (s->aligned_buf != NULL)  {
-
-        if (offset & sector_mask) {
-            /* align offset on a sector size bytes boundary */
-
-            shift = offset & sector_mask;
-            size = (shift + count + sector_mask) & ~sector_mask;
-            if (size > s->aligned_buf_size)
-                size = s->aligned_buf_size;
-            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size);
-            if (ret < 0)
-                return ret;
-
-            size = bs->buffer_alignment - shift;
-            if (size > count)
-                size = count;
-            memcpy(buf, s->aligned_buf + shift, size);
-
-            buf += size;
-            offset += size;
-            count -= size;
-            sum += size;
-
-            if (count == 0)
-                return sum;
-        }
-        if (count & sector_mask || (uintptr_t) buf & sector_mask) {
-
-            /* read on aligned buffer */
-
-            while (count) {
-
-                size = (count + sector_mask) & ~sector_mask;
-                if (size > s->aligned_buf_size)
-                    size = s->aligned_buf_size;
-
-                ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
-                if (ret < 0) {
-                    return ret;
-                } else if (ret == 0) {
-                    fprintf(stderr, "raw_pread: read beyond end of file\n");
-                    abort();
-                }
-
-                size = ret;
-                if (size > count)
-                    size = count;
-
-                memcpy(buf, s->aligned_buf, size);
-
-                buf += size;
-                offset += size;
-                count -= size;
-                sum += size;
-            }
-
-            return sum;
-        }
-    }
-
-    return raw_pread_aligned(bs, offset, buf, count) + sum;
-}
-
-static int raw_read(BlockDriverState *bs, int64_t sector_num,
-                    uint8_t *buf, int nb_sectors)
-{
-    int ret;
-
-    ret = raw_pread(bs, sector_num * BDRV_SECTOR_SIZE, buf,
-                    nb_sectors * BDRV_SECTOR_SIZE);
-    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
-        ret = 0;
-    return ret;
-}
-
-/*
- * offset and count are in bytes and possibly not aligned. For files opened
- * with O_DIRECT, necessary alignments are ensured before calling
- * raw_pwrite_aligned to do the actual write.
- */
-static int raw_pwrite(BlockDriverState *bs, int64_t offset,
-                      const uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    unsigned sector_mask = bs->buffer_alignment - 1;
-    int size, ret, shift, sum;
-
-    sum = 0;
-
-    if (s->aligned_buf != NULL) {
-
-        if (offset & sector_mask) {
-            /* align offset on a sector size bytes boundary */
-            shift = offset & sector_mask;
-            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf,
-                                    bs->buffer_alignment);
-            if (ret < 0)
-                return ret;
-
-            size = bs->buffer_alignment - shift;
-            if (size > count)
-                size = count;
-            memcpy(s->aligned_buf + shift, buf, size);
-
-            ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf,
-                                     bs->buffer_alignment);
-            if (ret < 0)
-                return ret;
-
-            buf += size;
-            offset += size;
-            count -= size;
-            sum += size;
-
-            if (count == 0)
-                return sum;
-        }
-        if (count & sector_mask || (uintptr_t) buf & sector_mask) {
-
-            while ((size = (count & ~sector_mask)) != 0) {
-
-                if (size > s->aligned_buf_size)
-                    size = s->aligned_buf_size;
-
-                memcpy(s->aligned_buf, buf, size);
-
-                ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size);
-                if (ret < 0)
-                    return ret;
-
-                buf += ret;
-                offset += ret;
-                count -= ret;
-                sum += ret;
-            }
-            /* here, count < sector_size because (count & ~sector_mask) == 0 */
-            if (count) {
-                ret = raw_pread_aligned(bs, offset, s->aligned_buf,
-                                     bs->buffer_alignment);
-                if (ret < 0)
-                    return ret;
-                 memcpy(s->aligned_buf, buf, count);
-
-                 ret = raw_pwrite_aligned(bs, offset, s->aligned_buf,
-                                     bs->buffer_alignment);
-                 if (ret < 0)
-                     return ret;
-                 if (count < ret)
-                     ret = count;
-
-                 sum += ret;
-            }
-            return sum;
-        }
-    }
-    return raw_pwrite_aligned(bs, offset, buf, count) + sum;
-}
-
-static int raw_write(BlockDriverState *bs, int64_t sector_num,
-                     const uint8_t *buf, int nb_sectors)
-{
-    int ret;
-    ret = raw_pwrite(bs, sector_num * BDRV_SECTOR_SIZE, buf,
-                     nb_sectors * BDRV_SECTOR_SIZE);
-    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
-        ret = 0;
-    return ret;
-}
-
 /*
  * Check if all memory in this vector is sector aligned.
  */
@@ -537,7 +323,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
 
     /*
      * If O_DIRECT is used the buffer needs to be aligned on a sector
-     * boundary.  Check if this is the case or telll the low-level
+     * boundary.  Check if this is the case or tell the low-level
      * driver that it needs to copy the buffer.
      */
     if (s->aligned_buf) {
@@ -596,10 +382,24 @@ static void raw_close(BlockDriverState *bs)
 static int raw_truncate(BlockDriverState *bs, int64_t offset)
 {
     BDRVRawState *s = bs->opaque;
-    if (s->type != FTYPE_FILE)
-        return -ENOTSUP;
-    if (ftruncate(s->fd, offset) < 0)
+    struct stat st;
+
+    if (fstat(s->fd, &st)) {
         return -errno;
+    }
+
+    if (S_ISREG(st.st_mode)) {
+        if (ftruncate(s->fd, offset) < 0) {
+            return -errno;
+        }
+    } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+       if (offset > raw_getlength(bs)) {
+           return -EINVAL;
+       }
+    } else {
+        return -ENOTSUP;
+    }
+
     return 0;
 }
 
@@ -622,6 +422,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
     } else
         return st.st_size;
 }
+#elif defined(__NetBSD__)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    struct stat st;
+
+    if (fstat(fd, &st))
+        return -1;
+    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+        struct dkwedge_info dkw;
+
+        if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) {
+            return dkw.dkw_size * 512;
+        } else {
+            struct disklabel dl;
+
+            if (ioctl(fd, DIOCGDINFO, &dl))
+                return -1;
+            return (uint64_t)dl.d_secsize *
+                dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+        }
+    } else
+        return st.st_size;
+}
 #elif defined(__sun__)
 static int64_t raw_getlength(BlockDriverState *bs)
 {
@@ -718,6 +543,17 @@ static int64_t raw_getlength(BlockDriverState *bs)
 }
 #endif
 
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    struct stat st;
+    BDRVRawState *s = bs->opaque;
+
+    if (fstat(s->fd, &st) < 0) {
+        return -errno;
+    }
+    return (int64_t)st.st_blocks * 512;
+}
+
 static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
@@ -747,12 +583,6 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
     return result;
 }
 
-static int raw_flush(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    return qemu_fdatasync(s->fd);
-}
-
 #ifdef CONFIG_XFS
 static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 {
@@ -772,7 +602,8 @@ static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 }
 #endif
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static coroutine_fn int raw_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
 #ifdef CONFIG_XFS
     BDRVRawState *s = bs->opaque;
@@ -800,12 +631,9 @@ static BlockDriver bdrv_file = {
     .instance_size = sizeof(BDRVRawState),
     .bdrv_probe = NULL, /* no probe for protocols */
     .bdrv_file_open = raw_open,
-    .bdrv_read = raw_read,
-    .bdrv_write = raw_write,
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
-    .bdrv_flush = raw_flush,
-    .bdrv_discard = raw_discard,
+    .bdrv_co_discard = raw_co_discard,
 
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
@@ -813,6 +641,8 @@ static BlockDriver bdrv_file = {
 
     .bdrv_truncate = raw_truncate,
     .bdrv_getlength = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     .create_options = raw_create_options,
 };
@@ -1072,15 +902,15 @@ static BlockDriver bdrv_host_device = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv    = raw_aio_readv,
     .bdrv_aio_writev   = raw_aio_writev,
     .bdrv_aio_flush    = raw_aio_flush,
 
-    .bdrv_read          = raw_read,
-    .bdrv_write         = raw_write,
+    .bdrv_truncate      = raw_truncate,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* generic scsi device */
 #ifdef __linux__
@@ -1115,6 +945,7 @@ static int floppy_probe_device(const char *filename)
     int fd, ret;
     int prio = 0;
     struct floppy_struct fdparam;
+    struct stat st;
 
     if (strstart(filename, "/dev/fd", NULL))
         prio = 50;
@@ -1123,12 +954,17 @@ static int floppy_probe_device(const char *filename)
     if (fd < 0) {
         goto out;
     }
+    ret = fstat(fd, &st);
+    if (ret == -1 || !S_ISBLK(st.st_mode)) {
+        goto outc;
+    }
 
     /* Attempt to detect via a floppy specific ioctl */
     ret = ioctl(fd, FDGETPRM, &fdparam);
     if (ret >= 0)
         prio = 100;
 
+outc:
     close(fd);
 out:
     return prio;
@@ -1158,7 +994,7 @@ static int floppy_media_changed(BlockDriverState *bs)
     return ret;
 }
 
-static int floppy_eject(BlockDriverState *bs, int eject_flag)
+static void floppy_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
     int fd;
@@ -1173,8 +1009,6 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
             perror("FDEJECT");
         close(fd);
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_floppy = {
@@ -1187,15 +1021,15 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
     .bdrv_aio_flush    = raw_aio_flush,
 
-    .bdrv_read          = raw_read,
-    .bdrv_write         = raw_write,
+    .bdrv_truncate      = raw_truncate,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = floppy_is_inserted,
@@ -1217,17 +1051,23 @@ static int cdrom_probe_device(const char *filename)
 {
     int fd, ret;
     int prio = 0;
+    struct stat st;
 
     fd = open(filename, O_RDONLY | O_NONBLOCK);
     if (fd < 0) {
         goto out;
     }
+    ret = fstat(fd, &st);
+    if (ret == -1 || !S_ISBLK(st.st_mode)) {
+        goto outc;
+    }
 
     /* Attempt to detect via a CDROM specific ioctl */
     ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
     if (ret >= 0)
         prio = 100;
 
+outc:
     close(fd);
 out:
     return prio;
@@ -1244,7 +1084,7 @@ static int cdrom_is_inserted(BlockDriverState *bs)
     return 0;
 }
 
-static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+static void cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1255,11 +1095,9 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
         if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
             perror("CDROMEJECT");
     }
-
-    return 0;
 }
 
-static int cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1270,8 +1108,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
          */
         /* perror("CDROM_LOCKDOOR"); */
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_cdrom = {
@@ -1284,20 +1120,20 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
     .bdrv_aio_flush    = raw_aio_flush,
 
-    .bdrv_read          = raw_read,
-    .bdrv_write         = raw_write,
+    .bdrv_truncate      = raw_truncate,
     .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 
     /* generic scsi device */
     .bdrv_ioctl         = hdev_ioctl,
@@ -1358,12 +1194,12 @@ static int cdrom_is_inserted(BlockDriverState *bs)
     return raw_getlength(bs) > 0;
 }
 
-static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+static void cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
 
     if (s->fd < 0)
-        return -ENOTSUP;
+        return;
 
     (void) ioctl(s->fd, CDIOCALLOW);
 
@@ -1375,17 +1211,15 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
             perror("CDIOCCLOSE");
     }
 
-    if (cdrom_reopen(bs) < 0)
-        return -ENOTSUP;
-    return 0;
+    cdrom_reopen(bs);
 }
 
-static int cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
     if (s->fd < 0)
-        return -ENOTSUP;
+        return;
     if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
         /*
          * Note: an error can happen if the distribution automatically
@@ -1393,8 +1227,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
          */
         /* perror("CDROM_LOCKDOOR"); */
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_cdrom = {
@@ -1407,20 +1239,20 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
     .bdrv_aio_flush    = raw_aio_flush,
 
-    .bdrv_read          = raw_read,
-    .bdrv_write         = raw_write,
+    .bdrv_truncate      = raw_truncate,
     .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 };
 #endif /* __FreeBSD__ */
 
index c204a80d79156c71f389cfa3ff7cabc07757ebf4..566ec27fb9eac5a77b37f1f2ed5cb7989d271cbc 100644 (file)
@@ -41,6 +41,7 @@ typedef struct BDRVRawState {
 int qemu_ftruncate64(int fd, int64_t length)
 {
     LARGE_INTEGER li;
+    DWORD dw;
     LONG high;
     HANDLE h;
     BOOL res;
@@ -53,12 +54,15 @@ int qemu_ftruncate64(int fd, int64_t length)
     /* get current position, ftruncate do not change position */
     li.HighPart = 0;
     li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
-    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+    if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
        return -1;
+    }
 
     high = length >> 32;
-    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+    dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
+    if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
        return -1;
+    }
     res = SetEndOfFile(h);
 
     /* back to old position */
@@ -88,11 +92,12 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
     }
 
     overlapped = FILE_ATTRIBUTE_NORMAL;
-    if ((flags & BDRV_O_NOCACHE))
-        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
-    else if (!(flags & BDRV_O_CACHE_WB))
+    if (flags & BDRV_O_NOCACHE)
+        overlapped |= FILE_FLAG_NO_BUFFERING;
+    if (!(flags & BDRV_O_CACHE_WB))
         overlapped |= FILE_FLAG_WRITE_THROUGH;
-    s->hfile = CreateFile(filename, access_flags,
+    s->hfile = CreateFile(filename,
+                          access_flags,
                           FILE_SHARE_READ, NULL,
                           OPEN_EXISTING, overlapped, NULL);
     if (s->hfile == INVALID_HANDLE_VALUE) {
@@ -213,6 +218,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
     return l.QuadPart;
 }
 
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
+                                              DWORD * high);
+    get_compressed_t get_compressed;
+    struct _stati64 st;
+    const char *filename = bs->filename;
+    /* WinNT support GetCompressedFileSize to determine allocate size */
+    get_compressed =
+        (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
+                                            "GetCompressedFileSizeA");
+    if (get_compressed) {
+        DWORD high, low;
+        low = get_compressed(filename, &high);
+        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
+            return (((int64_t) high) << 32) + low;
+        }
+    }
+
+    if (_stati64(filename, &st) < 0) {
+        return -1;
+    }
+    return st.st_size;
+}
+
 static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
@@ -252,11 +282,15 @@ static BlockDriver bdrv_file = {
     .bdrv_file_open    = raw_open,
     .bdrv_close                = raw_close,
     .bdrv_create       = raw_create,
-    .bdrv_flush                = raw_flush,
-    .bdrv_read         = raw_read,
-    .bdrv_write                = raw_write,
+
+    .bdrv_read              = raw_read,
+    .bdrv_write             = raw_write,
+    .bdrv_co_flush_to_disk  = raw_flush,
+
     .bdrv_truncate     = raw_truncate,
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 
     .create_options = raw_create_options,
 };
@@ -349,11 +383,12 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
     create_flags = OPEN_EXISTING;
 
     overlapped = FILE_ATTRIBUTE_NORMAL;
-    if ((flags & BDRV_O_NOCACHE))
-        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
-    else if (!(flags & BDRV_O_CACHE_WB))
+    if (flags & BDRV_O_NOCACHE)
+        overlapped |= FILE_FLAG_NO_BUFFERING;
+    if (!(flags & BDRV_O_CACHE_WB))
         overlapped |= FILE_FLAG_WRITE_THROUGH;
-    s->hfile = CreateFile(filename, access_flags,
+    s->hfile = CreateFile(filename,
+                          access_flags,
                           FILE_SHARE_READ, NULL,
                           create_flags, overlapped, NULL);
     if (s->hfile == INVALID_HANDLE_VALUE) {
@@ -366,41 +401,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
     return 0;
 }
 
-#if 0
-/***********************************************/
-/* removable device additional commands */
-
-static int raw_is_inserted(BlockDriverState *bs)
-{
-    return 1;
-}
-
-static int raw_media_changed(BlockDriverState *bs)
-{
-    return -ENOTSUP;
-}
-
-static int raw_eject(BlockDriverState *bs, int eject_flag)
-{
-    DWORD ret_count;
-
-    if (s->type == FTYPE_FILE)
-        return -ENOTSUP;
-    if (eject_flag) {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
-                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
-    } else {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
-                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
-    }
-}
-
-static int raw_set_locked(BlockDriverState *bs, int locked)
-{
-    return -ENOTSUP;
-}
-#endif
-
 static int hdev_has_zero_init(BlockDriverState *bs)
 {
     return 0;
@@ -413,12 +413,15 @@ static BlockDriver bdrv_host_device = {
     .bdrv_probe_device = hdev_probe_device,
     .bdrv_file_open    = hdev_open,
     .bdrv_close                = raw_close,
-    .bdrv_flush                = raw_flush,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_read         = raw_read,
-    .bdrv_write                = raw_write,
+    .bdrv_read              = raw_read,
+    .bdrv_write             = raw_write,
+    .bdrv_co_flush_to_disk  = raw_flush,
+
     .bdrv_getlength    = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
 };
 
 static void bdrv_file_init(void)
index b0f72d6a62cb29c3d177c811c8f29deadbf43e4f..6098070d6537aaef4a78c36ccf141fe25f1d324b 100644 (file)
@@ -9,45 +9,25 @@ static int raw_open(BlockDriverState *bs, int flags)
     return 0;
 }
 
-static int raw_read(BlockDriverState *bs, int64_t sector_num,
-                    uint8_t *buf, int nb_sectors)
+static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
+                                     int nb_sectors, QEMUIOVector *qiov)
 {
-    return bdrv_read(bs->file, sector_num, buf, nb_sectors);
+    return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
 }
 
-static int raw_write(BlockDriverState *bs, int64_t sector_num,
-                     const uint8_t *buf, int nb_sectors)
+static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
+                                      int nb_sectors, QEMUIOVector *qiov)
 {
-    return bdrv_write(bs->file, sector_num, buf, nb_sectors);
-}
-
-static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
-    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-    BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
-}
-
-static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
-    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-    BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+    return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
 }
 
 static void raw_close(BlockDriverState *bs)
 {
 }
 
-static int raw_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
-static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
-    BlockDriverCompletionFunc *cb, void *opaque)
+static int coroutine_fn raw_co_flush(BlockDriverState *bs)
 {
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t raw_getlength(BlockDriverState *bs)
@@ -65,9 +45,10 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
    return 1; /* everything can be opened as raw image */
 }
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static int coroutine_fn raw_co_discard(BlockDriverState *bs,
+                                       int64_t sector_num, int nb_sectors)
 {
-    return bdrv_discard(bs->file, sector_num, nb_sectors);
+    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
 }
 
 static int raw_is_inserted(BlockDriverState *bs)
@@ -75,15 +56,19 @@ static int raw_is_inserted(BlockDriverState *bs)
     return bdrv_is_inserted(bs->file);
 }
 
-static int raw_eject(BlockDriverState *bs, int eject_flag)
+static int raw_media_changed(BlockDriverState *bs)
 {
-    return bdrv_eject(bs->file, eject_flag);
+    return bdrv_media_changed(bs->file);
 }
 
-static int raw_set_locked(BlockDriverState *bs, int locked)
+static void raw_eject(BlockDriverState *bs, int eject_flag)
 {
-    bdrv_set_locked(bs->file, locked);
-    return 0;
+    bdrv_eject(bs->file, eject_flag);
+}
+
+static void raw_lock_medium(BlockDriverState *bs, bool locked)
+{
+    bdrv_lock_medium(bs->file, locked);
 }
 
 static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
@@ -120,26 +105,26 @@ static int raw_has_zero_init(BlockDriverState *bs)
 static BlockDriver bdrv_raw = {
     .format_name        = "raw",
 
-    /* It's really 0, but we need to make qemu_malloc() happy */
+    /* It's really 0, but we need to make g_malloc() happy */
     .instance_size      = 1,
 
     .bdrv_open          = raw_open,
     .bdrv_close         = raw_close,
-    .bdrv_read          = raw_read,
-    .bdrv_write         = raw_write,
-    .bdrv_flush         = raw_flush,
+
+    .bdrv_co_readv          = raw_co_readv,
+    .bdrv_co_writev         = raw_co_writev,
+    .bdrv_co_flush_to_disk  = raw_co_flush,
+    .bdrv_co_discard        = raw_co_discard,
+
     .bdrv_probe         = raw_probe,
     .bdrv_getlength     = raw_getlength,
     .bdrv_truncate      = raw_truncate,
 
-    .bdrv_aio_readv     = raw_aio_readv,
-    .bdrv_aio_writev    = raw_aio_writev,
-    .bdrv_aio_flush     = raw_aio_flush,
-    .bdrv_discard       = raw_discard,
-
     .bdrv_is_inserted   = raw_is_inserted,
+    .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
-    .bdrv_set_locked    = raw_set_locked,
+    .bdrv_lock_medium   = raw_lock_medium,
+
     .bdrv_ioctl         = raw_ioctl,
     .bdrv_aio_ioctl     = raw_aio_ioctl,
 
index 249a590c98ba5ca78ba4b5f942cc7ef24652fd02..54a6961737f760166ffc64233fa81653aa628381 100644 (file)
@@ -1,45 +1,56 @@
 /*
  * QEMU Block driver for RADOS (Ceph)
  *
- * Copyright (C) 2010 Christian Brunner <chb@muc.de>
+ * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
+ *                         Josh Durgin <josh.durgin@dreamhost.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
  */
 
+#include <inttypes.h>
+
 #include "qemu-common.h"
 #include "qemu-error.h"
-
-#include "rbd_types.h"
 #include "block_int.h"
 
-#include <rados/librados.h>
-
-
+#include <rbd/librbd.h>
 
 /*
  * When specifying the image filename use:
  *
- * rbd:poolname/devicename
+ * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
+ *
+ * poolname must be the name of an existing rados pool.
  *
- * poolname must be the name of an existing rados pool
+ * devicename is the name of the rbd image.
  *
- * devicename is the basename for all objects used to
- * emulate the raw device.
+ * Each option given is used to configure rados, and may be any valid
+ * Ceph option, "id", or "conf".
  *
- * Metadata information (image size, ...) is stored in an
- * object with the name "devicename.rbd".
+ * The "id" option indicates what user we should authenticate as to
+ * the Ceph cluster.  If it is excluded we will use the Ceph default
+ * (normally 'admin').
  *
- * The raw device is split into 4MB sized objects by default.
- * The sequencenumber is encoded in a 12 byte long hex-string,
- * and is attached to the devicename, separated by a dot.
- * e.g. "devicename.1234567890ab"
+ * The "conf" option specifies a Ceph configuration file to read.  If
+ * it is not specified, we will read from the default Ceph locations
+ * (e.g., /etc/ceph/ceph.conf).  To avoid reading _any_ configuration
+ * file, specify conf=/dev/null.
  *
+ * Configuration values containing :, @, or = can be escaped with a
+ * leading "\".
  */
 
 #define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
 
+#define RBD_MAX_CONF_NAME_SIZE 128
+#define RBD_MAX_CONF_VAL_SIZE 512
+#define RBD_MAX_CONF_SIZE 1024
+#define RBD_MAX_POOL_NAME_SIZE 128
+#define RBD_MAX_SNAP_NAME_SIZE 128
+#define RBD_MAX_SNAPS 100
+
 typedef struct RBDAIOCB {
     BlockDriverAIOCB common;
     QEMUBH *bh;
@@ -48,7 +59,6 @@ typedef struct RBDAIOCB {
     char *bounce;
     int write;
     int64_t sector_num;
-    int aiocnt;
     int error;
     struct BDRVRBDState *s;
     int cancelled;
@@ -59,7 +69,7 @@ typedef struct RADOSCB {
     RBDAIOCB *acb;
     struct BDRVRBDState *s;
     int done;
-    int64_t segsize;
+    int64_t size;
     char *buf;
     int ret;
 } RADOSCB;
@@ -69,25 +79,22 @@ typedef struct RADOSCB {
 
 typedef struct BDRVRBDState {
     int fds[2];
-    rados_pool_t pool;
-    rados_pool_t header_pool;
-    char name[RBD_MAX_OBJ_NAME_SIZE];
-    char block_name[RBD_MAX_BLOCK_NAME_SIZE];
-    uint64_t size;
-    uint64_t objsize;
+    rados_t cluster;
+    rados_ioctx_t io_ctx;
+    rbd_image_t image;
+    char name[RBD_MAX_IMAGE_NAME_SIZE];
     int qemu_aio_count;
+    char *snap;
     int event_reader_pos;
     RADOSCB *event_rcb;
 } BDRVRBDState;
 
-typedef struct rbd_obj_header_ondisk RbdHeader1;
-
 static void rbd_aio_bh_cb(void *opaque);
 
-static int rbd_next_tok(char *dst, int dst_len,
-                        char *src, char delim,
-                        const char *name,
-                        char **p)
+static int qemu_rbd_next_tok(char *dst, int dst_len,
+                             char *src, char delim,
+                             const char *name,
+                             char **p)
 {
     int l;
     char *end;
@@ -95,8 +102,15 @@ static int rbd_next_tok(char *dst, int dst_len,
     *p = NULL;
 
     if (delim != '\0') {
-        end = strchr(src, delim);
-        if (end) {
+        for (end = src; *end; ++end) {
+            if (*end == delim) {
+                break;
+            }
+            if (*end == '\\' && end[1] != '\0') {
+                end++;
+            }
+        }
+        if (*end == delim) {
             *p = end + 1;
             *end = '\0';
         }
@@ -115,10 +129,24 @@ static int rbd_next_tok(char *dst, int dst_len,
     return 0;
 }
 
-static int rbd_parsename(const char *filename,
-                         char *pool, int pool_len,
-                         char *snap, int snap_len,
-                         char *name, int name_len)
+static void qemu_rbd_unescape(char *src)
+{
+    char *p;
+
+    for (p = src; *src; ++src, ++p) {
+        if (*src == '\\' && src[1] != '\0') {
+            src++;
+        }
+        *p = *src;
+    }
+    *p = '\0';
+}
+
+static int qemu_rbd_parsename(const char *filename,
+                              char *pool, int pool_len,
+                              char *snap, int snap_len,
+                              char *name, int name_len,
+                              char *conf, int conf_len)
 {
     const char *start;
     char *p, *buf;
@@ -128,139 +156,142 @@ static int rbd_parsename(const char *filename,
         return -EINVAL;
     }
 
-    buf = qemu_strdup(start);
+    buf = g_strdup(start);
     p = buf;
+    *snap = '\0';
+    *conf = '\0';
 
-    ret = rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+    ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
     if (ret < 0 || !p) {
         ret = -EINVAL;
         goto done;
     }
-    ret = rbd_next_tok(name, name_len, p, '@', "object name", &p);
-    if (ret < 0) {
-        goto done;
+    qemu_rbd_unescape(pool);
+
+    if (strchr(p, '@')) {
+        ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
+        if (ret < 0) {
+            goto done;
+        }
+        ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+        qemu_rbd_unescape(snap);
+    } else {
+        ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
     }
-    if (!p) {
-        *snap = '\0';
+    qemu_rbd_unescape(name);
+    if (ret < 0 || !p) {
         goto done;
     }
 
-    ret = rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
+    ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
 
 done:
-    qemu_free(buf);
+    g_free(buf);
     return ret;
 }
 
-static int create_tmap_op(uint8_t op, const char *name, char **tmap_desc)
+static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
 {
-    uint32_t len = strlen(name);
-    uint32_t len_le = cpu_to_le32(len);
-    /* total_len = encoding op + name + empty buffer */
-    uint32_t total_len = 1 + (sizeof(uint32_t) + len) + sizeof(uint32_t);
-    uint8_t *desc = NULL;
-
-    desc = qemu_malloc(total_len);
-
-    *tmap_desc = (char *)desc;
-
-    *desc = op;
-    desc++;
-    memcpy(desc, &len_le, sizeof(len_le));
-    desc += sizeof(len_le);
-    memcpy(desc, name, len);
-    desc += len;
-    len = 0; /* no need for endian conversion for 0 */
-    memcpy(desc, &len, sizeof(len));
-    desc += sizeof(len);
-
-    return (char *)desc - *tmap_desc;
-}
+    const char *p = conf;
 
-static void free_tmap_op(char *tmap_desc)
-{
-    qemu_free(tmap_desc);
-}
+    while (*p) {
+        int len;
+        const char *end = strchr(p, ':');
 
-static int rbd_register_image(rados_pool_t pool, const char *name)
-{
-    char *tmap_desc;
-    const char *dir = RBD_DIRECTORY;
-    int ret;
+        if (end) {
+            len = end - p;
+        } else {
+            len = strlen(p);
+        }
 
-    ret = create_tmap_op(CEPH_OSD_TMAP_SET, name, &tmap_desc);
-    if (ret < 0) {
-        return ret;
+        if (strncmp(p, "id=", 3) == 0) {
+            len -= 3;
+            strncpy(clientname, p + 3, len);
+            clientname[len] = '\0';
+            return clientname;
+        }
+        if (end == NULL) {
+            break;
+        }
+        p = end + 1;
     }
-
-    ret = rados_tmap_update(pool, dir, tmap_desc, ret);
-    free_tmap_op(tmap_desc);
-
-    return ret;
+    return NULL;
 }
 
-static int touch_rbd_info(rados_pool_t pool, const char *info_oid)
+static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 {
-    int r = rados_write(pool, info_oid, 0, NULL, 0);
-    if (r < 0) {
-        return r;
-    }
-    return 0;
-}
+    char *p, *buf;
+    char name[RBD_MAX_CONF_NAME_SIZE];
+    char value[RBD_MAX_CONF_VAL_SIZE];
+    int ret = 0;
 
-static int rbd_assign_bid(rados_pool_t pool, uint64_t *id)
-{
-    uint64_t out[1];
-    const char *info_oid = RBD_INFO;
+    buf = g_strdup(conf);
+    p = buf;
 
-    *id = 0;
+    while (p) {
+        ret = qemu_rbd_next_tok(name, sizeof(name), p,
+                                '=', "conf option name", &p);
+        if (ret < 0) {
+            break;
+        }
+        qemu_rbd_unescape(name);
 
-    int r = touch_rbd_info(pool, info_oid);
-    if (r < 0) {
-        return r;
-    }
+        if (!p) {
+            error_report("conf option %s has no value", name);
+            ret = -EINVAL;
+            break;
+        }
 
-    r = rados_exec(pool, info_oid, "rbd", "assign_bid", NULL,
-                   0, (char *)out, sizeof(out));
-    if (r < 0) {
-        return r;
-    }
+        ret = qemu_rbd_next_tok(value, sizeof(value), p,
+                                ':', "conf option value", &p);
+        if (ret < 0) {
+            break;
+        }
+        qemu_rbd_unescape(value);
 
-    le64_to_cpus(out);
-    *id = out[0];
+        if (strcmp(name, "conf") == 0) {
+            ret = rados_conf_read_file(cluster, value);
+            if (ret < 0) {
+                error_report("error reading conf file %s", value);
+                break;
+            }
+        } else if (strcmp(name, "id") == 0) {
+            /* ignore, this is parsed by qemu_rbd_parse_clientname() */
+        } else {
+            ret = rados_conf_set(cluster, name, value);
+            if (ret < 0) {
+                error_report("invalid conf option %s", name);
+                ret = -EINVAL;
+                break;
+            }
+        }
+    }
 
-    return 0;
+    g_free(buf);
+    return ret;
 }
 
-static int rbd_create(const char *filename, QEMUOptionParameter *options)
+static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
 {
     int64_t bytes = 0;
     int64_t objsize;
-    uint64_t size;
-    time_t mtime;
-    uint8_t obj_order = RBD_DEFAULT_OBJ_ORDER;
-    char pool[RBD_MAX_SEG_NAME_SIZE];
-    char n[RBD_MAX_SEG_NAME_SIZE];
-    char name[RBD_MAX_OBJ_NAME_SIZE];
-    char snap_buf[RBD_MAX_SEG_NAME_SIZE];
-    char *snap = NULL;
-    RbdHeader1 header;
-    rados_pool_t p;
-    uint64_t bid;
-    uint32_t hi, lo;
+    int obj_order = 0;
+    char pool[RBD_MAX_POOL_NAME_SIZE];
+    char name[RBD_MAX_IMAGE_NAME_SIZE];
+    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+    char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
+    rados_t cluster;
+    rados_ioctx_t io_ctx;
     int ret;
 
-    if (rbd_parsename(filename,
-                      pool, sizeof(pool),
-                      snap_buf, sizeof(snap_buf),
-                      name, sizeof(name)) < 0) {
+    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+                           snap_buf, sizeof(snap_buf),
+                           name, sizeof(name),
+                           conf, sizeof(conf)) < 0) {
         return -EINVAL;
     }
-    if (snap_buf[0] != '\0') {
-        snap = snap_buf;
-    }
-
-    snprintf(n, sizeof(n), "%s%s", name, RBD_SUFFIX);
 
     /* Read out options */
     while (options && options->name) {
@@ -277,82 +308,62 @@ static int rbd_create(const char *filename, QEMUOptionParameter *options)
                     error_report("obj size too small");
                     return -EINVAL;
                 }
-               obj_order = ffs(objsize) - 1;
+                obj_order = ffs(objsize) - 1;
             }
         }
         options++;
     }
 
-    memset(&header, 0, sizeof(header));
-    pstrcpy(header.text, sizeof(header.text), RBD_HEADER_TEXT);
-    pstrcpy(header.signature, sizeof(header.signature), RBD_HEADER_SIGNATURE);
-    pstrcpy(header.version, sizeof(header.version), RBD_HEADER_VERSION);
-    header.image_size = cpu_to_le64(bytes);
-    header.options.order = obj_order;
-    header.options.crypt_type = RBD_CRYPT_NONE;
-    header.options.comp_type = RBD_COMP_NONE;
-    header.snap_seq = 0;
-    header.snap_count = 0;
-
-    if (rados_initialize(0, NULL) < 0) {
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    if (rados_create(&cluster, clientname) < 0) {
         error_report("error initializing");
         return -EIO;
     }
 
-    if (rados_open_pool(pool, &p)) {
-        error_report("error opening pool %s", pool);
-        rados_deinitialize();
-        return -EIO;
+    if (strstr(conf, "conf=") == NULL) {
+        /* try default location, but ignore failure */
+        rados_conf_read_file(cluster, NULL);
     }
 
-    /* check for existing rbd header file */
-    ret = rados_stat(p, n, &size, &mtime);
-    if (ret == 0) {
-        ret=-EEXIST;
-        goto done;
+    if (conf[0] != '\0' &&
+        qemu_rbd_set_conf(cluster, conf) < 0) {
+        error_report("error setting config options");
+        rados_shutdown(cluster);
+        return -EIO;
     }
 
-    ret = rbd_assign_bid(p, &bid);
-    if (ret < 0) {
-        error_report("failed assigning block id");
-        rados_deinitialize();
+    if (rados_connect(cluster) < 0) {
+        error_report("error connecting");
+        rados_shutdown(cluster);
         return -EIO;
     }
-    hi = bid >> 32;
-    lo = bid & 0xFFFFFFFF;
-    snprintf(header.block_name, sizeof(header.block_name), "rb.%x.%x", hi, lo);
 
-    /* create header file */
-    ret = rados_write(p, n, 0, (const char *)&header, sizeof(header));
-    if (ret < 0) {
-        goto done;
+    if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
+        error_report("error opening pool %s", pool);
+        rados_shutdown(cluster);
+        return -EIO;
     }
 
-    ret = rbd_register_image(p, name);
-done:
-    rados_close_pool(p);
-    rados_deinitialize();
+    ret = rbd_create(io_ctx, name, bytes, &obj_order);
+    rados_ioctx_destroy(io_ctx);
+    rados_shutdown(cluster);
 
     return ret;
 }
 
 /*
- * This aio completion is being called from rbd_aio_event_reader() and
- * runs in qemu context. It schedules a bh, but just in case the aio
+ * This aio completion is being called from qemu_rbd_aio_event_reader()
+ * and runs in qemu context. It schedules a bh, but just in case the aio
  * was not cancelled before.
  */
-static void rbd_complete_aio(RADOSCB *rcb)
+static void qemu_rbd_complete_aio(RADOSCB *rcb)
 {
     RBDAIOCB *acb = rcb->acb;
     int64_t r;
 
-    acb->aiocnt--;
-
     if (acb->cancelled) {
-        if (!acb->aiocnt) {
-            qemu_vfree(acb->bounce);
-            qemu_aio_release(acb);
-        }
+        qemu_vfree(acb->bounce);
+        qemu_aio_release(acb);
         goto done;
     }
 
@@ -363,41 +374,34 @@ static void rbd_complete_aio(RADOSCB *rcb)
             acb->ret = r;
             acb->error = 1;
         } else if (!acb->error) {
-            acb->ret += rcb->segsize;
+            acb->ret = rcb->size;
         }
     } else {
-        if (r == -ENOENT) {
-            memset(rcb->buf, 0, rcb->segsize);
-            if (!acb->error) {
-                acb->ret += rcb->segsize;
-            }
-        } else if (r < 0) {
-           memset(rcb->buf, 0, rcb->segsize);
+        if (r < 0) {
+            memset(rcb->buf, 0, rcb->size);
             acb->ret = r;
             acb->error = 1;
-        } else if (r < rcb->segsize) {
-            memset(rcb->buf + r, 0, rcb->segsize - r);
+        } else if (r < rcb->size) {
+            memset(rcb->buf + r, 0, rcb->size - r);
             if (!acb->error) {
-                acb->ret += rcb->segsize;
+                acb->ret = rcb->size;
             }
         } else if (!acb->error) {
-            acb->ret += r;
+            acb->ret = r;
         }
     }
     /* Note that acb->bh can be NULL in case where the aio was cancelled */
-    if (!acb->aiocnt) {
-        acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
-        qemu_bh_schedule(acb->bh);
-    }
+    acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
+    qemu_bh_schedule(acb->bh);
 done:
-    qemu_free(rcb);
+    g_free(rcb);
 }
 
 /*
  * aio fd read handler. It runs in the qemu context and calls the
  * completion handling of completed rados aio operations.
  */
-static void rbd_aio_event_reader(void *opaque)
+static void qemu_rbd_aio_event_reader(void *opaque)
 {
     BDRVRBDState *s = opaque;
 
@@ -407,182 +411,87 @@ static void rbd_aio_event_reader(void *opaque)
         char *p = (char *)&s->event_rcb;
 
         /* now read the rcb pointer that was sent from a non qemu thread */
-        if ((ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
-                        sizeof(s->event_rcb) - s->event_reader_pos)) > 0) {
-            if (ret > 0) {
-                s->event_reader_pos += ret;
-                if (s->event_reader_pos == sizeof(s->event_rcb)) {
-                    s->event_reader_pos = 0;
-                    rbd_complete_aio(s->event_rcb);
-                    s->qemu_aio_count --;
-                }
+        ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
+                   sizeof(s->event_rcb) - s->event_reader_pos);
+        if (ret > 0) {
+            s->event_reader_pos += ret;
+            if (s->event_reader_pos == sizeof(s->event_rcb)) {
+                s->event_reader_pos = 0;
+                qemu_rbd_complete_aio(s->event_rcb);
+                s->qemu_aio_count--;
             }
         }
     } while (ret < 0 && errno == EINTR);
 }
 
-static int rbd_aio_flush_cb(void *opaque)
+static int qemu_rbd_aio_flush_cb(void *opaque)
 {
     BDRVRBDState *s = opaque;
 
     return (s->qemu_aio_count > 0);
 }
 
-
-static int rbd_set_snapc(rados_pool_t pool, const char *snap, RbdHeader1 *header)
-{
-    uint32_t snap_count = le32_to_cpu(header->snap_count);
-    rados_snap_t *snaps = NULL;
-    rados_snap_t seq;
-    uint32_t i;
-    uint64_t snap_names_len = le64_to_cpu(header->snap_names_len);
-    int r;
-    rados_snap_t snapid = 0;
-
-    if (snap_count) {
-        const char *header_snap = (const char *)&header->snaps[snap_count];
-        const char *end = header_snap + snap_names_len;
-        snaps = qemu_malloc(sizeof(rados_snap_t) * header->snap_count);
-
-        for (i=0; i < snap_count; i++) {
-            snaps[i] = le64_to_cpu(header->snaps[i].id);
-
-            if (snap && strcmp(snap, header_snap) == 0) {
-                snapid = snaps[i];
-            }
-
-            header_snap += strlen(header_snap) + 1;
-            if (header_snap > end) {
-                error_report("bad header, snapshot list broken");
-            }
-        }
-    }
-
-    if (snap && !snapid) {
-        error_report("snapshot not found");
-        qemu_free(snaps);
-        return -ENOENT;
-    }
-    seq = le32_to_cpu(header->snap_seq);
-
-    r = rados_set_snap_context(pool, seq, snaps, snap_count);
-
-    rados_set_snap(pool, snapid);
-
-    qemu_free(snaps);
-
-    return r;
-}
-
-#define BUF_READ_START_LEN    4096
-
-static int rbd_read_header(BDRVRBDState *s, char **hbuf)
-{
-    char *buf = NULL;
-    char n[RBD_MAX_SEG_NAME_SIZE];
-    uint64_t len = BUF_READ_START_LEN;
-    int r;
-
-    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-
-    buf = qemu_malloc(len);
-
-    r = rados_read(s->header_pool, n, 0, buf, len);
-    if (r < 0) {
-        goto failed;
-    }
-
-    if (r < len) {
-        goto done;
-    }
-
-    qemu_free(buf);
-    buf = qemu_malloc(len);
-
-    r = rados_stat(s->header_pool, n, &len, NULL);
-    if (r < 0) {
-        goto failed;
-    }
-
-    r = rados_read(s->header_pool, n, 0, buf, len);
-    if (r < 0) {
-        goto failed;
-    }
-
-done:
-    *hbuf = buf;
-    return 0;
-
-failed:
-    qemu_free(buf);
-    return r;
-}
-
-static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
+static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRBDState *s = bs->opaque;
-    RbdHeader1 *header;
-    char pool[RBD_MAX_SEG_NAME_SIZE];
-    char snap_buf[RBD_MAX_SEG_NAME_SIZE];
-    char *snap = NULL;
-    char *hbuf = NULL;
+    char pool[RBD_MAX_POOL_NAME_SIZE];
+    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+    char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
     int r;
 
-    if (rbd_parsename(filename, pool, sizeof(pool),
-                      snap_buf, sizeof(snap_buf),
-                      s->name, sizeof(s->name)) < 0) {
+    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+                           snap_buf, sizeof(snap_buf),
+                           s->name, sizeof(s->name),
+                           conf, sizeof(conf)) < 0) {
         return -EINVAL;
     }
-    if (snap_buf[0] != '\0') {
-        snap = snap_buf;
-    }
 
-    if ((r = rados_initialize(0, NULL)) < 0) {
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    r = rados_create(&s->cluster, clientname);
+    if (r < 0) {
         error_report("error initializing");
         return r;
     }
 
-    if ((r = rados_open_pool(pool, &s->pool))) {
-        error_report("error opening pool %s", pool);
-        rados_deinitialize();
-        return r;
+    s->snap = NULL;
+    if (snap_buf[0] != '\0') {
+        s->snap = g_strdup(snap_buf);
     }
 
-    if ((r = rados_open_pool(pool, &s->header_pool))) {
-        error_report("error opening pool %s", pool);
-        rados_deinitialize();
-        return r;
+    if (strstr(conf, "conf=") == NULL) {
+        /* try default location, but ignore failure */
+        rados_conf_read_file(s->cluster, NULL);
     }
 
-    if ((r = rbd_read_header(s, &hbuf)) < 0) {
-        error_report("error reading header from %s", s->name);
-        goto failed;
+    if (conf[0] != '\0') {
+        r = qemu_rbd_set_conf(s->cluster, conf);
+        if (r < 0) {
+            error_report("error setting config options");
+            goto failed_shutdown;
+        }
     }
 
-    if (memcmp(hbuf + 64, RBD_HEADER_SIGNATURE, 4)) {
-        error_report("Invalid header signature");
-        r = -EMEDIUMTYPE;
-        goto failed;
+    r = rados_connect(s->cluster);
+    if (r < 0) {
+        error_report("error connecting");
+        goto failed_shutdown;
     }
 
-    if (memcmp(hbuf + 68, RBD_HEADER_VERSION, 8)) {
-        error_report("Unknown image version");
-        r = -EMEDIUMTYPE;
-        goto failed;
+    r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
+    if (r < 0) {
+        error_report("error opening pool %s", pool);
+        goto failed_shutdown;
     }
 
-    header = (RbdHeader1 *) hbuf;
-    s->size = le64_to_cpu(header->image_size);
-    s->objsize = 1ULL << header->options.order;
-    memcpy(s->block_name, header->block_name, sizeof(header->block_name));
-
-    r = rbd_set_snapc(s->pool, snap, header);
+    r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
     if (r < 0) {
-        error_report("failed setting snap context: %s", strerror(-r));
-        goto failed;
+        error_report("error reading header from %s", s->name);
+        goto failed_open;
     }
 
-    bs->read_only = (snap != NULL);
+    bs->read_only = (s->snap != NULL);
 
     s->event_reader_pos = 0;
     r = qemu_pipe(s->fds);
@@ -592,23 +501,23 @@ static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
     }
     fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
     fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
-    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], rbd_aio_event_reader, NULL,
-        rbd_aio_flush_cb, NULL, s);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
+                            NULL, qemu_rbd_aio_flush_cb, NULL, s);
 
-    qemu_free(hbuf);
 
     return 0;
 
 failed:
-    qemu_free(hbuf);
-
-    rados_close_pool(s->header_pool);
-    rados_close_pool(s->pool);
-    rados_deinitialize();
+    rbd_close(s->image);
+failed_open:
+    rados_ioctx_destroy(s->io_ctx);
+failed_shutdown:
+    rados_shutdown(s->cluster);
+    g_free(s->snap);
     return r;
 }
 
-static void rbd_close(BlockDriverState *bs)
+static void qemu_rbd_close(BlockDriverState *bs)
 {
     BDRVRBDState *s = bs->opaque;
 
@@ -617,16 +526,17 @@ static void rbd_close(BlockDriverState *bs)
     qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
         NULL);
 
-    rados_close_pool(s->header_pool);
-    rados_close_pool(s->pool);
-    rados_deinitialize();
+    rbd_close(s->image);
+    rados_ioctx_destroy(s->io_ctx);
+    g_free(s->snap);
+    rados_shutdown(s->cluster);
 }
 
 /*
  * Cancel aio. Since we don't reference acb in a non qemu threads,
  * it is safe to access it here.
  */
-static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
+static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     RBDAIOCB *acb = (RBDAIOCB *) blockacb;
     acb->cancelled = 1;
@@ -634,39 +544,28 @@ static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
 
 static AIOPool rbd_aio_pool = {
     .aiocb_size = sizeof(RBDAIOCB),
-    .cancel = rbd_aio_cancel,
+    .cancel = qemu_rbd_aio_cancel,
 };
 
-/*
- * This is the callback function for rados_aio_read and _write
- *
- * Note: this function is being called from a non qemu thread so
- * we need to be careful about what we do here. Generally we only
- * write to the block notification pipe, and do the rest of the
- * io completion handling from rbd_aio_event_reader() which
- * runs in a qemu context.
- */
-static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
+static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
 {
-    int ret;
-    rcb->ret = rados_aio_get_return_value(c);
-    rados_aio_release(c);
+    int ret = 0;
     while (1) {
         fd_set wfd;
-        int fd = rcb->s->fds[RBD_FD_WRITE];
+        int fd = s->fds[RBD_FD_WRITE];
 
-        /* send the rcb pointer to the qemu thread that is responsible
-           for the aio completion. Must do it in a qemu thread context */
+        /* send the op pointer to the qemu thread that is responsible
+           for the aio/op completion. Must do it in a qemu thread context */
         ret = write(fd, (void *)&rcb, sizeof(rcb));
         if (ret >= 0) {
             break;
         }
         if (errno == EINTR) {
             continue;
-       }
+        }
         if (errno != EAGAIN) {
             break;
-       }
+        }
 
         FD_ZERO(&wfd);
         FD_SET(fd, &wfd);
@@ -675,13 +574,31 @@ static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
         } while (ret < 0 && errno == EINTR);
     }
 
+    return ret;
+}
+
+/*
+ * This is the callback function for rbd_aio_read and _write
+ *
+ * Note: this function is being called from a non qemu thread so
+ * we need to be careful about what we do here. Generally we only
+ * write to the block notification pipe, and do the rest of the
+ * io completion handling from qemu_rbd_aio_event_reader() which
+ * runs in a qemu context.
+ */
+static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
+{
+    int ret;
+    rcb->ret = rbd_aio_get_return_value(c);
+    rbd_aio_release(c);
+    ret = qemu_rbd_send_pipe(rcb->s, rcb);
     if (ret < 0) {
-        error_report("failed writing to acb->s->fds\n");
-        qemu_free(rcb);
+        error_report("failed writing to acb->s->fds");
+        g_free(rcb);
     }
 }
 
-/* Callback when all queued rados_aio requests are complete */
+/* Callback when all queued rbd_aio requests are complete */
 
 static void rbd_aio_bh_cb(void *opaque)
 {
@@ -707,19 +624,20 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
 {
     RBDAIOCB *acb;
     RADOSCB *rcb;
-    rados_completion_t c;
-    char n[RBD_MAX_SEG_NAME_SIZE];
-    int64_t segnr, segoffs, segsize, last_segnr;
+    rbd_completion_t c;
     int64_t off, size;
     char *buf;
+    int r;
 
     BDRVRBDState *s = bs->opaque;
 
     acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
+    if (!acb) {
+        return NULL;
+    }
     acb->write = write;
     acb->qiov = qiov;
     acb->bounce = qemu_blockalign(bs, qiov->size);
-    acb->aiocnt = 0;
     acb->ret = 0;
     acb->error = 0;
     acb->s = s;
@@ -734,292 +652,187 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
 
     off = sector_num * BDRV_SECTOR_SIZE;
     size = nb_sectors * BDRV_SECTOR_SIZE;
-    segnr = off / s->objsize;
-    segoffs = off % s->objsize;
-    segsize = s->objsize - segoffs;
-
-    last_segnr = ((off + size - 1) / s->objsize);
-    acb->aiocnt = (last_segnr - segnr) + 1;
 
-    s->qemu_aio_count += acb->aiocnt; /* All the RADOSCB */
+    s->qemu_aio_count++; /* All the RADOSCB */
 
-    while (size > 0) {
-        if (size < segsize) {
-            segsize = size;
-        }
+    rcb = g_malloc(sizeof(RADOSCB));
+    rcb->done = 0;
+    rcb->acb = acb;
+    rcb->buf = buf;
+    rcb->s = acb->s;
+    rcb->size = size;
+    r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+    if (r < 0) {
+        goto failed;
+    }
 
-        snprintf(n, sizeof(n), "%s.%012" PRIx64, s->block_name,
-                 segnr);
-
-        rcb = qemu_malloc(sizeof(RADOSCB));
-        rcb->done = 0;
-        rcb->acb = acb;
-        rcb->segsize = segsize;
-        rcb->buf = buf;
-        rcb->s = acb->s;
-
-        if (write) {
-            rados_aio_create_completion(rcb, NULL,
-                                        (rados_callback_t) rbd_finish_aiocb,
-                                        &c);
-            rados_aio_write(s->pool, n, segoffs, buf, segsize, c);
-        } else {
-            rados_aio_create_completion(rcb,
-                                        (rados_callback_t) rbd_finish_aiocb,
-                                        NULL, &c);
-            rados_aio_read(s->pool, n, segoffs, buf, segsize, c);
-        }
+    if (write) {
+        r = rbd_aio_write(s->image, off, size, buf, c);
+    } else {
+        r = rbd_aio_read(s->image, off, size, buf, c);
+    }
 
-        buf += segsize;
-        size -= segsize;
-        segoffs = 0;
-        segsize = s->objsize;
-        segnr++;
+    if (r < 0) {
+        goto failed;
     }
 
     return &acb->common;
+
+failed:
+    g_free(rcb);
+    s->qemu_aio_count--;
+    qemu_aio_release(acb);
+    return NULL;
 }
 
-static BlockDriverAIOCB *rbd_aio_readv(BlockDriverState * bs,
-                                       int64_t sector_num, QEMUIOVector * qiov,
-                                       int nb_sectors,
-                                       BlockDriverCompletionFunc * cb,
-                                       void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov,
+                                            int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
 {
     return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
 }
 
-static BlockDriverAIOCB *rbd_aio_writev(BlockDriverState * bs,
-                                        int64_t sector_num, QEMUIOVector * qiov,
-                                        int nb_sectors,
-                                        BlockDriverCompletionFunc * cb,
-                                        void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             QEMUIOVector *qiov,
+                                             int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
 {
     return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
-static int rbd_getinfo(BlockDriverState * bs, BlockDriverInfo * bdi)
+static int qemu_rbd_co_flush(BlockDriverState *bs)
 {
+#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
+    /* rbd_flush added in 0.1.1 */
     BDRVRBDState *s = bs->opaque;
-    bdi->cluster_size = s->objsize;
+    return rbd_flush(s->image);
+#else
     return 0;
+#endif
 }
 
-static int64_t rbd_getlength(BlockDriverState * bs)
-{
-    BDRVRBDState *s = bs->opaque;
-
-    return s->size;
-}
-
-static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BDRVRBDState *s = bs->opaque;
-    char inbuf[512], outbuf[128];
-    uint64_t snap_id;
+    rbd_image_info_t info;
     int r;
-    char *p = inbuf;
-    char *end = inbuf + sizeof(inbuf);
-    char n[RBD_MAX_SEG_NAME_SIZE];
-    char *hbuf = NULL;
-    RbdHeader1 *header;
-
-    if (sn_info->name[0] == '\0') {
-        return -EINVAL; /* we need a name for rbd snapshots */
-    }
-
-    /*
-     * rbd snapshots are using the name as the user controlled unique identifier
-     * we can't use the rbd snapid for that purpose, as it can't be set
-     */
-    if (sn_info->id_str[0] != '\0' &&
-        strcmp(sn_info->id_str, sn_info->name) != 0) {
-        return -EINVAL;
-    }
-
-    if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
-        return -ERANGE;
-    }
 
-    r = rados_selfmanaged_snap_create(s->header_pool, &snap_id);
+    r = rbd_stat(s->image, &info, sizeof(info));
     if (r < 0) {
-        error_report("failed to create snap id: %s", strerror(-r));
         return r;
     }
 
-    *(uint32_t *)p = strlen(sn_info->name);
-    cpu_to_le32s((uint32_t *)p);
-    p += sizeof(uint32_t);
-    strncpy(p, sn_info->name, end - p);
-    p += strlen(p);
-    if (p + sizeof(snap_id) > end) {
-        error_report("invalid input parameter");
-        return -EINVAL;
-    }
-
-    *(uint64_t *)p = snap_id;
-    cpu_to_le64s((uint64_t *)p);
+    bdi->cluster_size = info.obj_size;
+    return 0;
+}
 
-    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
+static int64_t qemu_rbd_getlength(BlockDriverState *bs)
+{
+    BDRVRBDState *s = bs->opaque;
+    rbd_image_info_t info;
+    int r;
 
-    r = rados_exec(s->header_pool, n, "rbd", "snap_add", inbuf,
-                   sizeof(inbuf), outbuf, sizeof(outbuf));
+    r = rbd_stat(s->image, &info, sizeof(info));
     if (r < 0) {
-        error_report("rbd.snap_add execution failed failed: %s", strerror(-r));
         return r;
     }
 
-    sprintf(sn_info->id_str, "%s", sn_info->name);
+    return info.size;
+}
 
-    r = rbd_read_header(s, &hbuf);
-    if (r < 0) {
-        error_report("failed reading header: %s", strerror(-r));
-        return r;
-    }
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRBDState *s = bs->opaque;
+    int r;
 
-    header = (RbdHeader1 *) hbuf;
-    r = rbd_set_snapc(s->pool, sn_info->name, header);
+    r = rbd_resize(s->image, offset);
     if (r < 0) {
-        error_report("failed setting snap context: %s", strerror(-r));
-        goto failed;
+        return r;
     }
 
     return 0;
-
-failed:
-    qemu_free(header);
-    return r;
 }
 
-static int decode32(char **p, const char *end, uint32_t *v)
+static int qemu_rbd_snap_create(BlockDriverState *bs,
+                                QEMUSnapshotInfo *sn_info)
 {
-    if (*p + 4 > end) {
-       return -ERANGE;
+    BDRVRBDState *s = bs->opaque;
+    int r;
+
+    if (sn_info->name[0] == '\0') {
+        return -EINVAL; /* we need a name for rbd snapshots */
     }
 
-    *v = *(uint32_t *)(*p);
-    le32_to_cpus(v);
-    *p += 4;
-    return 0;
-}
+    /*
+     * rbd snapshots are using the name as the user controlled unique identifier
+     * we can't use the rbd snapid for that purpose, as it can't be set
+     */
+    if (sn_info->id_str[0] != '\0' &&
+        strcmp(sn_info->id_str, sn_info->name) != 0) {
+        return -EINVAL;
+    }
 
-static int decode64(char **p, const char *end, uint64_t *v)
-{
-    if (*p + 8 > end) {
+    if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
         return -ERANGE;
     }
 
-    *v = *(uint64_t *)(*p);
-    le64_to_cpus(v);
-    *p += 8;
-    return 0;
-}
-
-static int decode_str(char **p, const char *end, char **s)
-{
-    uint32_t len;
-    int r;
-
-    if ((r = decode32(p, end, &len)) < 0) {
+    r = rbd_snap_create(s->image, sn_info->name);
+    if (r < 0) {
+        error_report("failed to create snap: %s", strerror(-r));
         return r;
     }
 
-    *s = qemu_malloc(len + 1);
-    memcpy(*s, *p, len);
-    *p += len;
-    (*s)[len] = '\0';
-
-    return len;
+    return 0;
 }
 
-static int rbd_snap_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+static int qemu_rbd_snap_list(BlockDriverState *bs,
+                              QEMUSnapshotInfo **psn_tab)
 {
     BDRVRBDState *s = bs->opaque;
-    char n[RBD_MAX_SEG_NAME_SIZE];
     QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
-    RbdHeader1 *header;
-    char *hbuf = NULL;
-    char *outbuf = NULL, *end, *buf;
-    uint64_t len;
-    uint64_t snap_seq;
-    uint32_t snap_count;
-    int r, i;
-
-    /* read header to estimate how much space we need to read the snap
-     * list */
-    if ((r = rbd_read_header(s, &hbuf)) < 0) {
-        goto done_err;
-    }
-    header = (RbdHeader1 *)hbuf;
-    len = le64_to_cpu(header->snap_names_len);
-    len += 1024; /* should have already been enough, but new snapshots might
-                    already been created since we read the header. just allocate
-                    a bit more, so that in most cases it'll suffice anyway */
-    qemu_free(hbuf);
-
-    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-    while (1) {
-        qemu_free(outbuf);
-        outbuf = qemu_malloc(len);
+    int i, snap_count;
+    rbd_snap_info_t *snaps;
+    int max_snaps = RBD_MAX_SNAPS;
 
-        r = rados_exec(s->header_pool, n, "rbd", "snap_list", NULL, 0,
-                       outbuf, len);
-        if (r < 0) {
-            error_report("rbd.snap_list execution failed failed: %s", strerror(-r));
-            goto done_err;
+    do {
+        snaps = g_malloc(sizeof(*snaps) * max_snaps);
+        snap_count = rbd_snap_list(s->image, snaps, &max_snaps);
+        if (snap_count < 0) {
+            g_free(snaps);
         }
-        if (r != len) {
-            break;
-       }
+    } while (snap_count == -ERANGE);
 
-        /* if we're here, we probably raced with some snaps creation */
-        len *= 2;
+    if (snap_count <= 0) {
+        goto done;
     }
-    buf = outbuf;
-    end = buf + len;
 
-    if ((r = decode64(&buf, end, &snap_seq)) < 0) {
-        goto done_err;
-    }
-    if ((r = decode32(&buf, end, &snap_count)) < 0) {
-        goto done_err;
-    }
+    sn_tab = g_malloc0(snap_count * sizeof(QEMUSnapshotInfo));
 
-    sn_tab = qemu_mallocz(snap_count * sizeof(QEMUSnapshotInfo));
     for (i = 0; i < snap_count; i++) {
-        uint64_t id, image_size;
-        char *snap_name;
-
-        if ((r = decode64(&buf, end, &id)) < 0) {
-            goto done_err;
-        }
-        if ((r = decode64(&buf, end, &image_size)) < 0) {
-            goto done_err;
-        }
-        if ((r = decode_str(&buf, end, &snap_name)) < 0) {
-            goto done_err;
-        }
+        const char *snap_name = snaps[i].name;
 
         sn_info = sn_tab + i;
         pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
         pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
-        qemu_free(snap_name);
 
-        sn_info->vm_state_size = image_size;
+        sn_info->vm_state_size = snaps[i].size;
         sn_info->date_sec = 0;
         sn_info->date_nsec = 0;
         sn_info->vm_clock_nsec = 0;
     }
+    rbd_snap_list_end(snaps);
+
+ done:
     *psn_tab = sn_tab;
-    qemu_free(outbuf);
     return snap_count;
-done_err:
-    qemu_free(sn_tab);
-    qemu_free(outbuf);
-    return r;
 }
 
-static QEMUOptionParameter rbd_create_options[] = {
+static QEMUOptionParameter qemu_rbd_create_options[] = {
     {
      .name = BLOCK_OPT_SIZE,
      .type = OPT_SIZE,
@@ -1036,19 +849,21 @@ static QEMUOptionParameter rbd_create_options[] = {
 static BlockDriver bdrv_rbd = {
     .format_name        = "rbd",
     .instance_size      = sizeof(BDRVRBDState),
-    .bdrv_file_open     = rbd_open,
-    .bdrv_close         = rbd_close,
-    .bdrv_create        = rbd_create,
-    .bdrv_get_info      = rbd_getinfo,
-    .create_options     = rbd_create_options,
-    .bdrv_getlength     = rbd_getlength,
+    .bdrv_file_open     = qemu_rbd_open,
+    .bdrv_close         = qemu_rbd_close,
+    .bdrv_create        = qemu_rbd_create,
+    .bdrv_get_info      = qemu_rbd_getinfo,
+    .create_options     = qemu_rbd_create_options,
+    .bdrv_getlength     = qemu_rbd_getlength,
+    .bdrv_truncate      = qemu_rbd_truncate,
     .protocol_name      = "rbd",
 
-    .bdrv_aio_readv     = rbd_aio_readv,
-    .bdrv_aio_writev    = rbd_aio_writev,
+    .bdrv_aio_readv         = qemu_rbd_aio_readv,
+    .bdrv_aio_writev        = qemu_rbd_aio_writev,
+    .bdrv_co_flush_to_disk  = qemu_rbd_co_flush,
 
-    .bdrv_snapshot_create rbd_snap_create,
-    .bdrv_snapshot_list rbd_snap_list,
+    .bdrv_snapshot_create   = qemu_rbd_snap_create,
+    .bdrv_snapshot_list     = qemu_rbd_snap_list,
 };
 
 static void bdrv_rbd_init(void)
index a54e0dee3186dcdb7431371e2800d53c8020658e..62f1f3a0cf30a5c08387ae09466a441b29b3942c 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
 
@@ -65,7 +66,7 @@
  * 20 - 31 (12 bits): reserved data object space
  * 32 - 55 (24 bits): vdi object space
  * 56 - 59 ( 4 bits): reserved vdi object space
- * 60 - 63 ( 4 bits): object type indentifier space
+ * 60 - 63 ( 4 bits): object type identifier space
  */
 
 #define VDI_SPACE_SHIFT   32
@@ -195,7 +196,7 @@ static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
     return hval;
 }
 
-static inline int is_data_obj_writeable(SheepdogInode *inode, unsigned int idx)
+static inline int is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
 {
     return inode->vdi_id == inode->data_vdi_id[idx];
 }
@@ -273,7 +274,7 @@ struct SheepdogAIOCB {
     int ret;
     enum AIOCBState aiocb_type;
 
-    QEMUBH *bh;
+    Coroutine *coroutine;
     void (*aio_done_func)(SheepdogAIOCB *);
 
     int canceled;
@@ -294,6 +295,10 @@ typedef struct BDRVSheepdogState {
     char *port;
     int fd;
 
+    CoMutex lock;
+    Coroutine *co_send;
+    Coroutine *co_recv;
+
     uint32_t aioreq_seq_num;
     QLIST_HEAD(outstanding_aio_head, AIOReq) outstanding_aio_head;
 } BDRVSheepdogState;
@@ -345,19 +350,16 @@ static const char * sd_strerror(int err)
 /*
  * Sheepdog I/O handling:
  *
- * 1. In the sd_aio_readv/writev, read/write requests are added to the
- *    QEMU Bottom Halves.
- *
- * 2. In sd_readv_writev_bh_cb, the callbacks of BHs, we send the I/O
- *    requests to the server and link the requests to the
- *    outstanding_list in the BDRVSheepdogState.  we exits the
- *    function without waiting for receiving the response.
+ * 1. In sd_co_rw_vector, we send the I/O requests to the server and
+ *    link the requests to the outstanding_list in the
+ *    BDRVSheepdogState.  The function exits without waiting for
+ *    receiving the response.
  *
- * 3. We receive the response in aio_read_response, the fd handler to
+ * 2. We receive the response in aio_read_response, the fd handler to
  *    the sheepdog connection.  If metadata update is needed, we send
  *    the write request to the vdi object in sd_write_done, the write
- *    completion function.  The AIOCB callback is not called until all
- *    the requests belonging to the AIOCB are finished.
+ *    completion function.  We switch back to sd_co_readv/writev after
+ *    all the requests belonging to the AIOCB are finished.
  */
 
 static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
@@ -367,7 +369,7 @@ static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
 {
     AIOReq *aio_req;
 
-    aio_req = qemu_malloc(sizeof(*aio_req));
+    aio_req = g_malloc(sizeof(*aio_req));
     aio_req->aiocb = acb;
     aio_req->iov_offset = iov_offset;
     aio_req->oid = oid;
@@ -389,15 +391,15 @@ static inline int free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
     SheepdogAIOCB *acb = aio_req->aiocb;
     QLIST_REMOVE(aio_req, outstanding_aio_siblings);
     QLIST_REMOVE(aio_req, aioreq_siblings);
-    qemu_free(aio_req);
+    g_free(aio_req);
 
     return !QLIST_EMPTY(&acb->aioreq_head);
 }
 
-static void sd_finish_aiocb(SheepdogAIOCB *acb)
+static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
 {
     if (!acb->canceled) {
-        acb->common.cb(acb->common.opaque, acb->ret);
+        qemu_coroutine_enter(acb->coroutine, NULL);
     }
     qemu_aio_release(acb);
 }
@@ -410,7 +412,8 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
      * Sheepdog cannot cancel the requests which are already sent to
      * the servers, so we just complete the request with -EIO here.
      */
-    acb->common.cb(acb->common.opaque, -EIO);
+    acb->ret = -EIO;
+    qemu_coroutine_enter(acb->coroutine, NULL);
     acb->canceled = 1;
 }
 
@@ -434,30 +437,12 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
 
     acb->aio_done_func = NULL;
     acb->canceled = 0;
-    acb->bh = NULL;
+    acb->coroutine = qemu_coroutine_self();
     acb->ret = 0;
     QLIST_INIT(&acb->aioreq_head);
     return acb;
 }
 
-static int sd_schedule_bh(QEMUBHFunc *cb, SheepdogAIOCB *acb)
-{
-    if (acb->bh) {
-        error_report("bug: %d %d\n", acb->aiocb_type, acb->aiocb_type);
-        return -EIO;
-    }
-
-    acb->bh = qemu_bh_new(cb, acb);
-    if (!acb->bh) {
-        error_report("oom: %d %d\n", acb->aiocb_type, acb->aiocb_type);
-        return -EIO;
-    }
-
-    qemu_bh_schedule(acb->bh);
-
-    return 0;
-}
-
 #ifdef _WIN32
 
 struct msghdr {
@@ -475,7 +460,7 @@ static ssize_t sendmsg(int s, const struct msghdr *msg, int flags)
     for (i = 0; i < msg->msg_iovlen; i++) {
         size += msg->msg_iov[i].iov_len;
     }
-    buf = qemu_malloc(size);
+    buf = g_malloc(size);
 
     p = buf;
     for (i = 0; i < msg->msg_iovlen; i++) {
@@ -485,7 +470,7 @@ static ssize_t sendmsg(int s, const struct msghdr *msg, int flags)
 
     ret = send(s, buf, size, flags);
 
-    qemu_free(buf);
+    g_free(buf);
     return ret;
 }
 
@@ -499,9 +484,9 @@ static ssize_t recvmsg(int s, struct msghdr *msg, int flags)
     for (i = 0; i < msg->msg_iovlen; i++) {
         size += msg->msg_iov[i].iov_len;
     }
-    buf = qemu_malloc(size);
+    buf = g_malloc(size);
 
-    ret = recv(s, buf, size, flags);
+    ret = qemu_recv(s, buf, size, flags);
     if (ret < 0) {
         goto out;
     }
@@ -512,7 +497,7 @@ static ssize_t recvmsg(int s, struct msghdr *msg, int flags)
         p += msg->msg_iov[i].iov_len;
     }
 out:
-    qemu_free(buf);
+    g_free(buf);
     return ret;
 }
 
@@ -597,7 +582,7 @@ static int connect_to_sdog(const char *addr, const char *port)
 
     ret = getaddrinfo(addr, port, &hints, &res0);
     if (ret) {
-        error_report("unable to get address info %s, %s\n",
+        error_report("unable to get address info %s, %s",
                      addr, strerror(errno));
         return -1;
     }
@@ -627,7 +612,7 @@ static int connect_to_sdog(const char *addr, const char *port)
         goto success;
     }
     fd = -1;
-    error_report("failed connect to %s:%s\n", addr, port);
+    error_report("failed connect to %s:%s", addr, port);
 success:
     freeaddrinfo(res0);
     return fd;
@@ -640,10 +625,16 @@ static int do_readv_writev(int sockfd, struct iovec *iov, int len,
 again:
     ret = do_send_recv(sockfd, iov, len, iov_offset, write);
     if (ret < 0) {
-        if (errno == EINTR || errno == EAGAIN) {
+        if (errno == EINTR) {
+            goto again;
+        }
+        if (errno == EAGAIN) {
+            if (qemu_in_coroutine()) {
+                qemu_coroutine_yield();
+            }
             goto again;
         }
-        error_report("failed to recv a rsp, %s\n", strerror(errno));
+        error_report("failed to recv a rsp, %s", strerror(errno));
         return 1;
     }
 
@@ -702,7 +693,7 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data,
 
     ret = do_writev(sockfd, iov, sizeof(*hdr) + *wlen, 0);
     if (ret) {
-        error_report("failed to send a req, %s\n", strerror(errno));
+        error_report("failed to send a req, %s", strerror(errno));
         ret = -1;
     }
 
@@ -722,7 +713,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
 
     ret = do_read(sockfd, hdr, sizeof(*hdr));
     if (ret) {
-        error_report("failed to get a rsp, %s\n", strerror(errno));
+        error_report("failed to get a rsp, %s", strerror(errno));
         ret = -1;
         goto out;
     }
@@ -734,7 +725,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
     if (*rlen) {
         ret = do_read(sockfd, data, *rlen);
         if (ret) {
-            error_report("failed to get the data, %s\n", strerror(errno));
+            error_report("failed to get the data, %s", strerror(errno));
             ret = -1;
             goto out;
         }
@@ -744,7 +735,7 @@ out:
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type);
 
@@ -752,7 +743,7 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
  * This function searchs pending requests to the object `oid', and
  * sends them.
  */
-static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
+static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
 {
     AIOReq *aio_req, *next;
     SheepdogAIOCB *acb;
@@ -771,7 +762,7 @@ static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
         ret = add_aio_request(s, aio_req, acb->qiov->iov,
                               acb->qiov->niov, 0, acb->aiocb_type);
         if (ret < 0) {
-            error_report("add_aio_request is failed\n");
+            error_report("add_aio_request is failed");
             free_aio_req(s, aio_req);
             if (QLIST_EMPTY(&acb->aioreq_head)) {
                 sd_finish_aiocb(acb);
@@ -786,7 +777,7 @@ static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
  * This function is registered as a fd handler, and called from the
  * main loop when s->fd is ready for reading responses.
  */
-static void aio_read_response(void *opaque)
+static void coroutine_fn aio_read_response(void *opaque)
 {
     SheepdogObjRsp rsp;
     BDRVSheepdogState *s = opaque;
@@ -798,14 +789,14 @@ static void aio_read_response(void *opaque)
     unsigned long idx;
 
     if (QLIST_EMPTY(&s->outstanding_aio_head)) {
-        return;
+        goto out;
     }
 
     /* read a header */
     ret = do_read(fd, &rsp, sizeof(rsp));
     if (ret) {
-        error_report("failed to get the header, %s\n", strerror(errno));
-        return;
+        error_report("failed to get the header, %s", strerror(errno));
+        goto out;
     }
 
     /* find the right aio_req from the outstanding_aio list */
@@ -815,8 +806,8 @@ static void aio_read_response(void *opaque)
         }
     }
     if (!aio_req) {
-        error_report("cannot find aio_req %x\n", rsp.id);
-        return;
+        error_report("cannot find aio_req %x", rsp.id);
+        goto out;
     }
 
     acb = aio_req->aiocb;
@@ -851,25 +842,45 @@ static void aio_read_response(void *opaque)
         ret = do_readv(fd, acb->qiov->iov, rsp.data_length,
                        aio_req->iov_offset);
         if (ret) {
-            error_report("failed to get the data, %s\n", strerror(errno));
-            return;
+            error_report("failed to get the data, %s", strerror(errno));
+            goto out;
         }
         break;
     }
 
     if (rsp.result != SD_RES_SUCCESS) {
         acb->ret = -EIO;
-        error_report("%s\n", sd_strerror(rsp.result));
+        error_report("%s", sd_strerror(rsp.result));
     }
 
     rest = free_aio_req(s, aio_req);
     if (!rest) {
         /*
          * We've finished all requests which belong to the AIOCB, so
-         * we can call the callback now.
+         * we can switch back to sd_co_readv/writev now.
          */
         acb->aio_done_func(acb);
     }
+out:
+    s->co_recv = NULL;
+}
+
+static void co_read_response(void *opaque)
+{
+    BDRVSheepdogState *s = opaque;
+
+    if (!s->co_recv) {
+        s->co_recv = qemu_coroutine_create(aio_read_response);
+    }
+
+    qemu_coroutine_enter(s->co_recv, opaque);
+}
+
+static void co_write_request(void *opaque)
+{
+    BDRVSheepdogState *s = opaque;
+
+    qemu_coroutine_enter(s->co_send, NULL);
 }
 
 static int aio_flush_request(void *opaque)
@@ -916,7 +927,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
-        error_report("%s\n", strerror(errno));
+        error_report("%s", strerror(errno));
         return -1;
     }
 
@@ -924,12 +935,12 @@ static int get_sheep_fd(BDRVSheepdogState *s)
 
     ret = set_nodelay(fd);
     if (ret) {
-        error_report("%s\n", strerror(errno));
+        error_report("%s", strerror(errno));
         closesocket(fd);
         return -1;
     }
 
-    qemu_aio_set_fd_handler(fd, aio_read_response, NULL, aio_flush_request,
+    qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request,
                             NULL, s);
     return fd;
 }
@@ -957,7 +968,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
     char *p, *q;
     int nr_sep;
 
-    p = q = qemu_strdup(filename);
+    p = q = g_strdup(filename);
 
     /* count the number of separators */
     nr_sep = 0;
@@ -997,7 +1008,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
     }
 
     if (s->addr == NULL) {
-        qemu_free(q);
+        g_free(q);
     }
 
     return 0;
@@ -1040,7 +1051,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
     }
 
     if (rsp->result != SD_RES_SUCCESS) {
-        error_report("cannot get vdi info, %s, %s %d %s\n",
+        error_report("cannot get vdi info, %s, %s %d %s",
                      sd_strerror(rsp->result), filename, snapid, tag);
         ret = -1;
         goto out;
@@ -1053,7 +1064,7 @@ out:
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type)
 {
@@ -1068,7 +1079,7 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
     uint64_t old_oid = aio_req->base_oid;
 
     if (!nr_copies) {
-        error_report("bug\n");
+        error_report("bug");
     }
 
     memset(&hdr, 0, sizeof(hdr));
@@ -1096,24 +1107,33 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
 
     hdr.id = aio_req->id;
 
+    qemu_co_mutex_lock(&s->lock);
+    s->co_send = qemu_coroutine_self();
+    qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
+                            aio_flush_request, NULL, s);
     set_cork(s->fd, 1);
 
     /* send a header */
     ret = do_write(s->fd, &hdr, sizeof(hdr));
     if (ret) {
-        error_report("failed to send a req, %s\n", strerror(errno));
+        qemu_co_mutex_unlock(&s->lock);
+        error_report("failed to send a req, %s", strerror(errno));
         return -EIO;
     }
 
     if (wlen) {
         ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset);
         if (ret) {
-            error_report("failed to send a data, %s\n", strerror(errno));
+            qemu_co_mutex_unlock(&s->lock);
+            error_report("failed to send a data, %s", strerror(errno));
             return -EIO;
         }
     }
 
     set_cork(s->fd, 0);
+    qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
+                            aio_flush_request, NULL, s);
+    qemu_co_mutex_unlock(&s->lock);
 
     return 0;
 }
@@ -1150,7 +1170,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
 
     ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
     if (ret) {
-        error_report("failed to send a request to the sheep\n");
+        error_report("failed to send a request to the sheep");
         return -1;
     }
 
@@ -1158,7 +1178,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
     case SD_RES_SUCCESS:
         return 0;
     default:
-        error_report("%s\n", sd_strerror(rsp->result));
+        error_report("%s", sd_strerror(rsp->result));
         return -1;
     }
 }
@@ -1211,11 +1231,11 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
-        error_report("failed to connect\n");
+        error_report("failed to connect");
         goto out;
     }
 
-    buf = qemu_malloc(SD_INODE_SIZE);
+    buf = g_malloc(SD_INODE_SIZE);
     ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0);
 
     closesocket(fd);
@@ -1230,14 +1250,15 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
 
     bs->total_sectors = s->inode.vdi_size / SECTOR_SIZE;
     strncpy(s->name, vdi, sizeof(s->name));
-    qemu_free(buf);
+    qemu_co_mutex_init(&s->lock);
+    g_free(buf);
     return 0;
 out:
     qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
     if (s->fd >= 0) {
         closesocket(s->fd);
     }
-    qemu_free(buf);
+    g_free(buf);
     return -1;
 }
 
@@ -1280,7 +1301,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
     }
 
     if (rsp->result != SD_RES_SUCCESS) {
-        error_report("%s, %s\n", sd_strerror(rsp->result), filename);
+        error_report("%s, %s", sd_strerror(rsp->result), filename);
         return -EIO;
     }
 
@@ -1291,6 +1312,49 @@ static int do_sd_create(char *filename, int64_t vdi_size,
     return 0;
 }
 
+static int sd_prealloc(const char *filename)
+{
+    BlockDriverState *bs = NULL;
+    uint32_t idx, max_idx;
+    int64_t vdi_size;
+    void *buf = g_malloc0(SD_DATA_OBJ_SIZE);
+    int ret;
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        goto out;
+    }
+
+    vdi_size = bdrv_getlength(bs);
+    if (vdi_size < 0) {
+        ret = vdi_size;
+        goto out;
+    }
+    max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
+
+    for (idx = 0; idx < max_idx; idx++) {
+        /*
+         * The created image can be a cloned image, so we need to read
+         * a data from the source image.
+         */
+        ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+        ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+out:
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    g_free(buf);
+
+    return ret;
+}
+
 static int sd_create(const char *filename, QEMUOptionParameter *options)
 {
     int ret;
@@ -1300,14 +1364,16 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
     BDRVSheepdogState s;
     char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
     uint32_t snapid;
+    int prealloc = 0;
+    const char *vdiname;
 
-    strstart(filename, "sheepdog:", (const char **)&filename);
+    strstart(filename, "sheepdog:", &vdiname);
 
     memset(&s, 0, sizeof(s));
     memset(vdi, 0, sizeof(vdi));
     memset(tag, 0, sizeof(tag));
-    if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) {
-        error_report("invalid filename\n");
+    if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
+        error_report("invalid filename");
         return -EINVAL;
     }
 
@@ -1316,12 +1382,22 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
             vdi_size = options->value.n;
         } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
             backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
+            if (!options->value.s || !strcmp(options->value.s, "off")) {
+                prealloc = 0;
+            } else if (!strcmp(options->value.s, "full")) {
+                prealloc = 1;
+            } else {
+                error_report("Invalid preallocation mode: '%s'",
+                             options->value.s);
+                return -EINVAL;
+            }
         }
         options++;
     }
 
     if (vdi_size > SD_MAX_VDI_SIZE) {
-        error_report("too big image size\n");
+        error_report("too big image size");
         return -EINVAL;
     }
 
@@ -1333,7 +1409,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
         /* Currently, only Sheepdog backing image is supported. */
         drv = bdrv_find_protocol(backing_file);
         if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
-            error_report("backing_file must be a sheepdog image\n");
+            error_report("backing_file must be a sheepdog image");
             return -EINVAL;
         }
 
@@ -1344,7 +1420,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
         s = bs->opaque;
 
         if (!is_snapshot(&s->inode)) {
-            error_report("cannot clone from a non snapshot vdi\n");
+            error_report("cannot clone from a non snapshot vdi");
             bdrv_delete(bs);
             return -EINVAL;
         }
@@ -1353,7 +1429,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
         bdrv_delete(bs);
     }
 
-    return do_sd_create((char *)vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+    ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+    if (!prealloc || ret) {
+        return ret;
+    }
+
+    return sd_prealloc(filename);
 }
 
 static void sd_close(BlockDriverState *bs)
@@ -1384,12 +1465,12 @@ static void sd_close(BlockDriverState *bs)
 
     if (!ret && rsp->result != SD_RES_SUCCESS &&
         rsp->result != SD_RES_VDI_NOT_LOCKED) {
-        error_report("%s, %s\n", sd_strerror(rsp->result), s->name);
+        error_report("%s, %s", sd_strerror(rsp->result), s->name);
     }
 
     qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
     closesocket(s->fd);
-    qemu_free(s->addr);
+    g_free(s->addr);
 }
 
 static int64_t sd_getlength(BlockDriverState *bs)
@@ -1406,10 +1487,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
     unsigned int datalen;
 
     if (offset < s->inode.vdi_size) {
-        error_report("shrinking is not supported\n");
+        error_report("shrinking is not supported");
         return -EINVAL;
     } else if (offset > SD_MAX_VDI_SIZE) {
-        error_report("too big image size\n");
+        error_report("too big image size");
         return -EINVAL;
     }
 
@@ -1426,7 +1507,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
     close(fd);
 
     if (ret < 0) {
-        error_report("failed to update an inode.\n");
+        error_report("failed to update an inode.");
         return -EIO;
     }
 
@@ -1436,9 +1517,9 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
 /*
  * This function is called after writing data objects.  If we need to
  * update metadata, this sends a write request to the vdi object.
- * Otherwise, this calls the AIOCB callback.
+ * Otherwise, this switches back to sd_co_readv/writev.
  */
-static void sd_write_done(SheepdogAIOCB *acb)
+static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
 {
     int ret;
     BDRVSheepdogState *s = acb->common.bs->opaque;
@@ -1487,7 +1568,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
 
     dprintf("%" PRIx32 " is snapshot.\n", s->inode.vdi_id);
 
-    buf = qemu_malloc(SD_INODE_SIZE);
+    buf = g_malloc(SD_INODE_SIZE);
 
     ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1,
                        s->addr, s->port);
@@ -1499,7 +1580,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
-        error_report("failed to connect\n");
+        error_report("failed to connect");
         goto out;
     }
 
@@ -1519,7 +1600,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
     dprintf("%" PRIx32 " was newly created.\n", s->inode.vdi_id);
 
 out:
-    qemu_free(buf);
+    g_free(buf);
 
     return ret;
 }
@@ -1532,8 +1613,11 @@ out:
  * waiting the response.  The responses are received in the
  * `aio_read_response' function which is called from the main loop as
  * a fd handler.
+ *
+ * Returns 1 when we need to wait a response, 0 when there is no sent
+ * request and -errno in error cases.
  */
-static void sd_readv_writev_bh_cb(void *p)
+static int coroutine_fn sd_co_rw_vector(void *p)
 {
     SheepdogAIOCB *acb = p;
     int ret = 0;
@@ -1545,9 +1629,6 @@ static void sd_readv_writev_bh_cb(void *p)
     SheepdogInode *inode = &s->inode;
     AIOReq *aio_req;
 
-    qemu_bh_delete(acb->bh);
-    acb->bh = NULL;
-
     if (acb->aiocb_type == AIOCB_WRITE_UDATA && s->is_snapshot) {
         /*
          * In the case we open the snapshot VDI, Sheepdog creates the
@@ -1576,7 +1657,7 @@ static void sd_readv_writev_bh_cb(void *p)
 
             create = 1;
         } else if (acb->aiocb_type == AIOCB_WRITE_UDATA
-                   && !is_data_obj_writeable(inode, idx)) {
+                   && !is_data_obj_writable(inode, idx)) {
             /* Copy-On-Write */
             create = 1;
             old_oid = oid;
@@ -1617,7 +1698,7 @@ static void sd_readv_writev_bh_cb(void *p)
         ret = add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
                               create, acb->aiocb_type);
         if (ret < 0) {
-            error_report("add_aio_request is failed\n");
+            error_report("add_aio_request is failed");
             free_aio_req(s, aio_req);
             acb->ret = -EIO;
             goto out;
@@ -1629,42 +1710,47 @@ static void sd_readv_writev_bh_cb(void *p)
     }
 out:
     if (QLIST_EMPTY(&acb->aioreq_head)) {
-        sd_finish_aiocb(acb);
+        return acb->ret;
     }
+    return 1;
 }
 
-static BlockDriverAIOCB *sd_aio_writev(BlockDriverState *bs, int64_t sector_num,
-                                       QEMUIOVector *qiov, int nb_sectors,
-                                       BlockDriverCompletionFunc *cb,
-                                       void *opaque)
+static int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors, QEMUIOVector *qiov)
 {
     SheepdogAIOCB *acb;
+    int ret;
 
     if (bs->growable && sector_num + nb_sectors > bs->total_sectors) {
         /* TODO: shouldn't block here */
         if (sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE) < 0) {
-            return NULL;
+            return -EIO;
         }
         bs->total_sectors = sector_num + nb_sectors;
     }
 
-    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, cb, opaque);
+    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
     acb->aio_done_func = sd_write_done;
     acb->aiocb_type = AIOCB_WRITE_UDATA;
 
-    sd_schedule_bh(sd_readv_writev_bh_cb, acb);
-    return &acb->common;
+    ret = sd_co_rw_vector(acb);
+    if (ret <= 0) {
+        qemu_aio_release(acb);
+        return ret;
+    }
+
+    qemu_coroutine_yield();
+
+    return acb->ret;
 }
 
-static BlockDriverAIOCB *sd_aio_readv(BlockDriverState *bs, int64_t sector_num,
-                                      QEMUIOVector *qiov, int nb_sectors,
-                                      BlockDriverCompletionFunc *cb,
-                                      void *opaque)
+static int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
+                       int nb_sectors, QEMUIOVector *qiov)
 {
     SheepdogAIOCB *acb;
-    int i;
+    int i, ret;
 
-    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, cb, opaque);
+    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL);
     acb->aiocb_type = AIOCB_READ_UDATA;
     acb->aio_done_func = sd_finish_aiocb;
 
@@ -1676,8 +1762,15 @@ static BlockDriverAIOCB *sd_aio_readv(BlockDriverState *bs, int64_t sector_num,
         memset(qiov->iov[i].iov_base, 0, qiov->iov[i].iov_len);
     }
 
-    sd_schedule_bh(sd_readv_writev_bh_cb, acb);
-    return &acb->common;
+    ret = sd_co_rw_vector(acb);
+    if (ret <= 0) {
+        qemu_aio_release(acb);
+        return ret;
+    }
+
+    qemu_coroutine_yield();
+
+    return acb->ret;
 }
 
 static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
@@ -1694,7 +1787,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 
     if (s->is_snapshot) {
         error_report("You can't create a snapshot of a snapshot VDI, "
-                     "%s (%" PRIu32 ").\n", s->name, s->inode.vdi_id);
+                     "%s (%" PRIu32 ").", s->name, s->inode.vdi_id);
 
         return -EINVAL;
     }
@@ -1717,7 +1810,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
                        s->inode.nr_copies, datalen, 0, 0);
     if (ret < 0) {
-        error_report("failed to write snapshot's inode.\n");
+        error_report("failed to write snapshot's inode.");
         ret = -EIO;
         goto cleanup;
     }
@@ -1725,19 +1818,19 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1,
                        s->addr, s->port);
     if (ret < 0) {
-        error_report("failed to create inode for snapshot. %s\n",
+        error_report("failed to create inode for snapshot. %s",
                      strerror(errno));
         ret = -EIO;
         goto cleanup;
     }
 
-    inode = (SheepdogInode *)qemu_malloc(datalen);
+    inode = (SheepdogInode *)g_malloc(datalen);
 
     ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
                       s->inode.nr_copies, datalen, 0);
 
     if (ret < 0) {
-        error_report("failed to read new inode info. %s\n", strerror(errno));
+        error_report("failed to read new inode info. %s", strerror(errno));
         ret = -EIO;
         goto cleanup;
     }
@@ -1761,7 +1854,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     uint32_t snapid = 0;
     int ret = -ENOENT, fd;
 
-    old_s = qemu_malloc(sizeof(BDRVSheepdogState));
+    old_s = g_malloc(sizeof(BDRVSheepdogState));
 
     memcpy(old_s, s, sizeof(BDRVSheepdogState));
 
@@ -1776,18 +1869,18 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 
     ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
     if (ret) {
-        error_report("Failed to find_vdi_name\n");
+        error_report("Failed to find_vdi_name");
         ret = -ENOENT;
         goto out;
     }
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
-        error_report("failed to connect\n");
+        error_report("failed to connect");
         goto out;
     }
 
-    buf = qemu_malloc(SD_INODE_SIZE);
+    buf = g_malloc(SD_INODE_SIZE);
     ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
                       SD_INODE_SIZE, 0);
 
@@ -1801,24 +1894,24 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     memcpy(&s->inode, buf, sizeof(s->inode));
 
     if (!s->inode.vm_state_size) {
-        error_report("Invalid snapshot\n");
+        error_report("Invalid snapshot");
         ret = -ENOENT;
         goto out;
     }
 
     s->is_snapshot = 1;
 
-    qemu_free(buf);
-    qemu_free(old_s);
+    g_free(buf);
+    g_free(old_s);
 
     return 0;
 out:
     /* recover bdrv_sd_state */
     memcpy(s, old_s, sizeof(BDRVSheepdogState));
-    qemu_free(buf);
-    qemu_free(old_s);
+    g_free(buf);
+    g_free(old_s);
 
-    error_report("failed to open. recover old bdrv_sd_state.\n");
+    error_report("failed to open. recover old bdrv_sd_state.");
 
     return ret;
 }
@@ -1829,20 +1922,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;
@@ -1857,7 +1936,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
     uint64_t hval;
     uint32_t vid;
 
-    vdi_inuse = qemu_malloc(max);
+    vdi_inuse = g_malloc(max);
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
@@ -1879,7 +1958,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
         goto out;
     }
 
-    sn_tab = qemu_mallocz(nr * sizeof(*sn_tab));
+    sn_tab = g_malloc0(nr * sizeof(*sn_tab));
 
     /* calculate a vdi id with hash function */
     hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
@@ -1887,7 +1966,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     fd = connect_to_sdog(s->addr, s->port);
     if (fd < 0) {
-        error_report("failed to connect\n");
+        error_report("failed to connect");
         goto out;
     }
 
@@ -1922,7 +2001,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 out:
     *psn_tab = sn_tab;
 
-    qemu_free(vdi_inuse);
+    g_free(vdi_inuse);
 
     return found;
 }
@@ -1961,7 +2040,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
         }
 
         if (ret < 0) {
-            error_report("failed to save vmstate %s\n", strerror(errno));
+            error_report("failed to save vmstate %s", strerror(errno));
             ret = -EIO;
             goto cleanup;
         }
@@ -2003,6 +2082,11 @@ static QEMUOptionParameter sd_create_options[] = {
         .type = OPT_STRING,
         .help = "File name of a base image"
     },
+    {
+        .name = BLOCK_OPT_PREALLOC,
+        .type = OPT_STRING,
+        .help = "Preallocation mode (allowed values: off, full)"
+    },
     { NULL }
 };
 
@@ -2016,8 +2100,8 @@ BlockDriver bdrv_sheepdog = {
     .bdrv_getlength = sd_getlength,
     .bdrv_truncate  = sd_truncate,
 
-    .bdrv_aio_readv     = sd_aio_readv,
-    .bdrv_aio_writev    = sd_aio_writev,
+    .bdrv_co_readv  = sd_co_readv,
+    .bdrv_co_writev = sd_co_writev,
 
     .bdrv_snapshot_create   = sd_snapshot_create,
     .bdrv_snapshot_goto     = sd_snapshot_goto,
index 116b25bc9bc4c677de0882df7f9db0fcbbd5a691..02da6b44d045eb558a0ef0f3b4a613b1868e633e 100644 (file)
@@ -52,6 +52,7 @@
 #include "qemu-common.h"
 #include "block_int.h"
 #include "module.h"
+#include "migration.h"
 
 #if defined(CONFIG_UUID)
 #include <uuid/uuid.h>
@@ -87,6 +88,7 @@ void uuid_unparse(const uuid_t uu, char *out);
 #define MiB     (KiB * KiB)
 
 #define SECTOR_SIZE 512
+#define DEFAULT_CLUSTER_SIZE (1 * MiB)
 
 #if defined(CONFIG_VDI_DEBUG)
 #define logout(fmt, ...) \
@@ -113,8 +115,13 @@ 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). */
-#define VDI_UNALLOCATED UINT32_MAX
+/* A never-allocated block; semantically arbitrary content. */
+#define VDI_UNALLOCATED 0xffffffffU
+
+/* A discarded (no longer allocated) block; semantically zero-filled. */
+#define VDI_DISCARDED   0xfffffffeU
+
+#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
 
 #if !defined(CONFIG_UUID)
 void uuid_generate(uuid_t out)
@@ -151,6 +158,7 @@ typedef struct {
     /* Buffer for new allocated block. */
     void *block_buffer;
     void *orig_buf;
+    bool is_write;
     int header_modified;
     BlockDriverAIOCB *hd_aiocb;
     struct iovec hd_iov;
@@ -194,8 +202,10 @@ 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;
+
+    Error *migration_blocker;
 } BDRVVdiState;
 
 /* Change UUID from little endian (IPRT = VirtualBox format) to big endian
@@ -299,16 +309,16 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
     uint32_t *bmap;
     logout("\n");
 
-    bmap = qemu_malloc(s->header.blocks_in_image * sizeof(uint32_t));
+    bmap = g_malloc(s->header.blocks_in_image * sizeof(uint32_t));
     memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
 
     /* Check block map and value of blocks_allocated. */
     for (block = 0; block < s->header.blocks_in_image; block++) {
         uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
-        if (bmap_entry != VDI_UNALLOCATED) {
+        if (VDI_IS_ALLOCATED(bmap_entry)) {
             if (bmap_entry < s->header.blocks_in_image) {
                 blocks_allocated++;
-                if (bmap[bmap_entry] == VDI_UNALLOCATED) {
+                if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
                     bmap[bmap_entry] = bmap_entry;
                 } else {
                     fprintf(stderr, "ERROR: block index %" PRIu32
@@ -329,7 +339,7 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
         res->corruptions++;
     }
 
-    qemu_free(bmap);
+    g_free(bmap);
 
     return 0;
 }
@@ -441,16 +451,22 @@ static int vdi_open(BlockDriverState *bs, int flags)
     bmap_size = header.blocks_in_image * sizeof(uint32_t);
     bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
     if (bmap_size > 0) {
-        s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
+        s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
     }
     if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
         goto fail_free_bmap;
     }
 
+    /* Disable migration when vdi images are used */
+    error_set(&s->migration_blocker,
+              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+              "vdi", bs->device_name, "live migration");
+    migrate_add_blocker(s->migration_blocker);
+
     return 0;
 
  fail_free_bmap:
-    qemu_free(s->bmap);
+    g_free(s->bmap);
 
  fail:
     return -1;
@@ -470,7 +486,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
         n_sectors = nb_sectors;
     }
     *pnum = n_sectors;
-    return bmap_entry != VDI_UNALLOCATED;
+    return VDI_IS_ALLOCATED(bmap_entry);
 }
 
 static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
@@ -503,6 +519,8 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
         acb->hd_aiocb = NULL;
         acb->sector_num = sector_num;
         acb->qiov = qiov;
+        acb->is_write = is_write;
+
         if (qiov->niov > 1) {
             acb->buf = qemu_blockalign(bs, qiov->size);
             acb->orig_buf = acb->buf;
@@ -541,14 +559,20 @@ static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
 }
 
 static void vdi_aio_read_cb(void *opaque, int ret);
+static void vdi_aio_write_cb(void *opaque, int ret);
 
-static void vdi_aio_read_bh(void *opaque)
+static void vdi_aio_rw_bh(void *opaque)
 {
     VdiAIOCB *acb = opaque;
     logout("\n");
     qemu_bh_delete(acb->bh);
     acb->bh = NULL;
-    vdi_aio_read_cb(opaque, 0);
+
+    if (acb->is_write) {
+        vdi_aio_write_cb(opaque, 0);
+    } else {
+        vdi_aio_read_cb(opaque, 0);
+    }
 }
 
 static void vdi_aio_read_cb(void *opaque, int ret)
@@ -593,10 +617,10 @@ static void vdi_aio_read_cb(void *opaque, int ret)
     /* prepare next AIO request */
     acb->n_sectors = n_sectors;
     bmap_entry = le32_to_cpu(s->bmap[block_index]);
-    if (bmap_entry == VDI_UNALLOCATED) {
+    if (!VDI_IS_ALLOCATED(bmap_entry)) {
         /* Block not allocated, return zeros, no need to wait. */
         memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
-        ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
+        ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
         if (ret < 0) {
             goto done;
         }
@@ -610,6 +634,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
         acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
                                        n_sectors, vdi_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
             goto done;
         }
     }
@@ -628,12 +653,23 @@ static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     VdiAIOCB *acb;
+    int ret;
+
     logout("\n");
     acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     if (!acb) {
         return NULL;
     }
-    vdi_aio_read_cb(acb, 0);
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
     return &acb->common;
 }
 
@@ -663,7 +699,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         if (acb->header_modified) {
             VdiHeader *header = acb->block_buffer;
             logout("now writing modified header\n");
-            assert(acb->bmap_first != VDI_UNALLOCATED);
+            assert(VDI_IS_ALLOCATED(acb->bmap_first));
             *header = s->header;
             vdi_header_to_le(header);
             acb->header_modified = 0;
@@ -673,15 +709,16 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
                                             vdi_aio_write_cb, acb);
             if (acb->hd_aiocb == NULL) {
+                ret = -EIO;
                 goto done;
             }
             return;
-        } else if (acb->bmap_first != VDI_UNALLOCATED) {
+        } else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
             /* One or more new blocks were allocated. */
             uint64_t offset;
             uint32_t bmap_first;
             uint32_t bmap_last;
-            qemu_free(acb->block_buffer);
+            g_free(acb->block_buffer);
             acb->block_buffer = NULL;
             bmap_first = acb->bmap_first;
             bmap_last = acb->bmap_last;
@@ -702,6 +739,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
                                             n_sectors, vdi_aio_write_cb, acb);
             if (acb->hd_aiocb == NULL) {
+                ret = -EIO;
                 goto done;
             }
             return;
@@ -725,7 +763,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
     /* prepare next AIO request */
     acb->n_sectors = n_sectors;
     bmap_entry = le32_to_cpu(s->bmap[block_index]);
-    if (bmap_entry == VDI_UNALLOCATED) {
+    if (!VDI_IS_ALLOCATED(bmap_entry)) {
         /* Allocate new block and write to it. */
         uint64_t offset;
         uint8_t *block;
@@ -736,7 +774,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
                  (uint64_t)bmap_entry * s->block_sectors;
         block = acb->block_buffer;
         if (block == NULL) {
-            block = qemu_mallocz(s->block_size);
+            block = g_malloc0(s->block_size);
             acb->block_buffer = block;
             acb->bmap_first = block_index;
             assert(!acb->header_modified);
@@ -752,6 +790,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
                                         &acb->hd_qiov, s->block_sectors,
                                         vdi_aio_write_cb, acb);
         if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
             goto done;
         }
     } else {
@@ -764,6 +803,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
                                         n_sectors, vdi_aio_write_cb, acb);
         if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
             goto done;
         }
     }
@@ -783,12 +823,23 @@ static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     VdiAIOCB *acb;
+    int ret;
+
     logout("\n");
     acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
     if (!acb) {
         return NULL;
     }
-    vdi_aio_write_cb(acb, 0);
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
     return &acb->common;
 }
 
@@ -798,7 +849,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
     int result = 0;
     uint64_t bytes = 0;
     uint32_t blocks;
-    size_t block_size = 1 * MiB;
+    size_t block_size = DEFAULT_CLUSTER_SIZE;
     uint32_t image_type = VDI_TYPE_DYNAMIC;
     VdiHeader header;
     size_t i;
@@ -869,7 +920,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 
     bmap = NULL;
     if (bmap_size > 0) {
-        bmap = (uint32_t *)qemu_mallocz(bmap_size);
+        bmap = (uint32_t *)g_malloc0(bmap_size);
     }
     for (i = 0; i < blocks; i++) {
         if (image_type == VDI_TYPE_STATIC) {
@@ -881,7 +932,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
     if (write(fd, bmap, bmap_size) < 0) {
         result = -errno;
     }
-    qemu_free(bmap);
+    g_free(bmap);
     if (image_type == VDI_TYPE_STATIC) {
         if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
             result = -errno;
@@ -897,12 +948,18 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 
 static void vdi_close(BlockDriverState *bs)
 {
+    BDRVVdiState *s = bs->opaque;
+
+    g_free(s->bmap);
+
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
 }
 
-static int vdi_flush(BlockDriverState *bs)
+static coroutine_fn int vdi_co_flush(BlockDriverState *bs)
 {
     logout("\n");
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 
@@ -916,7 +973,8 @@ static QEMUOptionParameter vdi_create_options[] = {
     {
         .name = BLOCK_OPT_CLUSTER_SIZE,
         .type = OPT_SIZE,
-        .help = "VDI cluster (block) size"
+        .help = "VDI cluster (block) size",
+        .value = { .n = DEFAULT_CLUSTER_SIZE },
     },
 #endif
 #if defined(CONFIG_VDI_STATIC_IMAGE)
@@ -937,7 +995,7 @@ static BlockDriver bdrv_vdi = {
     .bdrv_open = vdi_open,
     .bdrv_close = vdi_close,
     .bdrv_create = vdi_create,
-    .bdrv_flush = vdi_flush,
+    .bdrv_co_flush_to_disk = vdi_co_flush,
     .bdrv_is_allocated = vdi_is_allocated,
     .bdrv_make_empty = vdi_make_empty,
 
index 8fc9d67208a727cc130cea29f17683abcb2f7fb7..f5441591d799fb14cb6464554d46d52ed6bf48ac 100644 (file)
 #include "qemu-common.h"
 #include "block_int.h"
 #include "module.h"
+#include "migration.h"
+#include <zlib.h>
 
 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
+#define VMDK4_COMPRESSION_DEFLATE 1
+#define VMDK4_FLAG_RGD (1 << 1)
+#define VMDK4_FLAG_COMPRESS (1 << 16)
+#define VMDK4_FLAG_MARKER (1 << 17)
 
 typedef struct {
     uint32_t version;
@@ -51,16 +57,24 @@ typedef struct {
     int64_t desc_offset;
     int64_t desc_size;
     int32_t num_gtes_per_gte;
-    int64_t rgd_offset;
     int64_t gd_offset;
+    int64_t rgd_offset;
     int64_t grain_offset;
     char filler[1];
     char check_bytes[4];
-} __attribute__((packed)) VMDK4Header;
+    uint16_t compressAlgorithm;
+} QEMU_PACKED VMDK4Header;
 
 #define L2_CACHE_SIZE 16
 
-typedef struct BDRVVmdkState {
+typedef struct VmdkExtent {
+    BlockDriverState *file;
+    bool flat;
+    bool compressed;
+    bool has_marker;
+    int64_t sectors;
+    int64_t end_sector;
+    int64_t flat_start_offset;
     int64_t l1_table_offset;
     int64_t l1_backup_table_offset;
     uint32_t *l1_table;
@@ -74,7 +88,17 @@ typedef struct BDRVVmdkState {
     uint32_t l2_cache_counts[L2_CACHE_SIZE];
 
     unsigned int cluster_sectors;
+} VmdkExtent;
+
+typedef struct BDRVVmdkState {
+    CoMutex lock;
+    int desc_offset;
+    bool cid_updated;
     uint32_t parent_cid;
+    int num_extents;
+    /* Extent array with num_extents entries, ascend ordered by address */
+    VmdkExtent *extents;
+    Error *migration_blocker;
 } BDRVVmdkState;
 
 typedef struct VmdkMetaData {
@@ -85,36 +109,117 @@ typedef struct VmdkMetaData {
     int valid;
 } VmdkMetaData;
 
+typedef struct VmdkGrainMarker {
+    uint64_t lba;
+    uint32_t size;
+    uint8_t  data[0];
+} VmdkGrainMarker;
+
 static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     uint32_t magic;
 
-    if (buf_size < 4)
+    if (buf_size < 4) {
         return 0;
+    }
     magic = be32_to_cpu(*(uint32_t *)buf);
     if (magic == VMDK3_MAGIC ||
-        magic == VMDK4_MAGIC)
+        magic == VMDK4_MAGIC) {
         return 100;
-    else
+    } else {
+        const char *p = (const char *)buf;
+        const char *end = p + buf_size;
+        while (p < end) {
+            if (*p == '#') {
+                /* skip comment line */
+                while (p < end && *p != '\n') {
+                    p++;
+                }
+                p++;
+                continue;
+            }
+            if (*p == ' ') {
+                while (p < end && *p == ' ') {
+                    p++;
+                }
+                /* skip '\r' if windows line endings used. */
+                if (p < end && *p == '\r') {
+                    p++;
+                }
+                /* only accept blank lines before 'version=' line */
+                if (p == end || *p != '\n') {
+                    return 0;
+                }
+                p++;
+                continue;
+            }
+            if (end - p >= strlen("version=X\n")) {
+                if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
+                    strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
+                    return 100;
+                }
+            }
+            if (end - p >= strlen("version=X\r\n")) {
+                if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
+                    strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
+                    return 100;
+                }
+            }
+            return 0;
+        }
         return 0;
+    }
 }
 
 #define CHECK_CID 1
 
 #define SECTOR_SIZE 512
-#define DESC_SIZE 20*SECTOR_SIZE       // 20 sectors of 512 bytes each
-#define HEADER_SIZE 512                        // first sector of 512 bytes
+#define DESC_SIZE (20 * SECTOR_SIZE)    /* 20 sectors of 512 bytes each */
+#define BUF_SIZE 4096
+#define HEADER_SIZE 512                 /* first sector of 512 bytes */
+
+static void vmdk_free_extents(BlockDriverState *bs)
+{
+    int i;
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *e;
+
+    for (i = 0; i < s->num_extents; i++) {
+        e = &s->extents[i];
+        g_free(e->l1_table);
+        g_free(e->l2_cache);
+        g_free(e->l1_backup_table);
+        if (e->file != bs->file) {
+            bdrv_delete(e->file);
+        }
+    }
+    g_free(s->extents);
+}
+
+static void vmdk_free_last_extent(BlockDriverState *bs)
+{
+    BDRVVmdkState *s = bs->opaque;
+
+    if (s->num_extents == 0) {
+        return;
+    }
+    s->num_extents--;
+    s->extents = g_realloc(s->extents, s->num_extents * sizeof(VmdkExtent));
+}
 
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
     char desc[DESC_SIZE];
-    uint32_t cid;
+    uint32_t cid = 0xffffffff;
     const char *p_name, *cid_str;
     size_t cid_str_size;
+    BDRVVmdkState *s = bs->opaque;
+    int ret;
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
         return 0;
+    }
 
     if (parent) {
         cid_str = "parentCID";
@@ -124,9 +229,11 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
         cid_str_size = sizeof("CID");
     }
 
-    if ((p_name = strstr(desc,cid_str)) != NULL) {
+    desc[DESC_SIZE - 1] = '\0';
+    p_name = strstr(desc, cid_str);
+    if (p_name != NULL) {
         p_name += cid_str_size;
-        sscanf(p_name,"%x",&cid);
+        sscanf(p_name, "%x", &cid);
     }
 
     return cid;
@@ -136,21 +243,33 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
 {
     char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
     char *p_name, *tmp_str;
+    BDRVVmdkState *s = bs->opaque;
+    int ret;
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
-        return -1;
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
+    }
+
+    desc[DESC_SIZE - 1] = '\0';
+    tmp_str = strstr(desc, "parentCID");
+    if (tmp_str == NULL) {
+        return -EINVAL;
+    }
 
-    tmp_str = strstr(desc,"parentCID");
     pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
-    if ((p_name = strstr(desc,"CID")) != NULL) {
+    p_name = strstr(desc, "CID");
+    if (p_name != NULL) {
         p_name += sizeof("CID");
         snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    if (bdrv_pwrite_sync(bs->file, 0x200, desc, DESC_SIZE) < 0)
-        return -1;
+    ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
+    }
+
     return 0;
 }
 
@@ -162,302 +281,429 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
     uint32_t cur_pcid;
 
     if (p_bs) {
-        cur_pcid = vmdk_read_cid(p_bs,0);
-        if (s->parent_cid != cur_pcid)
-            // CID not valid
+        cur_pcid = vmdk_read_cid(p_bs, 0);
+        if (s->parent_cid != cur_pcid) {
+            /* CID not valid */
             return 0;
+        }
     }
 #endif
-    // CID valid
+    /* CID valid */
     return 1;
 }
 
-static int vmdk_snapshot_create(const char *filename, const char *backing_file)
+static int vmdk_parent_open(BlockDriverState *bs)
 {
-    int snp_fd, p_fd;
+    char *p_name;
+    char desc[DESC_SIZE + 1];
+    BDRVVmdkState *s = bs->opaque;
     int ret;
-    uint32_t p_cid;
-    char *p_name, *gd_buf, *rgd_buf;
-    const char *real_filename, *temp_str;
-    VMDK4Header header;
-    uint32_t gde_entries, gd_size;
-    int64_t gd_offset, rgd_offset, capacity, gt_size;
-    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
-    static const char desc_template[] =
-    "# Disk DescriptorFile\n"
-    "version=1\n"
-    "CID=%x\n"
-    "parentCID=%x\n"
-    "createType=\"monolithicSparse\"\n"
-    "parentFileNameHint=\"%s\"\n"
-    "\n"
-    "# Extent description\n"
-    "RW %u SPARSE \"%s\"\n"
-    "\n"
-    "# The Disk Data Base \n"
-    "#DDB\n"
-    "\n";
-
-    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
-    if (snp_fd < 0)
-        return -errno;
-    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
-    if (p_fd < 0) {
-        close(snp_fd);
-        return -errno;
-    }
 
-    /* read the header */
-    if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
-    }
-    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
-        ret = -errno;
-        goto fail;
+    desc[DESC_SIZE] = '\0';
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
     }
 
-    /* write the header */
-    if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
-    }
-    if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
-        ret = -errno;
-        goto fail;
+    p_name = strstr(desc, "parentFileNameHint");
+    if (p_name != NULL) {
+        char *end_name;
+
+        p_name += sizeof("parentFileNameHint") + 1;
+        end_name = strchr(p_name, '\"');
+        if (end_name == NULL) {
+            return -EINVAL;
+        }
+        if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
+            return -EINVAL;
+        }
+
+        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
     }
 
-    memset(&header, 0, sizeof(header));
-    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
+    return 0;
+}
 
-    if (ftruncate(snp_fd, header.grain_offset << 9)) {
-        ret = -errno;
-        goto fail;
+/* Create and append extent to the extent array. Return the added VmdkExtent
+ * address. return NULL if allocation failed. */
+static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
+                           BlockDriverState *file, bool flat, int64_t sectors,
+                           int64_t l1_offset, int64_t l1_backup_offset,
+                           uint32_t l1_size,
+                           int l2_size, unsigned int cluster_sectors)
+{
+    VmdkExtent *extent;
+    BDRVVmdkState *s = bs->opaque;
+
+    s->extents = g_realloc(s->extents,
+                              (s->num_extents + 1) * sizeof(VmdkExtent));
+    extent = &s->extents[s->num_extents];
+    s->num_extents++;
+
+    memset(extent, 0, sizeof(VmdkExtent));
+    extent->file = file;
+    extent->flat = flat;
+    extent->sectors = sectors;
+    extent->l1_table_offset = l1_offset;
+    extent->l1_backup_table_offset = l1_backup_offset;
+    extent->l1_size = l1_size;
+    extent->l1_entry_sectors = l2_size * cluster_sectors;
+    extent->l2_size = l2_size;
+    extent->cluster_sectors = cluster_sectors;
+
+    if (s->num_extents > 1) {
+        extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
+    } else {
+        extent->end_sector = extent->sectors;
     }
-    /* the descriptor offset = 0x200 */
-    if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
+    bs->total_sectors = extent->end_sector;
+    return extent;
+}
+
+static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
+{
+    int ret;
+    int l1_size, i;
+
+    /* read the L1 table */
+    l1_size = extent->l1_size * sizeof(uint32_t);
+    extent->l1_table = g_malloc(l1_size);
+    ret = bdrv_pread(extent->file,
+                    extent->l1_table_offset,
+                    extent->l1_table,
+                    l1_size);
+    if (ret < 0) {
+        goto fail_l1;
     }
-    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
-        ret = -errno;
-        goto fail;
+    for (i = 0; i < extent->l1_size; i++) {
+        le32_to_cpus(&extent->l1_table[i]);
     }
 
-    if ((p_name = strstr(p_desc,"CID")) != NULL) {
-        p_name += sizeof("CID");
-        sscanf(p_name,"%x",&p_cid);
+    if (extent->l1_backup_table_offset) {
+        extent->l1_backup_table = g_malloc(l1_size);
+        ret = bdrv_pread(extent->file,
+                        extent->l1_backup_table_offset,
+                        extent->l1_backup_table,
+                        l1_size);
+        if (ret < 0) {
+            goto fail_l1b;
+        }
+        for (i = 0; i < extent->l1_size; i++) {
+            le32_to_cpus(&extent->l1_backup_table[i]);
+        }
     }
 
-    real_filename = filename;
-    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, '/')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, ':')) != NULL)
-        real_filename = temp_str + 1;
+    extent->l2_cache =
+        g_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
+    return 0;
+ fail_l1b:
+    g_free(extent->l1_backup_table);
+ fail_l1:
+    g_free(extent->l1_table);
+    return ret;
+}
 
-    snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
-             (uint32_t)header.capacity, real_filename);
+static int vmdk_open_vmdk3(BlockDriverState *bs,
+                           BlockDriverState *file,
+                           int flags)
+{
+    int ret;
+    uint32_t magic;
+    VMDK3Header header;
+    VmdkExtent *extent;
 
-    /* write the descriptor */
-    if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail;
+    ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
+        return ret;
     }
-    if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
-        ret = -errno;
-        goto fail;
+    extent = vmdk_add_extent(bs,
+                             bs->file, false,
+                             le32_to_cpu(header.disk_sectors),
+                             le32_to_cpu(header.l1dir_offset) << 9,
+                             0, 1 << 6, 1 << 9,
+                             le32_to_cpu(header.granularity));
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        /* free extent allocated by vmdk_add_extent */
+        vmdk_free_last_extent(bs);
     }
+    return ret;
+}
 
-    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
-    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
-    capacity = header.capacity * SECTOR_SIZE;       // Extent size
-    /*
-     * Each GDE span 32M disk, means:
-     * 512 GTE per GT, each GTE points to grain
-     */
-    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
-    if (!gt_size) {
-        ret = -EINVAL;
-        goto fail;
-    }
-    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde
-    gd_size = gde_entries * sizeof(uint32_t);
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
+                               int64_t desc_offset);
 
-    /* write RGD */
-    rgd_buf = qemu_malloc(gd_size);
-    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+static int vmdk_open_vmdk4(BlockDriverState *bs,
+                           BlockDriverState *file,
+                           int flags)
+{
+    int ret;
+    uint32_t magic;
+    uint32_t l1_size, l1_entry_sectors;
+    VMDK4Header header;
+    VmdkExtent *extent;
+    int64_t l1_backup_offset = 0;
+
+    ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
+        return ret;
     }
-    if (read(p_fd, rgd_buf, gd_size) != gd_size) {
-        ret = -errno;
-        goto fail_rgd;
+    if (header.capacity == 0 && header.desc_offset) {
+        return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
     }
-    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+    l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
+                        * le64_to_cpu(header.granularity);
+    if (l1_entry_sectors <= 0) {
+        return -EINVAL;
     }
-    if (write(snp_fd, rgd_buf, gd_size) == -1) {
-        ret = -errno;
-        goto fail_rgd;
+    l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
+                / l1_entry_sectors;
+    if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
+        l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
+    }
+    extent = vmdk_add_extent(bs, file, false,
+                          le64_to_cpu(header.capacity),
+                          le64_to_cpu(header.gd_offset) << 9,
+                          l1_backup_offset,
+                          l1_size,
+                          le32_to_cpu(header.num_gtes_per_gte),
+                          le64_to_cpu(header.granularity));
+    extent->compressed =
+        le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
+    extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        /* free extent allocated by vmdk_add_extent */
+        vmdk_free_last_extent(bs);
     }
+    return ret;
+}
 
-    /* write GD */
-    gd_buf = qemu_malloc(gd_size);
-    if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_gd;
+/* find an option value out of descriptor file */
+static int vmdk_parse_description(const char *desc, const char *opt_name,
+        char *buf, int buf_size)
+{
+    char *opt_pos, *opt_end;
+    const char *end = desc + strlen(desc);
+
+    opt_pos = strstr(desc, opt_name);
+    if (!opt_pos) {
+        return -1;
     }
-    if (read(p_fd, gd_buf, gd_size) != gd_size) {
-        ret = -errno;
-        goto fail_gd;
+    /* Skip "=\"" following opt_name */
+    opt_pos += strlen(opt_name) + 2;
+    if (opt_pos >= end) {
+        return -1;
     }
-    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
-        ret = -errno;
-        goto fail_gd;
+    opt_end = opt_pos;
+    while (opt_end < end && *opt_end != '"') {
+        opt_end++;
     }
-    if (write(snp_fd, gd_buf, gd_size) == -1) {
-        ret = -errno;
-        goto fail_gd;
+    if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
+        return -1;
     }
-    ret = 0;
-
-fail_gd:
-    qemu_free(gd_buf);
-fail_rgd:
-    qemu_free(rgd_buf);
-fail:
-    close(p_fd);
-    close(snp_fd);
-    return ret;
+    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
+    return 0;
 }
 
-static int vmdk_parent_open(BlockDriverState *bs)
+/* Open an extent file and append to bs array */
+static int vmdk_open_sparse(BlockDriverState *bs,
+                            BlockDriverState *file,
+                            int flags)
 {
-    char *p_name;
-    char desc[DESC_SIZE];
+    uint32_t magic;
 
-    /* the descriptor offset = 0x200 */
-    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
-        return -1;
+    if (bdrv_pread(file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
+        return -EIO;
+    }
 
-    if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
-        char *end_name;
+    magic = be32_to_cpu(magic);
+    switch (magic) {
+        case VMDK3_MAGIC:
+            return vmdk_open_vmdk3(bs, file, flags);
+            break;
+        case VMDK4_MAGIC:
+            return vmdk_open_vmdk4(bs, file, flags);
+            break;
+        default:
+            return -EINVAL;
+            break;
+    }
+}
 
-        p_name += sizeof("parentFileNameHint") + 1;
-        if ((end_name = strchr(p_name,'\"')) == NULL)
-            return -1;
-        if ((end_name - p_name) > sizeof (bs->backing_file) - 1)
-            return -1;
+static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
+        const char *desc_file_path)
+{
+    int ret;
+    char access[11];
+    char type[11];
+    char fname[512];
+    const char *p = desc;
+    int64_t sectors = 0;
+    int64_t flat_offset;
+    char extent_path[PATH_MAX];
+    BlockDriverState *extent_file;
+
+    while (*p) {
+        /* parse extent line:
+         * RW [size in sectors] FLAT "file-name.vmdk" OFFSET
+         * or
+         * RW [size in sectors] SPARSE "file-name.vmdk"
+         */
+        flat_offset = -1;
+        ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
+                access, &sectors, type, fname, &flat_offset);
+        if (ret < 4 || strcmp(access, "RW")) {
+            goto next_line;
+        } else if (!strcmp(type, "FLAT")) {
+            if (ret != 5 || flat_offset < 0) {
+                return -EINVAL;
+            }
+        } else if (ret != 4) {
+            return -EINVAL;
+        }
 
-        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
-    }
+        /* trim the quotation marks around */
+        if (fname[0] == '"') {
+            memmove(fname, fname + 1, strlen(fname));
+            if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
+                return -EINVAL;
+            }
+            fname[strlen(fname) - 1] = '\0';
+        }
+        if (sectors <= 0 ||
+            (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
+            (strcmp(access, "RW"))) {
+            goto next_line;
+        }
+
+        path_combine(extent_path, sizeof(extent_path),
+                desc_file_path, fname);
+        ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
+        if (ret) {
+            return ret;
+        }
 
+        /* save to extents array */
+        if (!strcmp(type, "FLAT")) {
+            /* FLAT extent */
+            VmdkExtent *extent;
+
+            extent = vmdk_add_extent(bs, extent_file, true, sectors,
+                            0, 0, 0, 0, sectors);
+            extent->flat_start_offset = flat_offset << 9;
+        } else if (!strcmp(type, "SPARSE")) {
+            /* SPARSE extent */
+            ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
+            if (ret) {
+                bdrv_delete(extent_file);
+                return ret;
+            }
+        } else {
+            fprintf(stderr,
+                "VMDK: Not supported extent type \"%s\""".\n", type);
+            return -ENOTSUP;
+        }
+next_line:
+        /* move to next line */
+        while (*p && *p != '\n') {
+            p++;
+        }
+        p++;
+    }
     return 0;
 }
 
-static int vmdk_open(BlockDriverState *bs, int flags)
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
+                               int64_t desc_offset)
 {
+    int ret;
+    char buf[2048];
+    char ct[128];
     BDRVVmdkState *s = bs->opaque;
-    uint32_t magic;
-    int l1_size, i;
-
-    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic))
-        goto fail;
 
-    magic = be32_to_cpu(magic);
-    if (magic == VMDK3_MAGIC) {
-        VMDK3Header header;
+    ret = bdrv_pread(bs->file, desc_offset, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+    buf[2047] = '\0';
+    if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
+        return -EINVAL;
+    }
+    if (strcmp(ct, "monolithicFlat") &&
+        strcmp(ct, "twoGbMaxExtentSparse") &&
+        strcmp(ct, "twoGbMaxExtentFlat")) {
+        fprintf(stderr,
+                "VMDK: Not supported image type \"%s\""".\n", ct);
+        return -ENOTSUP;
+    }
+    s->desc_offset = 0;
+    return vmdk_parse_extents(buf, bs, bs->file->filename);
+}
 
-        if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
-            goto fail;
-        s->cluster_sectors = le32_to_cpu(header.granularity);
-        s->l2_size = 1 << 9;
-        s->l1_size = 1 << 6;
-        bs->total_sectors = le32_to_cpu(header.disk_sectors);
-        s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
-        s->l1_backup_table_offset = 0;
-        s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
-    } else if (magic == VMDK4_MAGIC) {
-        VMDK4Header header;
-
-        if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
-            goto fail;
-        bs->total_sectors = le64_to_cpu(header.capacity);
-        s->cluster_sectors = le64_to_cpu(header.granularity);
-        s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
-        s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
-        if (s->l1_entry_sectors <= 0)
-            goto fail;
-        s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
-            / s->l1_entry_sectors;
-        s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
-        s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
+static int vmdk_open(BlockDriverState *bs, int flags)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
 
-        // try to open parent images, if exist
-        if (vmdk_parent_open(bs) != 0)
-            goto fail;
-        // write the CID once after the image creation
-        s->parent_cid = vmdk_read_cid(bs,1);
+    if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
+        s->desc_offset = 0x200;
     } else {
-        goto fail;
+        ret = vmdk_open_desc_file(bs, flags, 0);
+        if (ret) {
+            goto fail;
+        }
     }
-
-    /* read the L1 table */
-    l1_size = s->l1_size * sizeof(uint32_t);
-    s->l1_table = qemu_malloc(l1_size);
-    if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
+    /* try to open parent images, if exist */
+    ret = vmdk_parent_open(bs);
+    if (ret) {
         goto fail;
-    for(i = 0; i < s->l1_size; i++) {
-        le32_to_cpus(&s->l1_table[i]);
     }
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    qemu_co_mutex_init(&s->lock);
 
-    if (s->l1_backup_table_offset) {
-        s->l1_backup_table = qemu_malloc(l1_size);
-        if (bdrv_pread(bs->file, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
-            goto fail;
-        for(i = 0; i < s->l1_size; i++) {
-            le32_to_cpus(&s->l1_backup_table[i]);
-        }
-    }
+    /* Disable migration when VMDK images are used */
+    error_set(&s->migration_blocker,
+              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+              "vmdk", bs->device_name, "live migration");
+    migrate_add_blocker(s->migration_blocker);
 
-    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
     return 0;
- fail:
-    qemu_free(s->l1_backup_table);
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    return -1;
-}
 
-static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
-                                   uint64_t offset, int allocate);
+fail:
+    vmdk_free_extents(bs);
+    return ret;
+}
 
-static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
-                             uint64_t offset, int allocate)
+static int get_whole_cluster(BlockDriverState *bs,
+                VmdkExtent *extent,
+                uint64_t cluster_offset,
+                uint64_t offset,
+                bool allocate)
 {
-    BDRVVmdkState *s = bs->opaque;
-    uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB
+    /* 128 sectors * 512 bytes each = grain size 64KB */
+    uint8_t  whole_grain[extent->cluster_sectors * 512];
 
-    // we will be here if it's first write on non-exist grain(cluster).
-    // try to read from parent image, if exist
+    /* we will be here if it's first write on non-exist grain(cluster).
+     * try to read from parent image, if exist */
     if (bs->backing_hd) {
         int ret;
 
-        if (!vmdk_is_cid_valid(bs))
+        if (!vmdk_is_cid_valid(bs)) {
             return -1;
+        }
 
+        /* floor offset to cluster */
+        offset -= offset % (extent->cluster_sectors * 512);
         ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
-            s->cluster_sectors);
+                extent->cluster_sectors);
         if (ret < 0) {
             return -1;
         }
 
-        //Write grain only into the active image
-        ret = bdrv_write(bs->file, cluster_offset, whole_grain,
-            s->cluster_sectors);
+        /* Write grain only into the active image */
+        ret = bdrv_write(extent->file, cluster_offset, whole_grain,
+                extent->cluster_sectors);
         if (ret < 0) {
             return -1;
         }
@@ -465,85 +711,115 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
     return 0;
 }
 
-static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
+static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
 {
-    BDRVVmdkState *s = bs->opaque;
-
     /* update L2 table */
-    if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                    &(m_data->offset), sizeof(m_data->offset)) < 0)
+    if (bdrv_pwrite_sync(
+                extent->file,
+                ((int64_t)m_data->l2_offset * 512)
+                    + (m_data->l2_index * sizeof(m_data->offset)),
+                &(m_data->offset),
+                sizeof(m_data->offset)
+            ) < 0) {
         return -1;
+    }
     /* update backup L2 table */
-    if (s->l1_backup_table_offset != 0) {
-        m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
-        if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                        &(m_data->offset), sizeof(m_data->offset)) < 0)
+    if (extent->l1_backup_table_offset != 0) {
+        m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
+        if (bdrv_pwrite_sync(
+                    extent->file,
+                    ((int64_t)m_data->l2_offset * 512)
+                        + (m_data->l2_index * sizeof(m_data->offset)),
+                    &(m_data->offset), sizeof(m_data->offset)
+                ) < 0) {
             return -1;
+        }
     }
 
     return 0;
 }
 
-static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
-                                   uint64_t offset, int allocate)
+static int get_cluster_offset(BlockDriverState *bs,
+                                    VmdkExtent *extent,
+                                    VmdkMetaData *m_data,
+                                    uint64_t offset,
+                                    int allocate,
+                                    uint64_t *cluster_offset)
 {
-    BDRVVmdkState *s = bs->opaque;
     unsigned int l1_index, l2_offset, l2_index;
     int min_index, i, j;
     uint32_t min_count, *l2_table, tmp = 0;
-    uint64_t cluster_offset;
 
-    if (m_data)
+    if (m_data) {
         m_data->valid = 0;
-
-    l1_index = (offset >> 9) / s->l1_entry_sectors;
-    if (l1_index >= s->l1_size)
-        return 0;
-    l2_offset = s->l1_table[l1_index];
-    if (!l2_offset)
+    }
+    if (extent->flat) {
+        *cluster_offset = extent->flat_start_offset;
         return 0;
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (l2_offset == s->l2_cache_offsets[i]) {
+    }
+
+    offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;
+    l1_index = (offset >> 9) / extent->l1_entry_sectors;
+    if (l1_index >= extent->l1_size) {
+        return -1;
+    }
+    l2_offset = extent->l1_table[l1_index];
+    if (!l2_offset) {
+        return -1;
+    }
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (l2_offset == extent->l2_cache_offsets[i]) {
             /* increment the hit count */
-            if (++s->l2_cache_counts[i] == 0xffffffff) {
-                for(j = 0; j < L2_CACHE_SIZE; j++) {
-                    s->l2_cache_counts[j] >>= 1;
+            if (++extent->l2_cache_counts[i] == 0xffffffff) {
+                for (j = 0; j < L2_CACHE_SIZE; j++) {
+                    extent->l2_cache_counts[j] >>= 1;
                 }
             }
-            l2_table = s->l2_cache + (i * s->l2_size);
+            l2_table = extent->l2_cache + (i * extent->l2_size);
             goto found;
         }
     }
     /* not found: load a new entry in the least used one */
     min_index = 0;
     min_count = 0xffffffff;
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (s->l2_cache_counts[i] < min_count) {
-            min_count = s->l2_cache_counts[i];
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (extent->l2_cache_counts[i] < min_count) {
+            min_count = extent->l2_cache_counts[i];
             min_index = i;
         }
     }
-    l2_table = s->l2_cache + (min_index * s->l2_size);
-    if (bdrv_pread(bs->file, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
-                                                                        s->l2_size * sizeof(uint32_t))
-        return 0;
+    l2_table = extent->l2_cache + (min_index * extent->l2_size);
+    if (bdrv_pread(
+                extent->file,
+                (int64_t)l2_offset * 512,
+                l2_table,
+                extent->l2_size * sizeof(uint32_t)
+            ) != extent->l2_size * sizeof(uint32_t)) {
+        return -1;
+    }
 
-    s->l2_cache_offsets[min_index] = l2_offset;
-    s->l2_cache_counts[min_index] = 1;
+    extent->l2_cache_offsets[min_index] = l2_offset;
+    extent->l2_cache_counts[min_index] = 1;
  found:
-    l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
-    cluster_offset = le32_to_cpu(l2_table[l2_index]);
+    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
+    *cluster_offset = le32_to_cpu(l2_table[l2_index]);
 
-    if (!cluster_offset) {
-        if (!allocate)
-            return 0;
+    if (!*cluster_offset) {
+        if (!allocate) {
+            return -1;
+        }
 
-        // Avoid the L2 tables update for the images that have snapshots.
-        cluster_offset = bdrv_getlength(bs->file);
-        bdrv_truncate(bs->file, cluster_offset + (s->cluster_sectors << 9));
+        /* Avoid the L2 tables update for the images that have snapshots. */
+        *cluster_offset = bdrv_getlength(extent->file);
+        if (!extent->compressed) {
+            bdrv_truncate(
+                extent->file,
+                *cluster_offset + (extent->cluster_sectors << 9)
+            );
+        }
 
-        cluster_offset >>= 9;
-        tmp = cpu_to_le32(cluster_offset);
+        *cluster_offset >>= 9;
+        tmp = cpu_to_le32(*cluster_offset);
         l2_table[l2_index] = tmp;
 
         /* First of all we write grain itself, to avoid race condition
@@ -551,8 +827,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
          * This problem may occur because of insufficient space on host disk
          * or inappropriate VM shutdown.
          */
-        if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
-            return 0;
+        if (get_whole_cluster(
+                bs, extent, *cluster_offset, offset, allocate) == -1) {
+            return -1;
+        }
 
         if (m_data) {
             m_data->offset = tmp;
@@ -562,53 +840,202 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
             m_data->valid = 1;
         }
     }
-    cluster_offset <<= 9;
-    return cluster_offset;
+    *cluster_offset <<= 9;
+    return 0;
+}
+
+static VmdkExtent *find_extent(BDRVVmdkState *s,
+                                int64_t sector_num, VmdkExtent *start_hint)
+{
+    VmdkExtent *extent = start_hint;
+
+    if (!extent) {
+        extent = &s->extents[0];
+    }
+    while (extent < &s->extents[s->num_extents]) {
+        if (sector_num < extent->end_sector) {
+            return extent;
+        }
+        extent++;
+    }
+    return NULL;
 }
 
 static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum)
 {
     BDRVVmdkState *s = bs->opaque;
-    int index_in_cluster, n;
-    uint64_t cluster_offset;
+    int64_t index_in_cluster, n, ret;
+    uint64_t offset;
+    VmdkExtent *extent;
 
-    cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
-    index_in_cluster = sector_num % s->cluster_sectors;
-    n = s->cluster_sectors - index_in_cluster;
-    if (n > nb_sectors)
+    extent = find_extent(s, sector_num, NULL);
+    if (!extent) {
+        return 0;
+    }
+    ret = get_cluster_offset(bs, extent, NULL,
+                            sector_num * 512, 0, &offset);
+    /* get_cluster_offset returning 0 means success */
+    ret = !ret;
+
+    index_in_cluster = sector_num % extent->cluster_sectors;
+    n = extent->cluster_sectors - index_in_cluster;
+    if (n > nb_sectors) {
         n = nb_sectors;
+    }
     *pnum = n;
-    return (cluster_offset != 0);
+    return ret;
+}
+
+static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
+                            int64_t offset_in_cluster, const uint8_t *buf,
+                            int nb_sectors, int64_t sector_num)
+{
+    int ret;
+    VmdkGrainMarker *data = NULL;
+    uLongf buf_len;
+    const uint8_t *write_buf = buf;
+    int write_len = nb_sectors * 512;
+
+    if (extent->compressed) {
+        if (!extent->has_marker) {
+            ret = -EINVAL;
+            goto out;
+        }
+        buf_len = (extent->cluster_sectors << 9) * 2;
+        data = g_malloc(buf_len + sizeof(VmdkGrainMarker));
+        if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK ||
+                buf_len == 0) {
+            ret = -EINVAL;
+            goto out;
+        }
+        data->lba = sector_num;
+        data->size = buf_len;
+        write_buf = (uint8_t *)data;
+        write_len = buf_len + sizeof(VmdkGrainMarker);
+    }
+    ret = bdrv_pwrite(extent->file,
+                        cluster_offset + offset_in_cluster,
+                        write_buf,
+                        write_len);
+    if (ret != write_len) {
+        ret = ret < 0 ? ret : -EIO;
+        goto out;
+    }
+    ret = 0;
+ out:
+    g_free(data);
+    return ret;
+}
+
+static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
+                            int64_t offset_in_cluster, uint8_t *buf,
+                            int nb_sectors)
+{
+    int ret;
+    int cluster_bytes, buf_bytes;
+    uint8_t *cluster_buf, *compressed_data;
+    uint8_t *uncomp_buf;
+    uint32_t data_len;
+    VmdkGrainMarker *marker;
+    uLongf buf_len;
+
+
+    if (!extent->compressed) {
+        ret = bdrv_pread(extent->file,
+                          cluster_offset + offset_in_cluster,
+                          buf, nb_sectors * 512);
+        if (ret == nb_sectors * 512) {
+            return 0;
+        } else {
+            return -EIO;
+        }
+    }
+    cluster_bytes = extent->cluster_sectors * 512;
+    /* Read two clusters in case GrainMarker + compressed data > one cluster */
+    buf_bytes = cluster_bytes * 2;
+    cluster_buf = g_malloc(buf_bytes);
+    uncomp_buf = g_malloc(cluster_bytes);
+    ret = bdrv_pread(extent->file,
+                cluster_offset,
+                cluster_buf, buf_bytes);
+    if (ret < 0) {
+        goto out;
+    }
+    compressed_data = cluster_buf;
+    buf_len = cluster_bytes;
+    data_len = cluster_bytes;
+    if (extent->has_marker) {
+        marker = (VmdkGrainMarker *)cluster_buf;
+        compressed_data = marker->data;
+        data_len = le32_to_cpu(marker->size);
+    }
+    if (!data_len || data_len > buf_bytes) {
+        ret = -EINVAL;
+        goto out;
+    }
+    ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len);
+    if (ret != Z_OK) {
+        ret = -EINVAL;
+        goto out;
+
+    }
+    if (offset_in_cluster < 0 ||
+            offset_in_cluster + nb_sectors * 512 > buf_len) {
+        ret = -EINVAL;
+        goto out;
+    }
+    memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512);
+    ret = 0;
+
+ out:
+    g_free(uncomp_buf);
+    g_free(cluster_buf);
+    return ret;
 }
 
 static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    int index_in_cluster, n, ret;
+    int ret;
+    uint64_t n, index_in_cluster;
+    VmdkExtent *extent = NULL;
     uint64_t cluster_offset;
 
     while (nb_sectors > 0) {
-        cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
-        index_in_cluster = sector_num % s->cluster_sectors;
-        n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                            bs, extent, NULL,
+                            sector_num << 9, 0, &cluster_offset);
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
             n = nb_sectors;
-        if (!cluster_offset) {
-            // try to read from parent image, if exist
+        }
+        if (ret) {
+            /* if not allocated, try to read from parent image, if exist */
             if (bs->backing_hd) {
-                if (!vmdk_is_cid_valid(bs))
-                    return -1;
+                if (!vmdk_is_cid_valid(bs)) {
+                    return -EINVAL;
+                }
                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
-                if (ret < 0)
-                    return -1;
+                if (ret < 0) {
+                    return ret;
+                }
             } else {
                 memset(buf, 0, 512 * n);
             }
         } else {
-            if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
-                return -1;
+            ret = vmdk_read_extent(extent,
+                            cluster_offset, index_in_cluster * 512,
+                            buf, n);
+            if (ret) {
+                return ret;
+            }
         }
         nb_sectors -= n;
         sector_num += n;
@@ -617,114 +1044,149 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
+                                     uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    VmdkMetaData m_data;
-    int index_in_cluster, n;
+    VmdkExtent *extent = NULL;
+    int n, ret;
+    int64_t index_in_cluster;
     uint64_t cluster_offset;
-    static int cid_update = 0;
+    VmdkMetaData m_data;
 
     if (sector_num > bs->total_sectors) {
         fprintf(stderr,
                 "(VMDK) Wrong offset: sector_num=0x%" PRIx64
                 " total_sectors=0x%" PRIx64 "\n",
                 sector_num, bs->total_sectors);
-        return -1;
+        return -EIO;
     }
 
     while (nb_sectors > 0) {
-        index_in_cluster = sector_num & (s->cluster_sectors - 1);
-        n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                                bs,
+                                extent,
+                                &m_data,
+                                sector_num << 9, !extent->compressed,
+                                &cluster_offset);
+        if (extent->compressed) {
+            if (ret == 0) {
+                /* Refuse write to allocated cluster for streamOptimized */
+                fprintf(stderr,
+                        "VMDK: can't write to allocated cluster"
+                        " for streamOptimized\n");
+                return -EIO;
+            } else {
+                /* allocate */
+                ret = get_cluster_offset(
+                                        bs,
+                                        extent,
+                                        &m_data,
+                                        sector_num << 9, 1,
+                                        &cluster_offset);
+            }
+        }
+        if (ret) {
+            return -EINVAL;
+        }
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
             n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
-        if (!cluster_offset)
-            return -1;
+        }
 
-        if (bdrv_pwrite(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
-            return -1;
+        ret = vmdk_write_extent(extent,
+                        cluster_offset, index_in_cluster * 512,
+                        buf, n, sector_num);
+        if (ret) {
+            return ret;
+        }
         if (m_data.valid) {
             /* update L2 tables */
-            if (vmdk_L2update(bs, &m_data) == -1)
-                return -1;
+            if (vmdk_L2update(extent, &m_data) == -1) {
+                return -EIO;
+            }
         }
         nb_sectors -= n;
         sector_num += n;
         buf += n * 512;
 
-        // update CID on the first write every time the virtual disk is opened
-        if (!cid_update) {
-            vmdk_write_cid(bs, time(NULL));
-            cid_update++;
+        /* update CID on the first write every time the virtual disk is
+         * opened */
+        if (!s->cid_updated) {
+            ret = vmdk_write_cid(bs, time(NULL));
+            if (ret < 0) {
+                return ret;
+            }
+            s->cid_updated = true;
         }
     }
     return 0;
 }
 
-static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
+                                      const uint8_t *buf, int nb_sectors)
 {
-    int fd, i;
-    VMDK4Header header;
-    uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
-    static const char desc_template[] =
-        "# Disk DescriptorFile\n"
-        "version=1\n"
-        "CID=%x\n"
-        "parentCID=ffffffff\n"
-        "createType=\"monolithicSparse\"\n"
-        "\n"
-        "# Extent description\n"
-        "RW %" PRId64 " SPARSE \"%s\"\n"
-        "\n"
-        "# The Disk Data Base \n"
-        "#DDB\n"
-        "\n"
-        "ddb.virtualHWVersion = \"%d\"\n"
-        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
-        "ddb.geometry.heads = \"16\"\n"
-        "ddb.geometry.sectors = \"63\"\n"
-        "ddb.adapterType = \"ide\"\n";
-    char desc[1024];
-    const char *real_filename, *temp_str;
-    int64_t total_size = 0;
-    const char *backing_file = NULL;
-    int flags = 0;
     int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
 
-    // Read out options
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / 512;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
-            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
-        }
-        options++;
-    }
 
-    /* XXX: add support for backing file */
-    if (backing_file) {
-        return vmdk_snapshot_create(filename, backing_file);
-    }
+static int vmdk_create_extent(const char *filename, int64_t filesize,
+                              bool flat, bool compress)
+{
+    int ret, i;
+    int fd = 0;
+    VMDK4Header header;
+    uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
-              0644);
-    if (fd < 0)
+    fd = open(
+        filename,
+        O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+        0644);
+    if (fd < 0) {
         return -errno;
+    }
+    if (flat) {
+        ret = ftruncate(fd, filesize);
+        if (ret < 0) {
+            ret = -errno;
+        }
+        goto exit;
+    }
     magic = cpu_to_be32(VMDK4_MAGIC);
     memset(&header, 0, sizeof(header));
-    header.version = cpu_to_le32(1);
-    header.flags = cpu_to_le32(3); /* ?? */
-    header.capacity = cpu_to_le64(total_size);
-    header.granularity = cpu_to_le64(128);
-    header.num_gtes_per_gte = cpu_to_le32(512);
-
-    grains = (total_size + header.granularity - 1) / header.granularity;
+    header.version = 1;
+    header.flags =
+        3 | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0);
+    header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0;
+    header.capacity = filesize / 512;
+    header.granularity = 128;
+    header.num_gtes_per_gte = 512;
+
+    grains = (filesize / 512 + header.granularity - 1) / header.granularity;
     gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
-    gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
+    gt_count =
+        (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
     gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
 
     header.desc_offset = 1;
@@ -735,12 +1197,18 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
        ((header.gd_offset + gd_size + (gt_size * gt_count) +
          header.granularity - 1) / header.granularity) *
         header.granularity;
-
+    /* swap endianness for all header fields */
+    header.version = cpu_to_le32(header.version);
+    header.flags = cpu_to_le32(header.flags);
+    header.capacity = cpu_to_le64(header.capacity);
+    header.granularity = cpu_to_le64(header.granularity);
+    header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
     header.desc_offset = cpu_to_le64(header.desc_offset);
     header.desc_size = cpu_to_le64(header.desc_size);
     header.rgd_offset = cpu_to_le64(header.rgd_offset);
     header.gd_offset = cpu_to_le64(header.gd_offset);
     header.grain_offset = cpu_to_le64(header.grain_offset);
+    header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm);
 
     header.check_bytes[0] = 0xa;
     header.check_bytes[1] = 0x20;
@@ -759,7 +1227,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
         goto exit;
     }
 
-    ret = ftruncate(fd, header.grain_offset << 9);
+    ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
     if (ret < 0) {
         ret = -errno;
         goto exit;
@@ -767,7 +1235,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
 
     /* write grain directory */
     lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
-    for (i = 0, tmp = header.rgd_offset + gd_size;
+    for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
          i < gt_count; i++, tmp += gt_size) {
         ret = qemu_write_full(fd, &tmp, sizeof(tmp));
         if (ret != sizeof(tmp)) {
@@ -778,7 +1246,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
 
     /* write backup grain directory */
     lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
-    for (i = 0, tmp = header.gd_offset + gd_size;
+    for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
          i < gt_count; i++, tmp += gt_size) {
         ret = qemu_write_full(fd, &tmp, sizeof(tmp));
         if (ret != sizeof(tmp)) {
@@ -787,27 +1255,256 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
         }
     }
 
-    /* compose the descriptor */
-    real_filename = filename;
-    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, '/')) != NULL)
-        real_filename = temp_str + 1;
-    if ((temp_str = strrchr(real_filename, ':')) != NULL)
-        real_filename = temp_str + 1;
-    snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
-             total_size, real_filename,
-             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
-             total_size / (int64_t)(63 * 16));
+    ret = 0;
+ exit:
+    close(fd);
+    return ret;
+}
+
+static int filename_decompose(const char *filename, char *path, char *prefix,
+        char *postfix, size_t buf_len)
+{
+    const char *p, *q;
 
-    /* write the descriptor */
-    lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
+    if (filename == NULL || !strlen(filename)) {
+        fprintf(stderr, "Vmdk: no filename provided.\n");
+        return -1;
+    }
+    p = strrchr(filename, '/');
+    if (p == NULL) {
+        p = strrchr(filename, '\\');
+    }
+    if (p == NULL) {
+        p = strrchr(filename, ':');
+    }
+    if (p != NULL) {
+        p++;
+        if (p - filename >= buf_len) {
+            return -1;
+        }
+        pstrcpy(path, p - filename + 1, filename);
+    } else {
+        p = filename;
+        path[0] = '\0';
+    }
+    q = strrchr(p, '.');
+    if (q == NULL) {
+        pstrcpy(prefix, buf_len, p);
+        postfix[0] = '\0';
+    } else {
+        if (q - p >= buf_len) {
+            return -1;
+        }
+        pstrcpy(prefix, q - p + 1, p);
+        pstrcpy(postfix, buf_len, q);
+    }
+    return 0;
+}
+
+static int relative_path(char *dest, int dest_size,
+        const char *base, const char *target)
+{
+    int i = 0;
+    int n = 0;
+    const char *p, *q;
+#ifdef _WIN32
+    const char *sep = "\\";
+#else
+    const char *sep = "/";
+#endif
+
+    if (!(dest && base && target)) {
+        return -1;
+    }
+    if (path_is_absolute(target)) {
+        dest[dest_size - 1] = '\0';
+        strncpy(dest, target, dest_size - 1);
+        return 0;
+    }
+    while (base[i] == target[i]) {
+        i++;
+    }
+    p = &base[i];
+    q = &target[i];
+    while (*p) {
+        if (*p == *sep) {
+            n++;
+        }
+        p++;
+    }
+    dest[0] = '\0';
+    for (; n; n--) {
+        pstrcat(dest, dest_size, "..");
+        pstrcat(dest, dest_size, sep);
+    }
+    pstrcat(dest, dest_size, q);
+    return 0;
+}
+
+static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd, idx = 0;
+    char desc[BUF_SIZE];
+    int64_t total_size = 0, filesize;
+    const char *backing_file = NULL;
+    const char *fmt = NULL;
+    int flags = 0;
+    int ret = 0;
+    bool flat, split, compress;
+    char ext_desc_lines[BUF_SIZE] = "";
+    char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
+    const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
+    const char *desc_extent_line;
+    char parent_desc_line[BUF_SIZE] = "";
+    uint32_t parent_cid = 0xffffffff;
+    const char desc_template[] =
+        "# Disk DescriptorFile\n"
+        "version=1\n"
+        "CID=%x\n"
+        "parentCID=%x\n"
+        "createType=\"%s\"\n"
+        "%s"
+        "\n"
+        "# Extent description\n"
+        "%s"
+        "\n"
+        "# The Disk Data Base\n"
+        "#DDB\n"
+        "\n"
+        "ddb.virtualHWVersion = \"%d\"\n"
+        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
+        "ddb.geometry.heads = \"16\"\n"
+        "ddb.geometry.sectors = \"63\"\n"
+        "ddb.adapterType = \"ide\"\n";
+
+    if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
+        return -EINVAL;
+    }
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
+            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
+        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
+            fmt = options->value.s;
+        }
+        options++;
+    }
+    if (!fmt) {
+        /* Default format to monolithicSparse */
+        fmt = "monolithicSparse";
+    } else if (strcmp(fmt, "monolithicFlat") &&
+               strcmp(fmt, "monolithicSparse") &&
+               strcmp(fmt, "twoGbMaxExtentSparse") &&
+               strcmp(fmt, "twoGbMaxExtentFlat") &&
+               strcmp(fmt, "streamOptimized")) {
+        fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
+        return -EINVAL;
+    }
+    split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
+              strcmp(fmt, "twoGbMaxExtentSparse"));
+    flat = !(strcmp(fmt, "monolithicFlat") &&
+             strcmp(fmt, "twoGbMaxExtentFlat"));
+    compress = !strcmp(fmt, "streamOptimized");
+    if (flat) {
+        desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
+    } else {
+        desc_extent_line = "RW %lld SPARSE \"%s\"\n";
+    }
+    if (flat && backing_file) {
+        /* not supporting backing file for flat image */
+        return -ENOTSUP;
+    }
+    if (backing_file) {
+        char parent_filename[PATH_MAX];
+        BlockDriverState *bs = bdrv_new("");
+        ret = bdrv_open(bs, backing_file, 0, NULL);
+        if (ret != 0) {
+            bdrv_delete(bs);
+            return ret;
+        }
+        if (strcmp(bs->drv->format_name, "vmdk")) {
+            bdrv_delete(bs);
+            return -EINVAL;
+        }
+        parent_cid = vmdk_read_cid(bs, 0);
+        bdrv_delete(bs);
+        relative_path(parent_filename, sizeof(parent_filename),
+                      filename, backing_file);
+        snprintf(parent_desc_line, sizeof(parent_desc_line),
+                "parentFileNameHint=\"%s\"", parent_filename);
+    }
+
+    /* Create extents */
+    filesize = total_size;
+    while (filesize > 0) {
+        char desc_line[BUF_SIZE];
+        char ext_filename[PATH_MAX];
+        char desc_filename[PATH_MAX];
+        int64_t size = filesize;
+
+        if (split && size > split_size) {
+            size = split_size;
+        }
+        if (split) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
+                    prefix, flat ? 'f' : 's', ++idx, postfix);
+        } else if (flat) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
+                    prefix, postfix);
+        } else {
+            snprintf(desc_filename, sizeof(desc_filename), "%s%s",
+                    prefix, postfix);
+        }
+        snprintf(ext_filename, sizeof(ext_filename), "%s%s",
+                path, desc_filename);
+
+        if (vmdk_create_extent(ext_filename, size, flat, compress)) {
+            return -EINVAL;
+        }
+        filesize -= size;
+
+        /* Format description line */
+        snprintf(desc_line, sizeof(desc_line),
+                    desc_extent_line, size / 512, desc_filename);
+        pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
+    }
+    /* generate descriptor file */
+    snprintf(desc, sizeof(desc), desc_template,
+            (unsigned int)time(NULL),
+            parent_cid,
+            fmt,
+            parent_desc_line,
+            ext_desc_lines,
+            (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
+            total_size / (int64_t)(63 * 16 * 512));
+    if (split || flat) {
+        fd = open(
+                filename,
+                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                0644);
+    } else {
+        fd = open(
+                filename,
+                O_WRONLY | O_BINARY | O_LARGEFILE,
+                0644);
+    }
+    if (fd < 0) {
+        return -errno;
+    }
+    /* the descriptor offset = 0x200 */
+    if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
+        ret = -errno;
+        goto exit;
+    }
     ret = qemu_write_full(fd, desc, strlen(desc));
     if (ret != strlen(desc)) {
         ret = -errno;
         goto exit;
     }
-
     ret = 0;
 exit:
     close(fd);
@@ -818,15 +1515,50 @@ static void vmdk_close(BlockDriverState *bs)
 {
     BDRVVmdkState *s = bs->opaque;
 
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
+    vmdk_free_extents(bs);
+
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
 }
 
-static int vmdk_flush(BlockDriverState *bs)
+static coroutine_fn int vmdk_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    int i, ret, err;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_co_flush(bs->file);
+    for (i = 0; i < s->num_extents; i++) {
+        err = bdrv_co_flush(s->extents[i].file);
+        if (err < 0) {
+            ret = err;
+        }
+    }
+    return ret;
 }
 
+static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
+{
+    int i;
+    int64_t ret = 0;
+    int64_t r;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_get_allocated_file_size(bs->file);
+    if (ret < 0) {
+        return ret;
+    }
+    for (i = 0; i < s->num_extents; i++) {
+        if (s->extents[i].file == bs->file) {
+            continue;
+        }
+        r = bdrv_get_allocated_file_size(s->extents[i].file);
+        if (r < 0) {
+            return r;
+        }
+        ret += r;
+    }
+    return ret;
+}
 
 static QEMUOptionParameter vmdk_create_options[] = {
     {
@@ -844,20 +1576,28 @@ static QEMUOptionParameter vmdk_create_options[] = {
         .type = OPT_FLAG,
         .help = "VMDK version 6 image"
     },
+    {
+        .name = BLOCK_OPT_SUBFMT,
+        .type = OPT_STRING,
+        .help =
+            "VMDK flat extent format, can be one of "
+            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
+    },
     { NULL }
 };
 
 static BlockDriver bdrv_vmdk = {
-    .format_name       = "vmdk",
-    .instance_size     = sizeof(BDRVVmdkState),
-    .bdrv_probe                = vmdk_probe,
+    .format_name    = "vmdk",
+    .instance_size  = sizeof(BDRVVmdkState),
+    .bdrv_probe     = vmdk_probe,
     .bdrv_open      = vmdk_open,
-    .bdrv_read         = vmdk_read,
-    .bdrv_write                = vmdk_write,
-    .bdrv_close                = vmdk_close,
-    .bdrv_create       = vmdk_create,
-    .bdrv_flush                = vmdk_flush,
-    .bdrv_is_allocated = vmdk_is_allocated,
+    .bdrv_read      = vmdk_co_read,
+    .bdrv_write     = vmdk_co_write,
+    .bdrv_close     = vmdk_close,
+    .bdrv_create    = vmdk_create,
+    .bdrv_co_flush_to_disk  = vmdk_co_flush,
+    .bdrv_is_allocated      = vmdk_is_allocated,
+    .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
 
     .create_options = vmdk_create_options,
 };
index 7b025be01d967fc4b8a3bfe99140542118e52aa5..89a5ee26686a08252765de544a8aac4078a4e8f5 100644 (file)
@@ -25,6 +25,7 @@
 #include "qemu-common.h"
 #include "block_int.h"
 #include "module.h"
+#include "migration.h"
 
 /**************************************************************/
 
@@ -110,6 +111,7 @@ struct vhd_dyndisk_header {
 };
 
 typedef struct BDRVVPCState {
+    CoMutex lock;
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -127,6 +129,8 @@ typedef struct BDRVVPCState {
 
     uint64_t last_bitmap;
 #endif
+
+    Error *migration_blocker;
 } BDRVVPCState;
 
 static uint32_t vpc_checksum(uint8_t* buf, size_t size)
@@ -156,6 +160,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     struct vhd_dyndisk_header* dyndisk_header;
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
+    int err = -1;
 
     if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
@@ -176,6 +181,11 @@ static int vpc_open(BlockDriverState *bs, int flags)
     bs->total_sectors = (int64_t)
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
 
+    if (bs->total_sectors >= 65535 * 16 * 255) {
+        err = -EFBIG;
+        goto fail;
+    }
+
     if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
             != HEADER_SIZE)
         goto fail;
@@ -190,7 +200,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
 
     s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
-    s->pagetable = qemu_malloc(s->max_table_entries * 4);
+    s->pagetable = g_malloc(s->max_table_entries * 4);
 
     s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
     if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
@@ -214,15 +224,23 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->last_bitmap_offset = (int64_t) -1;
 
 #ifdef CACHE
-    s->pageentry_u8 = qemu_malloc(512);
+    s->pageentry_u8 = g_malloc(512);
     s->pageentry_u32 = s->pageentry_u8;
     s->pageentry_u16 = s->pageentry_u8;
     s->last_pagetable = -1;
 #endif
 
+    qemu_co_mutex_init(&s->lock);
+
+    /* Disable migration when VHD images are used */
+    error_set(&s->migration_blocker,
+              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+              "vpc", bs->device_name, "live migration");
+    migrate_add_blocker(s->migration_blocker);
+
     return 0;
  fail:
-    return -1;
+    return err;
 }
 
 /*
@@ -344,8 +362,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 
     // Initialize the block's bitmap
     memset(bitmap, 0xff, s->bitmap_size);
-    bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+    ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
         s->bitmap_size);
+    if (ret < 0) {
+        return ret;
+    }
 
     // Write new footer (the old one will be overwritten)
     s->free_data_block_offset += s->block_size + s->bitmap_size;
@@ -401,6 +422,17 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors)
 {
@@ -437,9 +469,20 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static int vpc_flush(BlockDriverState *bs)
+static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
 {
-    return bdrv_flush(bs->file);
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
+static coroutine_fn int vpc_co_flush(BlockDriverState *bs)
+{
+    return bdrv_co_flush(bs->file);
 }
 
 /*
@@ -505,12 +548,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);
@@ -591,7 +630,11 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
 
     memcpy(dyndisk_header->magic, "cxsparse", 8);
 
-    dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
+    /*
+     * Note: The spec is actually wrong here for data_offset, it says
+     * 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
+     */
+    dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
     dyndisk_header->table_offset = be64_to_cpu(3 * 512);
     dyndisk_header->version = be32_to_cpu(0x00010000);
     dyndisk_header->block_size = be32_to_cpu(block_size);
@@ -617,10 +660,13 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
 static void vpc_close(BlockDriverState *bs)
 {
     BDRVVPCState *s = bs->opaque;
-    qemu_free(s->pagetable);
+    g_free(s->pagetable);
 #ifdef CACHE
-    qemu_free(s->pageentry_u8);
+    g_free(s->pageentry_u8);
 #endif
+
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
 }
 
 static QEMUOptionParameter vpc_create_options[] = {
@@ -635,14 +681,16 @@ static QEMUOptionParameter vpc_create_options[] = {
 static BlockDriver bdrv_vpc = {
     .format_name    = "vpc",
     .instance_size  = sizeof(BDRVVPCState),
+
     .bdrv_probe     = vpc_probe,
     .bdrv_open      = vpc_open,
-    .bdrv_read      = vpc_read,
-    .bdrv_write     = vpc_write,
-    .bdrv_flush     = vpc_flush,
     .bdrv_close     = vpc_close,
     .bdrv_create    = vpc_create,
 
+    .bdrv_read              = vpc_co_read,
+    .bdrv_write             = vpc_co_write,
+    .bdrv_co_flush_to_disk  = vpc_co_flush,
+
     .create_options = vpc_create_options,
 };
 
index fe568fe2c7548556a202cb33b7e0c1c4243396fa..a310ce8c3ef99f76cb74943a8934267df6a5d833 100644 (file)
@@ -27,6 +27,7 @@
 #include "qemu-common.h"
 #include "block_int.h"
 #include "module.h"
+#include "migration.h"
 
 #ifndef S_IWGRP
 #define S_IWGRP 0
@@ -86,8 +87,7 @@ static inline void array_init(array_t* array,unsigned int item_size)
 
 static inline void array_free(array_t* array)
 {
-    if(array->pointer)
-        free(array->pointer);
+    g_free(array->pointer);
     array->size=array->next=0;
 }
 
@@ -101,7 +101,7 @@ static inline int array_ensure_allocated(array_t* array, int index)
 {
     if((index + 1) * array->item_size > array->size) {
        int new_size = (index + 32) * array->item_size;
-       array->pointer = qemu_realloc(array->pointer, new_size);
+       array->pointer = g_realloc(array->pointer, new_size);
        if (!array->pointer)
            return -1;
        array->size = new_size;
@@ -127,7 +127,7 @@ static inline void* array_get_next(array_t* array) {
 static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
     if((array->next+count)*array->item_size>array->size) {
        int increment=count*array->item_size;
-       array->pointer=qemu_realloc(array->pointer,array->size+increment);
+       array->pointer=g_realloc(array->pointer,array->size+increment);
        if(!array->pointer)
             return NULL;
        array->size+=increment;
@@ -159,7 +159,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
     is=array->item_size;
     from=array->pointer+index_from*is;
     to=array->pointer+index_to*is;
-    buf=qemu_malloc(is*count);
+    buf=g_malloc(is*count);
     memcpy(buf,from,is*count);
 
     if(index_to<index_from)
@@ -169,7 +169,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
 
     memcpy(to,buf,is*count);
 
-    free(buf);
+    g_free(buf);
 
     return 0;
 }
@@ -200,7 +200,7 @@ static int array_index(array_t* array, void* pointer)
 }
 
 /* These structures are used to fake a disk and the VFAT filesystem.
- * For this reason we need to use __attribute__((packed)). */
+ * For this reason we need to use QEMU_PACKED. */
 
 typedef struct bootsector_t {
     uint8_t jump[3];
@@ -224,7 +224,7 @@ typedef struct bootsector_t {
            uint8_t signature;
            uint32_t id;
            uint8_t volume_label[11];
-       } __attribute__((packed)) fat16;
+       } QEMU_PACKED fat16;
        struct {
            uint32_t sectors_per_fat;
            uint16_t flags;
@@ -233,12 +233,12 @@ typedef struct bootsector_t {
            uint16_t info_sector;
            uint16_t backup_boot_sector;
            uint16_t ignored;
-       } __attribute__((packed)) fat32;
+       } QEMU_PACKED fat32;
     } u;
     uint8_t fat_type[8];
     uint8_t ignored[0x1c0];
     uint8_t magic[2];
-} __attribute__((packed)) bootsector_t;
+} QEMU_PACKED bootsector_t;
 
 typedef struct {
     uint8_t head;
@@ -253,7 +253,7 @@ typedef struct partition_t {
     mbr_chs_t end_CHS;
     uint32_t start_sector_long;
     uint32_t length_sector_long;
-} __attribute__((packed)) partition_t;
+} QEMU_PACKED partition_t;
 
 typedef struct mbr_t {
     uint8_t ignored[0x1b8];
@@ -261,7 +261,7 @@ typedef struct mbr_t {
     uint8_t ignored2[2];
     partition_t partition[4];
     uint8_t magic[2];
-} __attribute__((packed)) mbr_t;
+} QEMU_PACKED mbr_t;
 
 typedef struct direntry_t {
     uint8_t name[8];
@@ -276,7 +276,7 @@ typedef struct direntry_t {
     uint16_t mdate;
     uint16_t begin;
     uint32_t size;
-} __attribute__((packed)) direntry_t;
+} QEMU_PACKED direntry_t;
 
 /* this structure are used to transparently access the files */
 
@@ -318,6 +318,7 @@ static void print_mapping(const struct mapping_t* mapping);
 /* here begins the real VVFAT driver */
 
 typedef struct BDRVVVFATState {
+    CoMutex lock;
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
@@ -350,6 +351,8 @@ typedef struct BDRVVVFATState {
     array_t commits;
     const char* path;
     int downcase_short_names;
+
+    Error *migration_blocker;
 } BDRVVVFATState;
 
 /* take the sector position spos and convert it to Cylinder/Head/Sector position
@@ -728,11 +731,11 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
        if(first_cluster == 0 && (is_dotdot || is_dot))
            continue;
 
-       buffer=(char*)qemu_malloc(length);
+       buffer=(char*)g_malloc(length);
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
 
        if(stat(buffer,&st)<0) {
-           free(buffer);
+            g_free(buffer);
             continue;
        }
 
@@ -755,7 +758,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
            direntry->begin=0; /* do that later */
         if (st.st_size > 0x7fffffff) {
            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
-           free(buffer);
+            g_free(buffer);
             closedir(dir);
            return -2;
         }
@@ -799,6 +802,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
        /* root directory */
        int cur = s->directory.next;
        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
+       s->directory.next = ROOT_ENTRIES;
        memset(array_get(&(s->directory), cur), 0,
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
     }
@@ -825,20 +829,6 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
     return s->faked_sectors + s->sectors_per_cluster * cluster_num;
 }
 
-static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
-{
-    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
-}
-
-#ifdef DBG
-static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
-{
-    if(mapping->mode==MODE_UNDEFINED)
-       return 0;
-    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
-}
-#endif
-
 static int init_directories(BDRVVVFATState* s,
        const char* dirname)
 {
@@ -850,7 +840,7 @@ static int init_directories(BDRVVVFATState* s,
     memset(&(s->first_sectors[0]),0,0x40*0x200);
 
     s->cluster_size=s->sectors_per_cluster*0x200;
-    s->cluster_buffer=qemu_malloc(s->cluster_size);
+    s->cluster_buffer=g_malloc(s->cluster_size);
 
     /*
      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
@@ -884,7 +874,7 @@ static int init_directories(BDRVVVFATState* s,
     mapping->dir_index = 0;
     mapping->info.dir.parent_mapping_index = -1;
     mapping->first_mapping_index = -1;
-    mapping->path = qemu_strdup(dirname);
+    mapping->path = g_strdup(dirname);
     i = strlen(mapping->path);
     if (i > 0 && mapping->path[i - 1] == '/')
        mapping->path[i - 1] = '\0';
@@ -929,11 +919,8 @@ static int init_directories(BDRVVVFATState* s,
        cluster = mapping->end;
 
        if(cluster > s->cluster_count) {
-           fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
-                   s->fat_type,
-                   s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
-                                                               : "2.88 MB"
-                                     : "504MB");
+           fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
+                   s->fat_type, s->sector_count / 2000.0);
            return -EINVAL;
        }
 
@@ -967,7 +954,7 @@ static int init_directories(BDRVVVFATState* s,
     bootsector->number_of_fats=0x2; /* number of FATs */
     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
-    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
+    bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
     s->fat.pointer[0] = bootsector->media_type;
     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
@@ -976,7 +963,7 @@ static int init_directories(BDRVVVFATState* s,
     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
 
     /* LATER TODO: if FAT32, this is wrong */
-    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
+    bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
     bootsector->u.fat16.current_head=0;
     bootsector->u.fat16.signature=0x29;
     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
@@ -998,7 +985,6 @@ static int is_consistent(BDRVVVFATState *s);
 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
 {
     BDRVVVFATState *s = bs->opaque;
-    int floppy = 0;
     int i;
 
 #ifdef DEBUG
@@ -1012,11 +998,8 @@ DLOG(if (stderr == NULL) {
 
     s->bs = bs;
 
-    s->fat_type=16;
     /* LATER TODO: if FAT32, adjust */
     s->sectors_per_cluster=0x10;
-    /* 504MB disk*/
-    bs->cyls=1024; bs->heads=16; bs->secs=63;
 
     s->current_cluster=0xffffffff;
 
@@ -1031,16 +1014,6 @@ DLOG(if (stderr == NULL) {
     if (!strstart(dirname, "fat:", NULL))
        return -1;
 
-    if (strstr(dirname, ":floppy:")) {
-       floppy = 1;
-       s->fat_type = 12;
-       s->first_sectors_number = 1;
-       s->sectors_per_cluster=2;
-       bs->cyls = 80; bs->heads = 2; bs->secs = 36;
-    }
-
-    s->sector_count=bs->cyls*bs->heads*bs->secs;
-
     if (strstr(dirname, ":32:")) {
        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
        s->fat_type = 32;
@@ -1048,9 +1021,31 @@ DLOG(if (stderr == NULL) {
        s->fat_type = 16;
     } else if (strstr(dirname, ":12:")) {
        s->fat_type = 12;
-       s->sector_count=2880;
     }
 
+    if (strstr(dirname, ":floppy:")) {
+       /* 1.44MB or 2.88MB floppy.  2.88MB can be FAT12 (default) or FAT16. */
+       if (!s->fat_type) {
+           s->fat_type = 12;
+           bs->secs = 36;
+           s->sectors_per_cluster=2;
+       } else {
+           bs->secs=(s->fat_type == 12 ? 18 : 36);
+           s->sectors_per_cluster=1;
+       }
+       s->first_sectors_number = 1;
+       bs->cyls=80; bs->heads=2;
+    } else {
+       /* 32MB or 504MB disk*/
+       if (!s->fat_type) {
+           s->fat_type = 16;
+       }
+       bs->cyls=(s->fat_type == 12 ? 64 : 1024);
+       bs->heads=16; bs->secs=63;
+    }
+
+    s->sector_count=bs->cyls*bs->heads*bs->secs-(s->first_sectors_number-1);
+
     if (strstr(dirname, ":rw:")) {
        if (enable_write_target(s))
            return -1;
@@ -1074,12 +1069,22 @@ DLOG(if (stderr == NULL) {
 
     if(s->first_sectors_number==0x40)
        init_mbr(s);
-
-    /* for some reason or other, MS-DOS does not like to know about CHS... */
-    if (floppy)
+    else {
+        /* MS-DOS does not like to know about CHS (?). */
        bs->heads = bs->cyls = bs->secs = 0;
+    }
 
     //    assert(is_consistent(s));
+    qemu_co_mutex_init(&s->lock);
+
+    /* Disable migration when vvfat is used rw */
+    if (s->qcow) {
+        error_set(&s->migration_blocker,
+                  QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+                  "vvfat (rw)", bs->device_name, "live migration");
+        migrate_add_blocker(s->migration_blocker);
+    }
+
     return 0;
 }
 
@@ -1138,25 +1143,6 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_
     return mapping;
 }
 
-/*
- * This function simply compares path == mapping->path. Since the mappings
- * are sorted by cluster, this is expensive: O(n).
- */
-static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
-       const char* path)
-{
-    int i;
-
-    for (i = 0; i < s->mapping.next; i++) {
-       mapping_t* mapping = array_get(&(s->mapping), i);
-       if (mapping->first_mapping_index < 0 &&
-               !strcmp(path, mapping->path))
-           return mapping;
-    }
-
-    return NULL;
-}
-
 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
 {
     if(!mapping)
@@ -1223,23 +1209,6 @@ read_cluster_directory:
 }
 
 #ifdef DEBUG
-static void hexdump(const void* address, uint32_t len)
-{
-    const unsigned char* p = address;
-    int i, j;
-
-    for (i = 0; i < len; i += 16) {
-       for (j = 0; j < 16 && i + j < len; j++)
-           fprintf(stderr, "%02x ", p[i + j]);
-       for (; j < 16; j++)
-           fprintf(stderr, "   ");
-       fprintf(stderr, " ");
-       for (j = 0; j < 16 && i + j < len; j++)
-           fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
-       fprintf(stderr, "\n");
-    }
-}
-
 static void print_direntry(const direntry_t* direntry)
 {
     int j = 0;
@@ -1293,19 +1262,19 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
     int i;
 
     for(i=0;i<nb_sectors;i++,sector_num++) {
-       if (sector_num >= s->sector_count)
+       if (sector_num >= bs->total_sectors)
           return -1;
        if (s->qcow) {
            int n;
-           if (s->qcow->drv->bdrv_is_allocated(s->qcow,
-                       sector_num, nb_sectors-i, &n)) {
+            if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
-               if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
-                   return -1;
-               i += n - 1;
-               sector_num += n - 1;
-               continue;
-           }
+                if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
+                    return -1;
+                }
+                i += n - 1;
+                sector_num += n - 1;
+                continue;
+            }
 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
        }
        if(sector_num<s->faked_sectors) {
@@ -1319,7 +1288,7 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
            uint32_t sector=sector_num-s->faked_sectors,
            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
            cluster_num=sector/s->sectors_per_cluster;
-           if(read_cluster(s, cluster_num) != 0) {
+           if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
                /* LATER TODO: strict: return -1; */
                memset(buf+i*0x200,0,0x200);
                continue;
@@ -1330,6 +1299,17 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
     return 0;
 }
 
+static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 /* LATER TODO: statify all functions */
 
 /*
@@ -1375,7 +1355,7 @@ DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
        assert(commit->path || commit->action == ACTION_WRITEOUT);
        if (commit->action != ACTION_WRITEOUT) {
            assert(commit->path);
-           free(commit->path);
+            g_free(commit->path);
        } else
            assert(commit->path == NULL);
     }
@@ -1548,7 +1528,7 @@ static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
        return 0;
 
     for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
-       was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+       was_modified = bdrv_is_allocated(s->qcow,
                cluster2sector(s, cluster_num) + i, 1, &dummy);
 
     return was_modified;
@@ -1638,10 +1618,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
 
            /* rename */
            if (strcmp(basename, basename2))
-               schedule_rename(s, cluster_num, qemu_strdup(path));
+               schedule_rename(s, cluster_num, g_strdup(path));
        } else if (is_file(direntry))
            /* new file */
-           schedule_new_file(s, qemu_strdup(path), cluster_num);
+           schedule_new_file(s, g_strdup(path), cluster_num);
        else {
             abort();
            return 0;
@@ -1697,16 +1677,16 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
                int64_t offset = cluster2sector(s, cluster_num);
 
                vvfat_close_current_file(s);
-               for (i = 0; i < s->sectors_per_cluster; i++)
-                   if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
-                               offset + i, 1, &dummy)) {
-                       if (vvfat_read(s->bs,
-                                   offset, s->cluster_buffer, 1))
-                           return -1;
-                       if (s->qcow->drv->bdrv_write(s->qcow,
-                                   offset, s->cluster_buffer, 1))
-                           return -2;
-                   }
+                for (i = 0; i < s->sectors_per_cluster; i++) {
+                    if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
+                        if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
+                            return -1;
+                        }
+                        if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
+                            return -2;
+                        }
+                    }
+                }
            }
        }
 
@@ -1735,13 +1715,13 @@ static int check_directory_consistency(BDRVVVFATState *s,
        int cluster_num, const char* path)
 {
     int ret = 0;
-    unsigned char* cluster = qemu_malloc(s->cluster_size);
+    unsigned char* cluster = g_malloc(s->cluster_size);
     direntry_t* direntries = (direntry_t*)cluster;
     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
 
     long_file_name lfn;
     int path_len = strlen(path);
-    char path2[PATH_MAX];
+    char path2[PATH_MAX + 1];
 
     assert(path_len < PATH_MAX); /* len was tested before! */
     pstrcpy(path2, sizeof(path2), path);
@@ -1758,10 +1738,10 @@ static int check_directory_consistency(BDRVVVFATState *s,
        mapping->mode &= ~MODE_DELETED;
 
        if (strcmp(basename, basename2))
-           schedule_rename(s, cluster_num, qemu_strdup(path));
+           schedule_rename(s, cluster_num, g_strdup(path));
     } else
        /* new directory */
-       schedule_mkdir(s, cluster_num, qemu_strdup(path));
+       schedule_mkdir(s, cluster_num, g_strdup(path));
 
     lfn_init(&lfn);
     do {
@@ -1782,14 +1762,14 @@ DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)clu
        if (subret) {
            fprintf(stderr, "Error fetching direntries\n");
        fail:
-           free(cluster);
+            g_free(cluster);
            return 0;
        }
 
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
            int cluster_count = 0;
 
-DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
+DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
                    is_free(direntries + i))
                continue;
@@ -1850,7 +1830,7 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
        cluster_num = modified_fat_get(s, cluster_num);
     } while(!fat_eof(s, cluster_num));
 
-    free(cluster);
+    g_free(cluster);
     return ret;
 }
 
@@ -1876,7 +1856,7 @@ DLOG(checkpoint());
      */
     if (s->fat2 == NULL) {
        int size = 0x200 * s->sectors_per_fat;
-       s->fat2 = qemu_malloc(size);
+       s->fat2 = g_malloc(size);
        memcpy(s->fat2, s->fat.pointer, size);
     }
     check = vvfat_read(s->bs,
@@ -1995,8 +1975,9 @@ static int remove_mapping(BDRVVVFATState* s, int mapping_index)
     mapping_t* first_mapping = array_get(&(s->mapping), 0);
 
     /* free mapping */
-    if (mapping->first_mapping_index < 0)
-       free(mapping->path);
+    if (mapping->first_mapping_index < 0) {
+        g_free(mapping->path);
+    }
 
     /* remove from s->mapping */
     array_remove(&(s->mapping), mapping_index);
@@ -2218,7 +2199,7 @@ static int commit_one_file(BDRVVVFATState* s,
     uint32_t first_cluster = c;
     mapping_t* mapping = find_mapping_for_cluster(s, c);
     uint32_t size = filesize_of_direntry(direntry);
-    char* cluster = qemu_malloc(s->cluster_size);
+    char* cluster = g_malloc(s->cluster_size);
     uint32_t i;
     int fd = 0;
 
@@ -2232,11 +2213,15 @@ static int commit_one_file(BDRVVVFATState* s,
     if (fd < 0) {
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                strerror(errno), errno);
+        g_free(cluster);
        return fd;
     }
-    if (offset > 0)
-       if (lseek(fd, offset, SEEK_SET) != offset)
-           return -3;
+    if (offset > 0) {
+        if (lseek(fd, offset, SEEK_SET) != offset) {
+            g_free(cluster);
+            return -3;
+        }
+    }
 
     while (offset < size) {
        uint32_t c1;
@@ -2252,11 +2237,15 @@ static int commit_one_file(BDRVVVFATState* s,
        ret = vvfat_read(s->bs, cluster2sector(s, c),
            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
 
-       if (ret < 0)
-           return ret;
+        if (ret < 0) {
+            g_free(cluster);
+            return ret;
+        }
 
-       if (write(fd, cluster, rest_size) < 0)
-           return -2;
+        if (write(fd, cluster, rest_size) < 0) {
+            g_free(cluster);
+            return -2;
+        }
 
        offset += rest_size;
        c = c1;
@@ -2265,9 +2254,11 @@ static int commit_one_file(BDRVVVFATState* s,
     if (ftruncate(fd, size)) {
         perror("ftruncate()");
         close(fd);
+        g_free(cluster);
         return -4;
     }
     close(fd);
+    g_free(cluster);
 
     return commit_mappings(s, first_cluster, dir_index);
 }
@@ -2383,7 +2374,7 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
                            mapping_t* m = find_mapping_for_cluster(s,
                                    begin_of_direntry(d));
                            int l = strlen(m->path);
-                           char* new_path = qemu_malloc(l + diff + 1);
+                           char* new_path = g_malloc(l + diff + 1);
 
                            assert(!strncmp(m->path, mapping->path, l2));
 
@@ -2399,7 +2390,7 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
                }
            }
 
-           free(old_path);
+            g_free(old_path);
            array_remove(&(s->commits), i);
            continue;
        } else if (commit->action == ACTION_MKDIR) {
@@ -2640,7 +2631,9 @@ static int do_commit(BDRVVVFATState* s)
        return ret;
     }
 
-    s->qcow->drv->bdrv_make_empty(s->qcow);
+    if (s->qcow->drv->bdrv_make_empty) {
+        s->qcow->drv->bdrv_make_empty(s->qcow);
+    }
 
     memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
 
@@ -2735,7 +2728,7 @@ DLOG(checkpoint());
      * Use qcow backend. Commit later.
      */
 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
-    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+    ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
     if (ret < 0) {
        fprintf(stderr, "Error writing to qcow backend\n");
        return ret;
@@ -2754,6 +2747,17 @@ DLOG(checkpoint());
     return 0;
 }
 
+static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
+                                       const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vvfat_is_allocated(BlockDriverState *bs,
        int64_t sector_num, int nb_sectors, int* n)
 {
@@ -2775,7 +2779,7 @@ static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
 static void write_target_close(BlockDriverState *bs) {
     BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
     bdrv_delete(s->qcow);
-    free(s->qcow_filename);
+    g_free(s->qcow_filename);
 }
 
 static BlockDriver vvfat_write_target = {
@@ -2794,7 +2798,7 @@ static int enable_write_target(BDRVVVFATState *s)
 
     array_init(&(s->commits), sizeof(commit_t));
 
-    s->qcow_filename = qemu_malloc(1024);
+    s->qcow_filename = g_malloc(1024);
     get_tmp_filename(s->qcow_filename, 1024);
 
     bdrv_qcow = bdrv_find_format("qcow");
@@ -2822,7 +2826,7 @@ static int enable_write_target(BDRVVVFATState *s)
 
     s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
     s->bs->backing_hd->drv = &vvfat_write_target;
-    s->bs->backing_hd->opaque = qemu_malloc(sizeof(void*));
+    s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
     *(void**)s->bs->backing_hd->opaque = s;
 
     return 0;
@@ -2836,16 +2840,20 @@ static void vvfat_close(BlockDriverState *bs)
     array_free(&(s->fat));
     array_free(&(s->directory));
     array_free(&(s->mapping));
-    if(s->cluster_buffer)
-        free(s->cluster_buffer);
+    g_free(s->cluster_buffer);
+
+    if (s->qcow) {
+        migrate_del_blocker(s->migration_blocker);
+        error_free(s->migration_blocker);
+    }
 }
 
 static BlockDriver bdrv_vvfat = {
     .format_name       = "vvfat",
     .instance_size     = sizeof(BDRVVVFATState),
     .bdrv_file_open    = vvfat_open,
-    .bdrv_read         = vvfat_read,
-    .bdrv_write                = vvfat_write,
+    .bdrv_read          = vvfat_co_read,
+    .bdrv_write         = vvfat_co_write,
     .bdrv_close                = vvfat_close,
     .bdrv_is_allocated = vvfat_is_allocated,
     .protocol_name     = "fat",
@@ -2878,11 +2886,5 @@ static void checkpoint(void) {
     direntry = array_get(&(vvv->directory), mapping->dir_index);
     assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
 #endif
-    return;
-    /* avoid compiler warnings: */
-    hexdump(NULL, 100);
-    remove_mapping(vvv, 0);
-    print_mapping(NULL);
-    print_direntry(NULL);
 }
 #endif
index 545ad11ff35c75d8a503e91dcbd385869f61a5fa..77c0187c3d3ad287eb7f90385094acdd751a1c6f 100644 (file)
@@ -27,6 +27,9 @@
 #include "block.h"
 #include "qemu-option.h"
 #include "qemu-queue.h"
+#include "qemu-coroutine.h"
+#include "qemu-timer.h"
+#include "qapi-types.h"
 
 #define BLOCK_FLAG_ENCRYPT     1
 #define BLOCK_FLAG_COMPAT6     4
@@ -39,6 +42,7 @@
 #define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
 #define BLOCK_OPT_TABLE_SIZE    "table_size"
 #define BLOCK_OPT_PREALLOC      "preallocation"
+#define BLOCK_OPT_SUBFMT        "subformat"
 
 typedef struct AIOPool {
     void (*cancel)(BlockDriverAIOCB *acb);
@@ -59,7 +63,6 @@ struct BlockDriver {
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
-    int (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
@@ -73,8 +76,34 @@ struct BlockDriver {
         BlockDriverCompletionFunc *cb, void *opaque);
     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque);
-    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
-                        int nb_sectors);
+    BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+    int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors);
+
+    /*
+     * Invalidate any cached meta-data.
+     */
+    void (*bdrv_invalidate_cache)(BlockDriverState *bs);
+
+    /*
+     * Flushes all data that was already written to the OS all the way down to
+     * the disk (for example raw-posix calls fsync()).
+     */
+    int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs);
+
+    /*
+     * Flushes all internal caches to the OS. The data may still sit in a
+     * writeback cache of the host OS, but it will survive a crash of the qemu
+     * process.
+     */
+    int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
 
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
@@ -85,6 +114,7 @@ struct BlockDriver {
     const char *protocol_name;
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors);
 
@@ -110,8 +140,8 @@ struct BlockDriver {
     /* removable device specific */
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
-    int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
-    int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+    void (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+    void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
 
     /* to control generic scsi devices */
     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
@@ -146,27 +176,23 @@ struct BlockDriverState {
     int read_only; /* if true, the media is read only */
     int keep_read_only; /* if true, the media was requested to stay read only */
     int open_flags; /* flags used to open the file, re-used for re-open */
-    int removable; /* if true, the media can be removed */
-    int locked;    /* if true, the media cannot temporarily be ejected */
-    int tray_open; /* if true, the virtual tray is open */
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
-    /* event callback when inserting/removing */
-    void (*change_cb)(void *opaque, int reason);
-    void *change_opaque;
 
     BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
-    DeviceState *peer;
+    void *dev;                  /* attached device model, if any */
+    /* TODO change to DeviceState when all users are qdevified */
+    const BlockDevOps *dev_ops;
+    void *dev_opaque;
 
     char filename[1024];
     char backing_file[1024]; /* if non zero, the image is a diff of
                                 this file image */
     char backing_format[16]; /* if non-zero and backing_file exists */
     int is_temporary;
-    int media_changed;
 
     BlockDriverState *backing_hd;
     BlockDriverState *file;
@@ -176,10 +202,9 @@ struct BlockDriverState {
     void *sync_aiocb;
 
     /* I/O stats (display with "info blockstats"). */
-    uint64_t rd_bytes;
-    uint64_t wr_bytes;
-    uint64_t rd_ops;
-    uint64_t wr_ops;
+    uint64_t nr_bytes[BDRV_MAX_IOTYPE];
+    uint64_t nr_ops[BDRV_MAX_IOTYPE];
+    uint64_t total_time_ns[BDRV_MAX_IOTYPE];
     uint64_t wr_highest_sector;
 
     /* Whether the disk can expand beyond total_sectors */
@@ -194,8 +219,9 @@ struct BlockDriverState {
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
     int cyls, heads, secs, translation;
-    int type;
     BlockErrorAction on_read_error, on_write_error;
+    bool iostatus_enabled;
+    BlockDeviceIoStatus iostatus;
     char device_name[32];
     unsigned long *dirty_bitmap;
     int64_t dirty_count;
@@ -204,9 +230,6 @@ struct BlockDriverState {
     void *private;
 };
 
-#define CHANGE_MEDIA   0x01
-#define CHANGE_SIZE    0x02
-
 struct BlockDriverAIOCB {
     AIOPool *pool;
     BlockDriverState *bs;
@@ -221,45 +244,8 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
                    BlockDriverCompletionFunc *cb, void *opaque);
 void qemu_aio_release(void *p);
 
-void *qemu_blockalign(BlockDriverState *bs, size_t size);
-
 #ifdef _WIN32
 int is_windows_drive(const char *filename);
 #endif
 
-typedef struct BlockConf {
-    BlockDriverState *bs;
-    uint16_t physical_block_size;
-    uint16_t logical_block_size;
-    uint16_t min_io_size;
-    uint32_t opt_io_size;
-    int32_t bootindex;
-    uint32_t discard_granularity;
-} BlockConf;
-
-static inline unsigned int get_physical_block_exp(BlockConf *conf)
-{
-    unsigned int exp = 0, size;
-
-    for (size = conf->physical_block_size;
-        size > conf->logical_block_size;
-        size >>= 1) {
-        exp++;
-    }
-
-    return exp;
-}
-
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
-    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
-    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
-                       _conf.logical_block_size, 512),                  \
-    DEFINE_PROP_UINT16("physical_block_size", _state,                   \
-                       _conf.physical_block_size, 512),                 \
-    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
-    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
-    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
-    DEFINE_PROP_UINT32("discard_granularity", _state, \
-                       _conf.discard_granularity, 0)
-
 #endif /* BLOCK_INT_H */
index 8c96754503f9116ca4aeb2f144eddcefcc585c06..222818690daa0279885b0e18a477f0d58ed9da97 100644 (file)
@@ -14,7 +14,6 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "sysemu.h"
-#include "hw/qdev.h"
 #include "block_int.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -182,9 +181,9 @@ static void drive_uninit(DriveInfo *dinfo)
 {
     qemu_opts_del(dinfo->opts);
     bdrv_delete(dinfo->bdrv);
-    qemu_free(dinfo->id);
+    g_free(dinfo->id);
     QTAILQ_REMOVE(&drives, dinfo, next);
-    qemu_free(dinfo);
+    g_free(dinfo);
 }
 
 void drive_put_ref(DriveInfo *dinfo)
@@ -240,14 +239,6 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     int ret;
 
     translation = BIOS_ATA_TRANSLATION_AUTO;
-
-    if (default_to_scsi) {
-        type = IF_SCSI;
-        pstrcpy(devname, sizeof(devname), "scsi");
-    } else {
-        type = IF_IDE;
-        pstrcpy(devname, sizeof(devname), "ide");
-    }
     media = MEDIA_DISK;
 
     /* extract parameters */
@@ -273,7 +264,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
             error_report("unsupported bus type '%s'", buf);
             return NULL;
        }
+    } else {
+        type = default_to_scsi ? IF_SCSI : IF_IDE;
+        pstrcpy(devname, sizeof(devname), if_name[type]);
     }
+
     max_devs = if_max_devs[type];
 
     if (cyls || heads || secs) {
@@ -293,7 +288,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
 
     if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
         if (!cyls) {
-            error_report("'%s' trans must be used with cyls,heads and secs",
+            error_report("'%s' trans must be used with cyls, heads and secs",
                          buf);
             return NULL;
         }
@@ -314,7 +309,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
            media = MEDIA_DISK;
        } else if (!strcmp(buf, "cdrom")) {
             if (cyls || secs || heads) {
-                error_report("'%s' invalid physical CHS format", buf);
+                error_report("CHS can't be set with media=%s", buf);
                return NULL;
             }
            media = MEDIA_CDROM;
@@ -325,18 +320,9 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     }
 
     if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
-        if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
-            bdrv_flags |= BDRV_O_NOCACHE;
-        } else if (!strcmp(buf, "writeback")) {
-            bdrv_flags |= BDRV_O_CACHE_WB;
-        } else if (!strcmp(buf, "unsafe")) {
-            bdrv_flags |= BDRV_O_CACHE_WB;
-            bdrv_flags |= BDRV_O_NO_FLUSH;
-        } else if (!strcmp(buf, "writethrough")) {
-            /* this is the default */
-        } else {
-           error_report("invalid cache option");
-           return NULL;
+        if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
+            error_report("invalid cache option");
+            return NULL;
         }
     }
 
@@ -446,12 +432,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
 
     /* init */
 
-    dinfo = qemu_mallocz(sizeof(*dinfo));
+    dinfo = g_malloc0(sizeof(*dinfo));
     if ((buf = qemu_opts_id(opts)) != NULL) {
-        dinfo->id = qemu_strdup(buf);
+        dinfo->id = g_strdup(buf);
     } else {
         /* no id supplied -> create one */
-        dinfo->id = qemu_mallocz(32);
+        dinfo->id = g_malloc0(32);
         if (type == IF_IDE || type == IF_SCSI)
             mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
         if (max_devs)
@@ -487,23 +473,19 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
             }
            break;
        case MEDIA_CDROM:
-            bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM);
+            dinfo->media_cd = 1;
            break;
        }
         break;
     case IF_SD:
-        /* FIXME: This isn't really a floppy, but it's a reasonable
-           approximation.  */
     case IF_FLOPPY:
-        bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY);
-        break;
     case IF_PFLASH:
     case IF_MTD:
         break;
     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);
@@ -545,9 +527,9 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
 
 err:
     bdrv_delete(dinfo->bdrv);
-    qemu_free(dinfo->id);
+    g_free(dinfo->id);
     QTAILQ_REMOVE(&drives, dinfo, next);
-    qemu_free(dinfo);
+    g_free(dinfo);
     return NULL;
 }
 
@@ -571,15 +553,16 @@ void do_commit(Monitor *mon, const QDict *qdict)
 int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *device = qdict_get_str(qdict, "device");
-    const char *filename = qdict_get_try_str(qdict, "snapshot_file");
+    const char *filename = qdict_get_try_str(qdict, "snapshot-file");
     const char *format = qdict_get_try_str(qdict, "format");
     BlockDriverState *bs;
-    BlockDriver *drv, *proto_drv;
+    BlockDriver *drv, *old_drv, *proto_drv;
     int ret = 0;
     int flags;
+    char old_filename[1024];
 
     if (!filename) {
-        qerror_report(QERR_MISSING_PARAMETER, "snapshot_file");
+        qerror_report(QERR_MISSING_PARAMETER, "snapshot-file");
         ret = -1;
         goto out;
     }
@@ -591,6 +574,11 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
         goto out;
     }
 
+    pstrcpy(old_filename, sizeof(old_filename), bs->filename);
+
+    old_drv = bs->drv;
+    flags = bs->open_flags;
+
     if (!format) {
         format = "qcow2";
     }
@@ -610,7 +598,7 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
     }
 
     ret = bdrv_img_create(filename, format, bs->filename,
-                          bs->drv->format_name, NULL, -1, bs->open_flags);
+                          bs->drv->format_name, NULL, -1, flags);
     if (ret) {
         goto out;
     }
@@ -618,15 +606,20 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
     qemu_aio_flush();
     bdrv_flush(bs);
 
-    flags = bs->open_flags;
     bdrv_close(bs);
     ret = bdrv_open(bs, filename, flags, drv);
     /*
-     * If reopening the image file we just created fails, we really
-     * are in trouble :(
+     * If reopening the image file we just created fails, fall back
+     * and try to re-open the original image. If that fails too, we
+     * are in serious trouble.
      */
     if (ret != 0) {
-        abort();
+        ret = bdrv_open(bs, old_filename, flags, old_drv);
+        if (ret != 0) {
+            qerror_report(QERR_OPEN_FILE_FAILED, old_filename);
+        } else {
+            qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        }
     }
 out:
     if (ret) {
@@ -638,13 +631,13 @@ out:
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
-    if (!force) {
-        if (!bdrv_is_removable(bs)) {
-            qerror_report(QERR_DEVICE_NOT_REMOVABLE,
-                           bdrv_get_device_name(bs));
-            return -1;
-        }
-        if (bdrv_is_locked(bs)) {
+    if (!bdrv_dev_has_removable_media(bs)) {
+        qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+        return -1;
+    }
+    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
+        bdrv_dev_eject_request(bs, force);
+        if (!force) {
             qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
             return -1;
         }
@@ -742,12 +735,12 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     bdrv_flush(bs);
     bdrv_close(bs);
 
-    /* if we have a device associated with this BlockDriverState (bs->peer)
+    /* if we have a device attached to this BlockDriverState
      * 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) {
+    if (bdrv_get_attached_dev(bs)) {
         bdrv_make_anon(bs);
     } else {
         drive_uninit(drive_get_by_blockdev(bs));
index 2c9e7804c916ad1e5f5e40d8dd2a7ec601d49032..3587786a648fd8f926bb7fcdbf3b1c9788601d1e 100644 (file)
@@ -33,6 +33,7 @@ struct DriveInfo {
     int bus;
     int unit;
     int auto_del;               /* see blockdev_mark_auto_del() */
+    int media_cd;
     QemuOpts *opts;
     char serial[BLOCK_SERIAL_STRLEN + 1];
     QTAILQ_ENTRY(DriveInfo) next;
index 6b12f8bba1dd1aa8915558de8fe8f0d7ec500c14..cc7d4a37adb40d5a283e6d15f6bdd0d3cbf7163b 100644 (file)
@@ -29,7 +29,7 @@
 #include "qemu.h"
 #include "qemu-common.h"
 /* For tb_lock */
-#include "exec-all.h"
+#include "cpu.h"
 #include "tcg.h"
 #include "qemu-timer.h"
 #include "envlist.h"
@@ -237,7 +237,7 @@ void cpu_loop(CPUX86State *env)
             break;
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
-            /* syscall from syscall intruction */
+            /* syscall from syscall instruction */
             if (bsd_type == target_freebsd)
                 env->regs[R_EAX] = do_freebsd_syscall(env,
                                                       env->regs[R_EAX],
@@ -690,7 +690,8 @@ static void usage(void)
            "-bsd type         select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
            "\n"
            "Debug options:\n"
-           "-d options   activate log (logfile=%s)\n"
+           "-d options   activate log (default logfile=%s)\n"
+           "-D logfile   override default logfile location\n"
            "-p pagesize  set the host page size to 'pagesize'\n"
            "-singlestep  always run in singlestep mode\n"
            "-strace      log system calls\n"
@@ -731,6 +732,8 @@ int main(int argc, char **argv)
 {
     const char *filename;
     const char *cpu_model;
+    const char *log_file = DEBUG_LOGFILE;
+    const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     TaskState ts1, *ts = &ts1;
@@ -745,9 +748,6 @@ int main(int argc, char **argv)
     if (argc <= 1)
         usage();
 
-    /* init debug */
-    cpu_set_log_filename(DEBUG_LOGFILE);
-
     if ((envlist = envlist_create()) == NULL) {
         (void) fprintf(stderr, "Unable to allocate envlist\n");
         exit(1);
@@ -775,22 +775,15 @@ int main(int argc, char **argv)
         if (!strcmp(r, "-")) {
             break;
         } else if (!strcmp(r, "d")) {
-            int mask;
-            const CPULogItem *item;
-
-            if (optind >= argc)
+            if (optind >= argc) {
+                break;
+            }
+            log_mask = argv[optind++];
+        } else if (!strcmp(r, "D")) {
+            if (optind >= argc) {
                 break;
-
-            r = argv[optind++];
-            mask = cpu_str_to_log_mask(r);
-            if (!mask) {
-                printf("Log items (comma separated):\n");
-                for(item = cpu_log_items; item->mask != 0; item++) {
-                    printf("%-10s %s\n", item->name, item->help);
-                }
-                exit(1);
             }
-            cpu_set_log(mask);
+            log_file = argv[optind++];
         } else if (!strcmp(r, "E")) {
             r = argv[optind++];
             if (envlist_setenv(envlist, r) != 0)
@@ -863,8 +856,27 @@ int main(int argc, char **argv)
             usage();
         }
     }
-    if (optind >= argc)
+
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    if (log_mask) {
+        int mask;
+        const CPULogItem *item;
+
+        mask = cpu_str_to_log_mask(log_mask);
+        if (!mask) {
+            printf("Log items (comma separated):\n");
+            for (item = cpu_log_items; item->mask != 0; item++) {
+                printf("%-10s %s\n", item->name, item->help);
+            }
+            exit(1);
+        }
+        cpu_set_log(mask);
+    }
+
+    if (optind >= argc) {
         usage();
+    }
     filename = argv[optind];
 
     /* Zero out regs */
@@ -893,7 +905,8 @@ int main(int argc, char **argv)
         cpu_model = "any";
 #endif
     }
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
index 207c774fb057fa494fb317b1967682efce6473e7..5d6cffc45857326fabef87ad177377c9ab245758 100644 (file)
@@ -94,7 +94,7 @@ void *qemu_vmalloc(size_t size)
     return p;
 }
 
-void *qemu_malloc(size_t size)
+void *g_malloc(size_t size)
 {
     char * p;
     size += 16;
@@ -104,12 +104,12 @@ void *qemu_malloc(size_t size)
 }
 
 /* We use map, which is always zero initialized.  */
-void * qemu_mallocz(size_t size)
+void * g_malloc0(size_t size)
 {
-    return qemu_malloc(size);
+    return g_malloc(size);
 }
 
-void qemu_free(void *ptr)
+void g_free(void *ptr)
 {
     /* FIXME: We should unmark the reserved pages here.  However this gets
        complicated when one target page spans multiple host pages, so we
@@ -119,18 +119,18 @@ void qemu_free(void *ptr)
     munmap(p, *p);
 }
 
-void *qemu_realloc(void *ptr, size_t size)
+void *g_realloc(void *ptr, size_t size)
 {
     size_t old_size, copy;
     void *new_ptr;
 
     if (!ptr)
-        return qemu_malloc(size);
+        return g_malloc(size);
     old_size = *(size_t *)((char *)ptr - 16);
     copy = old_size < size ? old_size : size;
-    new_ptr = qemu_malloc(size);
+    new_ptr = g_malloc(size);
     memcpy(new_ptr, ptr, copy);
-    qemu_free(ptr);
+    g_free(ptr);
     return new_ptr;
 }
 
index e343894ab1ba30defed772aacffe6c04da4e8f48..1ba2d083d11cd3d9101ef3b1a06a7cea50def0e6 100644 (file)
@@ -323,7 +323,7 @@ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
 abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
 
 /* Functions for accessing guest memory.  The tget and tput functions
-   read/write single values, byteswapping as neccessary.  The lock_user
+   read/write single values, byteswapping as necessary.  The lock_user
    gets a pointer to a contiguous area of guest memory, but does not perform
    and byteswapping.  lock_user may return either a pointer to the guest
    memory, or a temporary buffer.  */
index eb1cdf21cacdcc35a30fbdc5084380235e52b78e..18b43f1a2afc28fad6edde758998f0566bd449cc 100644 (file)
@@ -31,7 +31,6 @@
 #include <sys/syscall.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#include <signal.h>
 #include <utime.h>
 
 #include "qemu.h"
@@ -232,7 +231,7 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol
     void *hnamep, *holdp, *hnewp = NULL;
     size_t holdlen;
     abi_ulong oldlen = 0;
-    int32_t *snamep = qemu_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
     uint32_t kind = 0;
 
     if (oldlenp)
@@ -256,7 +255,7 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol
     unlock_user(holdp, oldp, holdlen);
     if (hnewp)
         unlock_user(hnewp, newp, 0);
-    qemu_free(snamep);
+    g_free(snamep);
     return ret;
 }
 #endif
diff --git a/bswap.h b/bswap.h
index 82a79517db971137f72d6c160b5721af131e6721..cc7f84d30f91a45964a13eb2fe4d3fa6db77a590 100644 (file)
--- a/bswap.h
+++ b/bswap.h
@@ -4,6 +4,7 @@
 #include "config-host.h"
 
 #include <inttypes.h>
+#include "softfloat.h"
 
 #ifdef CONFIG_MACHINE_BSWAP_H
 #include <sys/endian.h>
@@ -237,4 +238,476 @@ static inline uint32_t qemu_bswap_len(uint32_t value, int len)
     return bswap32(value) >> (32 - 8 * len);
 }
 
+typedef union {
+    float32 f;
+    uint32_t l;
+} CPU_FloatU;
+
+typedef union {
+    float64 d;
+#if defined(HOST_WORDS_BIGENDIAN)
+    struct {
+        uint32_t upper;
+        uint32_t lower;
+    } l;
+#else
+    struct {
+        uint32_t lower;
+        uint32_t upper;
+    } l;
+#endif
+    uint64_t ll;
+} CPU_DoubleU;
+
+typedef union {
+     floatx80 d;
+     struct {
+         uint64_t lower;
+         uint16_t upper;
+     } l;
+} CPU_LDoubleU;
+
+typedef union {
+    float128 q;
+#if defined(HOST_WORDS_BIGENDIAN)
+    struct {
+        uint32_t upmost;
+        uint32_t upper;
+        uint32_t lower;
+        uint32_t lowest;
+    } l;
+    struct {
+        uint64_t upper;
+        uint64_t lower;
+    } ll;
+#else
+    struct {
+        uint32_t lowest;
+        uint32_t lower;
+        uint32_t upper;
+        uint32_t upmost;
+    } l;
+    struct {
+        uint64_t lower;
+        uint64_t upper;
+    } ll;
+#endif
+} CPU_QuadU;
+
+/* unaligned/endian-independent pointer access */
+
+/*
+ * the generic syntax is:
+ *
+ * load: ld{type}{sign}{size}{endian}_p(ptr)
+ *
+ * store: st{type}{size}{endian}_p(ptr, val)
+ *
+ * Note there are small differences with the softmmu access API!
+ *
+ * type is:
+ * (empty): integer access
+ *   f    : float access
+ *
+ * sign is:
+ * (empty): for floats or 32 bit size
+ *   u    : unsigned
+ *   s    : signed
+ *
+ * size is:
+ *   b: 8 bits
+ *   w: 16 bits
+ *   l: 32 bits
+ *   q: 64 bits
+ *
+ * endian is:
+ * (empty): 8 bit access
+ *   be   : big endian
+ *   le   : little endian
+ */
+static inline int ldub_p(const void *ptr)
+{
+    return *(uint8_t *)ptr;
+}
+
+static inline int ldsb_p(const void *ptr)
+{
+    return *(int8_t *)ptr;
+}
+
+static inline void stb_p(void *ptr, int v)
+{
+    *(uint8_t *)ptr = v;
+}
+
+/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
+   kernel handles unaligned load/stores may give better results, but
+   it is a system wide setting : bad */
+#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+/* conservative code for little endian unaligned accesses */
+static inline int lduw_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return val;
+#else
+    const uint8_t *p = ptr;
+    return p[0] | (p[1] << 8);
+#endif
+}
+
+static inline int ldsw_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return (int16_t)val;
+#else
+    const uint8_t *p = ptr;
+    return (int16_t)(p[0] | (p[1] << 8));
+#endif
+}
+
+static inline int ldl_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return val;
+#else
+    const uint8_t *p = ptr;
+    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+#endif
+}
+
+static inline uint64_t ldq_le_p(const void *ptr)
+{
+    const uint8_t *p = ptr;
+    uint32_t v1, v2;
+    v1 = ldl_le_p(p);
+    v2 = ldl_le_p(p + 4);
+    return v1 | ((uint64_t)v2 << 32);
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+#ifdef _ARCH_PPC
+    __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
+#else
+    uint8_t *p = ptr;
+    p[0] = v;
+    p[1] = v >> 8;
+#endif
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+#ifdef _ARCH_PPC
+    __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
+#else
+    uint8_t *p = ptr;
+    p[0] = v;
+    p[1] = v >> 8;
+    p[2] = v >> 16;
+    p[3] = v >> 24;
+#endif
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+    uint8_t *p = ptr;
+    stl_le_p(p, (uint32_t)v);
+    stl_le_p(p + 4, v >> 32);
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(const void *ptr)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = ldl_le_p(ptr);
+    return u.f;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = v;
+    stl_le_p(ptr, u.i);
+}
+
+static inline float64 ldfq_le_p(const void *ptr)
+{
+    CPU_DoubleU u;
+    u.l.lower = ldl_le_p(ptr);
+    u.l.upper = ldl_le_p(ptr + 4);
+    return u.d;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+    CPU_DoubleU u;
+    u.d = v;
+    stl_le_p(ptr, u.l.lower);
+    stl_le_p(ptr + 4, u.l.upper);
+}
+
+#else
+
+static inline int lduw_le_p(const void *ptr)
+{
+    return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_le_p(const void *ptr)
+{
+    return *(int16_t *)ptr;
+}
+
+static inline int ldl_le_p(const void *ptr)
+{
+    return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_le_p(const void *ptr)
+{
+    return *(uint64_t *)ptr;
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+    *(uint16_t *)ptr = v;
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+    *(uint32_t *)ptr = v;
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+    *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(const void *ptr)
+{
+    return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_le_p(const void *ptr)
+{
+    return *(float64 *)ptr;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+    *(float32 *)ptr = v;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+    *(float64 *)ptr = v;
+}
+#endif
+
+#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+static inline int lduw_be_p(const void *ptr)
+{
+#if defined(__i386__)
+    int val;
+    asm volatile ("movzwl %1, %0\n"
+                  "xchgb %b0, %h0\n"
+                  : "=q" (val)
+                  : "m" (*(uint16_t *)ptr));
+    return val;
+#else
+    const uint8_t *b = ptr;
+    return ((b[0] << 8) | b[1]);
+#endif
+}
+
+static inline int ldsw_be_p(const void *ptr)
+{
+#if defined(__i386__)
+    int val;
+    asm volatile ("movzwl %1, %0\n"
+                  "xchgb %b0, %h0\n"
+                  : "=q" (val)
+                  : "m" (*(uint16_t *)ptr));
+    return (int16_t)val;
+#else
+    const uint8_t *b = ptr;
+    return (int16_t)((b[0] << 8) | b[1]);
+#endif
+}
+
+static inline int ldl_be_p(const void *ptr)
+{
+#if defined(__i386__) || defined(__x86_64__)
+    int val;
+    asm volatile ("movl %1, %0\n"
+                  "bswap %0\n"
+                  : "=r" (val)
+                  : "m" (*(uint32_t *)ptr));
+    return val;
+#else
+    const uint8_t *b = ptr;
+    return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+#endif
+}
+
+static inline uint64_t ldq_be_p(const void *ptr)
+{
+    uint32_t a,b;
+    a = ldl_be_p(ptr);
+    b = ldl_be_p((uint8_t *)ptr + 4);
+    return (((uint64_t)a<<32)|b);
+}
+
+static inline void stw_be_p(void *ptr, int v)
+{
+#if defined(__i386__)
+    asm volatile ("xchgb %b0, %h0\n"
+                  "movw %w0, %1\n"
+                  : "=q" (v)
+                  : "m" (*(uint16_t *)ptr), "0" (v));
+#else
+    uint8_t *d = (uint8_t *) ptr;
+    d[0] = v >> 8;
+    d[1] = v;
+#endif
+}
+
+static inline void stl_be_p(void *ptr, int v)
+{
+#if defined(__i386__) || defined(__x86_64__)
+    asm volatile ("bswap %0\n"
+                  "movl %0, %1\n"
+                  : "=r" (v)
+                  : "m" (*(uint32_t *)ptr), "0" (v));
+#else
+    uint8_t *d = (uint8_t *) ptr;
+    d[0] = v >> 24;
+    d[1] = v >> 16;
+    d[2] = v >> 8;
+    d[3] = v;
+#endif
+}
+
+static inline void stq_be_p(void *ptr, uint64_t v)
+{
+    stl_be_p(ptr, v >> 32);
+    stl_be_p((uint8_t *)ptr + 4, v);
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(const void *ptr)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = ldl_be_p(ptr);
+    return u.f;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = v;
+    stl_be_p(ptr, u.i);
+}
+
+static inline float64 ldfq_be_p(const void *ptr)
+{
+    CPU_DoubleU u;
+    u.l.upper = ldl_be_p(ptr);
+    u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
+    return u.d;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+    CPU_DoubleU u;
+    u.d = v;
+    stl_be_p(ptr, u.l.upper);
+    stl_be_p((uint8_t *)ptr + 4, u.l.lower);
+}
+
+#else
+
+static inline int lduw_be_p(const void *ptr)
+{
+    return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_be_p(const void *ptr)
+{
+    return *(int16_t *)ptr;
+}
+
+static inline int ldl_be_p(const void *ptr)
+{
+    return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_be_p(const void *ptr)
+{
+    return *(uint64_t *)ptr;
+}
+
+static inline void stw_be_p(void *ptr, int v)
+{
+    *(uint16_t *)ptr = v;
+}
+
+static inline void stl_be_p(void *ptr, int v)
+{
+    *(uint32_t *)ptr = v;
+}
+
+static inline void stq_be_p(void *ptr, uint64_t v)
+{
+    *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(const void *ptr)
+{
+    return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_be_p(const void *ptr)
+{
+    return *(float64 *)ptr;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+    *(float32 *)ptr = v;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+    *(float64 *)ptr = v;
+}
+
+#endif
+
 #endif /* BSWAP_H */
index 6931e7cc62a9d000d5738cd3f33dd49100be2257..df5b7cdace86e43f66e534f6cfd60c2234428cbd 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"
 
@@ -178,7 +177,7 @@ struct HCIInfo *bt_host_hci(const char *id)
     }
 # endif
 
-    s = qemu_mallocz(sizeof(struct bt_host_hci_s));
+    s = g_malloc0(sizeof(struct bt_host_hci_s));
     s->fd = fd;
     s->hci.cmd_send = bt_host_cmd;
     s->hci.sco_send = bt_host_sco;
index 679c5e05d7da30ef6c03adab098389061e77565d..bbc102985434e1ce217319e5e50ec612acfc39d1 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"
 
@@ -157,7 +156,7 @@ void bt_vhci_init(struct HCIInfo *info)
         exit(-1);
     }
 
-    s = qemu_mallocz(sizeof(struct bt_vhci_s));
+    s = g_malloc0(sizeof(struct bt_vhci_s));
     s->fd = fd;
     s->info = info ?: qemu_next_hci();
     s->info->opaque = s;
index 8435a3194603d24dbd325a8b16601bb72ac1ab68..fed9a227bb09676b4d804c9343ca55e06efb8054 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"
 
@@ -28,7 +27,6 @@ typedef struct QEMUFileBuffered
     BufferedCloseFunc *close;
     void *opaque;
     QEMUFile *file;
-    int has_error;
     int freeze_output;
     size_t bytes_xfer;
     size_t xfer_limit;
@@ -57,7 +55,7 @@ static void buffered_append(QEMUFileBuffered *s,
 
         s->buffer_capacity += size + 1024;
 
-        tmp = qemu_realloc(s->buffer, s->buffer_capacity);
+        tmp = g_realloc(s->buffer, s->buffer_capacity);
         if (tmp == NULL) {
             fprintf(stderr, "qemu file buffer expansion failed\n");
             exit(1);
@@ -73,9 +71,11 @@ static void buffered_append(QEMUFileBuffered *s,
 static void buffered_flush(QEMUFileBuffered *s)
 {
     size_t offset = 0;
+    int error;
 
-    if (s->has_error) {
-        DPRINTF("flush when error, bailing\n");
+    error = qemu_file_get_error(s->file);
+    if (error != 0) {
+        DPRINTF("flush when error, bailing: %s\n", strerror(-error));
         return;
     }
 
@@ -94,7 +94,7 @@ static void buffered_flush(QEMUFileBuffered *s)
 
         if (ret <= 0) {
             DPRINTF("error flushing data, %zd\n", ret);
-            s->has_error = 1;
+            qemu_file_set_error(s->file, ret);
             break;
         } else {
             DPRINTF("flushed %zd byte(s)\n", ret);
@@ -110,14 +110,15 @@ static void buffered_flush(QEMUFileBuffered *s)
 static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
 {
     QEMUFileBuffered *s = opaque;
-    int offset = 0;
+    int offset = 0, error;
     ssize_t ret;
 
     DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
 
-    if (s->has_error) {
-        DPRINTF("flush when error, bailing\n");
-        return -EINVAL;
+    error = qemu_file_get_error(s->file);
+    if (error) {
+        DPRINTF("flush when error, bailing: %s\n", strerror(-error));
+        return error;
     }
 
     DPRINTF("unfreezing output\n");
@@ -140,7 +141,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in
 
         if (ret <= 0) {
             DPRINTF("error putting\n");
-            s->has_error = 1;
+            qemu_file_set_error(s->file, ret);
             offset = -EINVAL;
             break;
         }
@@ -174,29 +175,37 @@ static int buffered_close(void *opaque)
 
     DPRINTF("closing\n");
 
-    while (!s->has_error && s->buffer_size) {
+    while (!qemu_file_get_error(s->file) && s->buffer_size) {
         buffered_flush(s);
         if (s->freeze_output)
-            s->wait_for_unfreeze(s);
+            s->wait_for_unfreeze(s->opaque);
     }
 
     ret = s->close(s->opaque);
 
     qemu_del_timer(s->timer);
     qemu_free_timer(s->timer);
-    qemu_free(s->buffer);
-    qemu_free(s);
+    g_free(s->buffer);
+    g_free(s);
 
     return ret;
 }
 
+/*
+ * The meaning of the return values is:
+ *   0: We can continue sending
+ *   1: Time to stop
+ *   negative: There has been an error
+ */
 static int buffered_rate_limit(void *opaque)
 {
     QEMUFileBuffered *s = opaque;
+    int ret;
 
-    if (s->has_error)
-        return 0;
-
+    ret = qemu_file_get_error(s->file);
+    if (ret) {
+        return ret;
+    }
     if (s->freeze_output)
         return 1;
 
@@ -209,9 +218,9 @@ static int buffered_rate_limit(void *opaque)
 static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
 {
     QEMUFileBuffered *s = opaque;
-    if (s->has_error)
+    if (qemu_file_get_error(s->file)) {
         goto out;
-
+    }
     if (new_rate > SIZE_MAX) {
         new_rate = SIZE_MAX;
     }
@@ -233,12 +242,12 @@ static void buffered_rate_tick(void *opaque)
 {
     QEMUFileBuffered *s = opaque;
 
-    if (s->has_error) {
+    if (qemu_file_get_error(s->file)) {
         buffered_close(s);
         return;
     }
 
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
 
     if (s->freeze_output)
         return;
@@ -260,7 +269,7 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque,
 {
     QEMUFileBuffered *s;
 
-    s = qemu_mallocz(sizeof(*s));
+    s = g_malloc0(sizeof(*s));
 
     s->opaque = opaque;
     s->xfer_limit = bytes_per_sec / 10;
@@ -274,9 +283,9 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque,
                              buffered_set_rate_limit,
                             buffered_get_rate_limit);
 
-    s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
+    s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s);
 
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
 
     return s->file;
 }
index 6afce5a5ca2fa6111939b91fa82242c0539e6dc5..5515773b89dcb20dba295071c0b32072ffb817ab 100644 (file)
@@ -56,9 +56,9 @@ START_TEST(qdict_put_obj_test)
 
     // destroy doesn't exit yet
     QDECREF(qi);
-    qemu_free(ent->key);
-    qemu_free(ent);
-    qemu_free(qdict);
+    g_free(ent->key);
+    g_free(ent);
+    g_free(qdict);
 }
 END_TEST
 
@@ -267,8 +267,9 @@ static QString *read_line(FILE *file, char *key)
 {
     char value[128];
 
-    if (fscanf(file, "%s%s", key, value) == EOF)
+    if (fscanf(file, "%127s%127s", key, value) == EOF) {
         return NULL;
+    }
     remove_dots(key);
     return qstring_from_str(value);
 }
index b71d9834f09f1836e0a86ed34ae3c6e3d0a51c1c..3344057b3b179b30db982c2ee55b12cfb4dca3b1 100644 (file)
@@ -33,7 +33,7 @@ START_TEST(qfloat_from_double_test)
     fail_unless(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
 
     // destroy doesn't exit yet
-    qemu_free(qf);
+    g_free(qf);
 }
 END_TEST
 
index f3b031698c4021612ba051ed1a61a501d7ed3683..3af51f20c82dea52f0d747ee34a0b14fe5ee632f 100644 (file)
@@ -32,7 +32,7 @@ START_TEST(qint_from_int_test)
     fail_unless(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
 
     // destroy doesn't exit yet
-    qemu_free(qi);
+    g_free(qi);
 }
 END_TEST
 
index 64fcdcb4ad0ac5c113d8ddd343375b0c46bf20ce..36d4ac26b4c7c9c7c02b85c99cfd37d74e65cf0a 100644 (file)
@@ -33,7 +33,8 @@ START_TEST(escaped_string)
         { "\"\\n\"", "\n" },
         { "\"\\r\"", "\r" },
         { "\"\\t\"", "\t" },
-        { "\"\\/\"", "\\/" },
+        { "\"/\"", "/" },
+        { "\"\\/\"", "/", .skip = 1 },
         { "\"\\\\\"", "\\" },
         { "\"\\\"\"", "\"" },
         { "\"hello world \\\"embedded string\\\"\"",
index 58984cbfcc32039f4b445956e579d67a05213b24..ee2454a27f71beba804c825bb41062a84a132029 100644 (file)
@@ -30,7 +30,7 @@ START_TEST(qlist_new_test)
     fail_unless(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
 
     // destroy doesn't exist yet
-    qemu_free(qlist);
+    g_free(qlist);
 }
 END_TEST
 
@@ -51,8 +51,8 @@ START_TEST(qlist_append_test)
 
     // destroy doesn't exist yet
     QDECREF(qi);
-    qemu_free(entry);
-    qemu_free(qlist);
+    g_free(entry);
+    g_free(qlist);
 }
 END_TEST
 
@@ -65,7 +65,7 @@ START_TEST(qobject_to_qlist_test)
     fail_unless(qobject_to_qlist(QOBJECT(qlist)) == qlist);
 
     // destroy doesn't exist yet
-    qemu_free(qlist);
+    g_free(qlist);
 }
 END_TEST
 
index c9bafc26b3285a2c9a56826fe0b1984266c4630c..93bd4757b7fe20bf642595073f50b8fb4836c760 100644 (file)
@@ -32,8 +32,8 @@ START_TEST(qstring_from_str_test)
     fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
 
     // destroy doesn't exit yet
-    qemu_free(qstring->string);
-    qemu_free(qstring);
+    g_free(qstring->string);
+    g_free(qstring);
 }
 END_TEST
 
diff --git a/cmd.c b/cmd.c
index db2c9c4c5ee066ca43a9210b6fc6d25d80c40033..0806e18ce0987e4c5a3005d75edbb03cfa9b645f 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -45,13 +45,11 @@ compare(const void *a, const void *b)
                      ((const cmdinfo_t *)b)->name);
 }
 
-void
-add_command(
-       const cmdinfo_t *ci)
+void add_command(const cmdinfo_t *ci)
 {
-       cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
-       cmdtab[ncmds - 1] = *ci;
-       qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
+    cmdtab = g_realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
+    cmdtab[ncmds - 1] = *ci;
+    qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
 }
 
 static int
@@ -122,16 +120,10 @@ find_command(
        return NULL;
 }
 
-void
-add_user_command(char *optarg)
+void add_user_command(char *optarg)
 {
-       ncmdline++;
-       cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
-       if (!cmdline) {
-               perror("realloc");
-               exit(1);
-       }
-       cmdline[ncmdline-1] = optarg;
+    cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *));
+    cmdline[ncmdline-1] = optarg;
 }
 
 static int
@@ -160,45 +152,44 @@ static void prep_fetchline(void *opaque)
 
 static char *get_prompt(void);
 
-void
-command_loop(void)
+void command_loop(void)
 {
-       int             c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
-       char            *input;
-       char            **v;
-       const cmdinfo_t *ct;
-
-       for (i = 0; !done && i < ncmdline; i++) {
-               input = strdup(cmdline[i]);
-               if (!input) {
-                       fprintf(stderr,
-                               _("cannot strdup command '%s': %s\n"),
-                               cmdline[i], strerror(errno));
-                       exit(1);
-               }
-               v = breakline(input, &c);
-               if (c) {
-                       ct = find_command(v[0]);
-                       if (ct) {
-                               if (ct->flags & CMD_FLAG_GLOBAL)
-                                       done = command(ct, c, v);
-                               else {
-                                       j = 0;
-                                       while (!done && (j = args_command(j)))
-                                               done = command(ct, c, v);
-                               }
-                       } else
-                               fprintf(stderr, _("command \"%s\" not found\n"),
-                                       v[0]);
-               }
-               doneline(input, v);
-       }
-       if (cmdline) {
-               free(cmdline);
-               return;
+    int c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
+    char *input;
+    char **v;
+    const cmdinfo_t *ct;
+
+    for (i = 0; !done && i < ncmdline; i++) {
+        input = strdup(cmdline[i]);
+        if (!input) {
+            fprintf(stderr, _("cannot strdup command '%s': %s\n"),
+                    cmdline[i], strerror(errno));
+            exit(1);
+        }
+        v = breakline(input, &c);
+        if (c) {
+            ct = find_command(v[0]);
+            if (ct) {
+                if (ct->flags & CMD_FLAG_GLOBAL) {
+                    done = command(ct, c, v);
+                } else {
+                    j = 0;
+                    while (!done && (j = args_command(j))) {
+                        done = command(ct, c, v);
+                    }
+                }
+            } else {
+                fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
+            }
        }
+        doneline(input, v);
+    }
+    if (cmdline) {
+        g_free(cmdline);
+        return;
+    }
 
-       while (!done) {
+    while (!done) {
         if (!prompted) {
             printf("%s", get_prompt());
             fflush(stdout);
@@ -212,22 +203,24 @@ command_loop(void)
         if (!fetchable) {
             continue;
         }
-               if ((input = fetchline()) == NULL)
-                       break;
-               v = breakline(input, &c);
-               if (c) {
-                       ct = find_command(v[0]);
-                       if (ct)
-                               done = command(ct, c, v);
-                       else
-                               fprintf(stderr, _("command \"%s\" not found\n"),
-                                       v[0]);
-               }
-               doneline(input, v);
+        input = fetchline();
+        if (input == NULL) {
+            break;
+        }
+        v = breakline(input, &c);
+        if (c) {
+            ct = find_command(v[0]);
+            if (ct) {
+                done = command(ct, c, v);
+            } else {
+                fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
+            }
+        }
+        doneline(input, v);
 
         prompted = 0;
         fetchable = 0;
-       }
+    }
     qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
 }
 
@@ -331,29 +324,32 @@ static char *qemu_strsep(char **input, const char *delim)
     return result;
 }
 
-char **
-breakline(
-       char    *input,
-       int     *count)
+char **breakline(char *input, int *count)
 {
-       int     c = 0;
-       char    *p;
-       char    **rval = calloc(sizeof(char *), 1);
-
-       while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
-               if (!*p)
-                       continue;
-               c++;
-               rval = realloc(rval, sizeof(*rval) * (c + 1));
-               if (!rval) {
-                       c = 0;
-                       break;
-               }
-               rval[c - 1] = p;
-               rval[c] = NULL;
-       }
-       *count = c;
-       return rval;
+    int c = 0;
+    char *p;
+    char **rval = calloc(sizeof(char *), 1);
+    char **tmp;
+
+    while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
+        if (!*p) {
+            continue;
+        }
+        c++;
+        tmp = realloc(rval, sizeof(*rval) * (c + 1));
+        if (!tmp) {
+            free(rval);
+            rval = NULL;
+            c = 0;
+            break;
+        } else {
+            rval = tmp;
+        }
+        rval[c - 1] = p;
+        rval[c] = NULL;
+    }
+    *count = c;
+    return rval;
 }
 
 void
@@ -389,7 +385,7 @@ cvtnum(
        if (sp[1] != '\0')
                return -1LL;
 
-       c = tolower(*sp);
+       c = qemu_tolower(*sp);
        switch (c) {
        default:
                return i;
@@ -486,7 +482,7 @@ timestr(
                        snprintf(ts, size, "%u:%02u.%02u",
                                (unsigned int) MINUTES(tv->tv_sec),
                                (unsigned int) SECONDS(tv->tv_sec),
-                               (unsigned int) usec * 100);
+                               (unsigned int) (usec * 100));
                        return;
                }
                format |= VERBOSE_FIXED_TIME;   /* fallback if hours needed */
@@ -497,9 +493,9 @@ timestr(
                        (unsigned int) HOURS(tv->tv_sec),
                        (unsigned int) MINUTES(tv->tv_sec),
                        (unsigned int) SECONDS(tv->tv_sec),
-                       (unsigned int) usec * 100);
+                       (unsigned int) (usec * 100));
        } else {
-               snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
+               snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
        }
 }
 
index a7cebc486747151081c39ac7e144c137a7a70992..02306a4f71ea5b32b88b1468084a621a2012fba0 100644 (file)
@@ -26,45 +26,45 @@ struct sigfd_compat_info
 static void *sigwait_compat(void *opaque)
 {
     struct sigfd_compat_info *info = opaque;
-    int err;
     sigset_t all;
 
     sigfillset(&all);
-    sigprocmask(SIG_BLOCK, &all, NULL);
-
-    do {
-        siginfo_t siginfo;
-
-        err = sigwaitinfo(&info->mask, &siginfo);
-        if (err == -1 && errno == EINTR) {
-            err = 0;
-            continue;
-        }
-
-        if (err > 0) {
-            char buffer[128];
+    pthread_sigmask(SIG_BLOCK, &all, NULL);
+
+    while (1) {
+        int sig;
+        int err;
+
+        err = sigwait(&info->mask, &sig);
+        if (err != 0) {
+            if (errno == EINTR) {
+                continue;
+            } else {
+                return NULL;
+            }
+        } else {
+            struct qemu_signalfd_siginfo buffer;
             size_t offset = 0;
 
-            memcpy(buffer, &err, sizeof(err));
+            memset(&buffer, 0, sizeof(buffer));
+            buffer.ssi_signo = sig;
+
             while (offset < sizeof(buffer)) {
                 ssize_t len;
 
-                len = write(info->fd, buffer + offset,
+                len = write(info->fd, (char *)&buffer + offset,
                             sizeof(buffer) - offset);
                 if (len == -1 && errno == EINTR)
                     continue;
 
                 if (len <= 0) {
-                    err = -1;
-                    break;
+                    return NULL;
                 }
 
                 offset += len;
             }
         }
-    } while (err >= 0);
-
-    return NULL;
+    }
 }
 
 static int qemu_signalfd_compat(const sigset_t *mask)
@@ -115,3 +115,22 @@ int qemu_signalfd(const sigset_t *mask)
 
     return qemu_signalfd_compat(mask);
 }
+
+bool qemu_signalfd_available(void)
+{
+#ifdef CONFIG_SIGNALFD
+    sigset_t mask;
+    int fd;
+    bool ok;
+    sigemptyset(&mask);
+    errno = 0;
+    fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
+    ok = (errno != ENOSYS);
+    if (fd >= 0) {
+        close(fd);
+    }
+    return ok;
+#else
+    return false;
+#endif
+}
index fc3791520f3209a074d1f0b8b210940692bb836d..6b04877b97063381fb7c51bcdaaf69c938a35f68 100644 (file)
@@ -39,5 +39,6 @@ struct qemu_signalfd_siginfo {
 };
 
 int qemu_signalfd(const sigset_t *mask);
+bool qemu_signalfd_available(void);
 
 #endif
diff --git a/compiler.h b/compiler.h
new file mode 100644 (file)
index 0000000..a1c0794
--- /dev/null
@@ -0,0 +1,51 @@
+/* public domain */
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include "config-host.h"
+
+/*----------------------------------------------------------------------------
+| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler.
+| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h.
+*----------------------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define QEMU_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define QEMU_GNUC_PREREQ(maj, min) 0
+#endif
+
+#define QEMU_NORETURN __attribute__ ((__noreturn__))
+
+#if QEMU_GNUC_PREREQ(3, 4)
+#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define QEMU_WARN_UNUSED_RESULT
+#endif
+
+#if defined(_WIN32)
+# define QEMU_PACKED __attribute__((gcc_struct, packed))
+#else
+# define QEMU_PACKED __attribute__((packed))
+#endif
+
+#define QEMU_BUILD_BUG_ON(x) \
+    typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
+
+#if defined __GNUC__
+# if !QEMU_GNUC_PREREQ(4, 4)
+   /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
+#  define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
+#  define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
+# else
+   /* Use gnu_printf when supported (qemu uses standard format strings). */
+#  define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
+#  define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
+# endif
+#else
+#define GCC_ATTR /**/
+#define GCC_FMT_ATTR(n, m)
+#endif
+
+#endif /* COMPILER_H */
index e20f78696a1b7c8c0c3b4d6b7b6c1c9dbdfad427..82c0ab265c29a707b698cdb2933b67d691f01a78 100644 (file)
--- a/config.h
+++ b/config.h
@@ -1,2 +1,2 @@
 #include "config-host.h"
-#include "config-target.h"
+#include "i386-softmmu/config-target.h"
index ab540e1ef5ecc5d57f152d3ad0476c3dc966164b..494bcb5069827d6f181894ecca2630526d56706a 100755 (executable)
--- a/configure
+++ b/configure
@@ -92,6 +92,7 @@ libs_tools=""
 audio_pt_int=""
 audio_win_int=""
 cc_i386=i386-pc-linux-gnu-gcc
+libs_qga=""
 
 target_list=""
 
@@ -113,10 +114,9 @@ curl=""
 curses=""
 docs=""
 fdt=""
-kvm=""
-kvm_para=""
 nptl=""
 sdl=""
+vnc="yes"
 sparse="no"
 uuid=""
 vde=""
@@ -126,19 +126,21 @@ vnc_jpeg=""
 vnc_png=""
 vnc_thread="no"
 xen=""
+xen_ctrl_version=""
 linux_aio=""
 attr=""
-vhost_net=""
+libattr=""
 xfs=""
-ffmpeg="no"
-ffmpeg_inc="distrib/ffmpeg"
-v4l2="no"
-v4l2_inc=""
+
+vhost_net="no"
+kvm="no"
+hax="no"
 gprof="no"
 debug_tcg="no"
 debug_mon="no"
 debug="no"
 strip_opt="yes"
+tcg_interpreter="no"
 bigendian="no"
 mingw32="no"
 EXESUF=""
@@ -147,6 +149,8 @@ mandir="\${prefix}/share/man"
 datadir="\${prefix}/share/qemu"
 docdir="\${prefix}/share/doc/qemu"
 bindir="\${prefix}/bin"
+libdir="\${prefix}/lib"
+includedir="\${prefix}/include"
 sysconfdir="\${prefix}/etc"
 confsuffix="/qemu"
 slirp="yes"
@@ -157,6 +161,7 @@ bsd="no"
 linux="no"
 solaris="no"
 profiler="no"
+ldst_optimization="no"
 cocoa="no"
 softmmu="yes"
 linux_user="no"
@@ -164,19 +169,29 @@ darwin_user="no"
 bsd_user="no"
 guest_base=""
 uname_release=""
-io_thread="no"
 mixemu="no"
-kerneldir=""
 aix="no"
 blobs="yes"
 pkgversion=""
-check_utests="no"
-user_pie="no"
+check_utests=""
+pie=""
 zero_malloc=""
 trace_backend="nop"
 trace_file="trace"
 spice=""
 rbd=""
+smartcard=""
+smartcard_nss=""
+usb_redir=""
+opengl=""
+zlib="yes"
+guest_agent="yes"
+libiscsi=""
+gl="yes"
+
+# for TIZEN-maru 
+maru="no"
+#
 
 # parse CC options first
 for opt do
@@ -215,23 +230,24 @@ done
 # Using uname is really, really broken.  Once we have the right set of checks
 # we can eliminate it's usage altogether
 
-cc="${cross_prefix}${CC-gcc}"
-ar="${cross_prefix}${AR-ar}"
-objcopy="${cross_prefix}${OBJCOPY-objcopy}"
-ld="${cross_prefix}${LD-ld}"
-strip="${cross_prefix}${STRIP-strip}"
-windres="${cross_prefix}${WINDRES-windres}"
-pkg_config="${cross_prefix}${PKG_CONFIG-pkg-config}"
-sdl_config="${cross_prefix}${SDL_CONFIG-sdl-config}"
+cc="${CC-${cross_prefix}gcc}"
+ar="${AR-${cross_prefix}ar}"
+objcopy="${OBJCOPY-${cross_prefix}objcopy}"
+ld="${LD-${cross_prefix}ld}"
+libtool="${LIBTOOL-${cross_prefix}libtool}"
+strip="${STRIP-${cross_prefix}strip}"
+windres="${WINDRES-${cross_prefix}windres}"
+pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
+sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
 
 # default flags for all hosts
 QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
 CFLAGS="-g $CFLAGS"
-QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
 QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
 QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
 QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_CFLAGS"
-QEMU_INCLUDES="-I. -I\$(SRC_PATH)"
+QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
 LDFLAGS="-g $LDFLAGS"
 
 # make source path absolute
@@ -278,12 +294,18 @@ elif check_define __s390__ ; then
   else
     cpu="s390"
   fi
+elif check_define __ARMEB__ ; then
+  cpu="armv4b"
+elif check_define __ARMEL__ ; then
+  cpu="armv4l"
+elif check_define __hppa__ ; then
+  cpu="hppa"
 else
   cpu=`uname -m`
 fi
 
 case "$cpu" in
-  alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
+  alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32)
     cpu="$cpu"
   ;;
   i386|i486|i586|i686|i86pc|BePC)
@@ -298,7 +320,7 @@ case "$cpu" in
   armv*l)
     cpu="armv4l"
   ;;
-  parisc|parisc64)
+  hppa|parisc|parisc64)
     cpu="hppa"
   ;;
   mips*)
@@ -406,6 +428,7 @@ SunOS)
   make="${MAKE-gmake}"
   install="${INSTALL-ginstall}"
   ld="gld"
+  smbd="${SMBD-/usr/sfw/sbin/smbd}"
   needs_libsunmath="no"
   solarisrev=`uname -r | cut -f2 -d.`
   # have to select again, because `uname -m` returns i86pc
@@ -456,6 +479,8 @@ Haiku)
   linux="yes"
   linux_user="yes"
   usb="linux"
+  kvm="yes"
+  vhost_net="yes"
   if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     audio_possible_drivers="$audio_possible_drivers fmod"
   fi
@@ -471,13 +496,15 @@ fi
 
 : ${make=${MAKE-make}}
 : ${install=${INSTALL-install}}
+: ${python=${PYTHON-python}}
+: ${smbd=${SMBD-/usr/sbin/smbd}}
 
 if test "$mingw32" = "yes" ; then
   EXESUF=".exe"
   QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
   # enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
   QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
-  LIBS="-lwinmm -lws2_32 -liphlpapi $LIBS"
+  LIBS="-lwinmm -lws2_32 -liberty -liphlpapi $LIBS"
   prefix="c:/Program Files/Qemu"
   mandir="\${prefix}"
   datadir="\${prefix}"
@@ -485,6 +512,7 @@ if test "$mingw32" = "yes" ; then
   bindir="\${prefix}"
   sysconfdir="\${prefix}"
   confsuffix=""
+  guest_agent="no"
 fi
 
 werror=""
@@ -494,6 +522,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"
@@ -510,6 +540,10 @@ for opt do
   ;;
   --install=*) install="$optarg"
   ;;
+  --python=*) python="$optarg"
+  ;;
+  --smbd=*) smbd="$optarg"
+  ;;
   --extra-cflags=*)
   ;;
   --extra-ldflags=*)
@@ -532,23 +566,35 @@ for opt do
   ;;
   --bindir=*) bindir="$optarg"
   ;;
+  --libdir=*) libdir="$optarg"
+  ;;
+  --includedir=*) includedir="$optarg"
+  ;;
   --datadir=*) datadir="$optarg"
   ;;
   --docdir=*) docdir="$optarg"
   ;;
   --sysconfdir=*) sysconfdir="$optarg"
   ;;
+  --sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\
+  --oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
+  --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
+    # These switches are silently ignored, for compatibility with
+    # autoconf-generated configure scripts. This allows QEMU's
+    # configure to be used by RPM and similar macros that set
+    # lots of directory switches by default.
+  ;;
   --disable-sdl) sdl="no"
   ;;
   --enable-sdl) sdl="yes"
   ;;
-  --fmod-lib=*) fmod_lib="$optarg"
+  --disable-vnc) vnc="no"
   ;;
-  --fmod-inc=*) fmod_inc="$optarg"
+  --enable-vnc) vnc="yes"
   ;;
-  --ffmpeg-inc=*) ffmpeg_inc="$optarg"
+  --fmod-lib=*) fmod_lib="$optarg"
   ;;
-  --v4l2-inc=*) v4l2_inc="$optarg"
+  --fmod-inc=*) fmod_inc="$optarg"
   ;;
   --oss-lib=*) oss_lib="$optarg"
   ;;
@@ -579,11 +625,6 @@ for opt do
   ;;
   --disable-strip) strip_opt="no"
   ;;
-  --disable-jpeg) jpeg="no"
-  ;;
-  --enable-jpeg) jpeg="yes"
-  ;;
-
   --disable-vnc-tls) vnc_tls="no"
   ;;
   --enable-vnc-tls) vnc_tls="yes"
@@ -604,14 +645,6 @@ for opt do
   ;;
   --enable-vnc-thread) vnc_thread="yes"
   ;;
-  --disable-ffmpeg) ffmpeg="no"
-  ;;
-  --enable-ffmpeg) ffmpeg="yes"
-  ;;
-  --disable-v4l2) v4l2="no"
-  ;;
-  --enable-v4l2) v4l2="yes"
-  ;;
   --disable-slirp) slirp="no"
   ;;
   --disable-uuid) uuid="no"
@@ -638,13 +671,29 @@ for opt do
   ;;
   --enable-kvm) kvm="yes"
   ;;
+  --disable-gl) gl="no"
+  ;;
+  --enable-gl) gl="yes"
+  ;;
+  --disable-hax) hax="no"
+  ;;
+  --enable-hax) hax="yes"
+  ;;
+  --disable-tcg-interpreter) tcg_interpreter="no"
+  ;;
+  --enable-tcg-interpreter) tcg_interpreter="yes"
+  ;;
   --disable-spice) spice="no"
   ;;
   --enable-spice) spice="yes"
   ;;
+  --disable-libiscsi) libiscsi="no"
+  ;;
+  --enable-libiscsi) libiscsi="yes"
+  ;;
   --enable-profiler) profiler="yes"
   ;;
-  --enable-tcg-x86-opt) tcg_x86_opt="yes"
+  --enable-ldst-optimization) ldst_optimization="yes"
   ;;
   --enable-cocoa)
       cocoa="yes" ;
@@ -677,9 +726,9 @@ for opt do
   ;;
   --disable-guest-base) guest_base="no"
   ;;
-  --enable-user-pie) user_pie="yes"
+  --enable-pie) pie="yes"
   ;;
-  --disable-user-pie) user_pie="no"
+  --disable-pie) pie="no"
   ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
@@ -719,12 +768,8 @@ for opt do
   ;;
   --enable-attr) attr="yes"
   ;;
-  --enable-io-thread) io_thread="yes"
-  ;;
   --disable-blobs) blobs="no"
   ;;
-  --kerneldir=*) kerneldir="$optarg"
-  ;;
   --with-pkgversion=*) pkgversion=" ($optarg)"
   ;;
   --disable-docs) docs="no"
@@ -735,12 +780,36 @@ for opt do
   ;;
   --enable-vhost-net) vhost_net="yes"
   ;;
-  --*dir)
+  --disable-opengl) opengl="no"
+  ;;
+  --enable-opengl) opengl="yes"
   ;;
   --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"
+  ;;
+  --disable-usb-redir) usb_redir="no"
+  ;;
+  --enable-usb-redir) usb_redir="yes"
+  ;;
+  --disable-zlib-test) zlib="no"
+  ;;
+  --enable-guest-agent) guest_agent="yes"
+  ;;
+  --disable-guest-agent) guest_agent="no"
+  ;;
+# for TIZEN-maru
+  --enable-maru) maru="yes"
+  ;;
+#
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -815,10 +884,84 @@ case "$cpu" in
     hppa*)
            host_guest_base="yes"
            ;;
+    unicore32*)
+           host_guest_base="yes"
+           ;;
 esac
 
 [ -z "$guest_base" ] && guest_base="$host_guest_base"
 
+
+default_target_list=""
+
+# these targets are portable
+if [ "$softmmu" = "yes" ] ; then
+    default_target_list="\
+i386-softmmu \
+x86_64-softmmu \
+alpha-softmmu \
+arm-softmmu \
+cris-softmmu \
+lm32-softmmu \
+m68k-softmmu \
+microblaze-softmmu \
+microblazeel-softmmu \
+mips-softmmu \
+mipsel-softmmu \
+mips64-softmmu \
+mips64el-softmmu \
+ppc-softmmu \
+ppcemb-softmmu \
+ppc64-softmmu \
+sh4-softmmu \
+sh4eb-softmmu \
+sparc-softmmu \
+sparc64-softmmu \
+s390x-softmmu \
+xtensa-softmmu \
+xtensaeb-softmmu \
+"
+fi
+# the following are Linux specific
+if [ "$linux_user" = "yes" ] ; then
+    default_target_list="${default_target_list}\
+i386-linux-user \
+x86_64-linux-user \
+alpha-linux-user \
+arm-linux-user \
+armeb-linux-user \
+cris-linux-user \
+m68k-linux-user \
+microblaze-linux-user \
+microblazeel-linux-user \
+mips-linux-user \
+mipsel-linux-user \
+ppc-linux-user \
+ppc64-linux-user \
+ppc64abi32-linux-user \
+sh4-linux-user \
+sh4eb-linux-user \
+sparc-linux-user \
+sparc64-linux-user \
+sparc32plus-linux-user \
+unicore32-linux-user \
+s390x-linux-user \
+"
+fi
+# the following are Darwin specific
+if [ "$darwin_user" = "yes" ] ; then
+    default_target_list="$default_target_list i386-darwin-user ppc-darwin-user "
+fi
+# the following are BSD specific
+if [ "$bsd_user" = "yes" ] ; then
+    default_target_list="${default_target_list}\
+i386-bsd-user \
+x86_64-bsd-user \
+sparc-bsd-user \
+sparc64-bsd-user \
+"
+fi
+
 if test x"$show_help" = x"yes" ; then
 cat << EOF
 
@@ -831,7 +974,9 @@ echo "  --help                   print this message"
 echo "  --prefix=PREFIX          install in PREFIX [$prefix]"
 echo "  --interp-prefix=PREFIX   where to find shared libraries, etc."
 echo "                           use %M for cpu name [$interp_prefix]"
-echo "  --target-list=LIST       set target list [$target_list]"
+echo "  --target-list=LIST       set target list (default: build everything)"
+echo "Available targets: $default_target_list" | \
+    fold -s -w 53 | sed -e 's/^/                           /'
 echo ""
 echo "Advanced options (experts only):"
 echo "  --source-path=PATH       path of source code [$source_path]"
@@ -843,6 +988,8 @@ echo "  --extra-cflags=CFLAGS    append extra C compiler flags QEMU_CFLAGS"
 echo "  --extra-ldflags=LDFLAGS  append extra linker flags LDFLAGS"
 echo "  --make=MAKE              use specified make [$make]"
 echo "  --install=INSTALL        use specified install [$install]"
+echo "  --python=PYTHON          use specified python [$python]"
+echo "  --smbd=SMBD              use specified smbd [$smbd]"
 echo "  --static                 enable static build [$static]"
 echo "  --mandir=PATH            install man pages in PATH"
 echo "  --datadir=PATH           install firmware in PATH"
@@ -858,6 +1005,8 @@ echo "  --disable-strip          disable stripping binaries"
 echo "  --disable-werror         disable compilation abort on warning"
 echo "  --disable-sdl            disable SDL"
 echo "  --enable-sdl             enable SDL"
+echo "  --disable-vnc            disable VNC"
+echo "  --enable-vnc             enable VNC"
 echo "  --enable-cocoa           enable COCOA (Mac OS X only)"
 echo "  --audio-drv-list=LIST    set audio drivers list:"
 echo "                           Available drivers: $audio_possible_drivers"
@@ -880,10 +1029,6 @@ echo "  --disable-vnc-png        disable PNG compression for VNC server (default
 echo "  --enable-vnc-png         enable PNG compression for VNC server"
 echo "  --disable-vnc-thread     disable threaded VNC server"
 echo "  --enable-vnc-thread      enable threaded VNC server"
-echo "  --disable-ffmpeg         disable FFMPEG lossy compression"
-echo "  --enable-ffmpeg          enable FFMPEG lossy compression"
-echo "  --disable-v4l2           disable camera using v4l2"
-echo "  --enable-v4l2            enable camera using v4l2"
 echo "  --disable-curses         disable curses output"
 echo "  --enable-curses          enable curses output"
 echo "  --disable-curl           disable curl connectivity"
@@ -894,8 +1039,17 @@ echo "  --disable-check-utests   disable check unit-tests"
 echo "  --enable-check-utests    enable check unit-tests"
 echo "  --disable-bluez          disable bluez stack connectivity"
 echo "  --enable-bluez           enable bluez stack connectivity"
+echo "  --disable-slirp          disable SLIRP userspace network connectivity"
 echo "  --disable-kvm            disable KVM acceleration support"
 echo "  --enable-kvm             enable KVM acceleration support"
+echo "  --disable-gl             disable GL acceleration support"
+
+echo "  --disable-hax            disable HAX acceleration support"
+echo "  --enable-hax             enable HAX acceleration support"
+
+echo "  --disable-gl             disable GL acceleration support"
+echo "  --enable-gl              enable GL acceleration support"
+echo "  --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)"
 echo "  --disable-nptl           disable usermode NPTL support"
 echo "  --enable-nptl            enable usermode NPTL support"
 echo "  --enable-system          enable all system emulation targets"
@@ -911,14 +1065,13 @@ echo "  --disable-bsd-user       disable all BSD usermode emulation targets"
 echo "  --enable-guest-base      enable GUEST_BASE support for usermode"
 echo "                           emulation targets"
 echo "  --disable-guest-base     disable GUEST_BASE support"
-echo "  --enable-user-pie        build usermode emulation targets as PIE"
-echo "  --disable-user-pie       do not build usermode emulation targets as PIE"
+echo "  --enable-pie             build Position Independent Executables"
+echo "  --disable-pie            do not build Position Independent Executables"
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
-echo "  --ffmpeg-inc             path to FFMPEG includes"
-echo "  --v4l2-inc               path to V4L2 includes"
 echo "  --oss-lib                path to OSS library"
 echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo "  --cpu=CPU                Build for host CPU [$cpu]"
 echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
 echo "  --disable-uuid           disable uuid support"
 echo "  --enable-uuid            enable uuid support"
@@ -928,9 +1081,7 @@ echo "  --disable-linux-aio      disable Linux AIO support"
 echo "  --enable-linux-aio       enable Linux AIO support"
 echo "  --disable-attr           disables attr and xattr support"
 echo "  --enable-attr            enable attr and xattr support"
-echo "  --enable-io-thread       enable IO thread"
 echo "  --disable-blobs          disable installing provided firmware blobs"
-echo "  --kerneldir=PATH         look for kernel includes in PATH"
 echo "  --enable-docs            enable documentation build"
 echo "  --disable-docs           disable documentation build"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
@@ -942,7 +1093,22 @@ 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-libiscsi       disable iscsi support"
+echo "  --enable-libiscsi        enable iscsi support"
+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 "  --disable-usb-redir      disable usb network redirection support"
+echo "  --enable-usb-redir       enable usb network redirection support"
+echo "  --disable-guest-agent    disable building of the QEMU Guest Agent"
+echo "  --enable-guest-agent     enable building of the QEMU Guest Agent"
+echo ""
+# for TIZEN-maru
+echo "TIZEN-maru options:"
+echo "  --enable-maru            enable maru board"
 echo ""
+#
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
 fi
@@ -962,19 +1128,67 @@ fi
 gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
 gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
 gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
-
-# TODO: build on i386 fails to use -fstack-protector-all option.
-gcc_flags="-fnostack-protector-all $gcc_flags"
-
+gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags"
 cat > $TMPC << EOF
 int main(void) { return 0; }
 EOF
 for flag in $gcc_flags; do
-    if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
+    if compile_prog "$flag -Werror" "" ; then
        QEMU_CFLAGS="$QEMU_CFLAGS $flag"
     fi
 done
 
+if test "$static" = "yes" ; then
+  if test "$pie" = "yes" ; then
+    echo "static and pie are mutually incompatible"
+    exit 1
+  else
+    pie="no"
+  fi
+fi
+
+if test "$pie" = ""; then
+  case "$cpu-$targetos" in
+    i386-Linux|x86_64-Linux|i386-OpenBSD|x86_64-OpenBSD)
+      ;;
+    *)
+      pie="no"
+      ;;
+  esac
+fi
+
+if test "$pie" != "no" ; then
+  cat > $TMPC << EOF
+
+#ifdef __linux__
+#  define THREAD __thread
+#else
+#  define THREAD
+#endif
+
+static THREAD int tls_var;
+
+int main(void) { return tls_var; }
+
+EOF
+  if compile_prog "-fPIE -DPIE" "-pie"; then
+    QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS"
+    LDFLAGS="-pie $LDFLAGS"
+    pie="yes"
+    if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then
+      LDFLAGS="-Wl,-z,relro -Wl,-z,now $LDFLAGS"
+    fi
+  else
+    if test "$pie" = "yes"; then
+      echo "PIE not available due to missing toolchain support"
+      exit 1
+    else
+      echo "Disabling PIE due to missing toolchain support"
+      pie="no"
+    fi
+  fi
+fi
+
 #
 # Solaris specific configure tool chain decisions
 #
@@ -1004,66 +1218,17 @@ if test "$solaris" = "yes" ; then
   fi
 fi
 
+if test "$guest_agent" != "no" ; then
+  if has $python; then
+    :
+  else
+    echo "Python not found. Use --python=/path/to/python"
+    exit 1
+  fi
+fi
 
 if test -z "$target_list" ; then
-# these targets are portable
-    if [ "$softmmu" = "yes" ] ; then
-        target_list="\
-i386-softmmu \
-x86_64-softmmu \
-arm-softmmu \
-cris-softmmu \
-m68k-softmmu \
-microblaze-softmmu \
-mips-softmmu \
-mipsel-softmmu \
-mips64-softmmu \
-mips64el-softmmu \
-ppc-softmmu \
-ppcemb-softmmu \
-ppc64-softmmu \
-sh4-softmmu \
-sh4eb-softmmu \
-sparc-softmmu \
-sparc64-softmmu \
-"
-    fi
-# the following are Linux specific
-    if [ "$linux_user" = "yes" ] ; then
-        target_list="${target_list}\
-i386-linux-user \
-x86_64-linux-user \
-alpha-linux-user \
-arm-linux-user \
-armeb-linux-user \
-cris-linux-user \
-m68k-linux-user \
-microblaze-linux-user \
-mips-linux-user \
-mipsel-linux-user \
-ppc-linux-user \
-ppc64-linux-user \
-ppc64abi32-linux-user \
-sh4-linux-user \
-sh4eb-linux-user \
-sparc-linux-user \
-sparc64-linux-user \
-sparc32plus-linux-user \
-"
-    fi
-# the following are Darwin specific
-    if [ "$darwin_user" = "yes" ] ; then
-        target_list="$target_list i386-darwin-user ppc-darwin-user "
-    fi
-# the following are BSD specific
-    if [ "$bsd_user" = "yes" ] ; then
-        target_list="${target_list}\
-i386-bsd-user \
-x86_64-bsd-user \
-sparc-bsd-user \
-sparc64-bsd-user \
-"
-    fi
+    target_list="$default_target_list"
 else
     target_list=`echo "$target_list" | sed -e 's/,/ /g'`
 fi
@@ -1157,18 +1322,20 @@ fi
 ##########################################
 # zlib check
 
-cat > $TMPC << EOF
+if test "$zlib" != "no" ; then
+    cat > $TMPC << EOF
 #include <zlib.h>
 int main(void) { zlibVersion(); return 0; }
 EOF
-if compile_prog "" "-lz" ; then
-    :
-else
-    echo
-    echo "Error: zlib check failed"
-    echo "Make sure to have the zlib libs and headers installed."
-    echo
-    exit 1
+    if compile_prog "" "-lz" ; then
+        :
+    else
+        echo
+        echo "Error: zlib check failed"
+        echo "Make sure to have the zlib libs and headers installed."
+        echo
+        exit 1
+    fi
 fi
 
 ##########################################
 
 if test "$xen" != "no" ; then
   xen_libs="-lxenstore -lxenctrl -lxenguest"
+
+  # Xen unstable
   cat > $TMPC <<EOF
 #include <xenctrl.h>
 #include <xs.h>
-int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+  xc_interface *xc;
+  xs_daemon_open();
+  xc = xc_interface_open(0, 0, 0);
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_gnttab_open(NULL, 0);
+  xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
+  return 0;
+}
 EOF
   if compile_prog "" "$xen_libs" ; then
+    xen_ctrl_version=410
     xen=yes
-    libs_softmmu="$xen_libs $libs_softmmu"
+
+  # Xen 4.0.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+  struct xen_add_to_physmap xatp = {
+    .domid = 0, .space = XENMAPSPACE_gmfn, .idx = 0, .gpfn = 0,
+  };
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_memory_op(0, XENMEM_add_to_physmap, &xatp);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=400
+    xen=yes
+
+  # Xen 3.4.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+int main(void) {
+  struct xen_add_to_physmap xatp = {
+    .domid = 0, .space = XENMAPSPACE_gmfn, .idx = 0, .gpfn = 0,
+  };
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_memory_op(0, XENMEM_add_to_physmap, &xatp);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=340
+    xen=yes
+
+  # Xen 3.3.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+int main(void) {
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=330
+    xen=yes
+
+  # Xen not found or unsupported
   else
     if test "$xen" = "yes" ; then
       feature_not_found "xen"
     fi
     xen=no
   fi
+
+  if test "$xen" = yes; then
+    libs_softmmu="$xen_libs $libs_softmmu"
+  fi
 fi
 
 ##########################################
 # pkg-config probe
 
 if ! has $pkg_config; then
-  echo warning: proceeding without "$pkg_config" >&2
-  pkg_config=/bin/false
+  echo "Error: pkg-config binary '$pkg_config' not found"
+  exit 1
+fi
+
+##########################################
+# libtool probe
+
+if ! has $libtool; then
+    libtool=
 fi
 
 ##########################################
@@ -1234,7 +1496,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
 
@@ -1301,7 +1563,7 @@ fi
 
 ##########################################
 # VNC TLS detection
-if test "$vnc_tls" != "no" ; then
+if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
   cat > $TMPC <<EOF
 #include <gnutls/gnutls.h>
 int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
@@ -1321,7 +1583,7 @@ fi
 
 ##########################################
 # VNC SASL detection
-if test "$vnc_sasl" != "no" ; then
+if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
   cat > $TMPC <<EOF
 #include <sasl/sasl.h>
 #include <stdio.h>
@@ -1343,7 +1605,7 @@ fi
 
 ##########################################
 # VNC JPEG detection
-if test "$vnc_jpeg" != "no" ; then
+if test "$vnc" = "yes" -a "$vnc_jpeg" != "no" ; then
 cat > $TMPC <<EOF
 #include <stdio.h>
 #include <jpeglib.h>
@@ -1364,7 +1626,7 @@ fi
 
 ##########################################
 # VNC PNG detection
-if test "$vnc_png" != "no" ; then
+if test "$vnc" = "yes" -a "$vnc_png" != "no" ; then
 cat > $TMPC <<EOF
 //#include <stdio.h>
 #include <png.h>
@@ -1375,80 +1637,22 @@ int main(void) {
     return 0;
 }
 EOF
+  if $pkg_config libpng --modversion >/dev/null 2>&1; then
+    vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
+    vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
+  else
     vnc_png_cflags=""
     vnc_png_libs="-lpng"
+  fi
   if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
     vnc_png=yes
     libs_softmmu="$vnc_png_libs $libs_softmmu"
+    QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
   else
     if test "$vnc_png" = "yes" ; then
       feature_not_found "vnc-png"
     fi
-    vnc_png=no
-  fi
-fi
-
-##########################################
-# FFMPEG detection
-if test "$ffmpeg" = "yes" ; then 
-cat > $TMPC <<EOF
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-
-int main(void) { AVFormatContext *pFormatCtx = NULL; av_find_stream_info(pFormatCtx); return 0; }
-EOF
-  ffmpeg_cflags="-I$source_path/tizen/$ffmpeg_inc/include"
-  if test "$linux" = "yes" ; then
-       ffmpeg_libs="-lavformat -lavcodec -lavutil -lm" 
-  elif test "$mingw32" = "yes" ; then
-       ffmpeg_libs="-lavformat.dll -lavcodec.dll -lavutil.dll -lm"
-  fi
-  ffmpeg_libpath="-L$source_path/tizen/$ffmpeg_inc/lib"
-  ffmpeg_libs="$ffmpeg_libpath $ffmpeg_libs"
-  if compile_prog "$ffmpeg_cflags" "$ffmpeg_libs" ; then
-    ffmpeg=yes
-    libs_softmmu="$ffmpeg_libs $libs_softmmu"
-  else
-    if test "$ffmpeg" = "yes" ; then
-      feature_not_found "ffmpeg"
-         exit 1;
-    fi
-    ffmpeg=no
-  fi
-fi
-
-##########################################
-# V4L2 detection
-if test "$v4l2" = "yes" ; then 
-cat > $TMPC <<EOF
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include <libv4l2.h>
-#include <libv4lconvert.h>
-
-int main(void) {v4l2_open("/dev/video0", O_RDWR); return 0; }
-EOF
-
-#  v4l2_cflags="-I$v4l2_inc"
-  if test "$linux" = "yes" ; then
-       v4l2_libs="-lv4l2 -lv4lconvert"
-  fi
-  if compile_prog "$v4l2_cflags" "$v4l2_libs" ; then
-    v4l2=yes
-    libs_softmmu="$v4l2_libs $libs_softmmu"
-  else
-    if test "$v4l2" = "yes" ; then
-      feature_not_found "v4l2"
-    fi
-    v4l2=no
+    vnc_png=no
   fi
 fi
 
@@ -1654,7 +1858,11 @@ fi
 
 ##########################################
 # curses probe
-curses_list="-lncurses -lcurses"
+if test "$mingw32" = "yes" ; then
+    curses_list="-lpdcurses"
+else
+    curses_list="-lncurses -lcurses"
+fi
 
 if test "$curses" != "no" ; then
   curses_found=no
@@ -1694,7 +1902,7 @@ fi
 if test "$curl" != "no" ; then
   cat > $TMPC << EOF
 #include <curl/curl.h>
-int main(void) { return curl_easy_init(); }
+int main(void) { curl_easy_init(); curl_multi_setopt(0, 0, 0); return 0; }
 EOF
   curl_cflags=`$curlconfig --cflags 2>/dev/null`
   curl_libs=`$curlconfig --libs 2>/dev/null`
@@ -1718,7 +1926,7 @@ if test "$check_utests" != "no" ; then
 #include <check.h>
 int main(void) { suite_create("qemu test"); return 0; }
 EOF
-  check_libs=`$pkg_config --libs check`
+  check_libs=`$pkg_config --libs check 2>/dev/null`
   if compile_prog "" $check_libs ; then
     check_utests=yes
     libs_tools="$check_libs $libs_tools"
@@ -1751,111 +1959,20 @@ EOF
 fi
 
 ##########################################
-# kvm probe
-if test "$kvm" != "no" ; then
-    cat > $TMPC <<EOF
-#include <linux/kvm.h>
-#if !defined(KVM_API_VERSION) || KVM_API_VERSION < 12 || KVM_API_VERSION > 12
-#error Invalid KVM version
-#endif
-EOF
-    must_have_caps="KVM_CAP_USER_MEMORY \
-                    KVM_CAP_DESTROY_MEMORY_REGION_WORKS \
-                    KVM_CAP_COALESCED_MMIO \
-                    KVM_CAP_SYNC_MMU \
-                   "
-    if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) ; then
-      must_have_caps="$caps \
-                      KVM_CAP_SET_TSS_ADDR \
-                      KVM_CAP_EXT_CPUID \
-                      KVM_CAP_CLOCKSOURCE \
-                      KVM_CAP_NOP_IO_DELAY \
-                      KVM_CAP_PV_MMU \
-                      KVM_CAP_MP_STATE \
-                      KVM_CAP_USER_NMI \
-                     "
-    fi
-    for c in $must_have_caps ; do
-      cat >> $TMPC <<EOF
-#if !defined($c)
-#error Missing KVM capability $c
-#endif
-EOF
-    done
-    cat >> $TMPC <<EOF
-int main(void) { return 0; }
-EOF
-  if test "$kerneldir" != "" ; then
-      kvm_cflags=-I"$kerneldir"/include
-      if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) \
-         -a -d "$kerneldir/arch/x86/include" ; then
-            kvm_cflags="$kvm_cflags -I$kerneldir/arch/x86/include"
-       elif test "$cpu" = "ppc" -a -d "$kerneldir/arch/powerpc/include" ; then
-           kvm_cflags="$kvm_cflags -I$kerneldir/arch/powerpc/include"
-       elif test "$cpu" = "s390x" -a -d "$kerneldir/arch/s390/include" ; then
-           kvm_cflags="$kvm_cflags -I$kerneldir/arch/s390/include"
-        elif test -d "$kerneldir/arch/$cpu/include" ; then
-            kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
-      fi
-  else
-    kvm_cflags=`$pkg_config --cflags kvm-kmod 2>/dev/null`
-  fi
-  if compile_prog "$kvm_cflags" "" ; then
-    kvm=yes
-    cat > $TMPC <<EOF
-#include <linux/kvm_para.h>
-int main(void) { return 0; }
-EOF
-    if compile_prog "$kvm_cflags" "" ; then
-      kvm_para=yes
-    fi
-  else
-    if test "$kvm" = "yes" ; then
-      if has awk && has grep; then
-        kvmerr=`LANG=C $cc $QEMU_CFLAGS -o $TMPE $kvm_cflags $TMPC 2>&1 \
-       | grep "error: " \
-       | awk -F "error: " '{if (NR>1) printf(", "); printf("%s",$2);}'`
-        if test "$kvmerr" != "" ; then
-          echo -e "${kvmerr}\n\
-NOTE: To enable KVM support, update your kernel to 2.6.29+ or install \
-recent kvm-kmod from http://sourceforge.net/projects/kvm."
-        fi
-      fi
-      feature_not_found "kvm"
-    fi
-    kvm=no
-  fi
-fi
-
-##########################################
-# test for vhost net
-
-if test "$vhost_net" != "no"; then
-    if test "$kvm" != "no"; then
-            cat > $TMPC <<EOF
-    #include <linux/vhost.h>
-    int main(void) { return 0; }
-EOF
-            if compile_prog "$kvm_cflags" "" ; then
-                vhost_net=yes
-            else
-                if test "$vhost_net" = "yes" ; then
-                    feature_not_found "vhost-net"
-                fi
-                vhost_net=no
-            fi
-    else
-            if test "$vhost_net" = "yes" ; then
-                echo "NOTE: vhost-net feature requires KVM (--enable-kvm)."
-                feature_not_found "vhost-net"
-            fi
-            vhost_net=no
-    fi
+# glib support probe
+if $pkg_config --modversion gthread-2.0 > /dev/null 2>&1 ; then
+    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
+    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
+    LIBS="$glib_libs $LIBS"
+    libs_qga="$glib_libs $libs_qga"
+else
+    echo "glib-2.0 required to compile QEMU"
+    exit 1
 fi
 
 ##########################################
 # pthread probe
-PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
+PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
 
 pthread=no
 cat > $TMPC << EOF
@@ -1887,41 +2004,24 @@ fi
 if test "$rbd" != "no" ; then
   cat > $TMPC <<EOF
 #include <stdio.h>
-#include <rados/librados.h>
-int main(void) { rados_initialize(0, NULL); return 0; }
-EOF
-  rbd_libs="-lrados"
-  if compile_prog "" "$rbd_libs" ; then
-    librados_too_old=no
-    cat > $TMPC <<EOF
-#include <stdio.h>
-#include <rados/librados.h>
-#ifndef CEPH_OSD_TMAP_SET
-#error missing CEPH_OSD_TMAP_SET
-#endif
+#include <rbd/librbd.h>
 int main(void) {
-    int (*func)(const rados_pool_t pool, uint64_t *snapid) = rados_selfmanaged_snap_create;
-    rados_initialize(0, NULL);
+    rados_t cluster;
+    rados_create(&cluster, NULL);
     return 0;
 }
 EOF
-    if compile_prog "" "$rbd_libs" ; then
-      rbd=yes
-      libs_tools="$rbd_libs $libs_tools"
-      libs_softmmu="$rbd_libs $libs_softmmu"
-    else
-      rbd=no
-      librados_too_old=yes
-    fi
+  rbd_libs="-lrbd -lrados"
+  if compile_prog "" "$rbd_libs" ; then
+    rbd=yes
+    libs_tools="$rbd_libs $libs_tools"
+    libs_softmmu="$rbd_libs $libs_softmmu"
   else
     if test "$rbd" = "yes" ; then
       feature_not_found "rados block device"
     fi
     rbd=no
   fi
-  if test "$librados_too_old" = "yes" ; then
-    echo "-> Your librados version is too old - upgrade needed to have rbd support"
-  fi
 fi
 
 ##########################################
@@ -1953,12 +2053,20 @@ if test "$attr" != "no" ; then
   cat > $TMPC <<EOF
 #include <stdio.h>
 #include <sys/types.h>
+#ifdef CONFIG_LIBATTR
 #include <attr/xattr.h>
+#else
+#include <sys/xattr.h>
+#endif
 int main(void) { getxattr(NULL, NULL, NULL, 0); setxattr(NULL, NULL, NULL, 0, 0); return 0; }
 EOF
-  if compile_prog "" "-lattr" ; then
+  if compile_prog "" "" ; then
+    attr=yes
+  # Older distros have <attr/xattr.h>, and need -lattr:
+  elif compile_prog "-DCONFIG_LIBATTR" "-lattr" ; then
     attr=yes
     LIBS="-lattr $LIBS"
+    libattr=yes
   else
     if test "$attr" = "yes" ; then
       feature_not_found "ATTR"
@@ -2002,15 +2110,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
@@ -2161,7 +2290,7 @@ cat > $TMPC << EOF
 
 int main(void)
 {
-    int efd = eventfd(0, 0);
+    int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
     return 0;
 }
 EOF
@@ -2231,6 +2360,59 @@ if compile_prog "" "" ; then
   dup3=yes
 fi
 
+# check for epoll support
+epoll=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    epoll_create(0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll=yes
+fi
+
+# epoll_create1 and epoll_pwait are later additions
+# so we must check separately for their presence
+epoll_create1=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    /* 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
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll_create1=yes
+fi
+
+epoll_pwait=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    epoll_pwait(0, 0, 0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll_pwait=yes
+fi
+
 # Check if tools are available to build documentation.
 if test "$docs" != "no" ; then
   if has makeinfo && has pod2man; then
@@ -2265,6 +2447,25 @@ if compile_prog "" "" ; then
   bswap_h=yes
 fi
 
+##########################################
+# Do we have libiscsi
+if test "$libiscsi" != "no" ; then
+  cat > $TMPC << EOF
+#include <iscsi/iscsi.h>
+int main(void) { iscsi_create_context(""); return 0; }
+EOF
+  if compile_prog "-Werror" "-liscsi" ; then
+    libiscsi="yes"
+    LIBS="$LIBS -liscsi"
+  else
+    if test "$libiscsi" = "yes" ; then
+      feature_not_found "libiscsi"
+    fi
+    libiscsi="no"
+  fi
+fi
+
+
 ##########################################
 # Do we need librt
 cat > $TMPC <<EOF
@@ -2296,23 +2497,6 @@ if compile_prog "" "" ; then
     need_offsetof=no
 fi
 
-##########################################
-# check if the compiler understands attribute warn_unused_result
-#
-# This could be smarter, but gcc -Werror does not error out even when warning
-# about attribute warn_unused_result
-
-gcc_attribute_warn_unused_result=no
-cat > $TMPC << EOF
-#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4)
-#error gcc 3.3 or older
-#endif
-int main(void) { return 0;}
-EOF
-if compile_prog "" ""; then
-    gcc_attribute_warn_unused_result=yes
-fi
-
 # spice probe
 if test "$spice" != "no" ; then
   cat > $TMPC << EOF
@@ -2321,7 +2505,7 @@ int main(void) { spice_server_new(); return 0; }
 EOF
   spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
   spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
-  if $pkg_config --atleast-version=0.5.3 spice-server >/dev/null 2>&1 && \
+  if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \
      compile_prog "$spice_cflags" "$spice_libs" ; then
     spice="yes"
     libs_softmmu="$libs_softmmu $spice_libs"
@@ -2334,6 +2518,47 @@ 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
+
+# check for usbredirparser for usb network redirection support
+if test "$usb_redir" != "no" ; then
+    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
+        usb_redir="yes"
+        usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
+        usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
+        QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
+        LIBS="$LIBS $usb_redir_libs"
+    else
+        if test "$usb_redir" = "yes"; then
+            feature_not_found "usb-redir"
+        fi
+        usb_redir="no"
+    fi
+fi
+
 ##########################################
 
 ##########################################
@@ -2342,7 +2567,13 @@ fi
 fdatasync=no
 cat > $TMPC << EOF
 #include <unistd.h>
-int main(void) { return fdatasync(0); }
+int main(void) {
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+return fdatasync(0);
+#else
+#abort Not supported
+#endif
+}
 EOF
 if compile_prog "" "" ; then
     fdatasync=yes
@@ -2420,6 +2651,68 @@ if test "$trace_backend" = "dtrace"; then
   fi
 fi
 
+##########################################
+# __sync_fetch_and_and requires at least -march=i486. Many toolchains
+# use i686 as default anyway, but for those that don't, an explicit
+# specification is necessary
+if test "$vhost_net" = "yes" && test "$cpu" = "i386"; then
+  cat > $TMPC << EOF
+int sfaa(unsigned *ptr)
+{
+  return __sync_fetch_and_and(ptr, 0);
+}
+
+int main(int argc, char **argv)
+{
+  int val = 42;
+  sfaa(&val);
+  return val;
+}
+EOF
+  if ! compile_prog "" "" ; then
+    CFLAGS+="-march=i486"
+  fi
+fi
+
+##########################################
+# check if we have makecontext
+
+ucontext_coroutine=no
+if test "$darwin" != "yes"; then
+  cat > $TMPC << EOF
+#include <ucontext.h>
+int main(void) { makecontext(0, 0, 0); }
+EOF
+  if compile_prog "" "" ; then
+      ucontext_coroutine=yes
+  fi
+fi
+
+##########################################
+# check if we have open_by_handle_at
+
+open_by_hande_at=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+int main(void) { struct file_handle fh; open_by_handle_at(0, &fh, 0); }
+EOF
+if compile_prog "" "" ; then
+    open_by_handle_at=yes
+fi
+
+########################################
+# check if we have linux/magic.h
+
+linux_magic_h=no
+cat > $TMPC << EOF
+#include <linux/magic.h>
+int main(void) {
+}
+EOF
+if compile_prog "" "" ; then
+    linux_magic_h=yes
+fi
+
 ##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
@@ -2477,9 +2770,12 @@ if test "$softmmu" = yes ; then
   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
   if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
       tools="qemu-nbd\$(EXESUF) $tools"
+    if [ "$guest_agent" = "yes" ]; then
+      tools="qemu-ga\$(EXESUF) $tools"
+    fi
     if [ "$check_utests" = "yes" ]; then
-      tools="check-qint check-qstring check-qdict check-qlist $tools"
-      tools="check-qfloat check-qjson $tools"
+      checks="check-qint check-qstring check-qdict check-qlist"
+      checks="check-qfloat check-qjson test-coroutine $checks"
     fi
   fi
 fi
@@ -2491,11 +2787,15 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
         "$softmmu" = yes ; then
   roms="optionrom"
 fi
-
+if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
+  roms="$roms spapr-rtas"
+fi
 
 echo "Install prefix    $prefix"
 echo "BIOS directory    `eval echo $datadir`"
 echo "binary directory  `eval echo $bindir`"
+echo "library directory `eval echo $libdir`"
+echo "include directory `eval echo $includedir`"
 echo "config directory  `eval echo $sysconfdir`"
 if test "$mingw32" = "no" ; then
 echo "Manual directory  `eval echo $mandir`"
@@ -2509,6 +2809,10 @@ echo "QEMU_CFLAGS       $QEMU_CFLAGS"
 echo "LDFLAGS           $LDFLAGS"
 echo "make              $make"
 echo "install           $install"
+echo "python            $python"
+if test "$slirp" = "yes" ; then
+    echo "smbd              $smbd"
+fi
 echo "host CPU          $cpu"
 echo "host big endian   $bigendian"
 echo "target list       $target_list"
@@ -2518,7 +2822,7 @@ echo "gprof enabled     $gprof"
 echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
 echo "profiler          $profiler"
-echo "TCG optimization  $tcg_x86_opt"
+echo "Fast TCG ld/st    $ldst_optimization"
 echo "static build      $static"
 echo "-Werror enabled   $werror"
 if test "$darwin" = "yes" ; then
@@ -2533,13 +2837,14 @@ echo "Audio drivers     $audio_drv_list"
 echo "Extra audio cards $audio_card_list"
 echo "Block whitelist   $block_drv_whitelist"
 echo "Mixer emulation   $mixemu"
-echo "VNC TLS support   $vnc_tls"
-echo "VNC SASL support  $vnc_sasl"
-echo "VNC JPEG support  $vnc_jpeg"
-echo "VNC PNG support   $vnc_png"
-echo "VNC thread        $vnc_thread"
-echo "FFMPEG support    $ffmpeg"
-echo "V4L2 support      $v4l2"  
+echo "VNC support       $vnc"
+if test "$vnc" = "yes" ; then
+    echo "VNC TLS support   $vnc_tls"
+    echo "VNC SASL support  $vnc_sasl"
+    echo "VNC JPEG support  $vnc_jpeg"
+    echo "VNC PNG support   $vnc_png"
+    echo "VNC thread        $vnc_thread"
+fi
 if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
@@ -2551,13 +2856,15 @@ echo "Documentation     $docs"
 echo "uname -r          $uname_release"
 echo "NPTL support      $nptl"
 echo "GUEST_BASE        $guest_base"
-echo "PIE user targets  $user_pie"
+echo "PIE               $pie"
 echo "vde support       $vde"
-echo "IO thread         $io_thread"
 echo "Linux AIO support $linux_aio"
 echo "ATTR/XATTR support $attr"
 echo "Install blobs     $blobs"
 echo "KVM support       $kvm"
+echo "HAX support       $hax"
+echo "GL support        $gl"
+echo "TCG interpreter   $tcg_interpreter"
 echo "fdt support       $fdt"
 echo "preadv support    $preadv"
 echo "fdatasync         $fdatasync"
@@ -2570,8 +2877,17 @@ 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 "usb net redir     $usb_redir"
+echo "OpenGL support    $opengl"
+echo "libiscsi support  $libiscsi"
+echo "build guest agent $guest_agent"
+
+# for TIZEN-maru
+echo "TIZEN-maru support $maru"
+#
 
-if test $sdl_too_old = "yes"; then
+if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
 fi
 
@@ -2586,6 +2902,8 @@ echo >> $config_host_mak
 echo all: >> $config_host_mak
 echo "prefix=$prefix" >> $config_host_mak
 echo "bindir=$bindir" >> $config_host_mak
+echo "libdir=$libdir" >> $config_host_mak
+echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
 echo "datadir=$datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
@@ -2593,12 +2911,21 @@ echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
 
 case "$cpu" in
-  i386|x86_64|alpha|cris|hppa|ia64|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)
     ARCH=arm
   ;;
+  *)
+    if test "$tcg_interpreter" = "yes" ; then
+        echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)"
+        ARCH=tci
+    else
+        echo "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
+        exit 1
+    fi
+  ;;
 esac
 echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
@@ -2657,14 +2984,15 @@ fi
 if test "$static" = "yes" ; then
   echo "CONFIG_STATIC=y" >> $config_host_mak
 fi
-if test $profiler = "yes" ; then
+if test "$profiler" = "yes" ; then
   echo "CONFIG_PROFILER=y" >> $config_host_mak
 fi
-if test $tcg_x86_opt = "yes" ; then
-  echo "CONFIG_TCG_TARGET_X86_OPT=y" >> $config_host_mak
+if test "$ldst_optimization" = "yes" ; then
+  echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_host_mak
 fi
 if test "$slirp" = "yes" ; then
   echo "CONFIG_SLIRP=y" >> $config_host_mak
+  echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
   QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES"
 fi
 if test "$vde" = "yes" ; then
@@ -2692,6 +3020,9 @@ echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak
 if test "$mixemu" = "yes" ; then
   echo "CONFIG_MIXEMU=y" >> $config_host_mak
 fi
+if test "$vnc" = "yes" ; then
+  echo "CONFIG_VNC=y" >> $config_host_mak
+fi
 if test "$vnc_tls" = "yes" ; then
   echo "CONFIG_VNC_TLS=y" >> $config_host_mak
   echo "VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_host_mak
@@ -2700,27 +3031,17 @@ if test "$vnc_sasl" = "yes" ; then
   echo "CONFIG_VNC_SASL=y" >> $config_host_mak
   echo "VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_host_mak
 fi
-if test "$vnc_jpeg" != "no" ; then
+if test "$vnc_jpeg" = "yes" ; then
   echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
   echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
 fi
-if test "$vnc_png" != "no" ; then
+if test "$vnc_png" = "yes" ; then
   echo "CONFIG_VNC_PNG=y" >> $config_host_mak
   echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
 fi
-if test "$vnc_thread" != "no" ; then
+if test "$vnc_thread" = "yes" ; then
   echo "CONFIG_VNC_THREAD=y" >> $config_host_mak
-  echo "CONFIG_THREAD=y" >> $config_host_mak
-fi
-if test "$ffmpeg" = "yes" ; then
-  echo "CONFIG_FFMPEG=y" >> $config_host_mak
-  echo "FFMPEG_CFLAGS=$ffmpeg_cflags" >> $config_host_mak
-fi
-if test "$v4l2" = "yes" ; then
-  echo "CONFIG_V4L2=y" >> $config_host_mak
-  echo "V4L2_CFLAGS=$v4l2_cflags" >> $config_host_mak
 fi
-
 if test "$fnmatch" = "yes" ; then
   echo "CONFIG_FNMATCH=y" >> $config_host_mak
 fi
@@ -2740,8 +3061,6 @@ if [ "$docs" = "yes" ] ; then
 fi
 if test "$sdl" = "yes" ; then
   echo "CONFIG_SDL=y" >> $config_host_mak
-  echo "SDL_LIBS=$sdl_libs -lSDL_image -lSDL_gfx" >> $config_host_mak
-
   echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
 fi
 if test "$cocoa" = "yes" ; then
@@ -2780,6 +3099,15 @@ fi
 if test "$dup3" = "yes" ; then
   echo "CONFIG_DUP3=y" >> $config_host_mak
 fi
+if test "$epoll" = "yes" ; then
+  echo "CONFIG_EPOLL=y" >> $config_host_mak
+fi
+if test "$epoll_create1" = "yes" ; then
+  echo "CONFIG_EPOLL_CREATE1=y" >> $config_host_mak
+fi
+if test "$epoll_pwait" = "yes" ; then
+  echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
+fi
 if test "$inotify" = "yes" ; then
   echo "CONFIG_INOTIFY=y" >> $config_host_mak
 fi
@@ -2803,12 +3131,10 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ=y" >> $config_host_mak
   echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
 fi
+echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
 if test "$xen" = "yes" ; then
-  echo "CONFIG_XEN=y" >> $config_host_mak
-fi
-if test "$io_thread" = "yes" ; then
-  echo "CONFIG_IOTHREAD=y" >> $config_host_mak
-  echo "CONFIG_THREAD=y" >> $config_host_mak
+  echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
+  echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
 fi
 if test "$linux_aio" = "yes" ; then
   echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
@@ -2816,6 +3142,9 @@ fi
 if test "$attr" = "yes" ; then
   echo "CONFIG_ATTR=y" >> $config_host_mak
 fi
+if test "$libattr" = "yes" ; then
+  echo "CONFIG_LIBATTR=y" >> $config_host_mak
+fi
 if test "$linux" = "yes" ; then
   if test "$attr" = "yes" ; then
     echo "CONFIG_VIRTFS=y" >> $config_host_mak
@@ -2836,12 +3165,12 @@ fi
 if test "$signalfd" = "yes" ; then
   echo "CONFIG_SIGNALFD=y" >> $config_host_mak
 fi
+if test "$tcg_interpreter" = "yes" ; then
+  echo "CONFIG_TCG_INTERPRETER=y" >> $config_host_mak
+fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
-if test "$gcc_attribute_warn_unused_result" = "yes" ; then
-  echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak
-fi
 if test "$fdatasync" = "yes" ; then
   echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 fi
@@ -2856,6 +3185,26 @@ 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 "$usb_redir" = "yes" ; then
+  echo "CONFIG_USB_REDIR=y" >> $config_host_mak
+fi
+
+if test "$opengl" = "yes" ; then
+  echo "CONFIG_OPENGL=y" >> $config_host_mak
+fi
+
+if test "$libiscsi" = "yes" ; then
+  echo "CONFIG_LIBISCSI=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
@@ -2870,6 +3219,18 @@ if test "$rbd" = "yes" ; then
   echo "CONFIG_RBD=y" >> $config_host_mak
 fi
 
+if test "$ucontext_coroutine" = "yes" ; then
+  echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
+fi
+
+if test "$open_by_handle_at" = "yes" ; then
+  echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
+fi
+
+if test "$linux_magic_h" = "yes" ; then
+  echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
+fi
+
 # USB host support
 case "$usb" in
 linux)
@@ -2883,26 +3244,51 @@ bsd)
 ;;
 esac
 
+# for TIZEN-maru
+if test "$maru" = "yes" ; then
+  echo "CONFIG_MARU=y" >> $config_host_mak
+fi
+#
+
+# use default implementation for tracing backend-specific routines
+trace_default=yes
 echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak
-if test "$trace_backend" = "simple"; then
-  echo "CONFIG_SIMPLE_TRACE=y" >> $config_host_mak
+if test "$trace_backend" = "nop"; then
+  echo "CONFIG_TRACE_NOP=y" >> $config_host_mak
 fi
-# Set the appropriate trace file.
 if test "$trace_backend" = "simple"; then
-  trace_file="\"$trace_file-%u\""
+  echo "CONFIG_TRACE_SIMPLE=y" >> $config_host_mak
+  trace_default=no
+  # Set the appropriate trace file.
+  trace_file="\"$trace_file-\" FMT_pid"
+fi
+if test "$trace_backend" = "stderr"; then
+  echo "CONFIG_TRACE_STDERR=y" >> $config_host_mak
+  trace_default=no
+fi
+if test "$trace_backend" = "ust"; then
+  echo "CONFIG_TRACE_UST=y" >> $config_host_mak
 fi
-if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
-  echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
+if test "$trace_backend" = "dtrace"; then
+  echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak
+  if test "$trace_backend_stap" = "yes" ; then
+    echo "CONFIG_TRACE_SYSTEMTAP=y" >> $config_host_mak
+  fi
 fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
+if test "$trace_default" = "yes"; then
+  echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
+fi
 
 echo "TOOLS=$tools" >> $config_host_mak
+echo "CHECKS=$checks" >> $config_host_mak
 echo "ROMS=$roms" >> $config_host_mak
 echo "MAKE=$make" >> $config_host_mak
 echo "INSTALL=$install" >> $config_host_mak
-echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak
-echo "INSTALL_DATA=$install -m0644 -p" >> $config_host_mak
-echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak
+echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak
+echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
+echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
+echo "PYTHON=$python" >> $config_host_mak
 echo "CC=$cc" >> $config_host_mak
 echo "CC_I386=$cc_i386" >> $config_host_mak
 echo "HOST_CC=$host_cc" >> $config_host_mak
@@ -2910,6 +3296,7 @@ echo "AR=$ar" >> $config_host_mak
 echo "OBJCOPY=$objcopy" >> $config_host_mak
 echo "LD=$ld" >> $config_host_mak
 echo "WINDRES=$windres" >> $config_host_mak
+echo "LIBTOOL=$libtool" >> $config_host_mak
 echo "CFLAGS=$CFLAGS" >> $config_host_mak
 echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
 echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
@@ -2925,6 +3312,7 @@ echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
 echo "LIBS+=$LIBS" >> $config_host_mak
 echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
 echo "EXESUF=$EXESUF" >> $config_host_mak
+echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
 
 # generate list of library paths for linker script
 
@@ -2943,9 +3331,6 @@ for d in libdis libdis-user; do
     symlink $source_path/Makefile.dis $d/Makefile
     echo > $d/config.mak
 done
-if test "$static" = "no" -a "$user_pie" = "yes" ; then
-  echo "QEMU_CFLAGS+=-fpie" > libdis-user/config.mak
-fi
 
 for target in $target_list; do
 target_dir="$target"
@@ -2954,7 +3339,7 @@ target_arch2=`echo $target | cut -d '-' -f 1`
 target_bigendian="no"
 
 case "$target_arch2" in
-  armeb|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
+  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
   target_bigendian=yes
   ;;
 esac
@@ -3001,6 +3386,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
@@ -3014,6 +3400,11 @@ target_nptl="no"
 interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_arch2/g"`
 echo "CONFIG_QEMU_INTERP_PREFIX=\"$interp_prefix1\"" >> $config_target_mak
 gdb_xml_files=""
+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=""
@@ -3021,14 +3412,16 @@ TARGET_ABI_DIR=""
 
 case "$target_arch2" in
   i386)
-    target_phys_bits=32
+    target_phys_bits=64
   ;;
   x86_64)
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
+    target_long_alignment=8
   ;;
   alpha)
     target_phys_bits=64
+    target_long_alignment=8
     target_nptl="yes"
   ;;
   arm|armeb)
@@ -3037,20 +3430,30 @@ case "$target_arch2" in
     target_nptl="yes"
     gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
     target_phys_bits=32
+    target_llong_alignment=4
   ;;
   cris)
     target_nptl="yes"
     target_phys_bits=32
   ;;
+  lm32)
+    target_phys_bits=32
+    target_libs_softmmu="$opengl_libs"
+  ;;
   m68k)
     bflt="yes"
     gdb_xml_files="cf-core.xml cf-fp.xml"
     target_phys_bits=32
+    target_int_alignment=2
+    target_long_alignment=2
+    target_llong_alignment=2
   ;;
-  microblaze)
+  microblaze|microblazeel)
+    TARGET_ARCH=microblaze
     bflt="yes"
     target_nptl="yes"
     target_phys_bits=32
+    target_libs_softmmu="$fdt_libs"
   ;;
   mips|mipsel)
     TARGET_ARCH=mips
@@ -3069,11 +3472,13 @@ case "$target_arch2" in
     TARGET_BASE_ARCH=mips
     echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
     target_phys_bits=64
+    target_long_alignment=8
   ;;
   ppc)
     gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
-    target_phys_bits=32
+    target_phys_bits=64
     target_nptl="yes"
+    target_libs_softmmu="$fdt_libs"
   ;;
   ppcemb)
     TARGET_BASE_ARCH=ppc
@@ -3081,12 +3486,15 @@ 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
     TARGET_ABI_DIR=ppc
     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
@@ -3095,6 +3503,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
@@ -3108,6 +3517,7 @@ case "$target_arch2" in
   sparc64)
     TARGET_BASE_ARCH=sparc
     target_phys_bits=64
+    target_long_alignment=8
   ;;
   sparc32plus)
     TARGET_ARCH=sparc64
@@ -3117,13 +3527,26 @@ 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
+  ;;
+  xtensa|xtensaeb)
+    TARGET_ARCH=xtensa
+    target_phys_bits=32
   ;;
   *)
     echo "Unsupported target CPU"
     exit 1
   ;;
 esac
+echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
+echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
+echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
+echo "TARGET_LLONG_ALIGNMENT=$target_llong_alignment" >> $config_target_mak
 echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak
 target_arch_name="`echo $TARGET_ARCH | tr '[:lower:]' '[:upper:]'`"
 echo "TARGET_$target_arch_name=y" >> $config_target_mak
@@ -3140,8 +3563,17 @@ echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
 case "$target_arch2" in
   i386|x86_64)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
+      target_phys_bits=64
       echo "CONFIG_XEN=y" >> $config_target_mak
+    else
+      echo "CONFIG_NO_XEN=y" >> $config_target_mak
     fi
+    if test "$gl" = "yes" ; then
+      echo "CONFIG_GL=y" >> $config_target_mak
+    fi
+    ;;
+  *)
+    echo "CONFIG_NO_XEN=y" >> $config_target_mak
 esac
 case "$target_arch2" in
   i386|x86_64|ppcemb|ppc|ppc64|s390x)
@@ -3150,25 +3582,35 @@ case "$target_arch2" in
       \( "$target_arch2" = "$cpu" -o \
       \( "$target_arch2" = "ppcemb" -a "$cpu" = "ppc" \) -o \
       \( "$target_arch2" = "ppc64"  -a "$cpu" = "ppc" \) -o \
+      \( "$target_arch2" = "ppc"    -a "$cpu" = "ppc64" \) -o \
+      \( "$target_arch2" = "ppcemb" -a "$cpu" = "ppc64" \) -o \
       \( "$target_arch2" = "x86_64" -a "$cpu" = "i386"   \) -o \
       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
       echo "CONFIG_KVM=y" >> $config_target_mak
-      echo "KVM_CFLAGS=$kvm_cflags" >> $config_target_mak
-      if test "$kvm_para" = "yes"; then
-        echo "CONFIG_KVM_PARA=y" >> $config_target_mak
-      fi
-      if test $vhost_net = "yes" ; then
+      if test "$vhost_net" = "yes" ; then
         echo "CONFIG_VHOST_NET=y" >> $config_target_mak
       fi
     fi
 esac
+
+case "$target_arch2" in
+  i386|x86_64)
+  if test "$hax" = "yes" ; then
+       echo "CONFIG_HAX=y" >> $config_target_mak
+       echo "CONFIG_HAX=y" >> $config_host_mak
+  fi
+esac
+
+if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then
+  echo "CONFIG_PSERIES=y" >> $config_target_mak
+fi
 if test "$target_bigendian" = "yes" ; then
   echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
 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
@@ -3181,6 +3623,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
@@ -3189,15 +3636,6 @@ 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
-
 if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
   echo "TARGET_HAS_BFLT=y" >> $config_target_mak
 fi
@@ -3218,7 +3656,9 @@ cflags=""
 includes=""
 ldflags=""
 
-if test "$ARCH" = "sparc64" ; then
+if test "$tcg_interpreter" = "yes"; then
+  includes="-I\$(SRC_PATH)/tcg/tci $includes"
+elif test "$ARCH" = "sparc64" ; then
   includes="-I\$(SRC_PATH)/tcg/sparc $includes"
 elif test "$ARCH" = "s390x" ; then
   includes="-I\$(SRC_PATH)/tcg/s390 $includes"
@@ -3228,7 +3668,6 @@ else
   includes="-I\$(SRC_PATH)/tcg/\$(ARCH) $includes"
 fi
 includes="-I\$(SRC_PATH)/tcg $includes"
-includes="-I\$(SRC_PATH)/fpu $includes"
 
 if test "$target_user_only" = "yes" ; then
     libdis_config_mak=libdis-user/config.mak
@@ -3266,7 +3705,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_M68K_DIS=y"  >> $config_target_mak
     echo "CONFIG_M68K_DIS=y"  >> $libdis_config_mak
   ;;
-  microblaze)
+  microblaze*)
     echo "CONFIG_MICROBLAZE_DIS=y"  >> $config_target_mak
     echo "CONFIG_MICROBLAZE_DIS=y"  >> $libdis_config_mak
   ;;
@@ -3290,8 +3729,16 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_SPARC_DIS=y"  >> $config_target_mak
     echo "CONFIG_SPARC_DIS=y"  >> $libdis_config_mak
   ;;
+  xtensa*)
+    echo "CONFIG_XTENSA_DIS=y"  >> $config_target_mak
+    echo "CONFIG_XTENSA_DIS=y"  >> $libdis_config_mak
+  ;;
   esac
 done
+if test "$tcg_interpreter" = "yes" ; then
+  echo "CONFIG_TCI_DIS=y"  >> $config_target_mak
+  echo "CONFIG_TCI_DIS=y"  >> $libdis_config_mak
+fi
 
 case "$ARCH" in
 alpha)
@@ -3305,18 +3752,23 @@ 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"
+    if test "$gl" = "yes" ; then
+      echo "CONFIG_GL=y" >> $config_host_mak
+      if test "$mingw32" = "yes" ; then
+        echo "LIBS+=-lopengl32 -lglu32" >> $config_host_mak
+      else
+        echo "LIBS+=-lGL -lGLU -lXcomposite -lXext -ldl" >> $config_host_mak
+      fi
+    fi
   ;;
   esac
 fi
 
-if test "$target_user_only" = "yes" -a "$static" = "no" -a \
-       "$user_pie" = "yes" ; then
-  cflags="-fpie $cflags"
-  ldflags="-pie $ldflags"
-fi
-
 if test "$target_softmmu" = "yes" -a \( \
         "$TARGET_ARCH" = "microblaze" -o \
         "$TARGET_ARCH" = "cris" \) ; then
@@ -3335,7 +3787,12 @@ if test "$gprof" = "yes" ; then
   fi
 fi
 
-linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/\$(ARCH).ld"
+if test "$ARCH" = "tci"; then
+  linker_script=""
+else
+  linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/\$(ARCH).ld"
+fi
+
 if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
   case "$ARCH" in
   sparc)
@@ -3351,6 +3808,23 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
   esac
 fi
 
+# use included Linux headers
+if test "$linux" = "yes" ; then
+  includes="-I\$(SRC_PATH)/linux-headers $includes"
+  mkdir -p linux-headers
+  case "$cpu" in
+  i386|x86_64)
+    symlink $source_path/linux-headers/asm-x86 linux-headers/asm
+    ;;
+  ppcemb|ppc|ppc64)
+    symlink $source_path/linux-headers/asm-powerpc linux-headers/asm
+    ;;
+  s390x)
+    symlink $source_path/linux-headers/asm-s390 linux-headers/asm
+    ;;
+  esac
+fi
+
 echo "LDFLAGS+=$ldflags" >> $config_target_mak
 echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak
 echo "QEMU_INCLUDES+=$includes" >> $config_target_mak
@@ -3359,18 +3833,30 @@ done # for target in $targets
 
 # build tree in object directory in case the source is not in the current directory
 DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
+DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
-FILES="Makefile tests/Makefile"
+DIRS="$DIRS qapi qapi-generated"
+DIRS="$DIRS qga trace"
+FILES="Makefile tests/Makefile qdict-test-data.txt"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
+FILES="$FILES pc-bios/spapr-rtas/Makefile"
 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-* \
+    $source_path/pc-bios/palcode-*
+do
     FILES="$FILES pc-bios/`basename $bios_file`"
 done
 mkdir -p $DIRS
 for f in $FILES ; do
-    test -e $f || symlink $source_path/$f $f
+    if [ -e "$source_path/$f" ] && ! [ -e "$f" ]; then
+        symlink "$source_path/$f" "$f"
+    fi
 done
 
 # temporary config to build submodules
@@ -3391,15 +3877,21 @@ 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
+    symlink "$source_path/libcacard/Makefile" libcacard/Makefile
+fi
+
 d=libuser
 mkdir -p $d
+mkdir -p $d/trace
 symlink $source_path/Makefile.user $d/Makefile
-if test "$static" = "no" -a "$user_pie" = "yes" ; then
-  echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
-fi
 
 if test "$docs" = "yes" ; then
   mkdir -p QMP
index 57d6eb506c10308d5709d0f5ecae3455b79ca40f..ed6a653fdfc553135ff59d68881457165c0298d7 100644 (file)
--- a/console.c
+++ b/console.c
@@ -115,6 +115,7 @@ typedef enum {
 /* ??? This is mis-named.
    It is used for both text and graphical consoles.  */
 struct TextConsole {
+    int index;
     console_type_t console_type;
     DisplayState *ds;
     /* Graphic console state.  */
@@ -177,12 +178,17 @@ void vga_hw_screen_dump(const char *filename)
     TextConsole *previous_active_console;
 
     previous_active_console = active_console;
-    active_console = consoles[0];
+
     /* There is currently no way of specifying which screen we want to dump,
        so always dump the first one.  */
-    if (consoles[0]->hw_screen_dump)
+    console_select(0);
+    if (consoles[0] && consoles[0]->hw_screen_dump) {
         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
-    active_console = previous_active_console;
+    }
+
+    if (previous_active_console) {
+        console_select(previous_active_console->index);
+    }
 }
 
 void vga_hw_text_update(console_ch_t *chardata)
@@ -343,6 +349,7 @@ static const uint32_t dmask4[4] = {
 
 static uint32_t color_table[2][8];
 
+#ifndef CONFIG_CURSES
 enum color_names {
     COLOR_BLACK   = 0,
     COLOR_RED     = 1,
@@ -353,6 +360,7 @@ enum color_names {
     COLOR_CYAN    = 6,
     COLOR_WHITE   = 7
 };
+#endif
 
 static const uint32_t color_table_rgb[2][8] = {
     {   /* dark */
@@ -461,7 +469,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
             font_data = *font_ptr++;
             if (t_attrib->uline
                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFFFF;
+                font_data = 0xFF;
             }
             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
@@ -474,7 +482,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
             font_data = *font_ptr++;
             if (t_attrib->uline
                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFFFF;
+                font_data = 0xFF;
             }
             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
@@ -487,7 +495,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
         for(i = 0; i < FONT_HEIGHT; i++) {
             font_data = *font_ptr++;
             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFFFF;
+                font_data = 0xFF;
             }
             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
@@ -516,7 +524,7 @@ static void text_console_resize(TextConsole *s)
     if (s->width < w1)
         w1 = s->width;
 
-    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
+    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
     for(y = 0; y < s->total_height; y++) {
         c = &cells[y * s->width];
         if (w1 > 0) {
@@ -531,7 +539,7 @@ static void text_console_resize(TextConsole *s)
             c++;
         }
     }
-    qemu_free(s->cells);
+    g_free(s->cells);
     s->cells = cells;
 }
 
@@ -1102,40 +1110,25 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static void console_send_event(CharDriverState *chr, int event)
-{
-    TextConsole *s = chr->opaque;
-    int i;
-
-    if (event == CHR_EVENT_FOCUS) {
-        for(i = 0; i < nb_consoles; i++) {
-            if (consoles[i] == s) {
-                console_select(i);
-                break;
-            }
-        }
-    }
-}
-
 static void kbd_send_chars(void *opaque)
 {
     TextConsole *s = opaque;
     int len;
     uint8_t buf[16];
 
-    len = qemu_chr_can_read(s->chr);
+    len = qemu_chr_be_can_write(s->chr);
     if (len > s->out_fifo.count)
         len = s->out_fifo.count;
     if (len > 0) {
         if (len > sizeof(buf))
             len = sizeof(buf);
         qemu_fifo_read(&s->out_fifo, buf, len);
-        qemu_chr_read(s->chr, buf, len);
+        qemu_chr_be_write(s->chr, buf, len);
     }
     /* characters are pending: we send them a bit later (XXX:
        horrible, should change char device API) */
     if (s->out_fifo.count > 0) {
-        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
+        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
     }
 }
 
@@ -1252,7 +1245,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 
     if (nb_consoles >= MAX_CONSOLES)
         return NULL;
-    s = qemu_mallocz(sizeof(TextConsole));
+    s = g_malloc0(sizeof(TextConsole));
     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
         (console_type == GRAPHIC_CONSOLE))) {
         active_console = s;
@@ -1260,6 +1253,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
     s->ds = ds;
     s->console_type = console_type;
     if (console_type != GRAPHIC_CONSOLE) {
+        s->index = nb_consoles;
         consoles[nb_consoles++] = s;
     } else {
         /* HACK: Put graphical consoles before text consoles.  */
@@ -1267,7 +1261,9 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
                 break;
             consoles[i] = consoles[i - 1];
+            consoles[i]->index = i;
         }
+        s->index = i;
         consoles[i] = s;
         nb_consoles++;
     }
@@ -1276,46 +1272,48 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 
 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
 {
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
 
+    int linesize = width * 4;
+    qemu_alloc_display(surface, width, height, linesize,
+                       qemu_default_pixelformat(32), 0);
     return surface;
 }
 
 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
                                           int width, int height)
 {
+    int linesize = width * 4;
+    qemu_alloc_display(surface, width, height, linesize,
+                       qemu_default_pixelformat(32), 0);
+    return surface;
+}
+
+void qemu_alloc_display(DisplaySurface *surface, int width, int height,
+                        int linesize, PixelFormat pf, int newflags)
+{
+    void *data;
     surface->width = width;
     surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
-    else
-        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
+    surface->linesize = linesize;
+    surface->pf = pf;
+    if (surface->flags & QEMU_ALLOCATED_FLAG) {
+        data = g_realloc(surface->data,
+                            surface->linesize * surface->height);
+    } else {
+        data = g_malloc(surface->linesize * surface->height);
+    }
+    surface->data = (uint8_t *)data;
+    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
 #ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
+    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
 #endif
-
-    return surface;
 }
 
 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
                                               int linesize, uint8_t *data)
 {
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
 
     surface->width = width;
     surface->height = height;
@@ -1334,8 +1332,8 @@ static void defaultallocator_free_displaysurface(DisplaySurface *surface)
     if (surface == NULL)
         return;
     if (surface->flags & QEMU_ALLOCATED_FLAG)
-        qemu_free(surface->data);
-    qemu_free(surface);
+        g_free(surface->data);
+    g_free(surface);
 }
 
 static struct DisplayAllocator default_allocator = {
@@ -1346,9 +1344,16 @@ static struct DisplayAllocator default_allocator = {
 
 static void dumb_display_init(void)
 {
-    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+    DisplayState *ds = g_malloc0(sizeof(DisplayState));
+    int width = 640;
+    int height = 480;
+
     ds->allocator = &default_allocator;
-    ds->surface = qemu_create_displaysurface(ds, 640, 480);
+    if (is_fixedsize_console()) {
+        width = active_console->g_width;
+        height = active_console->g_height;
+    }
+    ds->surface = qemu_create_displaysurface(ds, width, height);
     register_displaystate(ds);
 }
 
@@ -1394,14 +1399,14 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update,
     TextConsole *s;
     DisplayState *ds;
 
-    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
+    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
     ds->allocator = &default_allocator; 
     ds->surface = qemu_create_displaysurface(ds, 640, 480);
 
     s = new_console(ds, GRAPHIC_CONSOLE);
     if (s == NULL) {
         qemu_free_displaysurface(ds);
-        qemu_free(ds);
+        g_free(ds);
         return NULL;
     }
     s->hw_update = update;
@@ -1453,11 +1458,10 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
     s = chr->opaque;
 
     chr->chr_write = console_puts;
-    chr->chr_send_event = console_send_event;
 
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
-    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
+    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
     s->ds = ds;
 
     if (!color_inited) {
@@ -1505,14 +1509,14 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-CharDriverState *text_console_init(QemuOpts *opts)
+int text_console_init(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
     TextConsole *s;
     unsigned width;
     unsigned height;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
 
     if (n_text_consoles == 128) {
         fprintf(stderr, "Too many text consoles\n");
@@ -1536,8 +1540,8 @@ CharDriverState *text_console_init(QemuOpts *opts)
     }
 
     if (!s) {
-        free(chr);
-        return NULL;
+        g_free(chr);
+        return -EBUSY;
     }
 
     s->chr = chr;
@@ -1545,7 +1549,9 @@ CharDriverState *text_console_init(QemuOpts *opts)
     s->g_height = height;
     chr->opaque = s;
     chr->chr_set_echo = text_console_set_echo;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
 void text_consoles_set_display(DisplayState *ds)
index ed88432a0b25db261b352ec58044c465e187f780..3f490f55de10157660bd764e74305d1d0a6fccd8 100644 (file)
--- a/console.h
+++ b/console.h
@@ -4,6 +4,8 @@
 #include "qemu-char.h"
 #include "qdict.h"
 #include "notify.h"
+#include "qerror.h"
+#include "monitor.h"
 
 /* keyboard/mouse support */
 
@@ -43,8 +45,6 @@ typedef struct QEMUPutLEDEntry {
 
 void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
 void qemu_remove_kbd_event_handler(void);
-void qemu_add_ps2kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
-void qemu_remove_ps2kbd_event_handler(void);
 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
                                                 void *opaque, int absolute,
                                                 const char *name);
@@ -55,7 +55,11 @@ QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque)
 void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
 
 void kbd_put_keycode(int keycode);
+#ifdef CONFIG_MARU
+void qemu_add_ps2kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+void qemu_remove_ps2kbd_event_handler(void);
 void ps2kbd_put_keycode(int keycode);
+#endif
 void kbd_put_ledstate(int ledstate);
 void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
 
@@ -110,7 +114,7 @@ void kbd_put_keysym(int keysym);
 #define QEMU_ALLOCATED_FLAG     0x02
 #define QEMU_REALPIXELS_FLAG    0x04
 
-struct QEMU_PixelFormat {
+struct PixelFormat {
     uint8_t bits_per_pixel;
     uint8_t bytes_per_pixel;
     uint8_t depth; /* color depth in bits */
@@ -127,7 +131,7 @@ struct DisplaySurface {
     int linesize;        /* bytes per line */
     uint8_t *data;
 
-    struct QEMU_PixelFormat pf;
+    struct PixelFormat pf;
 };
 
 /* cursor data format is 32bit RGBA */
@@ -192,6 +196,8 @@ void register_displaystate(DisplayState *ds);
 DisplayState *get_displaystate(void);
 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
                                                 int linesize, uint8_t *data);
+void qemu_alloc_display(DisplaySurface *surface, int width, int height,
+                        int linesize, PixelFormat pf, int newflags);
 PixelFormat qemu_different_endianness_pixelformat(int bpp);
 PixelFormat qemu_default_pixelformat(int bpp);
 
@@ -327,7 +333,12 @@ static inline int ds_get_bytes_per_pixel(DisplayState *ds)
     return ds->surface->pf.bytes_per_pixel;
 }
 
+#ifdef CONFIG_CURSES
+#include <curses.h>
+typedef chtype console_ch_t;
+#else
 typedef unsigned long console_ch_t;
+#endif
 static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
 {
     if (!(ch & 0xff))
@@ -353,7 +364,7 @@ void vga_hw_text_update(console_ch_t *chardata);
 
 int is_graphic_console(void);
 int is_fixedsize_console(void);
-CharDriverState *text_console_init(QemuOpts *opts);
+int text_console_init(QemuOpts *opts, CharDriverState **_chr);
 void text_consoles_set_display(DisplayState *ds);
 void console_select(unsigned int index);
 void console_color_init(DisplayState *ds);
@@ -363,9 +374,6 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
 
 /* sdl.c */
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
-void sdl_display_set_rotation(int rot);
-void sdl_display_set_window_size(int w, int h);
-void sdl_display_force_refresh(void);
 
 /* cocoa.m */
 void cocoa_display_init(DisplayState *ds, int full_screen);
@@ -374,12 +382,24 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
 void vnc_display_init(DisplayState *ds);
 void vnc_display_close(DisplayState *ds);
 int vnc_display_open(DisplayState *ds, const char *display);
-int vnc_display_password(DisplayState *ds, const char *password);
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth);
 int vnc_display_disable_login(DisplayState *ds);
-int vnc_display_pw_expire(DisplayState *ds, time_t expires);
-void do_info_vnc_print(Monitor *mon, const QObject *data);
-void do_info_vnc(Monitor *mon, QObject **ret_data);
 char *vnc_display_local_addr(DisplayState *ds);
+#ifdef CONFIG_VNC
+int vnc_display_password(DisplayState *ds, const char *password);
+int vnc_display_pw_expire(DisplayState *ds, time_t expires);
+#else
+static inline int vnc_display_password(DisplayState *ds, const char *password)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+}
+static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+};
+#endif
 
 /* curses.c */
 void curses_display_init(DisplayState *ds, int full_screen);
diff --git a/coroutine-gthread.c b/coroutine-gthread.c
new file mode 100644 (file)
index 0000000..fdea27a
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * GThread coroutine initialization code
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2011  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * 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.0 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 <glib.h>
+#include "qemu-common.h"
+#include "qemu-coroutine-int.h"
+
+typedef struct {
+    Coroutine base;
+    GThread *thread;
+    bool runnable;
+    CoroutineAction action;
+} CoroutineGThread;
+
+static GCond *coroutine_cond;
+static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
+static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
+
+static void __attribute__((constructor)) coroutine_init(void)
+{
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+
+    coroutine_cond = g_cond_new();
+}
+
+static void coroutine_wait_runnable_locked(CoroutineGThread *co)
+{
+    while (!co->runnable) {
+        g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
+    }
+}
+
+static void coroutine_wait_runnable(CoroutineGThread *co)
+{
+    g_static_mutex_lock(&coroutine_lock);
+    coroutine_wait_runnable_locked(co);
+    g_static_mutex_unlock(&coroutine_lock);
+}
+
+static gpointer coroutine_thread(gpointer opaque)
+{
+    CoroutineGThread *co = opaque;
+
+    g_static_private_set(&coroutine_key, co, NULL);
+    coroutine_wait_runnable(co);
+    co->base.entry(co->base.entry_arg);
+    qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
+    return NULL;
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    CoroutineGThread *co;
+
+    co = g_malloc0(sizeof(*co));
+    co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
+                                      G_THREAD_PRIORITY_NORMAL, NULL);
+    if (!co->thread) {
+        g_free(co);
+        return NULL;
+    }
+    return &co->base;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_);
+
+    g_thread_join(co->thread);
+    g_free(co);
+}
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_,
+                                      Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
+    CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);
+
+    g_static_mutex_lock(&coroutine_lock);
+    from->runnable = false;
+    from->action = action;
+    to->runnable = true;
+    to->action = action;
+    g_cond_broadcast(coroutine_cond);
+
+    if (action != COROUTINE_TERMINATE) {
+        coroutine_wait_runnable_locked(from);
+    }
+    g_static_mutex_unlock(&coroutine_lock);
+    return from->action;
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    CoroutineGThread *co = g_static_private_get(&coroutine_key);
+
+    if (!co) {
+        co = g_malloc0(sizeof(*co));
+        co->runnable = true;
+        g_static_private_set(&coroutine_key, co, (GDestroyNotify)g_free);
+    }
+
+    return &co->base;
+}
+
+bool qemu_in_coroutine(void)
+{
+    CoroutineGThread *co = g_static_private_get(&coroutine_key);
+
+    return co && co->base.caller;
+}
diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
new file mode 100644 (file)
index 0000000..3d01075
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * ucontext coroutine initialization code
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2011  Kevin Wolf <kwolf@redhat.com>
+ *
+ * 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.0 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/>.
+ */
+
+/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+#include <stdlib.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <ucontext.h>
+#include "qemu-common.h"
+#include "qemu-coroutine-int.h"
+
+enum {
+    /* Maximum free pool size prevents holding too many freed coroutines */
+    POOL_MAX_SIZE = 64,
+};
+
+/** Free list to speed up creation */
+static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool);
+static unsigned int pool_size;
+
+typedef struct {
+    Coroutine base;
+    void *stack;
+    jmp_buf env;
+} CoroutineUContext;
+
+/**
+ * Per-thread coroutine bookkeeping
+ */
+typedef struct {
+    /** Currently executing coroutine */
+    Coroutine *current;
+
+    /** The default coroutine */
+    CoroutineUContext leader;
+} CoroutineThreadState;
+
+static pthread_key_t thread_state_key;
+
+/*
+ * va_args to makecontext() must be type 'int', so passing
+ * the pointer we need may require several int args. This
+ * union is a quick hack to let us do that
+ */
+union cc_arg {
+    void *p;
+    int i[2];
+};
+
+static CoroutineThreadState *coroutine_get_thread_state(void)
+{
+    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+    if (!s) {
+        s = g_malloc0(sizeof(*s));
+        s->current = &s->leader.base;
+        pthread_setspecific(thread_state_key, s);
+    }
+    return s;
+}
+
+static void qemu_coroutine_thread_cleanup(void *opaque)
+{
+    CoroutineThreadState *s = opaque;
+
+    g_free(s);
+}
+
+static void __attribute__((destructor)) coroutine_cleanup(void)
+{
+    Coroutine *co;
+    Coroutine *tmp;
+
+    QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
+        g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
+        g_free(co);
+    }
+}
+
+static void __attribute__((constructor)) coroutine_init(void)
+{
+    int ret;
+
+    ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
+    if (ret != 0) {
+        fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
+        abort();
+    }
+}
+
+static void coroutine_trampoline(int i0, int i1)
+{
+    union cc_arg arg;
+    CoroutineUContext *self;
+    Coroutine *co;
+
+    arg.i[0] = i0;
+    arg.i[1] = i1;
+    self = arg.p;
+    co = &self->base;
+
+    /* Initialize longjmp environment and switch back the caller */
+    if (!setjmp(self->env)) {
+        longjmp(*(jmp_buf *)co->entry_arg, 1);
+    }
+
+    while (true) {
+        co->entry(co->entry_arg);
+        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
+    }
+}
+
+static Coroutine *coroutine_new(void)
+{
+    const size_t stack_size = 1 << 20;
+    CoroutineUContext *co;
+    ucontext_t old_uc, uc;
+    jmp_buf old_env;
+    union cc_arg arg = {0};
+
+    /* The ucontext functions preserve signal masks which incurs a system call
+     * overhead.  setjmp()/longjmp() does not preserve signal masks but only
+     * works on the current stack.  Since we need a way to create and switch to
+     * a new stack, use the ucontext functions for that but setjmp()/longjmp()
+     * for everything else.
+     */
+
+    if (getcontext(&uc) == -1) {
+        abort();
+    }
+
+    co = g_malloc0(sizeof(*co));
+    co->stack = g_malloc(stack_size);
+    co->base.entry_arg = &old_env; /* stash away our jmp_buf */
+
+    uc.uc_link = &old_uc;
+    uc.uc_stack.ss_sp = co->stack;
+    uc.uc_stack.ss_size = stack_size;
+    uc.uc_stack.ss_flags = 0;
+
+    arg.p = co;
+
+    makecontext(&uc, (void (*)(void))coroutine_trampoline,
+                2, arg.i[0], arg.i[1]);
+
+    /* swapcontext() in, longjmp() back out */
+    if (!setjmp(old_env)) {
+        swapcontext(&old_uc, &uc);
+    }
+    return &co->base;
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    Coroutine *co;
+
+    co = QLIST_FIRST(&pool);
+    if (co) {
+        QLIST_REMOVE(co, pool_next);
+        pool_size--;
+    } else {
+        co = coroutine_new();
+    }
+    return co;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
+
+    if (pool_size < POOL_MAX_SIZE) {
+        QLIST_INSERT_HEAD(&pool, &co->base, pool_next);
+        co->base.caller = NULL;
+        pool_size++;
+        return;
+    }
+
+    g_free(co->stack);
+    g_free(co);
+}
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
+    CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
+    CoroutineThreadState *s = coroutine_get_thread_state();
+    int ret;
+
+    s->current = to_;
+
+    ret = setjmp(from->env);
+    if (ret == 0) {
+        longjmp(to->env, action);
+    }
+    return ret;
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    CoroutineThreadState *s = coroutine_get_thread_state();
+
+    return s->current;
+}
+
+bool qemu_in_coroutine(void)
+{
+    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+    return s && s->current->caller;
+}
diff --git a/coroutine-win32.c b/coroutine-win32.c
new file mode 100644 (file)
index 0000000..4179609
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Win32 coroutine initialization code
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf@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 "qemu-coroutine-int.h"
+
+typedef struct
+{
+    Coroutine base;
+
+    LPVOID fiber;
+    CoroutineAction action;
+} CoroutineWin32;
+
+static __thread CoroutineWin32 leader;
+static __thread Coroutine *current;
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
+    CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
+
+    current = to_;
+
+    to->action = action;
+    SwitchToFiber(to->fiber);
+    return from->action;
+}
+
+static void CALLBACK coroutine_trampoline(void *co_)
+{
+    Coroutine *co = co_;
+
+    while (true) {
+        co->entry(co->entry_arg);
+        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
+    }
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    const size_t stack_size = 1 << 20;
+    CoroutineWin32 *co;
+
+    co = g_malloc0(sizeof(*co));
+    co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
+    return &co->base;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
+
+    DeleteFiber(co->fiber);
+    g_free(co);
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    if (!current) {
+        current = &leader.base;
+        leader.fiber = ConvertThreadToFiber(NULL);
+    }
+    return current;
+}
+
+bool qemu_in_coroutine(void)
+{
+    return current && current->caller;
+}
index ffbd6a4df832f35459185f3f27ec106a89a246ee..5f47ab8df9a5e04aad82ac3f5811b42c8d1e18d9 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -20,6 +20,7 @@
 #define CPU_ALL_H
 
 #include "qemu-common.h"
+#include "qemu-tls.h"
 #include "cpu-common.h"
 
 /* some important defines:
@@ -35,8 +36,6 @@
  * TARGET_WORDS_BIGENDIAN : same for target cpu
  */
 
-#include "softfloat.h"
-
 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
 #define BSWAP_NEEDED
 #endif
@@ -114,60 +113,6 @@ static inline void tswap64s(uint64_t *s)
 #define bswaptls(s) bswap64s(s)
 #endif
 
-typedef union {
-    float32 f;
-    uint32_t l;
-} CPU_FloatU;
-
-/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
-   endian ! */
-typedef union {
-    float64 d;
-#if defined(HOST_WORDS_BIGENDIAN) \
-    || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
-    struct {
-        uint32_t upper;
-        uint32_t lower;
-    } l;
-#else
-    struct {
-        uint32_t lower;
-        uint32_t upper;
-    } l;
-#endif
-    uint64_t ll;
-} CPU_DoubleU;
-
-#ifdef TARGET_SPARC
-typedef union {
-    float128 q;
-#if defined(HOST_WORDS_BIGENDIAN) \
-    || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
-    struct {
-        uint32_t upmost;
-        uint32_t upper;
-        uint32_t lower;
-        uint32_t lowest;
-    } l;
-    struct {
-        uint64_t upper;
-        uint64_t lower;
-    } ll;
-#else
-    struct {
-        uint32_t lowest;
-        uint32_t lower;
-        uint32_t upper;
-        uint32_t upmost;
-    } l;
-    struct {
-        uint64_t lower;
-        uint64_t upper;
-    } ll;
-#endif
-} CPU_QuadU;
-#endif
-
 /* CPU memory access without any memory or io remapping */
 
 /*
@@ -203,392 +148,8 @@ typedef union {
  *   user   : user mode access using soft MMU
  *   kernel : kernel mode access using soft MMU
  */
-static inline int ldub_p(const void *ptr)
-{
-    return *(uint8_t *)ptr;
-}
-
-static inline int ldsb_p(const void *ptr)
-{
-    return *(int8_t *)ptr;
-}
-
-static inline void stb_p(void *ptr, int v)
-{
-    *(uint8_t *)ptr = v;
-}
-
-/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
-   kernel handles unaligned load/stores may give better results, but
-   it is a system wide setting : bad */
-#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
-
-/* conservative code for little endian unaligned accesses */
-static inline int lduw_le_p(const void *ptr)
-{
-#ifdef _ARCH_PPC
-    int val;
-    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
-    return val;
-#else
-    const uint8_t *p = ptr;
-    return p[0] | (p[1] << 8);
-#endif
-}
-
-static inline int ldsw_le_p(const void *ptr)
-{
-#ifdef _ARCH_PPC
-    int val;
-    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
-    return (int16_t)val;
-#else
-    const uint8_t *p = ptr;
-    return (int16_t)(p[0] | (p[1] << 8));
-#endif
-}
-
-static inline int ldl_le_p(const void *ptr)
-{
-#ifdef _ARCH_PPC
-    int val;
-    __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
-    return val;
-#else
-    const uint8_t *p = ptr;
-    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-#endif
-}
-
-static inline uint64_t ldq_le_p(const void *ptr)
-{
-    const uint8_t *p = ptr;
-    uint32_t v1, v2;
-    v1 = ldl_le_p(p);
-    v2 = ldl_le_p(p + 4);
-    return v1 | ((uint64_t)v2 << 32);
-}
-
-static inline void stw_le_p(void *ptr, int v)
-{
-#ifdef _ARCH_PPC
-    __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
-#else
-    uint8_t *p = ptr;
-    p[0] = v;
-    p[1] = v >> 8;
-#endif
-}
-
-static inline void stl_le_p(void *ptr, int v)
-{
-#ifdef _ARCH_PPC
-    __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
-#else
-    uint8_t *p = ptr;
-    p[0] = v;
-    p[1] = v >> 8;
-    p[2] = v >> 16;
-    p[3] = v >> 24;
-#endif
-}
-
-static inline void stq_le_p(void *ptr, uint64_t v)
-{
-    uint8_t *p = ptr;
-    stl_le_p(p, (uint32_t)v);
-    stl_le_p(p + 4, v >> 32);
-}
-
-/* float access */
-
-static inline float32 ldfl_le_p(const void *ptr)
-{
-    union {
-        float32 f;
-        uint32_t i;
-    } u;
-    u.i = ldl_le_p(ptr);
-    return u.f;
-}
-
-static inline void stfl_le_p(void *ptr, float32 v)
-{
-    union {
-        float32 f;
-        uint32_t i;
-    } u;
-    u.f = v;
-    stl_le_p(ptr, u.i);
-}
-
-static inline float64 ldfq_le_p(const void *ptr)
-{
-    CPU_DoubleU u;
-    u.l.lower = ldl_le_p(ptr);
-    u.l.upper = ldl_le_p(ptr + 4);
-    return u.d;
-}
-
-static inline void stfq_le_p(void *ptr, float64 v)
-{
-    CPU_DoubleU u;
-    u.d = v;
-    stl_le_p(ptr, u.l.lower);
-    stl_le_p(ptr + 4, u.l.upper);
-}
-
-#else
-
-static inline int lduw_le_p(const void *ptr)
-{
-    return *(uint16_t *)ptr;
-}
-
-static inline int ldsw_le_p(const void *ptr)
-{
-    return *(int16_t *)ptr;
-}
-
-static inline int ldl_le_p(const void *ptr)
-{
-    return *(uint32_t *)ptr;
-}
-
-static inline uint64_t ldq_le_p(const void *ptr)
-{
-    return *(uint64_t *)ptr;
-}
-
-static inline void stw_le_p(void *ptr, int v)
-{
-    *(uint16_t *)ptr = v;
-}
-
-static inline void stl_le_p(void *ptr, int v)
-{
-    *(uint32_t *)ptr = v;
-}
-
-static inline void stq_le_p(void *ptr, uint64_t v)
-{
-    *(uint64_t *)ptr = v;
-}
-
-/* float access */
-
-static inline float32 ldfl_le_p(const void *ptr)
-{
-    return *(float32 *)ptr;
-}
-
-static inline float64 ldfq_le_p(const void *ptr)
-{
-    return *(float64 *)ptr;
-}
-
-static inline void stfl_le_p(void *ptr, float32 v)
-{
-    *(float32 *)ptr = v;
-}
-
-static inline void stfq_le_p(void *ptr, float64 v)
-{
-    *(float64 *)ptr = v;
-}
-#endif
-
-#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
-
-static inline int lduw_be_p(const void *ptr)
-{
-#if defined(__i386__)
-    int val;
-    asm volatile ("movzwl %1, %0\n"
-                  "xchgb %b0, %h0\n"
-                  : "=q" (val)
-                  : "m" (*(uint16_t *)ptr));
-    return val;
-#else
-    const uint8_t *b = ptr;
-    return ((b[0] << 8) | b[1]);
-#endif
-}
-
-static inline int ldsw_be_p(const void *ptr)
-{
-#if defined(__i386__)
-    int val;
-    asm volatile ("movzwl %1, %0\n"
-                  "xchgb %b0, %h0\n"
-                  : "=q" (val)
-                  : "m" (*(uint16_t *)ptr));
-    return (int16_t)val;
-#else
-    const uint8_t *b = ptr;
-    return (int16_t)((b[0] << 8) | b[1]);
-#endif
-}
-
-static inline int ldl_be_p(const void *ptr)
-{
-#if defined(__i386__) || defined(__x86_64__)
-    int val;
-    asm volatile ("movl %1, %0\n"
-                  "bswap %0\n"
-                  : "=r" (val)
-                  : "m" (*(uint32_t *)ptr));
-    return val;
-#else
-    const uint8_t *b = ptr;
-    return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
-#endif
-}
-
-static inline uint64_t ldq_be_p(const void *ptr)
-{
-    uint32_t a,b;
-    a = ldl_be_p(ptr);
-    b = ldl_be_p((uint8_t *)ptr + 4);
-    return (((uint64_t)a<<32)|b);
-}
-
-static inline void stw_be_p(void *ptr, int v)
-{
-#if defined(__i386__)
-    asm volatile ("xchgb %b0, %h0\n"
-                  "movw %w0, %1\n"
-                  : "=q" (v)
-                  : "m" (*(uint16_t *)ptr), "0" (v));
-#else
-    uint8_t *d = (uint8_t *) ptr;
-    d[0] = v >> 8;
-    d[1] = v;
-#endif
-}
-
-static inline void stl_be_p(void *ptr, int v)
-{
-#if defined(__i386__) || defined(__x86_64__)
-    asm volatile ("bswap %0\n"
-                  "movl %0, %1\n"
-                  : "=r" (v)
-                  : "m" (*(uint32_t *)ptr), "0" (v));
-#else
-    uint8_t *d = (uint8_t *) ptr;
-    d[0] = v >> 24;
-    d[1] = v >> 16;
-    d[2] = v >> 8;
-    d[3] = v;
-#endif
-}
-
-static inline void stq_be_p(void *ptr, uint64_t v)
-{
-    stl_be_p(ptr, v >> 32);
-    stl_be_p((uint8_t *)ptr + 4, v);
-}
-
-/* float access */
-
-static inline float32 ldfl_be_p(const void *ptr)
-{
-    union {
-        float32 f;
-        uint32_t i;
-    } u;
-    u.i = ldl_be_p(ptr);
-    return u.f;
-}
-
-static inline void stfl_be_p(void *ptr, float32 v)
-{
-    union {
-        float32 f;
-        uint32_t i;
-    } u;
-    u.f = v;
-    stl_be_p(ptr, u.i);
-}
-
-static inline float64 ldfq_be_p(const void *ptr)
-{
-    CPU_DoubleU u;
-    u.l.upper = ldl_be_p(ptr);
-    u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
-    return u.d;
-}
-
-static inline void stfq_be_p(void *ptr, float64 v)
-{
-    CPU_DoubleU u;
-    u.d = v;
-    stl_be_p(ptr, u.l.upper);
-    stl_be_p((uint8_t *)ptr + 4, u.l.lower);
-}
-
-#else
-
-static inline int lduw_be_p(const void *ptr)
-{
-    return *(uint16_t *)ptr;
-}
-
-static inline int ldsw_be_p(const void *ptr)
-{
-    return *(int16_t *)ptr;
-}
 
-static inline int ldl_be_p(const void *ptr)
-{
-    return *(uint32_t *)ptr;
-}
-
-static inline uint64_t ldq_be_p(const void *ptr)
-{
-    return *(uint64_t *)ptr;
-}
-
-static inline void stw_be_p(void *ptr, int v)
-{
-    *(uint16_t *)ptr = v;
-}
-
-static inline void stl_be_p(void *ptr, int v)
-{
-    *(uint32_t *)ptr = v;
-}
-
-static inline void stq_be_p(void *ptr, uint64_t v)
-{
-    *(uint64_t *)ptr = v;
-}
-
-/* float access */
-
-static inline float32 ldfl_be_p(const void *ptr)
-{
-    return *(float32 *)ptr;
-}
-
-static inline float64 ldfq_be_p(const void *ptr)
-{
-    return *(float64 *)ptr;
-}
-
-static inline void stfl_be_p(void *ptr, float32 v)
-{
-    *(float32 *)ptr = v;
-}
-
-static inline void stfq_be_p(void *ptr, float64 v)
-{
-    *(float64 *)ptr = v;
-}
-
-#endif
-
-/* target CPU memory access functions */
+/* target-endianness CPU memory access functions */
 #if defined(TARGET_WORDS_BIGENDIAN)
 #define lduw_p(p) lduw_be_p(p)
 #define ldsw_p(p) ldsw_be_p(p)
@@ -730,7 +291,6 @@ extern unsigned long reserved_va;
 
 /* ??? These should be the larger of unsigned long and target_ulong.  */
 extern unsigned long qemu_real_host_page_size;
-extern unsigned long qemu_host_page_bits;
 extern unsigned long qemu_host_page_size;
 extern unsigned long qemu_host_page_mask;
 
@@ -775,27 +335,76 @@ void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
 void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
 extern CPUState *first_cpu;
-extern CPUState *cpu_single_env;
-
-#define CPU_INTERRUPT_HARD   0x02 /* hardware interrupt pending */
-#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
-#define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
-#define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
-#define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
-#define CPU_INTERRUPT_SMI    0x40 /* (x86 only) SMI interrupt pending */
-#define CPU_INTERRUPT_DEBUG  0x80 /* Debug event occured.  */
-#define CPU_INTERRUPT_VIRQ   0x100 /* virtual interrupt pending.  */
-#define CPU_INTERRUPT_NMI    0x200 /* NMI pending. */
-#define CPU_INTERRUPT_INIT   0x400 /* INIT pending. */
-#define CPU_INTERRUPT_SIPI   0x800 /* SIPI pending. */
-#define CPU_INTERRUPT_MCE    0x1000 /* (x86 only) MCE pending. */
-
-void cpu_interrupt(CPUState *s, int mask);
+DECLARE_TLS(CPUState *,cpu_single_env);
+#define cpu_single_env get_tls(cpu_single_env)
+
+/* Flags for use in ENV->INTERRUPT_PENDING.
+
+   The numbers assigned here are non-sequential in order to preserve
+   binary compatibility with the vmstate dump.  Bit 0 (0x0001) was
+   previously used for CPU_INTERRUPT_EXIT, and is cleared when loading
+   the vmstate dump.  */
+
+/* External hardware interrupt pending.  This is typically used for
+   interrupts from devices.  */
+#define CPU_INTERRUPT_HARD        0x0002
+
+/* Exit the current TB.  This is typically used when some system-level device
+   makes some change to the memory mapping.  E.g. the a20 line change.  */
+#define CPU_INTERRUPT_EXITTB      0x0004
+
+/* Halt the CPU.  */
+#define CPU_INTERRUPT_HALT        0x0020
+
+/* Debug event pending.  */
+#define CPU_INTERRUPT_DEBUG       0x0080
+
+/* Several target-specific external hardware interrupts.  Each target/cpu.h
+   should define proper names based on these defines.  */
+#define CPU_INTERRUPT_TGT_EXT_0   0x0008
+#define CPU_INTERRUPT_TGT_EXT_1   0x0010
+#define CPU_INTERRUPT_TGT_EXT_2   0x0040
+#define CPU_INTERRUPT_TGT_EXT_3   0x0200
+#define CPU_INTERRUPT_TGT_EXT_4   0x1000
+
+/* Several target-specific internal interrupts.  These differ from the
+   preceeding target-specific interrupts in that they are intended to
+   originate from within the cpu itself, typically in response to some
+   instruction being executed.  These, therefore, are not masked while
+   single-stepping within the debugger.  */
+#define CPU_INTERRUPT_TGT_INT_0   0x0100
+#define CPU_INTERRUPT_TGT_INT_1   0x0400
+#define CPU_INTERRUPT_TGT_INT_2   0x0800
+
+/* First unused bit: 0x2000.  */
+
+/* The set of all bits that should be masked when single-stepping.  */
+#define CPU_INTERRUPT_SSTEP_MASK \
+    (CPU_INTERRUPT_HARD          \
+     | CPU_INTERRUPT_TGT_EXT_0   \
+     | CPU_INTERRUPT_TGT_EXT_1   \
+     | CPU_INTERRUPT_TGT_EXT_2   \
+     | CPU_INTERRUPT_TGT_EXT_3   \
+     | CPU_INTERRUPT_TGT_EXT_4)
+
+#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);
 
-int qemu_cpu_has_work(CPUState *env);
+bool qemu_cpu_has_work(CPUState *env);
 
 /* Breakpoint/watchpoint flags */
 #define BP_MEM_READ           0x01
@@ -863,10 +472,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
 extern int phys_ram_fd;
 extern ram_addr_t ram_size;
 
+/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
+#define RAM_PREALLOC_MASK   (1 << 0)
+
 typedef struct RAMBlock {
     uint8_t *host;
     ram_addr_t offset;
     ram_addr_t length;
+    uint32_t flags;
     char idstr[256];
     QLIST_ENTRY(RAMBlock) next;
 #if defined(__linux__) && !defined(TARGET_S390X)
@@ -876,7 +489,7 @@ typedef struct RAMBlock {
 
 typedef struct RAMList {
     uint8_t *phys_dirty;
-    QLIST_HEAD(ram, RAMBlock) blocks;
+    QLIST_HEAD(, RAMBlock) blocks;
 } RAMList;
 extern RAMList ram_list;
 
@@ -959,14 +572,16 @@ int cpu_physical_memory_get_dirty_tracking(void);
 int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
                                    target_phys_addr_t end_addr);
 
+int cpu_physical_log_start(target_phys_addr_t start_addr,
+                           ram_addr_t size);
+
+int cpu_physical_log_stop(target_phys_addr_t start_addr,
+                          ram_addr_t size);
+
 void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 #endif /* !CONFIG_USER_ONLY */
 
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
-void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int broadcast);
-
 #endif /* CPU_ALL_H */
index 6d4a898ad14881336148c69836574bb24f9945a9..3f454286991d4f6ccdcaa059606284a4522b1b0a 100644 (file)
@@ -3,10 +3,6 @@
 
 /* CPU interfaces that are target indpendent.  */
 
-#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__)
-#define WORDS_ALIGNED
-#endif
-
 #ifdef TARGET_PHYS_ADDR_BITS
 #include "targphys.h"
 #endif
@@ -27,17 +23,36 @@ enum device_endian {
 };
 
 /* address in the RAM (different from a physical address) */
+#if defined(CONFIG_XEN_BACKEND) && TARGET_PHYS_ADDR_BITS == 64
+typedef uint64_t ram_addr_t;
+#  define RAM_ADDR_MAX UINT64_MAX
+#  define RAM_ADDR_FMT "%" PRIx64
+#else
 typedef unsigned long ram_addr_t;
+#  define RAM_ADDR_MAX ULONG_MAX
+#  define RAM_ADDR_FMT "%lx"
+#endif
 
 /* memory API */
 
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
 
-void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
-                                         ram_addr_t size,
-                                         ram_addr_t phys_offset,
-                                         ram_addr_t region_offset);
+void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
+                                      ram_addr_t size,
+                                      ram_addr_t phys_offset,
+                                      ram_addr_t region_offset,
+                                      bool log_dirty);
+
+static inline void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                                       ram_addr_t size,
+                                                       ram_addr_t phys_offset,
+                                                       ram_addr_t region_offset)
+{
+    cpu_register_physical_memory_log(start_addr, size, phys_offset,
+                                     region_offset, false);
+}
+
 static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
                                                 ram_addr_t size,
                                                 ram_addr_t phys_offset)
@@ -50,11 +65,15 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
                         ram_addr_t size, void *host);
 ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
 void qemu_ram_free(ram_addr_t addr);
+void qemu_ram_free_from_ptr(ram_addr_t addr);
+void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
+void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size);
 /* Same but slower, to use for migration, where the order of
  * RAMBlocks must not change. */
 void *qemu_safe_ram_ptr(ram_addr_t addr);
+void qemu_put_ram_ptr(void *addr);
 /* This should not be used by devices.  */
 int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
 ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
@@ -67,14 +86,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,
@@ -90,12 +109,17 @@ struct CPUPhysMemoryClient {
     void (*set_memory)(struct CPUPhysMemoryClient *client,
                        target_phys_addr_t start_addr,
                        ram_addr_t size,
-                       ram_addr_t phys_offset);
+                       ram_addr_t phys_offset,
+                       bool log_dirty);
     int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
                              target_phys_addr_t start_addr,
                              target_phys_addr_t end_addr);
     int (*migration_log)(struct CPUPhysMemoryClient *client,
                          int enable);
+    int (*log_start)(struct CPUPhysMemoryClient *client,
+                     target_phys_addr_t phys_addr, ram_addr_t size);
+    int (*log_stop)(struct CPUPhysMemoryClient *client,
+                    target_phys_addr_t phys_addr, ram_addr_t size);
     QLIST_ENTRY(CPUPhysMemoryClient) list;
 };
 
@@ -114,15 +138,30 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
 void qemu_flush_coalesced_mmio_buffer(void);
 
 uint32_t ldub_phys(target_phys_addr_t addr);
+uint32_t lduw_le_phys(target_phys_addr_t addr);
+uint32_t lduw_be_phys(target_phys_addr_t addr);
+uint32_t ldl_le_phys(target_phys_addr_t addr);
+uint32_t ldl_be_phys(target_phys_addr_t addr);
+uint64_t ldq_le_phys(target_phys_addr_t addr);
+uint64_t ldq_be_phys(target_phys_addr_t addr);
+void stb_phys(target_phys_addr_t addr, uint32_t val);
+void stw_le_phys(target_phys_addr_t addr, uint32_t val);
+void stw_be_phys(target_phys_addr_t addr, uint32_t val);
+void stl_le_phys(target_phys_addr_t addr, uint32_t val);
+void stl_be_phys(target_phys_addr_t addr, uint32_t val);
+void stq_le_phys(target_phys_addr_t addr, uint64_t val);
+void stq_be_phys(target_phys_addr_t addr, uint64_t val);
+
+#ifdef NEED_CPU_H
 uint32_t lduw_phys(target_phys_addr_t addr);
 uint32_t ldl_phys(target_phys_addr_t addr);
 uint64_t ldq_phys(target_phys_addr_t addr);
 void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
 void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
-void stb_phys(target_phys_addr_t addr, uint32_t val);
 void stw_phys(target_phys_addr_t addr, uint32_t val);
 void stl_phys(target_phys_addr_t addr, uint32_t val);
 void stq_phys(target_phys_addr_t addr, uint64_t val);
+#endif
 
 void cpu_physical_memory_write_rom(target_phys_addr_t addr,
                                    const uint8_t *buf, int len);
@@ -133,6 +172,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
 #define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
 #define IO_MEM_UNASSIGNED  (2 << IO_MEM_SHIFT)
 #define IO_MEM_NOTDIRTY    (3 << IO_MEM_SHIFT)
+#define IO_MEM_SUBPAGE_RAM (4 << IO_MEM_SHIFT)
 
 /* Acts like a ROM when read and like a device when written.  */
 #define IO_MEM_ROMD        (1)
index 8d4bf86c531f9ef7bd5f2a11950a1a7ea1c305f3..5e22d836e4173f8ef8cb2795d762071114fe9bc1 100644 (file)
 
 #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
 
+typedef int16_t target_short __attribute__ ((aligned(TARGET_SHORT_ALIGNMENT)));
+typedef uint16_t target_ushort __attribute__((aligned(TARGET_SHORT_ALIGNMENT)));
+typedef int32_t target_int __attribute__((aligned(TARGET_INT_ALIGNMENT)));
+typedef uint32_t target_uint __attribute__((aligned(TARGET_INT_ALIGNMENT)));
+typedef int64_t target_llong __attribute__((aligned(TARGET_LLONG_ALIGNMENT)));
+typedef uint64_t target_ullong __attribute__((aligned(TARGET_LLONG_ALIGNMENT)));
 /* target_ulong is the type of a virtual address */
 #if TARGET_LONG_SIZE == 4
-typedef int32_t target_long;
-typedef uint32_t target_ulong;
+typedef int32_t target_long __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+typedef uint32_t target_ulong __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
 #define TARGET_FMT_lx "%08x"
 #define TARGET_FMT_ld "%d"
 #define TARGET_FMT_lu "%u"
 #elif TARGET_LONG_SIZE == 8
-typedef int64_t target_long;
-typedef uint64_t target_ulong;
+typedef int64_t target_long __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+typedef uint64_t target_ulong __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
 #define TARGET_FMT_lx "%016" PRIx64
 #define TARGET_FMT_ld "%" PRId64
 #define TARGET_FMT_lu "%" PRIu64
@@ -197,6 +203,7 @@ typedef struct CPUWatchpoint {
     int nr_cores;  /* number of cores within this CPU package */        \
     int nr_threads;/* number of threads within this CPU */              \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
+    int thread_id;                                                      \
     /* user data */                                                     \
     void *opaque;                                                       \
                                                                         \
@@ -205,11 +212,14 @@ typedef struct CPUWatchpoint {
     uint32_t stopped; /* Artificially stopped */                        \
     struct QemuThread *thread;                                          \
     struct QemuCond *halt_cond;                                         \
+    int thread_kicked;                                                  \
     struct qemu_work_item *queued_work_first, *queued_work_last;        \
     const char *cpu_model_str;                                          \
     struct KVMState *kvm_state;                                         \
     struct kvm_run *kvm_run;                                            \
     int kvm_fd;                                                         \
-    int kvm_vcpu_dirty;
+    int kvm_vcpu_dirty;                                                        \
+    int hax_vcpu_dirty;                                                        \
+    struct hax_vcpu_state *hax_vcpu;
 
 #endif
index 8c9fb8b1a2176eb6b8b458d235e248a97b8eb855..989f28e9b4de075e299f3c95c696b5777ad2b911 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "config.h"
-#include "exec.h"
+#include "cpu.h"
 #include "disas.h"
 #include "tcg.h"
-#include "kvm.h"
+#include "hax.h"
 #include "qemu-barrier.h"
 
-#if !defined(CONFIG_SOFTMMU)
-#undef EAX
-#undef ECX
-#undef EDX
-#undef EBX
-#undef ESP
-#undef EBP
-#undef ESI
-#undef EDI
-#undef EIP
-#include <signal.h>
-#ifdef __linux__
-#include <sys/ucontext.h>
-#endif
-#endif
-
-#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
-// Work around ugly bugs in glibc that mangle global register contents
-#undef env
-#define env cpu_single_env
-#endif
-
 int tb_invalidated_flag;
 
 //#define CONFIG_DEBUG_EXEC
-//#define DEBUG_SIGNAL
 
-int qemu_cpu_has_work(CPUState *env)
+bool qemu_cpu_has_work(CPUState *env)
 {
     return cpu_has_work(env);
 }
 
-void cpu_loop_exit(void)
+void cpu_loop_exit(CPUState *env)
 {
     env->current_tb = NULL;
     longjmp(env->jmp_env, 1);
@@ -64,41 +41,20 @@ void cpu_loop_exit(void)
 /* exit the current TB from a signal handler. The host registers are
    restored in a state compatible with the CPU emulator
  */
-void cpu_resume_from_signal(CPUState *env1, void *puc)
+#if defined(CONFIG_SOFTMMU)
+void cpu_resume_from_signal(CPUState *env, void *puc)
 {
-#if !defined(CONFIG_SOFTMMU)
-#ifdef __linux__
-    struct ucontext *uc = puc;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-#endif
-#endif
-
-    env = env1;
-
     /* XXX: restore cpu registers saved in host registers */
 
-#if !defined(CONFIG_SOFTMMU)
-    if (puc) {
-        /* XXX: use siglongjmp ? */
-#ifdef __linux__
-#ifdef __ia64
-        sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
-#else
-        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
-#endif
-#elif defined(__OpenBSD__)
-        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
-#endif
-    }
-#endif
     env->exception_index = -1;
     longjmp(env->jmp_env, 1);
 }
+#endif
 
 /* Execute the code without caching the generated code. An interpreter
    could be used if available. */
-static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
+static void cpu_exec_nocache(CPUState *env, int max_cycles,
+                             TranslationBlock *orig_tb)
 {
     unsigned long next_tb;
     TranslationBlock *tb;
@@ -112,7 +68,7 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
                      max_cycles);
     env->current_tb = tb;
     /* execute the generated code */
-    next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
+    next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
     env->current_tb = NULL;
 
     if ((next_tb & 3) == 2) {
@@ -124,13 +80,14 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
     tb_free(tb);
 }
 
-static TranslationBlock *tb_find_slow(target_ulong pc,
+static TranslationBlock *tb_find_slow(CPUState *env,
+                                      target_ulong pc,
                                       target_ulong cs_base,
                                       uint64_t flags)
 {
     TranslationBlock *tb, **ptb1;
     unsigned int h;
-    tb_page_addr_t phys_pc, phys_page1, phys_page2;
+    tb_page_addr_t phys_pc, phys_page1;
     target_ulong virt_page2;
 
     tb_invalidated_flag = 0;
@@ -138,7 +95,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
     /* find translated block using physical mappings */
     phys_pc = get_page_addr_code(env, pc);
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
-    phys_page2 = -1;
     h = tb_phys_hash_func(phys_pc);
     ptb1 = &tb_phys_hash[h];
     for(;;) {
@@ -151,6 +107,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
             tb->flags == flags) {
             /* check next page if needed */
             if (tb->page_addr[1] != -1) {
+                tb_page_addr_t phys_page2;
+
                 virt_page2 = (pc & TARGET_PAGE_MASK) +
                     TARGET_PAGE_SIZE;
                 phys_page2 = get_page_addr_code(env, virt_page2);
@@ -178,7 +136,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
     return tb;
 }
 
-static inline TranslationBlock *tb_find_fast(void)
+static inline TranslationBlock *tb_find_fast(CPUState *env)
 {
     TranslationBlock *tb;
     target_ulong cs_base, pc;
@@ -191,7 +149,7 @@ static inline TranslationBlock *tb_find_fast(void)
     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                  tb->flags != flags)) {
-        tb = tb_find_slow(pc, cs_base, flags);
+        tb = tb_find_slow(env, pc, cs_base, flags);
     }
     return tb;
 }
@@ -210,51 +168,65 @@ static void cpu_handle_debug_exception(CPUState *env)
 {
     CPUWatchpoint *wp;
 
-    if (!env->watchpoint_hit)
-        QTAILQ_FOREACH(wp, &env->watchpoints, entry)
+    if (!env->watchpoint_hit) {
+        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
             wp->flags &= ~BP_WATCHPOINT_HIT;
-
-    if (debug_excp_handler)
+        }
+    }
+    if (debug_excp_handler) {
         debug_excp_handler(env);
+    }
 }
 
 /* main execution loop */
 
 volatile sig_atomic_t exit_request;
 
-int cpu_exec(CPUState *env1)
+/*
+ * QEMU emulate can happens because of MMIO or emulation mode, i.e. non-PG mode,
+ * when it's because of MMIO, the MMIO, the interrupt should not be emulated,
+ * because MMIO is emulated for only one instruction now and then back to
+ * HAX kernel
+ */
+int need_handle_intr_request(CPUState *env)
+{
+#ifdef CONFIG_HAX
+    if (!hax_enabled() || hax_vcpu_emulation_mode(env))
+        return env->interrupt_request;
+    return 0;
+#else
+    return env->interrupt_request;
+#endif
+}
+
+
+int cpu_exec(CPUState *env)
 {
-    volatile host_reg_t saved_env_reg;
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
     unsigned long next_tb;
 
-    if (cpu_halted(env1) == EXCP_HALTED)
-        return EXCP_HALTED;
+    if (env->halted) {
+        if (!cpu_has_work(env)) {
+            return EXCP_HALTED;
+        }
 
-    cpu_single_env = env1;
+        env->halted = 0;
+    }
 
-    /* the access to env below is actually saving the global register's
-       value, so that files not including target-xyz/exec.h are free to
-       use it.  */
-    QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
-    saved_env_reg = (host_reg_t) env;
-    barrier();
-    env = env1;
+    cpu_single_env = env;
 
     if (unlikely(exit_request)) {
         env->exit_request = 1;
     }
 
 #if defined(TARGET_I386)
-    if (!kvm_enabled()) {
-        /* put eflags in CPU temporary format */
-        CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
-        DF = 1 - (2 * ((env->eflags >> 10) & 1));
-        CC_OP = CC_OP_EFLAGS;
-        env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
-    }
+    /* put eflags in CPU temporary format */
+    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+    DF = 1 - (2 * ((env->eflags >> 10) & 1));
+    CC_OP = CC_OP_EFLAGS;
+    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
 #elif defined(TARGET_SPARC)
 #elif defined(TARGET_M68K)
     env->cc_op = CC_OP_FLAGS;
@@ -262,12 +234,16 @@ 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)
+    env->reserve_addr = -1;
+#elif defined(TARGET_LM32)
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -277,18 +253,14 @@ int cpu_exec(CPUState *env1)
     /* prepare setjmp context for exception handling */
     for(;;) {
         if (setjmp(env->jmp_env) == 0) {
-#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
-#undef env
-                    env = cpu_single_env;
-#define env cpu_single_env
-#endif
             /* if an exception is pending, we execute it here */
             if (env->exception_index >= 0) {
                 if (env->exception_index >= EXCP_INTERRUPT) {
                     /* exit request from the cpu execution loop */
                     ret = env->exception_index;
-                    if (ret == EXCP_DEBUG)
+                    if (ret == EXCP_DEBUG) {
                         cpu_handle_debug_exception(env);
+                    }
                     break;
                 } else {
 #if defined(CONFIG_USER_ONLY)
@@ -296,105 +268,69 @@ int cpu_exec(CPUState *env1)
                        which will be handled outside the cpu execution
                        loop */
 #if defined(TARGET_I386)
-                    do_interrupt_user(env->exception_index,
-                                      env->exception_is_int,
-                                      env->error_code,
-                                      env->exception_next_eip);
-                    /* successfully delivered */
-                    env->old_exception = -1;
+                    do_interrupt(env);
 #endif
                     ret = env->exception_index;
                     break;
 #else
-#if defined(TARGET_I386)
-                    /* simulate a real cpu exception. On i386, it can
-                       trigger new exceptions, but we do not handle
-                       double or triple faults yet. */
-                    do_interrupt(env->exception_index,
-                                 env->exception_is_int,
-                                 env->error_code,
-                                 env->exception_next_eip, 0);
-                    /* successfully delivered */
-                    env->old_exception = -1;
-#elif defined(TARGET_PPC)
-                    do_interrupt(env);
-#elif defined(TARGET_MICROBLAZE)
-                    do_interrupt(env);
-#elif defined(TARGET_MIPS)
-                    do_interrupt(env);
-#elif defined(TARGET_SPARC)
-                    do_interrupt(env);
-#elif defined(TARGET_ARM)
                     do_interrupt(env);
-#elif defined(TARGET_SH4)
-                   do_interrupt(env);
-#elif defined(TARGET_ALPHA)
-                    do_interrupt(env);
-#elif defined(TARGET_CRIS)
-                    do_interrupt(env);
-#elif defined(TARGET_M68K)
-                    do_interrupt(0);
-#endif
                     env->exception_index = -1;
 #endif
                 }
             }
 
-            if (kvm_enabled()) {
-                kvm_cpu_exec(env);
+#ifdef CONFIG_HAX
+            if (hax_enabled() && !hax_vcpu_exec(env))
                 longjmp(env->jmp_env, 1);
-            }
+#endif
 
             next_tb = 0; /* force lookup of first TB */
             for(;;) {
                 interrupt_request = env->interrupt_request;
-                if (unlikely(interrupt_request)) {
+                if (unlikely(need_handle_intr_request(env))) {
                     if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
                         /* Mask out external interrupts for this step. */
-                        interrupt_request &= ~(CPU_INTERRUPT_HARD |
-                                               CPU_INTERRUPT_FIQ |
-                                               CPU_INTERRUPT_SMI |
-                                               CPU_INTERRUPT_NMI);
+                        interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
                     }
                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                         env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                         env->exception_index = EXCP_DEBUG;
-                        cpu_loop_exit();
+                        cpu_loop_exit(env);
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
-    defined(TARGET_MICROBLAZE)
+    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         env->halted = 1;
                         env->exception_index = EXCP_HLT;
-                        cpu_loop_exit();
+                        cpu_loop_exit(env);
                     }
 #endif
 #if defined(TARGET_I386)
                     if (interrupt_request & CPU_INTERRUPT_INIT) {
-                            svm_check_intercept(SVM_EXIT_INIT);
+                            svm_check_intercept(env, SVM_EXIT_INIT);
                             do_cpu_init(env);
                             env->exception_index = EXCP_HALTED;
-                            cpu_loop_exit();
+                            cpu_loop_exit(env);
                     } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
                             do_cpu_sipi(env);
                     } else if (env->hflags2 & HF2_GIF_MASK) {
                         if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                             !(env->hflags & HF_SMM_MASK)) {
-                            svm_check_intercept(SVM_EXIT_SMI);
+                            svm_check_intercept(env, SVM_EXIT_SMI);
                             env->interrupt_request &= ~CPU_INTERRUPT_SMI;
-                            do_smm_enter();
+                            do_smm_enter(env);
                             next_tb = 0;
                         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
                                    !(env->hflags2 & HF2_NMI_MASK)) {
                             env->interrupt_request &= ~CPU_INTERRUPT_NMI;
                             env->hflags2 |= HF2_NMI_MASK;
-                            do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
+                            do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
                             next_tb = 0;
                        } else if (interrupt_request & CPU_INTERRUPT_MCE) {
                             env->interrupt_request &= ~CPU_INTERRUPT_MCE;
-                            do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
+                            do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
                             next_tb = 0;
                         } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                                    (((env->hflags2 & HF2_VINTR_MASK) && 
@@ -403,16 +339,11 @@ int cpu_exec(CPUState *env1)
                                      (env->eflags & IF_MASK && 
                                       !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
                             int intno;
-                            svm_check_intercept(SVM_EXIT_INTR);
+                            svm_check_intercept(env, SVM_EXIT_INTR);
                             env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                             intno = cpu_get_pic_interrupt(env);
                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
-#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
-#undef env
-                    env = cpu_single_env;
-#define env cpu_single_env
-#endif
-                            do_interrupt(intno, 0, 0, 0, 1);
+                            do_interrupt_x86_hardirq(env, intno, 1);
                             /* ensure that no TB jump will be modified as
                                the program flow was changed */
                             next_tb = 0;
@@ -422,10 +353,10 @@ int cpu_exec(CPUState *env1)
                                    !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                             int intno;
                             /* FIXME: this should respect TPR */
-                            svm_check_intercept(SVM_EXIT_VINTR);
+                            svm_check_intercept(env, SVM_EXIT_VINTR);
                             intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
-                            do_interrupt(intno, 0, 0, 0, 1);
+                            do_interrupt_x86_hardirq(env, intno, 1);
                             env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
                             next_tb = 0;
 #endif
@@ -443,6 +374,13 @@ int cpu_exec(CPUState *env1)
                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                         next_tb = 0;
                     }
+#elif defined(TARGET_LM32)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->ie & IE_IE)) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #elif defined(TARGET_MICROBLAZE)
                     if ((interrupt_request & CPU_INTERRUPT_HARD)
                         && (env->sregs[SR_MSR] & MSR_IE)
@@ -476,9 +414,6 @@ int cpu_exec(CPUState *env1)
                                 next_tb = 0;
                             }
                         }
-                   } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
-                       //do_interrupt(0, 0, 0, 0, 0);
-                       env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
                    }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
@@ -493,7 +428,7 @@ int cpu_exec(CPUState *env1)
                        jump normally, then does the exception return when the
                        CPU tries to execute code at the magic address.
                        This will cause the magic PC value to be pushed to
-                       the stack if an interrupt occured at the wrong time.
+                       the stack if an interrupt occurred at the wrong time.
                        We avoid this by disabling interrupts when
                        pc contains a magic address.  */
                     if (interrupt_request & CPU_INTERRUPT_HARD
@@ -503,16 +438,49 @@ int cpu_exec(CPUState *env1)
                         do_interrupt(env);
                         next_tb = 0;
                     }
-#elif defined(TARGET_SH4)
-                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+#elif defined(TARGET_UNICORE32)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && !(env->uncached_asr & ASR_I)) {
                         do_interrupt(env);
                         next_tb = 0;
                     }
-#elif defined(TARGET_ALPHA)
+#elif defined(TARGET_SH4)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_ALPHA)
+                    {
+                        int idx = -1;
+                        /* ??? This hard-codes the OSF/1 interrupt levels.  */
+                       switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
+                        case 0 ... 3:
+                            if (interrupt_request & CPU_INTERRUPT_HARD) {
+                                idx = EXCP_DEV_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 4:
+                            if (interrupt_request & CPU_INTERRUPT_TIMER) {
+                                idx = EXCP_CLK_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 5:
+                            if (interrupt_request & CPU_INTERRUPT_SMP) {
+                                idx = EXCP_SMP_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 6:
+                            if (interrupt_request & CPU_INTERRUPT_MCHK) {
+                                idx = EXCP_MCHK;
+                            }
+                        }
+                        if (idx >= 0) {
+                            env->exception_index = idx;
+                            env->error_code = 0;
+                            do_interrupt(env);
+                            next_tb = 0;
+                        }
+                    }
 #elif defined(TARGET_CRIS)
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && (env->pregs[PR_CCS] & I_FLAG)
@@ -537,11 +505,23 @@ int cpu_exec(CPUState *env1)
                            provide/save the vector when the interrupt is
                            first signalled.  */
                         env->exception_index = env->pending_vector;
-                        do_interrupt(1);
+                        do_interrupt_m68k_hardirq(env);
+                        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;
+                    }
+#elif defined(TARGET_XTENSA)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        env->exception_index = EXC_IRQ;
+                        do_interrupt(env);
                         next_tb = 0;
                     }
 #endif
-                   /* Don't use the cached interupt_request value,
+                   /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
@@ -553,13 +533,14 @@ int cpu_exec(CPUState *env1)
                 if (unlikely(env->exit_request)) {
                     env->exit_request = 0;
                     env->exception_index = EXCP_INTERRUPT;
-                    cpu_loop_exit();
+                    cpu_loop_exit(env);
                 }
 #if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
                 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
                     /* restore flags in standard format */
 #if defined(TARGET_I386)
-                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+                    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
+                        | (DF & DF_MASK);
                     log_cpu_state(env, X86_DUMP_CCOP);
                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
 #elif defined(TARGET_M68K)
@@ -574,7 +555,7 @@ int cpu_exec(CPUState *env1)
                 }
 #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
                 spin_lock(&tb_lock);
-                tb = tb_find_fast();
+                tb = tb_find_fast(env);
                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
                    doing it in tb_find_slow */
                 if (tb_invalidated_flag) {
@@ -606,12 +587,7 @@ int cpu_exec(CPUState *env1)
                 if (likely(!env->exit_request)) {
                     tc_ptr = tb->tc_ptr;
                 /* execute the generated code */
-#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
-#undef env
-                    env = cpu_single_env;
-#define env cpu_single_env
-#endif
-                    next_tb = tcg_qemu_tb_exec(tc_ptr);
+                    next_tb = tcg_qemu_tb_exec(env, tc_ptr);
                     if ((next_tb & 3) == 2) {
                         /* Instruction counter expired.  */
                         int insns_left;
@@ -632,29 +608,41 @@ int cpu_exec(CPUState *env1)
                         } else {
                             if (insns_left > 0) {
                                 /* Execute remaining instructions.  */
-                                cpu_exec_nocache(insns_left, tb);
+                                cpu_exec_nocache(env, insns_left, tb);
                             }
                             env->exception_index = EXCP_INTERRUPT;
                             next_tb = 0;
-                            cpu_loop_exit();
+                            cpu_loop_exit(env);
                         }
                     }
                 }
                 env->current_tb = NULL;
+#ifdef CONFIG_HAX
+                if (hax_enabled() && hax_stop_emulation(env))
+                    cpu_loop_exit(env);
+#endif
+
                 /* reset soft MMU for next block (it can currently
                    only be set by a memory fault) */
             } /* for(;;) */
+        } else {
+            /* Reload env after longjmp - the compiler may have smashed all
+             * local variables as longjmp is marked 'noreturn'. */
+            env = cpu_single_env;
         }
     } /* for(;;) */
 
 
 #if defined(TARGET_I386)
     /* restore flags in standard format */
-    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+    env->eflags = env->eflags | cpu_cc_compute_all(env, 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)
 #elif defined(TARGET_M68K)
     cpu_m68k_flush_flags(env, env->cc_op);
     env->cc_op = CC_OP_FLAGS;
@@ -666,606 +654,13 @@ int cpu_exec(CPUState *env1)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
 #endif
 
-    /* restore global registers */
-    barrier();
-    env = (void *) saved_env_reg;
-
     /* fail safe : never use cpu_single_env outside cpu_exec() */
     cpu_single_env = NULL;
     return ret;
 }
-
-/* must only be called from the generated code as an exception can be
-   generated */
-void tb_invalidate_page_range(target_ulong start, target_ulong end)
-{
-    /* XXX: cannot enable it yet because it yields to MMU exception
-       where NIP != read address on PowerPC */
-#if 0
-    target_ulong phys_addr;
-    phys_addr = get_phys_addr_code(env, start);
-    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
-#endif
-}
-
-#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
-
-void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
-{
-    CPUX86State *saved_env;
-
-    saved_env = env;
-    env = s;
-    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
-        selector &= 0xffff;
-        cpu_x86_load_seg_cache(env, seg_reg, selector,
-                               (selector << 4), 0xffff, 0);
-    } else {
-        helper_load_seg(seg_reg, selector);
-    }
-    env = saved_env;
-}
-
-void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
-{
-    CPUX86State *saved_env;
-
-    saved_env = env;
-    env = s;
-
-    helper_fsave(ptr, data32);
-
-    env = saved_env;
-}
-
-void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
-{
-    CPUX86State *saved_env;
-
-    saved_env = env;
-    env = s;
-
-    helper_frstor(ptr, data32);
-
-    env = saved_env;
-}
-
-#endif /* TARGET_I386 */
-
-#if !defined(CONFIG_SOFTMMU)
-
-#if defined(TARGET_I386)
-#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
-#else
-#define EXCEPTION_ACTION cpu_loop_exit()
-#endif
-
-/* 'pc' is the host PC at which the exception was raised. 'address' is
-   the effective address of the memory exception. 'is_write' is 1 if a
-   write caused the exception and otherwise 0'. 'old_set' is the
-   signal set which should be restored */
-static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
-                                    int is_write, sigset_t *old_set,
-                                    void *puc)
-{
-    TranslationBlock *tb;
-    int ret;
-
-    if (cpu_single_env)
-        env = cpu_single_env; /* XXX: find a correct solution for multithread */
-#if defined(DEBUG_SIGNAL)
-    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
-                pc, address, is_write, *(unsigned long *)old_set);
-#endif
-    /* XXX: locking issue */
-    if (is_write && page_unprotect(h2g(address), pc, puc)) {
-        return 1;
-    }
-
-    /* see if it is an MMU fault */
-    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
-    if (ret < 0)
-        return 0; /* not an MMU fault */
-    if (ret == 0)
-        return 1; /* the MMU fault was handled without causing real CPU fault */
-    /* now we have a real cpu fault */
-    tb = tb_find_pc(pc);
-    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);
-    }
-
-    /* we restore the process signal mask as the sigreturn should
-       do it (XXX: use sigsetjmp) */
-    sigprocmask(SIG_SETMASK, old_set, NULL);
-    EXCEPTION_ACTION;
-
-    /* never comes here */
-    return 1;
-}
-
-#if defined(__i386__)
-
-#if defined(__APPLE__)
-# include <sys/ucontext.h>
-
-# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
-# define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
-# define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
-# define MASK_sig(context)    ((context)->uc_sigmask)
-#elif defined (__NetBSD__)
-# include <ucontext.h>
-
-# define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
-# define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
-# define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
-# define MASK_sig(context)    ((context)->uc_sigmask)
-#elif defined (__FreeBSD__) || defined(__DragonFly__)
-# include <ucontext.h>
-
-# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
-# define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
-# define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
-# define MASK_sig(context)    ((context)->uc_sigmask)
-#elif defined(__OpenBSD__)
-# define EIP_sig(context)     ((context)->sc_eip)
-# define TRAP_sig(context)    ((context)->sc_trapno)
-# define ERROR_sig(context)   ((context)->sc_err)
-# define MASK_sig(context)    ((context)->sc_mask)
-#else
-# define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
-# define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
-# define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
-# define MASK_sig(context)    ((context)->uc_sigmask)
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
-    ucontext_t *uc = puc;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-#else
-    struct ucontext *uc = puc;
-#endif
-    unsigned long pc;
-    int trapno;
-
-#ifndef REG_EIP
-/* for glibc 2.1 */
-#define REG_EIP    EIP
-#define REG_ERR    ERR
-#define REG_TRAPNO TRAPNO
-#endif
-    pc = EIP_sig(uc);
-    trapno = TRAP_sig(uc);
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             trapno == 0xe ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
-                             &MASK_sig(uc), puc);
-}
-
-#elif defined(__x86_64__)
-
-#ifdef __NetBSD__
-#define PC_sig(context)       _UC_MACHINE_PC(context)
-#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
-#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#elif defined(__OpenBSD__)
-#define PC_sig(context)       ((context)->sc_rip)
-#define TRAP_sig(context)     ((context)->sc_trapno)
-#define ERROR_sig(context)    ((context)->sc_err)
-#define MASK_sig(context)     ((context)->sc_mask)
-#elif defined (__FreeBSD__) || defined(__DragonFly__)
-#include <ucontext.h>
-
-#define PC_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
-#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
-#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#else
-#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
-#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
-#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    unsigned long pc;
-#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
-    ucontext_t *uc = puc;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-#else
-    struct ucontext *uc = puc;
-#endif
-
-    pc = PC_sig(uc);
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             TRAP_sig(uc) == 0xe ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
-                             &MASK_sig(uc), puc);
-}
-
-#elif defined(_ARCH_PPC)
-
-/***********************************************************************
- * signal context platform-specific definitions
- * From Wine
- */
-#ifdef linux
-/* All Registers access - only for local access */
-# define REG_sig(reg_name, context)            ((context)->uc_mcontext.regs->reg_name)
-/* Gpr Registers access  */
-# define GPR_sig(reg_num, context)             REG_sig(gpr[reg_num], context)
-# define IAR_sig(context)                      REG_sig(nip, context)   /* Program counter */
-# define MSR_sig(context)                      REG_sig(msr, context)   /* Machine State Register (Supervisor) */
-# define CTR_sig(context)                      REG_sig(ctr, context)   /* Count register */
-# define XER_sig(context)                      REG_sig(xer, context) /* User's integer exception register */
-# define LR_sig(context)                       REG_sig(link, context) /* Link register */
-# define CR_sig(context)                       REG_sig(ccr, context) /* Condition register */
-/* Float Registers access  */
-# define FLOAT_sig(reg_num, context)           (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
-# define FPSCR_sig(context)                    (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
-/* Exception Registers access */
-# define DAR_sig(context)                      REG_sig(dar, context)
-# define DSISR_sig(context)                    REG_sig(dsisr, context)
-# define TRAP_sig(context)                     REG_sig(trap, context)
-#endif /* linux */
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <ucontext.h>
-# define IAR_sig(context)              ((context)->uc_mcontext.mc_srr0)
-# define MSR_sig(context)              ((context)->uc_mcontext.mc_srr1)
-# define CTR_sig(context)              ((context)->uc_mcontext.mc_ctr)
-# define XER_sig(context)              ((context)->uc_mcontext.mc_xer)
-# define LR_sig(context)               ((context)->uc_mcontext.mc_lr)
-# define CR_sig(context)               ((context)->uc_mcontext.mc_cr)
-/* Exception Registers access */
-# define DAR_sig(context)              ((context)->uc_mcontext.mc_dar)
-# define DSISR_sig(context)            ((context)->uc_mcontext.mc_dsisr)
-# define TRAP_sig(context)             ((context)->uc_mcontext.mc_exc)
-#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
-
-#ifdef __APPLE__
-# include <sys/ucontext.h>
-typedef struct ucontext SIGCONTEXT;
-/* All Registers access - only for local access */
-# define REG_sig(reg_name, context)            ((context)->uc_mcontext->ss.reg_name)
-# define FLOATREG_sig(reg_name, context)       ((context)->uc_mcontext->fs.reg_name)
-# define EXCEPREG_sig(reg_name, context)       ((context)->uc_mcontext->es.reg_name)
-# define VECREG_sig(reg_name, context)         ((context)->uc_mcontext->vs.reg_name)
-/* Gpr Registers access */
-# define GPR_sig(reg_num, context)             REG_sig(r##reg_num, context)
-# define IAR_sig(context)                      REG_sig(srr0, context)  /* Program counter */
-# define MSR_sig(context)                      REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
-# define CTR_sig(context)                      REG_sig(ctr, context)
-# define XER_sig(context)                      REG_sig(xer, context) /* Link register */
-# define LR_sig(context)                       REG_sig(lr, context)  /* User's integer exception register */
-# define CR_sig(context)                       REG_sig(cr, context)  /* Condition register */
-/* Float Registers access */
-# define FLOAT_sig(reg_num, context)           FLOATREG_sig(fpregs[reg_num], context)
-# define FPSCR_sig(context)                    ((double)FLOATREG_sig(fpscr, context))
-/* Exception Registers access */
-# define DAR_sig(context)                      EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
-# define DSISR_sig(context)                    EXCEPREG_sig(dsisr, context)
-# define TRAP_sig(context)                     EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
-#endif /* __APPLE__ */
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-    ucontext_t *uc = puc;
-#else
-    struct ucontext *uc = puc;
-#endif
-    unsigned long pc;
-    int is_write;
-
-    pc = IAR_sig(uc);
-    is_write = 0;
-#if 0
-    /* ppc 4xx case */
-    if (DSISR_sig(uc) & 0x00800000)
-        is_write = 1;
-#else
-    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
-        is_write = 1;
-#endif
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask, puc);
-}
-
-#elif defined(__alpha__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                           void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    uint32_t *pc = uc->uc_mcontext.sc_pc;
-    uint32_t insn = *pc;
-    int is_write = 0;
-
-    /* XXX: need kernel patch to get write flag faster */
-    switch (insn >> 26) {
-    case 0x0d: // stw
-    case 0x0e: // stb
-    case 0x0f: // stq_u
-    case 0x24: // stf
-    case 0x25: // stg
-    case 0x26: // sts
-    case 0x27: // stt
-    case 0x2c: // stl
-    case 0x2d: // stq
-    case 0x2e: // stl_c
-    case 0x2f: // stq_c
-       is_write = 1;
-    }
-
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask, puc);
-}
-#elif defined(__sparc__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    int is_write;
-    uint32_t insn;
-#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
-    uint32_t *regs = (uint32_t *)(info + 1);
-    void *sigmask = (regs + 20);
-    /* XXX: is there a standard glibc define ? */
-    unsigned long pc = regs[1];
-#else
-#ifdef __linux__
-    struct sigcontext *sc = puc;
-    unsigned long pc = sc->sigc_regs.tpc;
-    void *sigmask = (void *)sc->sigc_mask;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-    unsigned long pc = uc->sc_pc;
-    void *sigmask = (void *)(long)uc->sc_mask;
-#endif
-#endif
-
-    /* XXX: need kernel patch to get write flag faster */
-    is_write = 0;
-    insn = *(uint32_t *)pc;
-    if ((insn >> 30) == 3) {
-      switch((insn >> 19) & 0x3f) {
-      case 0x05: // stb
-      case 0x15: // stba
-      case 0x06: // sth
-      case 0x16: // stha
-      case 0x04: // st
-      case 0x14: // sta
-      case 0x07: // std
-      case 0x17: // stda
-      case 0x0e: // stx
-      case 0x1e: // stxa
-      case 0x24: // stf
-      case 0x34: // stfa
-      case 0x27: // stdf
-      case 0x37: // stdfa
-      case 0x26: // stqf
-      case 0x36: // stqfa
-      case 0x25: // stfsr
-      case 0x3c: // casa
-      case 0x3e: // casxa
-       is_write = 1;
-       break;
-      }
-    }
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, sigmask, NULL);
-}
-
-#elif defined(__arm__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    unsigned long pc;
-    int is_write;
-
-#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-    pc = uc->uc_mcontext.gregs[R15];
-#else
-    pc = uc->uc_mcontext.arm_pc;
-#endif
-    /* XXX: compute is_write */
-    is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write,
-                             &uc->uc_sigmask, puc);
-}
-
-#elif defined(__mc68000)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    unsigned long pc;
-    int is_write;
-
-    pc = uc->uc_mcontext.gregs[16];
-    /* XXX: compute is_write */
-    is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write,
-                             &uc->uc_sigmask, puc);
-}
-
-#elif defined(__ia64)
-
-#ifndef __ISR_VALID
-  /* This ought to be in <bits/siginfo.h>... */
-# define __ISR_VALID   1
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    unsigned long ip;
-    int is_write = 0;
-
-    ip = uc->uc_mcontext.sc_ip;
-    switch (host_signum) {
-      case SIGILL:
-      case SIGFPE:
-      case SIGSEGV:
-      case SIGBUS:
-      case SIGTRAP:
-         if (info->si_code && (info->si_segvflags & __ISR_VALID))
-             /* ISR.W (write-access) is bit 33:  */
-             is_write = (info->si_isr >> 33) & 1;
-         break;
-
-      default:
-         break;
-    }
-    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
-                             is_write,
-                             (sigset_t *)&uc->uc_sigmask, puc);
-}
-
-#elif defined(__s390__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    unsigned long pc;
-    uint16_t *pinsn;
-    int is_write = 0;
-
-    pc = uc->uc_mcontext.psw.addr;
-
-    /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
-       of the normal 2 arguments.  The 3rd argument contains the "int_code"
-       from the hardware which does in fact contain the is_write value.
-       The rt signal handler, as far as I can tell, does not give this value
-       at all.  Not that we could get to it from here even if it were.  */
-    /* ??? This is not even close to complete, since it ignores all
-       of the read-modify-write instructions.  */
-    pinsn = (uint16_t *)pc;
-    switch (pinsn[0] >> 8) {
-    case 0x50: /* ST */
-    case 0x42: /* STC */
-    case 0x40: /* STH */
-        is_write = 1;
-        break;
-    case 0xc4: /* RIL format insns */
-        switch (pinsn[0] & 0xf) {
-        case 0xf: /* STRL */
-        case 0xb: /* STGRL */
-        case 0x7: /* STHRL */
-            is_write = 1;
-        }
-        break;
-    case 0xe3: /* RXY format insns */
-        switch (pinsn[2] & 0xff) {
-        case 0x50: /* STY */
-        case 0x24: /* STG */
-        case 0x72: /* STCY */
-        case 0x70: /* STHY */
-        case 0x8e: /* STPQ */
-        case 0x3f: /* STRVH */
-        case 0x3e: /* STRV */
-        case 0x2f: /* STRVG */
-            is_write = 1;
-        }
-        break;
-    }
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask, puc);
-}
-
-#elif defined(__mips__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
-    greg_t pc = uc->uc_mcontext.pc;
-    int is_write;
-
-    /* XXX: compute is_write */
-    is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask, puc);
-}
-
-#elif defined(__hppa__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    struct siginfo *info = pinfo;
-    struct ucontext *uc = puc;
-    unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
-    uint32_t insn = *(uint32_t *)pc;
-    int is_write = 0;
-
-    /* XXX: need kernel patch to get write flag faster.  */
-    switch (insn >> 26) {
-    case 0x1a: /* STW */
-    case 0x19: /* STH */
-    case 0x18: /* STB */
-    case 0x1b: /* STWM */
-        is_write = 1;
-        break;
-
-    case 0x09: /* CSTWX, FSTWX, FSTWS */
-    case 0x0b: /* CSTDX, FSTDX, FSTDS */
-        /* Distinguish from coprocessor load ... */
-        is_write = (insn >> 9) & 1;
-        break;
-
-    case 0x03:
-        switch ((insn >> 6) & 15) {
-        case 0xa: /* STWS */
-        case 0x9: /* STHS */
-        case 0x8: /* STBS */
-        case 0xe: /* STWAS */
-        case 0xc: /* STBYS */
-            is_write = 1;
-        }
-        break;
-    }
-
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
-                             is_write, &uc->uc_sigmask, puc);
-}
-
-#else
-
-#error host CPU specific signal handler needed
-
-#endif
-
-#endif /* !defined(CONFIG_SOFTMMU) */
diff --git a/cpus.c b/cpus.c
index 4c9928e2ce633d2f09750266771c719962a4b15c..6d0ad8275a744ac82efeb88a26d4e2b2804ab806 100644 (file)
--- a/cpus.c
+++ b/cpus.c
 #include "gdbstub.h"
 #include "dma.h"
 #include "kvm.h"
-#include "exec-all.h"
+#include "hax.h"
+#include "qmp-commands.h"
 
+#include "qemu-thread.h"
 #include "cpus.h"
+#include "main-loop.h"
+
+#ifndef _WIN32
 #include "compatfd.h"
+#endif
+
 #ifdef CONFIG_LINUX
+
 #include <sys/prctl.h>
+
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
 #endif
 
-#ifdef SIGRTMIN
-#define SIG_IPI (SIGRTMIN+4)
-#else
-#define SIG_IPI SIGUSR1
+#ifndef PR_MCE_KILL_SET
+#define PR_MCE_KILL_SET 1
 #endif
 
-#ifndef PR_MCE_KILL
-#define PR_MCE_KILL 33
+#ifndef PR_MCE_KILL_EARLY
+#define PR_MCE_KILL_EARLY 1
 #endif
 
+#endif /* CONFIG_LINUX */
+
 static CPUState *next_cpu;
 
+/***********************************************************/
+/* guest cycle counter */
+
+/* Conversion factor from emulated instructions to virtual clock ticks.  */
+static int icount_time_shift;
+/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
+#define MAX_ICOUNT_SHIFT 10
+/* Compensate for varying guest execution speed.  */
+static int64_t qemu_icount_bias;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+static QEMUTimer *icount_warp_timer;
+static int64_t vm_clock_warp_start;
+static int64_t qemu_icount;
+
+typedef struct TimersState {
+    int64_t cpu_ticks_prev;
+    int64_t cpu_ticks_offset;
+    int64_t cpu_clock_offset;
+    int32_t cpu_ticks_enabled;
+    int64_t dummy;
+} TimersState;
+
+TimersState timers_state;
+
+/* Return the virtual CPU time, based on the instruction counter.  */
+int64_t cpu_get_icount(void)
+{
+    int64_t icount;
+    CPUState *env = cpu_single_env;;
+
+    icount = qemu_icount;
+    if (env) {
+        if (!can_do_io(env)) {
+            fprintf(stderr, "Bad clock read\n");
+        }
+        icount -= (env->icount_decr.u16.low + env->icount_extra);
+    }
+    return qemu_icount_bias + (icount << icount_time_shift);
+}
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+    if (use_icount) {
+        return cpu_get_icount();
+    }
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_ticks_offset;
+    } else {
+        int64_t ticks;
+        ticks = cpu_get_real_ticks();
+        if (timers_state.cpu_ticks_prev > ticks) {
+            /* Note: non increasing ticks may happen if the host uses
+               software suspend */
+            timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+        }
+        timers_state.cpu_ticks_prev = ticks;
+        return ticks + timers_state.cpu_ticks_offset;
+    }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+int64_t cpu_get_clock(void)
+{
+    int64_t ti;
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_clock_offset;
+    } else {
+        ti = get_clock();
+        return ti + timers_state.cpu_clock_offset;
+    }
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+    if (!timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
+        timers_state.cpu_clock_offset -= get_clock();
+        timers_state.cpu_ticks_enabled = 1;
+    }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+   cpu_get_ticks() after that.  */
+void cpu_disable_ticks(void)
+{
+    if (timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset = cpu_get_ticks();
+        timers_state.cpu_clock_offset = cpu_get_clock();
+        timers_state.cpu_ticks_enabled = 0;
+    }
+}
+
+/* Correlation between real and virtual time is always going to be
+   fairly approximate, so ignore small variation.
+   When the guest is idle real and virtual time will be aligned in
+   the IO wait loop.  */
+#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
+
+static void icount_adjust(void)
+{
+    int64_t cur_time;
+    int64_t cur_icount;
+    int64_t delta;
+    static int64_t last_delta;
+    /* If the VM is not running, then do nothing.  */
+    if (!runstate_is_running()) {
+        return;
+    }
+    cur_time = cpu_get_clock();
+    cur_icount = qemu_get_clock_ns(vm_clock);
+    delta = cur_icount - cur_time;
+    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
+    if (delta > 0
+        && last_delta + ICOUNT_WOBBLE < delta * 2
+        && icount_time_shift > 0) {
+        /* The guest is getting too far ahead.  Slow time down.  */
+        icount_time_shift--;
+    }
+    if (delta < 0
+        && last_delta - ICOUNT_WOBBLE > delta * 2
+        && icount_time_shift < MAX_ICOUNT_SHIFT) {
+        /* The guest is getting too far behind.  Speed time up.  */
+        icount_time_shift++;
+    }
+    last_delta = delta;
+    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+}
+
+static void icount_adjust_rt(void *opaque)
+{
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_adjust();
+}
+
+static void icount_adjust_vm(void *opaque)
+{
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+    icount_adjust();
+}
+
+static int64_t qemu_icount_round(int64_t count)
+{
+    return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
+}
+
+static void icount_warp_rt(void *opaque)
+{
+    if (vm_clock_warp_start == -1) {
+        return;
+    }
+
+    if (runstate_is_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_clock_expired(vm_clock)) {
+            qemu_notify_event();
+        }
+    }
+    vm_clock_warp_start = -1;
+}
+
+void qemu_clock_warp(QEMUClock *clock)
+{
+    int64_t deadline;
+
+    /*
+     * 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.
+     */
+    if (clock != vm_clock || !use_icount) {
+        return;
+    }
+
+    /*
+     * 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() || !qemu_clock_has_timers(vm_clock)) {
+        qemu_del_timer(icount_warp_timer);
+        return;
+    }
+
+    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
+    deadline = qemu_clock_deadline(vm_clock);
+    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(icount_warp_timer, vm_clock_warp_start + deadline);
+    } else {
+        qemu_notify_event();
+    }
+}
+
+static const VMStateDescription vmstate_timers = {
+    .name = "timer",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT64(cpu_ticks_offset, TimersState),
+        VMSTATE_INT64(dummy, TimersState),
+        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void configure_icount(const char *option)
+{
+    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+    if (!option) {
+        return;
+    }
+
+    icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+    if (strcmp(option, "auto") != 0) {
+        icount_time_shift = strtol(option, NULL, 0);
+        use_icount = 1;
+        return;
+    }
+
+    use_icount = 2;
+
+    /* 125MIPS seems a reasonable initial guess at the guest speed.
+       It will be corrected fairly quickly anyway.  */
+    icount_time_shift = 3;
+
+    /* Have both realtime and virtual time triggers for speed adjustment.
+       The realtime trigger catches emulated time passing too slowly,
+       the virtual time trigger catches emulated time passing too fast.
+       Realtime triggers occur even when idle, so use them less frequently
+       than VM triggers.  */
+    icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+}
+
 /***********************************************************/
 void hw_error(const char *fmt, ...)
 {
@@ -101,16 +387,16 @@ void cpu_synchronize_all_post_init(void)
 
 int cpu_is_stopped(CPUState *env)
 {
-    return !vm_running || env->stopped;
+    return !runstate_is_running() || env->stopped;
 }
 
-static void do_vm_stop(int reason)
+static void do_vm_stop(RunState state)
 {
-    if (vm_running) {
+    if (runstate_is_running()) {
         cpu_disable_ticks();
-        vm_running = 0;
         pause_all_vcpus();
-        vm_state_notify(0, reason);
+        runstate_set(state);
+        vm_state_notify(0, state);
         qemu_aio_flush();
         bdrv_flush_all();
         monitor_protocol_event(QEVENT_STOP, NULL);
@@ -119,331 +405,248 @@ static void do_vm_stop(int reason)
 
 static int cpu_can_run(CPUState *env)
 {
-    if (env->stop)
+    if (env->stop) {
         return 0;
-    if (env->stopped || !vm_running)
+    }
+    if (env->stopped || !runstate_is_running()) {
         return 0;
+    }
     return 1;
 }
 
-static int cpu_has_work(CPUState *env)
+static bool cpu_thread_is_idle(CPUState *env)
 {
-    if (env->stop)
-        return 1;
-    if (env->queued_work_first)
-        return 1;
-    if (env->stopped || !vm_running)
-        return 0;
-    if (!env->halted)
-        return 1;
-    if (qemu_cpu_has_work(env))
-        return 1;
-    return 0;
+    if (env->stop || env->queued_work_first) {
+        return false;
+    }
+    if (env->stopped || !runstate_is_running()) {
+        return true;
+    }
+    if (!env->halted || qemu_cpu_has_work(env) ||
+        (kvm_enabled() && kvm_irqchip_in_kernel()) ||
+        hax_enabled()) {
+        return false;
+    }
+    return true;
 }
 
-static int any_cpu_has_work(void)
+bool all_cpu_threads_idle(void)
 {
     CPUState *env;
 
-    for (env = first_cpu; env != NULL; env = env->next_cpu)
-        if (cpu_has_work(env))
-            return 1;
-    return 0;
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (!cpu_thread_is_idle(env)) {
+            return false;
+        }
+    }
+    return true;
 }
 
-static void cpu_debug_handler(CPUState *env)
+static void cpu_handle_guest_debug(CPUState *env)
 {
     gdb_set_stop_cpu(env);
-    debug_requested = EXCP_DEBUG;
-    vm_stop(EXCP_DEBUG);
+    qemu_system_debug_request();
+    env->stopped = 1;
 }
 
-#ifndef _WIN32
-static int io_thread_fd = -1;
-
-static void qemu_event_increment(void)
+static void cpu_signal(int sig)
 {
-    /* Write 8 bytes to be compatible with eventfd.  */
-    static const uint64_t val = 1;
-    ssize_t ret;
-
-    if (io_thread_fd == -1)
-        return;
+    if (cpu_single_env) {
+        cpu_exit(cpu_single_env);
+    }
+    exit_request = 1;
+}
 
-    do {
-        ret = write(io_thread_fd, &val, sizeof(val));
-    } while (ret < 0 && errno == EINTR);
+#ifdef CONFIG_LINUX
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
 
-    /* EAGAIN is fine, a read must be pending.  */
-    if (ret < 0 && errno != EAGAIN) {
-        fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
-                strerror(errno));
-        exit (1);
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS, &action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
     }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();
 }
 
-static void qemu_event_read(void *opaque)
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
 {
-    int fd = (unsigned long)opaque;
-    ssize_t len;
-    char buffer[512];
-
-    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
-    do {
-        len = read(fd, buffer, sizeof(buffer));
-    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+    if (kvm_on_sigbus(siginfo->ssi_code,
+                      (void *)(intptr_t)siginfo->ssi_addr)) {
+        sigbus_reraise();
+    }
 }
 
-static int qemu_event_init(void)
+static void qemu_init_sigbus(void)
 {
-    int err;
-    int fds[2];
+    struct sigaction action;
 
-    err = qemu_eventfd(fds);
-    if (err == -1)
-        return -errno;
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS, &action, NULL);
 
-    err = fcntl_setfl(fds[0], O_NONBLOCK);
-    if (err < 0)
-        goto fail;
+    prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
+}
 
-    err = fcntl_setfl(fds[1], O_NONBLOCK);
-    if (err < 0)
-        goto fail;
+static void qemu_kvm_eat_signals(CPUState *env)
+{
+    struct timespec ts = { 0, 0 };
+    siginfo_t siginfo;
+    sigset_t waitset;
+    sigset_t chkset;
+    int r;
 
-    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
-                         (void *)(unsigned long)fds[0]);
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    io_thread_fd = fds[1];
-    return 0;
+    do {
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
+            perror("sigtimedwait");
+            exit(1);
+        }
 
-fail:
-    close(fds[0]);
-    close(fds[1]);
-    return err;
-}
-#else
-HANDLE qemu_event_handle;
+        switch (r) {
+        case SIGBUS:
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
+                sigbus_reraise();
+            }
+            break;
+        default:
+            break;
+        }
 
-static void dummy_event_handler(void *opaque)
-{
+        r = sigpending(&chkset);
+        if (r == -1) {
+            perror("sigpending");
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
 }
 
-static int qemu_event_init(void)
-{
-    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!qemu_event_handle) {
-        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
-        return -1;
-    }
-    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
-    return 0;
-}
+#else /* !CONFIG_LINUX */
 
-static void qemu_event_increment(void)
+static void qemu_init_sigbus(void)
 {
-    if (!SetEvent(qemu_event_handle)) {
-        fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
-                GetLastError());
-        exit (1);
-    }
 }
-#endif
 
-#ifndef CONFIG_IOTHREAD
-int qemu_init_main_loop(void)
+static void qemu_kvm_eat_signals(CPUState *env)
 {
-    cpu_set_debug_excp_handler(cpu_debug_handler);
-
-    return qemu_event_init();
 }
 
-void qemu_main_loop_start(void)
+#endif /* !CONFIG_LINUX */
+
+#ifndef _WIN32
+static void dummy_signal(int sig)
 {
 }
 
-void qemu_init_vcpu(void *_env)
+static void qemu_kvm_init_cpu_signals(CPUState *env)
 {
-    CPUState *env = _env;
+    int r;
+    sigset_t set;
+    struct sigaction sigact;
 
-    env->nr_cores = smp_cores;
-    env->nr_threads = smp_threads;
-    if (kvm_enabled())
-        kvm_init_vcpu(env);
-    return;
-}
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = dummy_signal;
+    sigaction(SIG_IPI, &sigact, NULL);
 
-int qemu_cpu_self(void *env)
-{
-    return 1;
-}
+    pthread_sigmask(SIG_BLOCK, NULL, &set);
+    sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
+    r = kvm_set_signal_mask(env, &set);
+    if (r) {
+        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
+        exit(1);
+    }
 
-void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
-{
-    func(data);
+    sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
+    r = kvm_set_signal_mask(env, &set);
+    if (r) {
+        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
+        exit(1);
+    }
 }
 
-void resume_all_vcpus(void)
+static void qemu_tcg_init_cpu_signals(void)
 {
-}
+    sigset_t set;
+    struct sigaction sigact;
 
-void pause_all_vcpus(void)
-{
-}
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = cpu_signal;
+    sigaction(SIG_IPI, &sigact, NULL);
 
-void qemu_cpu_kick(void *env)
-{
-    return;
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
 }
 
-void qemu_notify_event(void)
+#else /* _WIN32 */
+static void qemu_kvm_init_cpu_signals(CPUState *env)
 {
-    CPUState *env = cpu_single_env;
-
-    qemu_event_increment ();
-    if (env) {
-        cpu_exit(env);
-    }
-    if (next_cpu && env != next_cpu) {
-        cpu_exit(next_cpu);
-    }
+    abort();
 }
 
-void qemu_mutex_lock_iothread(void) {}
-void qemu_mutex_unlock_iothread(void) {}
-
-void vm_stop(int reason)
+static void qemu_tcg_init_cpu_signals(void)
 {
-    do_vm_stop(reason);
 }
 
-#else /* CONFIG_IOTHREAD */
-
-#include "qemu-thread.h"
+#endif /* _WIN32 */
 
 QemuMutex qemu_global_mutex;
-static QemuMutex qemu_fair_mutex;
+static QemuCond qemu_io_proceeded_cond;
+static bool iothread_requesting_mutex;
 
 static QemuThread io_thread;
 
 static QemuThread *tcg_cpu_thread;
 static QemuCond *tcg_halt_cond;
 
-static int qemu_system_ready;
 /* cpu creation */
 static QemuCond qemu_cpu_cond;
 /* system init */
-static QemuCond qemu_system_cond;
 static QemuCond qemu_pause_cond;
 static QemuCond qemu_work_cond;
 
-static void tcg_init_ipi(void);
-static void kvm_init_ipi(CPUState *env);
-static sigset_t block_io_signals(void);
-
-/* If we have signalfd, we mask out the signals we want to handle and then
- * use signalfd to listen for them.  We rely on whatever the current signal
- * handler is to dispatch the signals when we receive them.
- */
-static void sigfd_handler(void *opaque)
+void qemu_init_cpu_loop(void)
 {
-    int fd = (unsigned long) opaque;
-    struct qemu_signalfd_siginfo info;
-    struct sigaction action;
-    ssize_t len;
-
-    while (1) {
-        do {
-            len = read(fd, &info, sizeof(info));
-        } while (len == -1 && errno == EINTR);
-
-        if (len == -1 && errno == EAGAIN) {
-            break;
-        }
-
-        if (len != sizeof(info)) {
-            printf("read from sigfd returned %zd: %m\n", len);
-            return;
-        }
-
-        sigaction(info.ssi_signo, NULL, &action);
-        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
-            action.sa_sigaction(info.ssi_signo,
-                                (siginfo_t *)&info, NULL);
-        } else if (action.sa_handler) {
-            action.sa_handler(info.ssi_signo);
-        }
-    }
-}
-
-static int qemu_signalfd_init(sigset_t mask)
-{
-    int sigfd;
-
-    sigfd = qemu_signalfd(&mask);
-    if (sigfd == -1) {
-        fprintf(stderr, "failed to create signalfd\n");
-        return -errno;
-    }
-
-    fcntl_setfl(sigfd, O_NONBLOCK);
-
-    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
-                         (void *)(unsigned long) sigfd);
-
-    return 0;
-}
-
-int qemu_init_main_loop(void)
-{
-    int ret;
-    sigset_t blocked_signals;
-
-    cpu_set_debug_excp_handler(cpu_debug_handler);
-
-    blocked_signals = block_io_signals();
-
-    ret = qemu_signalfd_init(blocked_signals);
-    if (ret)
-        return ret;
-
-    /* Note eventfd must be drained before signalfd handlers run */
-    ret = qemu_event_init();
-    if (ret)
-        return ret;
-
+    qemu_init_sigbus();
+    qemu_cond_init(&qemu_cpu_cond);
     qemu_cond_init(&qemu_pause_cond);
-    qemu_cond_init(&qemu_system_cond);
-    qemu_mutex_init(&qemu_fair_mutex);
+    qemu_cond_init(&qemu_work_cond);
+    qemu_cond_init(&qemu_io_proceeded_cond);
     qemu_mutex_init(&qemu_global_mutex);
-    qemu_mutex_lock(&qemu_global_mutex);
-
-    qemu_thread_self(&io_thread);
-
-    return 0;
-}
 
-void qemu_main_loop_start(void)
-{
-    qemu_system_ready = 1;
-    qemu_cond_broadcast(&qemu_system_cond);
+    qemu_thread_get_self(&io_thread);
 }
 
 void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
 {
     struct qemu_work_item wi;
 
-    if (qemu_cpu_self(env)) {
+    if (qemu_cpu_is_self(env)) {
         func(data);
         return;
     }
 
     wi.func = func;
     wi.data = data;
-    if (!env->queued_work_first)
+    if (!env->queued_work_first) {
         env->queued_work_first = &wi;
-    else
+    } else {
         env->queued_work_last->next = &wi;
+    }
     env->queued_work_last = &wi;
     wi.next = NULL;
     wi.done = false;
@@ -461,8 +664,9 @@ static void flush_queued_work(CPUState *env)
 {
     struct qemu_work_item *wi;
 
-    if (!env->queued_work_first)
+    if (!env->queued_work_first) {
         return;
+    }
 
     while ((wi = env->queued_work_first)) {
         env->queued_work_first = wi->next;
@@ -481,255 +685,155 @@ static void qemu_wait_io_event_common(CPUState *env)
         qemu_cond_signal(&qemu_pause_cond);
     }
     flush_queued_work(env);
+    env->thread_kicked = false;
 }
 
 static void qemu_tcg_wait_io_event(void)
 {
     CPUState *env;
 
-    while (!any_cpu_has_work())
-        qemu_cond_timedwait(tcg_halt_cond, &qemu_global_mutex, 1000);
-
-    qemu_mutex_unlock(&qemu_global_mutex);
-
-    /*
-     * Users of qemu_global_mutex can be starved, having no chance
-     * to acquire it since this path will get to it first.
-     * So use another lock to provide fairness.
-     */
-    qemu_mutex_lock(&qemu_fair_mutex);
-    qemu_mutex_unlock(&qemu_fair_mutex);
+    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);
+    }
 
-    qemu_mutex_lock(&qemu_global_mutex);
+    while (iothread_requesting_mutex) {
+        qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
+    }
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
         qemu_wait_io_event_common(env);
     }
 }
 
-static void sigbus_reraise(void)
-{
-    sigset_t set;
-    struct sigaction action;
-
-    memset(&action, 0, sizeof(action));
-    action.sa_handler = SIG_DFL;
-    if (!sigaction(SIGBUS, &action, NULL)) {
-        raise(SIGBUS);
-        sigemptyset(&set);
-        sigaddset(&set, SIGBUS);
-        sigprocmask(SIG_UNBLOCK, &set, NULL);
-    }
-    perror("Failed to re-raise SIGBUS!\n");
-    abort();
-}
-
-static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
-                           void *ctx)
-{
-#if defined(TARGET_I386)
-    if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))
-#endif
-        sigbus_reraise();
-}
-
-static void qemu_kvm_eat_signal(CPUState *env, int timeout)
-{
-    struct timespec ts;
-    int r, e;
-    siginfo_t siginfo;
-    sigset_t waitset;
-    sigset_t chkset;
-
-    ts.tv_sec = timeout / 1000;
-    ts.tv_nsec = (timeout % 1000) * 1000000;
-
-    sigemptyset(&waitset);
-    sigaddset(&waitset, SIG_IPI);
-    sigaddset(&waitset, SIGBUS);
-
-    do {
-        qemu_mutex_unlock(&qemu_global_mutex);
-
-        r = sigtimedwait(&waitset, &siginfo, &ts);
-        e = errno;
-
-        qemu_mutex_lock(&qemu_global_mutex);
-
-        if (r == -1 && !(e == EAGAIN || e == EINTR)) {
-            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-            exit(1);
-        }
-
-        switch (r) {
-        case SIGBUS:
-#ifdef TARGET_I386
-            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
-#endif
-                sigbus_reraise();
-            break;
-        default:
-            break;
-        }
-
-        r = sigpending(&chkset);
-        if (r == -1) {
-            fprintf(stderr, "sigpending: %s\n", strerror(e));
-            exit(1);
-        }
-    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
-}
-
 static void qemu_kvm_wait_io_event(CPUState *env)
 {
-    while (!cpu_has_work(env))
-        qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+    while (cpu_thread_is_idle(env)) {
+        qemu_cond_wait(env->halt_cond, &qemu_global_mutex);
+    }
 
-    qemu_kvm_eat_signal(env, 0);
+    qemu_kvm_eat_signals(env);
     qemu_wait_io_event_common(env);
 }
 
-static int qemu_cpu_exec(CPUState *env);
-
-static void *kvm_cpu_thread_fn(void *arg)
+static void *qemu_kvm_cpu_thread_fn(void *arg)
 {
     CPUState *env = arg;
+    int r;
 
     qemu_mutex_lock(&qemu_global_mutex);
-    qemu_thread_self(env->thread);
-    if (kvm_enabled())
-        kvm_init_vcpu(env);
+    qemu_thread_get_self(env->thread);
+    env->thread_id = qemu_get_thread_id();
 
-    kvm_init_ipi(env);
+    r = kvm_init_vcpu(env);
+    if (r < 0) {
+        fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
+        exit(1);
+    }
+
+    qemu_kvm_init_cpu_signals(env);
 
     /* signal CPU creation */
     env->created = 1;
     qemu_cond_signal(&qemu_cpu_cond);
 
-    /* and wait for machine initialization */
-    while (!qemu_system_ready)
-        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
-
     while (1) {
-        if (cpu_can_run(env))
-            qemu_cpu_exec(env);
+        if (cpu_can_run(env)) {
+            r = kvm_cpu_exec(env);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(env);
+            }
+        }
         qemu_kvm_wait_io_event(env);
     }
 
     return NULL;
 }
 
-static void *tcg_cpu_thread_fn(void *arg)
+static void tcg_exec_all(void);
+
+static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
     CPUState *env = arg;
 
-    tcg_init_ipi();
-    qemu_thread_self(env->thread);
+    qemu_tcg_init_cpu_signals();
+    qemu_thread_get_self(env->thread);
 
     /* signal CPU creation */
     qemu_mutex_lock(&qemu_global_mutex);
-    for (env = first_cpu; env != NULL; env = env->next_cpu)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->thread_id = qemu_get_thread_id();
         env->created = 1;
+    }
     qemu_cond_signal(&qemu_cpu_cond);
 
-    /* and wait for machine initialization */
-    while (!qemu_system_ready)
-        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+    /* wait for initial kick-off after machine start */
+    while (first_cpu->stopped) {
+        qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
+    }
 
     while (1) {
-        cpu_exec_all();
+        tcg_exec_all();
+        if (use_icount && qemu_clock_deadline(vm_clock) <= 0) {
+            qemu_notify_event();
+        }
         qemu_tcg_wait_io_event();
     }
 
     return NULL;
 }
 
-void qemu_cpu_kick(void *_env)
+static void qemu_cpu_kick_thread(CPUState *env)
 {
-    CPUState *env = _env;
-    qemu_cond_broadcast(env->halt_cond);
-    qemu_thread_signal(env->thread, SIG_IPI);
-}
-
-int qemu_cpu_self(void *_env)
-{
-    CPUState *env = _env;
-    QemuThread this;
-
-    qemu_thread_self(&this);
-
-    return qemu_thread_equal(&this, env->thread);
-}
+#ifndef _WIN32
+    int err;
 
-static void cpu_signal(int sig)
-{
-    if (cpu_single_env)
-        cpu_exit(cpu_single_env);
-    exit_request = 1;
+    err = pthread_kill(env->thread->thread, SIG_IPI);
+    if (err) {
+        fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
+        exit(1);
+    }
+#else /* _WIN32 */
+    if (!qemu_cpu_is_self(env)) {
+        SuspendThread(env->thread->thread);
+        cpu_signal(0);
+        ResumeThread(env->thread->thread);
+    }
+#endif
 }
 
-static void tcg_init_ipi(void)
+void qemu_cpu_kick(void *_env)
 {
-    sigset_t set;
-    struct sigaction sigact;
-
-    memset(&sigact, 0, sizeof(sigact));
-    sigact.sa_handler = cpu_signal;
-    sigaction(SIG_IPI, &sigact, NULL);
-
-    sigemptyset(&set);
-    sigaddset(&set, SIG_IPI);
-    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-}
+    CPUState *env = _env;
 
-static void dummy_signal(int sig)
-{
+    qemu_cond_broadcast(env->halt_cond);
+    if ((kvm_enabled()) && !env->thread_kicked) {
+        qemu_cpu_kick_thread(env);
+        env->thread_kicked = true;
+    }
 }
 
-static void kvm_init_ipi(CPUState *env)
+void qemu_cpu_kick_self(void)
 {
-    int r;
-    sigset_t set;
-    struct sigaction sigact;
-
-    memset(&sigact, 0, sizeof(sigact));
-    sigact.sa_handler = dummy_signal;
-    sigaction(SIG_IPI, &sigact, NULL);
+#ifndef _WIN32
+    assert(cpu_single_env);
 
-    pthread_sigmask(SIG_BLOCK, NULL, &set);
-    sigdelset(&set, SIG_IPI);
-    sigdelset(&set, SIGBUS);
-    r = kvm_set_signal_mask(env, &set);
-    if (r) {
-        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
-        exit(1);
+    if (!cpu_single_env->thread_kicked) {
+        qemu_cpu_kick_thread(cpu_single_env);
+        cpu_single_env->thread_kicked = true;
     }
+#else
+    abort();
+#endif
 }
 
-static sigset_t block_io_signals(void)
+int qemu_cpu_is_self(void *_env)
 {
-    sigset_t set;
-    struct sigaction action;
-
-    /* SIGUSR2 used by posix-aio-compat.c */
-    sigemptyset(&set);
-    sigaddset(&set, SIGUSR2);
-    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-
-    sigemptyset(&set);
-    sigaddset(&set, SIGIO);
-    sigaddset(&set, SIGALRM);
-    sigaddset(&set, SIG_IPI);
-    sigaddset(&set, SIGBUS);
-    pthread_sigmask(SIG_BLOCK, &set, NULL);
-
-    memset(&action, 0, sizeof(action));
-    action.sa_flags = SA_SIGINFO;
-    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
-    sigaction(SIGBUS, &action, NULL);
-    prctl(PR_MCE_KILL, 1, 1, 0, 0);
+    CPUState *env = _env;
 
-    return set;
+    return qemu_thread_is_self(env->thread);
 }
 
 void qemu_mutex_lock_iothread(void)
@@ -737,12 +841,13 @@ void qemu_mutex_lock_iothread(void)
     if (kvm_enabled()) {
         qemu_mutex_lock(&qemu_global_mutex);
     } else {
-        qemu_mutex_lock(&qemu_fair_mutex);
+        iothread_requesting_mutex = true;
         if (qemu_mutex_trylock(&qemu_global_mutex)) {
-            qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
+            qemu_cpu_kick_thread(first_cpu);
             qemu_mutex_lock(&qemu_global_mutex);
         }
-        qemu_mutex_unlock(&qemu_fair_mutex);
+        iothread_requesting_mutex = false;
+        qemu_cond_broadcast(&qemu_io_proceeded_cond);
     }
 }
 
@@ -756,8 +861,9 @@ static int all_vcpus_paused(void)
     CPUState *penv = first_cpu;
 
     while (penv) {
-        if (!penv->stopped)
+        if (!penv->stopped) {
             return 0;
+        }
         penv = (CPUState *)penv->next_cpu;
     }
 
@@ -768,6 +874,7 @@ void pause_all_vcpus(void)
 {
     CPUState *penv = first_cpu;
 
+    qemu_clock_enable(vm_clock, false);
     while (penv) {
         penv->stop = 1;
         qemu_cpu_kick(penv);
@@ -775,7 +882,7 @@ void pause_all_vcpus(void)
     }
 
     while (!all_vcpus_paused()) {
-        qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+        qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
         penv = first_cpu;
         while (penv) {
             qemu_cpu_kick(penv);
@@ -788,6 +895,7 @@ void resume_all_vcpus(void)
 {
     CPUState *penv = first_cpu;
 
+    qemu_clock_enable(vm_clock, true);
     while (penv) {
         penv->stop = 0;
         penv->stopped = 0;
@@ -796,33 +904,40 @@ void resume_all_vcpus(void)
     }
 }
 
-static void tcg_init_vcpu(void *_env)
+static void qemu_tcg_init_vcpu(void *_env)
 {
     CPUState *env = _env;
+
+#ifdef CONFIG_HAX
+       if (hax_enabled())
+               hax_init_vcpu(env);
+#endif
     /* share a single thread for all cpus with TCG */
     if (!tcg_cpu_thread) {
-        env->thread = qemu_mallocz(sizeof(QemuThread));
-        env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+        env->thread = g_malloc0(sizeof(QemuThread));
+        env->halt_cond = g_malloc0(sizeof(QemuCond));
         qemu_cond_init(env->halt_cond);
-        qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
-        while (env->created == 0)
-            qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
-        tcg_cpu_thread = env->thread;
         tcg_halt_cond = env->halt_cond;
+        qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env);
+        while (env->created == 0) {
+            qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+        }
+        tcg_cpu_thread = env->thread;
     } else {
         env->thread = tcg_cpu_thread;
         env->halt_cond = tcg_halt_cond;
     }
 }
 
-static void kvm_start_vcpu(CPUState *env)
+static void qemu_kvm_start_vcpu(CPUState *env)
 {
-    env->thread = qemu_mallocz(sizeof(QemuThread));
-    env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+    env->thread = g_malloc0(sizeof(QemuThread));
+    env->halt_cond = g_malloc0(sizeof(QemuCond));
     qemu_cond_init(env->halt_cond);
-    qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
-    while (env->created == 0)
-        qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+    qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env);
+    while (env->created == 0) {
+        qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+    }
 }
 
 void qemu_init_vcpu(void *_env)
@@ -831,46 +946,50 @@ void qemu_init_vcpu(void *_env)
 
     env->nr_cores = smp_cores;
     env->nr_threads = smp_threads;
-    if (kvm_enabled())
-        kvm_start_vcpu(env);
+    env->stopped = 1;
+    if (kvm_enabled()) {
+        qemu_kvm_start_vcpu(env);
+    }
     else
-        tcg_init_vcpu(env);
-}
-
-void qemu_notify_event(void)
-{
-    qemu_event_increment();
+        qemu_tcg_init_vcpu(env);
 }
 
-static void qemu_system_vmstop_request(int reason)
+void cpu_stop_current(void)
 {
-    vmstop_requested = reason;
-    qemu_notify_event();
+    if (cpu_single_env) {
+        cpu_single_env->stop = 0;
+        cpu_single_env->stopped = 1;
+        cpu_exit(cpu_single_env);
+        qemu_cond_signal(&qemu_pause_cond);
+    }
 }
 
-void vm_stop(int reason)
+void vm_stop(RunState state)
 {
-    QemuThread me;
-    qemu_thread_self(&me);
-
-    if (!qemu_thread_equal(&me, &io_thread)) {
-        qemu_system_vmstop_request(reason);
+    if (!qemu_thread_is_self(&io_thread)) {
+        qemu_system_vmstop_request(state);
         /*
          * FIXME: should not return to device code in case
          * vm_stop() has been requested.
          */
-        if (cpu_single_env) {
-            cpu_exit(cpu_single_env);
-            cpu_single_env->stop = 1;
-        }
+        cpu_stop_current();
         return;
     }
-    do_vm_stop(reason);
+    do_vm_stop(state);
 }
 
-#endif
+/* does a state transition even if the VM is already stopped,
+   current state is forgotten forever */
+void vm_stop_force_state(RunState state)
+{
+    if (runstate_is_running()) {
+        vm_stop(state);
+    } else {
+        runstate_set(state);
+    }
+}
 
-static int qemu_cpu_exec(CPUState *env)
+static int tcg_cpu_exec(CPUState *env)
 {
     int ret;
 #ifdef CONFIG_PROFILER
@@ -886,7 +1005,7 @@ static int qemu_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_clock_deadline(vm_clock));
         qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;
@@ -908,28 +1027,33 @@ static int qemu_cpu_exec(CPUState *env)
     return ret;
 }
 
-bool cpu_exec_all(void)
+static void tcg_exec_all(void)
 {
-    if (next_cpu == NULL)
+    int r;
+
+    /* Account partial waits to the vm_clock.  */
+    qemu_clock_warp(vm_clock);
+
+    if (next_cpu == NULL) {
         next_cpu = first_cpu;
+    }
     for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
         CPUState *env = next_cpu;
 
         qemu_clock_enable(vm_clock,
                           (env->singlestep_enabled & SSTEP_NOTIMER) == 0);
 
-        if (qemu_alarm_pending())
-            break;
         if (cpu_can_run(env)) {
-            if (qemu_cpu_exec(env) == EXCP_DEBUG) {
+            r = tcg_cpu_exec(env);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(env);
                 break;
             }
-        } else if (env->stop) {
+        } else if (env->stop || env->stopped) {
             break;
         }
     }
     exit_request = 0;
-    return any_cpu_has_work();
 }
 
 void set_numa_modes(void)
@@ -962,20 +1086,9 @@ void set_cpu_log(const char *optarg)
     cpu_set_log(mask);
 }
 
-/* Return the virtual CPU time, based on the instruction counter.  */
-int64_t cpu_get_icount(void)
+void set_cpu_log_filename(const char *optarg)
 {
-    int64_t icount;
-    CPUState *env = cpu_single_env;;
-
-    icount = qemu_icount;
-    if (env) {
-        if (!can_do_io(env)) {
-            fprintf(stderr, "Bad clock read\n");
-        }
-        icount -= (env->icount_decr.u16.low + env->icount_extra);
-    }
-    return qemu_icount_bias + (icount << icount_time_shift);
+    cpu_set_log_filename(optarg);
 }
 
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
@@ -987,3 +1100,57 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
     cpu_list(f, cpu_fprintf); /* deprecated */
 #endif
 }
+
+CpuInfoList *qmp_query_cpus(Error **errp)
+{
+    CpuInfoList *head = NULL, *cur_item = NULL;
+    CPUState *env;
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        CpuInfoList *info;
+
+        cpu_synchronize_state(env);
+
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->CPU = env->cpu_index;
+        info->value->current = (env == first_cpu);
+        info->value->halted = env->halted;
+        info->value->thread_id = env->thread_id;
+#if defined(TARGET_I386)
+        info->value->has_pc = true;
+        info->value->pc = env->eip + env->segs[R_CS].base;
+#elif defined(TARGET_PPC)
+        info->value->has_nip = true;
+        info->value->nip = env->nip;
+#elif defined(TARGET_SPARC)
+        info->value->has_pc = true;
+        info->value->pc = env->pc;
+        info->value->has_npc = true;
+        info->value->npc = env->npc;
+#elif defined(TARGET_MIPS)
+        info->value->has_PC = true;
+        info->value->PC = env->active_tc.PC;
+#endif
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
+        }
+    }
+
+    return head;
+}
+
+#ifdef         CONFIG_HAX
+void qemu_notify_hax_event(void)
+{
+       CPUState *env = cpu_single_env;
+
+       if (hax_enabled() && env)
+               hax_raise_event(env);
+}
+#endif
diff --git a/cpus.h b/cpus.h
index bf4d9bb87a75f521aed366a50d6257708aeab702..4ea2fe2c22ec1f47a54321e0ca9d610d38675cad 100644 (file)
--- a/cpus.h
+++ b/cpus.h
@@ -2,20 +2,21 @@
 #define QEMU_CPUS_H
 
 /* cpus.c */
-int qemu_init_main_loop(void);
-void qemu_main_loop_start(void);
+void qemu_init_cpu_loop(void);
 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;
-extern int debug_requested;
-extern int vmstop_requested;
-void vm_state_notify(int running, int reason);
-bool cpu_exec_all(void);
 void set_numa_modes(void);
 void set_cpu_log(const char *optarg);
+void set_cpu_log_filename(const char *optarg);
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
 
 #endif
index 5fa67d9f29799d60b1ba0d9c645dcbe4bd2492b5..5b8e90b2cdec4e64779782b8addb9c11fab703de 100644 (file)
@@ -1396,32 +1396,32 @@ get_opcode_entry (unsigned int insn,
   /* Allocate and clear the opcode-table.  */
   if (opc_table == NULL)
     {
-      opc_table = qemu_malloc (65536 * sizeof (opc_table[0]));
+      opc_table = g_malloc (65536 * sizeof (opc_table[0]));
 
       memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *));
 
       dip_prefixes
-       = qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+       = g_malloc (65536 * sizeof (const struct cris_opcode **));
 
       memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0]));
 
       bdapq_m1_prefixes
-       = qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+       = g_malloc (65536 * sizeof (const struct cris_opcode **));
 
       memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0]));
 
       bdapq_m2_prefixes
-       = qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+       = g_malloc (65536 * sizeof (const struct cris_opcode **));
 
       memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0]));
 
       bdapq_m4_prefixes
-       = qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+       = g_malloc (65536 * sizeof (const struct cris_opcode **));
 
       memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0]));
 
       rest_prefixes
-       = qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+       = g_malloc (65536 * sizeof (const struct cris_opcode **));
 
       memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0]));
     }
index dfb9eefaad27a1bbc0aaf9b7b219dd3a04b4f4fe..efc5917029a311091b53f26b14d44c4672ad641d 100644 (file)
--- a/cursor.c
+++ b/cursor.c
@@ -98,7 +98,7 @@ QEMUCursor *cursor_alloc(int width, int height)
     QEMUCursor *c;
     int datasize = width * height * sizeof(uint32_t);
 
-    c = qemu_mallocz(sizeof(QEMUCursor) + datasize);
+    c = g_malloc0(sizeof(QEMUCursor) + datasize);
     c->width  = width;
     c->height = height;
     c->refcount = 1;
@@ -117,7 +117,7 @@ void cursor_put(QEMUCursor *c)
     c->refcount--;
     if (c->refcount)
         return;
-    qemu_free(c);
+    g_free(c);
 }
 
 int cursor_get_mono_bpl(QEMUCursor *c)
index f9a7e3689e04605beebabef940f280e1a8fca572..24b3fe355bb499dcb6f637dffd8153b3f2018b36 100644 (file)
--- a/cutils.c
+++ b/cutils.c
@@ -136,7 +136,7 @@ int qemu_fdatasync(int fd)
 
 void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
 {
-    qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec));
+    qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
     qiov->niov = 0;
     qiov->nalloc = alloc_hint;
     qiov->size = 0;
@@ -160,7 +160,7 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
 
     if (qiov->niov == qiov->nalloc) {
         qiov->nalloc = 2 * qiov->nalloc + 1;
-        qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+        qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
     }
     qiov->iov[qiov->niov].iov_base = base;
     qiov->iov[qiov->niov].iov_len = len;
@@ -217,7 +217,10 @@ void qemu_iovec_destroy(QEMUIOVector *qiov)
 {
     assert(qiov->nalloc != -1);
 
-    qemu_free(qiov->iov);
+    qemu_iovec_reset(qiov);
+    g_free(qiov->iov);
+    qiov->nalloc = 0;
+    qiov->iov = NULL;
 }
 
 void qemu_iovec_reset(QEMUIOVector *qiov)
@@ -315,18 +318,34 @@ int fcntl_setfl(int fd, int flag)
 }
 #endif
 
+static int64_t suffix_mul(char suffix, int64_t unit)
+{
+    switch (qemu_toupper(suffix)) {
+    case STRTOSZ_DEFSUFFIX_B:
+        return 1;
+    case STRTOSZ_DEFSUFFIX_KB:
+        return unit;
+    case STRTOSZ_DEFSUFFIX_MB:
+        return unit * unit;
+    case STRTOSZ_DEFSUFFIX_GB:
+        return unit * unit * unit;
+    case STRTOSZ_DEFSUFFIX_TB:
+        return unit * unit * unit * unit;
+    }
+    return -1;
+}
+
 /*
  * Convert string to bytes, allowing either B/b for bytes, K/k for KB,
- * M/m for MB, G/g for GB or T/t for TB. Default without any postfix
- * is MB. End pointer will be returned in *end, if not NULL. A valid
- * value must be terminated by whitespace, ',' or '\0'. Return -1 on
- * error.
+ * M/m for MB, G/g for GB or T/t for TB. End pointer will be returned
+ * in *end, if not NULL. Return -1 on error.
  */
-int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+int64_t strtosz_suffix_unit(const char *nptr, char **end,
+                            const char default_suffix, int64_t unit)
 {
     int64_t retval = -1;
     char *endptr;
-    unsigned char c, d;
+    unsigned char c;
     int mul_required = 0;
     double val, mul, integral, fraction;
 
@@ -339,59 +358,17 @@ int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
     if (fraction != 0) {
         mul_required = 1;
     }
-    /*
-     * Any whitespace character is fine for terminating the number,
-     * in addition we accept ',' to handle strings where the size is
-     * part of a multi token argument.
-     */
     c = *endptr;
-    d = c;
-    if (qemu_isspace(c) || c == '\0' || c == ',') {
-        c = 0;
-        if (default_suffix) {
-            d = default_suffix;
-        } else {
-            d = c;
-        }
+    mul = suffix_mul(c, unit);
+    if (mul >= 0) {
+        endptr++;
+    } else {
+        mul = suffix_mul(default_suffix, unit);
+        assert(mul >= 0);
     }
-    switch (qemu_toupper(d)) {
-    case STRTOSZ_DEFSUFFIX_B:
-        mul = 1;
-        if (mul_required) {
-            goto fail;
-        }
-        break;
-    case STRTOSZ_DEFSUFFIX_KB:
-        mul = 1 << 10;
-        break;
-    case 0:
-        if (mul_required) {
-            goto fail;
-        }
-    case STRTOSZ_DEFSUFFIX_MB:
-        mul = 1ULL << 20;
-        break;
-    case STRTOSZ_DEFSUFFIX_GB:
-        mul = 1ULL << 30;
-        break;
-    case STRTOSZ_DEFSUFFIX_TB:
-        mul = 1ULL << 40;
-        break;
-    default:
+    if (mul == 1 && mul_required) {
         goto fail;
     }
-    /*
-     * If not terminated by whitespace, ',', or \0, increment endptr
-     * to point to next character, then check that we are terminated
-     * by an appropriate separating character, ie. whitespace, ',', or
-     * \0. If not, we are seeing trailing garbage, thus fail.
-     */
-    if (c != 0) {
-        endptr++;
-        if (!qemu_isspace(*endptr) && *endptr != ',' && *endptr != 0) {
-            goto fail;
-        }
-    }
     if ((val * mul >= INT64_MAX) || val < 0) {
         goto fail;
     }
@@ -405,7 +382,24 @@ fail:
     return retval;
 }
 
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+{
+    return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
+}
+
 int64_t strtosz(const char *nptr, char **end)
 {
     return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
 }
+
+int qemu_parse_fd(const char *param)
+{
+    int fd;
+    char *endptr = NULL;
+
+    fd = strtol(param, &endptr, 10);
+    if (*endptr || (fd == 0 && param == endptr)) {
+        return -1;
+    }
+    return fd;
+}
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 3bc3b655599a2948480871ed28c127179bacda0b..0aa828298b335ec28e4f89a926f36394caa92571 100644 (file)
@@ -865,11 +865,11 @@ unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
         page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
     }
 
-    DPRINTF("pushing argc %d \n", argc);
+    DPRINTF("pushing argc %d\n", argc);
     stl(stack, argc);
     stack--;
 
-    DPRINTF("pushing mh 0x%x \n", (int)mh);
+    DPRINTF("pushing mh 0x%x\n", (int)mh);
     stl(stack, (int) mh);
 
     /* Stack points on the mh */
index 175e12f968412582a0aac85deb636303167cec2a..c0f14f826061c9a17c8dfa7876c50ccae67210d8 100644 (file)
@@ -729,8 +729,6 @@ static void usage(void)
 
 /* XXX: currently only used for async signals (see signal.c) */
 CPUState *global_env;
-/* used only if single thread */
-CPUState *cpu_single_env = NULL;
 
 /* used to free thread contexts */
 TaskState *first_task_state;
@@ -738,6 +736,8 @@ TaskState *first_task_state;
 int main(int argc, char **argv)
 {
     const char *filename;
+    const char *log_file = DEBUG_LOGFILE;
+    const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     TaskState ts1, *ts = &ts1;
     CPUState *env;
@@ -749,9 +749,6 @@ int main(int argc, char **argv)
     if (argc <= 1)
         usage();
 
-    /* init debug */
-    cpu_set_log_filename(DEBUG_LOGFILE);
-
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -764,22 +761,15 @@ int main(int argc, char **argv)
         if (!strcmp(r, "-")) {
             break;
         } else if (!strcmp(r, "d")) {
-            int mask;
-            CPULogItem *item;
-
-        if (optind >= argc)
-        break;
-
-        r = argv[optind++];
-            mask = cpu_str_to_log_mask(r);
-            if (!mask) {
-                printf("Log items (comma separated):\n");
-                for(item = cpu_log_items; item->mask != 0; item++) {
-                    printf("%-10s %s\n", item->name, item->help);
-                }
-                exit(1);
+            if (optind >= argc) {
+                break;
+            }
+            log_mask = argv[optind++];
+        } else if (!strcmp(r, "D")) {
+            if (optind >= argc) {
+                break;
             }
-            cpu_set_log(mask);
+            log_file = argv[optind++];
         } else if (!strcmp(r, "s")) {
             r = argv[optind++];
             stack_size = strtol(r, (char **)&r, 0);
@@ -817,8 +807,27 @@ int main(int argc, char **argv)
             usage();
         }
     }
-    if (optind >= argc)
+
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    if (log_mask) {
+        int mask;
+        CPULogItem *item;
+
+        mask = cpu_str_to_log_mask(log_mask);
+        if (!mask) {
+            printf("Log items (comma separated):\n");
+            for (item = cpu_log_items; item->mask != 0; item++) {
+                printf("%-10s %s\n", item->name, item->help);
+            }
+            exit(1);
+        }
+        cpu_set_log(mask);
+    }
+
+    if (optind >= argc) {
         usage();
+    }
     filename = argv[optind];
 
     /* Zero out regs */
@@ -841,8 +850,8 @@ int main(int argc, char **argv)
 #error unsupported CPU
 #endif
     }
-    
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
index 48620184eec2a609e17d4eb144d8439aca68b4c2..c530227f1ca45b72fba74447f738ae5ef847431d 100644 (file)
@@ -21,7 +21,6 @@
 #include <string.h>
 #include <stdarg.h>
 #include <unistd.h>
-#include <signal.h>
 #include <errno.h>
 #include <sys/ucontext.h>
 
@@ -32,8 +31,6 @@
 #undef uc_link
 #endif
 
-#include <signal.h>
-
 #include "qemu.h"
 #include "qemu-common.h"
 
@@ -322,7 +319,6 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
                        void *set, CPUState *env)
 {
        void *frame;
-       int i, err = 0;
 
     fprintf(stderr, "setup_frame %d\n", sig);
        frame = get_sigframe(ka, env, sizeof(*frame));
index 060acc889de836d59f3a69e8ddeeb0719604aef5..f3cc1f83a6deeb1259dfcecff3e2f0ed0f011484 100644 (file)
@@ -977,7 +977,7 @@ long do_unix_syscall_indirect(void *cpu_env, int num)
 #elif TARGET_PPC
     {
         int i;
-        /* XXX: not really needed those regs are volatile accross calls */
+        /* XXX: not really needed those regs are volatile across calls */
         uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
         for(i = 11; i > 3; i--)
             *regs[i] = *regs[i-1];
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
new file mode 100644 (file)
index 0000000..bd1dd95
--- /dev/null
@@ -0,0 +1,12 @@
+# Default configuration for alpha-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_PCKBD=y
+CONFIG_VGA_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_VMWARE_VGA=y
+CONFIG_IDE_CMD646=y
+CONFIG_I8259=y
index 323fafbf7fbe0563e1095e27c170262dec0bd3a1..e67ebb360e0b354e28e0d68d0bf871d718f43d23 100644 (file)
@@ -4,6 +4,7 @@ include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
+CONFIG_VMMOUSE=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
@@ -18,3 +19,6 @@ CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
+CONFIG_HPET=y
+CONFIG_APPLESMC=y
+CONFIG_I8259=y
diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak
new file mode 100644 (file)
index 0000000..0d19974
--- /dev/null
@@ -0,0 +1,6 @@
+# Default configuration for lm32-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_SD=y
index 4399b8b3618d56e725dbda8acf8430db91c19924..613edab742bb16d67d384659f6bb0810639de2cd 100644 (file)
@@ -2,3 +2,4 @@
 
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_SERIAL=y
diff --git a/default-configs/microblazeel-linux-user.mak b/default-configs/microblazeel-linux-user.mak
new file mode 100644 (file)
index 0000000..378c6dd
--- /dev/null
@@ -0,0 +1 @@
+# Default configuration for microblazeel-linux-user
diff --git a/default-configs/microblazeel-softmmu.mak b/default-configs/microblazeel-softmmu.mak
new file mode 100644 (file)
index 0000000..4b40fb2
--- /dev/null
@@ -0,0 +1,5 @@
+# Default configuration for microblazeel-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_SERIAL=y
index f52497159820a9398060dde784236d1678033fb0..94a34862dcdb90f9b2cda803c134611a97929198 100644 (file)
@@ -26,3 +26,5 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
+CONFIG_I8259=y
index aeab6b2c28c6c0697aa58e83dfe670b6244e5902..b5d310816fc7895a1df7791f49ca738bf187079b 100644 (file)
@@ -26,3 +26,5 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
+CONFIG_I8259=y
index 8e6511cbeb43cd2773ca4a6553426ffdf3a32061..2831f44f2ab88559e4f797231611b9edcbc84b68 100644 (file)
@@ -28,3 +28,5 @@ CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_FULONG=y
+CONFIG_G364FB=y
+CONFIG_I8259=y
index a05ac25393d68e2b99117e1db178ccebc79d6375..14c949df13454dec62184b231a5cce6c1c24324c 100644 (file)
@@ -26,3 +26,5 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
+CONFIG_I8259=y
index 0471efbcd8cf0cc335ca442b109e6886f3d7eca7..22bd3502d46d8ab70e75ec899bde73c2452d5b42 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO=y
 CONFIG_USB_UHCI=y
 CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
 CONFIG_NE2000_PCI=y
 CONFIG_EEPRO100_PCI=y
 CONFIG_PCNET_PCI=y
index 45637429ed5bbe61ed545f94bca616b9b36e8a17..c85cdceb1524a7b8a4a4c30ac68ab1886b3f843b 100644 (file)
@@ -31,3 +31,4 @@ CONFIG_SOUND=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
+CONFIG_I8259=y
index d5073b3e09af84130e5ad992407198ffc8552161..8874115d81f9d627e0c9b322b66550a375b5406a 100644 (file)
@@ -31,3 +31,4 @@ CONFIG_SOUND=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
+CONFIG_I8259=y
index 9f0730c7a58d425ecf0ec6738ac152f39a9e1d9e..5db7205267fd87df41232aac7c6e2c86c441ff38 100644 (file)
@@ -31,3 +31,4 @@ CONFIG_SOUND=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
+CONFIG_I8259=y
diff --git a/default-configs/s390x-linux-user.mak b/default-configs/s390x-linux-user.mak
new file mode 100644 (file)
index 0000000..a243c99
--- /dev/null
@@ -0,0 +1 @@
+# Default configuration for s390x-linux-user
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 eff26d2a24b368c2bc6d9503013c505d619603ec..b75757ee5f704bd32638ce97f5dcea26f0961f13 100644 (file)
@@ -4,6 +4,7 @@ include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
+CONFIG_VMMOUSE=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
@@ -18,3 +19,6 @@ CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
+CONFIG_HPET=y
+CONFIG_APPLESMC=y
+CONFIG_I8259=y
diff --git a/default-configs/xtensa-softmmu.mak b/default-configs/xtensa-softmmu.mak
new file mode 100644 (file)
index 0000000..9d8899c
--- /dev/null
@@ -0,0 +1,5 @@
+# Default configuration for Xtensa
+
+CONFIG_SERIAL=y
+CONFIG_OPENCORES_ETH=y
+CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/xtensaeb-softmmu.mak b/default-configs/xtensaeb-softmmu.mak
new file mode 100644 (file)
index 0000000..9d8899c
--- /dev/null
@@ -0,0 +1,5 @@
+# Default configuration for Xtensa
+
+CONFIG_SERIAL=y
+CONFIG_OPENCORES_ETH=y
+CONFIG_PFLASH_CFI01=y
index 426a63155cf3fa7706367bcd9ed540d0aac8d8f1..86a694c95503357a6ee15cbe427922cd31ec319a 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "config.h"
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "device_tree.h"
 #include "hw/loader.h"
 
@@ -42,9 +41,10 @@ void *load_device_tree(const char *filename_path, int *sizep)
     }
 
     /* Expand to 2x size to give enough room for manipulation.  */
+    dt_size += 10000;
     dt_size *= 2;
     /* First allocate space in qemu for device tree */
-    fdt = qemu_mallocz(dt_size);
+    fdt = g_malloc0(dt_size);
 
     dt_file_load_size = load_image(filename_path, fdt);
     if (dt_file_load_size < 0) {
@@ -69,42 +69,104 @@ void *load_device_tree(const char *filename_path, int *sizep)
     return fdt;
 
 fail:
-    qemu_free(fdt);
+    g_free(fdt);
     return NULL;
 }
 
-int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, uint32_t *val_array, int size)
+static int findnode_nofail(void *fdt, const char *node_path)
 {
     int offset;
 
     offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    if (offset < 0) {
+        fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
+                fdt_strerror(offset));
+        exit(1);
+    }
 
-    return fdt_setprop(fdt, offset, property, val_array, size);
+    return offset;
+}
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, void *val_array, int size)
+{
+    int r;
+
+    r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
+                property, fdt_strerror(r));
+        exit(1);
+    }
+
+    return r;
 }
 
 int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
                               const char *property, uint32_t val)
 {
-    int offset;
+    int r;
 
-    offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
+                node_path, property, val, fdt_strerror(r));
+        exit(1);
+    }
 
-    return fdt_setprop_cell(fdt, offset, property, val);
+    return r;
 }
 
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
                                 const char *property, const char *string)
 {
-    int offset;
+    int r;
 
-    offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
+                node_path, property, string, fdt_strerror(r));
+        exit(1);
+    }
+
+    return r;
+}
+
+int qemu_devtree_nop_node(void *fdt, const char *node_path)
+{
+    int r;
+
+    r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
+                fdt_strerror(r));
+        exit(1);
+    }
+
+    return r;
+}
+
+int qemu_devtree_add_subnode(void *fdt, const char *name)
+{
+    char *dupname = g_strdup(name);
+    char *basename = strrchr(dupname, '/');
+    int retval;
+
+    if (!basename) {
+        g_free(dupname);
+        return -1;
+    }
+
+    basename[0] = '\0';
+    basename++;
+
+    retval = fdt_add_subnode(fdt, findnode_nofail(fdt, dupname), basename);
+    if (retval < 0) {
+        fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
+                fdt_strerror(retval));
+        exit(1);
+    }
 
-    return fdt_setprop_string(fdt, offset, property, string);
+    g_free(dupname);
+    return retval;
 }
index f05c4e7311375a443e2802e6c56ee7845ac7bc72..4378685b7a9ce3f658a7eeaa4cbad9058fbf33c7 100644 (file)
 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,
                                 const char *property, const char *string);
+int qemu_devtree_nop_node(void *fdt, const char *node_path);
+int qemu_devtree_add_subnode(void *fdt, const char *name);
 
 #endif /* __DEVICE_TREE_H__ */
index 296537ad3a06a8c84185ba9aceaa733f168f0733..4f15fad4faee8d27b916288811a47996ddbd9b08 100644 (file)
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -184,6 +184,9 @@ enum bfd_architecture
 #define bfd_mach_sh5        0x50
   bfd_arch_alpha,      /* Dec Alpha */
 #define bfd_mach_alpha 1
+#define bfd_mach_alpha_ev4  0x10
+#define bfd_mach_alpha_ev5  0x20
+#define bfd_mach_alpha_ev6  0x30
   bfd_arch_arm,        /* Advanced Risc Machines ARM */
 #define bfd_mach_arm_unknown   0
 #define bfd_mach_arm_2         1
@@ -362,6 +365,7 @@ typedef struct disassemble_info {
    target address.  Return number of bytes processed.  */
 typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
 
+int print_insn_tci(bfd_vma, disassemble_info*);
 int print_insn_big_mips         (bfd_vma, disassemble_info*);
 int print_insn_little_mips      (bfd_vma, disassemble_info*);
 int print_insn_i386             (bfd_vma, disassemble_info*);
diff --git a/disas.c b/disas.c
index c76f36f590a1e77fe82b2184b1f6d5db718b9b64..3b1fd977a8ef80833eb916fdf75dea8f0cb19c96 100644 (file)
--- a/disas.c
+++ b/disas.c
@@ -5,7 +5,6 @@
 #include <errno.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 
 /* Filled in by elfload.c.  Simplistic, but will do for now. */
@@ -138,7 +137,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
 
 /* Disassemble this for me please... (debugging). 'flags' has the following
    values:
-    i386 - nonzero means 16 bit code
+    i386 - 1 means 16 bit code, 2 means 64 bit code
     arm  - nonzero means thumb code
     ppc  - nonzero means little endian
     other targets - unused
@@ -205,7 +204,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
     disasm_info.mach = bfd_mach_sh4;
     print_insn = print_insn_sh;
 #elif defined(TARGET_ALPHA)
-    disasm_info.mach = bfd_mach_alpha;
+    disasm_info.mach = bfd_mach_alpha_ev6;
     print_insn = print_insn_alpha;
 #elif defined(TARGET_CRIS)
     if (flags != 32) {
@@ -215,6 +214,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;
@@ -271,7 +273,9 @@ void disas(FILE *out, void *code, unsigned long size)
 #else
     disasm_info.endian = BFD_ENDIAN_LITTLE;
 #endif
-#if defined(__i386__)
+#if defined(CONFIG_TCG_INTERPRETER)
+    print_insn = print_insn_tci;
+#elif defined(__i386__)
     disasm_info.mach = bfd_mach_i386_i386;
     print_insn = print_insn_i386;
 #elif defined(__x86_64__)
@@ -342,7 +346,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 +418,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);
index 712ed897f307e7d160d084fffc3631174a63fbf8..bdcd38cd271d4a4af0fb531da7cdbbaacb0019c9 100644 (file)
 
 void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
 {
-    qsg->sg = qemu_malloc(alloc_hint * sizeof(ScatterGatherEntry));
+    qsg->sg = g_malloc(alloc_hint * sizeof(ScatterGatherEntry));
     qsg->nsg = 0;
     qsg->nalloc = alloc_hint;
     qsg->size = 0;
 }
 
-void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
-                     target_phys_addr_t len)
+void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
 {
     if (qsg->nsg == qsg->nalloc) {
         qsg->nalloc = 2 * qsg->nalloc + 1;
-        qsg->sg = qemu_realloc(qsg->sg, qsg->nalloc * sizeof(ScatterGatherEntry));
+        qsg->sg = g_realloc(qsg->sg, qsg->nalloc * sizeof(ScatterGatherEntry));
     }
     qsg->sg[qsg->nsg].base = base;
     qsg->sg[qsg->nsg].len = len;
@@ -33,7 +32,7 @@ void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
 
 void qemu_sglist_destroy(QEMUSGList *qsg)
 {
-    qemu_free(qsg->sg);
+    g_free(qsg->sg);
 }
 
 typedef struct {
@@ -42,11 +41,13 @@ typedef struct {
     BlockDriverAIOCB *acb;
     QEMUSGList *sg;
     uint64_t sector_num;
-    int is_write;
+    bool to_dev;
+    bool in_cancel;
     int sg_cur_index;
-    target_phys_addr_t sg_cur_byte;
+    dma_addr_t sg_cur_byte;
     QEMUIOVector iov;
     QEMUBH *bh;
+    DMAIOFunc *io_func;
 } DMAAIOCB;
 
 static void dma_bdrv_cb(void *opaque, int ret);
@@ -57,7 +58,7 @@ static void reschedule_dma(void *opaque)
 
     qemu_bh_delete(dbs->bh);
     dbs->bh = NULL;
-    dma_bdrv_cb(opaque, 0);
+    dma_bdrv_cb(dbs, 0);
 }
 
 static void continue_after_map_failure(void *opaque)
@@ -74,9 +75,29 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
 
     for (i = 0; i < dbs->iov.niov; ++i) {
         cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
-                                  dbs->iov.iov[i].iov_len, !dbs->is_write,
+                                  dbs->iov.iov[i].iov_len, !dbs->to_dev,
                                   dbs->iov.iov[i].iov_len);
     }
+    qemu_iovec_reset(&dbs->iov);
+}
+
+static void dma_complete(DMAAIOCB *dbs, int ret)
+{
+    dma_bdrv_unmap(dbs);
+    if (dbs->common.cb) {
+        dbs->common.cb(dbs->common.opaque, ret);
+    }
+    qemu_iovec_destroy(&dbs->iov);
+    if (dbs->bh) {
+        qemu_bh_delete(dbs->bh);
+        dbs->bh = NULL;
+    }
+    if (!dbs->in_cancel) {
+        /* Requests may complete while dma_aio_cancel is in progress.  In
+         * this case, the AIOCB should not be released because it is still
+         * referenced by dma_aio_cancel.  */
+        qemu_aio_release(dbs);
+    }
 }
 
 static void dma_bdrv_cb(void *opaque, int ret)
@@ -88,19 +109,16 @@ static void dma_bdrv_cb(void *opaque, int ret)
     dbs->acb = NULL;
     dbs->sector_num += dbs->iov.size / 512;
     dma_bdrv_unmap(dbs);
-    qemu_iovec_reset(&dbs->iov);
 
     if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
-        dbs->common.cb(dbs->common.opaque, ret);
-        qemu_iovec_destroy(&dbs->iov);
-        qemu_aio_release(dbs);
+        dma_complete(dbs, ret);
         return;
     }
 
     while (dbs->sg_cur_index < dbs->sg->nsg) {
         cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
         cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
-        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
+        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->to_dev);
         if (!mem)
             break;
         qemu_iovec_add(&dbs->iov, mem, cur_len);
@@ -116,17 +134,10 @@ static void dma_bdrv_cb(void *opaque, int ret)
         return;
     }
 
-    if (dbs->is_write) {
-        dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov,
-                                   dbs->iov.size / 512, dma_bdrv_cb, dbs);
-    } else {
-        dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov,
-                                  dbs->iov.size / 512, dma_bdrv_cb, dbs);
-    }
+    dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
+                            dbs->iov.size / 512, dma_bdrv_cb, dbs);
     if (!dbs->acb) {
-        dma_bdrv_unmap(dbs);
-        qemu_iovec_destroy(&dbs->iov);
-        return;
+        dma_complete(dbs, -EIO);
     }
 }
 
@@ -135,8 +146,14 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
     DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
 
     if (dbs->acb) {
-        bdrv_aio_cancel(dbs->acb);
+        BlockDriverAIOCB *acb = dbs->acb;
+        dbs->acb = NULL;
+        dbs->in_cancel = true;
+        bdrv_aio_cancel(acb);
+        dbs->in_cancel = false;
     }
+    dbs->common.cb = NULL;
+    dma_complete(dbs, 0);
 }
 
 static AIOPool dma_aio_pool = {
@@ -144,12 +161,12 @@ static AIOPool dma_aio_pool = {
     .cancel             = dma_aio_cancel,
 };
 
-static BlockDriverAIOCB *dma_bdrv_io(
+BlockDriverAIOCB *dma_bdrv_io(
     BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
-    BlockDriverCompletionFunc *cb, void *opaque,
-    int is_write)
+    DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+    void *opaque, bool to_dev)
 {
-    DMAAIOCB *dbs =  qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
+    DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
 
     dbs->acb = NULL;
     dbs->bs = bs;
@@ -157,14 +174,11 @@ static BlockDriverAIOCB *dma_bdrv_io(
     dbs->sector_num = sector_num;
     dbs->sg_cur_index = 0;
     dbs->sg_cur_byte = 0;
-    dbs->is_write = is_write;
+    dbs->to_dev = to_dev;
+    dbs->io_func = io_func;
     dbs->bh = NULL;
     qemu_iovec_init(&dbs->iov, sg->nsg);
     dma_bdrv_cb(dbs, 0);
-    if (!dbs->acb) {
-        qemu_aio_release(dbs);
-        return NULL;
-    }
     return &dbs->common;
 }
 
@@ -173,12 +187,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
                                 QEMUSGList *sg, uint64_t sector,
                                 void (*cb)(void *opaque, int ret), void *opaque)
 {
-    return dma_bdrv_io(bs, sg, sector, cb, opaque, 0);
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, false);
 }
 
 BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
                                  QEMUSGList *sg, uint64_t sector,
                                  void (*cb)(void *opaque, int ret), void *opaque)
 {
-    return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true);
 }
diff --git a/dma.h b/dma.h
index f3bb27515952455b9ba29640c44340419c044502..a13209d7eb55531d7801acc32dbaa6f5e1d5420a 100644 (file)
--- a/dma.h
+++ b/dma.h
 #include "hw/hw.h"
 #include "block.h"
 
-typedef struct {
-    target_phys_addr_t base;
-    target_phys_addr_t len;
-} ScatterGatherEntry;
+typedef struct ScatterGatherEntry ScatterGatherEntry;
 
-typedef struct {
+#if defined(TARGET_PHYS_ADDR_BITS)
+typedef target_phys_addr_t dma_addr_t;
+
+#define DMA_ADDR_FMT TARGET_FMT_plx
+
+typedef enum {
+    DMA_DIRECTION_TO_DEVICE = 0,
+    DMA_DIRECTION_FROM_DEVICE = 1,
+} DMADirection;
+
+struct ScatterGatherEntry {
+    dma_addr_t base;
+    dma_addr_t len;
+};
+
+struct QEMUSGList {
     ScatterGatherEntry *sg;
     int nsg;
     int nalloc;
-    target_phys_addr_t size;
-} QEMUSGList;
+    dma_addr_t size;
+};
 
 void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
-void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
-                     target_phys_addr_t len);
+void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
 void qemu_sglist_destroy(QEMUSGList *qsg);
+#endif
+
+typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *iov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
 
+BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
+                              QEMUSGList *sg, uint64_t sector_num,
+                              DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+                              void *opaque, bool to_dev);
 BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
                                 QEMUSGList *sg, uint64_t sector,
                                 BlockDriverCompletionFunc *cb, void *opaque);
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/ich9-ehci-uhci.cfg b/docs/ich9-ehci-uhci.cfg
new file mode 100644 (file)
index 0000000..a0e9b96
--- /dev/null
@@ -0,0 +1,37 @@
+###########################################################################
+#
+# You can pass this file directly to qemu using the -readconfig
+# command line switch.
+#
+# This config file creates a EHCI adapter with companion UHCI
+# controllers as multifunction device in PCI slot "1d".
+#
+# Specify "bus=ehci.0" when creating usb devices to hook them up
+# there.
+#
+
+[device "ehci"]
+  driver = "ich9-usb-ehci1"
+  addr = "1d.7"
+  multifunction = "on"
+
+[device "uhci-1"]
+  driver = "ich9-usb-uhci1"
+  addr = "1d.0"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "0"
+
+[device "uhci-2"]
+  driver = "ich9-usb-uhci2"
+  addr = "1d.1"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "2"
+
+[device "uhci-3"]
+  driver = "ich9-usb-uhci3"
+  addr = "1d.2"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "4"
diff --git a/docs/libcacard.txt b/docs/libcacard.txt
new file mode 100644 (file)
index 0000000..f7d7519
--- /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 represent 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 corresponding 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 messaging 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.
+Responses 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 solely one 2 byte status code. If that status
+    code is defined in card_7816t.h, then this function is guaranteed 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
+    guaranteed 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 remaining 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 virtual 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 similar
+  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.
diff --git a/docs/memory.txt b/docs/memory.txt
new file mode 100644 (file)
index 0000000..3fc1683
--- /dev/null
@@ -0,0 +1,172 @@
+The memory API
+==============
+
+The memory API models the memory and I/O buses and controllers of a QEMU
+machine.  It attempts to allow modelling of:
+
+ - ordinary RAM
+ - memory-mapped I/O (MMIO)
+ - memory controllers that can dynamically reroute physical memory regions
+  to different destinations
+
+The memory model provides support for
+
+ - tracking RAM changes by the guest
+ - setting up coalesced memory for kvm
+ - setting up ioeventfd regions for kvm
+
+Memory is modelled as a tree (really acyclic graph) of MemoryRegion objects.
+The root of the tree is memory as seen from the CPU's viewpoint (the system
+bus).  Nodes in the tree represent other buses, memory controllers, and
+memory regions that have been rerouted.  Leaves are RAM and MMIO regions.
+
+Types of regions
+----------------
+
+There are four types of memory regions (all represented by a single C type
+MemoryRegion):
+
+- RAM: a RAM region is simply a range of host memory that can be made available
+  to the guest.
+
+- MMIO: a range of guest memory that is implemented by host callbacks;
+  each read or write causes a callback to be called on the host.
+
+- container: a container simply includes other memory regions, each at
+  a different offset.  Containers are useful for grouping several regions
+  into one unit.  For example, a PCI BAR may be composed of a RAM region
+  and an MMIO region.
+
+  A container's subregions are usually non-overlapping.  In some cases it is
+  useful to have overlapping regions; for example a memory controller that
+  can overlay a subregion of RAM with MMIO or ROM, or a PCI controller
+  that does not prevent card from claiming overlapping BARs.
+
+- alias: a subsection of another region.  Aliases allow a region to be
+  split apart into discontiguous regions.  Examples of uses are memory banks
+  used when the guest address space is smaller than the amount of RAM
+  addressed, or a memory controller that splits main memory to expose a "PCI
+  hole".  Aliases may point to any type of region, including other aliases,
+  but an alias may not point back to itself, directly or indirectly.
+
+
+Region names
+------------
+
+Regions are assigned names by the constructor.  For most regions these are
+only used for debugging purposes, but RAM regions also use the name to identify
+live migration sections.  This means that RAM region names need to have ABI
+stability.
+
+Region lifecycle
+----------------
+
+A region is created by one of the constructor functions (memory_region_init*())
+and destroyed by the destructor (memory_region_destroy()).  In between,
+a region can be added to an address space by using memory_region_add_subregion()
+and removed using memory_region_del_subregion().  Region attributes may be
+changed at any point; they take effect once the region becomes exposed to the
+guest.
+
+Overlapping regions and priority
+--------------------------------
+Usually, regions may not overlap each other; a memory address decodes into
+exactly one target.  In some cases it is useful to allow regions to overlap,
+and sometimes to control which of an overlapping regions is visible to the
+guest.  This is done with memory_region_add_subregion_overlap(), which
+allows the region to overlap any other region in the same container, and
+specifies a priority that allows the core to decide which of two regions at
+the same address are visible (highest wins).
+
+Visibility
+----------
+The memory core uses the following rules to select a memory region when the
+guest accesses an address:
+
+- all direct subregions of the root region are matched against the address, in
+  descending priority order
+  - if the address lies outside the region offset/size, the subregion is
+    discarded
+  - if the subregion is a leaf (RAM or MMIO), the search terminates
+  - if the subregion is a container, the same algorithm is used within the
+    subregion (after the address is adjusted by the subregion offset)
+  - if the subregion is an alias, the search is continues at the alias target
+    (after the address is adjusted by the subregion offset and alias offset)
+
+Example memory map
+------------------
+
+system_memory: container@0-2^48-1
+ |
+ +---- lomem: alias@0-0xdfffffff ---> #ram (0-0xdfffffff)
+ |
+ +---- himem: alias@0x100000000-0x11fffffff ---> #ram (0xe0000000-0xffffffff)
+ |
+ +---- vga-window: alias@0xa0000-0xbfffff ---> #pci (0xa0000-0xbffff)
+ |      (prio 1)
+ |
+ +---- pci-hole: alias@0xe0000000-0xffffffff ---> #pci (0xe0000000-0xffffffff)
+
+pci (0-2^32-1)
+ |
+ +--- vga-area: container@0xa0000-0xbffff
+ |      |
+ |      +--- alias@0x00000-0x7fff  ---> #vram (0x010000-0x017fff)
+ |      |
+ |      +--- alias@0x08000-0xffff  ---> #vram (0x020000-0x027fff)
+ |
+ +---- vram: ram@0xe1000000-0xe1ffffff
+ |
+ +---- vga-mmio: mmio@0xe2000000-0xe200ffff
+
+ram: ram@0x00000000-0xffffffff
+
+The is a (simplified) PC memory map. The 4GB RAM block is mapped into the
+system address space via two aliases: "lomem" is a 1:1 mapping of the first
+3.5GB; "himem" maps the last 0.5GB at address 4GB.  This leaves 0.5GB for the
+so-called PCI hole, that allows a 32-bit PCI bus to exist in a system with
+4GB of memory.
+
+The memory controller diverts addresses in the range 640K-768K to the PCI
+address space.  This is modelled using the "vga-window" alias, mapped at a
+higher priority so it obscures the RAM at the same addresses.  The vga window
+can be removed by programming the memory controller; this is modelled by
+removing the alias and exposing the RAM underneath.
+
+The pci address space is not a direct child of the system address space, since
+we only want parts of it to be visible (we accomplish this using aliases).
+It has two subregions: vga-area models the legacy vga window and is occupied
+by two 32K memory banks pointing at two sections of the framebuffer.
+In addition the vram is mapped as a BAR at address e1000000, and an additional
+BAR containing MMIO registers is mapped after it.
+
+Note that if the guest maps a BAR outside the PCI hole, it would not be
+visible as the pci-hole alias clips it to a 0.5GB range.
+
+Attributes
+----------
+
+Various region attributes (read-only, dirty logging, coalesced mmio, ioeventfd)
+can be changed during the region lifecycle.  They take effect once the region
+is made visible (which can be immediately, later, or never).
+
+MMIO Operations
+---------------
+
+MMIO regions are provided with ->read() and ->write() callbacks; in addition
+various constraints can be supplied to control how these callbacks are called:
+
+ - .valid.min_access_size, .valid.max_access_size define the access sizes
+   (in bytes) which the device accepts; accesses outside this range will
+   have device and bus specific behaviour (ignored, or machine check)
+ - .valid.aligned specifies that the device only accepts naturally aligned
+   accesses.  Unaligned accesses invoke device and bus specific behaviour.
+ - .impl.min_access_size, .impl.max_access_size define the access sizes
+   (in bytes) supported by the *implementation*; other access sizes will be
+   emulated using the ones available.  For example a 4-byte write will be
+   emulated using four 1-byte write, if .impl.max_access_size = 1.
+ - .impl.valid specifies that the *implementation* only supports unaligned
+   accesses; unaligned accesses will be emulated by two aligned accesses.
+ - .old_portio and .old_mmio can be used to ease porting from code using
+   cpu_register_io_memory() and register_ioport().  They should not be used
+   in new code.
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
new file mode 100644 (file)
index 0000000..5831e37
--- /dev/null
@@ -0,0 +1,316 @@
+= How to use the QAPI code generator =
+
+* Note: as of this writing, QMP does not use QAPI. Eventually QMP
+commands will be converted to use QAPI internally. The following
+information describes QMP/QAPI as it will exist after the
+conversion.
+
+QAPI is a native C API within QEMU which provides management-level
+functionality to internal/external users. For external
+users/processes, this interface is made available by a JSON-based
+QEMU Monitor protocol that is provided by the QMP server.
+
+To map QMP-defined interfaces to the native C QAPI implementations,
+a JSON-based schema is used to define types and function
+signatures, and a set of scripts is used to generate types/signatures,
+and marshaling/dispatch code. The QEMU Guest Agent also uses these
+scripts, paired with a separate schema, to generate
+marshaling/dispatch code for the guest agent server running in the
+guest.
+
+This document will describe how the schemas, scripts, and resulting
+code is used.
+
+
+== QMP/Guest agent schema ==
+
+This file defines the types, commands, and events used by QMP.  It should
+fully describe the interface used by QMP.
+
+This file is designed to be loosely based on JSON although it's technically
+executable Python.  While dictionaries are used, they are parsed as
+OrderedDicts so that ordering is preserved.
+
+There are two basic syntaxes used, type definitions and command definitions.
+
+The first syntax defines a type and is represented by a dictionary.  There are
+two kinds of types that are supported: complex user-defined types, and enums.
+
+A complex type is a dictionary containing a single key who's value is a
+dictionary.  This corresponds to a struct in C or an Object in JSON.  An
+example of a complex type is:
+
+ { 'type': 'MyType',
+   'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
+
+The use of '*' as a prefix to the name means the member is optional.  Optional
+members should always be added to the end of the dictionary to preserve
+backwards compatibility.
+
+An enumeration type is a dictionary containing a single key who's value is a
+list of strings.  An example enumeration is:
+
+ { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
+
+Generally speaking, complex types and enums should always use CamelCase for
+the type names.
+
+Commands are defined by using a list containing three members.  The first
+member is the command name, the second member is a dictionary containing
+arguments, and the third member is the return type.
+
+An example command is:
+
+ { 'command': 'my-command',
+   'data': { 'arg1': 'str', '*arg2': 'str' },
+   'returns': 'str' }
+
+Command names should be all lower case with words separated by a hyphen.
+
+
+== Code generation ==
+
+Schemas are fed into 3 scripts to generate all the code/files that, paired
+with the core QAPI libraries, comprise everything required to take JSON
+commands read in by a QMP/guest agent server, unmarshal the arguments into
+the underlying C types, call into the corresponding C function, and map the
+response back to a QMP/guest agent response to be returned to the user.
+
+As an example, we'll use the following schema, which describes a single
+complex user-defined type (which will produce a C struct, along with a list
+node structure that can be used to chain together a list of such types in
+case we want to accept/return a list of this type with a command), and a
+command which takes that type as a parameter and returns the same type:
+
+    mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
+    { 'type': 'UserDefOne',
+      'data': { 'integer': 'int', 'string': 'str' } }
+
+    { 'command': 'my-command',
+      'data':    {'arg1': 'UserDefOne'},
+      'returns': 'UserDefOne' }
+    mdroth@illuin:~/w/qemu2.git$
+
+=== scripts/qapi-types.py ===
+
+Used to generate the C types defined by a schema. The following files are
+created:
+
+$(prefix)qapi-types.h - C types corresponding to types defined in
+                        the schema you pass in
+$(prefix)qapi-types.c - Cleanup functions for the above C types
+
+The $(prefix) is an optional parameter used as a namespace to keep the
+generated code from one schema/code-generation separated from others so code
+can be generated/used from multiple schemas without clobbering previously
+created code.
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
+      --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    void qapi_free_UserDefOne(UserDefOne * obj)
+    {
+        QapiDeallocVisitor *md;
+        Visitor *v;
+
+        if (!obj) {
+            return;
+        }
+
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &obj, NULL, NULL);
+        qapi_dealloc_visitor_cleanup(md);
+    }
+
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+    #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+
+    #include "qapi/qapi-types-core.h"
+
+    typedef struct UserDefOne UserDefOne;
+
+    typedef struct UserDefOneList
+    {
+        UserDefOne *value;
+        struct UserDefOneList *next;
+    } UserDefOneList;
+
+    struct UserDefOne
+    {
+        int64_t integer;
+        char * string;
+    };
+
+    void qapi_free_UserDefOne(UserDefOne * obj);
+
+    #endif
+
+
+=== scripts/qapi-visit.py ===
+
+Used to generate the visitor functions used to walk through and convert
+a QObject (as provided by QMP) to a native C data structure and
+vice-versa, as well as the visitor function used to dealloc a complex
+schema-defined C type.
+
+The following files are generated:
+
+$(prefix)qapi-visit.c: visitor function for a particular C type, used
+                       to automagically convert QObjects into the
+                       corresponding C type and vice-versa, as well
+                       as for deallocating memory for an existing C
+                       type
+
+$(prefix)qapi-visit.h: declarations for previously mentioned visitor
+                       functions
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
+        --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "example-qapi-visit.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
+    {
+        visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
+        visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
+        visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
+        visit_end_struct(m, errp);
+    }
+
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
+    {
+        GenericList *i;
+
+        visit_start_list(m, name, errp);
+
+        for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+            UserDefOneList *native_i = (UserDefOneList *)i;
+            visit_type_UserDefOne(m, &native_i->value, NULL, errp);
+        }
+
+        visit_end_list(m, errp);
+    }
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+    #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+
+    #include "qapi/qapi-visit-core.h"
+    #include "example-qapi-types.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
+
+    #endif
+    mdroth@illuin:~/w/qemu2.git$
+
+
+=== scripts/qapi-commands.py ===
+
+Used to generate the marshaling/dispatch functions for the commands defined
+in the schema. The following files are generated:
+
+$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
+                        QMP command defined in the schema. Functions
+                        generated by qapi-visit.py are used to
+                        convert QObjects received from the wire into
+                        function parameters, and uses the same
+                        visitor functions to convert native C return
+                        values to QObjects from transmission back
+                        over the wire.
+
+$(prefix)qmp-commands.h: Function prototypes for the QMP commands
+                         specified in the schema.
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qemu-objects.h"
+    #include "qapi/qmp-core.h"
+    #include "qapi/qapi-visit-core.h"
+    #include "qapi/qmp-output-visitor.h"
+    #include "qapi/qmp-input-visitor.h"
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    #include "example-qmp-commands.h"
+    static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
+    {
+        QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+        QmpOutputVisitor *mo = qmp_output_visitor_new();
+        Visitor *v;
+
+        v = qmp_output_get_visitor(mo);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        qapi_dealloc_visitor_cleanup(md);
+
+
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+
+    static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+    {
+        UserDefOne * retval = NULL;
+        QmpInputVisitor *mi;
+        QapiDeallocVisitor *md;
+        Visitor *v;
+        UserDefOne * arg1 = NULL;
+
+        mi = qmp_input_visitor_new(QOBJECT(args));
+        v = qmp_input_get_visitor(mi);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+
+        if (error_is_set(errp)) {
+            goto out;
+        }
+        retval = qmp_my_command(arg1, errp);
+        qmp_marshal_output_my_command(retval, ret, errp);
+
+    out:
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        qapi_dealloc_visitor_cleanup(md);
+        return;
+    }
+
+    static void qmp_init_marshal(void)
+    {
+        qmp_register_command("my-command", qmp_marshal_input_my_command);
+    }
+
+    qapi_init(qmp_init_marshal);
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+    #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+
+    #include "example-qapi-types.h"
+    #include "error.h"
+
+    UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
+
+    #endif
+    mdroth@illuin:~/w/qemu2.git$
index 4bb2be885056cd6095cd0d0beb3de93c9f1c8e30..136d2711203f4385a381b9dcb81ea6b61ef02dee 100644 (file)
@@ -8,20 +8,23 @@ more buses for children.  You can specify a device's parent bus with
 
 A device typically has a device address on its parent bus.  For buses
 where this address can be configured, devices provide a bus-specific
-property.  These are
-
-    bus     property name       value format
-    PCI     addr                %x.%x (dev.fn, .fn optional)
-    I2C     address             %u
-    SCSI    scsi-id             %u
+property.  Examples:
+
+    bus         property name       value format
+    PCI         addr                %x.%x    (dev.fn, .fn optional)
+    I2C         address             %u
+    SCSI        scsi-id             %u
+    IDE         unit                %u
+    HDA         cad                 %u
+    virtio-serial-bus  nr           %u
+    ccid-bus    slot                %u
+    USB         port                %d(.%d)*    (port.port...)
 
 Example: device i440FX-pcihost is on the root bus, and provides a PCI
 bus named pci.0.  To put a FOO device into its slot 4, use -device
 FOO,bus=/i440FX-pcihost/pci.0,addr=4.  The abbreviated form bus=pci.0
 also works as long as the bus name is unique.
 
-Note: the USB device address can't be controlled at this time.
-
 === Block Devices ===
 
 A QEMU block device (drive) has a host and a guest part.
@@ -44,28 +47,43 @@ The new way keeps the parts separate: you create the host part with
 
 The various old ways to define drives all boil down to the common form
 
-    -drive if=TYPE,index=IDX,bus=BUS,unit=UNIT,HOST-OPTS...
+    -drive if=TYPE,bus=BUS,unit=UNIT,OPTS...
 
 TYPE, BUS and UNIT identify the controller device, which of its buses
 to use, and the drive's address on that bus.  Details depend on TYPE.
-IDX is an alternative way to specify BUS and UNIT.
+
+Instead of bus=BUS,unit=UNIT, you can also say index=IDX.
 
 In the new way, this becomes something like
 
    -drive if=none,id=DRIVE-ID,HOST-OPTS...
    -device DEVNAME,drive=DRIVE-ID,DEV-OPTS...
 
-The -device argument differs in detail for each kind of drive:
+The old OPTS get split into HOST-OPTS and DEV-OPTS as follows:
 
-* if=ide
+* file, format, snapshot, cache, aio, readonly, rerror, werror go into
+  HOST-OPTS.
+
+* cyls, head, secs and trans go into HOST-OPTS.  Future work: they
+  should go into DEV-OPTS instead.
+
+* serial goes into DEV-OPTS, for devices supporting serial numbers.
+  For other devices, it goes nowhere.
 
-  -device ide-drive,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+* media is special.  In the old way, it selects disk vs. CD-ROM with
+  if=ide, if=scsi and if=xen.  The new way uses DEVNAME for that.
+  Additionally, readonly=on goes into HOST-OPTS.
 
-  where IDE-BUS identifies an IDE bus, normally either ide.0 or ide.1,
-  and UNIT is either 0 or 1.
+* addr is special, see if=virtio below.
 
-  Bug: new way does not work for ide.1 unit 0 (in old terms: index=2)
-  unless you disable the default CD-ROM with -nodefaults.
+The -device argument differs in detail for each type of drive:
+
+* if=ide
+
+  -device DEVNAME,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+
+  where DEVNAME is either ide-hd or ide-cd, IDE-BUS identifies an IDE
+  bus, normally either ide.0 or ide.1, and UNIT is either 0 or 1.
 
 * if=scsi
 
@@ -77,27 +95,25 @@ The -device argument differs in detail for each kind of drive:
   As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
   control the PCI device address.
 
-  This SCSI controller a single SCSI bus, named ID.0.  Put a disk on
-  it:
+  This SCSI controller provides a single SCSI bus, named ID.0.  Put a
+  disk on it:
 
-  -device scsi-disk,drive=DRIVE-ID,bus=ID.0,scsi-id=SCSI-ID,removable=RMB
+  -device DEVNAME,drive=DRIVE-ID,bus=ID.0,scsi-id=UNIT
 
-  The (optional) removable parameter lets you override the SCSI INQUIRY
-  removable (RMB) bit for non CD-ROM devices.  It is ignored for CD-ROM devices
-  which are always removable.  RMB is "on" or "off".
+  where DEVNAME is either scsi-hd, scsi-cd or scsi-generic.
 
 * if=floppy
 
-  -global isa-fdc,driveA=DRIVE-ID,driveB=DRIVE-ID
+  -global isa-fdc.driveA=DRIVE-ID
+  -global isa-fdc.driveB=DRIVE-ID
 
   This is -global instead of -device, because the floppy controller is
   created automatically, and we want to configure that one, not create
   a second one (which isn't possible anyway).
 
-  Omitting a drive parameter makes that drive empty.
-
-  Bug: driveA works only if you disable the default floppy drive with
-  -nodefaults.
+  Without any -global isa-fdc,... you get an empty driveA and no
+  driveB.  You can use -nodefaults to suppress the default driveA, see
+  "Default Devices".
 
 * if=virtio
 
@@ -105,11 +121,12 @@ The -device argument differs in detail for each kind of drive:
 
   This lets you control PCI device class and MSI-X vectors.
 
-  IOEVENTFD controls whether or not ioeventfd is used for virtqueue notify.  It
-  can be set to on (default) or off.
+  IOEVENTFD controls whether or not ioeventfd is used for virtqueue
+  notify.  It can be set to on (default) or off.
 
   As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
-  control the PCI device address.
+  control the PCI device address.  This replaces option addr available
+  with -drive if=virtio.
 
 * if=pflash, if=mtd, if=sd, if=xen are not yet available with -device
 
@@ -117,15 +134,20 @@ For USB devices, the old way is actually different:
 
     -usbdevice disk:format=FMT:FILENAME
 
-Provides much less control than -drive's HOST-OPTS...  The new way
-fixes that:
+Provides much less control than -drive's OPTS...  The new way fixes
+that:
 
     -device usb-storage,drive=DRIVE-ID,removable=RMB
 
-The removable parameter gives control over the SCSI INQUIRY removable (RMB)
-bit.  USB thumbdrives usually set removable=on, while USB hard disks set
-removable=off.  See the if=scsi description above for details on the removable
-parameter, which applies only to scsi-disk devices and not to scsi-generic.
+The removable parameter gives control over the SCSI INQUIRY removable
+(RMB) bit.  USB thumbdrives usually set removable=on, while USB hard
+disks set removable=off.
+
+Bug: usb-storage pretends to be a block device, but it's really a SCSI
+controller that can serve only a single device, which it creates
+automatically.  The automatic creation guesses what kind of guest part
+to create from the host part, like -drive if=scsi.  Host and guest
+part are not cleanly separated.
 
 === Character Devices ===
 
@@ -170,7 +192,9 @@ The appropriate DEVNAME depends on the machine type.  For type "pc":
   -device usb-braille,chardev=braille,vendorid=VID,productid=PRID
   -chardev braille,id=braille
 
-* -virtioconsole is still being worked on
+* -virtioconsole becomes
+  -device virtio-serial-pci,class=C,vectors=V,ioeventfd=IOEVENTFD,max_ports=N
+  -device virtconsole,is_console=NUM,nr=NR,name=NAME
 
 LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
 
@@ -184,7 +208,7 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
 
 * con: becomes -chardev console
 
-* COM<NUM> becomes -chardev serial,path=<NUM>
+* COM<NUM> becomes -chardev serial,path=COM<NUM>
 
 * file:FNAME becomes -chardev file,path=FNAME
 
@@ -219,38 +243,29 @@ LEGACY-CHARDEV to refer to a host part defined with -chardev.
 
 === Network Devices ===
 
-A QEMU network device (NIC) has a host and a guest part.
+Host and guest part of network devices have always been separate.
 
-The old ways to define NICs define host and guest part together.  It
-looks like this:
+The old way to define the guest part looks like this:
 
-    -net nic,vlan=VLAN,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
+    -net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
 
 Except for USB it looks like this:
 
-    -usbdevice net:vlan=VLAN,macaddr=MACADDR,name=ID,addr=STR,vectors=V
+    -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID
 
-The new way keeps the parts separate: you create the host part with
--netdev, and the guest device with -device, like this:
+The new way is -device:
 
-    -netdev type=TYPE,id=NET-ID
     -device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS...
 
-Unlike the old way, this creates just a network device, not a VLAN.
-If you really want a VLAN, create it the usual way, then create the
-guest device like this:
-
-    -device DEVNAME,vlan=VLAN,mac=MACADDR,DEV-OPTS...
-
 DEVNAME equals MODEL, except for virtio you have to name the virtio
 device appropriate for the bus (virtio-net-pci for PCI), and for USB
-NIC you have to use usb-net.
+you have to use usb-net.
 
 The old name=ID parameter becomes the usual id=ID with -device.
 
 For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
 device address, as usual.  The old -net nic provides parameter addr
-for that, it is silently ignored when the NIC is not a PCI device.
+for that, which is silently ignored when the NIC is not a PCI device.
 
 For virtio-net-pci, you can control whether or not ioeventfd is used for
 virtqueue notify by setting ioeventfd= to on or off (default).
@@ -264,20 +279,25 @@ devices and ne2k_isa are.
 
 Some PCI devices aren't available with -net nic, e.g. i82558a.
 
-Bug: usb-net does not work, yet.  Patch posted.
+To connect to a VLAN instead of an ordinary host part, replace
+netdev=NET-ID by vlan=VLAN.
 
 === Graphics Devices ===
 
 Host and guest part of graphics devices have always been separate.
 
-The old way to define the guest graphics device is -vga VGA.
+The old way to define the guest graphics device is -vga VGA.  Not all
+machines support all -vga options.
 
-The new way is -device.  Map from -vga argument to -device:
+The new way is -device.  The mapping from -vga argument to -device
+depends on the machine type.  For machine "pc", it's:
 
     std         -device VGA
     cirrus      -device cirrus-vga
     vmware      -device vmware-svga
-    xenfb       not yet available with -device
+    qxl         -device qxl-vga
+    none        -nodefaults
+                disables more than just VGA, see "Default Devices"
 
 As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control
 the PCI device address.
@@ -285,13 +305,16 @@ the PCI device address.
 -device VGA supports properties bios-offset and bios-size, but they
 aren't used with machine type "pc".
 
-Bug: -device cirrus-vga and -device vmware-svga require -nodefaults.
+For machine "isapc", it's
 
-Bug: the new way requires PCI; ISA VGA is not yet available with
--device.
+    std         -device isa-vga
+    cirrus      not yet available with -device
+    none        -nodefaults
+                disables more than just VGA, see "Default Devices"
 
-Bug: the new way doesn't work for machine type "pc", because it
-violates obscure device initialization ordering constraints.
+Bug: the new way doesn't work for machine types "pc" and "isapc",
+because it violates obscure device initialization ordering
+constraints.
 
 === Audio Devices ===
 
@@ -308,6 +331,7 @@ Map from -soundhw sound card name to -device:
     cs4231a     -device cs4231a,iobase=IOADDR,irq=IRQ,dma=DMA
     es1370      -device ES1370
     gus         -device gus,iobase=IOADDR,irq=IRQ,dma=DMA,freq=F
+    hda         -device intel-hda,msi=MSI -device hda-duplex
     sb16        -device sb16,iobase=IOADDR,irq=IRQ,dma=DMA,dma16=DMA16,version=V
     adlib       not yet available with -device
     pcspk       not yet available with -device
@@ -321,9 +345,10 @@ The old way to define a virtual USB device is -usbdevice DRIVER:OPTS...
 
 The new way is -device DEVNAME,DEV-OPTS...  Details depend on DRIVER:
 
+* ccid            -device usb-ccid
+* keyboard        -device usb-kbd
 * mouse           -device usb-mouse
 * tablet          -device usb-tablet
-* keyboard        -device usb-kdb
 * wacom-tablet    -device usb-wacom-tablet
 * host:...        See "Host Device Assignment"
 * disk:...        See "Block Devices"
@@ -353,7 +378,7 @@ The new way is
 
     -device pci-assign,host=ADDR,iommu=IOMMU,id=ID
 
-The old dma=none becomes iommu=0 with -device.
+The old dma=none becomes iommu=off with -device.
 
 The old way to assign a host USB device is
 
@@ -365,4 +390,27 @@ The new way is
 
     -device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID
 
-where left out or zero BUS, ADDR, VID, PRID serve as wildcard.
+Omitted options match anything, just like the old way's wildcard.
+
+=== Default Devices ===
+
+QEMU creates a number of devices by default, depending on the machine
+type.
+
+-device DEVNAME... and global DEVNAME... suppress default devices for
+some DEVNAMEs:
+
+    default device      suppressing DEVNAMEs
+    CD-ROM              ide-cd, ide-drive, scsi-cd
+    isa-fdc's driveA    isa-fdc
+    parallel            isa-parallel
+    serial              isa-serial
+    VGA                 VGA, cirrus-vga, vmware-svga
+    virtioconsole       virtio-serial-pci, virtio-serial-s390, virtio-serial
+
+The default NIC is connected to a default part created along with it.
+It is *not* suppressed by configuring a NIC with -device (you may call
+that a bug).  -net and -netdev suppress the default NIC.
+
+-nodefaults suppresses all the default devices mentioned above, plus a
+few other things such as default SD-Card drive and default monitor.
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
new file mode 100644 (file)
index 0000000..e792953
--- /dev/null
@@ -0,0 +1,260 @@
+== General ==
+
+A qcow2 image file is organized in units of constant size, which are called
+(host) clusters. A cluster is the unit in which all allocations are done,
+both for actual guest data and for image metadata.
+
+Likewise, the virtual disk as seen by the guest is divided into (guest)
+clusters of the same size.
+
+All numbers in qcow2 are stored in Big Endian byte order.
+
+
+== Header ==
+
+The first cluster of a qcow2 image contains the file header:
+
+    Byte  0 -  3:   magic
+                    QCOW magic string ("QFI\xfb")
+
+          4 -  7:   version
+                    Version number (only valid value is 2)
+
+          8 - 15:   backing_file_offset
+                    Offset into the image file at which the backing file name
+                    is stored (NB: The string is not null terminated). 0 if the
+                    image doesn't have a backing file.
+
+         16 - 19:   backing_file_size
+                    Length of the backing file name in bytes. Must not be
+                    longer than 1023 bytes. Undefined if the image doesn't have
+                    a backing file.
+
+         20 - 23:   cluster_bits
+                    Number of bits that are used for addressing an offset
+                    within a cluster (1 << cluster_bits is the cluster size).
+                    Must not be less than 9 (i.e. 512 byte clusters).
+
+                    Note: qemu as of today has an implementation limit of 2 MB
+                    as the maximum cluster size and won't be able to open images
+                    with larger cluster sizes.
+
+         24 - 31:   size
+                    Virtual disk size in bytes
+
+         32 - 35:   crypt_method
+                    0 for no encryption
+                    1 for AES encryption
+
+         36 - 39:   l1_size
+                    Number of entries in the active L1 table
+
+         40 - 47:   l1_table_offset
+                    Offset into the image file at which the active L1 table
+                    starts. Must be aligned to a cluster boundary.
+
+         48 - 55:   refcount_table_offset
+                    Offset into the image file at which the refcount table
+                    starts. Must be aligned to a cluster boundary.
+
+         56 - 59:   refcount_table_clusters
+                    Number of clusters that the refcount table occupies
+
+         60 - 63:   nb_snapshots
+                    Number of snapshots contained in the image
+
+         64 - 71:   snapshots_offset
+                    Offset into the image file at which the snapshot table
+                    starts. Must be aligned to a cluster boundary.
+
+Directly after the image header, optional sections called header extensions can
+be stored. Each extension has a structure like the following:
+
+    Byte  0 -  3:   Header extension type:
+                        0x00000000 - End of the header extension area
+                        0xE2792ACA - Backing file format name
+                        other      - Unknown header extension, can be safely
+                                     ignored
+
+          4 -  7:   Length of the header extension data
+
+          8 -  n:   Header extension data
+
+          n -  m:   Padding to round up the header extension size to the next
+                    multiple of 8.
+
+The remaining space between the end of the header extension area and the end of
+the first cluster can be used for other data. Usually, the backing file name is
+stored there.
+
+
+== Host cluster management ==
+
+qcow2 manages the allocation of host clusters by maintaining a reference count
+for each host cluster. A refcount of 0 means that the cluster is free, 1 means
+that it is used, and >= 2 means that it is used and any write access must
+perform a COW (copy on write) operation.
+
+The refcounts are managed in a two-level table. The first level is called
+refcount table and has a variable size (which is stored in the header). The
+refcount table can cover multiple clusters, however it needs to be contiguous
+in the image file.
+
+It contains pointers to the second level structures which are called refcount
+blocks and are exactly one cluster in size.
+
+Given a offset into the image file, the refcount of its cluster can be obtained
+as follows:
+
+    refcount_block_entries = (cluster_size / sizeof(uint16_t))
+
+    refcount_block_index = (offset / cluster_size) % refcount_block_entries
+    refcount_table_index = (offset / cluster_size) / refcount_block_entries
+
+    refcount_block = load_cluster(refcount_table[refcount_table_index]);
+    return refcount_block[refcount_block_index];
+
+Refcount table entry:
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 63:    Bits 9-63 of the offset into the image file at which the
+                    refcount block starts. Must be aligned to a cluster
+                    boundary.
+
+                    If this is 0, the corresponding refcount block has not yet
+                    been allocated. All refcounts managed by this refcount block
+                    are 0.
+
+Refcount block entry:
+
+    Bit  0 - 15:    Reference count of the cluster
+
+
+== Cluster mapping ==
+
+Just as for refcounts, qcow2 uses a two-level structure for the mapping of
+guest clusters to host clusters. They are called L1 and L2 table.
+
+The L1 table has a variable size (stored in the header) and may use multiple
+clusters, however it must be contiguous in the image file. L2 tables are
+exactly one cluster in size.
+
+Given a offset into the virtual disk, the offset into the image file can be
+obtained as follows:
+
+    l2_entries = (cluster_size / sizeof(uint64_t))
+
+    l2_index = (offset / cluster_size) % l2_entries
+    l1_index = (offset / cluster_size) / l2_entries
+
+    l2_table = load_cluster(l1_table[l1_index]);
+    cluster_offset = l2_table[l2_index];
+
+    return cluster_offset + (offset % cluster_size)
+
+L1 table entry:
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 55:    Bits 9-55 of the offset into the image file at which the L2
+                    table starts. Must be aligned to a cluster boundary. If the
+                    offset is 0, the L2 table and all clusters described by this
+                    L2 table are unallocated.
+
+        56 - 62:    Reserved (set to 0)
+
+             63:    0 for an L2 table that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in the active L1 table.
+
+L2 table entry (for normal clusters):
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 55:    Bits 9-55 of host cluster offset. Must be aligned to a
+                    cluster boundary. If the offset is 0, the cluster is
+                    unallocated.
+
+        56 - 61:    Reserved (set to 0)
+
+             62:    0 (this cluster is not compressed)
+
+             63:    0 for a cluster that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in L2 tables that are reachable from the the active L1
+                    table.
+
+L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
+
+    Bit  0 -  x:    Host cluster offset. This is usually _not_ aligned to a
+                    cluster boundary!
+
+       x+1 - 61:    Compressed size of the images in sectors of 512 bytes
+
+             62:    1 (this cluster is compressed using zlib)
+
+             63:    0 for a cluster that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in L2 tables that are reachable from the the active L1
+                    table.
+
+If a cluster is unallocated, read requests shall read the data from the backing
+file. If there is no backing file or the backing file is smaller than the image,
+they shall read zeros for all parts that are not covered by the backing file.
+
+
+== Snapshots ==
+
+qcow2 supports internal snapshots. Their basic principle of operation is to
+switch the active L1 table, so that a different set of host clusters are
+exposed to the guest.
+
+When creating a snapshot, the L1 table should be copied and the refcount of all
+L2 tables and clusters reachable from this L1 table must be increased, so that
+a write causes a COW and isn't visible in other snapshots.
+
+When loading a snapshot, bit 63 of all entries in the new active L1 table and
+all L2 tables referenced by it must be reconstructed from the refcount table
+as it doesn't need to be accurate in inactive L1 tables.
+
+A directory of all snapshots is stored in the snapshot table, a contiguous area
+in the image file, whose starting offset and length are given by the header
+fields snapshots_offset and nb_snapshots. The entries of the snapshot table
+have variable length, depending on the length of ID, name and extra data.
+
+Snapshot table entry:
+
+    Byte 0 -  7:    Offset into the image file at which the L1 table for the
+                    snapshot starts. Must be aligned to a cluster boundary.
+
+         8 - 11:    Number of entries in the L1 table of the snapshots
+
+        12 - 13:    Length of the unique ID string describing the snapshot
+
+        14 - 15:    Length of the name of the snapshot
+
+        16 - 19:    Time at which the snapshot was taken in seconds since the
+                    Epoch
+
+        20 - 23:    Subsecond part of the time at which the snapshot was taken
+                    in nanoseconds
+
+        24 - 31:    Time that the guest was running until the snapshot was
+                    taken in nanoseconds
+
+        32 - 35:    Size of the VM state in bytes. 0 if no VM state is saved.
+                    If there is VM state, it starts at the first cluster
+                    described by first L1 table entry that doesn't describe a
+                    regular guest cluster (i.e. VM state is stored like guest
+                    disk content, except that it is stored at offsets that are
+                    larger than the virtual disk presented to the guest)
+
+        36 - 39:    Size of extra data in the table entry (used for future
+                    extensions of the format)
+
+        variable:   Extra data for future extensions. Must be ignored.
+
+        variable:   Unique ID string for the snapshot (not null terminated)
+
+        variable:   Name of the snapshot (not null terminated)
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 21183f9a6869dafbd7b66974f06cd65cc8e8df62..ea29f2c222396d2e52574202117ab0452b99ec78 100644 (file)
@@ -12,13 +12,14 @@ for debugging, profiling, and observing execution.
     ./configure --trace-backend=simple
     make
 
-2. Enable trace events you are interested in:
+2. Create a file with the events you want to trace:
 
-    $EDITOR trace-events  # remove "disable" from events you want
+   echo bdrv_aio_readv   > /tmp/events
+   echo bdrv_aio_writev >> /tmp/events
 
 3. Run the virtual machine to produce a trace file:
 
-    qemu ... # your normal QEMU invocation
+    qemu -trace events=/tmp/events ... # your normal QEMU invocation
 
 4. Pretty-print the binary trace file:
 
@@ -26,36 +27,38 @@ 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"
+    qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
+    qemu_vfree(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:
 
     #include "trace.h"  /* needed for trace event prototype */
-
-    void *qemu_malloc(size_t size)
+    
+    void *qemu_vmalloc(size_t size)
     {
         void *ptr;
-        if (!size && !allow_zero_malloc()) {
-            abort();
+        size_t align = QEMU_VMALLOC_ALIGN;
+     
+        if (size < align) {
+            align = getpagesize();
         }
-        ptr = oom_check(malloc(size ? size : 1));
-        trace_qemu_malloc(size, ptr);  /* <-- trace event */
+        ptr = qemu_memalign(align, size);
+        trace_qemu_vmalloc(size, ptr);
         return ptr;
     }
 
 === 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:
 
@@ -74,10 +77,7 @@ Trace events should use types as follows:
 
 Format strings should reflect the types defined in the trace event.  Take
 special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
-respectively.  This ensures portability between 32- and 64-bit platforms.  Note
-that format strings must begin and end with double quotes.  When using
-portability macros, ensure they are preceded and followed by double quotes:
-"value %"PRIx64"".
+respectively.  This ensures portability between 32- and 64-bit platforms.
 
 === Hints for adding new trace events ===
 
@@ -98,17 +98,59 @@ portability macros, ensure they are preceded and followed by double quotes:
 4. Name trace events after their function.  If there are multiple trace events
    in one function, append a unique distinguisher at the end of the name.
 
-5. Declare trace events with the "disable" keyword.  Some trace events can
-   produce a lot of output and users are typically only interested in a subset
-   of trace events.  Marking trace events disabled by default saves the user
-   from having to manually disable noisy trace events.
+5. If specific trace events are going to be called a huge number of times, this
+   might have a noticeable performance impact even when the trace events are
+   programmatically disabled. In this case you should declare the trace event
+   with the "disable" property, which will effectively disable it at compile
+   time (using the "nop" backend).
+
+== Generic interface and monitor commands ==
+
+You can programmatically query and control the dynamic state of trace events
+through a backend-agnostic interface:
+
+* trace_print_events
+
+* trace_event_set_state
+  Enables or disables trace events at runtime inside QEMU.
+  The function returns "true" if the state of the event has been successfully
+  changed, or "false" otherwise:
+
+    #include "trace/control.h"
+    
+    trace_event_set_state("virtio_irq", true); /* enable */
+    [...]
+    trace_event_set_state("virtio_irq", false); /* disable */
+
+Note that some of the backends do not provide an implementation for this
+interface, in which case QEMU will just print a warning.
+
+This functionality is also provided through monitor commands:
+
+* info trace-events
+  View available trace events and their state.  State 1 means enabled, state 0
+  means disabled.
+
+* trace-event NAME on|off
+  Enable/disable a given trace event or a group of events having common prefix
+  through wildcard.
+
+The "-trace events=<file>" command line argument can be used to enable the
+events listed in <file> from the very beginning of the program. This file must
+contain one event name per line.
+
+A basic wildcard matching is supported in both the monitor command "trace
+-event" and the events list file. That means you can enable/disable the events
+having a common prefix in a batch. For example, virtio-blk trace events could
+be enabled using:
+  trace-event virtio_blk_* on
 
 == 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
@@ -126,6 +168,17 @@ The "nop" backend generates empty trace event functions so that the compiler
 can optimize out trace events completely.  This is the default and imposes no
 performance penalty.
 
+Note that regardless of the selected trace backend, events with the "disable"
+property will be generated with the "nop" backend.
+
+=== Stderr ===
+
+The "stderr" backend sends trace events directly to standard error.  This
+effectively turns trace events into debug printfs.
+
+This is the simplest backend and can be used together with existing code that
+uses DPRINTF().
+
 === Simpletrace ===
 
 The "simple" backend supports common use cases and comes as part of the QEMU
@@ -133,10 +186,8 @@ source tree.  It may not be as powerful as platform-specific or third-party
 trace backends but it is portable.  This is the recommended trace backend
 unless you have specific needs for more advanced backends.
 
-=== Stderr ===
-
-The "stderr" backend sends trace events directly to standard error output
-during emulation.
+The "simple" backend currently does not capture string arguments, it simply
+records the char* pointer value instead of the string that is pointed to.
 
 ==== Monitor commands ====
 
@@ -149,36 +200,18 @@ during emulation.
   flushed and emptied.  This means the 'info trace' will display few or no
   entries if the buffer has just been flushed.
 
-* info trace-events
-  View available trace events and their state.  State 1 means enabled, state 0
-  means disabled.
-
-* trace-event NAME on|off
-  Enable/disable a given trace event.
-
 * trace-file on|off|flush|set <path>
   Enable/disable/flush the trace file or set the trace file name.
 
-==== Enabling/disabling trace events programmatically ====
-
-The st_change_trace_event_state() function can be used to enable or disable trace
-events at runtime inside QEMU:
-
-    #include "trace.h"
-    
-    st_change_trace_event_state("virtio_irq", true); /* enable */
-    [...]
-    st_change_trace_event_state("virtio_irq", false); /* disable */
-
 ==== 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.
 
@@ -187,3 +220,17 @@ consistent.
 The "ust" backend uses the LTTng Userspace Tracer library.  There are no
 monitor commands built into QEMU, instead UST utilities should be used to list,
 enable/disable, and dump traces.
+
+=== SystemTap ===
+
+The "dtrace" backend uses DTrace sdt probes but has only been tested with
+SystemTap.  When SystemTap support is detected a .stp file with wrapper probes
+is generated to make use in scripts more convenient.  This step can also be
+performed manually after a build in order to change the binary name in the .stp
+probes:
+
+    scripts/tracetool --dtrace --stap \
+                      --binary path/to/qemu-binary \
+                      --target-type system \
+                      --target-arch x86_64 \
+                      <trace-events >qemu.stp
diff --git a/docs/usb2.txt b/docs/usb2.txt
new file mode 100644 (file)
index 0000000..228aa33
--- /dev/null
@@ -0,0 +1,146 @@
+
+USB 2.0 Quick Start
+===================
+
+The QEMU EHCI Adapter can be used with and without companion
+controllers.  See below for the companion controller mode.
+
+When not running in companion controller mode there are two completely
+separate USB busses: One USB 1.1 bus driven by the UHCI controller and
+one USB 2.0 bus driven by the EHCI controller.  Devices must be
+attached to the correct controller manually.
+
+The '-usb' switch will make qemu create the UHCI controller as part of
+the PIIX3 chipset.  The USB 1.1 bus will carry the name "usb.0".
+
+You can use the standard -device switch to add a EHCI controller to
+your virtual machine.  It is strongly recommended to specify an ID for
+the controller so the USB 2.0 bus gets a individual name, for example
+'-device usb-ehci,id=ehci".  This will give you a USB 2.0 bus named
+"ehci.0".
+
+I strongly recomment to also use -device to attach usb devices because
+you can specify the bus they should be attached to this way.  Here is
+a complete example:
+
+    qemu -M pc ${otheroptions}                           \
+        -drive if=none,id=usbstick,file=/path/to/image   \
+        -usb                                             \
+        -device usb-ehci,id=ehci                         \
+        -device usb-tablet,bus=usb.0                     \
+        -device usb-storage,bus=ehci.0,drive=usbstick
+
+This attaches a usb tablet to the UHCI adapter and a usb mass storage
+device to the EHCI adapter.
+
+
+Companion controller support
+----------------------------
+
+Companion controller support has been added recently.  The operational
+model described above with two completely separate busses still works
+fine.  Additionally the UHCI and OHCI controllers got the ability to
+attach to a usb bus created by EHCI as companion controllers.  This is
+done by specifying the masterbus and firstport properties.  masterbus
+specifies the bus name the controller should attach to.  firstport
+specifies the first port the controller should attach to, which is
+needed as usually one ehci controller with six ports has three uhci
+companion controllers with two ports each.
+
+There is a config file in docs which will do all this for you, just
+try ...
+
+    qemu -readconfig docs/ich9-ehci-uhci.cfg
+
+... then use "bus=ehci.0" to assign your usb devices to that bus.
+
+
+More USB tips & tricks
+======================
+
+Recently the usb pass through driver (also known as usb-host) and the
+qemu usb subsystem gained a few capabilities which are available only
+via qdev properties, i,e. when using '-device'.
+
+
+physical port addressing
+------------------------
+
+First you can (for all usb devices) specify the physical port where
+the device will show up in the guest.  This can be done using the
+"port" property.  UHCI has two root ports (1,2).  EHCI has four root
+ports (1-4), the emulated (1.1) USB hub has eight ports.
+
+Plugging a tablet into UHCI port 1 works like this:
+
+        -device usb-tablet,bus=usb.0,port=1
+
+Plugging a hub into UHCI port 2 works like this:
+
+        -device usb-hub,bus=usb.0,port=2
+
+Plugging a virtual usb stick into port 4 of the hub just plugged works
+this way:
+
+        -device usb-storage,bus=usb.0,port=2.4,drive=...
+
+You can do basically the same in the monitor using the device_add
+command.  If you want to unplug devices too you should specify some
+unique id which you can use to refer to the device ...
+
+        (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+        (qemu) device_del my-tablet
+
+... when unplugging it with device_del.
+
+
+USB pass through hints
+----------------------
+
+The usb-host driver has a bunch of properties to specify the device
+which should be passed to the guest:
+
+  hostbus=<nr> -- Specifies the bus number the device must be attached
+  to.
+
+  hostaddr=<nr> -- Specifies the device address the device got
+  assigned by the guest os.
+
+  hostport=<str> -- Specifies the physical port the device is attached
+  to.
+
+  vendorid=<hexnr> -- Specifies the vendor ID of the device.
+  productid=<hexnr> -- Specifies the product ID of the device.
+
+In theory you can combine all these properties as you like.  In
+practice only a few combinations are useful:
+
+  (1) vendorid+productid -- match for a specific device, pass it to
+      the guest when it shows up somewhere in the host.
+
+  (2) hostbus+hostport -- match for a specific physical port in the
+      host, any device which is plugged in there gets passed to the
+      guest.
+
+  (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
+      hostaddr isn't stable, the next time you plug in the device it
+      gets a new one ...
+
+Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
+EHCI.  That means a device plugged into the very same physical port
+may show up on different busses depending on the speed.  The port I'm
+using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
+for 1.1 devices.  Passing through any device plugged into that port
+and also assign them to the correct bus can be done this way:
+
+    qemu -M pc ${otheroptions}                           \
+        -usb                                             \
+        -device usb-ehci,id=ehci                         \
+        -device usb-host,bus=usb.0,hostbus=3,hostport=1  \
+        -device usb-host,bus=ehci.0,hostbus=1,hostport=1
+
+enjoy,
+  Gerd
+
+--
+Gerd Hoffmann <kraxel@redhat.com>
index db00fbae04e20eec0c9bdd84700d5eff336dd2cc..3544372a65a408e117ccd55a4fcf42c57a8a36b1 100644 (file)
 #if !defined(__DYNGEN_EXEC_H__)
 #define __DYNGEN_EXEC_H__
 
-#include "qemu-common.h"
-
-#ifdef __OpenBSD__
-#include <sys/types.h>
-#endif
-
-/* XXX: This may be wrong for 64-bit ILP32 hosts.  */
-typedef void * host_reg_t;
-
-#if defined(__i386__)
+#if defined(CONFIG_TCG_INTERPRETER)
+/* The TCG interpreter does not need a special register AREG0,
+ * but it is possible to use one by defining AREG0.
+ * On i386, register edi seems to work. */
+/* Run without special register AREG0 or use a value defined elsewhere. */
+#elif defined(__i386__)
 #define AREG0 "ebp"
 #elif defined(__x86_64__)
 #define AREG0 "r14"
@@ -64,21 +60,11 @@ typedef void * host_reg_t;
 #error unsupported CPU
 #endif
 
-#define xglue(x, y) x ## y
-#define glue(x, y) xglue(x, y)
-#define stringify(s)   tostring(s)
-#define tostring(s)    #s
-
-/* The return address may point to the start of the next instruction.
-   Subtracting one gets us the call instruction itself.  */
-#if defined(__s390__) && !defined(__s390x__)
-# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
-#elif defined(__arm__)
-/* Thumb return addresses have the low bit set, so we need to subtract two.
-   This is still safe in ARM mode because instructions are 4 bytes.  */
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
+#if defined(AREG0)
+register CPUState *env asm(AREG0);
 #else
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
+/* TODO: Try env = cpu_single_env. */
+extern CPUState *env;
 #endif
 
 #endif /* !defined(__DYNGEN_EXEC_H__) */
diff --git a/elf.h b/elf.h
index 7067c90fb09549a8c36fcefdeb156cadc866e7a0..2e05d34620fa1fe2cc86292a24884389f3e76835 100644 (file)
--- a/elf.h
+++ b/elf.h
@@ -104,6 +104,9 @@ typedef int64_t  Elf64_Sxword;
 
 #define EM_H8_300H      47      /* Hitachi H8/300H */
 #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
@@ -122,6 +125,8 @@ typedef int64_t  Elf64_Sxword;
 #define EM_MICROBLAZE      189
 #define EM_MICROBLAZE_OLD  0xBAAB
 
+#define EM_XTENSA   94      /* Tensilica Xtensa */
+
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL                0
 #define DT_NEEDED      1
@@ -1191,6 +1196,25 @@ typedef struct elf64_note {
   Elf64_Word n_type;   /* Content type */
 } Elf64_Nhdr;
 
+
+/* This data structure represents a PT_LOAD segment.  */
+struct elf32_fdpic_loadseg {
+  /* Core address to which the segment is mapped.  */
+  Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  Elf32_Word p_memsz;
+};
+struct elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  Elf32_Half version;
+  /* Number of segments in this map.  */
+  Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
 #ifdef ELF_CLASS
 #if ELF_CLASS == ELFCLASS32
 
diff --git a/error.c b/error.c
new file mode 100644 (file)
index 0000000..990050f
--- /dev/null
+++ b/error.c
@@ -0,0 +1,146 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "error.h"
+#include "qjson.h"
+#include "qdict.h"
+#include "error_int.h"
+#include "qerror.h"
+
+struct Error
+{
+    QDict *obj;
+    const char *fmt;
+    char *msg;
+};
+
+void error_set(Error **errp, const char *fmt, ...)
+{
+    Error *err;
+    va_list ap;
+
+    if (errp == NULL) {
+        return;
+    }
+
+    err = g_malloc0(sizeof(*err));
+
+    va_start(ap, fmt);
+    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+    va_end(ap);
+    err->fmt = fmt;
+
+    *errp = err;
+}
+
+bool error_is_set(Error **errp)
+{
+    return (errp && *errp);
+}
+
+const char *error_get_pretty(Error *err)
+{
+    if (err->msg == NULL) {
+        QString *str;
+        str = qerror_format(err->fmt, err->obj);
+        err->msg = g_strdup(qstring_get_str(str));
+        QDECREF(str);
+    }
+
+    return err->msg;
+}
+
+const char *error_get_field(Error *err, const char *field)
+{
+    if (strcmp(field, "class") == 0) {
+        return qdict_get_str(err->obj, field);
+    } else {
+        QDict *dict = qdict_get_qdict(err->obj, "data");
+        return qdict_get_str(dict, field);
+    }
+}
+
+QDict *error_get_data(Error *err)
+{
+    QDict *data = qdict_get_qdict(err->obj, "data");
+    QINCREF(data);
+    return data;
+}
+
+void error_set_field(Error *err, const char *field, const char *value)
+{
+    QDict *dict = qdict_get_qdict(err->obj, "data");
+    return qdict_put(dict, field, qstring_from_str(value));
+}
+
+void error_free(Error *err)
+{
+    if (err) {
+        QDECREF(err->obj);
+        g_free(err->msg);
+        g_free(err);
+    }
+}
+
+bool error_is_type(Error *err, const char *fmt)
+{
+    const char *error_class;
+    char *ptr;
+    char *end;
+
+    if (!err) {
+        return false;
+    }
+
+    ptr = strstr(fmt, "'class': '");
+    assert(ptr != NULL);
+    ptr += strlen("'class': '");
+
+    end = strchr(ptr, '\'');
+    assert(end != NULL);
+
+    error_class = error_get_field(err, "class");
+    if (strlen(error_class) != end - ptr) {
+        return false;
+    }
+
+    return strncmp(ptr, error_class, end - ptr) == 0;
+}
+
+void error_propagate(Error **dst_err, Error *local_err)
+{
+    if (dst_err) {
+        *dst_err = local_err;
+    } else if (local_err) {
+        error_free(local_err);
+    }
+}
+
+QObject *error_get_qobject(Error *err)
+{
+    QINCREF(err->obj);
+    return QOBJECT(err->obj);
+}
+
+void error_set_qobject(Error **errp, QObject *obj)
+{
+    Error *err;
+    if (errp == NULL) {
+        return;
+    }
+    err = g_malloc0(sizeof(*err));
+    err->obj = qobject_to_qdict(obj);
+    qobject_incref(obj);
+
+    *errp = err;
+}
diff --git a/error.h b/error.h
new file mode 100644 (file)
index 0000000..6361f40
--- /dev/null
+++ b/error.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include "compiler.h"
+#include <stdbool.h>
+
+/**
+ * A class representing internal errors within QEMU.  An error has a string
+ * typename and optionally a set of named string parameters.
+ */
+typedef struct Error Error;
+
+/**
+ * Set an indirect pointer to an error given a printf-style format parameter.
+ * Currently, qerror.h defines these error formats.  This function is not
+ * meant to be used outside of QEMU.
+ */
+void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+/**
+ * Returns true if an indirect pointer to an error is pointing to a valid
+ * error object.
+ */
+bool error_is_set(Error **err);
+
+/**
+ * Get a human readable representation of an error object.
+ */
+const char *error_get_pretty(Error *err);
+
+/**
+ * Get an individual named error field.
+ */
+const char *error_get_field(Error *err, const char *field);
+
+/**
+ * Get an individual named error field.
+ */
+void error_set_field(Error *err, const char *field, const char *value);
+
+/**
+ * Propagate an error to an indirect pointer to an error.  This function will
+ * always transfer ownership of the error reference and handles the case where
+ * dst_err is NULL correctly.
+ */
+void error_propagate(Error **dst_err, Error *local_err);
+
+/**
+ * Free an error object.
+ */
+void error_free(Error *err);
+
+/**
+ * Determine if an error is of a speific type (based on the qerror format).
+ * Non-QEMU users should get the `class' field to identify the error type.
+ */
+bool error_is_type(Error *err, const char *fmt);
+
+#endif
diff --git a/error_int.h b/error_int.h
new file mode 100644 (file)
index 0000000..5e39424
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QEMU_ERROR_INT_H
+#define QEMU_ERROR_INT_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+/**
+ * Internal QEMU functions for working with Error.
+ *
+ * These are used to convert QErrors to Errors
+ */
+QDict *error_get_data(Error *err);
+QObject *error_get_qobject(Error *err);
+void error_set_qobject(Error **errp, QObject *obj);
+  
+#endif
diff --git a/event_notifier.c b/event_notifier.c
new file mode 100644 (file)
index 0000000..2c73555
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * event notifier support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "event_notifier.h"
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+int event_notifier_init(EventNotifier *e, int active)
+{
+#ifdef CONFIG_EVENTFD
+    int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
+    if (fd < 0)
+        return -errno;
+    e->fd = fd;
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+void event_notifier_cleanup(EventNotifier *e)
+{
+    close(e->fd);
+}
+
+int event_notifier_get_fd(EventNotifier *e)
+{
+    return e->fd;
+}
+
+int event_notifier_test_and_clear(EventNotifier *e)
+{
+    uint64_t value;
+    int r = read(e->fd, &value, sizeof(value));
+    return r == sizeof(value);
+}
+
+int event_notifier_test(EventNotifier *e)
+{
+    uint64_t value;
+    int r = read(e->fd, &value, sizeof(value));
+    if (r == sizeof(value)) {
+        /* restore previous value. */
+        int s = write(e->fd, &value, sizeof(value));
+        /* never blocks because we use EFD_SEMAPHORE.
+         * If we didn't we'd get EAGAIN on overflow
+         * and we'd have to write code to ignore it. */
+        assert(s == sizeof(value));
+    }
+    return r == sizeof(value);
+}
diff --git a/event_notifier.h b/event_notifier.h
new file mode 100644 (file)
index 0000000..24117ea
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef QEMU_EVENT_NOTIFIER_H
+#define QEMU_EVENT_NOTIFIER_H
+
+#include "qemu-common.h"
+
+struct EventNotifier {
+       int fd;
+};
+
+int event_notifier_init(EventNotifier *, int active);
+void event_notifier_cleanup(EventNotifier *);
+int event_notifier_get_fd(EventNotifier *);
+int event_notifier_test_and_clear(EventNotifier *);
+int event_notifier_test(EventNotifier *);
+
+#endif
index 8871d9a164e0d3abf665badfb61ce6573cb3d929..3819bef12a6b651239c6eb33701c27fc8d0237e6 100644 (file)
@@ -40,10 +40,11 @@ typedef ram_addr_t tb_page_addr_t;
 #define DISAS_UPDATE  2 /* cpu state was modified dynamically */
 #define DISAS_TB_JUMP 3 /* only pc was modified statically */
 
+struct TranslationBlock;
 typedef struct TranslationBlock TranslationBlock;
 
 /* XXX: make safe guess about sizes */
-#define MAX_OP_PER_INSTR 96
+#define MAX_OP_PER_INSTR 208
 
 #if HOST_LONG_BITS == 32
 #define MAX_OPC_PARAM_PER_ARG 2
@@ -77,26 +78,24 @@ 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,
                               target_ulong pc, target_ulong cs_base, int flags,
                               int cflags);
 void cpu_exec_init(CPUState *env);
-void QEMU_NORETURN cpu_loop_exit(void);
+void QEMU_NORETURN cpu_loop_exit(CPUState *env1);
 int page_unprotect(target_ulong address, unsigned long pc, void *puc);
 void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
                                    int is_cpu_write_access);
-void tb_invalidate_page_range(target_ulong start, target_ulong end);
 void tlb_flush_page(CPUState *env, target_ulong addr);
 void tlb_flush(CPUState *env, int flush_global);
 #if !defined(CONFIG_USER_ONLY)
@@ -123,6 +122,8 @@ void tlb_set_page(CPUState *env, target_ulong vaddr,
 
 #if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__)
 #define USE_DIRECT_JUMP
+#elif defined(CONFIG_TCG_INTERPRETER)
+#define USE_DIRECT_JUMP
 #endif
 
 struct TranslationBlock {
@@ -158,9 +159,6 @@ struct TranslationBlock {
     struct TranslationBlock *jmp_next[2];
     struct TranslationBlock *jmp_first;
     uint32_t icount;
-#ifdef CONFIG_EXEC_PROFILE
-    uint32_t tbexec_count[2];
-#endif
 };
 
 static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
@@ -183,7 +181,6 @@ static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)
     return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1);
 }
 
-TranslationBlock *tb_alloc(target_ulong pc);
 void tb_free(TranslationBlock *tb);
 void tb_flush(CPUState *env);
 void tb_link_page(TranslationBlock *tb,
@@ -194,7 +191,14 @@ extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
 
 #if defined(USE_DIRECT_JUMP)
 
-#if defined(_ARCH_PPC)
+#if defined(CONFIG_TCG_INTERPRETER)
+static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
+{
+    /* patch the branch destination */
+    *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
+    /* no need to flush icache explicitly */
+}
+#elif defined(_ARCH_PPC)
 void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
 #define tb_set_jmp_target1 ppc_tb_set_jmp_target
 #elif defined(__i386__) || defined(__x86_64__)
@@ -228,6 +232,8 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
 #endif
 }
+#else
+#error tb_set_jmp_target1 is missing
 #endif
 
 static inline void tb_set_jmp_target(TranslationBlock *tb,
@@ -272,13 +278,32 @@ extern spinlock_t tb_lock;
 
 extern int tb_invalidated_flag;
 
+/* The return address may point to the start of the next instruction.
+   Subtracting one gets us the call instruction itself.  */
+#if defined(CONFIG_TCG_INTERPRETER)
+/* Alpha and SH4 user mode emulations and Softmmu call GETPC().
+   For all others, GETPC remains undefined (which makes TCI a little faster. */
+# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4)
+extern void *tci_tb_ptr;
+#  define GETPC() tci_tb_ptr
+# endif
+#elif defined(__s390__) && !defined(__s390x__)
+# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+#elif defined(__arm__)
+/* Thumb return addresses have the low bit set, so we need to subtract two.
+   This is still safe in ARM mode because instructions are 4 bytes.  */
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
+#else
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 
 extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
               void *retaddr);
 
 #include "softmmu_defs.h"
@@ -327,19 +352,20 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
     }
     pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
     if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
-#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
-        do_unassigned_access(addr, 0, 1, 0, 4);
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
+        cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
 #else
         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
 #endif
     }
-    p = (void *)(unsigned long)addr
-        + env1->tlb_table[mmu_idx][page_index].addend;
+    p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
     return qemu_ram_addr_from_host_nofail(p);
 }
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT)
-/* extended versions of MMU helpers for x86 TCG target optimization */
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
+/* Extended versions of MMU helpers for qemu_ld/st optimization.
+   They get return address arguments because the caller PCs are not where helpers return to. */
+#if defined(__i386__) || defined(__x86_64__)
 uint8_t REGPARM __ldextb_mmu(target_ulong addr, int mmu_idx, void *ra);
 void REGPARM __stextb_mmu(target_ulong addr, uint8_t val, int mmu_idx, void *ra);
 uint16_t REGPARM __ldextw_mmu(target_ulong addr, int mmu_idx, void *ra);
@@ -348,7 +374,9 @@ uint32_t REGPARM __ldextl_mmu(target_ulong addr, int mmu_idx, void *ra);
 void REGPARM __stextl_mmu(target_ulong addr, uint32_t val, int mmu_idx, void *ra);
 uint64_t REGPARM __ldextq_mmu(target_ulong addr, int mmu_idx, void *ra);
 void REGPARM __stextq_mmu(target_ulong addr, uint64_t val, int mmu_idx, void *ra);
-#endif  /* CONFIG_TCG_TARGET_X86_OPT */
+#endif
+#endif  /* CONFIG_QEMU_LDST_OPTIMIZATION */
+
 #endif
 
 typedef void (CPUDebugExcpHandler)(CPUState *env);
@@ -361,4 +389,18 @@ extern int singlestep;
 /* cpu-exec.c */
 extern volatile sig_atomic_t exit_request;
 
+/* Deterministic execution requires that IO only be performed on the last
+   instruction of a TB so that interrupts take effect immediately.  */
+static inline int can_do_io(CPUState *env)
+{
+    if (!use_icount) {
+        return 1;
+    }
+    /* If not executing code then assume we are ok.  */
+    if (!env->current_tb) {
+        return 1;
+    }
+    return env->can_do_io != 0;
+}
+
 #endif
diff --git a/exec-memory.h b/exec-memory.h
new file mode 100644 (file)
index 0000000..334219f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Internal memory managment interfaces
+ *
+ * Copyright 2011 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Avi Kivity <avi@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef EXEC_MEMORY_H
+#define EXEC_MEMORY_H
+
+/*
+ * Internal interfaces between memory.c/exec.c/vl.c.  Do not #include unless
+ * you're one of them.
+ */
+
+#include "memory.h"
+
+#ifndef CONFIG_USER_ONLY
+
+/* Get the root memory region.  This interface should only be used temporarily
+ * until a proper bus interface is available.
+ */
+MemoryRegion *get_system_memory(void);
+
+/* Get the root I/O port region.  This interface should only be used
+ * temporarily until a proper bus interface is available.
+ */
+MemoryRegion *get_system_io(void);
+
+/* Set the root memory region.  This region is the system memory map. */
+void set_system_memory_map(MemoryRegion *mr);
+
+/* Set the I/O memory region.  This region is the I/O memory map. */
+void set_system_io_map(MemoryRegion *mr);
+
+#endif
+
+#endif
diff --git a/exec.c b/exec.c
index e950df25c32a1f7fbef9415d4971f5bf7bcfdcb6..a027be96b5bc4eda6e50c7c80b2b14e50fdc664c 100644 (file)
--- a/exec.c
+++ b/exec.c
 
 #include "qemu-common.h"
 #include "cpu.h"
-#include "exec-all.h"
 #include "tcg.h"
 #include "hw/hw.h"
 #include "hw/qdev.h"
 #include "osdep.h"
 #include "kvm.h"
+#include "hax.h"
+#include "hw/xen.h"
 #include "qemu-timer.h"
+#include "memory.h"
+#include "exec-memory.h"
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
-#include <signal.h>
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <sys/param.h>
 #if __FreeBSD_version >= 700104
@@ -51,6 +53,9 @@
 #include <libutil.h>
 #endif
 #endif
+#else /* !CONFIG_USER_ONLY */
+#include "xen-mapcache.h"
+#include "trace.h"
 #endif
 
 //#define DEBUG_TB_INVALIDATE
@@ -106,20 +111,21 @@ static uint8_t *code_gen_ptr;
 int phys_ram_fd;
 static int in_migration;
 
-RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) };
+
+static MemoryRegion *system_memory;
+static MemoryRegion *system_io;
+
 #endif
 
 CPUState *first_cpu;
 /* current CPU in the current thread. It is only valid inside
    cpu_exec() */
-CPUState *cpu_single_env;
+DEFINE_TLS(CPUState *,cpu_single_env);
 /* 0 = Do not count executed instructions.
    1 = Precise instruction counting.
    2 = Adaptive rate instruction counting.  */
 int use_icount = 0;
-/* Current instruction counter.  While executing translated code this may
-   include some instructions that have not yet been executed.  */
-int64_t qemu_icount;
 
 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
@@ -175,7 +181,6 @@ typedef struct PageDesc {
 #define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
 
 unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_bits;
 unsigned long qemu_host_page_size;
 unsigned long qemu_host_page_mask;
 
@@ -195,6 +200,7 @@ typedef struct PhysPageDesc {
 static void *l1_phys_map[P_L1_SIZE];
 
 static void io_mem_init(void);
+static void memory_map_init(void);
 
 /* io memory support */
 CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
@@ -265,9 +271,6 @@ static void page_init(void)
         qemu_host_page_size = qemu_real_host_page_size;
     if (qemu_host_page_size < TARGET_PAGE_SIZE)
         qemu_host_page_size = TARGET_PAGE_SIZE;
-    qemu_host_page_bits = 0;
-    while ((1 << qemu_host_page_bits) < qemu_host_page_size)
-        qemu_host_page_bits++;
     qemu_host_page_mask = ~(qemu_host_page_size - 1);
 
 #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
@@ -343,7 +346,7 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
     int i;
 
 #if defined(CONFIG_USER_ONLY)
-    /* We can't use qemu_malloc because it may recurse into a locked mutex. */
+    /* We can't use g_malloc because it may recurse into a locked mutex. */
 # define ALLOC(P, SIZE)                                 \
     do {                                                \
         P = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,    \
@@ -351,7 +354,7 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
     } while (0)
 #else
 # define ALLOC(P, SIZE) \
-    do { P = qemu_mallocz(SIZE); } while (0)
+    do { P = g_malloc0(SIZE); } while (0)
 #endif
 
     /* Level 1.  Always allocated.  */
@@ -408,7 +411,7 @@ static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
             if (!alloc) {
                 return NULL;
             }
-            *lp = p = qemu_mallocz(sizeof(void *) * L2_SIZE);
+            *lp = p = g_malloc0(sizeof(void *) * L2_SIZE);
         }
         lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1));
     }
@@ -421,7 +424,7 @@ static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
             return NULL;
         }
 
-        *lp = pd = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
+        *lp = pd = g_malloc(sizeof(PhysPageDesc) * L2_SIZE);
 
         for (i = 0; i < L2_SIZE; i++) {
             pd[i].phys_offset = IO_MEM_UNASSIGNED;
@@ -467,7 +470,6 @@ static void code_gen_alloc(unsigned long tb_size)
     code_gen_buffer_size = tb_size;
     if (code_gen_buffer_size == 0) {
 #if defined(CONFIG_USER_ONLY)
-        /* in user mode, phys_ram_size is not meaningful */
         code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
 #else
         /* XXX: needs adjustments */
@@ -518,7 +520,8 @@ static void code_gen_alloc(unsigned long tb_size)
         }
     }
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
-    || defined(__DragonFly__) || defined(__OpenBSD__)
+    || defined(__DragonFly__) || defined(__OpenBSD__) \
+    || defined(__NetBSD__)
     {
         int flags;
         void *addr = NULL;
@@ -548,29 +551,26 @@ static void code_gen_alloc(unsigned long tb_size)
         }
     }
 #else
-    code_gen_buffer = qemu_malloc(code_gen_buffer_size);
+    code_gen_buffer = g_malloc(code_gen_buffer_size);
     map_exec(code_gen_buffer, code_gen_buffer_size);
 #endif
 #endif /* !USE_STATIC_CODE_GEN_BUFFER */
     map_exec(code_gen_prologue, sizeof(code_gen_prologue));
-    code_gen_buffer_max_size = code_gen_buffer_size - 
-        (TCG_MAX_OP_SIZE * OPC_MAX_SIZE);
+    code_gen_buffer_max_size = code_gen_buffer_size -
+        (TCG_MAX_OP_SIZE * OPC_BUF_SIZE);
     code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
-    tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
+    tbs = g_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
 }
 
 /* Must be called before using the QEMU cpus. 'tb_size' is the size
    (in bytes) allocated to the translation buffer. Zero means default
    size. */
-void cpu_exec_init_all(unsigned long tb_size)
+void tcg_exec_init(unsigned long tb_size)
 {
     cpu_gen_init();
     code_gen_alloc(tb_size);
     code_gen_ptr = code_gen_buffer;
     page_init();
-#if !defined(CONFIG_USER_ONLY)
-    io_mem_init();
-#endif
 #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
     /* There's no guest base to take into account, so go ahead and
        initialize the prologue now.  */
@@ -578,6 +578,19 @@ void cpu_exec_init_all(unsigned long tb_size)
 #endif
 }
 
+bool tcg_enabled(void)
+{
+    return code_gen_buffer != NULL;
+}
+
+void cpu_exec_init_all(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+    memory_map_init();
+    io_mem_init();
+#endif
+}
+
 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
 
 static int cpu_common_post_load(void *opaque, int version_id)
@@ -638,6 +651,9 @@ void cpu_exec_init(CPUState *env)
     env->numa_node = 0;
     QTAILQ_INIT(&env->breakpoints);
     QTAILQ_INIT(&env->watchpoints);
+#ifndef CONFIG_USER_ONLY
+    env->thread_id = qemu_get_thread_id();
+#endif
     *penv = env;
 #if defined(CONFIG_USER_ONLY)
     cpu_list_unlock();
@@ -649,10 +665,36 @@ void cpu_exec_init(CPUState *env)
 #endif
 }
 
+/* Allocate a new translation block. Flush the translation buffer if
+   too many translation blocks or too much generated code. */
+static TranslationBlock *tb_alloc(target_ulong pc)
+{
+    TranslationBlock *tb;
+
+    if (nb_tbs >= code_gen_max_blocks ||
+        (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
+        return NULL;
+    tb = &tbs[nb_tbs++];
+    tb->pc = pc;
+    tb->cflags = 0;
+    return tb;
+}
+
+void tb_free(TranslationBlock *tb)
+{
+    /* In practice this is mostly used for single use temporary TB
+       Ignore the hard cases and just back up if this TB happens to
+       be the last one generated.  */
+    if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
+        code_gen_ptr = tb->tc_ptr;
+        nb_tbs--;
+    }
+}
+
 static inline void invalidate_page_bitmap(PageDesc *p)
 {
     if (p->code_bitmap) {
-        qemu_free(p->code_bitmap);
+        g_free(p->code_bitmap);
         p->code_bitmap = NULL;
     }
     p->code_write_count = 0;
@@ -912,7 +954,7 @@ static void build_page_bitmap(PageDesc *p)
     int n, tb_start, tb_end;
     TranslationBlock *tb;
 
-    p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
+    p->code_bitmap = g_malloc0(TARGET_PAGE_SIZE / 8);
 
     tb = p->first_tb;
     while (tb != NULL) {
@@ -1041,8 +1083,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);
             }
@@ -1150,7 +1191,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);
         }
@@ -1177,12 +1218,16 @@ static inline void tb_alloc_page(TranslationBlock *tb,
                                  unsigned int n, tb_page_addr_t page_addr)
 {
     PageDesc *p;
-    TranslationBlock *last_first_tb;
+#ifndef CONFIG_USER_ONLY
+    bool page_already_protected;
+#endif
 
     tb->page_addr[n] = page_addr;
     p = page_find_alloc(page_addr >> TARGET_PAGE_BITS, 1);
     tb->page_next[n] = p->first_tb;
-    last_first_tb = p->first_tb;
+#ifndef CONFIG_USER_ONLY
+    page_already_protected = p->first_tb != NULL;
+#endif
     p->first_tb = (TranslationBlock *)((long)tb | n);
     invalidate_page_bitmap(p);
 
@@ -1218,7 +1263,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
     /* if some code is already present, then the pages are already
        protected. So we handle the case where only the first TB is
        allocated in a physical page */
-    if (!last_first_tb) {
+    if (!page_already_protected) {
         tlb_protect_code(page_addr);
     }
 #endif
@@ -1226,32 +1271,6 @@ static inline void tb_alloc_page(TranslationBlock *tb,
 #endif /* TARGET_HAS_SMC */
 }
 
-/* Allocate a new translation block. Flush the translation buffer if
-   too many translation blocks or too much generated code. */
-TranslationBlock *tb_alloc(target_ulong pc)
-{
-    TranslationBlock *tb;
-
-    if (nb_tbs >= code_gen_max_blocks ||
-        (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
-        return NULL;
-    tb = &tbs[nb_tbs++];
-    tb->pc = pc;
-    tb->cflags = 0;
-    return tb;
-}
-
-void tb_free(TranslationBlock *tb)
-{
-    /* In practice this is mostly used for single use temporary TB
-       Ignore the hard cases and just back up if this TB happens to
-       be the last one generated.  */
-    if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
-        code_gen_ptr = tb->tc_ptr;
-        nb_tbs--;
-    }
-}
-
 /* add a new TB and link it to the physical page tables. phys_page2 is
    (-1) to indicate that only one page contains the TB. */
 void tb_link_page(TranslationBlock *tb,
@@ -1422,7 +1441,7 @@ int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
                 TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
         return -EINVAL;
     }
-    wp = qemu_malloc(sizeof(*wp));
+    wp = g_malloc(sizeof(*wp));
 
     wp->vaddr = addr;
     wp->len_mask = len_mask;
@@ -1465,7 +1484,7 @@ void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
 
     tlb_flush_page(env, watchpoint->vaddr);
 
-    qemu_free(watchpoint);
+    g_free(watchpoint);
 }
 
 /* Remove all matching watchpoints.  */
@@ -1487,7 +1506,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
 #if defined(TARGET_HAS_ICE)
     CPUBreakpoint *bp;
 
-    bp = qemu_malloc(sizeof(*bp));
+    bp = g_malloc(sizeof(*bp));
 
     bp->pc = pc;
     bp->flags = flags;
@@ -1534,7 +1553,7 @@ void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
 
     breakpoint_invalidate(env, breakpoint->pc);
 
-    qemu_free(breakpoint);
+    g_free(breakpoint);
 #endif
 }
 
@@ -1627,38 +1646,46 @@ 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.
      */
-    if (!qemu_cpu_self(env)) {
+    if (!qemu_cpu_is_self(env)) {
         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;
@@ -1708,11 +1735,12 @@ static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
 
 static void cpu_notify_set_memory(target_phys_addr_t start_addr,
                                   ram_addr_t size,
-                                  ram_addr_t phys_offset)
+                                  ram_addr_t phys_offset,
+                                  bool log_dirty)
 {
     CPUPhysMemoryClient *client;
     QLIST_FOREACH(client, &memory_client_list, list) {
-        client->set_memory(client, start_addr, size, phys_offset);
+        client->set_memory(client, start_addr, size, phys_offset, log_dirty);
     }
 }
 
@@ -1739,8 +1767,21 @@ static int cpu_notify_migration_log(int enable)
     return 0;
 }
 
-static void phys_page_for_each_1(CPUPhysMemoryClient *client,
-                                 int level, void **lp)
+struct last_map {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    ram_addr_t phys_offset;
+};
+
+/* The l1_phys_map provides the upper P_L1_BITs of the guest physical
+ * address.  Each intermediate table provides the next L2_BITs of guest
+ * physical address space.  The number of levels vary based on host and
+ * guest configuration, making it efficient to build the final guest
+ * physical address by seeding the L1 offset and shifting and adding in
+ * each L2 offset as we recurse through them. */
+static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level,
+                                 void **lp, target_phys_addr_t addr,
+                                 struct last_map *map)
 {
     int i;
 
@@ -1749,16 +1790,32 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
     }
     if (level == 0) {
         PhysPageDesc *pd = *lp;
+        addr <<= L2_BITS + TARGET_PAGE_BITS;
         for (i = 0; i < L2_SIZE; ++i) {
             if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
-                client->set_memory(client, pd[i].region_offset,
-                                   TARGET_PAGE_SIZE, pd[i].phys_offset);
+                target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS;
+
+                if (map->size &&
+                    start_addr == map->start_addr + map->size &&
+                    pd[i].phys_offset == map->phys_offset + map->size) {
+
+                    map->size += TARGET_PAGE_SIZE;
+                    continue;
+                } else if (map->size) {
+                    client->set_memory(client, map->start_addr,
+                                       map->size, map->phys_offset, false);
+                }
+
+                map->start_addr = start_addr;
+                map->size = TARGET_PAGE_SIZE;
+                map->phys_offset = pd[i].phys_offset;
             }
         }
     } else {
         void **pp = *lp;
         for (i = 0; i < L2_SIZE; ++i) {
-            phys_page_for_each_1(client, level - 1, pp + i);
+            phys_page_for_each_1(client, level - 1, pp + i,
+                                 (addr << L2_BITS) | i, map);
         }
     }
 }
@@ -1766,9 +1823,15 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
 static void phys_page_for_each(CPUPhysMemoryClient *client)
 {
     int i;
+    struct last_map map = { };
+
     for (i = 0; i < P_L1_SIZE; ++i) {
         phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
-                             l1_phys_map + 1);
+                             l1_phys_map + i, i, &map);
+    }
+    if (map.size) {
+        client->set_memory(client, map.start_addr, map.size, map.phys_offset,
+                           false);
     }
 }
 
@@ -2039,7 +2102,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
     /* we modify the TLB cache so that the dirty bit will be set again
        when accessing the range */
     start1 = (unsigned long)qemu_safe_ram_ptr(start);
-    /* Chek that we don't span multiple blocks - this breaks the
+    /* Check that we don't span multiple blocks - this breaks the
        address comparisons below.  */
     if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
             != (end - 1) - start) {
@@ -2078,6 +2141,36 @@ int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
     return ret;
 }
 
+int cpu_physical_log_start(target_phys_addr_t start_addr,
+                           ram_addr_t size)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        if (client->log_start) {
+            int r = client->log_start(client, start_addr, size);
+            if (r < 0) {
+                return r;
+            }
+        }
+    }
+    return 0;
+}
+
+int cpu_physical_log_stop(target_phys_addr_t start_addr,
+                          ram_addr_t size)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        if (client->log_stop) {
+            int r = client->log_stop(client, start_addr, size);
+            if (r < 0) {
+                return r;
+            }
+        }
+    }
+    return 0;
+}
+
 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
 {
     ram_addr_t ram_addr;
@@ -2567,10 +2660,11 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
    start_addr and region_offset are rounded down to a page boundary
    before calculating this offset.  This should not be a problem unless
    the low bits of start_addr and region_offset differ.  */
-void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
                                          ram_addr_t size,
                                          ram_addr_t phys_offset,
-                                         ram_addr_t region_offset)
+                                         ram_addr_t region_offset,
+                                         bool log_dirty)
 {
     target_phys_addr_t addr, end_addr;
     PhysPageDesc *p;
@@ -2578,7 +2672,9 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
     ram_addr_t orig_size = size;
     subpage_t *subpage;
 
-    cpu_notify_set_memory(start_addr, size, phys_offset);
+    assert(size);
+
+    cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
 
     if (phys_offset == IO_MEM_UNASSIGNED) {
         region_offset = start_addr;
@@ -2586,7 +2682,9 @@ void cpu_register_physical_memory_offset(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;
@@ -2638,7 +2736,8 @@ void cpu_register_physical_memory_offset(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 */
@@ -2776,13 +2875,13 @@ static void *file_ram_alloc(RAMBlock *block,
 static ram_addr_t find_ram_offset(ram_addr_t size)
 {
     RAMBlock *block, *next_block;
-    ram_addr_t offset = 0, mingap = ULONG_MAX;
+    ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
 
     if (QLIST_EMPTY(&ram_list.blocks))
         return 0;
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
-        ram_addr_t end, next = ULONG_MAX;
+        ram_addr_t end, next = RAM_ADDR_MAX;
 
         end = block->offset + block->length;
 
@@ -2792,10 +2891,17 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
             }
         }
         if (next - end >= size && next - end < mingap) {
-            offset =  end;
+            offset = end;
             mingap = next - end;
         }
     }
+
+    if (offset == RAM_ADDR_MAX) {
+        fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
+                (uint64_t)size);
+        abort();
+    }
+
     return offset;
 }
 
@@ -2816,13 +2922,13 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
     RAMBlock *new_block, *block;
 
     size = TARGET_PAGE_ALIGN(size);
-    new_block = qemu_mallocz(sizeof(*new_block));
+    new_block = g_malloc0(sizeof(*new_block));
 
     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
         char *id = dev->parent_bus->info->get_dev_path(dev);
         if (id) {
             snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
-            qemu_free(id);
+            g_free(id);
         }
     }
     pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
@@ -2835,8 +2941,10 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
         }
     }
 
+    new_block->offset = find_ram_offset(size);
     if (host) {
         new_block->host = host;
+        new_block->flags |= RAM_PREALLOC_MASK;
     } else {
         if (mem_path) {
 #if defined (__linux__) && !defined(TARGET_S390X)
@@ -2851,23 +2959,50 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
 #endif
         } else {
 #if defined(TARGET_S390X) && defined(CONFIG_KVM)
-            /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
-            new_block->host = mmap((void*)0x1000000, size,
+            /* S390 KVM requires the topmost vma of the RAM to be smaller than
+               an system defined value, which is at least 256GB. Larger systems
+               have larger values. We put the guest between the end of data
+               segment (system break) and this value. We use 32GB as a base to
+               have enough room for the system break to grow. */
+            new_block->host = mmap((void*)0x800000000, size,
                                    PROT_EXEC|PROT_READ|PROT_WRITE,
-                                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+            if (new_block->host == MAP_FAILED) {
+                fprintf(stderr, "Allocating RAM failed\n");
+                abort();
+            }
 #else
-            new_block->host = qemu_vmalloc(size);
+            if (xen_enabled()) {
+                xen_ram_alloc(new_block->offset, size);
+            } else {
+                new_block->host = qemu_vmalloc(size);
+#ifdef CONFIG_HAX
+               /*
+                * In Hax, the qemu allocate the virtual address, and HAX kernel
+                * populate the memory with physical memory. Currently we have no
+                * paging, so user should make sure enough free memory in advance
+                */
+               if (hax_enabled())
+               {
+                       int ret;
+                       ret = hax_populate_ram((uint64_t)new_block->host, size);
+                       if (ret < 0)
+                       {
+                               fprintf(stderr, "Hax failed to populate ram\n");
+                               exit(-1);
+                       }
+               }
+#endif
+            }
 #endif
             qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
         }
     }
-
-    new_block->offset = find_ram_offset(size);
     new_block->length = size;
 
     QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
 
-    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+    ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
                                        last_ram_offset() >> TARGET_PAGE_BITS);
     memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
            0xff, size >> TARGET_PAGE_BITS);
@@ -2883,6 +3018,19 @@ ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
     return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
 }
 
+void qemu_ram_free_from_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr == block->offset) {
+            QLIST_REMOVE(block, next);
+            g_free(block);
+            return;
+        }
+    }
+}
+
 void qemu_ram_free(ram_addr_t addr)
 {
     RAMBlock *block;
@@ -2890,7 +3038,9 @@ void qemu_ram_free(ram_addr_t addr)
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         if (addr == block->offset) {
             QLIST_REMOVE(block, next);
-            if (mem_path) {
+            if (block->flags & RAM_PREALLOC_MASK) {
+                ;
+            } else if (mem_path) {
 #if defined (__linux__) && !defined(TARGET_S390X)
                 if (block->fd) {
                     munmap(block->host, block->length);
@@ -2898,21 +3048,88 @@ void qemu_ram_free(ram_addr_t addr)
                 } else {
                     qemu_vfree(block->host);
                 }
+#else
+                abort();
 #endif
             } else {
 #if defined(TARGET_S390X) && defined(CONFIG_KVM)
                 munmap(block->host, block->length);
 #else
-                qemu_vfree(block->host);
+                if (xen_enabled()) {
+                    xen_invalidate_map_cache_entry(block->host);
+                } else {
+                    qemu_vfree(block->host);
+                }
 #endif
             }
-            qemu_free(block);
+            g_free(block);
             return;
         }
     }
 
 }
 
+#ifndef _WIN32
+void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
+{
+    RAMBlock *block;
+    ram_addr_t offset;
+    int flags;
+    void *area, *vaddr;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        offset = addr - block->offset;
+        if (offset < block->length) {
+            vaddr = block->host + offset;
+            if (block->flags & RAM_PREALLOC_MASK) {
+                ;
+            } else {
+                flags = MAP_FIXED;
+                munmap(vaddr, length);
+                if (mem_path) {
+#if defined(__linux__) && !defined(TARGET_S390X)
+                    if (block->fd) {
+#ifdef MAP_POPULATE
+                        flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
+                            MAP_PRIVATE;
+#else
+                        flags |= MAP_PRIVATE;
+#endif
+                        area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                    flags, block->fd, offset);
+                    } else {
+                        flags |= MAP_PRIVATE | MAP_ANONYMOUS;
+                        area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                    flags, -1, 0);
+                    }
+#else
+                    abort();
+#endif
+                } else {
+#if defined(TARGET_S390X) && defined(CONFIG_KVM)
+                    flags |= MAP_SHARED | MAP_ANONYMOUS;
+                    area = mmap(vaddr, length, PROT_EXEC|PROT_READ|PROT_WRITE,
+                                flags, -1, 0);
+#else
+                    flags |= MAP_PRIVATE | MAP_ANONYMOUS;
+                    area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                flags, -1, 0);
+#endif
+                }
+                if (area != vaddr) {
+                    fprintf(stderr, "Could not remap addr: "
+                            RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
+                            length, addr);
+                    exit(1);
+                }
+                qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
+            }
+            return;
+        }
+    }
+}
+#endif /* !_WIN32 */
+
 /* Return a host pointer to ram allocated with qemu_ram_alloc.
    With the exception of the softmmu code in this file, this should
    only be used for local memory (e.g. video ram) that the device owns,
@@ -2927,8 +3144,23 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         if (addr - block->offset < block->length) {
-            QLIST_REMOVE(block, next);
-            QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            /* Move this entry to to start of the list.  */
+            if (block != QLIST_FIRST(&ram_list.blocks)) {
+                QLIST_REMOVE(block, next);
+                QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            }
+            if (xen_enabled()) {
+                /* We need to check if the requested address is in the RAM
+                 * because we don't want to map the entire memory in QEMU.
+                 * In that case just map until the end of the page.
+                 */
+                if (block->offset == 0) {
+                    return xen_map_cache(addr, 0, 0);
+                } else if (block->host == NULL) {
+                    block->host =
+                        xen_map_cache(block->offset, block->length, 1);
+                }
+            }
             return block->host + (addr - block->offset);
         }
     }
@@ -2948,6 +3180,18 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         if (addr - block->offset < block->length) {
+            if (xen_enabled()) {
+                /* We need to check if the requested address is in the RAM
+                 * because we don't want to map the entire memory in QEMU.
+                 * In that case just map until the end of the page.
+                 */
+                if (block->offset == 0) {
+                    return xen_map_cache(addr, 0, 0);
+                } else if (block->host == NULL) {
+                    block->host =
+                        xen_map_cache(block->offset, block->length, 1);
+                }
+            }
             return block->host + (addr - block->offset);
         }
     }
@@ -2958,17 +3202,57 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)
     return NULL;
 }
 
+/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
+ * but takes a size argument */
+void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
+{
+    if (*size == 0) {
+        return NULL;
+    }
+    if (xen_enabled()) {
+        return xen_map_cache(addr, *size, 1);
+    } else {
+        RAMBlock *block;
+
+        QLIST_FOREACH(block, &ram_list.blocks, next) {
+            if (addr - block->offset < block->length) {
+                if (addr - block->offset + *size > block->length)
+                    *size = block->length - addr + block->offset;
+                return block->host + (addr - block->offset);
+            }
+        }
+
+        fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+        abort();
+    }
+}
+
+void qemu_put_ram_ptr(void *addr)
+{
+    trace_qemu_put_ram_ptr(addr);
+}
+
 int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
 {
     RAMBlock *block;
     uint8_t *host = ptr;
 
+    if (xen_enabled()) {
+        *ram_addr = xen_ram_addr_from_mapcache(ptr);
+        return 0;
+    }
+
     QLIST_FOREACH(block, &ram_list.blocks, next) {
+        /* This case append when the block is not mapped. */
+        if (block->host == NULL) {
+            continue;
+        }
         if (host - block->host < block->length) {
             *ram_addr = block->offset + (host - block->host);
             return 0;
         }
     }
+
     return -1;
 }
 
@@ -2990,8 +3274,8 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 0, 0, 0, 1);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
 #endif
     return 0;
 }
@@ -3001,8 +3285,8 @@ static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 0, 0, 0, 2);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
 #endif
     return 0;
 }
@@ -3012,8 +3296,8 @@ static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 0, 0, 0, 4);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
 #endif
     return 0;
 }
@@ -3023,8 +3307,8 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 1, 0, 0, 1);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
 #endif
 }
 
@@ -3033,8 +3317,8 @@ static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 1, 0, 0, 2);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
 #endif
 }
 
@@ -3043,8 +3327,8 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
 #endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
-    do_unassigned_access(addr, 1, 0, 0, 4);
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
 #endif
 }
 
@@ -3161,7 +3445,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;
@@ -3305,6 +3589,63 @@ static CPUWriteMemoryFunc * const subpage_write[] = {
     &subpage_writel,
 };
 
+static uint32_t subpage_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    return ldub_p(ptr);
+}
+
+static void subpage_ram_writeb(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    stb_p(ptr, value);
+}
+
+static uint32_t subpage_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    return lduw_p(ptr);
+}
+
+static void subpage_ram_writew(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    stw_p(ptr, value);
+}
+
+static uint32_t subpage_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    return ldl_p(ptr);
+}
+
+static void subpage_ram_writel(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    ram_addr_t raddr = addr;
+    void *ptr = qemu_get_ram_ptr(raddr);
+    stl_p(ptr, value);
+}
+
+static CPUReadMemoryFunc * const subpage_ram_read[] = {
+    &subpage_ram_readb,
+    &subpage_ram_readw,
+    &subpage_ram_readl,
+};
+
+static CPUWriteMemoryFunc * const subpage_ram_write[] = {
+    &subpage_ram_writeb,
+    &subpage_ram_writew,
+    &subpage_ram_writel,
+};
+
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
                              ram_addr_t memory, ram_addr_t region_offset)
 {
@@ -3318,8 +3659,9 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
     printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
            mmio, start, end, idx, eidx, memory);
 #endif
-    if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
-        memory = IO_MEM_UNASSIGNED;
+    if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+        memory = IO_MEM_SUBPAGE_RAM;
+    }
     memory = (memory >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
     for (; idx <= eidx; idx++) {
         mmio->sub_io_index[idx] = memory;
@@ -3336,7 +3678,7 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
     subpage_t *mmio;
     int subpage_memory;
 
-    mmio = qemu_mallocz(sizeof(subpage_t));
+    mmio = g_malloc0(sizeof(subpage_t));
 
     mmio->base = base;
     subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio,
@@ -3442,7 +3784,7 @@ static CPUWriteMemoryFunc * const swapendian_writefn[3]={
 
 static void swapendian_init(int io_index)
 {
-    SwapEndianContainer *c = qemu_malloc(sizeof(SwapEndianContainer));
+    SwapEndianContainer *c = g_malloc(sizeof(SwapEndianContainer));
     int i;
 
     /* Swap mmio for big endian targets */
@@ -3460,7 +3802,7 @@ static void swapendian_init(int io_index)
 static void swapendian_del(int io_index)
 {
     if (io_mem_read[io_index][0] == swapendian_readfn[0]) {
-        qemu_free(io_mem_opaque[io_index]);
+        g_free(io_mem_opaque[io_index]);
     }
 }
 
@@ -3552,6 +3894,9 @@ static void io_mem_init(void)
     cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
                                  notdirty_mem_write, NULL,
                                  DEVICE_NATIVE_ENDIAN);
+    cpu_register_io_memory_fixed(IO_MEM_SUBPAGE_RAM, subpage_ram_read,
+                                 subpage_ram_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
     for (i=0; i<5; i++)
         io_mem_used[i] = 1;
 
@@ -3560,6 +3905,27 @@ static void io_mem_init(void)
                                           DEVICE_NATIVE_ENDIAN);
 }
 
+static void memory_map_init(void)
+{
+    system_memory = g_malloc(sizeof(*system_memory));
+    memory_region_init(system_memory, "system", INT64_MAX);
+    set_system_memory_map(system_memory);
+
+    system_io = g_malloc(sizeof(*system_io));
+    memory_region_init(system_io, "io", 65536);
+    set_system_io_map(system_io);
+}
+
+MemoryRegion *get_system_memory(void)
+{
+    return system_memory;
+}
+
+MemoryRegion *get_system_io(void)
+{
+    return system_io;
+}
+
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 /* physical memory access (slow version, mainly for debug) */
@@ -3611,7 +3977,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
     uint8_t *ptr;
     uint32_t val;
     target_phys_addr_t page;
-    unsigned long pd;
+    ram_addr_t pd;
     PhysPageDesc *p;
 
     while (len > 0) {
@@ -3651,7 +4017,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                     l = 1;
                 }
             } else {
-                unsigned long addr1;
+                ram_addr_t addr1;
                 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
                 /* RAM case */
                 ptr = qemu_get_ram_ptr(addr1);
@@ -3663,6 +4029,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                     cpu_physical_memory_set_dirty_flags(
                         addr1, (0xff & ~CODE_DIRTY_FLAG));
                 }
+                qemu_put_ram_ptr(ptr);
             }
         } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -3690,9 +4057,9 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 }
             } else {
                 /* RAM case */
-                ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
-                    (addr & ~TARGET_PAGE_MASK);
-                memcpy(buf, ptr, l);
+                ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
+                memcpy(buf, ptr + (addr & ~TARGET_PAGE_MASK), l);
+                qemu_put_ram_ptr(ptr);
             }
         }
         len -= l;
@@ -3733,6 +4100,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
             /* ROM/RAM case */
             ptr = qemu_get_ram_ptr(addr1);
             memcpy(ptr, buf, l);
+            qemu_put_ram_ptr(ptr);
         }
         len -= l;
         buf += l;
@@ -3759,7 +4127,7 @@ static QLIST_HEAD(map_client_list, MapClient) map_client_list
 
 void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
 {
-    MapClient *client = qemu_malloc(sizeof(*client));
+    MapClient *client = g_malloc(sizeof(*client));
 
     client->opaque = opaque;
     client->callback = callback;
@@ -3772,7 +4140,7 @@ void cpu_unregister_map_client(void *_client)
     MapClient *client = (MapClient *)_client;
 
     QLIST_REMOVE(client, link);
-    qemu_free(client);
+    g_free(client);
 }
 
 static void cpu_notify_map_clients(void)
@@ -3798,14 +4166,14 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
                               int is_write)
 {
     target_phys_addr_t len = *plen;
-    target_phys_addr_t done = 0;
+    target_phys_addr_t todo = 0;
     int l;
-    uint8_t *ret = NULL;
-    uint8_t *ptr;
     target_phys_addr_t page;
     unsigned long pd;
     PhysPageDesc *p;
-    unsigned long addr1;
+    ram_addr_t raddr = RAM_ADDR_MAX;
+    ram_addr_t rlen;
+    void *ret;
 
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
@@ -3820,31 +4188,30 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
         }
 
         if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
-            if (done || bounce.buffer) {
+            if (todo || bounce.buffer) {
                 break;
             }
             bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
             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 {
-            addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
-            ptr = qemu_get_ram_ptr(addr1);
+
+            *plen = l;
+            return bounce.buffer;
         }
-        if (!done) {
-            ret = ptr;
-        } else if (ret + done != ptr) {
-            break;
+        if (!todo) {
+            raddr = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         }
 
         len -= l;
         addr += l;
-        done += l;
+        todo += l;
     }
-    *plen = done;
+    rlen = todo;
+    ret = qemu_ram_ptr_length(raddr, &rlen);
+    *plen = rlen;
     return ret;
 }
 
@@ -3874,6 +4241,9 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
                 access_len -= l;
             }
         }
+        if (xen_enabled()) {
+            xen_invalidate_map_cache_entry(buffer);
+        }
         return;
     }
     if (is_write) {
@@ -3885,7 +4255,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 }
 
 /* warning: addr must be aligned */
-uint32_t ldl_phys(target_phys_addr_t addr)
+static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
+                                         enum device_endian endian)
 {
     int io_index;
     uint8_t *ptr;
@@ -3907,17 +4278,52 @@ uint32_t ldl_phys(target_phys_addr_t addr)
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap32(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap32(val);
+        }
+#endif
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
-        val = ldl_p(ptr);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = ldl_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = ldl_be_p(ptr);
+            break;
+        default:
+            val = ldl_p(ptr);
+            break;
+        }
     }
     return val;
 }
 
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint32_t ldl_le_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint32_t ldl_be_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
 /* warning: addr must be aligned */
-uint64_t ldq_phys(target_phys_addr_t addr)
+static inline uint64_t ldq_phys_internal(target_phys_addr_t addr,
+                                         enum device_endian endian)
 {
     int io_index;
     uint8_t *ptr;
@@ -3938,6 +4344,9 @@ uint64_t ldq_phys(target_phys_addr_t addr)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+
+        /* XXX This is broken when device endian != cpu endian.
+               Fix and add "endian" variable check */
 #ifdef TARGET_WORDS_BIGENDIAN
         val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
         val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
@@ -3949,11 +4358,36 @@ uint64_t ldq_phys(target_phys_addr_t addr)
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
-        val = ldq_p(ptr);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = ldq_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = ldq_be_p(ptr);
+            break;
+        default:
+            val = ldq_p(ptr);
+            break;
+        }
     }
     return val;
 }
 
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint64_t ldq_le_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint64_t ldq_be_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
 /* XXX: optimize */
 uint32_t ldub_phys(target_phys_addr_t addr)
 {
@@ -3963,7 +4397,8 @@ uint32_t ldub_phys(target_phys_addr_t addr)
 }
 
 /* warning: addr must be aligned */
-uint32_t lduw_phys(target_phys_addr_t addr)
+static inline uint32_t lduw_phys_internal(target_phys_addr_t addr,
+                                          enum device_endian endian)
 {
     int io_index;
     uint8_t *ptr;
@@ -3985,15 +4420,49 @@ uint32_t lduw_phys(target_phys_addr_t addr)
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
         val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap16(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap16(val);
+        }
+#endif
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
-        val = lduw_p(ptr);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = lduw_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = lduw_be_p(ptr);
+            break;
+        default:
+            val = lduw_p(ptr);
+            break;
+        }
     }
     return val;
 }
 
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint32_t lduw_le_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint32_t lduw_be_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
 /* warning: addr must be aligned. The ram page is not masked as dirty
    and the code inside is not invalidated. It is useful if the dirty
    bits are used to track modified PTEs */
@@ -4066,7 +4535,8 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
 }
 
 /* warning: addr must be aligned */
-void stl_phys(target_phys_addr_t addr, uint32_t val)
+static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val,
+                                     enum device_endian endian)
 {
     int io_index;
     uint8_t *ptr;
@@ -4084,13 +4554,32 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap32(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap32(val);
+        }
+#endif
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1;
         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         /* RAM case */
         ptr = qemu_get_ram_ptr(addr1);
-        stl_p(ptr, val);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            stl_le_p(ptr, val);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            stl_be_p(ptr, val);
+            break;
+        default:
+            stl_p(ptr, val);
+            break;
+        }
         if (!cpu_physical_memory_is_dirty(addr1)) {
             /* invalidate code */
             tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
@@ -4101,6 +4590,21 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
     }
 }
 
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
+}
+
+void stl_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
+}
+
+void stl_be_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
+}
+
 /* XXX: optimize */
 void stb_phys(target_phys_addr_t addr, uint32_t val)
 {
@@ -4109,7 +4613,8 @@ void stb_phys(target_phys_addr_t addr, uint32_t val)
 }
 
 /* warning: addr must be aligned */
-void stw_phys(target_phys_addr_t addr, uint32_t val)
+static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val,
+                                     enum device_endian endian)
 {
     int io_index;
     uint8_t *ptr;
@@ -4127,13 +4632,32 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap16(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap16(val);
+        }
+#endif
         io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1;
         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         /* RAM case */
         ptr = qemu_get_ram_ptr(addr1);
-        stw_p(ptr, val);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            stw_le_p(ptr, val);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            stw_be_p(ptr, val);
+            break;
+        default:
+            stw_p(ptr, val);
+            break;
+        }
         if (!cpu_physical_memory_is_dirty(addr1)) {
             /* invalidate code */
             tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
@@ -4144,11 +4668,38 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
     }
 }
 
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
+}
+
+void stw_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
+}
+
+void stw_be_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
+}
+
 /* XXX: optimize */
 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);
+}
+
+void stq_le_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = cpu_to_le64(val);
+    cpu_physical_memory_write(addr, &val, 8);
+}
+
+void stq_be_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = cpu_to_be64(val);
+    cpu_physical_memory_write(addr, &val, 8);
 }
 
 /* virtual memory access for debug (includes writing to ROM) */
@@ -4196,7 +4747,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;
@@ -4295,6 +4846,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
 }
 
 #define MMUSUFFIX _cmmu
+#undef GETPC
 #define GETPC() NULL
 #define env cpu_single_env
 #define SOFTMMU_CODE_ACCESS
index 783822820ef02bbc9293e8bb4b8a217661f3d238..e82ce2332db0e076fb09f9a28e011e71324b23fd 100644 (file)
@@ -1,3 +1,8 @@
+/*
+ * QEMU float support macros
+ *
+ * Derived from SoftFloat.
+ */
 
 /*============================================================================
 
@@ -30,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
@@ -39,9 +55,9 @@ these four paragraphs for those parts of this code that are retained.
 | The result is stored in the location pointed to by `zPtr'.
 *----------------------------------------------------------------------------*/
 
-INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+INLINE void shift32RightJamming( uint32_t a, int16 count, uint32_t *zPtr )
 {
-    bits32 z;
+    uint32_t z;
 
     if ( count == 0 ) {
         z = a;
@@ -65,9 +81,9 @@ INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
 | The result is stored in the location pointed to by `zPtr'.
 *----------------------------------------------------------------------------*/
 
-INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
+INLINE void shift64RightJamming( uint64_t a, int16 count, uint64_t *zPtr )
 {
-    bits64 z;
+    uint64_t z;
 
     if ( count == 0 ) {
         z = a;
@@ -101,9 +117,9 @@ INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
 
 INLINE void
  shift64ExtraRightJamming(
-     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
-    bits64 z0, z1;
+    uint64_t z0, z1;
     int8 negCount = ( - count ) & 63;
 
     if ( count == 0 ) {
@@ -138,9 +154,9 @@ INLINE void
 
 INLINE void
  shift128Right(
-     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
-    bits64 z0, z1;
+    uint64_t z0, z1;
     int8 negCount = ( - count ) & 63;
 
     if ( count == 0 ) {
@@ -173,9 +189,9 @@ INLINE void
 
 INLINE void
  shift128RightJamming(
-     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
-    bits64 z0, z1;
+    uint64_t z0, z1;
     int8 negCount = ( - count ) & 63;
 
     if ( count == 0 ) {
@@ -224,16 +240,16 @@ INLINE void
 
 INLINE void
  shift128ExtraRightJamming(
-     bits64 a0,
-     bits64 a1,
-     bits64 a2,
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
      int16 count,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
  )
 {
-    bits64 z0, z1, z2;
+    uint64_t z0, z1, z2;
     int8 negCount = ( - count ) & 63;
 
     if ( count == 0 ) {
@@ -282,7 +298,7 @@ INLINE void
 
 INLINE void
  shortShift128Left(
-     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
 
     *z1Ptr = a1<<count;
@@ -301,16 +317,16 @@ INLINE void
 
 INLINE void
  shortShift192Left(
-     bits64 a0,
-     bits64 a1,
-     bits64 a2,
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
      int16 count,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
  )
 {
-    bits64 z0, z1, z2;
+    uint64_t z0, z1, z2;
     int8 negCount;
 
     z2 = a2<<count;
@@ -336,9 +352,9 @@ INLINE void
 
 INLINE void
  add128(
-     bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
-    bits64 z1;
+    uint64_t z1;
 
     z1 = a1 + b1;
     *z1Ptr = z1;
@@ -356,18 +372,18 @@ INLINE void
 
 INLINE void
  add192(
-     bits64 a0,
-     bits64 a1,
-     bits64 a2,
-     bits64 b0,
-     bits64 b1,
-     bits64 b2,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t b2,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
  )
 {
-    bits64 z0, z1, z2;
+    uint64_t z0, z1, z2;
     int8 carry0, carry1;
 
     z2 = a2 + b2;
@@ -394,7 +410,7 @@ INLINE void
 
 INLINE void
  sub128(
-     bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+     uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
 
     *z1Ptr = a1 - b1;
@@ -412,18 +428,18 @@ INLINE void
 
 INLINE void
  sub192(
-     bits64 a0,
-     bits64 a1,
-     bits64 a2,
-     bits64 b0,
-     bits64 b1,
-     bits64 b2,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t b2,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
  )
 {
-    bits64 z0, z1, z2;
+    uint64_t z0, z1, z2;
     int8 borrow0, borrow1;
 
     z2 = a2 - b2;
@@ -446,21 +462,21 @@ INLINE void
 | `z0Ptr' and `z1Ptr'.
 *----------------------------------------------------------------------------*/
 
-INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
+INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
 {
-    bits32 aHigh, aLow, bHigh, bLow;
-    bits64 z0, zMiddleA, zMiddleB, z1;
+    uint32_t aHigh, aLow, bHigh, bLow;
+    uint64_t z0, zMiddleA, zMiddleB, z1;
 
     aLow = a;
     aHigh = a>>32;
     bLow = b;
     bHigh = b>>32;
-    z1 = ( (bits64) aLow ) * bLow;
-    zMiddleA = ( (bits64) aLow ) * bHigh;
-    zMiddleB = ( (bits64) aHigh ) * bLow;
-    z0 = ( (bits64) aHigh ) * bHigh;
+    z1 = ( (uint64_t) aLow ) * bLow;
+    zMiddleA = ( (uint64_t) aLow ) * bHigh;
+    zMiddleB = ( (uint64_t) aHigh ) * bLow;
+    z0 = ( (uint64_t) aHigh ) * bHigh;
     zMiddleA += zMiddleB;
-    z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
+    z0 += ( ( (uint64_t) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
     zMiddleA <<= 32;
     z1 += zMiddleA;
     z0 += ( z1 < zMiddleA );
@@ -478,15 +494,15 @@ INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
 
 INLINE void
  mul128By64To192(
-     bits64 a0,
-     bits64 a1,
-     bits64 b,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t b,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
  )
 {
-    bits64 z0, z1, z2, more1;
+    uint64_t z0, z1, z2, more1;
 
     mul64To128( a1, b, &z1, &z2 );
     mul64To128( a0, b, &z0, &more1 );
@@ -506,18 +522,18 @@ INLINE void
 
 INLINE void
  mul128To256(
-     bits64 a0,
-     bits64 a1,
-     bits64 b0,
-     bits64 b1,
-     bits64 *z0Ptr,
-     bits64 *z1Ptr,
-     bits64 *z2Ptr,
-     bits64 *z3Ptr
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr,
+     uint64_t *z3Ptr
  )
 {
-    bits64 z0, z1, z2, z3;
-    bits64 more1, more2;
+    uint64_t z0, z1, z2, z3;
+    uint64_t more1, more2;
 
     mul64To128( a1, b1, &z2, &z3 );
     mul64To128( a1, b0, &z1, &more2 );
@@ -543,18 +559,18 @@ INLINE void
 | unsigned integer is returned.
 *----------------------------------------------------------------------------*/
 
-static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
+static uint64_t estimateDiv128To64( uint64_t a0, uint64_t a1, uint64_t b )
 {
-    bits64 b0, b1;
-    bits64 rem0, rem1, term0, term1;
-    bits64 z;
+    uint64_t b0, b1;
+    uint64_t rem0, rem1, term0, term1;
+    uint64_t z;
 
     if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
     b0 = b>>32;
     z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
     mul64To128( b, z, &term0, &term1 );
     sub128( a0, a1, term0, term1, &rem0, &rem1 );
-    while ( ( (sbits64) rem0 ) < 0 ) {
+    while ( ( (int64_t) rem0 ) < 0 ) {
         z -= LIT64( 0x100000000 );
         b1 = b<<32;
         add128( rem0, rem1, b0, b1, &rem0, &rem1 );
@@ -575,18 +591,18 @@ static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
 | value.
 *----------------------------------------------------------------------------*/
 
-static bits32 estimateSqrt32( int16 aExp, bits32 a )
+static uint32_t estimateSqrt32( int16 aExp, uint32_t a )
 {
-    static const bits16 sqrtOddAdjustments[] = {
+    static const uint16_t sqrtOddAdjustments[] = {
         0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
         0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
     };
-    static const bits16 sqrtEvenAdjustments[] = {
+    static const uint16_t sqrtEvenAdjustments[] = {
         0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
         0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
     };
     int8 index;
-    bits32 z;
+    uint32_t z;
 
     index = ( a>>27 ) & 15;
     if ( aExp & 1 ) {
@@ -598,9 +614,9 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
         z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ];
         z = a / z + z;
         z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
-        if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+        if ( z <= a ) return (uint32_t) ( ( (int32_t) a )>>1 );
     }
-    return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
+    return ( (uint32_t) ( ( ( (uint64_t) a )<<31 ) / z ) ) + ( z>>1 );
 
 }
 
@@ -609,8 +625,15 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
 | `a'.  If `a' is zero, 32 is returned.
 *----------------------------------------------------------------------------*/
 
-static int8 countLeadingZeros32( bits32 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,
@@ -642,7 +665,7 @@ static int8 countLeadingZeros32( bits32 a )
     }
     shiftCount += countLeadingZerosHigh[ a>>24 ];
     return shiftCount;
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -650,12 +673,19 @@ static int8 countLeadingZeros32( bits32 a )
 | `a'.  If `a' is zero, 64 is returned.
 *----------------------------------------------------------------------------*/
 
-static int8 countLeadingZeros64( bits64 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;
-    if ( a < ( (bits64) 1 )<<32 ) {
+    if ( a < ( (uint64_t) 1 )<<32 ) {
         shiftCount += 32;
     }
     else {
@@ -663,7 +693,7 @@ static int8 countLeadingZeros64( bits64 a )
     }
     shiftCount += countLeadingZeros32( a );
     return shiftCount;
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -672,7 +702,7 @@ static int8 countLeadingZeros64( bits64 a )
 | Otherwise, returns 0.
 *----------------------------------------------------------------------------*/
 
-INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
 {
 
     return ( a0 == b0 ) && ( a1 == b1 );
@@ -685,7 +715,7 @@ INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
 | Otherwise, returns 0.
 *----------------------------------------------------------------------------*/
 
-INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
 {
 
     return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
@@ -698,7 +728,7 @@ INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
 | returns 0.
 *----------------------------------------------------------------------------*/
 
-INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
 {
 
     return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
@@ -711,7 +741,7 @@ INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
 | Otherwise, returns 0.
 *----------------------------------------------------------------------------*/
 
-INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+INLINE flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
 {
 
     return ( a0 != b0 ) || ( a1 != b1 );
index eb644b2273949e68ebff6d1123b393d10cd19af5..c5e2dab9f66f125c01f990311d32cfc657b7c038 100644 (file)
@@ -1,3 +1,8 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
 
 /*============================================================================
 
@@ -30,12 +35,78 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
-#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
 #endif
 
+/*----------------------------------------------------------------------------
+| The pattern for a default generated half-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+const float16 float16_default_nan = const_float16(0x7E00);
+#elif SNAN_BIT_IS_ONE
+const float16 float16_default_nan = const_float16(0x7DFF);
+#else
+const float16 float16_default_nan = const_float16(0xFE00);
+#endif
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+const float32 float32_default_nan = const_float32(0x7FFFFFFF);
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+const float32 float32_default_nan = const_float32(0x7FC00000);
+#elif SNAN_BIT_IS_ONE
+const float32 float32_default_nan = const_float32(0x7FBFFFFF);
+#else
+const float32 float32_default_nan = const_float32(0xFFC00000);
+#endif
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF ));
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 ));
+#elif SNAN_BIT_IS_ONE
+const float64 float64_default_nan = const_float64(LIT64( 0x7FF7FFFFFFFFFFFF ));
+#else
+const float64 float64_default_nan = const_float64(LIT64( 0xFFF8000000000000 ));
+#endif
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision NaN.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define floatx80_default_nan_high 0x7FFF
+#define floatx80_default_nan_low  LIT64( 0xBFFFFFFFFFFFFFFF )
+#else
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low  LIT64( 0xC000000000000000 )
+#endif
+
+const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high,
+                                                    floatx80_default_nan_low);
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated quadruple-precision NaN.  The `high' and
+| `low' values hold the most- and least-significant bits, respectively.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
+#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
+#else
+#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
+#define float128_default_nan_low  LIT64( 0x0000000000000000 )
+#endif
+
+const float128 float128_default_nan = make_float128(float128_default_nan_high,
+                                                    float128_default_nan_low);
+
 /*----------------------------------------------------------------------------
 | Raises the exceptions specified by `flags'.  Floating-point traps can be
 | defined here if desired.  It is currently not possible for such a trap
@@ -53,21 +124,98 @@ void float_raise( int8 flags STATUS_PARAM )
 *----------------------------------------------------------------------------*/
 typedef struct {
     flag sign;
-    bits64 high, low;
+    uint64_t high, low;
 } commonNaNT;
 
 /*----------------------------------------------------------------------------
-| The pattern for a default generated single-precision NaN.
+| Returns 1 if the half-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
-#if defined(TARGET_SPARC)
-#define float32_default_nan make_float32(0x7FFFFFFF)
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
-#define float32_default_nan make_float32(0x7FC00000)
-#elif SNAN_BIT_IS_ONE
-#define float32_default_nan make_float32(0x7FBFFFFF)
+
+int float16_is_quiet_nan(float16 a_)
+{
+    uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+    return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#else
+    return ((a & ~0x8000) >= 0x7c80);
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the half-precision floating-point value `a' is a signaling
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float16_is_signaling_nan(float16 a_)
+{
+    uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+    return ((a & ~0x8000) >= 0x7c80);
+#else
+    return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the half-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+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) || defined(TARGET_UNICORE32)
+        return float16_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
 #else
-#define float32_default_nan make_float32(0xFFC00000)
+        uint16_t a = float16_val(a_);
+        a |= (1 << 9);
+        return make_float16(a);
 #endif
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the half-precision floating-point NaN
+| `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float16ToCommonNaN( float16 a STATUS_PARAM )
+{
+    commonNaNT z;
+
+    if ( float16_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
+    z.sign = float16_val(a) >> 15;
+    z.low = 0;
+    z.high = ((uint64_t) float16_val(a))<<54;
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the half-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float16 commonNaNToFloat16(commonNaNT a STATUS_PARAM)
+{
+    uint16_t mantissa = a.high>>54;
+
+    if (STATUS(default_nan_mode)) {
+        return float16_default_nan;
+    }
+
+    if (mantissa) {
+        return make_float16(((((uint16_t) a.sign) << 15)
+                             | (0x1F << 10) | mantissa));
+    } else {
+        return float16_default_nan;
+    }
+}
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is a quiet
@@ -80,7 +228,7 @@ int float32_is_quiet_nan( float32 a_ )
 #if SNAN_BIT_IS_ONE
     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
 #else
-    return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+    return ( 0xFF800000 <= (uint32_t) ( a<<1 ) );
 #endif
 }
 
@@ -93,7 +241,7 @@ int float32_is_signaling_nan( float32 a_ )
 {
     uint32_t a = float32_val(a_);
 #if SNAN_BIT_IS_ONE
-    return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+    return ( 0xFF800000 <= (uint32_t) ( a<<1 ) );
 #else
     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
 #endif
@@ -108,13 +256,13 @@ 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
 #  endif
 #else
-        bits32 a = float32_val(a_);
+        uint32_t a = float32_val(a_);
         a |= (1 << 22);
         return make_float32(a);
 #endif
@@ -135,7 +283,7 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
     if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
     z.sign = float32_val(a)>>31;
     z.low = 0;
-    z.high = ( (bits64) float32_val(a) )<<41;
+    z.high = ( (uint64_t) float32_val(a) )<<41;
     return z;
 }
 
@@ -144,12 +292,17 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
 | precision floating-point format.
 *----------------------------------------------------------------------------*/
 
-static float32 commonNaNToFloat32( commonNaNT a )
+static float32 commonNaNToFloat32( commonNaNT a STATUS_PARAM)
 {
-    bits32 mantissa = a.high>>41;
+    uint32_t mantissa = a.high>>41;
+
+    if ( STATUS(default_nan_mode) ) {
+        return float32_default_nan;
+    }
+
     if ( mantissa )
         return make_float32(
-            ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
+            ( ( (uint32_t) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
     else
         return float32_default_nan;
 }
@@ -266,6 +419,82 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
 }
 #endif
 
+/*----------------------------------------------------------------------------
+| Select which NaN to propagate for a three-input operation.
+| For the moment we assume that no CPU needs the 'larger significand'
+| information.
+| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
+     * the default NaN
+     */
+    if (infzero && cIsQNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return 3;
+    }
+
+    /* This looks different from the ARM ARM pseudocode, because the ARM ARM
+     * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
+     */
+    if (cIsSNaN) {
+        return 2;
+    } else if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (cIsQNaN) {
+        return 2;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#elif defined(TARGET_PPC)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
+     * to return an input NaN if we have one (ie c) rather than generating
+     * a default NaN
+     */
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return 2;
+    }
+
+    /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
+     * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
+     */
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else if (cIsSNaN || cIsQNaN) {
+        return 2;
+    } else {
+        return 1;
+    }
+}
+#else
+/* A default implementation: prefer a to b to c.
+ * This is unlikely to actually match any real implementation.
+ */
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else if (bIsSNaN || bIsQNaN) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+#endif
+
 /*----------------------------------------------------------------------------
 | Takes two single-precision floating-point values `a' and `b', one of which
 | is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
@@ -276,7 +505,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 {
     flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
     flag aIsLargerSignificand;
-    bits32 av, bv;
+    uint32_t av, bv;
 
     aIsQuietNaN = float32_is_quiet_nan( a );
     aIsSignalingNaN = float32_is_signaling_nan( a );
@@ -290,9 +519,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
     if ( STATUS(default_nan_mode) )
         return float32_default_nan;
 
-    if ((bits32)(av<<1) < (bits32)(bv<<1)) {
+    if ((uint32_t)(av<<1) < (uint32_t)(bv<<1)) {
         aIsLargerSignificand = 0;
-    } else if ((bits32)(bv<<1) < (bits32)(av<<1)) {
+    } else if ((uint32_t)(bv<<1) < (uint32_t)(av<<1)) {
         aIsLargerSignificand = 1;
     } else {
         aIsLargerSignificand = (av < bv) ? 1 : 0;
@@ -307,17 +536,55 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 }
 
 /*----------------------------------------------------------------------------
-| The pattern for a default generated double-precision NaN.
+| Takes three single-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result.  If any of  `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
 *----------------------------------------------------------------------------*/
-#if defined(TARGET_SPARC)
-#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
-#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
-#elif SNAN_BIT_IS_ONE
-#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
-#else
-#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
-#endif
+
+static float32 propagateFloat32MulAddNaN(float32 a, float32 b,
+                                         float32 c, flag infzero STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+        cIsQuietNaN, cIsSignalingNaN;
+    int which;
+
+    aIsQuietNaN = float32_is_quiet_nan(a);
+    aIsSignalingNaN = float32_is_signaling_nan(a);
+    bIsQuietNaN = float32_is_quiet_nan(b);
+    bIsSignalingNaN = float32_is_signaling_nan(b);
+    cIsQuietNaN = float32_is_quiet_nan(c);
+    cIsSignalingNaN = float32_is_signaling_nan(c);
+
+    if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+    }
+
+    which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+                          bIsQuietNaN, bIsSignalingNaN,
+                          cIsQuietNaN, cIsSignalingNaN, infzero STATUS_VAR);
+
+    if (STATUS(default_nan_mode)) {
+        /* Note that this check is after pickNaNMulAdd so that function
+         * has an opportunity to set the Invalid flag.
+         */
+        return float32_default_nan;
+    }
+
+    switch (which) {
+    case 0:
+        return float32_maybe_silence_nan(a);
+    case 1:
+        return float32_maybe_silence_nan(b);
+    case 2:
+        return float32_maybe_silence_nan(c);
+    case 3:
+    default:
+        return float32_default_nan;
+    }
+}
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is a quiet
@@ -326,13 +593,13 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 
 int float64_is_quiet_nan( float64 a_ )
 {
-    bits64 a = float64_val(a_);
+    uint64_t a = float64_val(a_);
 #if SNAN_BIT_IS_ONE
     return
            ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
         && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
 #else
-    return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+    return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) );
 #endif
 }
 
@@ -343,9 +610,9 @@ int float64_is_quiet_nan( float64 a_ )
 
 int float64_is_signaling_nan( float64 a_ )
 {
-    bits64 a = float64_val(a_);
+    uint64_t a = float64_val(a_);
 #if SNAN_BIT_IS_ONE
-    return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+    return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) );
 #else
     return
            ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
@@ -362,13 +629,13 @@ 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
 #  endif
 #else
-        bits64 a = float64_val(a_);
+        uint64_t a = float64_val(a_);
         a |= LIT64( 0x0008000000000000 );
         return make_float64(a);
 #endif
@@ -398,13 +665,17 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
 | precision floating-point format.
 *----------------------------------------------------------------------------*/
 
-static float64 commonNaNToFloat64( commonNaNT a )
+static float64 commonNaNToFloat64( commonNaNT a STATUS_PARAM)
 {
-    bits64 mantissa = a.high>>12;
+    uint64_t mantissa = a.high>>12;
+
+    if ( STATUS(default_nan_mode) ) {
+        return float64_default_nan;
+    }
 
     if ( mantissa )
         return make_float64(
-              ( ( (bits64) a.sign )<<63 )
+              ( ( (uint64_t) a.sign )<<63 )
             | LIT64( 0x7FF0000000000000 )
             | ( a.high>>12 ));
     else
@@ -421,7 +692,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 {
     flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
     flag aIsLargerSignificand;
-    bits64 av, bv;
+    uint64_t av, bv;
 
     aIsQuietNaN = float64_is_quiet_nan( a );
     aIsSignalingNaN = float64_is_signaling_nan( a );
@@ -435,9 +706,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
     if ( STATUS(default_nan_mode) )
         return float64_default_nan;
 
-    if ((bits64)(av<<1) < (bits64)(bv<<1)) {
+    if ((uint64_t)(av<<1) < (uint64_t)(bv<<1)) {
         aIsLargerSignificand = 0;
-    } else if ((bits64)(bv<<1) < (bits64)(av<<1)) {
+    } else if ((uint64_t)(bv<<1) < (uint64_t)(av<<1)) {
         aIsLargerSignificand = 1;
     } else {
         aIsLargerSignificand = (av < bv) ? 1 : 0;
@@ -451,20 +722,56 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
     }
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
-| The pattern for a default generated extended double-precision NaN.  The
-| `high' and `low' values hold the most- and least-significant bits,
-| respectively.
+| Takes three double-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result.  If any of  `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
 *----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
-#define floatx80_default_nan_high 0x7FFF
-#define floatx80_default_nan_low  LIT64( 0xBFFFFFFFFFFFFFFF )
-#else
-#define floatx80_default_nan_high 0xFFFF
-#define floatx80_default_nan_low  LIT64( 0xC000000000000000 )
-#endif
+
+static float64 propagateFloat64MulAddNaN(float64 a, float64 b,
+                                         float64 c, flag infzero STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+        cIsQuietNaN, cIsSignalingNaN;
+    int which;
+
+    aIsQuietNaN = float64_is_quiet_nan(a);
+    aIsSignalingNaN = float64_is_signaling_nan(a);
+    bIsQuietNaN = float64_is_quiet_nan(b);
+    bIsSignalingNaN = float64_is_signaling_nan(b);
+    cIsQuietNaN = float64_is_quiet_nan(c);
+    cIsSignalingNaN = float64_is_signaling_nan(c);
+
+    if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+    }
+
+    which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+                          bIsQuietNaN, bIsSignalingNaN,
+                          cIsQuietNaN, cIsSignalingNaN, infzero STATUS_VAR);
+
+    if (STATUS(default_nan_mode)) {
+        /* Note that this check is after pickNaNMulAdd so that function
+         * has an opportunity to set the Invalid flag.
+         */
+        return float64_default_nan;
+    }
+
+    switch (which) {
+    case 0:
+        return float64_maybe_silence_nan(a);
+    case 1:
+        return float64_maybe_silence_nan(b);
+    case 2:
+        return float64_maybe_silence_nan(c);
+    case 3:
+    default:
+        return float64_default_nan;
+    }
+}
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the extended double-precision floating-point value `a' is a
@@ -475,16 +782,16 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 int floatx80_is_quiet_nan( floatx80 a )
 {
 #if SNAN_BIT_IS_ONE
-    bits64 aLow;
+    uint64_t aLow;
 
     aLow = a.low & ~ LIT64( 0x4000000000000000 );
     return
            ( ( a.high & 0x7FFF ) == 0x7FFF )
-        && (bits64) ( aLow<<1 )
+        && (uint64_t) ( aLow<<1 )
         && ( a.low == aLow );
 #else
     return ( ( a.high & 0x7FFF ) == 0x7FFF )
-        && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
+        && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 )));
 #endif
 }
 
@@ -498,14 +805,14 @@ int floatx80_is_signaling_nan( floatx80 a )
 {
 #if SNAN_BIT_IS_ONE
     return ( ( a.high & 0x7FFF ) == 0x7FFF )
-        && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
+        && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 )));
 #else
-    bits64 aLow;
+    uint64_t aLow;
 
     aLow = a.low & ~ LIT64( 0x4000000000000000 );
     return
            ( ( a.high & 0x7FFF ) == 0x7FFF )
-        && (bits64) ( aLow<<1 )
+        && (uint64_t) ( aLow<<1 )
         && ( a.low == aLow );
 #endif
 }
@@ -519,7 +826,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
@@ -544,9 +851,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;
 }
 
@@ -555,15 +868,24 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
 | double-precision floating-point format.
 *----------------------------------------------------------------------------*/
 
-static floatx80 commonNaNToFloatx80( commonNaNT a )
+static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM)
 {
     floatx80 z;
 
-    if (a.high)
-        z.low = a.high;
-    else
+    if ( STATUS(default_nan_mode) ) {
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+
+    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 = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+        z.high = floatx80_default_nan_high;
+    }
+
     return z;
 }
 
@@ -607,22 +929,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
     }
 }
 
-#endif
-
-#ifdef FLOAT128
-
-/*----------------------------------------------------------------------------
-| The pattern for a default generated quadruple-precision NaN.  The `high' and
-| `low' values hold the most- and least-significant bits, respectively.
-*----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
-#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
-#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
-#else
-#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
-#define float128_default_nan_low  LIT64( 0x0000000000000000 )
-#endif
-
 /*----------------------------------------------------------------------------
 | Returns 1 if the quadruple-precision floating-point value `a' is a quiet
 | NaN; otherwise returns 0.
@@ -636,7 +942,7 @@ int float128_is_quiet_nan( float128 a )
         && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
 #else
     return
-           ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+           ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) )
         && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
 #endif
 }
@@ -650,7 +956,7 @@ int float128_is_signaling_nan( float128 a )
 {
 #if SNAN_BIT_IS_ONE
     return
-           ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+           ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) )
         && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
 #else
     return
@@ -668,7 +974,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
@@ -703,12 +1009,18 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
 | precision floating-point format.
 *----------------------------------------------------------------------------*/
 
-static float128 commonNaNToFloat128( commonNaNT a )
+static float128 commonNaNToFloat128( commonNaNT a STATUS_PARAM)
 {
     float128 z;
 
+    if ( STATUS(default_nan_mode) ) {
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+
     shift128Right( a.high, a.low, 16, &z.high, &z.low );
-    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
+    z.high |= ( ( (uint64_t) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
     return z;
 }
 
@@ -752,4 +1064,3 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
     }
 }
 
-#endif
index 17842f43dac691aed848c365272e6e853738593e..81a7d1ae09ecb2545867d2b4dcab92675ec5ce4d 100644 (file)
@@ -1,3 +1,8 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
 
 /*============================================================================
 
@@ -30,6 +35,11 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
+/* softfloat (and in particular the code in softfloat-specialize.h) is
+ * target-dependent and needs the TARGET_* macros.
+ */
+#include "config.h"
+
 #include "softfloat.h"
 
 /*----------------------------------------------------------------------------
@@ -59,12 +69,37 @@ void set_float_exception_flags(int val STATUS_PARAM)
     STATUS(float_exception_flags) = val;
 }
 
-#ifdef FLOATX80
 void set_floatx80_rounding_precision(int val STATUS_PARAM)
 {
     STATUS(floatx80_rounding_precision) = val;
 }
-#endif
+
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the half-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint32_t extractFloat16Frac(float16 a)
+{
+    return float16_val(a) & 0x3ff;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the half-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int16 extractFloat16Exp(float16 a)
+{
+    return (float16_val(a) >> 10) & 0x1f;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloat16Sign(float16 a)
+{
+    return float16_val(a)>>15;
+}
 
 /*----------------------------------------------------------------------------
 | Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
@@ -77,7 +112,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM)
 | positive or negative integer is returned.
 *----------------------------------------------------------------------------*/
 
-static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM)
+static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM)
 {
     int8 roundingMode;
     flag roundNearestEven;
@@ -108,7 +143,7 @@ static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM)
     if ( zSign ) z = - z;
     if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
         float_raise( float_flag_invalid STATUS_VAR);
-        return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+        return zSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
     }
     if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
     return z;
@@ -127,7 +162,7 @@ static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM)
 | returned.
 *----------------------------------------------------------------------------*/
 
-static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PARAM)
+static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATUS_PARAM)
 {
     int8 roundingMode;
     flag roundNearestEven, increment;
@@ -135,7 +170,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA
 
     roundingMode = STATUS(float_rounding_mode);
     roundNearestEven = ( roundingMode == float_round_nearest_even );
-    increment = ( (sbits64) absZ1 < 0 );
+    increment = ( (int64_t) absZ1 < 0 );
     if ( ! roundNearestEven ) {
         if ( roundingMode == float_round_to_zero ) {
             increment = 0;
@@ -152,7 +187,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA
     if ( increment ) {
         ++absZ0;
         if ( absZ0 == 0 ) goto overflow;
-        absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven );
+        absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven );
     }
     z = absZ0;
     if ( zSign ) z = - z;
@@ -160,7 +195,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA
  overflow:
         float_raise( float_flag_invalid STATUS_VAR);
         return
-              zSign ? (sbits64) LIT64( 0x8000000000000000 )
+              zSign ? (int64_t) LIT64( 0x8000000000000000 )
             : LIT64( 0x7FFFFFFFFFFFFFFF );
     }
     if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact;
@@ -172,7 +207,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA
 | Returns the fraction bits of the single-precision floating-point value `a'.
 *----------------------------------------------------------------------------*/
 
-INLINE bits32 extractFloat32Frac( float32 a )
+INLINE uint32_t extractFloat32Frac( float32 a )
 {
 
     return float32_val(a) & 0x007FFFFF;
@@ -224,7 +259,7 @@ static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
 *----------------------------------------------------------------------------*/
 
 static void
- normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+ normalizeFloat32Subnormal( uint32_t aSig, int16 *zExpPtr, uint32_t *zSigPtr )
 {
     int8 shiftCount;
 
@@ -245,11 +280,11 @@ static void
 | significand.
 *----------------------------------------------------------------------------*/
 
-INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
+INLINE float32 packFloat32( flag zSign, int16 zExp, uint32_t zSig )
 {
 
     return make_float32(
-          ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig);
+          ( ( (uint32_t) zSign )<<31 ) + ( ( (uint32_t) zExp )<<23 ) + zSig);
 
 }
 
@@ -275,7 +310,7 @@ INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
 | Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
-static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM)
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM)
 {
     int8 roundingMode;
     flag roundNearestEven;
@@ -300,16 +335,19 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
         }
     }
     roundBits = zSig & 0x7F;
-    if ( 0xFD <= (bits16) zExp ) {
+    if ( 0xFD <= (uint16_t) zExp ) {
         if (    ( 0xFD < zExp )
              || (    ( zExp == 0xFD )
-                  && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
+                  && ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
            ) {
             float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
             return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat32(zSign, 0, 0);
+            }
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -338,7 +376,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
 *----------------------------------------------------------------------------*/
 
 static float32
- normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM)
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM)
 {
     int8 shiftCount;
 
@@ -351,7 +389,7 @@ static float32
 | Returns the fraction bits of the double-precision floating-point value `a'.
 *----------------------------------------------------------------------------*/
 
-INLINE bits64 extractFloat64Frac( float64 a )
+INLINE uint64_t extractFloat64Frac( float64 a )
 {
 
     return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF );
@@ -403,7 +441,7 @@ static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
 *----------------------------------------------------------------------------*/
 
 static void
- normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr )
+ normalizeFloat64Subnormal( uint64_t aSig, int16 *zExpPtr, uint64_t *zSigPtr )
 {
     int8 shiftCount;
 
@@ -424,11 +462,11 @@ static void
 | significand.
 *----------------------------------------------------------------------------*/
 
-INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
+INLINE float64 packFloat64( flag zSign, int16 zExp, uint64_t zSig )
 {
 
     return make_float64(
-        ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig);
+        ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<52 ) + zSig);
 
 }
 
@@ -454,7 +492,7 @@ INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
 | Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
-static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM)
+static float64 roundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM)
 {
     int8 roundingMode;
     flag roundNearestEven;
@@ -479,16 +517,19 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
         }
     }
     roundBits = zSig & 0x3FF;
-    if ( 0x7FD <= (bits16) zExp ) {
+    if ( 0x7FD <= (uint16_t) zExp ) {
         if (    ( 0x7FD < zExp )
              || (    ( zExp == 0x7FD )
-                  && ( (sbits64) ( zSig + roundIncrement ) < 0 ) )
+                  && ( (int64_t) ( zSig + roundIncrement ) < 0 ) )
            ) {
             float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
             return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat64(zSign, 0, 0);
+            }
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -517,7 +558,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
 *----------------------------------------------------------------------------*/
 
 static float64
- normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM)
+ normalizeRoundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM)
 {
     int8 shiftCount;
 
@@ -526,14 +567,12 @@ static float64
 
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the fraction bits of the extended double-precision floating-point
 | value `a'.
 *----------------------------------------------------------------------------*/
 
-INLINE bits64 extractFloatx80Frac( floatx80 a )
+INLINE uint64_t extractFloatx80Frac( floatx80 a )
 {
 
     return a.low;
@@ -572,7 +611,7 @@ INLINE flag extractFloatx80Sign( floatx80 a )
 *----------------------------------------------------------------------------*/
 
 static void
- normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr )
+ normalizeFloatx80Subnormal( uint64_t aSig, int32 *zExpPtr, uint64_t *zSigPtr )
 {
     int8 shiftCount;
 
@@ -587,12 +626,12 @@ static void
 | extended double-precision floating-point value, returning the result.
 *----------------------------------------------------------------------------*/
 
-INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
+INLINE floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
 {
     floatx80 z;
 
     z.low = zSig;
-    z.high = ( ( (bits16) zSign )<<15 ) + zExp;
+    z.high = ( ( (uint16_t) zSign )<<15 ) + zExp;
     return z;
 
 }
@@ -623,7 +662,7 @@ INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
 
 static floatx80
  roundAndPackFloatx80(
-     int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+     int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1
  STATUS_PARAM)
 {
     int8 roundingMode;
@@ -660,14 +699,17 @@ static floatx80
         }
     }
     roundBits = zSig0 & roundMask;
-    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+    if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) {
         if (    ( 0x7FFE < zExp )
              || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
            ) {
             goto overflow;
         }
         if ( zExp <= 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloatx80(zSign, 0, 0);
+            }
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < 0 )
@@ -678,7 +720,7 @@ static floatx80
             if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR);
             if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
             zSig0 += roundIncrement;
-            if ( (sbits64) zSig0 < 0 ) zExp = 1;
+            if ( (int64_t) zSig0 < 0 ) zExp = 1;
             roundIncrement = roundMask + 1;
             if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
                 roundMask |= roundIncrement;
@@ -701,7 +743,7 @@ static floatx80
     if ( zSig0 == 0 ) zExp = 0;
     return packFloatx80( zSign, zExp, zSig0 );
  precision80:
-    increment = ( (sbits64) zSig1 < 0 );
+    increment = ( (int64_t) zSig1 < 0 );
     if ( ! roundNearestEven ) {
         if ( roundingMode == float_round_to_zero ) {
             increment = 0;
@@ -715,7 +757,7 @@ static floatx80
             }
         }
     }
-    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+    if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) {
         if (    ( 0x7FFE < zExp )
              || (    ( zExp == 0x7FFE )
                   && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
@@ -744,7 +786,7 @@ static floatx80
             if ( isTiny && zSig1 ) float_raise( float_flag_underflow STATUS_VAR);
             if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact;
             if ( roundNearestEven ) {
-                increment = ( (sbits64) zSig1 < 0 );
+                increment = ( (int64_t) zSig1 < 0 );
             }
             else {
                 if ( zSign ) {
@@ -757,8 +799,8 @@ static floatx80
             if ( increment ) {
                 ++zSig0;
                 zSig0 &=
-                    ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
-                if ( (sbits64) zSig0 < 0 ) zExp = 1;
+                    ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+                if ( (int64_t) zSig0 < 0 ) zExp = 1;
             }
             return packFloatx80( zSign, zExp, zSig0 );
         }
@@ -771,7 +813,7 @@ static floatx80
             zSig0 = LIT64( 0x8000000000000000 );
         }
         else {
-            zSig0 &= ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+            zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
         }
     }
     else {
@@ -792,7 +834,7 @@ static floatx80
 
 static floatx80
  normalizeRoundAndPackFloatx80(
-     int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+     int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1
  STATUS_PARAM)
 {
     int8 shiftCount;
@@ -810,16 +852,12 @@ static floatx80
 
 }
 
-#endif
-
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the least-significant 64 fraction bits of the quadruple-precision
 | floating-point value `a'.
 *----------------------------------------------------------------------------*/
 
-INLINE bits64 extractFloat128Frac1( float128 a )
+INLINE uint64_t extractFloat128Frac1( float128 a )
 {
 
     return a.low;
@@ -831,7 +869,7 @@ INLINE bits64 extractFloat128Frac1( float128 a )
 | floating-point value `a'.
 *----------------------------------------------------------------------------*/
 
-INLINE bits64 extractFloat128Frac0( float128 a )
+INLINE uint64_t extractFloat128Frac0( float128 a )
 {
 
     return a.high & LIT64( 0x0000FFFFFFFFFFFF );
@@ -873,11 +911,11 @@ INLINE flag extractFloat128Sign( float128 a )
 
 static void
  normalizeFloat128Subnormal(
-     bits64 aSig0,
-     bits64 aSig1,
+     uint64_t aSig0,
+     uint64_t aSig1,
      int32 *zExpPtr,
-     bits64 *zSig0Ptr,
-     bits64 *zSig1Ptr
+     uint64_t *zSig0Ptr,
+     uint64_t *zSig1Ptr
  )
 {
     int8 shiftCount;
@@ -916,12 +954,12 @@ static void
 *----------------------------------------------------------------------------*/
 
 INLINE float128
- packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
+ packFloat128( flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 )
 {
     float128 z;
 
     z.low = zSig1;
-    z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
+    z.high = ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<48 ) + zSig0;
     return z;
 
 }
@@ -949,14 +987,14 @@ INLINE float128
 
 static float128
  roundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 STATUS_PARAM)
+     flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1, uint64_t zSig2 STATUS_PARAM)
 {
     int8 roundingMode;
     flag roundNearestEven, increment, isTiny;
 
     roundingMode = STATUS(float_rounding_mode);
     roundNearestEven = ( roundingMode == float_round_nearest_even );
-    increment = ( (sbits64) zSig2 < 0 );
+    increment = ( (int64_t) zSig2 < 0 );
     if ( ! roundNearestEven ) {
         if ( roundingMode == float_round_to_zero ) {
             increment = 0;
@@ -970,7 +1008,7 @@ static float128
             }
         }
     }
-    if ( 0x7FFD <= (bits32) zExp ) {
+    if ( 0x7FFD <= (uint32_t) zExp ) {
         if (    ( 0x7FFD < zExp )
              || (    ( zExp == 0x7FFD )
                   && eq128(
@@ -998,7 +1036,10 @@ static float128
             return packFloat128( zSign, 0x7FFF, 0, 0 );
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat128(zSign, 0, 0, 0);
+            }
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -1014,7 +1055,7 @@ static float128
             zExp = 0;
             if ( isTiny && zSig2 ) float_raise( float_flag_underflow STATUS_VAR);
             if ( roundNearestEven ) {
-                increment = ( (sbits64) zSig2 < 0 );
+                increment = ( (int64_t) zSig2 < 0 );
             }
             else {
                 if ( zSign ) {
@@ -1050,10 +1091,10 @@ static float128
 
 static float128
  normalizeRoundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 STATUS_PARAM)
+     flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 STATUS_PARAM)
 {
     int8 shiftCount;
-    bits64 zSig2;
+    uint64_t zSig2;
 
     if ( zSig0 == 0 ) {
         zSig0 = zSig1;
@@ -1074,8 +1115,6 @@ static float128
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 32-bit two's complement integer `a'
 | to the single-precision floating-point format.  The conversion is performed
@@ -1087,7 +1126,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM )
     flag zSign;
 
     if ( a == 0 ) return float32_zero;
-    if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+    if ( a == (int32_t) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
     zSign = ( a < 0 );
     return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR );
 
@@ -1104,7 +1143,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM )
     flag zSign;
     uint32 absA;
     int8 shiftCount;
-    bits64 zSig;
+    uint64_t zSig;
 
     if ( a == 0 ) return float64_zero;
     zSign = ( a < 0 );
@@ -1115,8 +1154,6 @@ float64 int32_to_float64( int32 a STATUS_PARAM )
 
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 32-bit two's complement integer `a'
 | to the extended double-precision floating-point format.  The conversion
@@ -1129,7 +1166,7 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM )
     flag zSign;
     uint32 absA;
     int8 shiftCount;
-    bits64 zSig;
+    uint64_t zSig;
 
     if ( a == 0 ) return packFloatx80( 0, 0, 0 );
     zSign = ( a < 0 );
@@ -1140,10 +1177,6 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM )
 
 }
 
-#endif
-
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 32-bit two's complement integer `a' to
 | the quadruple-precision floating-point format.  The conversion is performed
@@ -1155,7 +1188,7 @@ float128 int32_to_float128( int32 a STATUS_PARAM )
     flag zSign;
     uint32 absA;
     int8 shiftCount;
-    bits64 zSig0;
+    uint64_t zSig0;
 
     if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
     zSign = ( a < 0 );
@@ -1166,8 +1199,6 @@ float128 int32_to_float128( int32 a STATUS_PARAM )
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 64-bit two's complement integer `a'
 | to the single-precision floating-point format.  The conversion is performed
@@ -1232,7 +1263,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM )
     flag zSign;
 
     if ( a == 0 ) return float64_zero;
-    if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) {
+    if ( a == (int64_t) LIT64( 0x8000000000000000 ) ) {
         return packFloat64( 1, 0x43E, 0 );
     }
     zSign = ( a < 0 );
@@ -1247,8 +1278,6 @@ float64 uint64_to_float64( uint64 a STATUS_PARAM )
 
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 64-bit two's complement integer `a'
 | to the extended double-precision floating-point format.  The conversion
@@ -1270,10 +1299,6 @@ floatx80 int64_to_floatx80( int64 a STATUS_PARAM )
 
 }
 
-#endif
-
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 64-bit two's complement integer `a' to
 | the quadruple-precision floating-point format.  The conversion is performed
@@ -1286,7 +1311,7 @@ float128 int64_to_float128( int64 a STATUS_PARAM )
     uint64 absA;
     int8 shiftCount;
     int32 zExp;
-    bits64 zSig0, zSig1;
+    uint64_t zSig0, zSig1;
 
     if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
     zSign = ( a < 0 );
@@ -1307,8 +1332,6 @@ float128 int64_to_float128( int64 a STATUS_PARAM )
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the single-precision floating-point value
 | `a' to the 32-bit two's complement integer format.  The conversion is
@@ -1323,8 +1346,8 @@ int32 float32_to_int32( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits32 aSig;
-    bits64 aSig64;
+    uint32_t aSig;
+    uint64_t aSig64;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
@@ -1354,7 +1377,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits32 aSig;
+    uint32_t aSig;
     int32 z;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
@@ -1367,7 +1390,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
             float_raise( float_flag_invalid STATUS_VAR);
             if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
         }
-        return (sbits32) 0x80000000;
+        return (int32_t) 0x80000000;
     }
     else if ( aExp <= 0x7E ) {
         if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
@@ -1375,7 +1398,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
     }
     aSig = ( aSig | 0x00800000 )<<8;
     z = aSig>>( - shiftCount );
-    if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+    if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
     }
     if ( aSign ) z = - z;
@@ -1397,7 +1420,7 @@ int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits32 aSig;
+    uint32_t aSig;
     int32 z;
 
     aSig = extractFloat32Frac( a );
@@ -1411,7 +1434,7 @@ int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
                 return 0x7FFF;
             }
         }
-        return (sbits32) 0xffff8000;
+        return (int32_t) 0xffff8000;
     }
     else if ( aExp <= 0x7E ) {
         if ( aExp | aSig ) {
@@ -1422,7 +1445,7 @@ int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
     shiftCount -= 0x10;
     aSig = ( aSig | 0x00800000 )<<8;
     z = aSig>>( - shiftCount );
-    if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+    if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
     }
     if ( aSign ) {
@@ -1446,8 +1469,8 @@ int64 float32_to_int64( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits32 aSig;
-    bits64 aSig64, aSigExtra;
+    uint32_t aSig;
+    uint64_t aSig64, aSigExtra;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
@@ -1459,7 +1482,7 @@ int64 float32_to_int64( float32 a STATUS_PARAM )
         if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
             return LIT64( 0x7FFFFFFFFFFFFFFF );
         }
-        return (sbits64) LIT64( 0x8000000000000000 );
+        return (int64_t) LIT64( 0x8000000000000000 );
     }
     if ( aExp ) aSig |= 0x00800000;
     aSig64 = aSig;
@@ -1483,8 +1506,8 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits32 aSig;
-    bits64 aSig64;
+    uint32_t aSig;
+    uint64_t aSig64;
     int64 z;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
@@ -1499,7 +1522,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
         }
-        return (sbits64) LIT64( 0x8000000000000000 );
+        return (int64_t) LIT64( 0x8000000000000000 );
     }
     else if ( aExp <= 0x7E ) {
         if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
@@ -1508,7 +1531,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
     aSig64 = aSig | 0x00800000;
     aSig64 <<= 40;
     z = aSig64>>( - shiftCount );
-    if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) {
+    if ( (uint64_t) ( aSig64<<( shiftCount & 63 ) ) ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
     }
     if ( aSign ) z = - z;
@@ -1527,14 +1550,14 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
+    uint32_t aSig;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
     if ( aExp == 0xFF ) {
-        if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ));
+        if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloat64( aSign, 0x7FF, 0 );
     }
     if ( aExp == 0 ) {
@@ -1542,12 +1565,10 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
         normalizeFloat32Subnormal( aSig, &aExp, &aSig );
         --aExp;
     }
-    return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 );
+    return packFloat64( aSign, aExp + 0x380, ( (uint64_t) aSig )<<29 );
 
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the single-precision floating-point value
 | `a' to the extended double-precision floating-point format.  The conversion
@@ -1559,14 +1580,14 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
+    uint32_t aSig;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
     if ( aExp == 0xFF ) {
-        if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) );
+        if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
     if ( aExp == 0 ) {
@@ -1574,14 +1595,10 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
         normalizeFloat32Subnormal( aSig, &aExp, &aSig );
     }
     aSig |= 0x00800000;
-    return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 );
+    return packFloatx80( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<40 );
 
 }
 
-#endif
-
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the single-precision floating-point value
 | `a' to the double-precision floating-point format.  The conversion is
@@ -1593,14 +1610,14 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
+    uint32_t aSig;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
     if ( aExp == 0xFF ) {
-        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) );
+        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloat128( aSign, 0x7FFF, 0, 0 );
     }
     if ( aExp == 0 ) {
@@ -1608,12 +1625,10 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
         normalizeFloat32Subnormal( aSig, &aExp, &aSig );
         --aExp;
     }
-    return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
+    return packFloat128( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<25, 0 );
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Rounds the single-precision floating-point value `a' to an integer, and
 | returns the result as a single-precision floating-point value.  The
@@ -1625,9 +1640,9 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
 {
     flag aSign;
     int16 aExp;
-    bits32 lastBitMask, roundBitsMask;
+    uint32_t lastBitMask, roundBitsMask;
     int8 roundingMode;
-    bits32 z;
+    uint32_t z;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
     aExp = extractFloat32Exp( a );
@@ -1638,7 +1653,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
         return a;
     }
     if ( aExp <= 0x7E ) {
-        if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a;
+        if ( (uint32_t) ( float32_val(a)<<1 ) == 0 ) return a;
         STATUS(float_exception_flags) |= float_flag_inexact;
         aSign = extractFloat32Sign( a );
         switch ( STATUS(float_rounding_mode) ) {
@@ -1685,7 +1700,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
 static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
 {
     int16 aExp, bExp, zExp;
-    bits32 aSig, bSig, zSig;
+    uint32_t aSig, bSig, zSig;
     int16 expDiff;
 
     aSig = extractFloat32Frac( a );
@@ -1729,7 +1744,12 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
             return a;
         }
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                if (aSig | bSig) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat32(zSign, 0, 0);
+            }
             return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
         }
         zSig = 0x40000000 + aSig + bSig;
@@ -1739,7 +1759,7 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
     aSig |= 0x20000000;
     zSig = ( aSig + bSig )<<1;
     --zExp;
-    if ( (sbits32) zSig < 0 ) {
+    if ( (int32_t) zSig < 0 ) {
         zSig = aSig + bSig;
         ++zExp;
     }
@@ -1759,7 +1779,7 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
 static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
 {
     int16 aExp, bExp, zExp;
-    bits32 aSig, bSig, zSig;
+    uint32_t aSig, bSig, zSig;
     int16 expDiff;
 
     aSig = extractFloat32Frac( a );
@@ -1879,9 +1899,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int16 aExp, bExp, zExp;
-    bits32 aSig, bSig;
-    bits64 zSig64;
-    bits32 zSig;
+    uint32_t aSig, bSig;
+    uint64_t zSig64;
+    uint32_t zSig;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
@@ -1922,9 +1942,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM )
     zExp = aExp + bExp - 0x7F;
     aSig = ( aSig | 0x00800000 )<<7;
     bSig = ( bSig | 0x00800000 )<<8;
-    shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 );
+    shift64RightJamming( ( (uint64_t) aSig ) * bSig, 32, &zSig64 );
     zSig = zSig64;
-    if ( 0 <= (sbits32) ( zSig<<1 ) ) {
+    if ( 0 <= (int32_t) ( zSig<<1 ) ) {
         zSig <<= 1;
         --zExp;
     }
@@ -1942,7 +1962,7 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int16 aExp, bExp, zExp;
-    bits32 aSig, bSig, zSig;
+    uint32_t aSig, bSig, zSig;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -1988,9 +2008,9 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM )
         aSig >>= 1;
         ++zExp;
     }
-    zSig = ( ( (bits64) aSig )<<32 ) / bSig;
+    zSig = ( ( (uint64_t) aSig )<<32 ) / bSig;
     if ( ( zSig & 0x3F ) == 0 ) {
-        zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 );
+        zSig |= ( (uint64_t) bSig * zSig != ( (uint64_t) aSig )<<32 );
     }
     return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR );
 
@@ -2006,11 +2026,11 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, zSign;
     int16 aExp, bExp, expDiff;
-    bits32 aSig, bSig;
-    bits32 q;
-    bits64 aSig64, bSig64, q64;
-    bits32 alternateASig;
-    sbits32 sigMean;
+    uint32_t aSig, bSig;
+    uint32_t q;
+    uint64_t aSig64, bSig64, q64;
+    uint32_t alternateASig;
+    int32_t sigMean;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2054,7 +2074,7 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
         q = ( bSig <= aSig );
         if ( q ) aSig -= bSig;
         if ( 0 < expDiff ) {
-            q = ( ( (bits64) aSig )<<32 ) / bSig;
+            q = ( ( (uint64_t) aSig )<<32 ) / bSig;
             q >>= 32 - expDiff;
             bSig >>= 2;
             aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
@@ -2066,8 +2086,8 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
     }
     else {
         if ( bSig <= aSig ) aSig -= bSig;
-        aSig64 = ( (bits64) aSig )<<40;
-        bSig64 = ( (bits64) bSig )<<40;
+        aSig64 = ( (uint64_t) aSig )<<40;
+        bSig64 = ( (uint64_t) bSig )<<40;
         expDiff -= 64;
         while ( 0 < expDiff ) {
             q64 = estimateDiv128To64( aSig64, 0, bSig64 );
@@ -2086,17 +2106,224 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
         alternateASig = aSig;
         ++q;
         aSig -= bSig;
-    } while ( 0 <= (sbits32) aSig );
+    } while ( 0 <= (int32_t) aSig );
     sigMean = aSig + alternateASig;
     if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
         aSig = alternateASig;
     }
-    zSign = ( (sbits32) aSig < 0 );
+    zSign = ( (int32_t) aSig < 0 );
     if ( zSign ) aSig = - aSig;
     return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR );
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the single-precision floating-point values
+| `a' and `b' then adding 'c', with no intermediate rounding step after the
+| multiplication.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic 754-2008.
+| The flags argument allows the caller to select negation of the
+| addend, the intermediate product, or the final result. (The difference
+| between this and having the caller do a separate negation is that negating
+| externally will flip the sign bit on NaNs.)
+*----------------------------------------------------------------------------*/
+
+float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
+{
+    flag aSign, bSign, cSign, zSign;
+    int aExp, bExp, cExp, pExp, zExp, expDiff;
+    uint32_t aSig, bSig, cSig;
+    flag pInf, pZero, pSign;
+    uint64_t pSig64, cSig64, zSig64;
+    uint32_t pSig;
+    int shiftcount;
+    flag signflip, infzero;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+    c = float32_squash_input_denormal(c STATUS_VAR);
+    aSig = extractFloat32Frac(a);
+    aExp = extractFloat32Exp(a);
+    aSign = extractFloat32Sign(a);
+    bSig = extractFloat32Frac(b);
+    bExp = extractFloat32Exp(b);
+    bSign = extractFloat32Sign(b);
+    cSig = extractFloat32Frac(c);
+    cExp = extractFloat32Exp(c);
+    cSign = extractFloat32Sign(c);
+
+    infzero = ((aExp == 0 && aSig == 0 && bExp == 0xff && bSig == 0) ||
+               (aExp == 0xff && aSig == 0 && bExp == 0 && bSig == 0));
+
+    /* It is implementation-defined whether the cases of (0,inf,qnan)
+     * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
+     * they return if they do), so we have to hand this information
+     * off to the target-specific pick-a-NaN routine.
+     */
+    if (((aExp == 0xff) && aSig) ||
+        ((bExp == 0xff) && bSig) ||
+        ((cExp == 0xff) && cSig)) {
+        return propagateFloat32MulAddNaN(a, b, c, infzero STATUS_VAR);
+    }
+
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+
+    if (flags & float_muladd_negate_c) {
+        cSign ^= 1;
+    }
+
+    signflip = (flags & float_muladd_negate_result) ? 1 : 0;
+
+    /* Work out the sign and type of the product */
+    pSign = aSign ^ bSign;
+    if (flags & float_muladd_negate_product) {
+        pSign ^= 1;
+    }
+    pInf = (aExp == 0xff) || (bExp == 0xff);
+    pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
+
+    if (cExp == 0xff) {
+        if (pInf && (pSign ^ cSign)) {
+            /* addition of opposite-signed infinities => InvalidOperation */
+            float_raise(float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        /* Otherwise generate an infinity of the same sign */
+        return packFloat32(cSign ^ signflip, 0xff, 0);
+    }
+
+    if (pInf) {
+        return packFloat32(pSign ^ signflip, 0xff, 0);
+    }
+
+    if (pZero) {
+        if (cExp == 0) {
+            if (cSig == 0) {
+                /* Adding two exact zeroes */
+                if (pSign == cSign) {
+                    zSign = pSign;
+                } else if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign = 1;
+                } else {
+                    zSign = 0;
+                }
+                return packFloat32(zSign ^ signflip, 0, 0);
+            }
+            /* Exact zero plus a denorm */
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat32(cSign ^ signflip, 0, 0);
+            }
+        }
+        /* Zero plus something non-zero : just return the something */
+        return c ^ (signflip << 31);
+    }
+
+    if (aExp == 0) {
+        normalizeFloat32Subnormal(aSig, &aExp, &aSig);
+    }
+    if (bExp == 0) {
+        normalizeFloat32Subnormal(bSig, &bExp, &bSig);
+    }
+
+    /* Calculate the actual result a * b + c */
+
+    /* Multiply first; this is easy. */
+    /* NB: we subtract 0x7e where float32_mul() subtracts 0x7f
+     * because we want the true exponent, not the "one-less-than"
+     * flavour that roundAndPackFloat32() takes.
+     */
+    pExp = aExp + bExp - 0x7e;
+    aSig = (aSig | 0x00800000) << 7;
+    bSig = (bSig | 0x00800000) << 8;
+    pSig64 = (uint64_t)aSig * bSig;
+    if ((int64_t)(pSig64 << 1) >= 0) {
+        pSig64 <<= 1;
+        pExp--;
+    }
+
+    zSign = pSign ^ signflip;
+
+    /* Now pSig64 is the significand of the multiply, with the explicit bit in
+     * position 62.
+     */
+    if (cExp == 0) {
+        if (!cSig) {
+            /* Throw out the special case of c being an exact zero now */
+            shift64RightJamming(pSig64, 32, &pSig64);
+            pSig = pSig64;
+            return roundAndPackFloat32(zSign, pExp - 1,
+                                       pSig STATUS_VAR);
+        }
+        normalizeFloat32Subnormal(cSig, &cExp, &cSig);
+    }
+
+    cSig64 = (uint64_t)cSig << (62 - 23);
+    cSig64 |= LIT64(0x4000000000000000);
+    expDiff = pExp - cExp;
+
+    if (pSign == cSign) {
+        /* Addition */
+        if (expDiff > 0) {
+            /* scale c to match p */
+            shift64RightJamming(cSig64, expDiff, &cSig64);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            /* scale p to match c */
+            shift64RightJamming(pSig64, -expDiff, &pSig64);
+            zExp = cExp;
+        } else {
+            /* no scaling needed */
+            zExp = cExp;
+        }
+        /* Add significands and make sure explicit bit ends up in posn 62 */
+        zSig64 = pSig64 + cSig64;
+        if ((int64_t)zSig64 < 0) {
+            shift64RightJamming(zSig64, 1, &zSig64);
+        } else {
+            zExp--;
+        }
+    } else {
+        /* Subtraction */
+        if (expDiff > 0) {
+            shift64RightJamming(cSig64, expDiff, &cSig64);
+            zSig64 = pSig64 - cSig64;
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            shift64RightJamming(pSig64, -expDiff, &pSig64);
+            zSig64 = cSig64 - pSig64;
+            zExp = cExp;
+            zSign ^= 1;
+        } else {
+            zExp = pExp;
+            if (cSig64 < pSig64) {
+                zSig64 = pSig64 - cSig64;
+            } else if (pSig64 < cSig64) {
+                zSig64 = cSig64 - pSig64;
+                zSign ^= 1;
+            } else {
+                /* Exact zero */
+                zSign = signflip;
+                if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign ^= 1;
+                }
+                return packFloat32(zSign, 0, 0);
+            }
+        }
+        --zExp;
+        /* Normalize to put the explicit bit back into bit 62. */
+        shiftcount = countLeadingZeros64(zSig64) - 1;
+        zSig64 <<= shiftcount;
+        zExp -= shiftcount;
+    }
+    shift64RightJamming(zSig64, 32, &zSig64);
+    return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
+}
+
+
 /*----------------------------------------------------------------------------
 | Returns the square root of the single-precision floating-point value `a'.
 | The operation is performed according to the IEC/IEEE Standard for Binary
@@ -2107,8 +2334,8 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, zExp;
-    bits32 aSig, zSig;
-    bits64 rem, term;
+    uint32_t aSig, zSig;
+    uint64_t rem, term;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
@@ -2138,11 +2365,11 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
             goto roundAndPack;
         }
         aSig >>= aExp & 1;
-        term = ( (bits64) zSig ) * zSig;
-        rem = ( ( (bits64) aSig )<<32 ) - term;
-        while ( (sbits64) rem < 0 ) {
+        term = ( (uint64_t) zSig ) * zSig;
+        rem = ( ( (uint64_t) aSig )<<32 ) - term;
+        while ( (int64_t) rem < 0 ) {
             --zSig;
-            rem += ( ( (bits64) zSig )<<1 ) | 1;
+            rem += ( ( (uint64_t) zSig )<<1 ) | 1;
         }
         zSig |= ( rem != 0 );
     }
@@ -2172,28 +2399,28 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
 
 static const float64 float32_exp2_coefficients[15] =
 {
-    make_float64( 0x3ff0000000000000ll ), /*  1 */
-    make_float64( 0x3fe0000000000000ll ), /*  2 */
-    make_float64( 0x3fc5555555555555ll ), /*  3 */
-    make_float64( 0x3fa5555555555555ll ), /*  4 */
-    make_float64( 0x3f81111111111111ll ), /*  5 */
-    make_float64( 0x3f56c16c16c16c17ll ), /*  6 */
-    make_float64( 0x3f2a01a01a01a01all ), /*  7 */
-    make_float64( 0x3efa01a01a01a01all ), /*  8 */
-    make_float64( 0x3ec71de3a556c734ll ), /*  9 */
-    make_float64( 0x3e927e4fb7789f5cll ), /* 10 */
-    make_float64( 0x3e5ae64567f544e4ll ), /* 11 */
-    make_float64( 0x3e21eed8eff8d898ll ), /* 12 */
-    make_float64( 0x3de6124613a86d09ll ), /* 13 */
-    make_float64( 0x3da93974a8c07c9dll ), /* 14 */
-    make_float64( 0x3d6ae7f3e733b81fll ), /* 15 */
+    const_float64( 0x3ff0000000000000ll ), /*  1 */
+    const_float64( 0x3fe0000000000000ll ), /*  2 */
+    const_float64( 0x3fc5555555555555ll ), /*  3 */
+    const_float64( 0x3fa5555555555555ll ), /*  4 */
+    const_float64( 0x3f81111111111111ll ), /*  5 */
+    const_float64( 0x3f56c16c16c16c17ll ), /*  6 */
+    const_float64( 0x3f2a01a01a01a01all ), /*  7 */
+    const_float64( 0x3efa01a01a01a01all ), /*  8 */
+    const_float64( 0x3ec71de3a556c734ll ), /*  9 */
+    const_float64( 0x3e927e4fb7789f5cll ), /* 10 */
+    const_float64( 0x3e5ae64567f544e4ll ), /* 11 */
+    const_float64( 0x3e21eed8eff8d898ll ), /* 12 */
+    const_float64( 0x3de6124613a86d09ll ), /* 13 */
+    const_float64( 0x3da93974a8c07c9dll ), /* 14 */
+    const_float64( 0x3d6ae7f3e733b81fll ), /* 15 */
 };
 
 float32 float32_exp2( float32 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
+    uint32_t aSig;
     float64 r, x, xn;
     int i;
     a = float32_squash_input_denormal(a STATUS_VAR);
@@ -2241,7 +2468,7 @@ float32 float32_log2( float32 a STATUS_PARAM )
 {
     flag aSign, zSign;
     int16 aExp;
-    bits32 aSig, zSig, i;
+    uint32_t aSig, zSig, i;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
@@ -2267,7 +2494,7 @@ float32 float32_log2( float32 a STATUS_PARAM )
     zSig = aExp << 23;
 
     for (i = 1 << 22; i > 0; i >>= 1) {
-        aSig = ( (bits64)aSig * aSig ) >> 23;
+        aSig = ( (uint64_t)aSig * aSig ) >> 23;
         if ( aSig & 0x01000000 ) {
             aSig >>= 1;
             zSig |= i;
@@ -2282,39 +2509,39 @@ 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) ) ||
-            ( (bits32) ( ( 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 )
 {
     flag aSign, bSign;
-    bits32 av, bv;
+    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2328,21 +2555,22 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
     bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
-    if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
+    if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
     return ( av == bv ) || ( aSign ^ ( av < bv ) );
 
 }
 
 /*----------------------------------------------------------------------------
 | 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 )
 {
     flag aSign, bSign;
-    bits32 av, bv;
+    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2356,21 +2584,20 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
     bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
-    if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
+    if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 );
     return ( av != bv ) && ( aSign ^ ( av < bv ) );
 
 }
 
 /*----------------------------------------------------------------------------
-| 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 )
 {
-    bits32 av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2378,12 +2605,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 ) || ( (bits32) ( ( 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 );
 }
 
 /*----------------------------------------------------------------------------
@@ -2396,7 +2644,7 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
 int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
-    bits32 av, bv;
+    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2412,7 +2660,7 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
     bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
-    if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
+    if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
     return ( av == bv ) || ( aSign ^ ( av < bv ) );
 
 }
@@ -2427,7 +2675,7 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
 int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
-    bits32 av, bv;
+    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2443,11 +2691,34 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
     bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
-    if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
+    if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 );
     return ( av != bv ) && ( aSign ^ ( av < bv ) );
 
 }
 
+/*----------------------------------------------------------------------------
+| 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
@@ -2462,7 +2733,7 @@ int32 float64_to_int32( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits64 aSig;
+    uint64_t aSig;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
@@ -2490,7 +2761,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits64 aSig, savedASig;
+    uint64_t aSig, savedASig;
     int32 z;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
@@ -2514,7 +2785,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
     if ( ( z < 0 ) ^ aSign ) {
  invalid:
         float_raise( float_flag_invalid STATUS_VAR);
-        return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
     }
     if ( ( aSig<<shiftCount ) != savedASig ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
@@ -2537,7 +2808,7 @@ int16 float64_to_int16_round_to_zero( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits64 aSig, savedASig;
+    uint64_t aSig, savedASig;
     int32 z;
 
     aSig = extractFloat64Frac( a );
@@ -2566,7 +2837,7 @@ int16 float64_to_int16_round_to_zero( float64 a STATUS_PARAM )
     if ( ( (int16_t)z < 0 ) ^ aSign ) {
  invalid:
         float_raise( float_flag_invalid STATUS_VAR);
-        return aSign ? (sbits32) 0xffff8000 : 0x7FFF;
+        return aSign ? (int32_t) 0xffff8000 : 0x7FFF;
     }
     if ( ( aSig<<shiftCount ) != savedASig ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
@@ -2588,7 +2859,7 @@ int64 float64_to_int64( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits64 aSig, aSigExtra;
+    uint64_t aSig, aSigExtra;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
@@ -2605,7 +2876,7 @@ int64 float64_to_int64( float64 a STATUS_PARAM )
                ) {
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
-            return (sbits64) LIT64( 0x8000000000000000 );
+            return (int64_t) LIT64( 0x8000000000000000 );
         }
         aSigExtra = 0;
         aSig <<= - shiftCount;
@@ -2631,7 +2902,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, shiftCount;
-    bits64 aSig;
+    uint64_t aSig;
     int64 z;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
@@ -2651,7 +2922,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
                     return LIT64( 0x7FFFFFFFFFFFFFFF );
                 }
             }
-            return (sbits64) LIT64( 0x8000000000000000 );
+            return (int64_t) LIT64( 0x8000000000000000 );
         }
         z = aSig<<shiftCount;
     }
@@ -2661,7 +2932,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
             return 0;
         }
         z = aSig>>( - shiftCount );
-        if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
+        if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) {
             STATUS(float_exception_flags) |= float_flag_inexact;
         }
     }
@@ -2681,15 +2952,15 @@ float32 float64_to_float32( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits64 aSig;
-    bits32 zSig;
+    uint64_t aSig;
+    uint32_t zSig;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
     if ( aExp == 0x7FF ) {
-        if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) );
+        if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloat32( aSign, 0xFF, 0 );
     }
     shift64RightJamming( aSig, 22, &aSig );
@@ -2713,29 +2984,28 @@ float32 float64_to_float32( float64 a STATUS_PARAM )
 | than the desired result exponent whenever `zSig' is a complete, normalized
 | significand.
 *----------------------------------------------------------------------------*/
-static bits16 packFloat16(flag zSign, int16 zExp, bits16 zSig)
+static float16 packFloat16(flag zSign, int16 zExp, uint16_t zSig)
 {
-    return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig;
+    return make_float16(
+        (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig);
 }
 
 /* Half precision floats come in two formats: standard IEEE and "ARM" format.
    The latter gains extra exponent range by omitting the NaN/Inf encodings.  */
-  
-float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM )
+
+float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM)
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
+    uint32_t aSig;
 
-    aSign = a >> 15;
-    aExp = (a >> 10) & 0x1f;
-    aSig = a & 0x3ff;
+    aSign = extractFloat16Sign(a);
+    aExp = extractFloat16Exp(a);
+    aSig = extractFloat16Frac(a);
 
     if (aExp == 0x1f && ieee) {
         if (aSig) {
-            /* Make sure correct exceptions are raised.  */
-            float32ToCommonNaN(a STATUS_VAR);
-            aSig |= 0x200;
+            return commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) STATUS_VAR);
         }
         return packFloat32(aSign, 0xff, aSig << 13);
     }
@@ -2753,13 +3023,13 @@ float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM )
     return packFloat32( aSign, aExp + 0x70, aSig << 13);
 }
 
-bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
+float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM)
 {
     flag aSign;
     int16 aExp;
-    bits32 aSig;
-    bits32 mask;
-    bits32 increment;
+    uint32_t aSig;
+    uint32_t mask;
+    uint32_t increment;
     int8 roundingMode;
     a = float32_squash_input_denormal(a STATUS_VAR);
 
@@ -2768,24 +3038,30 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
     aSign = extractFloat32Sign( a );
     if ( aExp == 0xFF ) {
         if (aSig) {
-            /* Make sure correct exceptions are raised.  */
-            float32ToCommonNaN(a STATUS_VAR);
-            aSig |= 0x00400000;
+            /* Input is a NaN */
+            float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+            if (!ieee) {
+                return packFloat16(aSign, 0, 0);
+            }
+            return r;
+        }
+        /* Infinity */
+        if (!ieee) {
+            float_raise(float_flag_invalid STATUS_VAR);
+            return packFloat16(aSign, 0x1f, 0x3ff);
         }
-        return packFloat16(aSign, 0x1f, aSig >> 13);
+        return packFloat16(aSign, 0x1f, 0);
     }
-    if (aExp == 0 && aSign == 0) {
+    if (aExp == 0 && aSig == 0) {
         return packFloat16(aSign, 0, 0);
     }
     /* Decimal point between bits 22 and 23.  */
     aSig |= 0x00800000;
     aExp -= 0x7f;
     if (aExp < -14) {
-        mask = 0x007fffff;
-        if (aExp < -24) {
-            aExp = -25;
-        } else {
-            mask >>= 24 + aExp;
+        mask = 0x00ffffff;
+        if (aExp >= -24) {
+            mask >>= 25 + aExp;
         }
     } else {
         mask = 0x00001fff;
@@ -2827,7 +3103,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
         }
     } else {
         if (aExp > 16) {
-            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR);
             return packFloat16(aSign, 0x1f, 0x3ff);
         }
     }
@@ -2841,8 +3117,6 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
     return packFloat16(aSign, aExp + 14, aSig >> 13);
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the double-precision floating-point value
 | `a' to the extended double-precision floating-point format.  The conversion
@@ -2854,14 +3128,14 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits64 aSig;
+    uint64_t aSig;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
     if ( aExp == 0x7FF ) {
-        if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) );
+        if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
     if ( aExp == 0 ) {
@@ -2874,10 +3148,6 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
 
 }
 
-#endif
-
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the double-precision floating-point value
 | `a' to the quadruple-precision floating-point format.  The conversion is
@@ -2889,14 +3159,14 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits64 aSig, zSig0, zSig1;
+    uint64_t aSig, zSig0, zSig1;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
     if ( aExp == 0x7FF ) {
-        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) );
+        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         return packFloat128( aSign, 0x7FFF, 0, 0 );
     }
     if ( aExp == 0 ) {
@@ -2909,8 +3179,6 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Rounds the double-precision floating-point value `a' to an integer, and
 | returns the result as a double-precision floating-point value.  The
@@ -2922,9 +3190,9 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits64 lastBitMask, roundBitsMask;
+    uint64_t lastBitMask, roundBitsMask;
     int8 roundingMode;
-    bits64 z;
+    uint64_t z;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aExp = extractFloat64Exp( a );
@@ -2935,7 +3203,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
         return a;
     }
     if ( aExp < 0x3FF ) {
-        if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a;
+        if ( (uint64_t) ( float64_val(a)<<1 ) == 0 ) return a;
         STATUS(float_exception_flags) |= float_flag_inexact;
         aSign = extractFloat64Sign( a );
         switch ( STATUS(float_rounding_mode) ) {
@@ -2995,7 +3263,7 @@ float64 float64_trunc_to_int( float64 a STATUS_PARAM)
 static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
 {
     int16 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig;
+    uint64_t aSig, bSig, zSig;
     int16 expDiff;
 
     aSig = extractFloat64Frac( a );
@@ -3039,7 +3307,12 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
             return a;
         }
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                if (aSig | bSig) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat64(zSign, 0, 0);
+            }
             return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
         }
         zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
@@ -3049,7 +3322,7 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
     aSig |= LIT64( 0x2000000000000000 );
     zSig = ( aSig + bSig )<<1;
     --zExp;
-    if ( (sbits64) zSig < 0 ) {
+    if ( (int64_t) zSig < 0 ) {
         zSig = aSig + bSig;
         ++zExp;
     }
@@ -3069,7 +3342,7 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
 static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
 {
     int16 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig;
+    uint64_t aSig, bSig, zSig;
     int16 expDiff;
 
     aSig = extractFloat64Frac( a );
@@ -3189,7 +3462,7 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int16 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig0, zSig1;
+    uint64_t aSig, bSig, zSig0, zSig1;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
@@ -3232,7 +3505,7 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM )
     bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
     mul64To128( aSig, bSig, &zSig0, &zSig1 );
     zSig0 |= ( zSig1 != 0 );
-    if ( 0 <= (sbits64) ( zSig0<<1 ) ) {
+    if ( 0 <= (int64_t) ( zSig0<<1 ) ) {
         zSig0 <<= 1;
         --zExp;
     }
@@ -3250,9 +3523,9 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int16 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig;
-    bits64 rem0, rem1;
-    bits64 term0, term1;
+    uint64_t aSig, bSig, zSig;
+    uint64_t rem0, rem1;
+    uint64_t term0, term1;
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
 
@@ -3302,7 +3575,7 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM )
     if ( ( zSig & 0x1FF ) <= 2 ) {
         mul64To128( bSig, zSig, &term0, &term1 );
         sub128( aSig, 0, term0, term1, &rem0, &rem1 );
-        while ( (sbits64) rem0 < 0 ) {
+        while ( (int64_t) rem0 < 0 ) {
             --zSig;
             add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
         }
@@ -3322,9 +3595,9 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, zSign;
     int16 aExp, bExp, expDiff;
-    bits64 aSig, bSig;
-    bits64 q, alternateASig;
-    sbits64 sigMean;
+    uint64_t aSig, bSig;
+    uint64_t q, alternateASig;
+    int64_t sigMean;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
@@ -3387,17 +3660,237 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM )
         alternateASig = aSig;
         ++q;
         aSig -= bSig;
-    } while ( 0 <= (sbits64) aSig );
+    } while ( 0 <= (int64_t) aSig );
     sigMean = aSig + alternateASig;
     if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
         aSig = alternateASig;
     }
-    zSign = ( (sbits64) aSig < 0 );
+    zSign = ( (int64_t) aSig < 0 );
     if ( zSign ) aSig = - aSig;
     return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR );
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the double-precision floating-point values
+| `a' and `b' then adding 'c', with no intermediate rounding step after the
+| multiplication.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic 754-2008.
+| The flags argument allows the caller to select negation of the
+| addend, the intermediate product, or the final result. (The difference
+| between this and having the caller do a separate negation is that negating
+| externally will flip the sign bit on NaNs.)
+*----------------------------------------------------------------------------*/
+
+float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
+{
+    flag aSign, bSign, cSign, zSign;
+    int aExp, bExp, cExp, pExp, zExp, expDiff;
+    uint64_t aSig, bSig, cSig;
+    flag pInf, pZero, pSign;
+    uint64_t pSig0, pSig1, cSig0, cSig1, zSig0, zSig1;
+    int shiftcount;
+    flag signflip, infzero;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+    c = float64_squash_input_denormal(c STATUS_VAR);
+    aSig = extractFloat64Frac(a);
+    aExp = extractFloat64Exp(a);
+    aSign = extractFloat64Sign(a);
+    bSig = extractFloat64Frac(b);
+    bExp = extractFloat64Exp(b);
+    bSign = extractFloat64Sign(b);
+    cSig = extractFloat64Frac(c);
+    cExp = extractFloat64Exp(c);
+    cSign = extractFloat64Sign(c);
+
+    infzero = ((aExp == 0 && aSig == 0 && bExp == 0x7ff && bSig == 0) ||
+               (aExp == 0x7ff && aSig == 0 && bExp == 0 && bSig == 0));
+
+    /* It is implementation-defined whether the cases of (0,inf,qnan)
+     * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
+     * they return if they do), so we have to hand this information
+     * off to the target-specific pick-a-NaN routine.
+     */
+    if (((aExp == 0x7ff) && aSig) ||
+        ((bExp == 0x7ff) && bSig) ||
+        ((cExp == 0x7ff) && cSig)) {
+        return propagateFloat64MulAddNaN(a, b, c, infzero STATUS_VAR);
+    }
+
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+
+    if (flags & float_muladd_negate_c) {
+        cSign ^= 1;
+    }
+
+    signflip = (flags & float_muladd_negate_result) ? 1 : 0;
+
+    /* Work out the sign and type of the product */
+    pSign = aSign ^ bSign;
+    if (flags & float_muladd_negate_product) {
+        pSign ^= 1;
+    }
+    pInf = (aExp == 0x7ff) || (bExp == 0x7ff);
+    pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
+
+    if (cExp == 0x7ff) {
+        if (pInf && (pSign ^ cSign)) {
+            /* addition of opposite-signed infinities => InvalidOperation */
+            float_raise(float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        /* Otherwise generate an infinity of the same sign */
+        return packFloat64(cSign ^ signflip, 0x7ff, 0);
+    }
+
+    if (pInf) {
+        return packFloat64(pSign ^ signflip, 0x7ff, 0);
+    }
+
+    if (pZero) {
+        if (cExp == 0) {
+            if (cSig == 0) {
+                /* Adding two exact zeroes */
+                if (pSign == cSign) {
+                    zSign = pSign;
+                } else if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign = 1;
+                } else {
+                    zSign = 0;
+                }
+                return packFloat64(zSign ^ signflip, 0, 0);
+            }
+            /* Exact zero plus a denorm */
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat64(cSign ^ signflip, 0, 0);
+            }
+        }
+        /* Zero plus something non-zero : just return the something */
+        return c ^ ((uint64_t)signflip << 63);
+    }
+
+    if (aExp == 0) {
+        normalizeFloat64Subnormal(aSig, &aExp, &aSig);
+    }
+    if (bExp == 0) {
+        normalizeFloat64Subnormal(bSig, &bExp, &bSig);
+    }
+
+    /* Calculate the actual result a * b + c */
+
+    /* Multiply first; this is easy. */
+    /* NB: we subtract 0x3fe where float64_mul() subtracts 0x3ff
+     * because we want the true exponent, not the "one-less-than"
+     * flavour that roundAndPackFloat64() takes.
+     */
+    pExp = aExp + bExp - 0x3fe;
+    aSig = (aSig | LIT64(0x0010000000000000))<<10;
+    bSig = (bSig | LIT64(0x0010000000000000))<<11;
+    mul64To128(aSig, bSig, &pSig0, &pSig1);
+    if ((int64_t)(pSig0 << 1) >= 0) {
+        shortShift128Left(pSig0, pSig1, 1, &pSig0, &pSig1);
+        pExp--;
+    }
+
+    zSign = pSign ^ signflip;
+
+    /* Now [pSig0:pSig1] is the significand of the multiply, with the explicit
+     * bit in position 126.
+     */
+    if (cExp == 0) {
+        if (!cSig) {
+            /* Throw out the special case of c being an exact zero now */
+            shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
+            return roundAndPackFloat64(zSign, pExp - 1,
+                                       pSig1 STATUS_VAR);
+        }
+        normalizeFloat64Subnormal(cSig, &cExp, &cSig);
+    }
+
+    /* Shift cSig and add the explicit bit so [cSig0:cSig1] is the
+     * significand of the addend, with the explicit bit in position 126.
+     */
+    cSig0 = cSig << (126 - 64 - 52);
+    cSig1 = 0;
+    cSig0 |= LIT64(0x4000000000000000);
+    expDiff = pExp - cExp;
+
+    if (pSign == cSign) {
+        /* Addition */
+        if (expDiff > 0) {
+            /* scale c to match p */
+            shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            /* scale p to match c */
+            shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
+            zExp = cExp;
+        } else {
+            /* no scaling needed */
+            zExp = cExp;
+        }
+        /* Add significands and make sure explicit bit ends up in posn 126 */
+        add128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+        if ((int64_t)zSig0 < 0) {
+            shift128RightJamming(zSig0, zSig1, 1, &zSig0, &zSig1);
+        } else {
+            zExp--;
+        }
+        shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
+        return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
+    } else {
+        /* Subtraction */
+        if (expDiff > 0) {
+            shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
+            sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
+            sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
+            zExp = cExp;
+            zSign ^= 1;
+        } else {
+            zExp = pExp;
+            if (lt128(cSig0, cSig1, pSig0, pSig1)) {
+                sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+            } else if (lt128(pSig0, pSig1, cSig0, cSig1)) {
+                sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
+                zSign ^= 1;
+            } else {
+                /* Exact zero */
+                zSign = signflip;
+                if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign ^= 1;
+                }
+                return packFloat64(zSign, 0, 0);
+            }
+        }
+        --zExp;
+        /* Do the equivalent of normalizeRoundAndPackFloat64() but
+         * starting with the significand in a pair of uint64_t.
+         */
+        if (zSig0) {
+            shiftcount = countLeadingZeros64(zSig0) - 1;
+            shortShift128Left(zSig0, zSig1, shiftcount, &zSig0, &zSig1);
+            if (zSig1) {
+                zSig0 |= 1;
+            }
+            zExp -= shiftcount;
+        } else {
+            shiftcount = countLeadingZeros64(zSig1) - 1;
+            zSig0 = zSig1 << shiftcount;
+            zExp -= (shiftcount + 64);
+        }
+        return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
+    }
+}
+
 /*----------------------------------------------------------------------------
 | Returns the square root of the double-precision floating-point value `a'.
 | The operation is performed according to the IEC/IEEE Standard for Binary
@@ -3408,8 +3901,8 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp, zExp;
-    bits64 aSig, zSig, doubleZSig;
-    bits64 rem0, rem1, term0, term1;
+    uint64_t aSig, zSig, doubleZSig;
+    uint64_t rem0, rem1, term0, term1;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
@@ -3439,7 +3932,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
         doubleZSig = zSig<<1;
         mul64To128( zSig, zSig, &term0, &term1 );
         sub128( aSig, 0, term0, term1, &rem0, &rem1 );
-        while ( (sbits64) rem0 < 0 ) {
+        while ( (int64_t) rem0 < 0 ) {
             --zSig;
             doubleZSig -= 2;
             add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 );
@@ -3459,7 +3952,7 @@ float64 float64_log2( float64 a STATUS_PARAM )
 {
     flag aSign, zSign;
     int16 aExp;
-    bits64 aSig, aSig0, aSig1, zSig, i;
+    uint64_t aSig, aSig0, aSig1, zSig, i;
     a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
@@ -3482,7 +3975,7 @@ float64 float64_log2( float64 a STATUS_PARAM )
     aExp -= 0x3FF;
     aSig |= LIT64( 0x0010000000000000 );
     zSign = aExp < 0;
-    zSig = (bits64)aExp << 52;
+    zSig = (uint64_t)aExp << 52;
     for (i = 1LL << 51; i > 0; i >>= 1) {
         mul64To128( aSig, aSig, &aSig0, &aSig1 );
         aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 );
@@ -3499,41 +3992,40 @@ 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.
 *----------------------------------------------------------------------------*/
 
 int float64_eq( float64 a, float64 b STATUS_PARAM )
 {
-    bits64 av, bv;
+    uint64_t av, bv;
     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);
-        }
+        float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
     av = float64_val(a);
     bv = float64_val(b);
-    return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
 
 }
 
 /*----------------------------------------------------------------------------
 | 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 )
 {
     flag aSign, bSign;
-    bits64 av, bv;
+    uint64_t av, bv;
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
 
@@ -3547,21 +4039,22 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
     bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
-    if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
+    if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
     return ( av == bv ) || ( aSign ^ ( av < bv ) );
 
 }
 
 /*----------------------------------------------------------------------------
 | 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 )
 {
     flag aSign, bSign;
-    bits64 av, bv;
+    uint64_t av, bv;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
@@ -3575,21 +4068,20 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
     bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
-    if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
+    if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 );
     return ( av != bv ) && ( aSign ^ ( av < bv ) );
 
 }
 
 /*----------------------------------------------------------------------------
-| 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.
+| 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_eq_signaling( float64 a, float64 b STATUS_PARAM )
+int float64_unordered( float64 a, float64 b STATUS_PARAM )
 {
-    bits64 av, bv;
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
 
@@ -3597,11 +4089,35 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
          || ( ( 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.  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_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    uint64_t av, bv;
+    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 0;
     }
     av = float64_val(a);
     bv = float64_val(b);
-    return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
 
 }
 
@@ -3615,7 +4131,7 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
 int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
-    bits64 av, bv;
+    uint64_t av, bv;
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
 
@@ -3631,7 +4147,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
     bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
-    if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
+    if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
     return ( av == bv ) || ( aSign ^ ( av < bv ) );
 
 }
@@ -3646,7 +4162,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
 int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
-    bits64 av, bv;
+    uint64_t av, bv;
     a = float64_squash_input_denormal(a STATUS_VAR);
     b = float64_squash_input_denormal(b STATUS_VAR);
 
@@ -3662,12 +4178,33 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
     bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
-    if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
+    if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 );
     return ( av != bv ) && ( aSign ^ ( av < bv ) );
 
 }
 
-#ifdef FLOATX80
+/*----------------------------------------------------------------------------
+| 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;
+}
 
 /*----------------------------------------------------------------------------
 | Returns the result of converting the extended double-precision floating-
@@ -3683,12 +4220,12 @@ int32 floatx80_to_int32( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig;
+    uint64_t aSig;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
-    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+    if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0;
     shiftCount = 0x4037 - aExp;
     if ( shiftCount <= 0 ) shiftCount = 1;
     shift64RightJamming( aSig, shiftCount, &aSig );
@@ -3710,14 +4247,14 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig, savedASig;
+    uint64_t aSig, savedASig;
     int32 z;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( 0x401E < aExp ) {
-        if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+        if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0;
         goto invalid;
     }
     else if ( aExp < 0x3FFF ) {
@@ -3732,7 +4269,7 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM )
     if ( ( z < 0 ) ^ aSign ) {
  invalid:
         float_raise( float_flag_invalid STATUS_VAR);
-        return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
     }
     if ( ( aSig<<shiftCount ) != savedASig ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
@@ -3755,7 +4292,7 @@ int64 floatx80_to_int64( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig, aSigExtra;
+    uint64_t aSig, aSigExtra;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
@@ -3770,7 +4307,7 @@ int64 floatx80_to_int64( floatx80 a STATUS_PARAM )
                ) {
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
-            return (sbits64) LIT64( 0x8000000000000000 );
+            return (int64_t) LIT64( 0x8000000000000000 );
         }
         aSigExtra = 0;
     }
@@ -3795,7 +4332,7 @@ int64 floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig;
+    uint64_t aSig;
     int64 z;
 
     aSig = extractFloatx80Frac( a );
@@ -3810,14 +4347,14 @@ int64 floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM )
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
         }
-        return (sbits64) LIT64( 0x8000000000000000 );
+        return (int64_t) LIT64( 0x8000000000000000 );
     }
     else if ( aExp < 0x3FFF ) {
         if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
         return 0;
     }
     z = aSig>>( - shiftCount );
-    if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
+    if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
     }
     if ( aSign ) z = - z;
@@ -3836,14 +4373,14 @@ float32 floatx80_to_float32( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 aSig;
+    uint64_t aSig;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( aSig<<1 ) ) {
-            return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) );
+        if ( (uint64_t) ( aSig<<1 ) ) {
+            return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat32( aSign, 0xFF, 0 );
     }
@@ -3864,14 +4401,14 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 aSig, zSig;
+    uint64_t aSig, zSig;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( aSig<<1 ) ) {
-            return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) );
+        if ( (uint64_t) ( aSig<<1 ) ) {
+            return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat64( aSign, 0x7FF, 0 );
     }
@@ -3881,8 +4418,6 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
 
 }
 
-#ifdef FLOAT128
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the extended double-precision floating-
 | point value `a' to the quadruple-precision floating-point format.  The
@@ -3894,21 +4429,19 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int16 aExp;
-    bits64 aSig, zSig0, zSig1;
+    uint64_t aSig, zSig0, zSig1;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
-    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
-        return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) );
+    if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) {
+        return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
     }
     shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
     return packFloat128( aSign, aExp, zSig0, zSig1 );
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Rounds the extended double-precision floating-point value `a' to an integer,
 | and returns the result as an extended quadruple-precision floating-point
@@ -3920,27 +4453,27 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 lastBitMask, roundBitsMask;
+    uint64_t lastBitMask, roundBitsMask;
     int8 roundingMode;
     floatx80 z;
 
     aExp = extractFloatx80Exp( a );
     if ( 0x403E <= aExp ) {
-        if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) {
+        if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
             return propagateFloatx80NaN( a, a STATUS_VAR );
         }
         return a;
     }
     if ( aExp < 0x3FFF ) {
         if (    ( aExp == 0 )
-             && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
+             && ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
             return a;
         }
         STATUS(float_exception_flags) |= float_flag_inexact;
         aSign = extractFloatx80Sign( a );
         switch ( STATUS(float_rounding_mode) ) {
          case float_round_nearest_even:
-            if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 )
+            if ( ( aExp == 0x3FFE ) && (uint64_t) ( extractFloatx80Frac( a )<<1 )
                ) {
                 return
                     packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
@@ -3993,7 +4526,7 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM )
 static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM)
 {
     int32 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig0, zSig1;
+    uint64_t aSig, bSig, zSig0, zSig1;
     int32 expDiff;
 
     aSig = extractFloatx80Frac( a );
@@ -4003,7 +4536,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     expDiff = aExp - bExp;
     if ( 0 < expDiff ) {
         if ( aExp == 0x7FFF ) {
-            if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
             return a;
         }
         if ( bExp == 0 ) --expDiff;
@@ -4012,7 +4545,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     }
     else if ( expDiff < 0 ) {
         if ( bExp == 0x7FFF ) {
-            if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
             return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
         }
         if ( aExp == 0 ) ++expDiff;
@@ -4021,7 +4554,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     }
     else {
         if ( aExp == 0x7FFF ) {
-            if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+            if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
                 return propagateFloatx80NaN( a, b STATUS_VAR );
             }
             return a;
@@ -4036,7 +4569,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
         goto shiftRight1;
     }
     zSig0 = aSig + bSig;
-    if ( (sbits64) zSig0 < 0 ) goto roundAndPack;
+    if ( (int64_t) zSig0 < 0 ) goto roundAndPack;
  shiftRight1:
     shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
     zSig0 |= LIT64( 0x8000000000000000 );
@@ -4059,7 +4592,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
 static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM )
 {
     int32 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig0, zSig1;
+    uint64_t aSig, bSig, zSig0, zSig1;
     int32 expDiff;
     floatx80 z;
 
@@ -4071,7 +4604,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     if ( 0 < expDiff ) goto aExpBigger;
     if ( expDiff < 0 ) goto bExpBigger;
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+        if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
             return propagateFloatx80NaN( a, b STATUS_VAR );
         }
         float_raise( float_flag_invalid STATUS_VAR);
@@ -4089,7 +4622,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 );
  bExpBigger:
     if ( bExp == 0x7FFF ) {
-        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
     if ( aExp == 0 ) ++expDiff;
@@ -4101,7 +4634,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     goto normalizeRoundAndPack;
  aExpBigger:
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         return a;
     }
     if ( bExp == 0 ) --expDiff;
@@ -4168,7 +4701,7 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int32 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig0, zSig1;
+    uint64_t aSig, bSig, zSig0, zSig1;
     floatx80 z;
 
     aSig = extractFloatx80Frac( a );
@@ -4179,15 +4712,15 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM )
     bSign = extractFloatx80Sign( b );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
-        if (    (bits64) ( aSig<<1 )
-             || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+        if (    (uint64_t) ( aSig<<1 )
+             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
             return propagateFloatx80NaN( a, b STATUS_VAR );
         }
         if ( ( bExp | bSig ) == 0 ) goto invalid;
         return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
     if ( bExp == 0x7FFF ) {
-        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         if ( ( aExp | aSig ) == 0 ) {
  invalid:
             float_raise( float_flag_invalid STATUS_VAR);
@@ -4207,7 +4740,7 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM )
     }
     zExp = aExp + bExp - 0x3FFE;
     mul64To128( aSig, bSig, &zSig0, &zSig1 );
-    if ( 0 < (sbits64) zSig0 ) {
+    if ( 0 < (int64_t) zSig0 ) {
         shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
         --zExp;
     }
@@ -4227,8 +4760,8 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int32 aExp, bExp, zExp;
-    bits64 aSig, bSig, zSig0, zSig1;
-    bits64 rem0, rem1, rem2, term0, term1, term2;
+    uint64_t aSig, bSig, zSig0, zSig1;
+    uint64_t rem0, rem1, rem2, term0, term1, term2;
     floatx80 z;
 
     aSig = extractFloatx80Frac( a );
@@ -4239,15 +4772,15 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM )
     bSign = extractFloatx80Sign( b );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         if ( bExp == 0x7FFF ) {
-            if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
             goto invalid;
         }
         return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
     if ( bExp == 0x7FFF ) {
-        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         return packFloatx80( zSign, 0, 0 );
     }
     if ( bExp == 0 ) {
@@ -4277,15 +4810,15 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM )
     zSig0 = estimateDiv128To64( aSig, rem1, bSig );
     mul64To128( bSig, zSig0, &term0, &term1 );
     sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
-    while ( (sbits64) rem0 < 0 ) {
+    while ( (int64_t) rem0 < 0 ) {
         --zSig0;
         add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
     }
     zSig1 = estimateDiv128To64( rem1, 0, bSig );
-    if ( (bits64) ( zSig1<<1 ) <= 8 ) {
+    if ( (uint64_t) ( zSig1<<1 ) <= 8 ) {
         mul64To128( bSig, zSig1, &term1, &term2 );
         sub128( rem1, 0, term1, term2, &rem1, &rem2 );
-        while ( (sbits64) rem1 < 0 ) {
+        while ( (int64_t) rem1 < 0 ) {
             --zSig1;
             add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
         }
@@ -4307,8 +4840,8 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, zSign;
     int32 aExp, bExp, expDiff;
-    bits64 aSig0, aSig1, bSig;
-    bits64 q, term0, term1, alternateASig0, alternateASig1;
+    uint64_t aSig0, aSig1, bSig;
+    uint64_t q, term0, term1, alternateASig0, alternateASig1;
     floatx80 z;
 
     aSig0 = extractFloatx80Frac( a );
@@ -4317,14 +4850,14 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM )
     bSig = extractFloatx80Frac( b );
     bExp = extractFloatx80Exp( b );
     if ( aExp == 0x7FFF ) {
-        if (    (bits64) ( aSig0<<1 )
-             || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+        if (    (uint64_t) ( aSig0<<1 )
+             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
             return propagateFloatx80NaN( a, b STATUS_VAR );
         }
         goto invalid;
     }
     if ( bExp == 0x7FFF ) {
-        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
         return a;
     }
     if ( bExp == 0 ) {
@@ -4338,7 +4871,7 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM )
         normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
     }
     if ( aExp == 0 ) {
-        if ( (bits64) ( aSig0<<1 ) == 0 ) return a;
+        if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a;
         normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
     }
     bSig |= LIT64( 0x8000000000000000 );
@@ -4403,15 +4936,15 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, zExp;
-    bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     floatx80 z;
 
     aSig0 = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
-        if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR );
+        if ( (uint64_t) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR );
         if ( ! aSign ) return a;
         goto invalid;
     }
@@ -4434,7 +4967,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
     doubleZSig0 = zSig0<<1;
     mul64To128( zSig0, zSig0, &term0, &term1 );
     sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
-    while ( (sbits64) rem0 < 0 ) {
+    while ( (int64_t) rem0 < 0 ) {
         --zSig0;
         doubleZSig0 -= 2;
         add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
@@ -4446,7 +4979,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
         sub128( rem1, 0, term1, term2, &rem1, &rem2 );
         mul64To128( zSig1, zSig1, &term2, &term3 );
         sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
+        while ( (int64_t) rem1 < 0 ) {
             --zSig1;
             shortShift128Left( 0, zSig1, 1, &term2, &term3 );
             term3 |= 1;
@@ -4464,31 +4997,28 @@ 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 )
 {
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (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
            ( a.low == b.low )
         && (    ( a.high == b.high )
              || (    ( a.low == 0 )
-                  && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+                  && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) )
            );
 
 }
@@ -4496,8 +5026,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 )
@@ -4505,9 +5036,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
     flag aSign, bSign;
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -4517,7 +5048,7 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            || (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            || (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  == 0 );
     }
     return
@@ -4528,9 +5059,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 )
@@ -4538,9 +5069,9 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
     flag aSign, bSign;
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -4550,7 +5081,7 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            && (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            && (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  != 0 );
     }
     return
@@ -4560,28 +5091,50 @@ 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 )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (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
            ( a.low == b.low )
         && (    ( a.high == b.high )
              || (    ( a.low == 0 )
-                  && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+                  && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) )
            );
 
 }
@@ -4598,9 +5151,9 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
     flag aSign, bSign;
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
         if (    floatx80_is_signaling_nan( a )
              || floatx80_is_signaling_nan( b ) ) {
@@ -4613,7 +5166,7 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            || (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            || (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  == 0 );
     }
     return
@@ -4634,9 +5187,9 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
     flag aSign, bSign;
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
         if (    floatx80_is_signaling_nan( a )
              || floatx80_is_signaling_nan( b ) ) {
@@ -4649,7 +5202,7 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            && (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            && (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  != 0 );
     }
     return
@@ -4658,9 +5211,27 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 
 }
 
-#endif
-
-#ifdef FLOAT128
+/*----------------------------------------------------------------------------
+| 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;
+}
 
 /*----------------------------------------------------------------------------
 | Returns the result of converting the quadruple-precision floating-point
@@ -4676,7 +5247,7 @@ int32 float128_to_int32( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig0, aSig1;
+    uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
@@ -4705,7 +5276,7 @@ int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig0, aSig1, savedASig;
+    uint64_t aSig0, aSig1, savedASig;
     int32 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -4730,7 +5301,7 @@ int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM )
     if ( ( z < 0 ) ^ aSign ) {
  invalid:
         float_raise( float_flag_invalid STATUS_VAR);
-        return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
     }
     if ( ( aSig0<<shiftCount ) != savedASig ) {
         STATUS(float_exception_flags) |= float_flag_inexact;
@@ -4753,7 +5324,7 @@ int64 float128_to_int64( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig0, aSig1;
+    uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
@@ -4771,7 +5342,7 @@ int64 float128_to_int64( float128 a STATUS_PARAM )
                ) {
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
-            return (sbits64) LIT64( 0x8000000000000000 );
+            return (int64_t) LIT64( 0x8000000000000000 );
         }
         shortShift128Left( aSig0, aSig1, - shiftCount, &aSig0, &aSig1 );
     }
@@ -4796,7 +5367,7 @@ int64 float128_to_int64_round_to_zero( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, shiftCount;
-    bits64 aSig0, aSig1;
+    uint64_t aSig0, aSig1;
     int64 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -4818,10 +5389,10 @@ int64 float128_to_int64_round_to_zero( float128 a STATUS_PARAM )
                     return LIT64( 0x7FFFFFFFFFFFFFFF );
                 }
             }
-            return (sbits64) LIT64( 0x8000000000000000 );
+            return (int64_t) LIT64( 0x8000000000000000 );
         }
         z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
-        if ( (bits64) ( aSig1<<shiftCount ) ) {
+        if ( (uint64_t) ( aSig1<<shiftCount ) ) {
             STATUS(float_exception_flags) |= float_flag_inexact;
         }
     }
@@ -4834,7 +5405,7 @@ int64 float128_to_int64_round_to_zero( float128 a STATUS_PARAM )
         }
         z = aSig0>>( - shiftCount );
         if (    aSig1
-             || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) {
+             || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) {
             STATUS(float_exception_flags) |= float_flag_inexact;
         }
     }
@@ -4854,8 +5425,8 @@ float32 float128_to_float32( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 aSig0, aSig1;
-    bits32 zSig;
+    uint64_t aSig0, aSig1;
+    uint32_t zSig;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
@@ -4863,7 +5434,7 @@ float32 float128_to_float32( float128 a STATUS_PARAM )
     aSign = extractFloat128Sign( a );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) );
+            return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat32( aSign, 0xFF, 0 );
     }
@@ -4889,7 +5460,7 @@ float64 float128_to_float64( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 aSig0, aSig1;
+    uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
@@ -4897,7 +5468,7 @@ float64 float128_to_float64( float128 a STATUS_PARAM )
     aSign = extractFloat128Sign( a );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) );
+            return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat64( aSign, 0x7FF, 0 );
     }
@@ -4911,8 +5482,6 @@ float64 float128_to_float64( float128 a STATUS_PARAM )
 
 }
 
-#ifdef FLOATX80
-
 /*----------------------------------------------------------------------------
 | Returns the result of converting the quadruple-precision floating-point
 | value `a' to the extended double-precision floating-point format.  The
@@ -4924,7 +5493,7 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 aSig0, aSig1;
+    uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
@@ -4932,7 +5501,7 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
     aSign = extractFloat128Sign( a );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
-            return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) );
+            return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
     }
@@ -4948,8 +5517,6 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
 
 }
 
-#endif
-
 /*----------------------------------------------------------------------------
 | Rounds the quadruple-precision floating-point value `a' to an integer, and
 | returns the result as a quadruple-precision floating-point value.  The
@@ -4961,7 +5528,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp;
-    bits64 lastBitMask, roundBitsMask;
+    uint64_t lastBitMask, roundBitsMask;
     int8 roundingMode;
     float128 z;
 
@@ -4986,9 +5553,9 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
                 if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
             }
             else {
-                if ( (sbits64) z.low < 0 ) {
+                if ( (int64_t) z.low < 0 ) {
                     ++z.high;
-                    if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
+                    if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1;
                 }
             }
         }
@@ -5002,7 +5569,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
     }
     else {
         if ( aExp < 0x3FFF ) {
-            if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+            if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
             STATUS(float_exception_flags) |= float_flag_inexact;
             aSign = extractFloat128Sign( a );
             switch ( STATUS(float_rounding_mode) ) {
@@ -5064,7 +5631,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
 static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM)
 {
     int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
     int32 expDiff;
 
     aSig1 = extractFloat128Frac1( a );
@@ -5113,7 +5680,12 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
         }
         add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+            if (STATUS(flush_to_zero)) {
+                if (zSig0 | zSig1) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat128(zSign, 0, 0, 0);
+            }
             return packFloat128( zSign, 0, zSig0, zSig1 );
         }
         zSig2 = 0;
@@ -5145,7 +5717,7 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
 static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM)
 {
     int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
     int32 expDiff;
     float128 z;
 
@@ -5270,7 +5842,7 @@ float128 float128_mul( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
     float128 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -5334,8 +5906,8 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign, zSign;
     int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     float128 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -5389,7 +5961,7 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM )
     zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
     mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
     sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
-    while ( (sbits64) rem0 < 0 ) {
+    while ( (int64_t) rem0 < 0 ) {
         --zSig0;
         add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
     }
@@ -5397,7 +5969,7 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM )
     if ( ( zSig1 & 0x3FFF ) <= 4 ) {
         mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
         sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
+        while ( (int64_t) rem1 < 0 ) {
             --zSig1;
             add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
         }
@@ -5418,9 +5990,9 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, zSign;
     int32 aExp, bExp, expDiff;
-    bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
-    bits64 allZero, alternateASig0, alternateASig1, sigMean1;
-    sbits64 sigMean0;
+    uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
+    uint64_t allZero, alternateASig0, alternateASig1, sigMean1;
+    int64_t sigMean0;
     float128 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -5502,15 +6074,15 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM )
         alternateASig1 = aSig1;
         ++q;
         sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
-    } while ( 0 <= (sbits64) aSig0 );
+    } while ( 0 <= (int64_t) aSig0 );
     add128(
-        aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 );
+        aSig0, aSig1, alternateASig0, alternateASig1, (uint64_t *)&sigMean0, &sigMean1 );
     if (    ( sigMean0 < 0 )
          || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
         aSig0 = alternateASig0;
         aSig1 = alternateASig1;
     }
-    zSign = ( (sbits64) aSig0 < 0 );
+    zSign = ( (int64_t) aSig0 < 0 );
     if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
     return
         normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR );
@@ -5527,8 +6099,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
 {
     flag aSign;
     int32 aExp, zExp;
-    bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     float128 z;
 
     aSig1 = extractFloat128Frac1( a );
@@ -5560,7 +6132,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
     doubleZSig0 = zSig0<<1;
     mul64To128( zSig0, zSig0, &term0, &term1 );
     sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
-    while ( (sbits64) rem0 < 0 ) {
+    while ( (int64_t) rem0 < 0 ) {
         --zSig0;
         doubleZSig0 -= 2;
         add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
@@ -5572,7 +6144,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
         sub128( rem1, 0, term1, term2, &rem1, &rem2 );
         mul64To128( zSig1, zSig1, &term2, &term3 );
         sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
+        while ( (int64_t) rem1 < 0 ) {
             --zSig1;
             shortShift128Left( 0, zSig1, 1, &term2, &term3 );
             term3 |= 1;
@@ -5588,7 +6160,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.
 *----------------------------------------------------------------------------*/
 
@@ -5600,26 +6173,23 @@ 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
            ( a.low == b.low )
         && (    ( a.high == b.high )
              || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+                  && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) )
            );
 
 }
 
 /*----------------------------------------------------------------------------
 | 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 )
@@ -5639,7 +6209,7 @@ int float128_le( float128 a, float128 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            || (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  == 0 );
     }
     return
@@ -5650,8 +6220,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 )
@@ -5671,7 +6242,7 @@ int float128_lt( float128 a, float128 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            && (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  != 0 );
     }
     return
@@ -5680,14 +6251,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 )
@@ -5695,14 +6286,17 @@ 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
            ( a.low == b.low )
         && (    ( a.high == b.high )
              || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+                  && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) )
            );
 
 }
@@ -5734,7 +6328,7 @@ int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            || (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  == 0 );
     }
     return
@@ -5770,7 +6364,7 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
     if ( aSign != bSign ) {
         return
                aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+            && (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
                  != 0 );
     }
     return
@@ -5779,23 +6373,44 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
 
 }
 
-#endif
+/*----------------------------------------------------------------------------
+| 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;
+}
 
 /* misc functions */
-float32 uint32_to_float32( unsigned int a STATUS_PARAM )
+float32 uint32_to_float32( uint32 a STATUS_PARAM )
 {
     return int64_to_float32(a STATUS_VAR);
 }
 
-float64 uint32_to_float64( unsigned int a STATUS_PARAM )
+float64 uint32_to_float64( uint32 a STATUS_PARAM )
 {
     return int64_to_float64(a STATUS_VAR);
 }
 
-unsigned int float32_to_uint32( float32 a STATUS_PARAM )
+uint32 float32_to_uint32( float32 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint32 res;
 
     v = float32_to_int64(a STATUS_VAR);
     if (v < 0) {
@@ -5810,10 +6425,10 @@ unsigned int float32_to_uint32( float32 a STATUS_PARAM )
     return res;
 }
 
-unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
+uint32 float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint32 res;
 
     v = float32_to_int64_round_to_zero(a STATUS_VAR);
     if (v < 0) {
@@ -5828,10 +6443,10 @@ unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
     return res;
 }
 
-unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
+uint16 float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint16 res;
 
     v = float32_to_int64_round_to_zero(a STATUS_VAR);
     if (v < 0) {
@@ -5846,10 +6461,10 @@ unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
     return res;
 }
 
-unsigned int float64_to_uint32( float64 a STATUS_PARAM )
+uint32 float64_to_uint32( float64 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint32 res;
 
     v = float64_to_int64(a STATUS_VAR);
     if (v < 0) {
@@ -5864,10 +6479,10 @@ unsigned int float64_to_uint32( float64 a STATUS_PARAM )
     return res;
 }
 
-unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
+uint32 float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint32 res;
 
     v = float64_to_int64_round_to_zero(a STATUS_VAR);
     if (v < 0) {
@@ -5882,10 +6497,10 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
     return res;
 }
 
-unsigned int float64_to_uint16_round_to_zero( float64 a STATUS_PARAM )
+uint16 float64_to_uint16_round_to_zero( float64 a STATUS_PARAM )
 {
     int64_t v;
-    unsigned int res;
+    uint16 res;
 
     v = float64_to_int64_round_to_zero(a STATUS_VAR);
     if (v < 0) {
@@ -5928,7 +6543,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
                                       int is_quiet STATUS_PARAM )            \
 {                                                                            \
     flag aSign, bSign;                                                       \
-    bits ## s av, bv;                                                        \
+    uint ## s ## _t av, bv;                                                  \
     a = float ## s ## _squash_input_denormal(a STATUS_VAR);                  \
     b = float ## s ## _squash_input_denormal(b STATUS_VAR);                  \
                                                                              \
@@ -5948,7 +6563,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
     av = float ## s ## _val(a);                                              \
     bv = float ## s ## _val(b);                                              \
     if ( aSign != bSign ) {                                                  \
-        if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) {                         \
+        if ( (uint ## s ## _t) ( ( av | bv )<<1 ) == 0 ) {                   \
             /* zero case */                                                  \
             return float_relation_equal;                                     \
         } else {                                                             \
@@ -5976,6 +6591,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 )
 {
@@ -6020,12 +6681,61 @@ 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;
-    bits32 aSig;
+    int16_t aExp;
+    uint32_t aSig;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
@@ -6033,6 +6743,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 )
@@ -6040,6 +6753,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 );
@@ -6048,8 +6767,8 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
 float64 float64_scalbn( float64 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int16 aExp;
-    bits64 aSig;
+    int16_t aExp;
+    uint64_t aSig;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
@@ -6057,6 +6776,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 )
@@ -6064,46 +6786,62 @@ 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 );
 }
 
-#ifdef FLOATX80
 floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int16 aExp;
-    bits64 aSig;
+    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 );
 }
-#endif
 
-#ifdef FLOAT128
 float128 float128_scalbn( float128 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
+    int32_t aExp;
+    uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
     aSig0 = extractFloat128Frac0( a );
     aExp = extractFloat128Exp( a );
     aSign = extractFloat128Sign( a );
     if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return propagateFloat128NaN( a, a STATUS_VAR );
+        }
         return a;
     }
     if ( aExp != 0 )
@@ -6111,9 +6849,14 @@ 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 );
 
 }
-#endif
index 4a5345ceca3abdf76f2a2dfd72455c0b0f7efd21..063d3dd6183045cbfb00e0ca686ea30bcfa35c26 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
 /*============================================================================
 
 This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
@@ -37,7 +43,7 @@ these four paragraphs for those parts of this code that are retained.
 #endif
 
 #include <inttypes.h>
-#include "config.h"
+#include "config-host.h"
 
 /*----------------------------------------------------------------------------
 | Each of the following `typedef's defines the most convenient type that holds
@@ -51,7 +57,7 @@ typedef uint8_t flag;
 typedef uint8_t uint8;
 typedef int8_t int8;
 #ifndef _AIX
-typedef int uint16;
+typedef int16_t uint16;
 typedef int int16;
 #endif
 typedef unsigned int uint32;
@@ -59,42 +65,9 @@ typedef signed int int32;
 typedef uint64_t uint64;
 typedef int64_t int64;
 
-/*----------------------------------------------------------------------------
-| Each of the following `typedef's defines a type that holds integers
-| of _exactly_ the number of bits specified.  For instance, for most
-| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
-| `unsigned short int' and `signed short int' (or `short int'), respectively.
-*----------------------------------------------------------------------------*/
-typedef uint8_t bits8;
-typedef int8_t sbits8;
-typedef uint16_t bits16;
-typedef int16_t sbits16;
-typedef uint32_t bits32;
-typedef int32_t sbits32;
-typedef uint64_t bits64;
-typedef int64_t sbits64;
-
 #define LIT64( a ) a##LL
 #define INLINE static inline
 
-/*----------------------------------------------------------------------------
-| The macro `FLOATX80' must be defined to enable the extended double-precision
-| floating-point format `floatx80'.  If this macro is not defined, the
-| `floatx80' type will not be defined, and none of the functions that either
-| input or output the `floatx80' type will be defined.  The same applies to
-| the `FLOAT128' macro and the quadruple-precision format `float128'.
-*----------------------------------------------------------------------------*/
-#ifdef CONFIG_SOFTFLOAT
-/* bit exact soft float support */
-#define FLOATX80
-#define FLOAT128
-#else
-/* native float support */
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(CONFIG_BSD)
-#define FLOATX80
-#endif
-#endif /* !CONFIG_SOFTFLOAT */
-
 #define STATUS_PARAM , float_status *status
 #define STATUS(field) status->field
 #define STATUS_VAR , status
@@ -109,7 +82,6 @@ enum {
     float_relation_unordered =  2
 };
 
-#ifdef CONFIG_SOFTFLOAT
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE floating-point types.
 *----------------------------------------------------------------------------*/
@@ -119,32 +91,44 @@ enum {
    x86/gcc 3.x seems to struggle a bit, so leave them disabled by default.  */
 //#define USE_SOFTFLOAT_STRUCT_TYPES
 #ifdef USE_SOFTFLOAT_STRUCT_TYPES
+typedef struct {
+    uint16_t v;
+} float16;
+#define float16_val(x) (((float16)(x)).v)
+#define make_float16(x) __extension__ ({ float16 f16_val = {x}; f16_val; })
+#define const_float16(x) { x }
 typedef struct {
     uint32_t v;
 } float32;
 /* The cast ensures an error if the wrong type is passed.  */
 #define float32_val(x) (((float32)(x)).v)
 #define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; })
+#define const_float32(x) { x }
 typedef struct {
     uint64_t v;
 } float64;
 #define float64_val(x) (((float64)(x)).v)
 #define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; })
+#define const_float64(x) { x }
 #else
+typedef uint16_t float16;
 typedef uint32_t float32;
 typedef uint64_t float64;
+#define float16_val(x) (x)
 #define float32_val(x) (x)
 #define float64_val(x) (x)
+#define make_float16(x) (x)
 #define make_float32(x) (x)
 #define make_float64(x) (x)
+#define const_float16(x) (x)
+#define const_float32(x) (x)
+#define const_float64(x) (x)
 #endif
-#ifdef FLOATX80
 typedef struct {
     uint64_t low;
     uint16_t high;
 } floatx80;
-#endif
-#ifdef FLOAT128
+#define make_floatx80(exp, mant) ((floatx80) { mant, exp })
 typedef struct {
 #ifdef HOST_WORDS_BIGENDIAN
     uint64_t high, low;
@@ -152,7 +136,7 @@ typedef struct {
     uint64_t low, high;
 #endif
 } float128;
-#endif
+#define make_float128(high_, low_) ((float128) { .high = high_, .low = low_ })
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE floating-point underflow tininess-detection mode.
@@ -181,16 +165,15 @@ enum {
     float_flag_overflow  =  8,
     float_flag_underflow = 16,
     float_flag_inexact   = 32,
-    float_flag_input_denormal = 64
+    float_flag_input_denormal = 64,
+    float_flag_output_denormal = 128
 };
 
 typedef struct float_status {
     signed char float_detect_tininess;
     signed char float_rounding_mode;
     signed char float_exception_flags;
-#ifdef FLOATX80
     signed char floatx80_rounding_precision;
-#endif
     /* should denormalised results go to zero and set the inexact flag? */
     flag flush_to_zero;
     /* should denormalised inputs go to zero and set the input_denormal flag? */
@@ -200,6 +183,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;
@@ -216,9 +203,7 @@ INLINE int get_float_exception_flags(float_status *status)
 {
     return STATUS(float_exception_flags);
 }
-#ifdef FLOATX80
 void set_floatx80_rounding_precision(int val STATUS_PARAM);
-#endif
 
 /*----------------------------------------------------------------------------
 | Routine to raise any or all of the software IEC/IEEE floating-point
@@ -226,54 +211,66 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM);
 *----------------------------------------------------------------------------*/
 void float_raise( int8 flags STATUS_PARAM);
 
+/*----------------------------------------------------------------------------
+| Options to indicate which negations to perform in float*_muladd()
+| Using these differs from negating an input or output before calling
+| the muladd function in that this means that a NaN doesn't have its
+| sign bit inverted before it is propagated.
+*----------------------------------------------------------------------------*/
+enum {
+    float_muladd_negate_c = 1,
+    float_muladd_negate_product = 2,
+    float_muladd_negate_result = 3,
+};
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE integer-to-floating-point conversion routines.
 *----------------------------------------------------------------------------*/
-float32 int32_to_float32( int STATUS_PARAM );
-float64 int32_to_float64( int STATUS_PARAM );
-float32 uint32_to_float32( unsigned int STATUS_PARAM );
-float64 uint32_to_float64( unsigned int STATUS_PARAM );
-#ifdef FLOATX80
-floatx80 int32_to_floatx80( int STATUS_PARAM );
-#endif
-#ifdef FLOAT128
-float128 int32_to_float128( int STATUS_PARAM );
-#endif
-float32 int64_to_float32( int64_t STATUS_PARAM );
-float32 uint64_to_float32( uint64_t STATUS_PARAM );
-float64 int64_to_float64( int64_t STATUS_PARAM );
-float64 uint64_to_float64( uint64_t STATUS_PARAM );
-#ifdef FLOATX80
-floatx80 int64_to_floatx80( int64_t STATUS_PARAM );
-#endif
-#ifdef FLOAT128
-float128 int64_to_float128( int64_t STATUS_PARAM );
-#endif
+float32 int32_to_float32( int32 STATUS_PARAM );
+float64 int32_to_float64( int32 STATUS_PARAM );
+float32 uint32_to_float32( uint32 STATUS_PARAM );
+float64 uint32_to_float64( uint32 STATUS_PARAM );
+floatx80 int32_to_floatx80( int32 STATUS_PARAM );
+float128 int32_to_float128( int32 STATUS_PARAM );
+float32 int64_to_float32( int64 STATUS_PARAM );
+float32 uint64_to_float32( uint64 STATUS_PARAM );
+float64 int64_to_float64( int64 STATUS_PARAM );
+float64 uint64_to_float64( uint64 STATUS_PARAM );
+floatx80 int64_to_floatx80( int64 STATUS_PARAM );
+float128 int64_to_float128( int64 STATUS_PARAM );
 
 /*----------------------------------------------------------------------------
 | Software half-precision conversion routines.
 *----------------------------------------------------------------------------*/
-bits16 float32_to_float16( float32, flag STATUS_PARAM );
-float32 float16_to_float32( bits16, flag STATUS_PARAM );
+float16 float32_to_float16( float32, flag STATUS_PARAM );
+float32 float16_to_float32( float16, flag STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software half-precision operations.
+*----------------------------------------------------------------------------*/
+int float16_is_quiet_nan( float16 );
+int float16_is_signaling_nan( float16 );
+float16 float16_maybe_silence_nan( float16 );
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated half-precision NaN.
+*----------------------------------------------------------------------------*/
+extern const float16 float16_default_nan;
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision conversion routines.
 *----------------------------------------------------------------------------*/
-int float32_to_int16_round_to_zero( float32 STATUS_PARAM );
-unsigned int float32_to_uint16_round_to_zero( float32 STATUS_PARAM );
-int float32_to_int32( float32 STATUS_PARAM );
-int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
-unsigned int float32_to_uint32( float32 STATUS_PARAM );
-unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
-int64_t float32_to_int64( float32 STATUS_PARAM );
-int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM );
+int16 float32_to_int16_round_to_zero( float32 STATUS_PARAM );
+uint16 float32_to_uint16_round_to_zero( float32 STATUS_PARAM );
+int32 float32_to_int32( float32 STATUS_PARAM );
+int32 float32_to_int32_round_to_zero( float32 STATUS_PARAM );
+uint32 float32_to_uint32( float32 STATUS_PARAM );
+uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
+int64 float32_to_int64( float32 STATUS_PARAM );
+int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM );
 float64 float32_to_float64( float32 STATUS_PARAM );
-#ifdef FLOATX80
 floatx80 float32_to_floatx80( float32 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
 float128 float32_to_float128( float32 STATUS_PARAM );
-#endif
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision operations.
@@ -284,17 +281,22 @@ float32 float32_sub( float32, float32 STATUS_PARAM );
 float32 float32_mul( float32, float32 STATUS_PARAM );
 float32 float32_div( float32, float32 STATUS_PARAM );
 float32 float32_rem( float32, float32 STATUS_PARAM );
+float32 float32_muladd(float32, float32, float32, int STATUS_PARAM);
 float32 float32_sqrt( float32 STATUS_PARAM );
 float32 float32_exp2( float32 STATUS_PARAM );
 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 );
@@ -341,30 +343,40 @@ INLINE int float32_is_zero_or_denormal(float32 a)
     return (float32_val(a) & 0x7f800000) == 0;
 }
 
+INLINE float32 float32_set_sign(float32 a, int sign)
+{
+    return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31));
+}
+
 #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)
+
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+extern const float32 float32_default_nan;
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
 *----------------------------------------------------------------------------*/
-int float64_to_int16_round_to_zero( float64 STATUS_PARAM );
-unsigned int float64_to_uint16_round_to_zero( float64 STATUS_PARAM );
-int float64_to_int32( float64 STATUS_PARAM );
-int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
-unsigned int float64_to_uint32( float64 STATUS_PARAM );
-unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
-int64_t float64_to_int64( float64 STATUS_PARAM );
-int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
-uint64_t float64_to_uint64 (float64 a STATUS_PARAM);
-uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
+int16 float64_to_int16_round_to_zero( float64 STATUS_PARAM );
+uint16 float64_to_uint16_round_to_zero( float64 STATUS_PARAM );
+int32 float64_to_int32( float64 STATUS_PARAM );
+int32 float64_to_int32_round_to_zero( float64 STATUS_PARAM );
+uint32 float64_to_uint32( float64 STATUS_PARAM );
+uint32 float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
+int64 float64_to_int64( float64 STATUS_PARAM );
+int64 float64_to_int64_round_to_zero( float64 STATUS_PARAM );
+uint64 float64_to_uint64 (float64 a STATUS_PARAM);
+uint64 float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
 float32 float64_to_float32( float64 STATUS_PARAM );
-#ifdef FLOATX80
 floatx80 float64_to_floatx80( float64 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
 float128 float64_to_float128( float64 STATUS_PARAM );
-#endif
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision operations.
@@ -376,16 +388,21 @@ float64 float64_sub( float64, float64 STATUS_PARAM );
 float64 float64_mul( float64, float64 STATUS_PARAM );
 float64 float64_div( float64, float64 STATUS_PARAM );
 float64 float64_rem( float64, float64 STATUS_PARAM );
+float64 float64_muladd(float64, float64, float64, int STATUS_PARAM);
 float64 float64_sqrt( float64 STATUS_PARAM );
 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 );
@@ -427,24 +444,39 @@ INLINE int float64_is_any_nan(float64 a)
     return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
 }
 
+INLINE int float64_is_zero_or_denormal(float64 a)
+{
+    return (float64_val(a) & 0x7ff0000000000000LL) == 0;
+}
+
+INLINE float64 float64_set_sign(float64 a, int sign)
+{
+    return make_float64((float64_val(a) & 0x7fffffffffffffffULL)
+                        | ((int64_t)sign << 63));
+}
+
 #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)
 
-#ifdef FLOATX80
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+extern const float64 float64_default_nan;
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE extended double-precision conversion routines.
 *----------------------------------------------------------------------------*/
-int floatx80_to_int32( floatx80 STATUS_PARAM );
-int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
-int64_t floatx80_to_int64( floatx80 STATUS_PARAM );
-int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
+int32 floatx80_to_int32( floatx80 STATUS_PARAM );
+int32 floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
+int64 floatx80_to_int64( floatx80 STATUS_PARAM );
+int64 floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
 float32 floatx80_to_float32( floatx80 STATUS_PARAM );
 float64 floatx80_to_float64( floatx80 STATUS_PARAM );
-#ifdef FLOAT128
 float128 floatx80_to_float128( floatx80 STATUS_PARAM );
-#endif
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE extended double-precision operations.
@@ -459,9 +491,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 );
@@ -481,7 +517,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)
@@ -494,27 +530,38 @@ INLINE int floatx80_is_zero(floatx80 a)
     return (a.high & 0x7fff) == 0 && a.low == 0;
 }
 
+INLINE int floatx80_is_zero_or_denormal(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0;
+}
+
 INLINE int floatx80_is_any_nan(floatx80 a)
 {
     return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
 }
 
-#endif
+#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)
 
-#ifdef FLOAT128
+/*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision NaN.
+*----------------------------------------------------------------------------*/
+extern const floatx80 floatx80_default_nan;
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE quadruple-precision conversion routines.
 *----------------------------------------------------------------------------*/
-int float128_to_int32( float128 STATUS_PARAM );
-int float128_to_int32_round_to_zero( float128 STATUS_PARAM );
-int64_t float128_to_int64( float128 STATUS_PARAM );
-int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM );
+int32 float128_to_int32( float128 STATUS_PARAM );
+int32 float128_to_int32_round_to_zero( float128 STATUS_PARAM );
+int64 float128_to_int64( float128 STATUS_PARAM );
+int64 float128_to_int64_round_to_zero( float128 STATUS_PARAM );
 float32 float128_to_float32( float128 STATUS_PARAM );
 float64 float128_to_float64( float128 STATUS_PARAM );
-#ifdef FLOATX80
 floatx80 float128_to_floatx80( float128 STATUS_PARAM );
-#endif
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE quadruple-precision operations.
@@ -529,9 +576,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 );
@@ -566,18 +615,20 @@ INLINE int float128_is_zero(float128 a)
     return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
 }
 
+INLINE int float128_is_zero_or_denormal(float128 a)
+{
+    return (a.high & 0x7fff000000000000LL) == 0;
+}
+
 INLINE int float128_is_any_nan(float128 a)
 {
     return ((a.high >> 48) & 0x7fff) == 0x7fff &&
         ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0));
 }
 
-#endif
-
-#else /* CONFIG_SOFTFLOAT */
-
-#include "softfloat-native.h"
-
-#endif /* !CONFIG_SOFTFLOAT */
+/*----------------------------------------------------------------------------
+| The pattern for a default generated quadruple-precision NaN.
+*----------------------------------------------------------------------------*/
+extern const float128 float128_default_nan;
 
 #endif /* !SOFTFLOAT_H */
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
new file mode 100644 (file)
index 0000000..c823fe0
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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 struct FsCred
+{
+    uid_t   fc_uid;
+    gid_t   fc_gid;
+    mode_t  fc_mode;
+    dev_t   fc_rdev;
+} FsCred;
+
+struct xattr_operations;
+struct FsContext;
+struct V9fsPath;
+
+typedef struct extended_ops {
+    int (*get_st_gen)(struct FsContext *, struct V9fsPath *,
+                      mode_t, uint64_t *);
+} extended_ops;
+
+/* export flags */
+#define V9FS_IMMEDIATE_WRITEOUT     0x00000001
+#define V9FS_PATHNAME_FSCONTEXT     0x00000002
+/*
+ * uid/gid set on fileserver files
+ */
+#define V9FS_SM_PASSTHROUGH         0x00000004
+/*
+ * uid/gid part of xattr
+ */
+#define V9FS_SM_MAPPED              0x00000008
+/*
+ * Server will try to set uid/gid.
+ * On failure ignore the error.
+ */
+#define V9FS_SM_NONE                0x00000010
+#define V9FS_RDONLY                 0x00000020
+
+#define V9FS_SEC_MASK               0x0000001C
+
+
+
+typedef struct FsContext
+{
+    uid_t uid;
+    char *fs_root;
+    int export_flags;
+    struct xattr_operations **xops;
+    struct extended_ops exops;
+    /* fs driver specific data */
+    void *private;
+} FsContext;
+
+typedef struct V9fsPath {
+    uint16_t size;
+    char *data;
+} V9fsPath;
+
+typedef union V9fsFidOpenState V9fsFidOpenState;
+
+void cred_init(FsCred *);
+
+typedef struct FileOperations
+{
+    int (*init)(struct FsContext *);
+    int (*lstat)(FsContext *, V9fsPath *, struct stat *);
+    ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
+    int (*chmod)(FsContext *, V9fsPath *, FsCred *);
+    int (*chown)(FsContext *, V9fsPath *, FsCred *);
+    int (*mknod)(FsContext *, V9fsPath *, const char *, FsCred *);
+    int (*utimensat)(FsContext *, V9fsPath *, const struct timespec *);
+    int (*remove)(FsContext *, const char *);
+    int (*symlink)(FsContext *, const char *, V9fsPath *,
+                   const char *, FsCred *);
+    int (*link)(FsContext *, V9fsPath *, V9fsPath *, const char *);
+    int (*setuid)(FsContext *, uid_t);
+    int (*close)(FsContext *, V9fsFidOpenState *);
+    int (*closedir)(FsContext *, V9fsFidOpenState *);
+    int (*opendir)(FsContext *, V9fsPath *, V9fsFidOpenState *);
+    int (*open)(FsContext *, V9fsPath *, int, V9fsFidOpenState *);
+    int (*open2)(FsContext *, V9fsPath *, const char *,
+                 int, FsCred *, V9fsFidOpenState *);
+    void (*rewinddir)(FsContext *, V9fsFidOpenState *);
+    off_t (*telldir)(FsContext *, V9fsFidOpenState *);
+    int (*readdir_r)(FsContext *, V9fsFidOpenState *,
+                     struct dirent *, struct dirent **);
+    void (*seekdir)(FsContext *, V9fsFidOpenState *, off_t);
+    ssize_t (*preadv)(FsContext *, V9fsFidOpenState *,
+                      const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
+                       const struct iovec *, int, off_t);
+    int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
+    int (*fstat)(FsContext *, int, V9fsFidOpenState *, struct stat *);
+    int (*rename)(FsContext *, const char *, const char *);
+    int (*truncate)(FsContext *, V9fsPath *, off_t);
+    int (*fsync)(FsContext *, int, V9fsFidOpenState *, int);
+    int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
+                         const char *, void *, size_t);
+    ssize_t (*llistxattr)(FsContext *, V9fsPath *, void *, size_t);
+    int (*lsetxattr)(FsContext *, V9fsPath *,
+                     const char *, void *, size_t, int);
+    int (*lremovexattr)(FsContext *, V9fsPath *, const char *);
+    int (*name_to_path)(FsContext *, V9fsPath *, const char *, V9fsPath *);
+    int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
+                    V9fsPath *newdir, const char *new_name);
+    int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
+    void *opaque;
+} FileOperations;
+
+#endif
diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c
new file mode 100644 (file)
index 0000000..4e700dd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Gautham R Shenoy <ego@in.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 <stdio.h>
+#include <string.h>
+#include "qemu-fsdev.h"
+#include "qemu-config.h"
+
+int qemu_fsdev_add(QemuOpts *opts)
+{
+    return 0;
+}
+
+static void fsdev_register_config(void)
+{
+    qemu_add_opts(&qemu_fsdev_opts);
+    qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
index 0b332907bdad073c1f22dd533bdd6dced8dc4f8b..6684f7ea90f886aac26902f507c1a8993bcc1f67 100644 (file)
 #include "qemu-common.h"
 #include "qemu-config.h"
 
-static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
-    QTAILQ_HEAD_INITIALIZER(fstype_entries);
+static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
+    QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
 
-static FsTypeTable FsTypes[] = {
+static FsDriverTable FsDrivers[] = {
     { .name = "local", .ops = &local_ops},
+#ifdef CONFIG_OPEN_BY_HANDLE
+    { .name = "handle", .ops = &handle_ops},
+#endif
+    { .name = "synth", .ops = &synth_ops},
 };
 
 int qemu_fsdev_add(QemuOpts *opts)
 {
-    struct FsTypeListEntry *fsle;
+    struct FsDriverListEntry *fsle;
     int i;
     const char *fsdev_id = qemu_opts_id(opts);
-    const char *fstype = qemu_opt_get(opts, "fstype");
+    const char *fsdriver = qemu_opt_get(opts, "fsdriver");
     const char *path = qemu_opt_get(opts, "path");
     const char *sec_model = qemu_opt_get(opts, "security_model");
+    const char *writeout = qemu_opt_get(opts, "writeout");
+    bool ro = qemu_opt_get_bool(opts, "readonly", 0);
 
     if (!fsdev_id) {
         fprintf(stderr, "fsdev: No id specified\n");
         return -1;
     }
 
-    if (fstype) {
-        for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
-            if (strcmp(FsTypes[i].name, fstype) == 0) {
+    if (fsdriver) {
+        for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) {
+            if (strcmp(FsDrivers[i].name, fsdriver) == 0) {
                 break;
             }
         }
 
-        if (i == ARRAY_SIZE(FsTypes)) {
-            fprintf(stderr, "fsdev: fstype %s not found\n", fstype);
+        if (i == ARRAY_SIZE(FsDrivers)) {
+            fprintf(stderr, "fsdev: fsdriver %s not found\n", fsdriver);
             return -1;
         }
     } else {
-        fprintf(stderr, "fsdev: No fstype specified\n");
+        fprintf(stderr, "fsdev: No fsdriver specified\n");
         return -1;
     }
 
-    if (!sec_model) {
-        fprintf(stderr, "fsdev: No security_model specified.\n");
+    if (!strcmp(fsdriver, "local") && !sec_model) {
+        fprintf(stderr, "security model not specified, "
+                "local fs needs security model\nvalid options are:"
+                "\tsecurity_model=[passthrough|mapped|none]\n");
+        return -1;
+    }
+
+    if (strcmp(fsdriver, "local") && sec_model) {
+        fprintf(stderr, "only local fs driver needs security model\n");
         return -1;
     }
 
@@ -65,24 +78,49 @@ int qemu_fsdev_add(QemuOpts *opts)
         return -1;
     }
 
-    fsle = qemu_malloc(sizeof(*fsle));
+    fsle = g_malloc(sizeof(*fsle));
 
-    fsle->fse.fsdev_id = qemu_strdup(fsdev_id);
-    fsle->fse.path = qemu_strdup(path);
-    fsle->fse.security_model = qemu_strdup(sec_model);
-    fsle->fse.ops = FsTypes[i].ops;
+    fsle->fse.fsdev_id = g_strdup(fsdev_id);
+    fsle->fse.path = g_strdup(path);
+    fsle->fse.ops = FsDrivers[i].ops;
+    fsle->fse.export_flags = 0;
+    if (writeout) {
+        if (!strcmp(writeout, "immediate")) {
+            fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
+        }
+    }
+    if (ro) {
+        fsle->fse.export_flags |= V9FS_RDONLY;
+    } else {
+        fsle->fse.export_flags &= ~V9FS_RDONLY;
+    }
 
-    QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next);
-    return 0;
+    if (strcmp(fsdriver, "local")) {
+        goto done;
+    }
 
+    if (!strcmp(sec_model, "passthrough")) {
+        fsle->fse.export_flags |= V9FS_SM_PASSTHROUGH;
+    } else if (!strcmp(sec_model, "mapped")) {
+        fsle->fse.export_flags |= V9FS_SM_MAPPED;
+    } else if (!strcmp(sec_model, "none")) {
+        fsle->fse.export_flags |= V9FS_SM_NONE;
+    } else {
+        fprintf(stderr, "Invalid security model %s specified, valid options are"
+                "\n\t [passthrough|mapped|none]\n", sec_model);
+        return -1;
+    }
+done:
+    QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next);
+    return 0;
 }
 
-FsTypeEntry *get_fsdev_fsentry(char *id)
+FsDriverEntry *get_fsdev_fsentry(char *id)
 {
     if (id) {
-        struct FsTypeListEntry *fsle;
+        struct FsDriverListEntry *fsle;
 
-        QTAILQ_FOREACH(fsle, &fstype_entries, next) {
+        QTAILQ_FOREACH(fsle, &fsdriver_entries, next) {
             if (strcmp(fsle->fse.fsdev_id, id) == 0) {
                 return &fsle->fse;
             }
index a704043bebdd703151eb5e66e5819f5d87324122..8ef847374aa6dbe21b87f4f4b24dd3b00dd83536 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"
 
 
 /*
  * -----------------
  *  etc
  */
-typedef struct FsTypeTable {
+typedef struct FsDriverTable {
     const char *name;
     FileOperations *ops;
-} FsTypeTable;
+} FsDriverTable;
 
 /*
  * Structure to store the various fsdev's passed through command line.
  */
-typedef struct FsTypeEntry {
+typedef struct FsDriverEntry {
     char *fsdev_id;
     char *path;
-    char *security_model;
+    int export_flags;
     FileOperations *ops;
-} FsTypeEntry;
+} FsDriverEntry;
 
-typedef struct FsTypeListEntry {
-    FsTypeEntry fse;
-    QTAILQ_ENTRY(FsTypeListEntry) next;
-} FsTypeListEntry;
+typedef struct FsDriverListEntry {
+    FsDriverEntry fse;
+    QTAILQ_ENTRY(FsDriverListEntry) next;
+} FsDriverListEntry;
 
 int qemu_fsdev_add(QemuOpts *opts);
-FsTypeEntry *get_fsdev_fsentry(char *id);
+FsDriverEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
+extern FileOperations handle_ops;
+extern FileOperations synth_ops;
 #endif
index d6556c9a2fe1268ff3c53f9238a2e8a7fc428c0e..640cf4ee2add8931a7d465a0252d9bf9da0f5745 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
 
 #define MAX_PACKET_LENGTH 4096
 
-#include "exec-all.h"
+#include "cpu.h"
 #include "qemu_socket.h"
 #include "kvm.h"
 
+#ifndef TARGET_CPU_MEMORY_RW_DEBUG
+static inline int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                                         uint8_t *buf, int len, int is_write)
+{
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+#else
+/* target_memory_rw_debug() defined in cpu.h */
+#endif
 
 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
 };
 
@@ -314,7 +328,7 @@ static int get_char(GDBState *s)
     int ret;
 
     for(;;) {
-        ret = recv(s->fd, &ch, 1, 0);
+        ret = qemu_recv(s->fd, &ch, 1, 0);
         if (ret < 0) {
             if (errno == ECONNRESET)
                 s->fd = -1;
@@ -377,7 +391,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
         }
     }
 #else
-    qemu_chr_write(s->chr, buf, len);
+    qemu_chr_fe_write(s->chr, buf, len);
 #endif
 }
 
@@ -719,7 +733,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
             {
                 if (gdb_has_xml)
                     return 0;
-                GET_REG32(0); /* fpscr */
+                GET_REG32(env->fpscr);
             }
         }
     }
@@ -800,7 +814,11 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 #if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
     if (n < 64) {
         /* fprs */
-        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+        if (n & 1) {
+            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+        }
     }
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     switch (n) {
@@ -817,15 +835,15 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 #else
     if (n < 64) {
         /* f0-f31 */
-        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+        if (n & 1) {
+            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+        }
     }
     if (n < 80) {
         /* f32-f62 (double width, even numbers only) */
-        uint64_t val;
-
-        val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32;
-        val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]);
-        GET_REG64(val);
+        GET_REG64(env->fpr[(n - 32) / 2].ll);
     }
     switch (n) {
     case 80: GET_REGL(env->pc);
@@ -864,7 +882,12 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 #if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
     else if (n < 64) {
         /* fprs */
-        *((uint32_t *)&env->fpr[n - 32]) = tmp;
+        /* f0-f31 */
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
     } else {
         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
         switch (n) {
@@ -882,12 +905,16 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 #else
     else if (n < 64) {
         /* f0-f31 */
-        env->fpr[n] = ldfl_p(mem_buf);
+        tmp = ldl_p(mem_buf);
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
         return 4;
     } else if (n < 80) {
         /* f32-f62 (double width, even numbers only) */
-        *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32;
-        *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp;
+        env->fpr[(n - 32) / 2].ll = tmp;
     } else {
         switch (n) {
         case 80: env->pc = tmp; break;
@@ -1100,10 +1127,6 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
             env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
             /* set rounding mode */
             RESTORE_ROUNDING_MODE;
-#ifndef CONFIG_SOFTFLOAT
-            /* no floating point exception for native float */
-            SET_FP_ENABLE(env->active_fpu.fcr31, 0);
-#endif
             break;
         case 71: env->active_fpu.fcr0 = tmp; break;
         }
@@ -1431,7 +1454,11 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
             /* XXX */
             break;
         case S390_PC_REGNUM: GET_REGL(env->psw.addr); break;
-        case S390_CC_REGNUM: GET_REG32(env->cc); break;
+        case S390_CC_REGNUM:
+            env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
+                                 env->cc_vr);
+            GET_REG32(env->cc_op);
+            break;
     }
 
     return 0;
@@ -1457,11 +1484,173 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
             /* XXX */
             break;
         case S390_PC_REGNUM: env->psw.addr = tmpl; break;
-        case S390_CC_REGNUM: env->cc = tmp32; r=4; break;
+        case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break;
     }
 
     return r;
 }
+#elif defined (TARGET_LM32)
+
+#include "hw/lm32_pic.h"
+#define NUM_CORE_REGS (32 + 7)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        GET_REG32(env->regs[n]);
+    } else {
+        switch (n) {
+        case 32:
+            GET_REG32(env->pc);
+            break;
+        /* FIXME: put in right exception ID */
+        case 33:
+            GET_REG32(0);
+            break;
+        case 34:
+            GET_REG32(env->eba);
+            break;
+        case 35:
+            GET_REG32(env->deba);
+            break;
+        case 36:
+            GET_REG32(env->ie);
+            break;
+        case 37:
+            GET_REG32(lm32_pic_get_im(env->pic_state));
+            break;
+        case 38:
+            GET_REG32(lm32_pic_get_ip(env->pic_state));
+            break;
+        }
+    }
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+        env->regs[n] = tmp;
+    } else {
+        switch (n) {
+        case 32:
+            env->pc = tmp;
+            break;
+        case 34:
+            env->eba = tmp;
+            break;
+        case 35:
+            env->deba = tmp;
+            break;
+        case 36:
+            env->ie = tmp;
+            break;
+        case 37:
+            lm32_pic_set_im(env->pic_state, tmp);
+            break;
+        case 38:
+            lm32_pic_set_ip(env->pic_state, tmp);
+            break;
+        }
+    }
+    return 4;
+}
+#elif defined(TARGET_XTENSA)
+
+/* Use num_core_regs to see only non-privileged registers in an unmodified gdb.
+ * Use num_regs to see all registers. gdb modification is required for that:
+ * reset bit 0 in the 'flags' field of the registers definitions in the
+ * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
+ */
+#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
+#define num_g_regs NUM_CORE_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        GET_REG32(env->pc);
+        break;
+
+    case 1: /*ar*/
+        xtensa_sync_phys_from_window(env);
+        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
+        break;
+
+    case 2: /*SR*/
+        GET_REG32(env->sregs[reg->targno & 0xff]);
+        break;
+
+    case 3: /*UR*/
+        GET_REG32(env->uregs[reg->targno & 0xff]);
+        break;
+
+    case 8: /*a*/
+        GET_REG32(env->regs[reg->targno & 0x0f]);
+        break;
+
+    default:
+        qemu_log("%s from reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        env->pc = tmp;
+        break;
+
+    case 1: /*ar*/
+        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+        xtensa_sync_window_from_phys(env);
+        break;
+
+    case 2: /*SR*/
+        env->sregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 3: /*UR*/
+        env->uregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 8: /*a*/
+        env->regs[reg->targno & 0x0f] = tmp;
+        break;
+
+    default:
+        qemu_log("%s to reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+
+    return 4;
+}
 #else
 
 #define NUM_CORE_REGS 0
@@ -1478,7 +1667,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 
 #endif
 
+#if !defined(TARGET_XTENSA)
 static int num_g_regs = NUM_CORE_REGS;
+#endif
 
 #ifdef GDB_CORE_XML
 /* Encode data using the encoding for 'x' packets.  */
@@ -1575,6 +1766,7 @@ static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
     return 0;
 }
 
+#if !defined(TARGET_XTENSA)
 /* Register a supplemental set of CPU registers.  If g_pos is nonzero it
    specifies the first register number and these registers are included in
    a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
@@ -1589,12 +1781,6 @@ void gdb_register_coprocessor(CPUState * env,
     GDBRegisterState **p;
     static int last_reg = NUM_CORE_REGS;
 
-    s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState));
-    s->base_reg = last_reg;
-    s->num_regs = num_regs;
-    s->get_reg = get_reg;
-    s->set_reg = set_reg;
-    s->xml = xml;
     p = &env->gdb_regs;
     while (*p) {
         /* Check for duplicates.  */
@@ -1602,6 +1788,14 @@ void gdb_register_coprocessor(CPUState * env,
             return;
         p = &(*p)->next;
     }
+
+    s = g_new0(GDBRegisterState, 1);
+    s->base_reg = last_reg;
+    s->num_regs = num_regs;
+    s->get_reg = get_reg;
+    s->set_reg = set_reg;
+    s->xml = xml;
+
     /* Add to end of list.  */
     last_reg += num_regs;
     *p = s;
@@ -1614,6 +1808,7 @@ void gdb_register_coprocessor(CPUState * env,
         }
     }
 }
+#endif
 
 #ifndef CONFIG_USER_ONLY
 static const int xlat_gdb_type[] = {
@@ -1737,6 +1932,10 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #elif defined (TARGET_S390X)
     cpu_synchronize_state(s->c_cpu);
     s->c_cpu->psw.addr = pc;
+#elif defined (TARGET_LM32)
+    s->c_cpu->pc = pc;
+#elif defined(TARGET_XTENSA)
+    s->c_cpu->pc = pc;
 #endif
 }
 
@@ -1907,6 +2106,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'g':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         len = 0;
         for (addr = 0; addr < num_g_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1917,6 +2117,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'G':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
@@ -1932,7 +2133,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ',')
             p++;
         len = strtoull(p, NULL, 16);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
             put_packet (s, "E14");
         } else {
             memtohex(buf, mem_buf, len);
@@ -1947,10 +2148,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
             put_packet(s, "E14");
-        else
+        } else {
             put_packet(s, "OK");
+        }
         break;
     case 'p':
         /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
@@ -2113,7 +2315,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             hextomem(mem_buf, p + 5, len);
             len = len / 2;
             mem_buf[len++] = 0;
-            qemu_chr_read(s->mon_chr, mem_buf, len);
+            qemu_chr_be_write(s->mon_chr, mem_buf, len);
             put_packet(s, "OK");
             break;
         }
@@ -2186,7 +2388,7 @@ void gdb_set_stop_cpu(CPUState *env)
 }
 
 #ifndef CONFIG_USER_ONLY
-static void gdb_vm_state_change(void *opaque, int running, int reason)
+static void gdb_vm_state_change(void *opaque, int running, RunState state)
 {
     GDBState *s = gdbserver_state;
     CPUState *env = s->c_cpu;
@@ -2194,14 +2396,11 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
     const char *type;
     int ret;
 
-    if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
-        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 == EXCP_DEBUG) {
+    }
+    switch (state) {
+    case RUN_STATE_DEBUG:
         if (env->watchpoint_hit) {
             switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
@@ -2218,17 +2417,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 RUN_STATE_PAUSED:
         ret = GDB_SIGNAL_INT;
+        break;
+    case RUN_STATE_SHUTDOWN:
+        ret = GDB_SIGNAL_QUIT;
+        break;
+    case RUN_STATE_IO_ERROR:
+        ret = GDB_SIGNAL_IO;
+        break;
+    case RUN_STATE_WATCHDOG:
+        ret = GDB_SIGNAL_ALRM;
+        break;
+    case RUN_STATE_INTERNAL_ERROR:
+        ret = GDB_SIGNAL_ABRT;
+        break;
+    case RUN_STATE_SAVE_VM:
+    case RUN_STATE_RESTORE_VM:
+        return;
+    case RUN_STATE_FINISH_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
 
@@ -2252,7 +2478,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
     gdb_current_syscall_cb = cb;
     s->state = RS_SYSCALL;
 #ifndef CONFIG_USER_ONLY
-    vm_stop(EXCP_DEBUG);
+    vm_stop(RUN_STATE_DEBUG);
 #endif
     s->state = RS_IDLE;
     va_start(va, fmt);
@@ -2323,10 +2549,10 @@ static void gdb_read_byte(GDBState *s, int ch)
         if (ch != '$')
             return;
     }
-    if (vm_running) {
+    if (runstate_is_running()) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
-        vm_stop(EXCP_INTERRUPT);
+        vm_stop(RUN_STATE_PAUSED);
     } else
 #endif
     {
@@ -2394,7 +2620,7 @@ void gdb_exit(CPUState *env, int code)
 
 #ifndef CONFIG_USER_ONLY
   if (s->chr) {
-      qemu_chr_close(s->chr);
+      qemu_chr_delete(s->chr);
   }
 #endif
 }
@@ -2501,7 +2727,7 @@ static void gdb_accept(void)
     val = 1;
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 
-    s = qemu_mallocz(sizeof(GDBState));
+    s = g_malloc0(sizeof(GDBState));
     s->c_cpu = first_cpu;
     s->g_cpu = first_cpu;
     s->fd = fd;
@@ -2588,7 +2814,7 @@ static void gdb_chr_event(void *opaque, int event)
 {
     switch (event) {
     case CHR_EVENT_OPENED:
-        vm_stop(EXCP_INTERRUPT);
+        vm_stop(RUN_STATE_PAUSED);
         gdb_has_xml = 0;
         break;
     default:
@@ -2628,8 +2854,9 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
 #ifndef _WIN32
 static void gdb_sigterm_handler(int signal)
 {
-    if (vm_running)
-        vm_stop(EXCP_INTERRUPT);
+    if (runstate_is_running()) {
+        vm_stop(RUN_STATE_PAUSED);
+    }
 }
 #endif
 
@@ -2658,7 +2885,7 @@ int gdbserver_start(const char *device)
             sigaction(SIGINT, &act, NULL);
         }
 #endif
-        chr = qemu_chr_open("gdb", device, NULL);
+        chr = qemu_chr_new("gdb", device, NULL);
         if (!chr)
             return -1;
 
@@ -2668,18 +2895,18 @@ int gdbserver_start(const char *device)
 
     s = gdbserver_state;
     if (!s) {
-        s = qemu_mallocz(sizeof(GDBState));
+        s = g_malloc0(sizeof(GDBState));
         gdbserver_state = s;
 
         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
 
         /* Initialize a monitor terminal for gdb */
-        mon_chr = qemu_mallocz(sizeof(*mon_chr));
+        mon_chr = g_malloc0(sizeof(*mon_chr));
         mon_chr->chr_write = gdb_monitor_write;
         monitor_init(mon_chr, 0);
     } else {
         if (s->chr)
-            qemu_chr_close(s->chr);
+            qemu_chr_delete(s->chr);
         mon_chr = s->mon_chr;
         memset(s, 0, sizeof(GDBState));
     }
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/hax.h b/hax.h
new file mode 100644 (file)
index 0000000..99aaa48
--- /dev/null
+++ b/hax.h
@@ -0,0 +1,48 @@
+/* header to be included in non-HAX-specific code */
+#ifndef _HAX_H
+#define _HAX_H
+
+#include "config-host.h"
+#include "qemu-common.h"
+//#include "cpu.h"
+#include "kvm.h"
+#include "hw/hw.h"
+#include "bitops.h"
+
+extern int hax_disabled;
+#define dprint printf
+#ifdef CONFIG_HAX
+int hax_enabled(void);
+int hax_pre_init(ram_addr_t ram_size);
+int hax_init(void);
+int hax_sync_vcpus(void);
+#ifdef NEED_CPU_H
+int hax_init_vcpu(CPUState *env);
+int hax_vcpu_exec(CPUState *env);
+void hax_vcpu_sync_state(CPUState *env, int modified);
+//extern void hax_cpu_synchronize_state(CPUState *env);
+//extern void hax_cpu_synchronize_post_reset(CPUState *env);
+//extern void hax_cpu_synchronize_post_init(CPUState *env);
+int hax_populate_ram(uint64_t va, uint32_t size);
+int hax_set_phys_mem(target_phys_addr_t start_addr,
+                     ram_addr_t size, ram_addr_t phys_offset);
+int hax_vcpu_emulation_mode(CPUState *env);
+int hax_stop_emulation(CPUState *env);
+int hax_stop_translate(CPUState *env);
+int hax_arch_get_registers(CPUState *env);
+int hax_vcpu_destroy(CPUState *env);
+void hax_raise_event(CPUState *env);
+int need_handle_intr_request(CPUState *env);
+int hax_handle_io(CPUState *env, uint32_t df, uint16_t port, int direction,
+                int size, int count, void *buffer);
+void qemu_notify_hax_event(void);
+#endif
+void hax_reset_vcpu_state(void *opaque);
+
+#include "target-i386/hax-interface.h"
+#include "target-i386/hax-i386.h"
+#else
+#define hax_enabled() (0)
+#endif
+
+#endif
index 372bef42902054c08e1f4d4c019f42d9449bb1df..089c1ac23d4c21f1db51e6c18c50c601e5017863 100644 (file)
@@ -43,7 +43,7 @@ ETEXI
         .params     = "",
         .help       = "quit the emulator",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_quit,
+        .mhandler.cmd = hmp_quit,
     },
 
 STEXI
@@ -180,13 +180,12 @@ STEXI
 Output logs to @var{filename}.
 ETEXI
 
-#ifdef CONFIG_SIMPLE_TRACE
     {
         .name       = "trace-event",
         .args_type  = "name:s,option:b",
         .params     = "name on|off",
         .help       = "changes status of a specific trace event",
-        .mhandler.cmd = do_change_trace_event_state,
+        .mhandler.cmd = do_trace_event_set_state,
     },
 
 STEXI
@@ -195,6 +194,7 @@ STEXI
 changes status of a trace event
 ETEXI
 
+#if defined(CONFIG_TRACE_SIMPLE)
     {
         .name       = "trace-file",
         .args_type  = "op:s?,arg:F?",
@@ -290,8 +290,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "stop emulation",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_stop,
+        .mhandler.cmd = hmp_stop,
     },
 
 STEXI
@@ -478,8 +477,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "reset the system",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_reset,
+        .mhandler.cmd = hmp_system_reset,
     },
 
 STEXI
@@ -494,8 +492,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "send system power down event",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_powerdown,
+        .mhandler.cmd = hmp_system_powerdown,
     },
 
 STEXI
@@ -590,8 +587,7 @@ ETEXI
         .args_type  = "index:i",
         .params     = "index",
         .help       = "set the default CPU",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_cpu_set,
+        .mhandler.cmd = hmp_cpu,
     },
 
 STEXI
@@ -740,10 +736,11 @@ ETEXI
 #if defined(TARGET_I386)
     {
         .name       = "nmi",
-        .args_type  = "cpu_index:i",
-        .params     = "cpu",
-        .help       = "inject an NMI on the given CPU",
-        .mhandler.cmd = do_inject_nmi,
+        .args_type  = "",
+        .params     = "",
+        .help       = "inject an NMI on all guest's CPUs",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_inject_nmi,
     },
 #endif
 STEXI
@@ -821,16 +818,13 @@ Set maximum tolerated downtime (in seconds) for migration.
 ETEXI
 
     {
-        .name       = "snapshot_blkdev",
-        .args_type  = "device:B,snapshot_file:s?,format:s?",
-        .params     = "device [new-image-file] [format]",
-        .help       = "initiates a live snapshot\n\t\t\t"
-                      "of device. If a new image file is specified, the\n\t\t\t"
-                      "new image file will become the new root image.\n\t\t\t"
-                      "If format is specified, the snapshot file will\n\t\t\t"
-                      "be created in that format. Otherwise the\n\t\t\t"
-                      "snapshot will be internal! (currently unsupported)",
-        .mhandler.cmd_new = do_snapshot_blkdev,
+        .name       = "client_migrate_info",
+        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+        .params     = "protocol hostname port tls-port cert-subject",
+        .help       = "send migration info to spice/vnc client",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = client_migrate_info,
+        .flags      = MONITOR_CMD_ASYNC,
     },
 
 STEXI
@@ -842,12 +836,16 @@ new parameters (if specified) once the vm migration finished successfully.
 ETEXI
 
     {
-        .name       = "client_migrate_info",
-        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
-        .params     = "protocol hostname port tls-port cert-subject",
-        .help       = "send migration info to spice/vnc client",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = client_migrate_info,
+        .name       = "snapshot_blkdev",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .help       = "initiates a live snapshot\n\t\t\t"
+                      "of device. If a new image file is specified, the\n\t\t\t"
+                      "new image file will become the new root image.\n\t\t\t"
+                      "If format is specified, the snapshot file will\n\t\t\t"
+                      "be created in that format. Otherwise the\n\t\t\t"
+                      "snapshot will be internal! (currently unsupported)",
+        .mhandler.cmd_new = do_snapshot_blkdev,
     },
 
 STEXI
@@ -1305,13 +1303,11 @@ show i8259 (PIC) state
 @item info pci
 show emulated PCI device info
 @item info tlb
-show virtual to physical memory mappings (i386, SH4 and SPARC only)
+show virtual to physical memory mappings (i386, SH4, SPARC, and PPC only)
 @item info mem
 show the active virtual memory mappings (i386 only)
 @item info jit
 show dynamic compiler info
-@item info kvm
-show KVM information
 @item info numa
 show NUMA information
 @item info kvm
@@ -1355,14 +1351,17 @@ show roms
 @end table
 ETEXI
 
-#ifdef CONFIG_SIMPLE_TRACE
+#ifdef CONFIG_TRACE_SIMPLE
 STEXI
 @item info trace
 show contents of trace buffer
+ETEXI
+#endif
+
+STEXI
 @item info trace-events
 show available trace events and their state
 ETEXI
-#endif
 
 STEXI
 @end table
diff --git a/hmp.c b/hmp.c
new file mode 100644 (file)
index 0000000..443d3a7
--- /dev/null
+++ b/hmp.c
@@ -0,0 +1,523 @@
+/*
+ * Human Monitor Interface
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "hmp.h"
+#include "qmp-commands.h"
+
+void hmp_info_name(Monitor *mon)
+{
+    NameInfo *info;
+
+    info = qmp_query_name(NULL);
+    if (info->has_name) {
+        monitor_printf(mon, "%s\n", info->name);
+    }
+    qapi_free_NameInfo(info);
+}
+
+void hmp_info_version(Monitor *mon)
+{
+    VersionInfo *info;
+
+    info = qmp_query_version(NULL);
+
+    monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
+                   info->qemu.major, info->qemu.minor, info->qemu.micro,
+                   info->package);
+
+    qapi_free_VersionInfo(info);
+}
+
+void hmp_info_kvm(Monitor *mon)
+{
+    KvmInfo *info;
+
+    info = qmp_query_kvm(NULL);
+    monitor_printf(mon, "kvm support: ");
+    if (info->present) {
+        monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
+    } else {
+        monitor_printf(mon, "not compiled\n");
+    }
+
+    qapi_free_KvmInfo(info);
+}
+
+void hmp_info_status(Monitor *mon)
+{
+    StatusInfo *info;
+
+    info = qmp_query_status(NULL);
+
+    monitor_printf(mon, "VM status: %s%s",
+                   info->running ? "running" : "paused",
+                   info->singlestep ? " (single step mode)" : "");
+
+    if (!info->running && info->status != RUN_STATE_PAUSED) {
+        monitor_printf(mon, " (%s)", RunState_lookup[info->status]);
+    }
+
+    monitor_printf(mon, "\n");
+
+    qapi_free_StatusInfo(info);
+}
+
+void hmp_info_uuid(Monitor *mon)
+{
+    UuidInfo *info;
+
+    info = qmp_query_uuid(NULL);
+    monitor_printf(mon, "%s\n", info->UUID);
+    qapi_free_UuidInfo(info);
+}
+
+void hmp_info_chardev(Monitor *mon)
+{
+    ChardevInfoList *char_info, *info;
+
+    char_info = qmp_query_chardev(NULL);
+    for (info = char_info; info; info = info->next) {
+        monitor_printf(mon, "%s: filename=%s\n", info->value->label,
+                                                 info->value->filename);
+    }
+
+    qapi_free_ChardevInfoList(char_info);
+}
+
+void hmp_info_mice(Monitor *mon)
+{
+    MouseInfoList *mice_list, *mouse;
+
+    mice_list = qmp_query_mice(NULL);
+    if (!mice_list) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    for (mouse = mice_list; mouse; mouse = mouse->next) {
+        monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
+                       mouse->value->current ? '*' : ' ',
+                       mouse->value->index, mouse->value->name,
+                       mouse->value->absolute ? " (absolute)" : "");
+    }
+
+    qapi_free_MouseInfoList(mice_list);
+}
+
+void hmp_info_migrate(Monitor *mon)
+{
+    MigrationInfo *info;
+
+    info = qmp_query_migrate(NULL);
+
+    if (info->has_status) {
+        monitor_printf(mon, "Migration status: %s\n", info->status);
+    }
+
+    if (info->has_ram) {
+        monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
+                       info->ram->transferred >> 10);
+        monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
+                       info->ram->remaining >> 10);
+        monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
+                       info->ram->total >> 10);
+    }
+
+    if (info->has_disk) {
+        monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
+                       info->disk->transferred >> 10);
+        monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
+                       info->disk->remaining >> 10);
+        monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
+                       info->disk->total >> 10);
+    }
+
+    qapi_free_MigrationInfo(info);
+}
+
+void hmp_info_cpus(Monitor *mon)
+{
+    CpuInfoList *cpu_list, *cpu;
+
+    cpu_list = qmp_query_cpus(NULL);
+
+    for (cpu = cpu_list; cpu; cpu = cpu->next) {
+        int active = ' ';
+
+        if (cpu->value->CPU == monitor_get_cpu_index()) {
+            active = '*';
+        }
+
+        monitor_printf(mon, "%c CPU #%" PRId64 ": ", active, cpu->value->CPU);
+
+        if (cpu->value->has_pc) {
+            monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+        }
+        if (cpu->value->has_nip) {
+            monitor_printf(mon, "nip=0x%016" PRIx64, cpu->value->nip);
+        }
+        if (cpu->value->has_npc) {
+            monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+            monitor_printf(mon, "npc=0x%016" PRIx64, cpu->value->npc);
+        }
+        if (cpu->value->has_PC) {
+            monitor_printf(mon, "PC=0x%016" PRIx64, cpu->value->PC);
+        }
+
+        if (cpu->value->halted) {
+            monitor_printf(mon, " (halted)");
+        }
+
+        monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
+    }
+
+    qapi_free_CpuInfoList(cpu_list);
+}
+
+void hmp_info_block(Monitor *mon)
+{
+    BlockInfoList *block_list, *info;
+
+    block_list = qmp_query_block(NULL);
+
+    for (info = block_list; info; info = info->next) {
+        monitor_printf(mon, "%s: removable=%d",
+                       info->value->device, info->value->removable);
+
+        if (info->value->removable) {
+            monitor_printf(mon, " locked=%d", info->value->locked);
+            monitor_printf(mon, " tray-open=%d", info->value->tray_open);
+        }
+
+        if (info->value->has_io_status) {
+            monitor_printf(mon, " io-status=%s",
+                           BlockDeviceIoStatus_lookup[info->value->io_status]);
+        }
+
+        if (info->value->has_inserted) {
+            monitor_printf(mon, " file=");
+            monitor_print_filename(mon, info->value->inserted->file);
+
+            if (info->value->inserted->has_backing_file) {
+                monitor_printf(mon, " backing_file=");
+                monitor_print_filename(mon, info->value->inserted->backing_file);
+            }
+            monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
+                           info->value->inserted->ro,
+                           info->value->inserted->drv,
+                           info->value->inserted->encrypted);
+        } else {
+            monitor_printf(mon, " [not inserted]");
+        }
+
+        monitor_printf(mon, "\n");
+    }
+
+    qapi_free_BlockInfoList(block_list);
+}
+
+void hmp_info_blockstats(Monitor *mon)
+{
+    BlockStatsList *stats_list, *stats;
+
+    stats_list = qmp_query_blockstats(NULL);
+
+    for (stats = stats_list; stats; stats = stats->next) {
+        if (!stats->value->has_device) {
+            continue;
+        }
+
+        monitor_printf(mon, "%s:", stats->value->device);
+        monitor_printf(mon, " rd_bytes=%" PRId64
+                       " wr_bytes=%" PRId64
+                       " rd_operations=%" PRId64
+                       " wr_operations=%" PRId64
+                       " flush_operations=%" PRId64
+                       " wr_total_time_ns=%" PRId64
+                       " rd_total_time_ns=%" PRId64
+                       " flush_total_time_ns=%" PRId64
+                       "\n",
+                       stats->value->stats->rd_bytes,
+                       stats->value->stats->wr_bytes,
+                       stats->value->stats->rd_operations,
+                       stats->value->stats->wr_operations,
+                       stats->value->stats->flush_operations,
+                       stats->value->stats->wr_total_time_ns,
+                       stats->value->stats->rd_total_time_ns,
+                       stats->value->stats->flush_total_time_ns);
+    }
+
+    qapi_free_BlockStatsList(stats_list);
+}
+
+void hmp_info_vnc(Monitor *mon)
+{
+    VncInfo *info;
+    Error *err = NULL;
+    VncClientInfoList *client;
+
+    info = qmp_query_vnc(&err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+
+    if (!info->enabled) {
+        monitor_printf(mon, "Server: disabled\n");
+        goto out;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    if (info->has_host && info->has_service) {
+        monitor_printf(mon, "     address: %s:%s\n", info->host, info->service);
+    }
+    if (info->has_auth) {
+        monitor_printf(mon, "        auth: %s\n", info->auth);
+    }
+
+    if (!info->has_clients || info->clients == NULL) {
+        monitor_printf(mon, "Client: none\n");
+    } else {
+        for (client = info->clients; client; client = client->next) {
+            monitor_printf(mon, "Client:\n");
+            monitor_printf(mon, "     address: %s:%s\n",
+                           client->value->host, client->value->service);
+            monitor_printf(mon, "  x509_dname: %s\n",
+                           client->value->x509_dname ?
+                           client->value->x509_dname : "none");
+            monitor_printf(mon, "    username: %s\n",
+                           client->value->has_sasl_username ?
+                           client->value->sasl_username : "none");
+        }
+    }
+
+out:
+    qapi_free_VncInfo(info);
+}
+
+void hmp_info_spice(Monitor *mon)
+{
+    SpiceChannelList *chan;
+    SpiceInfo *info;
+
+    info = qmp_query_spice(NULL);
+
+    if (!info->enabled) {
+        monitor_printf(mon, "Server: disabled\n");
+        goto out;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    if (info->has_port) {
+        monitor_printf(mon, "     address: %s:%" PRId64 "\n",
+                       info->host, info->port);
+    }
+    if (info->has_tls_port) {
+        monitor_printf(mon, "     address: %s:%" PRId64 " [tls]\n",
+                       info->host, info->tls_port);
+    }
+    monitor_printf(mon, "        auth: %s\n", info->auth);
+    monitor_printf(mon, "    compiled: %s\n", info->compiled_version);
+
+    if (!info->has_channels || info->channels == NULL) {
+        monitor_printf(mon, "Channels: none\n");
+    } else {
+        for (chan = info->channels; chan; chan = chan->next) {
+            monitor_printf(mon, "Channel:\n");
+            monitor_printf(mon, "     address: %s:%s%s\n",
+                           chan->value->host, chan->value->port,
+                           chan->value->tls ? " [tls]" : "");
+            monitor_printf(mon, "     session: %" PRId64 "\n",
+                           chan->value->connection_id);
+            monitor_printf(mon, "     channel: %" PRId64 ":%" PRId64 "\n",
+                           chan->value->channel_type, chan->value->channel_id);
+        }
+    }
+
+out:
+    qapi_free_SpiceInfo(info);
+}
+
+void hmp_info_balloon(Monitor *mon)
+{
+    BalloonInfo *info;
+    Error *err = NULL;
+
+    info = qmp_query_balloon(&err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+
+    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
+    if (info->has_mem_swapped_in) {
+        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
+    }
+    if (info->has_mem_swapped_out) {
+        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
+    }
+    if (info->has_major_page_faults) {
+        monitor_printf(mon, " major_page_faults=%" PRId64,
+                       info->major_page_faults);
+    }
+    if (info->has_minor_page_faults) {
+        monitor_printf(mon, " minor_page_faults=%" PRId64,
+                       info->minor_page_faults);
+    }
+    if (info->has_free_mem) {
+        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
+    }
+    if (info->has_total_mem) {
+        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
+    }
+
+    monitor_printf(mon, "\n");
+
+    qapi_free_BalloonInfo(info);
+}
+
+static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
+{
+    PciMemoryRegionList *region;
+
+    monitor_printf(mon, "  Bus %2" PRId64 ", ", dev->bus);
+    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+                   dev->slot, dev->function);
+    monitor_printf(mon, "    ");
+
+    if (dev->class_info.has_desc) {
+        monitor_printf(mon, "%s", dev->class_info.desc);
+    } else {
+        monitor_printf(mon, "Class %04" PRId64, dev->class_info.class);
+    }
+
+    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+                   dev->id.vendor, dev->id.device);
+
+    if (dev->has_irq) {
+        monitor_printf(mon, "      IRQ %" PRId64 ".\n", dev->irq);
+    }
+
+    if (dev->has_pci_bridge) {
+        monitor_printf(mon, "      BUS %" PRId64 ".\n",
+                       dev->pci_bridge->bus.number);
+        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
+                       dev->pci_bridge->bus.secondary);
+        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
+                       dev->pci_bridge->bus.subordinate);
+
+        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
+                       dev->pci_bridge->bus.io_range->base,
+                       dev->pci_bridge->bus.io_range->limit);
+
+        monitor_printf(mon,
+                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       dev->pci_bridge->bus.memory_range->base,
+                       dev->pci_bridge->bus.memory_range->limit);
+
+        monitor_printf(mon, "      prefetchable memory range "
+                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       dev->pci_bridge->bus.prefetchable_range->base,
+                       dev->pci_bridge->bus.prefetchable_range->limit);
+    }
+
+    for (region = dev->regions; region; region = region->next) {
+        uint64_t addr, size;
+
+        addr = region->value->address;
+        size = region->value->size;
+
+        monitor_printf(mon, "      BAR%" PRId64 ": ", region->value->bar);
+
+        if (!strcmp(region->value->type, "io")) {
+            monitor_printf(mon, "I/O at 0x%04" PRIx64
+                                " [0x%04" PRIx64 "].\n",
+                           addr, addr + size - 1);
+        } else {
+            monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
+                               " [0x%08" PRIx64 "].\n",
+                           region->value->mem_type_64 ? 64 : 32,
+                           region->value->prefetch ? " prefetchable" : "",
+                           addr, addr + size - 1);
+        }
+    }
+
+    monitor_printf(mon, "      id \"%s\"\n", dev->qdev_id);
+
+    if (dev->has_pci_bridge) {
+        if (dev->pci_bridge->has_devices) {
+            PciDeviceInfoList *cdev;
+            for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
+                hmp_info_pci_device(mon, cdev->value);
+            }
+        }
+    }
+}
+
+void hmp_info_pci(Monitor *mon)
+{
+    PciInfoList *info;
+    Error *err = NULL;
+
+    info = qmp_query_pci(&err);
+    if (err) {
+        monitor_printf(mon, "PCI devices not supported\n");
+        error_free(err);
+        return;
+    }
+
+    for (; info; info = info->next) {
+        PciDeviceInfoList *dev;
+
+        for (dev = info->value->devices; dev; dev = dev->next) {
+            hmp_info_pci_device(mon, dev->value);
+        }
+    }
+
+    qapi_free_PciInfoList(info);
+}
+
+void hmp_quit(Monitor *mon, const QDict *qdict)
+{
+    monitor_suspend(mon);
+    qmp_quit(NULL);
+}
+
+void hmp_stop(Monitor *mon, const QDict *qdict)
+{
+    qmp_stop(NULL);
+}
+
+void hmp_system_reset(Monitor *mon, const QDict *qdict)
+{
+    qmp_system_reset(NULL);
+}
+
+void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
+{
+    qmp_system_powerdown(NULL);
+}
+
+void hmp_cpu(Monitor *mon, const QDict *qdict)
+{
+    int64_t cpu_index;
+
+    /* XXX: drop the monitor_set_cpu() usage when all HMP commands that
+            use it are converted to the QAPI */
+    cpu_index = qdict_get_int(qdict, "index");
+    if (monitor_set_cpu(cpu_index) < 0) {
+        monitor_printf(mon, "invalid CPU index\n");
+    }
+}
diff --git a/hmp.h b/hmp.h
new file mode 100644 (file)
index 0000000..4422578
--- /dev/null
+++ b/hmp.h
@@ -0,0 +1,41 @@
+/*
+ * Human Monitor Interface
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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.
+ *
+ */
+
+#ifndef HMP_H
+#define HMP_H
+
+#include "qemu-common.h"
+#include "qapi-types.h"
+
+void hmp_info_name(Monitor *mon);
+void hmp_info_version(Monitor *mon);
+void hmp_info_kvm(Monitor *mon);
+void hmp_info_status(Monitor *mon);
+void hmp_info_uuid(Monitor *mon);
+void hmp_info_chardev(Monitor *mon);
+void hmp_info_mice(Monitor *mon);
+void hmp_info_migrate(Monitor *mon);
+void hmp_info_cpus(Monitor *mon);
+void hmp_info_block(Monitor *mon);
+void hmp_info_blockstats(Monitor *mon);
+void hmp_info_vnc(Monitor *mon);
+void hmp_info_spice(Monitor *mon);
+void hmp_info_balloon(Monitor *mon);
+void hmp_info_pci(Monitor *mon);
+void hmp_quit(Monitor *mon, const QDict *qdict);
+void hmp_stop(Monitor *mon, const QDict *qdict);
+void hmp_system_reset(Monitor *mon, const QDict *qdict);
+void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
+void hmp_cpu(Monitor *mon, const QDict *qdict);
+
+#endif
index 0ddc17658295a9f9d4c1a05e45c8489efdfa5a7a..821db93671778513a426f8fdca961585a2e6614f 100644 (file)
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 
-#include "osdep.h"
+#include "compiler.h"   /* QEMU_GNUC_PREREQ */
 
 #if defined(__x86_64__)
 #define __HAVE_FAST_MULU64__
index 49f99c8d9ea0c9cdff794d082792869c2828e634..435da7355328fbb423a89ed3cbe75f18b020306c 100644 (file)
@@ -1645,7 +1645,7 @@ static const char *const fp_reg_names[] =
 
 typedef unsigned int CORE_ADDR;
 
-/* Get at various relevent fields of an instruction word.  */
+/* Get at various relevant fields of an instruction word.  */
 
 #define MASK_5  0x1f
 #define MASK_10 0x3ff
@@ -1771,13 +1771,13 @@ static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" };
 static void
 fput_reg (unsigned reg, disassemble_info *info)
 {
-  (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0");
+  (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0");
 }
 
 static void
 fput_fp_reg (unsigned reg, disassemble_info *info)
 {
-  (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0");
+  (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0");
 }
 
 static void
@@ -1794,7 +1794,7 @@ fput_fp_reg_r (unsigned reg, disassemble_info *info)
 static void
 fput_creg (unsigned reg, disassemble_info *info)
 {
-  (*info->fprintf_func) (info->stream, control_reg[reg]);
+  (*info->fprintf_func) (info->stream, "%s", control_reg[reg]);
 }
 
 /* Print constants with sign.  */
diff --git a/hppa.ld b/hppa.ld
index 9a4b22c022edbcc2548a478e0763b468f16e7698..3555b3e8e805330d40e9601f3f7a4a9fc84151cd 100644 (file)
--- a/hppa.ld
+++ b/hppa.ld
@@ -75,36 +75,34 @@ SECTIONS
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .PARISC.unwind   : { *(.PARISC.unwind) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN(0x10000) + (. & (0x10000 - 1));
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
new file mode 100644 (file)
index 0000000..9b6d47d
--- /dev/null
@@ -0,0 +1,168 @@
+
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "fsdev/qemu-fsdev.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p-coth.h"
+
+int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
+                      struct dirent **result)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            errno = 0;
+            err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result);
+            if (!*result && errno) {
+                err = -errno;
+            } else {
+                err = 0;
+            }
+        });
+    return err;
+}
+
+off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
+{
+    off_t err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->telldir(&s->ctx, &fidp->fs);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
+{
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
+    v9fs_co_run_in_worker(
+        {
+            s->ops->seekdir(&s->ctx, &fidp->fs, offset);
+        });
+}
+
+void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
+{
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
+    v9fs_co_run_in_worker(
+        {
+            s->ops->rewinddir(&s->ctx, &fidp->fs);
+        });
+}
+
+int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
+                  mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
+{
+    int err;
+    FsCred cred;
+    V9fsPath path;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
+    cred_init(&cred);
+    cred.fc_mode = mode;
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->mkdir(&s->ctx, &fidp->path, name->data,  &cred);
+            if (err < 0) {
+                err = -errno;
+            } else {
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
+                }
+                v9fs_path_free(&path);
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
+            if (err < 0) {
+                err = -errno;
+            } else {
+                err = 0;
+            }
+        });
+    v9fs_path_unlock(s);
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(pdu);
+        }
+    }
+    return err;
+}
+
+int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->closedir(&s->ctx, fs);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    if (!err) {
+        total_open_fd--;
+    }
+    return err;
+}
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
new file mode 100644 (file)
index 0000000..b15838c
--- /dev/null
@@ -0,0 +1,261 @@
+
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "fsdev/qemu-fsdev.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p-coth.h"
+
+int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
+                   V9fsStatDotl *v9stat)
+{
+    int err = 0;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    if (s->ctx.exops.get_st_gen) {
+        v9fs_path_read_lock(s);
+        v9fs_co_run_in_worker(
+            {
+                err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
+                                              &v9stat->st_gen);
+                if (err < 0) {
+                    err = -errno;
+                }
+            });
+        v9fs_path_unlock(s);
+    }
+    return err;
+}
+
+int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lstat(&s->ctx, path, stbuf);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
+            if (err == -1) {
+                err = -errno;
+            } else {
+                err = 0;
+            }
+        });
+    v9fs_path_unlock(s);
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(pdu);
+        }
+    }
+    return err;
+}
+
+int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+                  int flags, int mode, struct stat *stbuf)
+{
+    int err;
+    FsCred cred;
+    V9fsPath path;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    cred_init(&cred);
+    cred.fc_mode = mode & 07777;
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    /*
+     * Hold the directory fid lock so that directory path name
+     * don't change. Read lock is fine because this fid cannot
+     * be used by any other operation.
+     */
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->open2(&s->ctx, &fidp->path,
+                                name->data, flags, &cred, &fidp->fs);
+            if (err < 0) {
+                err = -errno;
+            } else {
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                        s->ops->close(&s->ctx, &fidp->fs);
+                    } else {
+                        v9fs_path_copy(&fidp->path, &path);
+                    }
+                } else {
+                    s->ops->close(&s->ctx, &fidp->fs);
+                }
+                v9fs_path_free(&path);
+            }
+        });
+    v9fs_path_unlock(s);
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(pdu);
+        }
+    }
+    return err;
+}
+
+int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->close(&s->ctx, fs);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    if (!err) {
+        total_open_fd--;
+    }
+    return err;
+}
+
+int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
+                 V9fsFidState *newdirfid, V9fsString *name)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->link(&s->ctx, &oldfid->path,
+                               &newdirfid->path, name->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
+                    struct iovec *iov, int iovcnt, int64_t offset)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
+                   struct iovec *iov, int iovcnt, int64_t offset)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
new file mode 100644 (file)
index 0000000..83f125b
--- /dev/null
@@ -0,0 +1,344 @@
+
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "fsdev/qemu-fsdev.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p-coth.h"
+
+int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
+{
+    int err;
+    ssize_t len;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    buf->data = g_malloc(PATH_MAX);
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            len = s->ops->readlink(&s->ctx, path,
+                                   buf->data, PATH_MAX - 1);
+            if (len > -1) {
+                buf->size = len;
+                buf->data[len] = 0;
+                err = 0;
+            } else {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    if (err) {
+        g_free(buf->data);
+        buf->data = NULL;
+        buf->size = 0;
+    }
+    return err;
+}
+
+int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->statfs(&s->ctx, path, stbuf);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
+{
+    int err;
+    FsCred cred;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    cred_init(&cred);
+    cred.fc_mode = mode;
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->chmod(&s->ctx, path, &cred);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
+                      struct timespec times[2])
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->utimensat(&s->ctx, path, times);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
+{
+    int err;
+    FsCred cred;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->chown(&s->ctx, path, &cred);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->truncate(&s->ctx, path, size);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+                  gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
+{
+    int err;
+    V9fsPath path;
+    FsCred cred;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    cred_init(&cred);
+    cred.fc_uid  = uid;
+    cred.fc_gid  = gid;
+    cred.fc_mode = mode;
+    cred.fc_rdev = dev;
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
+            if (err < 0) {
+                err = -errno;
+            } else {
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
+                }
+                v9fs_path_free(&path);
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+/* Only works with path name based fid */
+int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->remove(&s->ctx, path->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+/* Only work with path name based fid */
+int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
+                     V9fsPath *newdirpath, V9fsString *newname)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
+                                   newdirpath, newname->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
+                    const char *oldpath, gid_t gid, struct stat *stbuf)
+{
+    int err;
+    FsCred cred;
+    V9fsPath path;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    cred_init(&cred);
+    cred.fc_uid = dfidp->uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = 0777;
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
+                                  name->data, &cred);
+            if (err < 0) {
+                err = -errno;
+            } else {
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
+                }
+                v9fs_path_free(&path);
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+/*
+ * For path name based fid we don't block. So we can
+ * directly call the fs driver ops.
+ */
+int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
+                         const char *name, V9fsPath *path)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
+        err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+        if (err < 0) {
+            err = -errno;
+        }
+    } else {
+        if (v9fs_request_cancelled(pdu)) {
+            return -EINTR;
+        }
+        v9fs_co_run_in_worker(
+            {
+                err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+                if (err < 0) {
+                    err = -errno;
+                }
+            });
+    }
+    return err;
+}
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
new file mode 100644 (file)
index 0000000..8a48228
--- /dev/null
@@ -0,0 +1,107 @@
+
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "fsdev/qemu-fsdev.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p-coth.h"
+
+int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->llistxattr(&s->ctx, path, value, size);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
+                      V9fsString *xattr_name,
+                      void *value, size_t size)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lgetxattr(&s->ctx, path,
+                                    xattr_name->data,
+                                    value, size);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
+                      V9fsString *xattr_name, void *value,
+                      size_t size, int flags)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lsetxattr(&s->ctx, path,
+                                    xattr_name->data, value,
+                                    size, flags);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
+
+int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path,
+                         V9fsString *xattr_name)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_path_read_lock(s);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    v9fs_path_unlock(s);
+    return err;
+}
diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c
new file mode 100644 (file)
index 0000000..25556cc
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
+ *  Venkateswararao Jujjuri(JV) <jvrao@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 "qemu-char.h"
+#include "fsdev/qemu-fsdev.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p-coth.h"
+
+/* v9fs glib thread pool */
+static V9fsThPool v9fs_pool;
+
+void co_run_in_worker_bh(void *opaque)
+{
+    Coroutine *co = opaque;
+    g_thread_pool_push(v9fs_pool.pool, co, NULL);
+}
+
+static void v9fs_qemu_process_req_done(void *arg)
+{
+    char byte;
+    ssize_t len;
+    Coroutine *co;
+
+    do {
+        len = read(v9fs_pool.rfd, &byte, sizeof(byte));
+    } while (len == -1 &&  errno == EINTR);
+
+    while ((co = g_async_queue_try_pop(v9fs_pool.completed)) != NULL) {
+        qemu_coroutine_enter(co, NULL);
+    }
+}
+
+static void v9fs_thread_routine(gpointer data, gpointer user_data)
+{
+    ssize_t len;
+    char byte = 0;
+    Coroutine *co = data;
+
+    qemu_coroutine_enter(co, NULL);
+
+    g_async_queue_push(v9fs_pool.completed, co);
+    do {
+        len = write(v9fs_pool.wfd, &byte, sizeof(byte));
+    } while (len == -1 && errno == EINTR);
+}
+
+int v9fs_init_worker_threads(void)
+{
+    int ret = 0;
+    int notifier_fds[2];
+    V9fsThPool *p = &v9fs_pool;
+    sigset_t set, oldset;
+
+    sigfillset(&set);
+    /* Leave signal handling to the iothread.  */
+    pthread_sigmask(SIG_SETMASK, &set, &oldset);
+
+    if (qemu_pipe(notifier_fds) == -1) {
+        ret = -1;
+        goto err_out;
+    }
+    p->pool = g_thread_pool_new(v9fs_thread_routine, p, -1, FALSE, NULL);
+    if (!p->pool) {
+        ret = -1;
+        goto err_out;
+    }
+    p->completed = g_async_queue_new();
+    if (!p->completed) {
+        /*
+         * We are going to terminate.
+         * So don't worry about cleanup
+         */
+        ret = -1;
+        goto err_out;
+    }
+    p->rfd = notifier_fds[0];
+    p->wfd = notifier_fds[1];
+
+    fcntl(p->rfd, F_SETFL, O_NONBLOCK);
+    fcntl(p->wfd, F_SETFL, O_NONBLOCK);
+
+    qemu_set_fd_handler(p->rfd, v9fs_qemu_process_req_done, NULL, NULL);
+err_out:
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+    return ret;
+}
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
new file mode 100644 (file)
index 0000000..c4b74b0
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
+ *  Venkateswararao Jujjuri(JV) <jvrao@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_COTH_H
+#define _QEMU_VIRTIO_9P_COTH_H
+
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
+#include "virtio-9p.h"
+#include <glib.h>
+
+typedef struct V9fsThPool {
+    int rfd;
+    int wfd;
+    GThreadPool *pool;
+    GAsyncQueue *completed;
+} V9fsThPool;
+
+/*
+ * we want to use bottom half because we want to make sure the below
+ * sequence of events.
+ *
+ *   1. Yield the coroutine in the QEMU thread.
+ *   2. Submit the coroutine to a worker thread.
+ *   3. Enter the coroutine in the worker thread.
+ * we cannot swap step 1 and 2, because that would imply worker thread
+ * can enter coroutine while step1 is still running
+ */
+#define v9fs_co_run_in_worker(code_block)                               \
+    do {                                                                \
+        QEMUBH *co_bh;                                                  \
+        co_bh = qemu_bh_new(co_run_in_worker_bh,                        \
+                            qemu_coroutine_self());                     \
+        qemu_bh_schedule(co_bh);                                        \
+        /*                                                              \
+         * yeild in qemu thread and re-enter back                       \
+         * in glib worker thread                                        \
+         */                                                             \
+        qemu_coroutine_yield();                                         \
+        qemu_bh_delete(co_bh);                                          \
+        code_block;                                                     \
+        /* re-enter back to qemu thread */                              \
+        qemu_coroutine_yield();                                         \
+    } while (0)
+
+extern void co_run_in_worker_bh(void *);
+extern int v9fs_init_worker_threads(void);
+extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *,
+                           struct dirent *, struct dirent **result);
+extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *);
+extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t);
+extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
+                             V9fsString *, void *, size_t);
+extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t,
+                         gid_t, dev_t, mode_t, struct stat *);
+extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *,
+                         mode_t, uid_t, gid_t, struct stat *);
+extern int v9fs_co_remove(V9fsPDU *, V9fsPath *);
+extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
+extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
+extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
+                            V9fsPath *, V9fsString *);
+extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *);
+extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
+                         gid_t, int, int, struct stat *);
+extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
+                             void *, size_t, int);
+extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *);
+extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *);
+extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
+                           const char *, gid_t, struct stat *);
+extern int v9fs_co_link(V9fsPDU *, V9fsFidState *,
+                        V9fsFidState *, V9fsString *);
+extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *,
+                           struct iovec *, int, int64_t);
+extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
+                          struct iovec *, int, int64_t);
+extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
+                                const char *, V9fsPath *);
+extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
+                          V9fsStatDotl *v9stat);
+
+#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
new file mode 100644 (file)
index 0000000..cd343e1
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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 "hw/virtio.h"
+#include "hw/pc.h"
+#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-xattr.h"
+#include "virtio-9p-coth.h"
+
+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)
+{
+    int len;
+    struct virtio_9p_config *cfg;
+    V9fsState *s = to_virtio_9p(vdev);
+
+    len = strlen(s->tag);
+    cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
+    stw_raw(&cfg->tag_len, len);
+    /* We don't copy the terminating null to config space */
+    memcpy(cfg->tag, s->tag, len);
+    memcpy(config, cfg, s->config_size);
+    g_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+{
+    V9fsState *s;
+    int i, len;
+    struct stat stat;
+    FsDriverEntry *fse;
+    V9fsPath path;
+
+    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);
+    QLIST_INIT(&s->active_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);
+    }
+
+    s->ctx.export_flags = fse->export_flags;
+    s->ctx.fs_root = g_strdup(fse->path);
+    s->ctx.exops.get_st_gen = NULL;
+
+    if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
+        s->ctx.xops = passthrough_xattr_ops;
+    } else if (fse->export_flags & V9FS_SM_MAPPED) {
+        s->ctx.xops = mapped_xattr_ops;
+    } else if (fse->export_flags & V9FS_SM_NONE) {
+        s->ctx.xops = none_xattr_ops;
+    }
+
+    len = strlen(conf->tag);
+    if (len > MAX_TAG_LEN - 1) {
+        fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
+                "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN - 1);
+        exit(1);
+    }
+
+    s->tag = strdup(conf->tag);
+    s->ctx.uid = -1;
+
+    s->ops = fse->ops;
+    s->vdev.get_features = virtio_9p_get_features;
+    s->config_size = sizeof(struct virtio_9p_config) + len;
+    s->vdev.get_config = virtio_9p_get_config;
+    s->fid_list = NULL;
+    qemu_co_rwlock_init(&s->rename_lock);
+
+    if (s->ops->init(&s->ctx) < 0) {
+        fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
+                " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root);
+        exit(1);
+    }
+    if (v9fs_init_worker_threads() < 0) {
+        fprintf(stderr, "worker thread initialization failed\n");
+        exit(1);
+    }
+
+    /*
+     * Check details of export path, We need to use fs driver
+     * call back to do that. Since we are in the init path, we don't
+     * use co-routines here.
+     */
+    v9fs_path_init(&path);
+    if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
+        fprintf(stderr,
+                "error in converting name to path %s", strerror(errno));
+        exit(1);
+    }
+    if (s->ops->lstat(&s->ctx, &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);
+    }
+    v9fs_path_free(&path);
+
+    return &s->vdev;
+}
+
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static PCIDeviceInfo virtio_9p_info = {
+    .qdev.name = "virtio-9p-pci",
+    .qdev.size = sizeof(VirtIOPCIProxy),
+    .init      = virtio_9p_init_pci,
+    .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id = 0x1009,
+    .revision  = VIRTIO_PCI_ABI_VERSION,
+    .class_id  = 0x2,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                        VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+        DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+        DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+        DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+        DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .qdev.reset = virtio_pci_reset,
+};
+
+static void virtio_9p_register_devices(void)
+{
+    pci_qdev_register(&virtio_9p_info);
+    virtio_9p_set_fd_limit();
+}
+
+device_init(virtio_9p_register_devices)
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
new file mode 100644 (file)
index 0000000..f97d898
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Virtio 9p handle callback
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "hw/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 "qemu-xattr.h"
+#include <unistd.h>
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+#include <sys/ioctl.h>
+
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC  0x58465342
+#endif
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
+#endif
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
+#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
+#endif
+
+struct handle_data {
+    int mountfd;
+    int handle_bytes;
+};
+
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
+}
+
+static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
+{
+    int fd, ret;
+    fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);;
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode & 07777);
+    if (ret < 0) {
+        goto err_out;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+err_out:
+    close(fd);
+    return ret;
+}
+
+
+static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
+                        struct stat *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                               char *buf, size_t bufsz)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = readlinkat(fd, "", buf, bufsz);
+    close(fd);
+    return ret;
+}
+
+static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return close(fs->fd);
+}
+
+static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return closedir(fs->dir);
+}
+
+static int handle_open(FsContext *ctx, V9fsPath *fs_path,
+                       int flags, V9fsFidOpenState *fs)
+{
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
+    return fs->fd;
+}
+
+static int handle_opendir(FsContext *ctx,
+                          V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+    int ret;
+    ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
+    if (ret < 0) {
+        return -1;
+    }
+    fs->dir = fdopendir(ret);
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
+}
+
+static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return rewinddir(fs->dir);
+}
+
+static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return telldir(fs->dir);
+}
+
+static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                            struct dirent *entry,
+                            struct dirent **result)
+{
+    return readdir_r(fs->dir, entry, result);
+}
+
+static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+    return seekdir(fs->dir, off);
+}
+
+static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
+                             int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fs->fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fs->fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fs->fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                              const struct iovec *iov,
+                              int iovcnt, off_t offset)
+{
+    ssize_t ret;
+#ifdef CONFIG_PREADV
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fs->fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        ret = writev(fs->fd, iov, iovcnt);
+    }
+#endif
+#ifdef CONFIG_SYNC_FILE_RANGE
+    if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
+        /*
+         * Initiate a writeback. This is not a data integrity sync.
+         * We want to ensure that we don't leave dirty pages in the cache
+         * after write when writeout=immediate is sepcified.
+         */
+        sync_file_range(fs->fd, offset, ret,
+                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
+    }
+#endif
+    return ret;
+}
+
+static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode);
+    close(fd);
+    return ret;
+}
+
+static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mkdirat(dirfd, name, credp->fc_mode);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_fstat(FsContext *fs_ctx, int fid_type,
+                        V9fsFidOpenState *fs, struct stat *stbuf)
+{
+    int fd;
+
+    if (fid_type == P9_FID_DIR) {
+        fd = dirfd(fs->dir);
+    } else {
+        fd = fs->fd;
+    }
+    return fstat(fd, stbuf);
+}
+
+static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+                        int flags, FsCred *credp, V9fsFidOpenState *fs)
+{
+    int ret;
+    int dirfd, fd;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
+    if (fd >= 0) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+        if (ret < 0) {
+            close(fd);
+            fd = ret;
+        } else {
+            fs->fd = fd;
+        }
+    }
+    close(dirfd);
+    return fd;
+}
+
+
+static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
+                          V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+    int fd, dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = symlinkat(oldpath, dirfd, name);
+    if (!ret) {
+        fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
+        if (fd < 0) {
+            ret = fd;
+            goto err_out;
+        }
+        ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+        close(fd);
+    }
+err_out:
+    close(dirfd);
+    return ret;
+}
+
+static int handle_link(FsContext *ctx, V9fsPath *oldpath,
+                       V9fsPath *dirpath, const char *name)
+{
+    int oldfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
+    if (oldfd < 0) {
+        return oldfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
+    if (newdirfd < 0) {
+        close(oldfd);
+        return newdirfd;
+    }
+    ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
+    close(newdirfd);
+    close(oldfd);
+    return ret;
+}
+
+static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = ftruncate(fd, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_rename(FsContext *ctx, const char *oldpath,
+                         const char *newpath)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
+                            const struct timespec *buf)
+{
+    int ret;
+#ifdef CONFIG_UTIMENSAT
+    int fd;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = futimens(fd, buf);
+    close(fd);
+#else
+    ret = -1;
+    errno = ENOSYS;
+#endif
+    return ret;
+}
+
+static int handle_remove(FsContext *ctx, const char *path)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_fsync(FsContext *ctx, int fid_type,
+                        V9fsFidOpenState *fs, int datasync)
+{
+    int fd;
+
+    if (fid_type == P9_FID_DIR) {
+        fd = dirfd(fs->dir);
+    } else {
+        fd = fs->fd;
+    }
+
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
+                         struct statfs *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatfs(fd, stbuf);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+                                const char *name, void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fgetxattr(fd, name, value, size);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+                                 void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = flistxattr(fd, value, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fsetxattr(fd, name, value, size, flags);
+    close(fd);
+    return ret;
+}
+
+static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                               const char *name)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fremovexattr(fd, name);
+    close(fd);
+    return ret;
+}
+
+static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    char buffer[PATH_MAX];
+    struct file_handle *fh;
+    int dirfd, ret, mnt_id;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    /* "." and ".." are not allowed */
+    if (!strcmp(name, ".") || !strcmp(name, "..")) {
+        errno = EINVAL;
+        return -1;
+
+    }
+    if (dir_path) {
+        dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    } else {
+        /* relative to export root */
+        dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+    }
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
+    fh->handle_bytes = data->handle_bytes;
+    /* add a "./" at the begining of the path */
+    snprintf(buffer, PATH_MAX, "./%s", name);
+    /* flag = 0 imply don't follow symlink */
+    ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
+    if (!ret) {
+        target->data = (char *)fh;
+        target->size = sizeof(struct file_handle) + data->handle_bytes;
+    } else {
+        g_free(fh);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
+                           const char *old_name, V9fsPath *newdir,
+                           const char *new_name)
+{
+    int olddirfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
+    if (olddirfd < 0) {
+        return olddirfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
+    if (newdirfd < 0) {
+        close(olddirfd);
+        return newdirfd;
+    }
+    ret = renameat(olddirfd, old_name, newdirfd, new_name);
+    close(newdirfd);
+    close(olddirfd);
+    return ret;
+}
+
+static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
+                           const char *name, int flags)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+    int rflags;
+
+    dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+
+    rflags = 0;
+    if (flags & P9_DOTL_AT_REMOVEDIR) {
+        rflags |= AT_REMOVEDIR;
+    }
+
+    ret = unlinkat(dirfd, name, rflags);
+
+    close(dirfd);
+    return ret;
+}
+
+static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
+                                 mode_t st_mode, uint64_t *st_gen)
+{
+    int err;
+    V9fsFidOpenState fid_open;
+
+    /*
+     * Do not try to open special files like device nodes, fifos etc
+     * We can get fd for regular files and directories only
+     */
+    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
+            return 0;
+    }
+    err = handle_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
+    }
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    handle_close(ctx, &fid_open);
+    return err;
+}
+
+static int handle_init(FsContext *ctx)
+{
+    int ret, mnt_id;
+    struct statfs stbuf;
+    struct file_handle fh;
+    struct handle_data *data = g_malloc(sizeof(struct handle_data));
+
+    data->mountfd = open(ctx->fs_root, O_DIRECTORY);
+    if (data->mountfd < 0) {
+        ret = data->mountfd;
+        goto err_out;
+    }
+    ret = statfs(ctx->fs_root, &stbuf);
+    if (!ret) {
+        switch (stbuf.f_type) {
+        case EXT2_SUPER_MAGIC:
+        case BTRFS_SUPER_MAGIC:
+        case REISERFS_SUPER_MAGIC:
+        case XFS_SUPER_MAGIC:
+            ctx->exops.get_st_gen = handle_ioc_getversion;
+            break;
+        }
+    }
+    memset(&fh, 0, sizeof(struct file_handle));
+    ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
+    if (ret && errno == EOVERFLOW) {
+        data->handle_bytes = fh.handle_bytes;
+        ctx->private = data;
+        ret = 0;
+        goto out;
+    }
+    /* we got 0 byte handle ? */
+    ret = -1;
+    close(data->mountfd);
+err_out:
+    g_free(data);
+out:
+    return ret;
+}
+
+FileOperations handle_ops = {
+    .init         = handle_init,
+    .lstat        = handle_lstat,
+    .readlink     = handle_readlink,
+    .close        = handle_close,
+    .closedir     = handle_closedir,
+    .open         = handle_open,
+    .opendir      = handle_opendir,
+    .rewinddir    = handle_rewinddir,
+    .telldir      = handle_telldir,
+    .readdir_r    = handle_readdir_r,
+    .seekdir      = handle_seekdir,
+    .preadv       = handle_preadv,
+    .pwritev      = handle_pwritev,
+    .chmod        = handle_chmod,
+    .mknod        = handle_mknod,
+    .mkdir        = handle_mkdir,
+    .fstat        = handle_fstat,
+    .open2        = handle_open2,
+    .symlink      = handle_symlink,
+    .link         = handle_link,
+    .truncate     = handle_truncate,
+    .rename       = handle_rename,
+    .chown        = handle_chown,
+    .utimensat    = handle_utimensat,
+    .remove       = handle_remove,
+    .fsync        = handle_fsync,
+    .statfs       = handle_statfs,
+    .lgetxattr    = handle_lgetxattr,
+    .llistxattr   = handle_llistxattr,
+    .lsetxattr    = handle_lsetxattr,
+    .lremovexattr = handle_lremovexattr,
+    .name_to_path = handle_name_to_path,
+    .renameat     = handle_renameat,
+    .unlinkat     = handle_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
new file mode 100644 (file)
index 0000000..371a94d
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * 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 "hw/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 "qemu-xattr.h"
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+#include <sys/ioctl.h>
+
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC  0x58465342
+#endif
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
+#endif
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
+#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
+#endif
+
+static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
+{
+    int err;
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->export_flags & V9FS_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, buffer), "user.virtfs.uid", &tmp_uid,
+                    sizeof(uid_t)) > 0) {
+            stbuf->st_uid = tmp_uid;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
+                    sizeof(gid_t)) > 0) {
+            stbuf->st_gid = tmp_gid;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+                    &tmp_mode, sizeof(mode_t)) > 0) {
+            stbuf->st_mode = tmp_mode;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
+                        sizeof(dev_t)) > 0) {
+                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)
+{
+    char buffer[PATH_MAX];
+
+    if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
+        return -1;
+    }
+    if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+                credp->fc_gid) < 0) {
+        /*
+         * If we fail to change ownership and if we are
+         * using security model none. Ignore the error
+         */
+        if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                              char *buf, size_t bufsz)
+{
+    ssize_t tsize = -1;
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        int fd;
+        fd = open(rpath(fs_ctx, path, buffer), 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->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
+    }
+    return tsize;
+}
+
+static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return close(fs->fd);
+}
+
+static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return closedir(fs->dir);
+}
+
+static int local_open(FsContext *ctx, V9fsPath *fs_path,
+                      int flags, V9fsFidOpenState *fs)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    fs->fd = open(rpath(ctx, path, buffer), flags);
+    return fs->fd;
+}
+
+static int local_opendir(FsContext *ctx,
+                         V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    fs->dir = opendir(rpath(ctx, path, buffer));
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
+}
+
+static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return rewinddir(fs->dir);
+}
+
+static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    return telldir(fs->dir);
+}
+
+static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                           struct dirent *entry,
+                           struct dirent **result)
+{
+    return readdir_r(fs->dir, entry, result);
+}
+
+static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+    return seekdir(fs->dir, off);
+}
+
+static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                            const struct iovec *iov,
+                            int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fs->fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fs->fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fs->fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
+                             int iovcnt, off_t offset)
+{
+    ssize_t ret
+;
+#ifdef CONFIG_PREADV
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fs->fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        ret = writev(fs->fd, iov, iovcnt);
+    }
+#endif
+#ifdef CONFIG_SYNC_FILE_RANGE
+    if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
+        /*
+         * Initiate a writeback. This is not a data integrity sync.
+         * We want to ensure that we don't leave dirty pages in the cache
+         * after write when writeout=immediate is sepcified.
+         */
+        sync_file_range(fs->fd, offset, ret,
+                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
+    }
+#endif
+    return ret;
+}
+
+static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
+    }
+    return -1;
+}
+
+static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    char *path;
+    int err = -1;
+    int serrno = 0;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
+    /* Determine the security model */
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        err = mknod(rpath(fs_ctx, path, buffer),
+                SM_LOCAL_MODE_BITS|S_IFREG, 0);
+        if (err == -1) {
+            goto out;
+        }
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
+                credp->fc_rdev);
+        if (err == -1) {
+            goto out;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    goto out;
+
+err_end:
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+out:
+    v9fs_string_free(&fullname);
+    return err;
+}
+
+static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    char *path;
+    int err = -1;
+    int serrno = 0;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
+    /* Determine the security model */
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+        if (err == -1) {
+            goto out;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFDIR;
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
+        if (err == -1) {
+            goto out;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    goto out;
+
+err_end:
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+out:
+    v9fs_string_free(&fullname);
+    return err;
+}
+
+static int local_fstat(FsContext *fs_ctx, int fid_type,
+                       V9fsFidOpenState *fs, struct stat *stbuf)
+{
+    int err, fd;
+
+    if (fid_type == P9_FID_DIR) {
+        fd = dirfd(fs->dir);
+    } else {
+        fd = fs->fd;
+    }
+
+    err = fstat(fd, stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->export_flags & V9FS_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, V9fsPath *dir_path, const char *name,
+                       int flags, FsCred *credp, V9fsFidOpenState *fs)
+{
+    char *path;
+    int fd = -1;
+    int err = -1;
+    int serrno = 0;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
+    /* Determine the security model */
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            err = fd;
+            goto out;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFREG;
+        /* Set cleint credentials in xattr */
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
+        if (fd == -1) {
+            err = fd;
+            goto out;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    err = fd;
+    fs->fd = fd;
+    goto out;
+
+err_end:
+    close(fd);
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+out:
+    v9fs_string_free(&fullname);
+    return err;
+}
+
+
+static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+                         V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+    char *newpath;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    newpath = fullname.data;
+
+    /* Determine the security model */
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        int fd;
+        ssize_t oldpath_size, write_size;
+        fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
+                SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            err = fd;
+            goto out;
+        }
+        /* 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, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
+        if (err) {
+            goto out;
+        }
+        err = lchown(rpath(fs_ctx, newpath, buffer), 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->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
+                serrno = errno;
+                goto err_end;
+            } else
+                err = 0;
+        }
+    }
+    goto out;
+
+err_end:
+    remove(rpath(fs_ctx, newpath, buffer));
+    errno = serrno;
+out:
+    v9fs_string_free(&fullname);
+    return err;
+}
+
+static int local_link(FsContext *ctx, V9fsPath *oldpath,
+                      V9fsPath *dirpath, const char *name)
+{
+    int ret;
+    V9fsString newpath;
+    char buffer[PATH_MAX], buffer1[PATH_MAX];
+
+    v9fs_string_init(&newpath);
+    v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
+
+    ret = link(rpath(ctx, oldpath->data, buffer),
+               rpath(ctx, newpath.data, buffer1));
+    v9fs_string_free(&newpath);
+    return ret;
+}
+
+static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    return truncate(rpath(ctx, path, buffer), size);
+}
+
+static int local_rename(FsContext *ctx, const char *oldpath,
+                        const char *newpath)
+{
+    char buffer[PATH_MAX], buffer1[PATH_MAX];
+
+    return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+}
+
+static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
+        (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+        (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        return lchown(rpath(fs_ctx, path, buffer),
+                      credp->fc_uid, credp->fc_gid);
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    }
+    return -1;
+}
+
+static int local_utimensat(FsContext *s, V9fsPath *fs_path,
+                           const struct timespec *buf)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    return qemu_utimens(rpath(s, path, buffer), buf);
+}
+
+static int local_remove(FsContext *ctx, const char *path)
+{
+    char buffer[PATH_MAX];
+    return remove(rpath(ctx, path, buffer));
+}
+
+static int local_fsync(FsContext *ctx, int fid_type,
+                       V9fsFidOpenState *fs, int datasync)
+{
+    int fd;
+
+    if (fid_type == P9_FID_DIR) {
+        fd = dirfd(fs->dir);
+    } else {
+        fd = fs->fd;
+    }
+
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
+{
+    char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
+    return statfs(rpath(s, path, buffer), stbuf);
+}
+
+static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+                               const char *name, void *value, size_t size)
+{
+    char *path = fs_path->data;
+
+    return v9fs_get_xattr(ctx, path, name, value, size);
+}
+
+static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+                                void *value, size_t size)
+{
+    char *path = fs_path->data;
+
+    return v9fs_list_xattr(ctx, path, value, size);
+}
+
+static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+                           void *value, size_t size, int flags)
+{
+    char *path = fs_path->data;
+
+    return v9fs_set_xattr(ctx, path, name, value, size, flags);
+}
+
+static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                              const char *name)
+{
+    char *path = fs_path->data;
+
+    return v9fs_remove_xattr(ctx, path, name);
+}
+
+static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    if (dir_path) {
+        v9fs_string_sprintf((V9fsString *)target, "%s/%s",
+                            dir_path->data, name);
+    } else {
+        v9fs_string_sprintf((V9fsString *)target, "%s", name);
+    }
+    /* Bump the size for including terminating NULL */
+    target->size++;
+    return 0;
+}
+
+static int local_renameat(FsContext *ctx, V9fsPath *olddir,
+                          const char *old_name, V9fsPath *newdir,
+                          const char *new_name)
+{
+    int ret;
+    V9fsString old_full_name, new_full_name;
+
+    v9fs_string_init(&old_full_name);
+    v9fs_string_init(&new_full_name);
+
+    v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
+    v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
+
+    ret = local_rename(ctx, old_full_name.data, new_full_name.data);
+    v9fs_string_free(&old_full_name);
+    v9fs_string_free(&new_full_name);
+    return ret;
+}
+
+static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
+                          const char *name, int flags)
+{
+    int ret;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+    v9fs_string_init(&fullname);
+
+    v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+    ret = remove(rpath(ctx, fullname.data, buffer));
+    v9fs_string_free(&fullname);
+
+    return ret;
+}
+
+static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
+                                mode_t st_mode, uint64_t *st_gen)
+{
+    int err;
+#ifdef FS_IOC_GETVERSION
+    V9fsFidOpenState fid_open;
+
+    /*
+     * Do not try to open special files like device nodes, fifos etc
+     * We can get fd for regular files and directories only
+     */
+    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
+            return 0;
+    }
+    err = local_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
+    }
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    local_close(ctx, &fid_open);
+#else
+    err = -ENOTTY;
+#endif
+    return err;
+}
+
+static int local_init(FsContext *ctx)
+{
+    int err = 0;
+    struct statfs stbuf;
+
+    ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
+#ifdef FS_IOC_GETVERSION
+    /*
+     * use ioc_getversion only if the iocl is definied
+     */
+    err = statfs(ctx->fs_root, &stbuf);
+    if (!err) {
+        switch (stbuf.f_type) {
+        case EXT2_SUPER_MAGIC:
+        case BTRFS_SUPER_MAGIC:
+        case REISERFS_SUPER_MAGIC:
+        case XFS_SUPER_MAGIC:
+            ctx->exops.get_st_gen = local_ioc_getversion;
+            break;
+        }
+    }
+#endif
+    return err;
+}
+
+FileOperations local_ops = {
+    .init  = local_init,
+    .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_r = local_readdir_r,
+    .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,
+    .name_to_path = local_name_to_path,
+    .renameat  = local_renameat,
+    .unlinkat = local_unlinkat,
+};
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..a1948e3
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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 "qemu-xattr.h"
+#include "hw/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)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), 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)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
+            size, flags);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    char buffer[PATH_MAX];
+    ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
+    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)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), 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)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
+            size, flags);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    char buffer[PATH_MAX];
+    ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
+    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-synth.c b/hw/9pfs/virtio-9p-synth.c
new file mode 100644 (file)
index 0000000..92e0b09
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Virtio 9p synthetic file system support
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Malahal Naineni <malahal@us.ibm.com>
+ *  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 "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-synth.h"
+
+#include <sys/stat.h>
+
+/* Root node for synth file system */
+V9fsSynthNode v9fs_synth_root = {
+    .name = "/",
+    .actual_attr = {
+        .mode = 0555 | S_IFDIR,
+        .nlink = 1,
+    },
+    .attr = &v9fs_synth_root.actual_attr,
+};
+
+static QemuMutex  v9fs_synth_mutex;
+static int v9fs_synth_node_count;
+/* set to 1 when the synth fs is ready */
+static int v9fs_synth_fs;
+
+static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
+                                        const char *name,
+                                        V9fsSynthNodeAttr *attr, int inode)
+{
+    V9fsSynthNode *node;
+
+    /* Add directory type and remove write bits */
+    mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
+    node = g_malloc0(sizeof(V9fsSynthNode));
+    if (attr) {
+        /* We are adding .. or . entries */
+        node->attr = attr;
+        node->attr->nlink++;
+    } else {
+        node->attr = &node->actual_attr;
+        node->attr->inode = inode;
+        node->attr->nlink = 1;
+        /* We don't allow write to directories */
+        node->attr->mode   = mode;
+        node->attr->write = NULL;
+        node->attr->read  = NULL;
+    }
+    node->private = node;
+    strncpy(node->name, name, sizeof(node->name));
+    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
+    return node;
+}
+
+int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+                          const char *name, V9fsSynthNode **result)
+{
+    int ret;
+    V9fsSynthNode *node, *tmp;
+
+    if (!v9fs_synth_fs) {
+        return EAGAIN;
+    }
+    if (!name || (strlen(name) >= NAME_MAX)) {
+        return EINVAL;
+    }
+    if (!parent) {
+        parent = &v9fs_synth_root;
+    }
+    qemu_mutex_lock(&v9fs_synth_mutex);
+    QLIST_FOREACH(tmp, &parent->child, sibling) {
+        if (!strcmp(tmp->name, name)) {
+            ret = EEXIST;
+            goto err_out;
+        }
+    }
+    /* Add the name */
+    node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++);
+    v9fs_add_dir_node(node, parent->attr->mode, "..",
+                      parent->attr, parent->attr->inode);
+    v9fs_add_dir_node(node, node->attr->mode, ".",
+                      node->attr, node->attr->inode);
+    *result = node;
+    ret = 0;
+err_out:
+    qemu_mutex_unlock(&v9fs_synth_mutex);
+    return ret;
+}
+
+int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+                             const char *name, v9fs_synth_read read,
+                             v9fs_synth_write write, void *arg)
+{
+    int ret;
+    V9fsSynthNode *node, *tmp;
+
+    if (!v9fs_synth_fs) {
+        return EAGAIN;
+    }
+    if (!name || (strlen(name) >= NAME_MAX)) {
+        return EINVAL;
+    }
+    if (!parent) {
+        parent = &v9fs_synth_root;
+    }
+
+    qemu_mutex_lock(&v9fs_synth_mutex);
+    QLIST_FOREACH(tmp, &parent->child, sibling) {
+        if (!strcmp(tmp->name, name)) {
+            ret = EEXIST;
+            goto err_out;
+        }
+    }
+    /* Add file type and remove write bits */
+    mode = ((mode & 0777) | S_IFREG);
+    node = g_malloc0(sizeof(V9fsSynthNode));
+    node->attr         = &node->actual_attr;
+    node->attr->inode  = v9fs_synth_node_count++;
+    node->attr->nlink  = 1;
+    node->attr->read   = read;
+    node->attr->write  = write;
+    node->attr->mode   = mode;
+    node->private      = arg;
+    strncpy(node->name, name, sizeof(node->name));
+    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
+    ret = 0;
+err_out:
+    qemu_mutex_unlock(&v9fs_synth_mutex);
+    return ret;
+}
+
+static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
+{
+    stbuf->st_dev = 0;
+    stbuf->st_ino = node->attr->inode;
+    stbuf->st_mode = node->attr->mode;
+    stbuf->st_nlink = node->attr->nlink;
+    stbuf->st_uid = 0;
+    stbuf->st_gid = 0;
+    stbuf->st_rdev = 0;
+    stbuf->st_size = 0;
+    stbuf->st_blksize = 0;
+    stbuf->st_blocks = 0;
+    stbuf->st_atime = 0;
+    stbuf->st_mtime = 0;
+    stbuf->st_ctime = 0;
+}
+
+static int v9fs_synth_lstat(FsContext *fs_ctx,
+                            V9fsPath *fs_path, struct stat *stbuf)
+{
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    v9fs_synth_fill_statbuf(node, stbuf);
+    return 0;
+}
+
+static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type,
+                            V9fsFidOpenState *fs, struct stat *stbuf)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    v9fs_synth_fill_statbuf(synth_open->node, stbuf);
+    return 0;
+}
+
+static int v9fs_synth_opendir(FsContext *ctx,
+                             V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open;
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    synth_open = g_malloc(sizeof(*synth_open));
+    synth_open->node = node;
+    node->open_count++;
+    fs->private = synth_open;
+    return 0;
+}
+
+static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+
+    node->open_count--;
+    g_free(synth_open);
+    fs->private = NULL;
+    return 0;
+}
+
+static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    return synth_open->offset;
+}
+
+static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    synth_open->offset = off;
+}
+
+static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    v9fs_synth_seekdir(ctx, fs, 0);
+}
+
+static void v9fs_synth_direntry(V9fsSynthNode *node,
+                                struct dirent *entry, off_t off)
+{
+    strcpy(entry->d_name, node->name);
+    entry->d_ino = node->attr->inode;
+    entry->d_off = off + 1;
+}
+
+static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
+                                 struct dirent **result, off_t off)
+{
+    int i = 0;
+    V9fsSynthNode *node;
+
+    rcu_read_lock();
+    QLIST_FOREACH(node, &dir->child, sibling) {
+        /* This is the off child of the directory */
+        if (i == off) {
+            break;
+        }
+        i++;
+    }
+    rcu_read_unlock();
+    if (!node) {
+        /* end of directory */
+        *result = NULL;
+        return 0;
+    }
+    v9fs_synth_direntry(node, entry, off);
+    *result = entry;
+    return 0;
+}
+
+static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                                struct dirent *entry, struct dirent **result)
+{
+    int ret;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset);
+    if (!ret && *result != NULL) {
+        synth_open->offset++;
+    }
+    return ret;
+}
+
+static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
+                           int flags, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open;
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    synth_open = g_malloc(sizeof(*synth_open));
+    synth_open->node = node;
+    node->open_count++;
+    fs->private = synth_open;
+    return 0;
+}
+
+static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
+                            const char *name, int flags,
+                            FsCred *credp, V9fsFidOpenState *fs)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+
+    node->open_count--;
+    g_free(synth_open);
+    fs->private = NULL;
+    return 0;
+}
+
+static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                                  const struct iovec *iov,
+                                  int iovcnt, off_t offset)
+{
+    int i, count = 0, wcount;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    if (!node->attr->write) {
+        errno = EPERM;
+        return -1;
+    }
+    for (i = 0; i < iovcnt; i++) {
+        wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
+                                   offset, node->private);
+        offset += wcount;
+        count  += wcount;
+        /* If we wrote less than requested. we are done */
+        if (wcount < iov[i].iov_len) {
+            break;
+        }
+    }
+    return count;
+}
+
+static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                                 const struct iovec *iov,
+                                 int iovcnt, off_t offset)
+{
+    int i, count = 0, rcount;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    if (!node->attr->read) {
+        errno = EPERM;
+        return -1;
+    }
+    for (i = 0; i < iovcnt; i++) {
+        rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
+                                  offset, node->private);
+        offset += rcount;
+        count  += rcount;
+        /* If we read less than requested. we are done */
+        if (rcount < iov[i].iov_len) {
+            break;
+        }
+    }
+    return count;
+}
+
+static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path,
+                       const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
+                       const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path,
+                                   char *buf, size_t bufsz)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath,
+                              V9fsPath *newpath, const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
+                           V9fsPath *newpath, const char *buf)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_rename(FsContext *ctx, const char *oldpath,
+                             const char *newpath)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
+                                const struct timespec *buf)
+{
+    errno = EPERM;
+    return 0;
+}
+
+static int v9fs_synth_remove(FsContext *ctx, const char *path)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_fsync(FsContext *ctx, int fid_type,
+                            V9fsFidOpenState *fs, int datasync)
+{
+    errno = ENOSYS;
+    return 0;
+}
+
+static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path,
+                             struct statfs *stbuf)
+{
+    stbuf->f_type = 0xABCD;
+    stbuf->f_bsize = 512;
+    stbuf->f_blocks = 0;
+    stbuf->f_files = v9fs_synth_node_count;
+    stbuf->f_namelen = NAME_MAX;
+    return 0;
+}
+
+static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path,
+                                    const char *name, void *value, size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path,
+                                     void *value, size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
+                                const char *name, void *value,
+                                size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_lremovexattr(FsContext *ctx,
+                                   V9fsPath *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                                   const char *name, V9fsPath *target)
+{
+    V9fsSynthNode *node;
+    V9fsSynthNode *dir_node;
+
+    /* "." and ".." are not allowed */
+    if (!strcmp(name, ".") || !strcmp(name, "..")) {
+        errno = EINVAL;
+        return -1;
+
+    }
+    if (!dir_path) {
+        dir_node = &v9fs_synth_root;
+    } else {
+        dir_node = *(V9fsSynthNode **)dir_path->data;
+    }
+    if (!strcmp(name, "/")) {
+        node = dir_node;
+        goto out;
+    }
+    /* search for the name in the childern */
+    rcu_read_lock();
+    QLIST_FOREACH(node, &dir_node->child, sibling) {
+        if (!strcmp(node->name, name)) {
+            break;
+        }
+    }
+    rcu_read_unlock();
+
+    if (!node) {
+        errno = ENOENT;
+        return -1;
+    }
+out:
+    /* Copy the node pointer to fid */
+    target->data = g_malloc(sizeof(void *));
+    memcpy(target->data, &node, sizeof(void *));
+    target->size = sizeof(void *);
+    return 0;
+}
+
+static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
+                               const char *old_name, V9fsPath *newdir,
+                               const char *new_name)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
+                               const char *name, int flags)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_init(FsContext *ctx)
+{
+    QLIST_INIT(&v9fs_synth_root.child);
+    qemu_mutex_init(&v9fs_synth_mutex);
+
+    /* Add "." and ".." entries for root */
+    v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+                      "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+    v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+                      ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+
+    /* Mark the subsystem is ready for use */
+    v9fs_synth_fs = 1;
+    return 0;
+}
+
+FileOperations synth_ops = {
+    .init         = v9fs_synth_init,
+    .lstat        = v9fs_synth_lstat,
+    .readlink     = v9fs_synth_readlink,
+    .close        = v9fs_synth_close,
+    .closedir     = v9fs_synth_closedir,
+    .open         = v9fs_synth_open,
+    .opendir      = v9fs_synth_opendir,
+    .rewinddir    = v9fs_synth_rewinddir,
+    .telldir      = v9fs_synth_telldir,
+    .readdir_r    = v9fs_synth_readdir_r,
+    .seekdir      = v9fs_synth_seekdir,
+    .preadv       = v9fs_synth_preadv,
+    .pwritev      = v9fs_synth_pwritev,
+    .chmod        = v9fs_synth_chmod,
+    .mknod        = v9fs_synth_mknod,
+    .mkdir        = v9fs_synth_mkdir,
+    .fstat        = v9fs_synth_fstat,
+    .open2        = v9fs_synth_open2,
+    .symlink      = v9fs_synth_symlink,
+    .link         = v9fs_synth_link,
+    .truncate     = v9fs_synth_truncate,
+    .rename       = v9fs_synth_rename,
+    .chown        = v9fs_synth_chown,
+    .utimensat    = v9fs_synth_utimensat,
+    .remove       = v9fs_synth_remove,
+    .fsync        = v9fs_synth_fsync,
+    .statfs       = v9fs_synth_statfs,
+    .lgetxattr    = v9fs_synth_lgetxattr,
+    .llistxattr   = v9fs_synth_llistxattr,
+    .lsetxattr    = v9fs_synth_lsetxattr,
+    .lremovexattr = v9fs_synth_lremovexattr,
+    .name_to_path = v9fs_synth_name_to_path,
+    .renameat     = v9fs_synth_renameat,
+    .unlinkat     = v9fs_synth_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-synth.h b/hw/9pfs/virtio-9p-synth.h
new file mode 100644 (file)
index 0000000..e03f434
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+typedef struct V9fsSynthNode V9fsSynthNode;
+typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset,
+                                   void *arg);
+typedef ssize_t (*v9fs_synth_write)(void *buf, int len, off_t offset,
+                                    void *arg);
+typedef struct V9fsSynthNodeAttr {
+    int mode;
+    int inode;
+    int nlink;
+    v9fs_synth_read read;
+    v9fs_synth_write write;
+} V9fsSynthNodeAttr;
+
+struct V9fsSynthNode {
+    QLIST_HEAD(, V9fsSynthNode) child;
+    QLIST_ENTRY(V9fsSynthNode) sibling;
+    char name[NAME_MAX];
+    V9fsSynthNodeAttr *attr;
+    V9fsSynthNodeAttr actual_attr;
+    void *private;
+    int open_count;
+};
+
+typedef struct V9fsSynthOpenState {
+    off_t offset;
+    V9fsSynthNode *node;
+} V9fsSynthOpenState;
+
+extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+                                 const char *name, V9fsSynthNode **result);
+extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+                                    const char *name, v9fs_synth_read read,
+                                    v9fs_synth_write write, void *arg);
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..5044a3e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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 "hw/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)
+{
+    char buffer[PATH_MAX];
+    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, buffer), 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)
+{
+    char buffer[PATH_MAX];
+    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, buffer), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    char buffer[PATH_MAX];
+    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, buffer), 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..7f08f6e
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 "hw/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;
+    char buffer[PATH_MAX];
+    void *ovalue = value;
+    XattrOperations *xops;
+    char *orig_value, *orig_value_start;
+    ssize_t xattr_len, parsed_len = 0, attr_len;
+
+    /* Get the actual len */
+    xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
+    if (xattr_len <= 0) {
+        return xattr_len;
+    }
+
+    /* Now fetch the xattr and find the actual size */
+    orig_value = g_malloc(xattr_len);
+    xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
+
+    /* 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:
+    g_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..9437280
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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 "qemu-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)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+}
+
+static inline int pt_setxattr(FsContext *ctx, const char *path,
+                              const char *name, void *value,
+                              size_t size, int flags)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+                                 const char *path, const char *name)
+{
+    char buffer[PATH_MAX];
+    return lremovexattr(rpath(ctx, path, buffer), 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..b3fc3d0
--- /dev/null
@@ -0,0 +1,3309 @@
+/*
+ * 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 <glib.h>
+#include <glib/gprintf.h>
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
+#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-xattr.h"
+#include "virtio-9p-coth.h"
+#include "trace.h"
+#include "migration.h"
+
+int open_fd_hw;
+int total_open_fd;
+static int open_fd_rc;
+
+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;
+}
+
+struct dotl_openflag_map {
+    int dotl_flag;
+    int open_flag;
+};
+
+static int dotl_to_open_flags(int flags)
+{
+    int i;
+    /*
+     * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
+     * and P9_DOTL_NOACCESS
+     */
+    int oflags = flags & O_ACCMODE;
+
+    struct dotl_openflag_map dotl_oflag_map[] = {
+        { P9_DOTL_CREATE, O_CREAT },
+        { P9_DOTL_EXCL, O_EXCL },
+        { P9_DOTL_NOCTTY , O_NOCTTY },
+        { P9_DOTL_TRUNC, O_TRUNC },
+        { P9_DOTL_APPEND, O_APPEND },
+        { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
+        { P9_DOTL_DSYNC, O_DSYNC },
+        { P9_DOTL_FASYNC, FASYNC },
+        { P9_DOTL_DIRECT, O_DIRECT },
+        { P9_DOTL_LARGEFILE, O_LARGEFILE },
+        { P9_DOTL_DIRECTORY, O_DIRECTORY },
+        { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
+        { P9_DOTL_NOATIME, O_NOATIME },
+        { P9_DOTL_SYNC, O_SYNC },
+    };
+
+    for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
+        if (flags & dotl_oflag_map[i].dotl_flag) {
+            oflags |= dotl_oflag_map[i].open_flag;
+        }
+    }
+
+    return oflags;
+}
+
+void cred_init(FsCred *credp)
+{
+    credp->fc_uid = -1;
+    credp->fc_gid = -1;
+    credp->fc_mode = -1;
+    credp->fc_rdev = -1;
+}
+
+static int get_dotl_openflags(V9fsState *s, int oflags)
+{
+    int flags;
+    /*
+     * Filter the client open flags
+     */
+    flags = dotl_to_open_flags(oflags);
+    flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+    /*
+     * Ignore direct disk access hint until the server supports it.
+     */
+    flags &= ~O_DIRECT;
+    return flags;
+}
+
+void v9fs_string_init(V9fsString *str)
+{
+    str->data = NULL;
+    str->size = 0;
+}
+
+void v9fs_string_free(V9fsString *str)
+{
+    g_free(str->data);
+    str->data = NULL;
+    str->size = 0;
+}
+
+void v9fs_string_null(V9fsString *str)
+{
+    v9fs_string_free(str);
+}
+
+void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+{
+    va_list ap;
+
+    v9fs_string_free(str);
+
+    va_start(ap, fmt);
+    str->size = g_vasprintf(&str->data, fmt, ap);
+    va_end(ap);
+}
+
+void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+{
+    v9fs_string_free(lhs);
+    v9fs_string_sprintf(lhs, "%s", rhs->data);
+}
+
+void v9fs_path_init(V9fsPath *path)
+{
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_free(V9fsPath *path)
+{
+    g_free(path->data);
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
+{
+    v9fs_path_free(lhs);
+    lhs->data = g_malloc(rhs->size);
+    memcpy(lhs->data, rhs->data, rhs->size);
+    lhs->size = rhs->size;
+}
+
+int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                      const char *name, V9fsPath *path)
+{
+    int err;
+    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+    if (err < 0) {
+        err = -errno;
+    }
+    return err;
+}
+
+/*
+ * Return TRUE if s1 is an ancestor of s2.
+ *
+ * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
+ * As a special case, We treat s1 as ancestor of s2 if they are same!
+ */
+static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
+{
+    if (!strncmp(s1->data, s2->data, s1->size - 1)) {
+        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static size_t v9fs_string_size(V9fsString *str)
+{
+    return str->size;
+}
+
+/*
+ * returns 0 if fid got re-opened, 1 if not, < 0 on error */
+static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
+{
+    int err = 1;
+    if (f->fid_type == P9_FID_FILE) {
+        if (f->fs.fd == -1) {
+            do {
+                err = v9fs_co_open(pdu, f, f->open_flags);
+            } while (err == -EINTR && !pdu->cancelled);
+        }
+    } else if (f->fid_type == P9_FID_DIR) {
+        if (f->fs.dir == NULL) {
+            do {
+                err = v9fs_co_opendir(pdu, f);
+            } while (err == -EINTR && !pdu->cancelled);
+        }
+    }
+    return err;
+}
+
+static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
+{
+    int err;
+    V9fsFidState *f;
+    V9fsState *s = pdu->s;
+
+    for (f = s->fid_list; f; f = f->next) {
+        BUG_ON(f->clunked);
+        if (f->fid == fid) {
+            /*
+             * Update the fid ref upfront so that
+             * we don't get reclaimed when we yield
+             * in open later.
+             */
+            f->ref++;
+            /*
+             * check whether we need to reopen the
+             * file. We might have closed the fd
+             * while trying to free up some file
+             * descriptors.
+             */
+            err = v9fs_reopen_fid(pdu, f);
+            if (err < 0) {
+                f->ref--;
+                return NULL;
+            }
+            /*
+             * Mark the fid as referenced so that the LRU
+             * reclaim won't close the file descriptor
+             */
+            f->flags |= FID_REFERENCED;
+            return f;
+        }
+    }
+    return NULL;
+}
+
+static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState *f;
+
+    for (f = s->fid_list; f; f = f->next) {
+        /* If fid is already there return NULL */
+        BUG_ON(f->clunked);
+        if (f->fid == fid) {
+            return NULL;
+        }
+    }
+    f = g_malloc0(sizeof(V9fsFidState));
+    f->fid = fid;
+    f->fid_type = P9_FID_NONE;
+    f->ref = 1;
+    /*
+     * Mark the fid as referenced so that the LRU
+     * reclaim won't close the file descriptor
+     */
+    f->flags |= FID_REFERENCED;
+    f->next = s->fid_list;
+    s->fid_list = f;
+
+    return f;
+}
+
+static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, 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_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
+                                   fidp->fs.xattr.value,
+                                   fidp->fs.xattr.len,
+                                   fidp->fs.xattr.flags);
+    } else {
+        retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
+    }
+free_out:
+    v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+    if (fidp->fs.xattr.value) {
+        g_free(fidp->fs.xattr.value);
+    }
+    return retval;
+}
+
+static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
+{
+    int retval = 0;
+
+    if (fidp->fid_type == P9_FID_FILE) {
+        /* If we reclaimed the fd no need to close */
+        if (fidp->fs.fd != -1) {
+            retval = v9fs_co_close(pdu, &fidp->fs);
+        }
+    } else if (fidp->fid_type == P9_FID_DIR) {
+        if (fidp->fs.dir != NULL) {
+            retval = v9fs_co_closedir(pdu, &fidp->fs);
+        }
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        retval = v9fs_xattr_fid_clunk(pdu, fidp);
+    }
+    v9fs_path_free(&fidp->path);
+    g_free(fidp);
+    return retval;
+}
+
+static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
+{
+    BUG_ON(!fidp->ref);
+    fidp->ref--;
+    /*
+     * Don't free the fid if it is in reclaim list
+     */
+    if (!fidp->ref && fidp->clunked) {
+        if (fidp->fid == pdu->s->root_fid) {
+            /*
+             * if the clunked fid is root fid then we
+             * have unmounted the fs on the client side.
+             * delete the migration blocker. Ideally, this
+             * should be hooked to transport close notification
+             */
+            if (pdu->s->migration_blocker) {
+                migrate_del_blocker(pdu->s->migration_blocker);
+                error_free(pdu->s->migration_blocker);
+                pdu->s->migration_blocker = NULL;
+            }
+        }
+        free_fid(pdu, fidp);
+    }
+}
+
+static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState **fidpp, *fidp;
+
+    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
+        if ((*fidpp)->fid == fid) {
+            break;
+        }
+    }
+    if (*fidpp == NULL) {
+        return NULL;
+    }
+    fidp = *fidpp;
+    *fidpp = fidp->next;
+    fidp->clunked = 1;
+    return fidp;
+}
+
+void v9fs_reclaim_fd(V9fsPDU *pdu)
+{
+    int reclaim_count = 0;
+    V9fsState *s = pdu->s;
+    V9fsFidState *f, *reclaim_list = NULL;
+
+    for (f = s->fid_list; f; f = f->next) {
+        /*
+         * Unlink fids cannot be reclaimed. Check
+         * for them and skip them. Also skip fids
+         * currently being operated on.
+         */
+        if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
+            continue;
+        }
+        /*
+         * if it is a recently referenced fid
+         * we leave the fid untouched and clear the
+         * reference bit. We come back to it later
+         * in the next iteration. (a simple LRU without
+         * moving list elements around)
+         */
+        if (f->flags & FID_REFERENCED) {
+            f->flags &= ~FID_REFERENCED;
+            continue;
+        }
+        /*
+         * Add fids to reclaim list.
+         */
+        if (f->fid_type == P9_FID_FILE) {
+            if (f->fs.fd != -1) {
+                /*
+                 * Up the reference count so that
+                 * a clunk request won't free this fid
+                 */
+                f->ref++;
+                f->rclm_lst = reclaim_list;
+                reclaim_list = f;
+                f->fs_reclaim.fd = f->fs.fd;
+                f->fs.fd = -1;
+                reclaim_count++;
+            }
+        } else if (f->fid_type == P9_FID_DIR) {
+            if (f->fs.dir != NULL) {
+                /*
+                 * Up the reference count so that
+                 * a clunk request won't free this fid
+                 */
+                f->ref++;
+                f->rclm_lst = reclaim_list;
+                reclaim_list = f;
+                f->fs_reclaim.dir = f->fs.dir;
+                f->fs.dir = NULL;
+                reclaim_count++;
+            }
+        }
+        if (reclaim_count >= open_fd_rc) {
+            break;
+        }
+    }
+    /*
+     * Now close the fid in reclaim list. Free them if they
+     * are already clunked.
+     */
+    while (reclaim_list) {
+        f = reclaim_list;
+        reclaim_list = f->rclm_lst;
+        if (f->fid_type == P9_FID_FILE) {
+            v9fs_co_close(pdu, &f->fs_reclaim);
+        } else if (f->fid_type == P9_FID_DIR) {
+            v9fs_co_closedir(pdu, &f->fs_reclaim);
+        }
+        f->rclm_lst = NULL;
+        /*
+         * Now drop the fid reference, free it
+         * if clunked.
+         */
+        put_fid(pdu, f);
+    }
+}
+
+static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
+{
+    int err;
+    V9fsState *s = pdu->s;
+    V9fsFidState *fidp, head_fid;
+
+    head_fid.next = s->fid_list;
+    for (fidp = s->fid_list; fidp; fidp = fidp->next) {
+        if (fidp->path.size != path->size) {
+            continue;
+        }
+        if (!memcmp(fidp->path.data, path->data, path->size)) {
+            /* Mark the fid non reclaimable. */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+
+            /* reopen the file/dir if already closed */
+            err = v9fs_reopen_fid(pdu, fidp);
+            if (err < 0) {
+                return -1;
+            }
+            /*
+             * Go back to head of fid list because
+             * the list could have got updated when
+             * switched to the worker thread
+             */
+            if (err == 0) {
+                fidp = &head_fid;
+            }
+        }
+    }
+    return 0;
+}
+
+static void virtfs_reset(V9fsPDU *pdu)
+{
+    V9fsState *s = pdu->s;
+    V9fsFidState *fidp = NULL;
+
+    /* Free all fids */
+    while (s->fid_list) {
+        fidp = s->fid_list;
+        s->fid_list = fidp->next;
+
+        if (fidp->ref) {
+            fidp->clunked = 1;
+        } else {
+            free_fid(pdu, fidp);
+        }
+    }
+    if (fidp) {
+        /* One or more unclunked fids found... */
+        error_report("9pfs:%s: One or more uncluncked fids "
+                     "found during reset", __func__);
+    }
+    return;
+}
+
+#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;
+
+    memset(&qidp->path, 0, sizeof(qidp->path));
+    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(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
+{
+    struct stat stbuf;
+    int err;
+
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+    if (err < 0) {
+        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);
+        QLIST_INSERT_HEAD(&s->active_list, pdu, next);
+    }
+    return pdu;
+}
+
+static void free_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    if (pdu) {
+        /*
+         * Cancelled pdu are added back to the freelist
+         * by flush request .
+         */
+        if (!pdu->cancelled) {
+            QLIST_REMOVE(pdu, next);
+            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 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 's': {
+            V9fsString *str = va_arg(ap, V9fsString *);
+            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
+            /* FIXME: sanity check str->size */
+            str->data = g_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 '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;
+        }
+        trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
+    }
+
+    /* 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);
+
+    /* Now wakeup anybody waiting in flush for this request */
+    qemu_co_queue_next(&pdu->complete);
+
+    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(V9fsPDU *pdu, V9fsPath *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_co_readlink(pdu, name, &v9stat->extension);
+        if (err < 0) {
+            return 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 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");
+}
+
+/* Will call this only for path name based fid */
+static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
+{
+    V9fsPath str;
+    v9fs_path_init(&str);
+    v9fs_path_copy(&str, dst);
+    v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
+    v9fs_path_free(&str);
+    /* +1 to include terminating NULL */
+    dst->size++;
+}
+
+static inline bool is_ro_export(FsContext *ctx)
+{
+    return ctx->export_flags & V9FS_RDONLY;
+}
+
+static void v9fs_version(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    V9fsString version;
+    size_t offset = 7;
+
+    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
+    trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
+
+    virtfs_reset(pdu);
+
+    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);
+    trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
+
+    complete_pdu(s, pdu, offset);
+
+    v9fs_string_free(&version);
+    return;
+}
+
+static void v9fs_attach(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    int32_t fid, afid, n_uname;
+    V9fsString uname, aname;
+    V9fsFidState *fidp;
+    size_t offset = 7;
+    V9fsQID qid;
+    ssize_t err;
+
+    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
+    trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
+
+    fidp = alloc_fid(s, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    fidp->uid = n_uname;
+    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
+    if (err < 0) {
+        err = -EINVAL;
+        clunk_fid(s, fid);
+        goto out;
+    }
+    err = fid_to_qid(pdu, fidp, &qid);
+    if (err < 0) {
+        err = -EINVAL;
+        clunk_fid(s, fid);
+        goto out;
+    }
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+    err = offset;
+    trace_v9fs_attach_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path);
+    s->root_fid = fid;
+    /* disable migration */
+    error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
+              s->ctx.fs_root, s->tag);
+    migrate_add_blocker(s->migration_blocker);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&uname);
+    v9fs_string_free(&aname);
+}
+
+static void v9fs_stat(void *opaque)
+{
+    int32_t fid;
+    V9fsStat v9stat;
+    ssize_t err = 0;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_stat(pdu->tag, pdu->id, fid);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
+    if (err < 0) {
+        goto out;
+    }
+    offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
+    err = offset;
+    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
+                           v9stat.atime, v9stat.mtime, v9stat.length);
+    v9fs_stat_free(&v9stat);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_getattr(void *opaque)
+{
+    int32_t fid;
+    size_t offset = 7;
+    ssize_t retval = 0;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    uint64_t request_mask;
+    V9fsStatDotl v9stat_dotl;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
+    trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        retval = -ENOENT;
+        goto out_nofid;
+    }
+    /*
+     * Currently we only support BASIC fields in stat, so there is no
+     * need to look at request_mask.
+     */
+    retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+    if (retval < 0) {
+        goto out;
+    }
+    stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
+
+    /*  fill st_gen if requested and supported by underlying fs */
+    if (request_mask & P9_STATS_GEN) {
+        retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
+        if (retval < 0) {
+            goto out;
+        }
+        v9stat_dotl.st_result_mask |= P9_STATS_GEN;
+    }
+    retval = offset;
+    retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
+    trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
+                              v9stat_dotl.st_mode, v9stat_dotl.st_uid,
+                              v9stat_dotl.st_gid);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, retval);
+}
+
+/* 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(void *opaque)
+{
+    int err = 0;
+    int32_t fid;
+    V9fsFidState *fidp;
+    size_t offset = 7;
+    V9fsIattr v9iattr;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    if (v9iattr.valid & ATTR_MODE) {
+        err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+        struct timespec times[2];
+        if (v9iattr.valid & ATTR_ATIME) {
+            if (v9iattr.valid & ATTR_ATIME_SET) {
+                times[0].tv_sec = v9iattr.atime_sec;
+                times[0].tv_nsec = v9iattr.atime_nsec;
+            } else {
+                times[0].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+        if (v9iattr.valid & ATTR_MTIME) {
+            if (v9iattr.valid & ATTR_MTIME_SET) {
+                times[1].tv_sec = v9iattr.mtime_sec;
+                times[1].tv_nsec = v9iattr.mtime_nsec;
+            } else {
+                times[1].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
+        if (err < 0) {
+            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 ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
+        ((v9iattr.valid & ATTR_CTIME)
+         && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+        if (!(v9iattr.valid & ATTR_UID)) {
+            v9iattr.uid = -1;
+        }
+        if (!(v9iattr.valid & ATTR_GID)) {
+            v9iattr.gid = -1;
+        }
+        err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
+                            v9iattr.gid);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9iattr.valid & (ATTR_SIZE)) {
+        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    err = offset;
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
+{
+    int i;
+    size_t offset = 7;
+    offset += pdu_marshal(pdu, offset, "w", nwnames);
+    for (i = 0; i < nwnames; i++) {
+        offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
+    }
+    return offset;
+}
+
+static void v9fs_walk(void *opaque)
+{
+    int name_idx;
+    V9fsQID *qids = NULL;
+    int i, err = 0;
+    V9fsPath dpath, path;
+    uint16_t nwnames;
+    struct stat stbuf;
+    size_t offset = 7;
+    int32_t fid, newfid;
+    V9fsString *wnames = NULL;
+    V9fsFidState *fidp;
+    V9fsFidState *newfidp = NULL;;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
+                            &newfid, &nwnames);
+
+    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
+
+    if (nwnames && nwnames <= P9_MAXWELEM) {
+        wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
+        qids   = g_malloc0(sizeof(qids[0]) * nwnames);
+        for (i = 0; i < nwnames; i++) {
+            offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
+        }
+    } else if (nwnames > P9_MAXWELEM) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    v9fs_path_init(&dpath);
+    v9fs_path_init(&path);
+    /*
+     * Both dpath and path initially poin to fidp.
+     * Needed to handle request with nwnames == 0
+     */
+    v9fs_path_copy(&dpath, &fidp->path);
+    v9fs_path_copy(&path, &fidp->path);
+    for (name_idx = 0; name_idx < nwnames; name_idx++) {
+        err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        stat_to_qid(&stbuf, &qids[name_idx]);
+        v9fs_path_copy(&dpath, &path);
+    }
+    if (fid == newfid) {
+        BUG_ON(fidp->fid_type != P9_FID_NONE);
+        v9fs_path_copy(&fidp->path, &path);
+    } else {
+        newfidp = alloc_fid(s, newfid);
+        if (newfidp == NULL) {
+            err = -EINVAL;
+            goto out;
+        }
+        newfidp->uid = fidp->uid;
+        v9fs_path_copy(&newfidp->path, &path);
+    }
+    err = v9fs_walk_marshal(pdu, nwnames, qids);
+    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
+out:
+    put_fid(pdu, fidp);
+    if (newfidp) {
+        put_fid(pdu, newfidp);
+    }
+    v9fs_path_free(&dpath);
+    v9fs_path_free(&path);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    if (nwnames && nwnames <= P9_MAXWELEM) {
+        for (name_idx = 0; name_idx < nwnames; name_idx++) {
+            v9fs_string_free(&wnames[name_idx]);
+        }
+        g_free(wnames);
+        g_free(qids);
+    }
+    return;
+}
+
+static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
+{
+    struct statfs stbuf;
+    int32_t iounit = 0;
+    V9fsState *s = pdu->s;
+
+    /*
+     * iounit should be multiples of f_bsize (host filesystem block size
+     * and as well as less than (client msize - P9_IOHDRSZ))
+     */
+    if (!v9fs_co_statfs(pdu, path, &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(void *opaque)
+{
+    int flags;
+    int32_t fid;
+    int32_t mode;
+    V9fsQID qid;
+    int iounit = 0;
+    ssize_t err = 0;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    if (s->proto_version == V9FS_PROTO_2000L) {
+        pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
+    } else {
+        pdu_unmarshal(pdu, offset, "db", &fid, &mode);
+    }
+    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    BUG_ON(fidp->fid_type != P9_FID_NONE);
+
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    if (S_ISDIR(stbuf.st_mode)) {
+        err = v9fs_co_opendir(pdu, fidp);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_DIR;
+        offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
+        err = offset;
+    } else {
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            flags = get_dotl_openflags(s, mode);
+        } else {
+            flags = omode_to_uflags(mode);
+        }
+        if (is_ro_export(&s->ctx)) {
+            if (mode & O_WRONLY || mode & O_RDWR ||
+                mode & O_APPEND || mode & O_TRUNC) {
+                err = -EROFS;
+                goto out;
+            }
+            flags |= O_NOATIME;
+        }
+        err = v9fs_co_open(pdu, fidp, flags);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_FILE;
+        fidp->open_flags = flags;
+        if (flags & O_EXCL) {
+            /*
+             * We let the host file system do O_EXCL check
+             * We should not reclaim such fd
+             */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+        }
+        iounit = get_iounit(pdu, &fidp->path);
+        offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+        err = offset;
+    }
+    trace_v9fs_open_return(pdu->tag, pdu->id,
+                           qid.type, qid.version, qid.path, iounit);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_lcreate(void *opaque)
+{
+    int32_t dfid, flags, mode;
+    gid_t gid;
+    ssize_t err = 0;
+    ssize_t offset = 7;
+    V9fsString name;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+    V9fsQID qid;
+    int32_t iounit;
+    V9fsPDU *pdu = opaque;
+
+    pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
+                  &mode, &gid);
+    trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
+
+    fidp = get_fid(pdu, dfid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+
+    flags = get_dotl_openflags(pdu->s, flags);
+    err = v9fs_co_open2(pdu, fidp, &name, gid,
+                        flags | O_CREAT, mode, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    fidp->fid_type = P9_FID_FILE;
+    fidp->open_flags = flags;
+    if (flags & O_EXCL) {
+        /*
+         * We let the host file system do O_EXCL check
+         * We should not reclaim such fd
+         */
+        fidp->flags |= FID_NON_RECLAIMABLE;
+    }
+    iounit =  get_iounit(pdu, &fidp->path);
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    err = offset;
+    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path, iounit);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+static void v9fs_fsync(void *opaque)
+{
+    int err;
+    int32_t fid;
+    int datasync;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
+    trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_fsync(pdu, fidp, datasync);
+    if (!err) {
+        err = offset;
+    }
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_clunk(void *opaque)
+{
+    int err;
+    int32_t fid;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_clunk(pdu->tag, pdu->id, fid);
+
+    fidp = clunk_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    /*
+     * Bump the ref so that put_fid will
+     * free the fid.
+     */
+    fidp->ref++;
+    err = offset;
+
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
+                           uint64_t off, uint32_t max_count)
+{
+    size_t offset = 7;
+    int read_count;
+    int64_t xattr_len;
+
+    xattr_len = fidp->fs.xattr.len;
+    read_count = xattr_len - off;
+    if (read_count > max_count) {
+        read_count = max_count;
+    } else if (read_count < 0) {
+        /*
+         * read beyond XATTR value
+         */
+        read_count = 0;
+    }
+    offset += pdu_marshal(pdu, offset, "d", read_count);
+    offset += pdu_pack(pdu, offset,
+                       ((char *)fidp->fs.xattr.value) + off,
+                       read_count);
+    return offset;
+}
+
+static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
+                                     V9fsFidState *fidp, uint32_t max_count)
+{
+    V9fsPath path;
+    V9fsStat v9stat;
+    int len, err = 0;
+    int32_t count = 0;
+    struct stat stbuf;
+    off_t saved_dir_pos;
+    struct dirent *dent, *result;
+
+    /* save the directory position */
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
+    if (saved_dir_pos < 0) {
+        return saved_dir_pos;
+    }
+
+    dent = g_malloc(sizeof(struct dirent));
+
+    while (1) {
+        v9fs_path_init(&path);
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
+        if (err || !result) {
+            break;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
+        if (err < 0) {
+            goto out;
+        }
+        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
+        len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
+        if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
+            v9fs_stat_free(&v9stat);
+            v9fs_path_free(&path);
+            g_free(dent);
+            return count;
+        }
+        count += len;
+        v9fs_stat_free(&v9stat);
+        v9fs_path_free(&path);
+        saved_dir_pos = dent->d_off;
+    }
+out:
+    g_free(dent);
+    v9fs_path_free(&path);
+    if (err < 0) {
+        return err;
+    }
+    return count;
+}
+
+/*
+ * Create a QEMUIOVector for a sub-region of PDU iovecs
+ *
+ * @qiov:       uninitialized QEMUIOVector
+ * @skip:       number of bytes to skip from beginning of PDU
+ * @size:       number of bytes to include
+ * @is_write:   true - write, false - read
+ *
+ * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
+ * with qemu_iovec_destroy().
+ */
+static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
+                                    uint64_t skip, size_t size,
+                                    bool is_write)
+{
+    QEMUIOVector elem;
+    struct iovec *iov;
+    unsigned int niov;
+
+    if (is_write) {
+        iov = pdu->elem.out_sg;
+        niov = pdu->elem.out_num;
+    } else {
+        iov = pdu->elem.in_sg;
+        niov = pdu->elem.in_num;
+    }
+
+    qemu_iovec_init_external(&elem, iov, niov);
+    qemu_iovec_init(qiov, niov);
+    qemu_iovec_copy(qiov, &elem, skip, size);
+}
+
+static void v9fs_read(void *opaque)
+{
+    int32_t fid;
+    uint64_t off;
+    ssize_t err = 0;
+    int32_t count = 0;
+    size_t offset = 7;
+    uint32_t max_count;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
+    trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    if (fidp->fid_type == P9_FID_DIR) {
+
+        if (off == 0) {
+            v9fs_co_rewinddir(pdu, fidp);
+        }
+        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
+        if (count < 0) {
+            err = count;
+            goto out;
+        }
+        err = offset;
+        err += pdu_marshal(pdu, offset, "d", count);
+        err += count;
+    } else if (fidp->fid_type == P9_FID_FILE) {
+        QEMUIOVector qiov_full;
+        QEMUIOVector qiov;
+        int32_t len;
+
+        v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
+        qemu_iovec_init(&qiov, qiov_full.niov);
+        do {
+            qemu_iovec_reset(&qiov);
+            qemu_iovec_copy(&qiov, &qiov_full, count, qiov_full.size - count);
+            if (0) {
+                print_sg(qiov.iov, qiov.niov);
+            }
+            /* Loop in case of EINTR */
+            do {
+                len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
+                if (len >= 0) {
+                    off   += len;
+                    count += len;
+                }
+            } while (len == -EINTR && !pdu->cancelled);
+            if (len < 0) {
+                /* IO error return the error */
+                err = len;
+                goto out;
+            }
+        } while (count < max_count && len > 0);
+        err = offset;
+        err += pdu_marshal(pdu, offset, "d", count);
+        err += count;
+        qemu_iovec_destroy(&qiov);
+        qemu_iovec_destroy(&qiov_full);
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
+    } else {
+        err = -EINVAL;
+    }
+    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+}
+
+static size_t v9fs_readdir_data_size(V9fsString *name)
+{
+    /*
+     * 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)
+     */
+    return 24 + v9fs_string_size(name);
+}
+
+static int v9fs_do_readdir(V9fsPDU *pdu,
+                           V9fsFidState *fidp, int32_t max_count)
+{
+    size_t size;
+    V9fsQID qid;
+    V9fsString name;
+    int len, err = 0;
+    int32_t count = 0;
+    off_t saved_dir_pos;
+    struct dirent *dent, *result;
+
+    /* save the directory position */
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
+    if (saved_dir_pos < 0) {
+        return saved_dir_pos;
+    }
+
+    dent = g_malloc(sizeof(struct dirent));
+
+    while (1) {
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
+        if (err || !result) {
+            break;
+        }
+        v9fs_string_init(&name);
+        v9fs_string_sprintf(&name, "%s", dent->d_name);
+        if ((count + v9fs_readdir_data_size(&name)) > max_count) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
+            v9fs_string_free(&name);
+            g_free(dent);
+            return count;
+        }
+        /*
+         * 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(dent->d_ino), sizeof(qid.path));
+        memcpy(&qid.path, &dent->d_ino, size);
+        /* Fill the other fields with dummy values */
+        qid.type = 0;
+        qid.version = 0;
+
+        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
+        len = pdu_marshal(pdu, 11 + count, "Qqbs",
+                          &qid, dent->d_off,
+                          dent->d_type, &name);
+        count += len;
+        v9fs_string_free(&name);
+        saved_dir_pos = dent->d_off;
+    }
+    g_free(dent);
+    if (err < 0) {
+        return err;
+    }
+    return count;
+}
+
+static void v9fs_readdir(void *opaque)
+{
+    int32_t fid;
+    V9fsFidState *fidp;
+    ssize_t retval = 0;
+    size_t offset = 7;
+    uint64_t initial_offset;
+    int32_t count;
+    uint32_t max_count;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
+
+    trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        retval = -EINVAL;
+        goto out_nofid;
+    }
+    if (!fidp->fs.dir) {
+        retval = -EINVAL;
+        goto out;
+    }
+    if (initial_offset == 0) {
+        v9fs_co_rewinddir(pdu, fidp);
+    } else {
+        v9fs_co_seekdir(pdu, fidp, initial_offset);
+    }
+    count = v9fs_do_readdir(pdu, fidp, max_count);
+    if (count < 0) {
+        retval = count;
+        goto out;
+    }
+    retval = offset;
+    retval += pdu_marshal(pdu, offset, "d", count);
+    retval += count;
+    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, retval);
+}
+
+static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
+                            uint64_t off, uint32_t count,
+                            struct iovec *sg, int cnt)
+{
+    int i, to_copy;
+    ssize_t err = 0;
+    int write_count;
+    int64_t xattr_len;
+    size_t offset = 7;
+
+
+    xattr_len = fidp->fs.xattr.len;
+    write_count = xattr_len - off;
+    if (write_count > count) {
+        write_count = count;
+    } else if (write_count < 0) {
+        /*
+         * write beyond XATTR value len specified in
+         * xattrcreate
+         */
+        err = -ENOSPC;
+        goto out;
+    }
+    offset += pdu_marshal(pdu, offset, "d", write_count);
+    err = offset;
+    fidp->fs.xattr.copied_len += write_count;
+    /*
+     * Now copy the content from sg list
+     */
+    for (i = 0; i < cnt; i++) {
+        if (write_count > sg[i].iov_len) {
+            to_copy = sg[i].iov_len;
+        } else {
+            to_copy = write_count;
+        }
+        memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
+        /* updating vs->off since we are not using below */
+        off += to_copy;
+        write_count -= to_copy;
+    }
+out:
+    return err;
+}
+
+static void v9fs_write(void *opaque)
+{
+    ssize_t err;
+    int32_t fid;
+    uint64_t off;
+    uint32_t count;
+    int32_t len = 0;
+    int32_t total = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    QEMUIOVector qiov_full;
+    QEMUIOVector qiov;
+
+    offset += pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
+    v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
+    trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    if (fidp->fid_type == P9_FID_FILE) {
+        if (fidp->fs.fd == -1) {
+            err = -EINVAL;
+            goto out;
+        }
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        /*
+         * setxattr operation
+         */
+        err = v9fs_xattr_write(s, pdu, fidp, off, count,
+                               qiov_full.iov, qiov_full.niov);
+        goto out;
+    } else {
+        err = -EINVAL;
+        goto out;
+    }
+    qemu_iovec_init(&qiov, qiov_full.niov);
+    do {
+        qemu_iovec_reset(&qiov);
+        qemu_iovec_copy(&qiov, &qiov_full, total, qiov_full.size - total);
+        if (0) {
+            print_sg(qiov.iov, qiov.niov);
+        }
+        /* Loop in case of EINTR */
+        do {
+            len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
+            if (len >= 0) {
+                off   += len;
+                total += len;
+            }
+        } while (len == -EINTR && !pdu->cancelled);
+        if (len < 0) {
+            /* IO error return the error */
+            err = len;
+            goto out_qiov;
+        }
+    } while (total < count && len > 0);
+
+    offset = 7;
+    offset += pdu_marshal(pdu, offset, "d", total);
+    err = offset;
+    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
+out_qiov:
+    qemu_iovec_destroy(&qiov);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    qemu_iovec_destroy(&qiov_full);
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_create(void *opaque)
+{
+    int32_t fid;
+    int err = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t perm;
+    int8_t mode;
+    V9fsPath path;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString extension;
+    int iounit;
+    V9fsPDU *pdu = opaque;
+
+    v9fs_path_init(&path);
+
+    pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
+                  &perm, &mode, &extension);
+
+    trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    if (perm & P9_STAT_MODE_DIR) {
+        err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
+                            fidp->uid, -1, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+        err = v9fs_co_opendir(pdu, fidp);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_DIR;
+    } else if (perm & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_co_symlink(pdu, fidp, &name,
+                              extension.data, -1 , &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+    } else if (perm & P9_STAT_MODE_LINK) {
+        int32_t ofid = atoi(extension.data);
+        V9fsFidState *ofidp = get_fid(pdu, ofid);
+        if (ofidp == NULL) {
+            err = -EINVAL;
+            goto out;
+        }
+        err = v9fs_co_link(pdu, ofidp, fidp, &name);
+        put_fid(pdu, ofidp);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+        if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
+            goto out;
+        }
+    } else if (perm & P9_STAT_MODE_DEVICE) {
+        char ctype;
+        uint32_t major, minor;
+        mode_t nmode = 0;
+
+        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
+            err = -errno;
+            goto out;
+        }
+
+        switch (ctype) {
+        case 'c':
+            nmode = S_IFCHR;
+            break;
+        case 'b':
+            nmode = S_IFBLK;
+            break;
+        default:
+            err = -EIO;
+            goto out;
+        }
+
+        nmode |= perm & 0777;
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+                            makedev(major, minor), nmode, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+    } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+                            0, S_IFIFO | (perm & 0777), &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+    } else if (perm & P9_STAT_MODE_SOCKET) {
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+                            0, S_IFSOCK | (perm & 0777), &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
+    } else {
+        err = v9fs_co_open2(pdu, fidp, &name, -1,
+                            omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_FILE;
+        fidp->open_flags = omode_to_uflags(mode);
+        if (fidp->open_flags & O_EXCL) {
+            /*
+             * We let the host file system do O_EXCL check
+             * We should not reclaim such fd
+             */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+        }
+    }
+    iounit = get_iounit(pdu, &fidp->path);
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    err = offset;
+    trace_v9fs_create_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path, iounit);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+   complete_pdu(pdu->s, pdu, err);
+   v9fs_string_free(&name);
+   v9fs_string_free(&extension);
+   v9fs_path_free(&path);
+}
+
+static void v9fs_symlink(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    V9fsString name;
+    V9fsString symname;
+    V9fsFidState *dfidp;
+    V9fsQID qid;
+    struct stat stbuf;
+    int32_t dfid;
+    int err = 0;
+    gid_t gid;
+    size_t offset = 7;
+
+    pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
+    trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
+
+    dfidp = get_fid(pdu, dfid);
+    if (dfidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+    err = offset;
+    trace_v9fs_symlink_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path);
+out:
+    put_fid(pdu, dfidp);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+    v9fs_string_free(&symname);
+}
+
+static void v9fs_flush(void *opaque)
+{
+    int16_t tag;
+    size_t offset = 7;
+    V9fsPDU *cancel_pdu;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "w", &tag);
+    trace_v9fs_flush(pdu->tag, pdu->id, tag);
+
+    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
+        if (cancel_pdu->tag == tag) {
+            break;
+        }
+    }
+    if (cancel_pdu) {
+        cancel_pdu->cancelled = 1;
+        /*
+         * Wait for pdu to complete.
+         */
+        qemu_co_queue_wait(&cancel_pdu->complete);
+        cancel_pdu->cancelled = 0;
+        free_pdu(pdu->s, cancel_pdu);
+    }
+    complete_pdu(s, pdu, 7);
+    return;
+}
+
+static void v9fs_link(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    int32_t dfid, oldfid;
+    V9fsFidState *dfidp, *oldfidp;
+    V9fsString name;;
+    size_t offset = 7;
+    int err = 0;
+
+    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+    trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
+
+    dfidp = get_fid(pdu, dfid);
+    if (dfidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+
+    oldfidp = get_fid(pdu, oldfid);
+    if (oldfidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
+    if (!err) {
+        err = offset;
+    }
+out:
+    put_fid(pdu, dfidp);
+out_nofid:
+    v9fs_string_free(&name);
+    complete_pdu(s, pdu, err);
+}
+
+/* Only works with path name based fid */
+static void v9fs_remove(void *opaque)
+{
+    int32_t fid;
+    int err = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_remove(pdu->tag, pdu->id, fid);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
+        err = -EOPNOTSUPP;
+        goto out_err;
+    }
+    /*
+     * IF the file is unlinked, we cannot reopen
+     * the file later. So don't reclaim fd
+     */
+    err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_co_remove(pdu, &fidp->path);
+    if (!err) {
+        err = offset;
+    }
+out_err:
+    /* For TREMOVE we need to clunk the fid even on failed remove */
+    clunk_fid(pdu->s, fidp->fid);
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+}
+
+static void v9fs_unlinkat(void *opaque)
+{
+    int err = 0;
+    V9fsString name;
+    int32_t dfid, flags;
+    size_t offset = 7;
+    V9fsPath path;
+    V9fsFidState *dfidp;
+    V9fsPDU *pdu = opaque;
+
+    pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
+
+    dfidp = get_fid(pdu, dfid);
+    if (dfidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    /*
+     * IF the file is unlinked, we cannot reopen
+     * the file later. So don't reclaim fd
+     */
+    v9fs_path_init(&path);
+    err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_mark_fids_unreclaim(pdu, &path);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
+    if (!err) {
+        err = offset;
+    }
+out_err:
+    put_fid(pdu, dfidp);
+    v9fs_path_free(&path);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+
+/* Only works with path name based fid */
+static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
+                                int32_t newdirfid, V9fsString *name)
+{
+    char *end;
+    int err = 0;
+    V9fsPath new_path;
+    V9fsFidState *tfidp;
+    V9fsState *s = pdu->s;
+    V9fsFidState *dirfidp = NULL;
+    char *old_name, *new_name;
+
+    v9fs_path_init(&new_path);
+    if (newdirfid != -1) {
+        dirfidp = get_fid(pdu, newdirfid);
+        if (dirfidp == NULL) {
+            err = -ENOENT;
+            goto out_nofid;
+        }
+        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
+        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
+    } else {
+        old_name = fidp->path.data;
+        end = strrchr(old_name, '/');
+        if (end) {
+            end++;
+        } else {
+            end = old_name;
+        }
+        new_name = g_malloc0(end - old_name + name->size + 1);
+        strncat(new_name, old_name, end - old_name);
+        strncat(new_name + (end - old_name), name->data, name->size);
+        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
+        g_free(new_name);
+    }
+    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
+    if (err < 0) {
+        goto out;
+    }
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
+        }
+    }
+out:
+    if (dirfidp) {
+        put_fid(pdu, dirfidp);
+    }
+    v9fs_path_free(&new_path);
+out_nofid:
+    return err;
+}
+
+/* Only works with path name based fid */
+static void v9fs_rename(void *opaque)
+{
+    int32_t fid;
+    ssize_t err = 0;
+    size_t offset = 7;
+    V9fsString name;
+    int32_t newdirfid;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    BUG_ON(fidp->fid_type != P9_FID_NONE);
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
+        err = -EOPNOTSUPP;
+        goto out;
+    }
+    v9fs_path_write_lock(s);
+    err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
+    v9fs_path_unlock(s);
+    if (!err) {
+        err = offset;
+    }
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
+                               V9fsString *old_name, V9fsPath *newdir,
+                               V9fsString *new_name)
+{
+    V9fsFidState *tfidp;
+    V9fsPath oldpath, newpath;
+    V9fsState *s = pdu->s;
+
+
+    v9fs_path_init(&oldpath);
+    v9fs_path_init(&newpath);
+    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
+    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
+
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
+        }
+    }
+    v9fs_path_free(&oldpath);
+    v9fs_path_free(&newpath);
+}
+
+static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
+                                  V9fsString *old_name, int32_t newdirfid,
+                                  V9fsString *new_name)
+{
+    int err = 0;
+    V9fsState *s = pdu->s;
+    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
+
+    olddirfidp = get_fid(pdu, olddirfid);
+    if (olddirfidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+    if (newdirfid != -1) {
+        newdirfidp = get_fid(pdu, newdirfid);
+        if (newdirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+    } else {
+        newdirfidp = get_fid(pdu, olddirfid);
+    }
+
+    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    if (err < 0) {
+        goto out;
+    }
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
+        /* Only for path based fid  we need to do the below fixup */
+        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    }
+out:
+    if (olddirfidp) {
+        put_fid(pdu, olddirfidp);
+    }
+    if (newdirfidp) {
+        put_fid(pdu, newdirfidp);
+    }
+    return err;
+}
+
+static void v9fs_renameat(void *opaque)
+{
+    ssize_t err = 0;
+    size_t offset = 7;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    int32_t olddirfid, newdirfid;
+    V9fsString old_name, new_name;
+
+    pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
+                  &old_name, &newdirfid, &new_name);
+
+    v9fs_path_write_lock(s);
+    err = v9fs_complete_renameat(pdu, olddirfid,
+                                 &old_name, newdirfid, &new_name);
+    v9fs_path_unlock(s);
+    if (!err) {
+        err = offset;
+    }
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&old_name);
+    v9fs_string_free(&new_name);
+}
+
+static void v9fs_wstat(void *opaque)
+{
+    int32_t fid;
+    int err = 0;
+    int16_t unused;
+    V9fsStat v9stat;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
+    trace_v9fs_wstat(pdu->tag, pdu->id, fid,
+                     v9stat.mode, v9stat.atime, v9stat.mtime);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    /* do we need to sync the file? */
+    if (donttouch_stat(&v9stat)) {
+        err = v9fs_co_fsync(pdu, fidp, 0);
+        goto out;
+    }
+    if (v9stat.mode != -1) {
+        uint32_t v9_mode;
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        v9_mode = stat_to_v9mode(&stbuf);
+        if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
+            (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
+            /* Attempting to change the type */
+            err = -EIO;
+            goto out;
+        }
+        err = v9fs_co_chmod(pdu, &fidp->path,
+                            v9mode_to_mode(v9stat.mode,
+                                           &v9stat.extension));
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9stat.mtime != -1 || v9stat.atime != -1) {
+        struct timespec times[2];
+        if (v9stat.atime != -1) {
+            times[0].tv_sec = v9stat.atime;
+            times[0].tv_nsec = 0;
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+        if (v9stat.mtime != -1) {
+            times[1].tv_sec = v9stat.mtime;
+            times[1].tv_nsec = 0;
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
+        err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9stat.name.size != 0) {
+        err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9stat.length != -1) {
+        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    err = offset;
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    v9fs_stat_free(&v9stat);
+    complete_pdu(s, pdu, err);
+}
+
+static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
+{
+    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;
+    size_t offset = 7;
+    int32_t bsize_factor;
+
+    /*
+     * compute bsize factor based on host file system block size
+     * and client msize
+     */
+    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
+    if (!bsize_factor) {
+        bsize_factor = 1;
+    }
+    f_type  = stbuf->f_type;
+    f_bsize = stbuf->f_bsize;
+    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
+     */
+    f_blocks = stbuf->f_blocks/bsize_factor;
+    f_bfree  = stbuf->f_bfree/bsize_factor;
+    f_bavail = stbuf->f_bavail/bsize_factor;
+    f_files  = stbuf->f_files;
+    f_ffree  = stbuf->f_ffree;
+    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
+               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
+    f_namelen = stbuf->f_namelen;
+
+    return pdu_marshal(pdu, offset, "ddqqqqqqd",
+                       f_type, f_bsize, f_blocks, f_bfree,
+                       f_bavail, f_files, f_ffree,
+                       fsid_val, f_namelen);
+}
+
+static void v9fs_statfs(void *opaque)
+{
+    int32_t fid;
+    ssize_t retval = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    struct statfs stbuf;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        retval = -ENOENT;
+        goto out_nofid;
+    }
+    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
+    if (retval < 0) {
+        goto out;
+    }
+    retval = offset;
+    retval += v9fs_fill_statfs(s, pdu, &stbuf);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, retval);
+    return;
+}
+
+static void v9fs_mknod(void *opaque)
+{
+
+    int mode;
+    gid_t gid;
+    int32_t fid;
+    V9fsQID qid;
+    int err = 0;
+    int major, minor;
+    size_t offset = 7;
+    V9fsString name;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
+                  &major, &minor, &gid);
+    trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
+                        makedev(major, minor), mode, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    err = offset;
+    err += pdu_marshal(pdu, offset, "Q", &qid);
+    trace_v9fs_mknod_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+/*
+ * 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(void *opaque)
+{
+    int8_t status;
+    V9fsFlock *flock;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    int32_t fid, err = 0;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    flock = g_malloc(sizeof(*flock));
+    pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
+                  &flock->flags, &flock->start, &flock->length,
+                  &flock->proc_id, &flock->client_id);
+
+    trace_v9fs_lock(pdu->tag, pdu->id, fid,
+                    flock->type, flock->start, flock->length);
+
+    status = P9_LOCK_ERROR;
+
+    /* We support only block flag now (that too ignored currently) */
+    if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    status = P9_LOCK_SUCCESS;
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    err = offset;
+    err += pdu_marshal(pdu, offset, "b", status);
+    trace_v9fs_lock_return(pdu->tag, pdu->id, status);
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&flock->client_id);
+    g_free(flock);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+static void v9fs_getlock(void *opaque)
+{
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+    int32_t fid, err = 0;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    glock = g_malloc(sizeof(*glock));
+    pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
+                  &glock->start, &glock->length, &glock->proc_id,
+                  &glock->client_id);
+
+    trace_v9fs_getlock(pdu->tag, pdu->id, fid,
+                       glock->type, glock->start, glock->length);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    glock->type = P9_LOCK_TYPE_UNLCK;
+    offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
+                          glock->start, glock->length, glock->proc_id,
+                          &glock->client_id);
+    err = offset;
+    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
+                              glock->length, glock->proc_id);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&glock->client_id);
+    g_free(glock);
+}
+
+static void v9fs_mkdir(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    size_t offset = 7;
+    int32_t fid;
+    struct stat stbuf;
+    V9fsQID qid;
+    V9fsString name;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+    int err = 0;
+
+    pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
+
+    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
+
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+    err = offset;
+    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path, err);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+static void v9fs_xattrwalk(void *opaque)
+{
+    int64_t size;
+    V9fsString name;
+    ssize_t err = 0;
+    size_t offset = 7;
+    int32_t fid, newfid;
+    V9fsFidState *file_fidp;
+    V9fsFidState *xattr_fidp = NULL;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
+    trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
+
+    file_fidp = get_fid(pdu, fid);
+    if (file_fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    xattr_fidp = alloc_fid(s, newfid);
+    if (xattr_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+    v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
+    if (name.data[0] == 0) {
+        /*
+         * listxattr request. Get the size first
+         */
+        size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
+        if (size < 0) {
+            err = size;
+            clunk_fid(s, xattr_fidp->fid);
+            goto out;
+        }
+        /*
+         * Read the xattr value
+         */
+        xattr_fidp->fs.xattr.len = size;
+        xattr_fidp->fid_type = P9_FID_XATTR;
+        xattr_fidp->fs.xattr.copied_len = -1;
+        if (size) {
+            xattr_fidp->fs.xattr.value = g_malloc(size);
+            err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
+                                     xattr_fidp->fs.xattr.value,
+                                     xattr_fidp->fs.xattr.len);
+            if (err < 0) {
+                clunk_fid(s, xattr_fidp->fid);
+                goto out;
+            }
+        }
+        offset += pdu_marshal(pdu, offset, "q", size);
+        err = offset;
+    } else {
+        /*
+         * specific xattr fid. We check for xattr
+         * presence also collect the xattr size
+         */
+        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
+                                 &name, NULL, 0);
+        if (size < 0) {
+            err = size;
+            clunk_fid(s, xattr_fidp->fid);
+            goto out;
+        }
+        /*
+         * Read the xattr value
+         */
+        xattr_fidp->fs.xattr.len = size;
+        xattr_fidp->fid_type = P9_FID_XATTR;
+        xattr_fidp->fs.xattr.copied_len = -1;
+        if (size) {
+            xattr_fidp->fs.xattr.value = g_malloc(size);
+            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
+                                    &name, xattr_fidp->fs.xattr.value,
+                                    xattr_fidp->fs.xattr.len);
+            if (err < 0) {
+                clunk_fid(s, xattr_fidp->fid);
+                goto out;
+            }
+        }
+        offset += pdu_marshal(pdu, offset, "q", size);
+        err = offset;
+    }
+    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
+out:
+    put_fid(pdu, file_fidp);
+    if (xattr_fidp) {
+        put_fid(pdu, xattr_fidp);
+    }
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+static void v9fs_xattrcreate(void *opaque)
+{
+    int flags;
+    int32_t fid;
+    int64_t size;
+    ssize_t err = 0;
+    V9fsString name;
+    size_t offset = 7;
+    V9fsFidState *file_fidp;
+    V9fsFidState *xattr_fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dsqd",
+                  &fid, &name, &size, &flags);
+    trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
+
+    file_fidp = get_fid(pdu, fid);
+    if (file_fidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    /* Make the file fid point to xattr */
+    xattr_fidp = file_fidp;
+    xattr_fidp->fid_type = P9_FID_XATTR;
+    xattr_fidp->fs.xattr.copied_len = 0;
+    xattr_fidp->fs.xattr.len = size;
+    xattr_fidp->fs.xattr.flags = flags;
+    v9fs_string_init(&xattr_fidp->fs.xattr.name);
+    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
+    if (size) {
+        xattr_fidp->fs.xattr.value = g_malloc(size);
+    } else {
+        xattr_fidp->fs.xattr.value = NULL;
+    }
+    err = offset;
+    put_fid(pdu, file_fidp);
+out_nofid:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&name);
+}
+
+static void v9fs_readlink(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    size_t offset = 7;
+    V9fsString target;
+    int32_t fid;
+    int err = 0;
+    V9fsFidState *fidp;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_readlink(pdu->tag, pdu->id, fid);
+    fidp = get_fid(pdu, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+
+    v9fs_string_init(&target);
+    err = v9fs_co_readlink(pdu, &fidp->path, &target);
+    if (err < 0) {
+        goto out;
+    }
+    offset += pdu_marshal(pdu, offset, "s", &target);
+    err = offset;
+    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
+    v9fs_string_free(&target);
+out:
+    put_fid(pdu, fidp);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+}
+
+static CoroutineEntry *pdu_co_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_TRENAMEAT] = v9fs_renameat,
+    [P9_TREADLINK] = v9fs_readlink,
+    [P9_TUNLINKAT] = v9fs_unlinkat,
+    [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 v9fs_op_not_supp(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
+}
+
+static void v9fs_fs_ro(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    complete_pdu(pdu->s, pdu, -EROFS);
+}
+
+static inline bool is_read_only_op(V9fsPDU *pdu)
+{
+    switch (pdu->id) {
+    case P9_TREADDIR:
+    case P9_TSTATFS:
+    case P9_TGETATTR:
+    case P9_TXATTRWALK:
+    case P9_TLOCK:
+    case P9_TGETLOCK:
+    case P9_TREADLINK:
+    case P9_TVERSION:
+    case P9_TLOPEN:
+    case P9_TATTACH:
+    case P9_TSTAT:
+    case P9_TWALK:
+    case P9_TCLUNK:
+    case P9_TFSYNC:
+    case P9_TOPEN:
+    case P9_TREAD:
+    case P9_TAUTH:
+    case P9_TFLUSH:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    Coroutine *co;
+    CoroutineEntry *handler;
+
+    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
+        (pdu_co_handlers[pdu->id] == NULL)) {
+        handler = v9fs_op_not_supp;
+    } else {
+        handler = pdu_co_handlers[pdu->id];
+    }
+
+    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
+        handler = v9fs_fs_ro;
+    }
+    co = qemu_coroutine_create(handler);
+    qemu_coroutine_enter(co, pdu);
+}
+
+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;
+        pdu->s = s;
+        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);
+        qemu_co_queue_init(&pdu->complete);
+        submit_pdu(s, pdu);
+    }
+    free_pdu(s, pdu);
+}
+
+void virtio_9p_set_fd_limit(void)
+{
+    struct rlimit rlim;
+    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+        fprintf(stderr, "Failed to get the resource limit\n");
+        exit(1);
+    }
+    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
+    open_fd_rc = rlim.rlim_cur/2;
+}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
new file mode 100644 (file)
index 0000000..19a797b
--- /dev/null
@@ -0,0 +1,472 @@
+#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 <sys/resource.h>
+#include "hw/virtio.h"
+#include "fsdev/file-op-9p.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.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_TRENAMEAT = 74,
+    P9_RRENAMEAT,
+    P9_TUNLINKAT = 76,
+    P9_RUNLINKAT,
+    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
+
+#define FID_REFERENCED          0x1
+#define FID_NON_RECLAIMABLE     0x2
+static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+{
+    snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
+    return buffer;
+}
+
+/*
+ * 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 V9fsState;
+
+struct V9fsPDU
+{
+    uint32_t size;
+    uint16_t tag;
+    uint8_t id;
+    uint8_t cancelled;
+    CoQueue complete;
+    VirtQueueElement elem;
+    struct V9fsState *s;
+    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
+{
+    uint16_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;
+
+/*
+ * Filled by fs driver on open and other
+ * calls.
+ */
+union V9fsFidOpenState {
+    int fd;
+    DIR *dir;
+    V9fsXattr xattr;
+    /*
+     * private pointer for fs drivers, that
+     * have its own internal representation of
+     * open files.
+     */
+    void *private;
+};
+
+struct V9fsFidState
+{
+    int fid_type;
+    int32_t fid;
+    V9fsPath path;
+    V9fsFidOpenState fs;
+    V9fsFidOpenState fs_reclaim;
+    int flags;
+    int open_flags;
+    uid_t uid;
+    int ref;
+    int clunked;
+    V9fsFidState *next;
+    V9fsFidState *rclm_lst;
+};
+
+typedef struct V9fsState
+{
+    VirtIODevice vdev;
+    VirtQueue *vq;
+    V9fsPDU pdus[MAX_REQ];
+    QLIST_HEAD(, V9fsPDU) free_list;
+    QLIST_HEAD(, V9fsPDU) active_list;
+    V9fsFidState *fid_list;
+    FileOperations *ops;
+    FsContext ctx;
+    char *tag;
+    size_t config_size;
+    enum p9_proto_version proto_version;
+    int32_t msize;
+    /*
+     * lock ensuring atomic path update
+     * on rename.
+     */
+    CoRwlock rename_lock;
+    int32_t root_fid;
+    Error *migration_blocker;
+} V9fsState;
+
+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 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 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;
+
+struct virtio_9p_config
+{
+    /* number of characters in tag */
+    uint16_t tag_len;
+    /* Variable size tag name */
+    uint8_t tag[0];
+} QEMU_PACKED;
+
+typedef struct V9fsMkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsQID qid;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsMkState;
+
+/* 9p2000.L open flags */
+#define P9_DOTL_RDONLY        00000000
+#define P9_DOTL_WRONLY        00000001
+#define P9_DOTL_RDWR          00000002
+#define P9_DOTL_NOACCESS      00000003
+#define P9_DOTL_CREATE        00000100
+#define P9_DOTL_EXCL          00000200
+#define P9_DOTL_NOCTTY        00000400
+#define P9_DOTL_TRUNC         00001000
+#define P9_DOTL_APPEND        00002000
+#define P9_DOTL_NONBLOCK      00004000
+#define P9_DOTL_DSYNC         00010000
+#define P9_DOTL_FASYNC        00020000
+#define P9_DOTL_DIRECT        00040000
+#define P9_DOTL_LARGEFILE     00100000
+#define P9_DOTL_DIRECTORY     00200000
+#define P9_DOTL_NOFOLLOW      00400000
+#define P9_DOTL_NOATIME       01000000
+#define P9_DOTL_CLOEXEC       02000000
+#define P9_DOTL_SYNC          04000000
+
+/* 9p2000.L at flags */
+#define P9_DOTL_AT_REMOVEDIR         0x200
+
+/* 9P2000.L lock type */
+#define P9_LOCK_TYPE_RDLCK 0
+#define P9_LOCK_TYPE_WRLCK 1
+#define P9_LOCK_TYPE_UNLCK 2
+
+#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 V9fsGetlock
+{
+    uint8_t type;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsGetlock;
+
+extern int open_fd_hw;
+extern int total_open_fd;
+
+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);
+}
+
+static inline void v9fs_path_write_lock(V9fsState *s)
+{
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_wrlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_read_lock(V9fsState *s)
+{
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_rdlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_unlock(V9fsState *s)
+{
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_unlock(&s->rename_lock);
+    }
+}
+
+static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
+{
+    return pdu->cancelled;
+}
+
+extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
+extern void virtio_9p_set_fd_limit(void);
+extern void v9fs_reclaim_fd(V9fsPDU *pdu);
+extern void v9fs_string_init(V9fsString *str);
+extern void v9fs_string_free(V9fsString *str);
+extern void v9fs_string_null(V9fsString *str);
+extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
+extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
+extern void v9fs_path_init(V9fsPath *path);
+extern void v9fs_path_free(V9fsPath *path);
+extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
+extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                             const char *name, V9fsPath *path);
+#endif
index b5e53283957f363390c2e503023cb30afd8a2034..6f108f4ce2036ce5ec200b9adfe4b9f2c41ab6bc 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 /* 64 external IRQ lines.  */
index d71072d456c141c8701419e767fc62221d7c53c9..0dbba3b54a5ee2ebbe97ebb1550375f22ecb8240 100644 (file)
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -18,6 +18,7 @@
 #include "audiodev.h"
 #include "audio/audio.h"
 #include "pci.h"
+#include "dma.h"
 
 enum {
     AC97_Reset                     = 0x00,
@@ -149,6 +150,7 @@ typedef struct AC97BusMasterRegs {
 typedef struct AC97LinkState {
     PCIDevice dev;
     QEMUSoundCard card;
+    uint32_t use_broken_id;
     uint32_t glob_cnt;
     uint32_t glob_sta;
     uint32_t cas;
@@ -160,8 +162,9 @@ typedef struct AC97LinkState {
     SWVoiceIn *voice_mc;
     int invalid_freq[3];
     uint8_t silence[128];
-    uint32_t base[2];
     int bup_flag;
+    MemoryRegion io_nam;
+    MemoryRegion io_nabm;
 } AC97LinkState;
 
 enum {
@@ -223,7 +226,7 @@ static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
 {
     uint8_t b[8];
 
-    cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8);
+    pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8);
     r->bd_valid = 1;
     r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
     r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
@@ -583,7 +586,7 @@ static uint32_t nam_readw (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     uint32_t val = ~0U;
-    uint32_t index = addr - s->base[0];
+    uint32_t index = addr;
     s->cas = 0;
     val = mixer_load (s, index);
     return val;
@@ -611,7 +614,7 @@ static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
 static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
-    uint32_t index = addr - s->base[0];
+    uint32_t index = addr;
     s->cas = 0;
     switch (index) {
     case AC97_Reset:
@@ -714,7 +717,7 @@ static uint32_t nabm_readb (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -769,7 +772,7 @@ static uint32_t nabm_readw (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -798,7 +801,7 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -848,7 +851,7 @@ static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_LVI:
     case PO_LVI:
@@ -904,7 +907,7 @@ static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_SR:
     case PO_SR:
@@ -924,7 +927,7 @@ static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_BDBAR:
     case PO_BDBAR:
@@ -972,7 +975,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
     while (temp) {
         int copied;
         to_copy = audio_MIN (temp, sizeof (tmpbuf));
-        cpu_physical_memory_read (addr, tmpbuf, to_copy);
+        pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
         copied = AUD_write (s->voice_po, tmpbuf, to_copy);
         dolog ("write_audio max=%x to_copy=%x copied=%x\n",
                max, to_copy, copied);
@@ -1001,8 +1004,6 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
 
 static void write_bup (AC97LinkState *s, int elapsed)
 {
-    int written = 0;
-
     dolog ("write_bup\n");
     if (!(s->bup_flag & BUP_SET)) {
         if (s->bup_flag & BUP_LAST) {
@@ -1026,7 +1027,6 @@ static void write_bup (AC97LinkState *s, int elapsed)
                 return;
             temp -= copied;
             elapsed -= copied;
-            written += copied;
         }
     }
 }
@@ -1056,7 +1056,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
             *stop = 1;
             break;
         }
-        cpu_physical_memory_write (addr, tmpbuf, acquired);
+        pci_dma_write (&s->dev, addr, tmpbuf, acquired);
         temp -= acquired;
         addr += acquired;
         nread += acquired;
@@ -1069,7 +1069,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
 static void transfer_audio (AC97LinkState *s, int index, int elapsed)
 {
     AC97BusMasterRegs *r = &s->bm_regs[index];
-    int written = 0, stop = 0;
+    int stop = 0;
 
     if (s->invalid_freq[index]) {
         AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
@@ -1114,7 +1114,6 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed)
         switch (index) {
         case PO_INDEX:
             temp = write_audio (s, r, elapsed, &stop);
-            written += temp;
             elapsed -= temp;
             r->picb -= (temp >> 1);
             break;
@@ -1234,31 +1233,33 @@ static const VMStateDescription vmstate_ac97 = {
     }
 };
 
-static void ac97_map (PCIDevice *pci_dev, int region_num,
-                      pcibus_t addr, pcibus_t size, int type)
-{
-    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
-    PCIDevice *d = &s->dev;
-
-    if (!region_num) {
-        s->base[0] = addr;
-        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
-        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
-        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
-        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
-        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
-        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
-    }
-    else {
-        s->base[1] = addr;
-        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
-        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
-        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
-        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
-        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
-        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
-    }
-}
+static const MemoryRegionPortio nam_portio[] = {
+    { 0, 256 * 1, 1, .read = nam_readb, },
+    { 0, 256 * 2, 2, .read = nam_readw, },
+    { 0, 256 * 4, 4, .read = nam_readl, },
+    { 0, 256 * 1, 1, .write = nam_writeb, },
+    { 0, 256 * 2, 2, .write = nam_writew, },
+    { 0, 256 * 4, 4, .write = nam_writel, },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps ac97_io_nam_ops = {
+    .old_portio = nam_portio,
+};
+
+static const MemoryRegionPortio nabm_portio[] = {
+    { 0, 64 * 1, 1, .read = nabm_readb, },
+    { 0, 64 * 2, 2, .read = nabm_readw, },
+    { 0, 64 * 4, 4, .read = nabm_readl, },
+    { 0, 64 * 1, 1, .write = nabm_writeb, },
+    { 0, 64 * 2, 2, .write = nabm_writew, },
+    { 0, 64 * 4, 4, .write = nabm_writel, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps ac97_io_nabm_ops = {
+    .old_portio = nabm_portio,
+};
 
 static void ac97_on_reset (void *opaque)
 {
@@ -1281,9 +1282,6 @@ static int ac97_initfn (PCIDevice *dev)
     AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
     uint8_t *c = s->dev.config;
 
-    pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
-    pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
-
     /* TODO: no need to override */
     c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
     c[PCI_COMMAND + 1] = 0x00;
@@ -1292,9 +1290,7 @@ static int ac97_initfn (PCIDevice *dev)
     c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
 
-    c[PCI_REVISION_ID] = 0x01;      /* rid revision ro */
     c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
-    pci_config_set_class (c, PCI_CLASS_MULTIMEDIA_AUDIO); /* ro */
 
     /* TODO set when bar is registered. no need to override. */
     /* nabmar native audio mixer base address rw */
@@ -1310,25 +1306,35 @@ static int ac97_initfn (PCIDevice *dev)
     c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
     c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
 
-    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;      /* svid subsystem vendor id rwo */
-    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
-
-    c[PCI_SUBSYSTEM_ID] = 0x00;      /* sid subsystem id rwo */
-    c[PCI_SUBSYSTEM_ID + 1] = 0x00;
+    if (s->use_broken_id) {
+        c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;
+        c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
+        c[PCI_SUBSYSTEM_ID] = 0x00;
+        c[PCI_SUBSYSTEM_ID + 1] = 0x00;
+    }
 
     c[PCI_INTERRUPT_LINE] = 0x00;      /* intr_ln interrupt line rw */
-    /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
 
-    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
-                      ac97_map);
-    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
+    memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
+    memory_region_init_io (&s->io_nabm, &ac97_io_nabm_ops, s, "ac97-nabm", 256);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
+    pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm);
     qemu_register_reset (ac97_on_reset, s);
     AUD_register_card ("ac97", &s->card);
     ac97_on_reset (s);
     return 0;
 }
 
+static int ac97_exitfn (PCIDevice *dev)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+
+    memory_region_destroy (&s->io_nam);
+    memory_region_destroy (&s->io_nabm);
+    return 0;
+}
+
 int ac97_init (PCIBus *bus)
 {
     pci_create_simple (bus, -1, "AC97");
@@ -1341,6 +1347,15 @@ static PCIDeviceInfo ac97_info = {
     .qdev.size    = sizeof (AC97LinkState),
     .qdev.vmsd    = &vmstate_ac97,
     .init         = ac97_initfn,
+    .exit         = ac97_exitfn,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_82801AA_5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
 };
 
 static void ac97_register (void)
index 8071e7bebaf67cb312fe05b88231f8e9a02f97b3..1cf35e116abacccc0082ead37b307e8240618a0c 100644 (file)
--- a/hw/acpi.c
+++ b/hw/acpi.c
  * 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"
 
-struct acpi_table_header
-{
-    char signature [4];    /* ACPI signature (4 ASCII characters) */
+struct acpi_table_header {
+    uint16_t _length;         /* our length, not actual part of the hdr */
+                              /* XXX why we have 2 length fields here? */
+    char sig[4];              /* ACPI signature (4 ASCII characters) */
     uint32_t length;          /* Length of table, in bytes, including header */
     uint8_t revision;         /* ACPI Specification minor version # */
     uint8_t checksum;         /* To make sum of entire table == 0 */
-    char oem_id [6];       /* OEM identification */
-    char oem_table_id [8]; /* OEM table identification */
+    char oem_id[6];           /* OEM identification */
+    char oem_table_id[8];     /* OEM table identification */
     uint32_t oem_revision;    /* OEM revision number */
-    char asl_compiler_id [4]; /* ASL compiler vendor ID */
+    char asl_compiler_id[4];  /* ASL compiler vendor ID */
     uint32_t asl_compiler_revision; /* ASL compiler revision number */
-} __attribute__((packed));
+} QEMU_PACKED;
+
+#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
+#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t)  /* size of the extra prefix */
+
+static const char dfl_hdr[ACPI_TABLE_HDR_SIZE] =
+    "\0\0"                   /* fake _length (2) */
+    "QEMU\0\0\0\0\1\0"       /* sig (4), len(4), revno (1), csum (1) */
+    "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
+    "QEMU\1\0\0\0"           /* ASL compiler ID (4), version (4) */
+    ;
 
 char *acpi_tables;
 size_t acpi_tables_len;
@@ -39,161 +51,392 @@ static int acpi_checksum(const uint8_t *data, int len)
 {
     int sum, i;
     sum = 0;
-    for(i = 0; i < len; i++)
+    for (i = 0; i < len; i++) {
         sum += data[i];
+    }
     return (-sum) & 0xff;
 }
 
+/* like strncpy() but zero-fills the tail of destination */
+static void strzcpy(char *dst, const char *src, size_t size)
+{
+    size_t len = strlen(src);
+    if (len >= size) {
+        len = size;
+    } else {
+      memset(dst + len, 0, size - len);
+    }
+    memcpy(dst, src, len);
+}
+
+/* XXX fixme: this function uses obsolete argument parsing interface */
 int acpi_table_add(const char *t)
 {
-    static const char *dfl_id = "QEMUQEMU";
     char buf[1024], *p, *f;
-    struct acpi_table_header acpi_hdr;
     unsigned long val;
-    uint32_t length;
-    struct acpi_table_header *acpi_hdr_p;
-    size_t off;
+    size_t len, start, allen;
+    bool has_header;
+    int changed;
+    int r;
+    struct acpi_table_header hdr;
 
-    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
-  
-    if (get_param_value(buf, sizeof(buf), "sig", t)) {
-        strncpy(acpi_hdr.signature, buf, 4);
+    r = 0;
+    r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
+    r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
+    switch (r) {
+    case 0:
+        buf[0] = '\0';
+        /* fallthrough for default behavior */
+    case 1:
+        has_header = false;
+        break;
+    case 2:
+        has_header = true;
+        break;
+    default:
+        fprintf(stderr, "acpitable: both data and file are specified\n");
+        return -1;
+    }
+
+    if (!acpi_tables) {
+        allen = sizeof(uint16_t);
+        acpi_tables = g_malloc0(allen);
     } else {
-        strncpy(acpi_hdr.signature, dfl_id, 4);
+        allen = acpi_tables_len;
+    }
+
+    start = allen;
+    acpi_tables = g_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE);
+    allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE;
+
+    /* now read in the data files, reallocating buffer as needed */
+
+    for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
+        int fd = open(f, O_RDONLY);
+
+        if (fd < 0) {
+            fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno));
+            return -1;
+        }
+
+        for (;;) {
+            char data[8192];
+            r = read(fd, data, sizeof(data));
+            if (r == 0) {
+                break;
+            } else if (r > 0) {
+                acpi_tables = g_realloc(acpi_tables, allen + r);
+                memcpy(acpi_tables + allen, data, r);
+                allen += r;
+            } else if (errno != EINTR) {
+                fprintf(stderr, "can't read file %s: %s\n",
+                        f, strerror(errno));
+                close(fd);
+                return -1;
+            }
+        }
+
+        close(fd);
+    }
+
+    /* now fill in the header fields */
+
+    f = acpi_tables + start;   /* start of the table */
+    changed = 0;
+
+    /* copy the header to temp place to align the fields */
+    memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE);
+
+    /* length of the table minus our prefix */
+    len = allen - start - ACPI_TABLE_PFX_SIZE;
+
+    hdr._length = cpu_to_le16(len);
+
+    if (get_param_value(buf, sizeof(buf), "sig", t)) {
+        strzcpy(hdr.sig, buf, sizeof(hdr.sig));
+        ++changed;
+    }
+
+    /* length of the table including header, in bytes */
+    if (has_header) {
+        /* check if actual length is correct */
+        val = le32_to_cpu(hdr.length);
+        if (val != len) {
+            fprintf(stderr,
+                "warning: acpitable has wrong length,"
+                " header says %lu, actual size %zu bytes\n",
+                val, len);
+            ++changed;
+        }
     }
+    /* we may avoid putting length here if has_header is true */
+    hdr.length = cpu_to_le32(len);
+
     if (get_param_value(buf, sizeof(buf), "rev", t)) {
-        val = strtoul(buf, &p, 10);
-        if (val > 255 || *p != '\0')
-            goto out;
-    } else {
-        val = 1;
+        val = strtoul(buf, &p, 0);
+        if (val > 255 || *p) {
+            fprintf(stderr, "acpitable: \"rev=%s\" is invalid\n", buf);
+            return -1;
+        }
+        hdr.revision = (uint8_t)val;
+        ++changed;
     }
-    acpi_hdr.revision = (int8_t)val;
 
     if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
-        strncpy(acpi_hdr.oem_id, buf, 6);
-    } else {
-        strncpy(acpi_hdr.oem_id, dfl_id, 6);
+        strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
+        ++changed;
     }
 
     if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
-        strncpy(acpi_hdr.oem_table_id, buf, 8);
-    } else {
-        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
+        strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
+        ++changed;
     }
 
     if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
-        val = strtol(buf, &p, 10);
-        if(*p != '\0')
-            goto out;
-    } else {
-        val = 1;
+        val = strtol(buf, &p, 0);
+        if (*p) {
+            fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf);
+            return -1;
+        }
+        hdr.oem_revision = cpu_to_le32(val);
+        ++changed;
     }
-    acpi_hdr.oem_revision = cpu_to_le32(val);
 
     if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
-        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
-    } else {
-        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
+        strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
+        ++changed;
     }
 
     if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
-        val = strtol(buf, &p, 10);
-        if(*p != '\0')
-            goto out;
-    } else {
-        val = 1;
+        val = strtol(buf, &p, 0);
+        if (*p) {
+            fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n",
+                    "asl_compiler_rev", buf);
+            return -1;
+        }
+        hdr.asl_compiler_revision = cpu_to_le32(val);
+        ++changed;
     }
-    acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
-    
-    if (!get_param_value(buf, sizeof(buf), "data", t)) {
-         buf[0] = '\0';
+
+    if (!has_header && !changed) {
+        fprintf(stderr, "warning: acpitable: no table headers are specified\n");
     }
 
-    length = sizeof(acpi_hdr);
 
-    f = buf;
-    while (buf[0]) {
-        struct stat s;
-        char *n = strchr(f, ':');
-        if (n)
-            *n = '\0';
-        if(stat(f, &s) < 0) {
-            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
-            goto out;
-        }
-        length += s.st_size;
-        if (!n)
-            break;
-        *n = ':';
-        f = n + 1;
+    /* now calculate checksum of the table, complete with the header */
+    /* we may as well leave checksum intact if has_header is true */
+    /* alternatively there may be a way to set cksum to a given value */
+    hdr.checksum = 0;    /* for checksum calculation */
+
+    /* put header back */
+    memcpy(f, &hdr, sizeof(hdr));
+
+    if (changed || !has_header || 1) {
+        ((struct acpi_table_header *)f)->checksum =
+            acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len);
     }
 
-    if (!acpi_tables) {
-        acpi_tables_len = sizeof(uint16_t);
-        acpi_tables = qemu_mallocz(acpi_tables_len);
-    }
-    acpi_tables = qemu_realloc(acpi_tables,
-                               acpi_tables_len + sizeof(uint16_t) + length);
-    p = acpi_tables + acpi_tables_len;
-    acpi_tables_len += sizeof(uint16_t) + length;
-
-    *(uint16_t*)p = cpu_to_le32(length);
-    p += sizeof(uint16_t);
-    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
-    off = sizeof(acpi_hdr);
-
-    f = buf;
-    while (buf[0]) {
-        struct stat s;
-        int fd;
-        char *n = strchr(f, ':');
-        if (n)
-            *n = '\0';
-        fd = open(f, O_RDONLY);
-
-        if(fd < 0)
-            goto out;
-        if(fstat(fd, &s) < 0) {
-            close(fd);
-            goto out;
-        }
+    /* increase number of tables */
+    (*(uint16_t *)acpi_tables) =
+        cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
 
-        /* off < length is necessary because file size can be changed
-           under our foot */
-        while(s.st_size && off < length) {
-            int r;
-            r = read(fd, p + off, s.st_size);
-            if (r > 0) {
-                off += r;
-                s.st_size -= r;
-            } else if ((r < 0 && errno != EINTR) || r == 0) {
-                close(fd);
-                goto out;
-            }
-        }
+    acpi_tables_len = allen;
+    return 0;
 
-        close(fd);
-        if (!n)
+}
+
+/* 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;
-        f = n + 1;
+        }
     }
-    if (off < length) {
-        /* don't pass random value in process to guest */
-        memset(p + off, 0, length - off);
+}
+
+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;
     }
+}
 
-    acpi_hdr_p = (struct acpi_table_header*)p;
-    acpi_hdr_p->length = cpu_to_le32(length);
-    acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
-    /* increase number of tables */
-    (*(uint16_t*)acpi_tables) =
-           cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
-    return 0;
-out:
-    if (acpi_tables) {
-        qemu_free(acpi_tables);
-        acpi_tables = NULL;
+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 = g_malloc0(len / 2);
+    gpe->en = g_malloc0(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 -1;
+
+    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 5bbc2b5a26677b4552b42bc6ab14ffd5d4ed26f9..d9075e661188639aad866f4e8c886c289f3373ad 100644 (file)
@@ -23,6 +23,7 @@
 #include "acpi.h"
 #include "sysemu.h"
 #include "range.h"
+#include "ioport.h"
 
 //#define DEBUG
 
 #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 +51,23 @@ 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;
+    Notifier machine_ready;
 
     /* for pci hotplug */
-    struct gpe_regs gpe;
+    ACPIGPE gpe;
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
 } PIIX4PMState;
@@ -82,52 +77,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(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(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 +113,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(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 +138,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 +167,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 +212,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 +255,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()
@@ -332,7 +276,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
 
     s->pci0_hotplug_enable = ~0;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
         PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
         int slot = PCI_SLOT(pdev->devfn);
@@ -363,13 +307,23 @@ 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;
+
+    acpi_pm1_evt_power_down(pm1a, tmr);
+}
+
+static void piix4_pm_machine_ready(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+    pci_conf[0x63] = 0x60;
+    pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
+       (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
 
-    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);
-    }
 }
 
 static int piix4_pm_initfn(PCIDevice *dev)
@@ -378,13 +332,9 @@ static int piix4_pm_initfn(PCIDevice *dev)
     uint8_t *pci_conf;
 
     pci_conf = s->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_3);
     pci_conf[0x06] = 0x80;
     pci_conf[0x07] = 0x02;
-    pci_conf[0x08] = 0x03; // revision number
     pci_conf[0x09] = 0x00;
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
     pci_conf[0x3d] = 0x01; // interrupt pin 1
 
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
@@ -402,22 +352,20 @@ static int piix4_pm_initfn(PCIDevice *dev)
 
     /* XXX: which specification is used ? The i82731AB has different
        mappings */
-    pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
-    pci_conf[0x63] = 0x60;
-    pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
-       (serial_hds[1] != NULL ? 0x90 : 0);
-
     pci_conf[0x90] = s->smb_io_base | 1;
     pci_conf[0x91] = s->smb_io_base >> 8;
     pci_conf[0xd2] = 0x09;
     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(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);
 
     pm_smbus_init(&s->dev.qdev, &s->smb);
+    s->machine_ready.notify = piix4_pm_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
     qemu_register_reset(piix4_reset, s);
     piix4_acpi_system_hot_add_init(dev->bus, s);
 
@@ -436,7 +384,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;
 
@@ -454,6 +402,10 @@ static PCIDeviceInfo piix4_pm_info = {
     .no_hotplug         = 1,
     .init               = piix4_pm_initfn,
     .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_INTEL,
+    .device_id          = PCI_DEVICE_ID_INTEL_82371AB_3,
+    .revision           = 0x03,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
     .qdev.props         = (Property[]) {
         DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
         DEFINE_PROP_END_OF_LIST(),
@@ -467,74 +419,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);
@@ -585,11 +483,13 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
     BusState *bus = opaque;
     DeviceState *qdev, *next;
     PCIDevice *dev;
+    PCIDeviceInfo *info;
     int slot = ffs(val) - 1;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         dev = DO_UPCAST(PCIDevice, qdev, qdev);
-        if (PCI_SLOT(dev->devfn) == slot) {
+        info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
             qdev_free(qdev);
         }
     }
@@ -617,8 +517,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 +535,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..aa15f55dc9a5d58d69d259bf880cf38788be3ef6 100644 (file)
--- a/hw/adb.c
+++ b/hw/adb.c
@@ -22,7 +22,7 @@
  * THE SOFTWARE.
  */
 #include "hw.h"
-#include "ppc_mac.h"
+#include "adb.h"
 #include "console.h"
 
 /* debug ADB */
@@ -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)
 {
@@ -301,12 +290,11 @@ void adb_kbd_init(ADBBusState *bus)
 {
     ADBDevice *d;
     KBDState *s;
-    s = qemu_mallocz(sizeof(KBDState));
+    s = g_malloc0(sizeof(KBDState));
     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,42 +427,29 @@ 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)
 {
     ADBDevice *d;
     MouseState *s;
 
-    s = qemu_mallocz(sizeof(MouseState));
+    s = g_malloc0(sizeof(MouseState));
     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);
 }
diff --git a/hw/adb.h b/hw/adb.h
new file mode 100644 (file)
index 0000000..b2a591c
--- /dev/null
+++ b/hw/adb.h
@@ -0,0 +1,67 @@
+/*
+ * QEMU ADB emulation shared definitions and prototypes
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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(__ADB_H__)
+#define __ADB_H__
+
+#define MAX_ADB_DEVICES 16
+
+#define ADB_MAX_OUT_LEN 16
+
+typedef struct ADBDevice ADBDevice;
+
+/* buf = NULL means polling */
+typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
+                              const uint8_t *buf, int len);
+typedef int ADBDeviceReset(ADBDevice *d);
+
+struct ADBDevice {
+    struct ADBBusState *bus;
+    int devaddr;
+    int handler;
+    ADBDeviceRequest *devreq;
+    ADBDeviceReset *devreset;
+    void *opaque;
+};
+
+typedef struct ADBBusState {
+    ADBDevice devices[MAX_ADB_DEVICES];
+    int nb_devices;
+    int poll_index;
+} ADBBusState;
+
+int adb_request(ADBBusState *s, uint8_t *buf_out,
+                const uint8_t *buf, int len);
+int adb_poll(ADBBusState *s, uint8_t *buf_out);
+
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
+                               void *opaque);
+void adb_kbd_init(ADBBusState *bus);
+void adb_mouse_init(ADBBusState *bus);
+
+extern ADBBusState adb_bus;
+#endif /* !defined(__ADB_H__) */
index 1d8092baca729615debf6c44510e19e084cceec5..e4bfcc6420045d61ac79c5129b4784268310f431 100644 (file)
@@ -119,7 +119,6 @@ static IO_WRITE_PROTO (adlib_write)
 {
     AdlibState *s = opaque;
     int a = nport & 3;
-    int status;
 
     s->active = 1;
     AUD_set_active_out (s->voice, 1);
@@ -127,9 +126,9 @@ static IO_WRITE_PROTO (adlib_write)
     adlib_kill_timers (s);
 
 #ifdef HAS_YMF262
-    status = YMF262Write (0, a, val);
+    YMF262Write (0, a, val);
 #else
-    status = OPLWrite (s->opl, a, val);
+    OPLWrite (s->opl, a, val);
 #endif
 }
 
@@ -166,7 +165,7 @@ static void timer_handler (int c, double interval_Sec)
     s->ticking[n] = 1;
 #ifdef DEBUG
     interval = get_ticks_per_sec() * interval_Sec;
-    exp = qemu_get_clock (vm_clock) + interval;
+    exp = qemu_get_clock_ns (vm_clock) + interval;
     s->exp[n] = exp;
 #endif
 
@@ -268,7 +267,7 @@ static void Adlib_fini (AdlibState *s)
 #endif
 
     if (s->mixbuf) {
-        qemu_free (s->mixbuf);
+        g_free (s->mixbuf);
     }
 
     s->active = 0;
@@ -323,7 +322,7 @@ int Adlib_init (qemu_irq *pic)
     }
 
     s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
-    s->mixbuf = qemu_mallocz (s->samples << SHIFT);
+    s->mixbuf = g_malloc0 (s->samples << SHIFT);
 
     register_ioport_read (0x388, 4, 1, adlib_read, s);
     register_ioport_write (0x388, 4, 1, adlib_write, 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;
 }
 
diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
new file mode 100644 (file)
index 0000000..fcc20e9
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * QEMU Alpha DP264/CLIPPER hardware system emulator.
+ *
+ * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
+ * variants because CLIPPER doesn't have an SMC669 SuperIO controler
+ * that we need to emulate as well.
+ */
+
+#include "hw.h"
+#include "elf.h"
+#include "loader.h"
+#include "boards.h"
+#include "alpha_sys.h"
+#include "sysemu.h"
+#include "mc146818rtc.h"
+#include "ide.h"
+
+#define MAX_IDE_BUS 2
+
+static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
+{
+    if (((addr >> 41) & 3) == 2) {
+        addr &= 0xffffffffffull;
+    }
+    return addr;
+}
+
+/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
+    (0) The dev_irq_n lines into the cpu, which we totally ignore,
+    (1) The DRIR lines in the typhoon chipset,
+    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
+    (3) The interrupt number assigned by the kernel.
+   The following function is concerned with (1) only.  */
+
+static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    int slot = d->devfn >> 3;
+
+    assert(irq_num >= 0 && irq_num <= 3);
+
+    return (slot + 1) * 4 + irq_num;
+}
+
+static void clipper_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 *cpus[4];
+    PCIBus *pci_bus;
+    qemu_irq rtc_irq;
+    long size, i;
+    const char *palcode_filename;
+    uint64_t palcode_entry, palcode_low, palcode_high;
+    uint64_t kernel_entry, kernel_low, kernel_high;
+
+    /* Create up to 4 cpus.  */
+    memset(cpus, 0, sizeof(cpus));
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i] = cpu_init(cpu_model ? cpu_model : "ev67");
+    }
+
+    cpus[0]->trap_arg0 = ram_size;
+    cpus[0]->trap_arg1 = 0;
+    cpus[0]->trap_arg2 = smp_cpus;
+
+    /* Init the chipset.  */
+    pci_bus = typhoon_init(ram_size, &rtc_irq, cpus, clipper_pci_map_irq);
+
+    rtc_init(1980, rtc_irq);
+    pit_init(0x40, 0);
+    isa_create_simple("i8042");
+
+    /* VGA setup.  Don't bother loading the bios.  */
+    alpha_pci_vga_setup(pci_bus);
+
+    /* Serial code setup.  */
+    for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    /* Network setup.  e1000 is good enough, failing Tulip support.  */
+    for (i = 0; i < nb_nics; i++) {
+        pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
+    }
+
+    /* IDE disk setup.  */
+    {
+        DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+        ide_drive_get(hd, MAX_IDE_BUS);
+
+        pci_cmd646_ide_init(pci_bus, hd, 0);
+    }
+
+    /* Load PALcode.  Given that this is not "real" cpu palcode,
+       but one explicitly written for the emulation, we might as
+       well load it directly from and ELF image.  */
+    palcode_filename = (bios_name ? bios_name : "palcode-clipper");
+    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+    if (palcode_filename == NULL) {
+        hw_error("no palcode provided\n");
+        exit(1);
+    }
+    size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
+                    NULL, &palcode_entry, &palcode_low, &palcode_high,
+                    0, EM_ALPHA, 0);
+    if (size < 0) {
+        hw_error("could not load palcode '%s'\n", palcode_filename);
+        exit(1);
+    }
+
+    /* Start all cpus at the PALcode RESET entry point.  */
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i]->pal_mode = 1;
+        cpus[i]->pc = palcode_entry;
+        cpus[i]->palbr = palcode_entry;
+    }
+
+    /* Load a kernel.  */
+    if (kernel_filename) {
+        uint64_t param_offset;
+
+        size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
+                        NULL, &kernel_entry, &kernel_low, &kernel_high,
+                        0, EM_ALPHA, 0);
+        if (size < 0) {
+            hw_error("could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+
+        cpus[0]->trap_arg1 = kernel_entry;
+
+        param_offset = kernel_low - 0x6000;
+
+        if (kernel_cmdline) {
+            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
+        }
+
+        if (initrd_filename) {
+            long initrd_base, initrd_size;
+
+            initrd_size = get_image_size(initrd_filename);
+            if (initrd_size < 0) {
+                hw_error("could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+
+            /* Put the initrd image as high in memory as possible.  */
+            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+            load_image_targphys(initrd_filename, initrd_base,
+                                ram_size - initrd_base);
+
+            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
+            stq_phys(param_offset + 0x108, initrd_size);
+        }
+    }
+}
+
+static QEMUMachine clipper_machine = {
+    .name = "clipper",
+    .desc = "Alpha DP264/CLIPPER",
+    .init = clipper_init,
+    .max_cpus = 4,
+    .is_default = 1,
+};
+
+static void clipper_machine_init(void)
+{
+    qemu_register_machine(&clipper_machine);
+}
+
+machine_init(clipper_machine_init);
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
new file mode 100644 (file)
index 0000000..e975702
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * QEMU Alpha PCI support functions.
+ *
+ * Some of this isn't very Alpha specific at all.
+ *
+ * ??? Sparse memory access not implemented.
+ */
+
+#include "config.h"
+#include "alpha_sys.h"
+#include "qemu-log.h"
+#include "sysemu.h"
+#include "vmware_vga.h"
+
+
+/* PCI IO reads/writes, to byte-word addressable memory.  */
+/* ??? Doesn't handle multiple PCI busses.  */
+
+static uint64_t bw_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    abort();
+}
+
+static void bw_io_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, val);
+        break;
+    case 2:
+        cpu_outw(addr, val);
+        break;
+    case 4:
+        cpu_outl(addr, val);
+        break;
+    default:
+        abort();
+    }
+}
+
+const MemoryRegionOps alpha_pci_bw_io_ops = {
+    .read = bw_io_read,
+    .write = bw_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI config space reads/writes, to byte-word addressable memory.  */
+static uint64_t bw_conf1_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    PCIBus *b = opaque;
+    return pci_data_read(b, addr, size);
+}
+
+static void bw_conf1_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    PCIBus *b = opaque;
+    pci_data_write(b, addr, val, size);
+}
+
+const MemoryRegionOps alpha_pci_conf1_ops = {
+    .read = bw_conf1_read,
+    .write = bw_conf1_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle.  */
+
+static uint64_t iack_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    return pic_read_irq(isa_pic);
+}
+
+static void special_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t val, unsigned size)
+{
+    qemu_log("pci: special write cycle");
+}
+
+const MemoryRegionOps alpha_pci_iack_ops = {
+    .read = iack_read,
+    .write = special_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+\f
+void alpha_pci_vga_setup(PCIBus *pci_bus)
+{
+    switch (vga_interface_type) {
+#ifdef CONFIG_SPICE
+    case VGA_QXL:
+        pci_create_simple(pci_bus, -1, "qxl-vga");
+        return;
+#endif
+    case VGA_CIRRUS:
+        pci_cirrus_vga_init(pci_bus);
+        return;
+    case VGA_VMWARE:
+        if (pci_vmsvga_init(pci_bus)) {
+            return;
+        }
+        break;
+    }
+    /* If VGA is enabled at all, and one of the above didn't work, then
+       fallback to Standard VGA.  */
+    if (vga_interface_type != VGA_NONE) {
+        pci_vga_init(pci_bus);
+    }
+}
diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h
new file mode 100644 (file)
index 0000000..13f0177
--- /dev/null
@@ -0,0 +1,24 @@
+/* Alpha cores and system support chips.  */
+
+#ifndef HW_ALPHA_H
+#define HW_ALPHA_H 1
+
+#include "pci.h"
+#include "pci_host.h"
+#include "ide.h"
+#include "net.h"
+#include "pc.h"
+#include "usb-ohci.h"
+#include "irq.h"
+
+
+PCIBus *typhoon_init(ram_addr_t, qemu_irq *, CPUState *[4], pci_map_irq_fn);
+
+/* alpha_pci.c.  */
+extern const MemoryRegionOps alpha_pci_bw_io_ops;
+extern const MemoryRegionOps alpha_pci_conf1_ops;
+extern const MemoryRegionOps alpha_pci_iack_ops;
+
+void alpha_pci_vga_setup(PCIBus *pci_bus);
+
+#endif
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
new file mode 100644 (file)
index 0000000..c7608bb
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
+ *
+ * Written by Richard Henderson.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "hw.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "alpha_sys.h"
+#include "exec-memory.h"
+
+
+typedef struct TyphoonCchip {
+    MemoryRegion region;
+    uint64_t misc;
+    uint64_t drir;
+    uint64_t dim[4];
+    uint32_t iic[4];
+    CPUState *cpu[4];
+} TyphoonCchip;
+
+typedef struct TyphoonWindow {
+    uint32_t base_addr;
+    uint32_t mask;
+    uint32_t translated_base_pfn;
+} TyphoonWindow;
+typedef struct TyphoonPchip {
+    MemoryRegion region;
+    MemoryRegion reg_iack;
+    MemoryRegion reg_mem;
+    MemoryRegion reg_io;
+    MemoryRegion reg_conf;
+    uint64_t ctl;
+    TyphoonWindow win[4];
+} TyphoonPchip;
+
+typedef struct TyphoonState {
+    PCIHostState host;
+    TyphoonCchip cchip;
+    TyphoonPchip pchip;
+    MemoryRegion dchip_region;
+    MemoryRegion ram_region;
+
+    /* QEMU emulation state.  */
+    uint32_t latch_tmp;
+} TyphoonState;
+
+/* Called when one of DRIR or DIM changes.  */
+static void cpu_irq_change(CPUState *env, uint64_t req)
+{
+    /* If there are any non-masked interrupts, tell the cpu.  */
+    if (env) {
+        if (req) {
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+static uint64_t cchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    CPUState *env = cpu_single_env;
+    TyphoonState *s = opaque;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; probably the only thing relevant is
+           PIP<14> Pchip 1 Present = 0.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        ret = s->cchip.misc | (env->cpu_index & 3);
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200:
+        /* DIM0: Device Interrupt Mask Register, CPU0.  */
+        ret = s->cchip.dim[0];
+        break;
+    case 0x0240:
+        /* DIM1: Device Interrupt Mask Register, CPU1.  */
+        ret = s->cchip.dim[1];
+        break;
+    case 0x0280:
+        /* DIR0: Device Interrupt Request Register, CPU0.  */
+        ret = s->cchip.dim[0] & s->cchip.drir;
+        break;
+    case 0x02c0:
+        /* DIR1: Device Interrupt Request Register, CPU1.  */
+        ret = s->cchip.dim[1] & s->cchip.drir;
+        break;
+    case 0x0300:
+        /* DRIR: Device Raw Interrupt Request Register.  */
+        ret = s->cchip.drir;
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380:
+        /* IIC0: Interval Ignore Count Register, CPU0.  */
+        ret = s->cchip.iic[0];
+        break;
+    case 0x03c0:
+        /* IIC1: Interval Ignore Count Register, CPU1.  */
+        ret = s->cchip.iic[1];
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        ret = s->cchip.dim[2];
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        ret = s->cchip.dim[3];
+        break;
+    case 0x0680:
+        /* DIR2: Device Interrupt Request Register, CPU2.  */
+        ret = s->cchip.dim[2] & s->cchip.drir;
+        break;
+    case 0x06c0:
+        /* DIR3: Device Interrupt Request Register, CPU3.  */
+        ret = s->cchip.dim[3] & s->cchip.drir;
+        break;
+
+    case 0x0700:
+        /* IIC2: Interval Ignore Count Register, CPU2.  */
+        ret = s->cchip.iic[2];
+        break;
+    case 0x0740:
+        /* IIC3: Interval Ignore Count Register, CPU3.  */
+        ret = s->cchip.iic[3];
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static uint64_t dchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+    return 0;
+}
+
+static uint64_t pchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        ret = s->pchip.win[0].base_addr;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        ret = s->pchip.win[1].base_addr;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        ret = s->pchip.win[2].base_addr;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        ret = s->pchip.win[3].base_addr;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        ret = s->pchip.win[0].mask;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        ret = s->pchip.win[1].mask;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        ret = s->pchip.win[2].mask;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        ret = s->pchip.win[3].mask;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        ret = s->pchip.ctl;
+        break;
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
+        break;
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+    case 0x0500: /* PMONCTL */
+    case 0x0540: /* PMONCNT */
+    case 0x0800: /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static void cchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval, newval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; nothing relevant RW.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        newval = oldval = s->cchip.misc;
+        newval &= ~(val & 0x10000ff0);     /* W1C fields */
+        if (val & 0x100000) {
+            newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
+        } else {
+            newval |= val & 0x00f00000;    /* ABT field is W1S */
+            if ((newval & 0xf0000) == 0) {
+                newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
+            }
+        }
+        newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
+
+        newval &= ~0xf0000000000ull;       /* WO and RW fields */
+        newval |= val & 0xf0000000000ull;
+        s->cchip.misc = newval;
+
+        /* Pass on changes to IPI and ITI state.  */
+        if ((newval ^ oldval) & 0xff0) {
+            int i;
+            for (i = 0; i < 4; ++i) {
+                CPUState *env = s->cchip.cpu[i];
+                if (env) {
+                    /* IPI can be either cleared or set by the write.  */
+                    if (newval & (1 << (i + 8))) {
+                        cpu_interrupt(env, CPU_INTERRUPT_SMP);
+                    } else {
+                        cpu_reset_interrupt(env, CPU_INTERRUPT_SMP);
+                    }
+
+                    /* ITI can only be cleared by the write.  */
+                    if ((newval & (1 << (i + 4))) == 0) {
+                        cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER);
+                    }
+                }
+            }
+        }
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200: /* DIM0 */
+        /* DIM: Device Interrupt Mask Register, CPU0.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
+        break;
+    case 0x0240: /* DIM1 */
+        /* DIM: Device Interrupt Mask Register, CPU1.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
+        break;
+
+    case 0x0280: /* DIR0 (RO) */
+    case 0x02c0: /* DIR1 (RO) */
+    case 0x0300: /* DRIR (RO) */
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380: /* IIC0 */
+        s->cchip.iic[0] = val & 0xffffff;
+        break;
+    case 0x03c0: /* IIC1 */
+        s->cchip.iic[1] = val & 0xffffff;
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        s->cchip.dim[2] = val;
+        cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        s->cchip.dim[3] = val;
+        cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
+        break;
+
+    case 0x0680: /* DIR2 (RO) */
+    case 0x06c0: /* DIR3 (RO) */
+        break;
+
+    case 0x0700: /* IIC2 */
+        s->cchip.iic[2] = val & 0xffffff;
+        break;
+    case 0x0740: /* IIC3 */
+        s->cchip.iic[3] = val & 0xffffff;
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static void dchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+}
+
+static void pchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        s->pchip.win[0].base_addr = val;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        s->pchip.win[1].base_addr = val;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        s->pchip.win[2].base_addr = val;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        s->pchip.win[3].base_addr = val;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        s->pchip.win[0].mask = val;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        s->pchip.win[1].mask = val;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        s->pchip.win[2].mask = val;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        s->pchip.win[3].mask = val;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        s->pchip.win[0].translated_base_pfn = val >> 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        s->pchip.win[1].translated_base_pfn = val >> 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        s->pchip.win[2].translated_base_pfn = val >> 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        s->pchip.win[3].translated_base_pfn = val >> 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        oldval = s->pchip.ctl;
+        oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
+        oldval |= val & 0x00001cff0fc7ffull;
+
+        s->pchip.ctl = oldval;
+        break;
+
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
+        break;
+
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+
+    case 0x0500:
+        /* PMONCTL */
+    case 0x0540:
+        /* PMONCNT */
+    case 0x0800:
+        /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static const MemoryRegionOps cchip_ops = {
+    .read = cchip_read,
+    .write = cchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps dchip_ops = {
+    .read = dchip_read,
+    .write = dchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static const MemoryRegionOps pchip_ops = {
+    .read = pchip_read,
+    .write = pchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void typhoon_set_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    uint64_t drir;
+    int i;
+
+    /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
+    drir = s->cchip.drir;
+    if (level) {
+        drir |= 1ull << irq;
+    } else {
+        drir &= ~(1ull << irq);
+    }
+    s->cchip.drir = drir;
+
+    for (i = 0; i < 4; ++i) {
+        cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
+    }
+}
+
+static void typhoon_set_isa_irq(void *opaque, int irq, int level)
+{
+    typhoon_set_irq(opaque, 55, level);
+}
+
+static void typhoon_set_timer_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    int i;
+
+    /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
+       and so we don't have to worry about missing interrupts just
+       because we never actually ACK the interrupt.  Just ignore any
+       case of the interrupt level going low.  */
+    if (level == 0) {
+        return;
+    }
+
+    /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
+    for (i = 0; i < 4; ++i) {
+        CPUState *env = s->cchip.cpu[i];
+        if (env) {
+            uint32_t iic = s->cchip.iic[i];
+
+            /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
+               Bit 24 is the OverFlow bit, RO, and set when the count
+               decrements past 0.  When is OF cleared?  My guess is that
+               OF is actually cleared when the IIC is written, and that
+               the ICNT field always decrements.  At least, that's an
+               interpretation that makes sense, and "allows the CPU to
+               determine exactly how mant interval timer ticks were
+               skipped".  At least within the next 4M ticks...  */
+
+            iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
+            s->cchip.iic[i] = iic;
+
+            if (iic & 0x1000000) {
+                /* Set the ITI bit for this cpu.  */
+                s->cchip.misc |= 1 << (i + 4);
+                /* And signal the interrupt.  */
+                cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+            }
+        }
+    }
+}
+
+static void typhoon_alarm_timer(void *opaque)
+{
+    TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
+    int cpu = (uintptr_t)opaque & 3;
+
+    /* Set the ITI bit for this cpu.  */
+    s->cchip.misc |= 1 << (cpu + 4);
+    cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER);
+}
+
+PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
+                     CPUState *cpus[4], pci_map_irq_fn sys_map_irq)
+{
+    const uint64_t MB = 1024 * 1024;
+    const uint64_t GB = 1024 * MB;
+    MemoryRegion *addr_space = get_system_memory();
+    MemoryRegion *addr_space_io = get_system_io();
+    DeviceState *dev;
+    PCIHostState *p;
+    TyphoonState *s;
+    PCIBus *b;
+    int i;
+
+    dev = qdev_create(NULL, "typhoon-pcihost");
+    qdev_init_nofail(dev);
+
+    p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = container_of(p, TyphoonState, host);
+
+    /* Remember the CPUs so that we can deliver interrupts to them.  */
+    for (i = 0; i < 4; i++) {
+        CPUState *env = cpus[i];
+        s->cchip.cpu[i] = env;
+        if (env) {
+            env->alarm_timer = qemu_new_timer_ns(rtc_clock,
+                                                 typhoon_alarm_timer,
+                                                 (void *)((uintptr_t)s + i));
+        }
+    }
+
+    *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
+
+    /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
+       but the address space hole reserved at this point is 8TB.  */
+    memory_region_init_ram(&s->ram_region, NULL, "ram", ram_size);
+    memory_region_add_subregion(addr_space, 0, &s->ram_region);
+
+    /* TIGbus, 0x801.0000.0000, 1GB.  */
+    /* ??? The TIGbus is used for delivering interrupts, and access to
+       the flash ROM.  I'm not sure that we need to implement it at all.  */
+
+    /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
+    memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x80180000000ULL,
+                                &s->pchip.region);
+
+    /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
+    memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801a0000000ULL,
+                                &s->cchip.region);
+
+    /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
+    memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801b0000000ULL,
+                                &s->dchip_region);
+
+    /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
+    memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB);
+    memory_region_add_subregion(addr_space, 0x80000000000ULL,
+                                &s->pchip.reg_mem);
+
+    /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
+    /* ??? Ideally we drop the "system" i/o space on the floor and give the
+       PCI subsystem the full address space reserved by the chipset.
+       We can't do that until the MEM and IO paths in memory.c are unified.  */
+    memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
+                          "pci0-io", 32*MB);
+    memory_region_add_subregion(addr_space, 0x801fc000000ULL,
+                                &s->pchip.reg_io);
+
+    b = pci_register_bus(&s->host.busdev.qdev, "pci",
+                         typhoon_set_irq, sys_map_irq, s,
+                         &s->pchip.reg_mem, addr_space_io, 0, 64);
+    s->host.bus = b;
+
+    /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
+    memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
+                          "pci0-iack", 64*MB);
+    memory_region_add_subregion(addr_space, 0x801f8000000ULL,
+                                &s->pchip.reg_iack);
+
+    /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
+    memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b,
+                          "pci0-conf", 16*MB);
+    memory_region_add_subregion(addr_space, 0x801fe000000ULL,
+                                &s->pchip.reg_conf);
+
+    /* For the record, these are the mappings for the second PCI bus.
+       We can get away with not implementing them because we indicate
+       via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
+    /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
+    /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
+    /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
+    /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
+    /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
+
+    /* Init the ISA bus.  */
+    /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
+    {
+        qemu_irq isa_pci_irq, *isa_irqs;
+
+        isa_bus_new(NULL, addr_space_io);
+        isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
+        isa_irqs = i8259_init(isa_pci_irq);
+        isa_bus_irqs(isa_irqs);
+    }
+
+    return b;
+}
+
+static int typhoon_pcihost_init(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo typhoon_pcihost_info = {
+    .init = typhoon_pcihost_init,
+    .qdev.name = "typhoon-pcihost",
+    .qdev.size = sizeof(TyphoonState),
+    .qdev.no_user = 1
+};
+
+static void typhoon_register(void)
+{
+    sysbus_register_withprop(&typhoon_pcihost_info);
+}
+device_init(typhoon_register);
index b9f19a9944a20c209898238f4c64652a0af32ae1..3fe1f00d9b4659a98eb166f040a5bd5793368009 100644 (file)
@@ -3,30 +3,20 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 
 #include "hw.h"
-#include "pc.h"
 #include "mcf.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 #define AN5206_MBAR_ADDR 0x10000000
 #define AN5206_RAMBAR_ADDR 0x20000000
 
-/* Stub functions for hardware that doesn't exist.  */
-void pic_info(Monitor *mon)
-{
-}
-
-void irq_info(Monitor *mon)
-{
-}
-
 /* Board init.  */
 
 static void an5206_init(ram_addr_t ram_size,
@@ -38,6 +28,9 @@ static void an5206_init(ram_addr_t ram_size,
     int kernel_size;
     uint64_t elf_entry;
     target_phys_addr_t entry;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "m5206";
@@ -53,12 +46,12 @@ static void an5206_init(ram_addr_t ram_size,
     env->rambar0 = AN5206_RAMBAR_ADDR | 1;
 
     /* DRAM at address zero */
-    cpu_register_physical_memory(0, ram_size,
-        qemu_ram_alloc(NULL, "an5206.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "an5206.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Internal SRAM.  */
-    cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
-        qemu_ram_alloc(NULL, "an5206.sram", 512) | IO_MEM_RAM);
+    memory_region_init_ram(sram, NULL, "an5206.sram", 512);
+    memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
 
     mcf5206_init(AN5206_MBAR_ADDR, env);
 
index 84e9af76a219632c5e2f26221d32f142c3a430a0..c232946280079c2fe27cd1c9f6fdabb200f312c3 100644 (file)
@@ -31,9 +31,9 @@
 #include "pci_host.h"
 #include "pci_bridge.h"
 #include "pci_internals.h"
-#include "rwhandler.h"
 #include "apb_pci.h"
 #include "sysemu.h"
+#include "exec-memory.h"
 
 /* debug APB */
 //#define DEBUG_APB
@@ -69,7 +69,10 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
 typedef struct APBState {
     SysBusDevice busdev;
     PCIBus      *bus;
-    ReadWriteHandler pci_config_handler;
+    MemoryRegion apb_config;
+    MemoryRegion pci_config;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_ioport;
     uint32_t iommu[4];
     uint32_t pci_control[16];
     uint32_t pci_irq_map[8];
@@ -80,7 +83,7 @@ typedef struct APBState {
 } APBState;
 
 static void apb_config_writel (void *opaque, target_phys_addr_t addr,
-                               uint32_t val)
+                               uint64_t val, unsigned size)
 {
     APBState *s = opaque;
 
@@ -127,8 +130,8 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
     }
 }
 
-static uint32_t apb_config_readl (void *opaque,
-                                  target_phys_addr_t addr)
+static uint64_t apb_config_readl (void *opaque,
+                                  target_phys_addr_t addr, unsigned size)
 {
     APBState *s = opaque;
     uint32_t val;
@@ -175,33 +178,27 @@ static uint32_t apb_config_readl (void *opaque,
     return val;
 }
 
-static CPUWriteMemoryFunc * const apb_config_write[] = {
-    &apb_config_writel,
-    &apb_config_writel,
-    &apb_config_writel,
+static const MemoryRegionOps apb_config_ops = {
+    .read = apb_config_readl,
+    .write = apb_config_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const apb_config_read[] = {
-    &apb_config_readl,
-    &apb_config_readl,
-    &apb_config_readl,
-};
-
-static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
-                                 uint32_t val, int size)
+static void apb_pci_config_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t val, unsigned size)
 {
-    APBState *s = container_of(h, APBState, pci_config_handler);
+    APBState *s = opaque;
 
     val = qemu_bswap_len(val, size);
     APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
     pci_data_write(s->bus, addr, val, size);
 }
 
-static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
-                                    int size)
+static uint64_t apb_pci_config_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
 {
     uint32_t ret;
-    APBState *s = container_of(h, APBState, pci_config_handler);
+    APBState *s = opaque;
 
     ret = pci_data_read(s->bus, addr, size);
     ret = qemu_bswap_len(ret, size);
@@ -251,16 +248,12 @@ static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
-    &pci_apb_iowriteb,
-    &pci_apb_iowritew,
-    &pci_apb_iowritel,
-};
-
-static CPUReadMemoryFunc * const pci_apb_ioread[] = {
-    &pci_apb_ioreadb,
-    &pci_apb_ioreadw,
-    &pci_apb_ioreadl,
+static const MemoryRegionOps pci_ioport_ops = {
+    .old_mmio = {
+        .read = { pci_apb_ioreadb, pci_apb_ioreadw, pci_apb_ioreadl },
+        .write = { pci_apb_iowriteb, pci_apb_iowritew, pci_apb_iowritel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* The APB host has an IRQ line for each IRQ line of each slot.  */
@@ -304,9 +297,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
         return rc;
     }
 
-    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
-
     /*
      * command register:
      * According to PCI bridge spec, after reset
@@ -321,7 +311,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
     pci_set_word(dev->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
     return 0;
 }
 
@@ -348,10 +337,14 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
     sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
     d = FROM_SYSBUS(APBState, s);
 
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
+
     d->bus = pci_register_bus(&d->busdev.qdev, "pci",
-                                         pci_apb_set_irq, pci_pbm_map_irq, d,
-                                         0, 32);
-    pci_bus_set_mem_base(d->bus, mem_base);
+                              pci_apb_set_irq, pci_pbm_map_irq, d,
+                              &d->pci_mmio,
+                              get_system_io(),
+                              0, 32);
 
     for (i = 0; i < 32; i++) {
         sysbus_connect_irq(s, i, pic[i]);
@@ -394,10 +387,15 @@ static void pci_pbm_reset(DeviceState *d)
     }
 }
 
+static const MemoryRegionOps pci_config_ops = {
+    .read = apb_pci_config_read,
+    .write = apb_pci_config_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static int pci_pbm_init_device(SysBusDevice *dev)
 {
     APBState *s;
-    int pci_config, apb_config, pci_ioport;
     unsigned int i;
 
     s = FROM_SYSBUS(APBState, dev);
@@ -409,41 +407,32 @@ static int pci_pbm_init_device(SysBusDevice *dev)
     }
 
     /* apb_config */
-    apb_config = cpu_register_io_memory(apb_config_read,
-                                        apb_config_write, s,
-                                        DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
+                          0x10000);
     /* at region 0 */
-    sysbus_init_mmio(dev, 0x10000ULL, apb_config);
+    sysbus_init_mmio_region(dev, &s->apb_config);
 
-    /* PCI configuration space */
-    s->pci_config_handler.read = apb_pci_config_read;
-    s->pci_config_handler.write = apb_pci_config_write;
-    pci_config = cpu_register_io_memory_simple(&s->pci_config_handler,
-                                               DEVICE_NATIVE_ENDIAN);
-    assert(pci_config >= 0);
+    memory_region_init_io(&s->pci_config, &pci_config_ops, s, "apb-pci-config",
+                          0x1000000);
     /* at region 1 */
-    sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
+    sysbus_init_mmio_region(dev, &s->pci_config);
 
     /* pci_ioport */
-    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
-                                        pci_apb_iowrite, s,
-                                        DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->pci_ioport, &pci_ioport_ops, s,
+                          "apb-pci-ioport", 0x10000);
     /* at region 2 */
-    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
+    sysbus_init_mmio_region(dev, &s->pci_ioport);
 
     return 0;
 }
 
 static int pbm_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
     pci_set_word(d->config + PCI_COMMAND,
                  PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
     pci_set_word(d->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_DEVSEL_MEDIUM);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     return 0;
 }
 
@@ -451,6 +440,9 @@ static PCIDeviceInfo pbm_pci_host_info = {
     .qdev.name = "pbm",
     .qdev.size = sizeof(PCIDevice),
     .init      = pbm_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SABRE,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
     .is_bridge = 1,
 };
 
@@ -468,6 +460,9 @@ static PCIDeviceInfo pbm_pci_bridge_info = {
     .qdev.reset = pci_bridge_reset,
     .init = apb_pci_bridge_initfn,
     .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SIMBA,
+    .revision = 0x11,
     .config_write = pci_bridge_write_config,
     .is_bridge = 1,
 };
index 218d1bb6da060ee34b87fc6811cf585f469c1722..8289eef5b83df249a9d7b049e4878b2761f28c81 100644 (file)
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -23,6 +23,7 @@
 #include "host-utils.h"
 #include "sysbus.h"
 #include "trace.h"
+#include "pc.h"
 
 /* APIC Local Vector Table */
 #define APIC_LVT_TIMER   0
@@ -80,6 +81,7 @@ typedef struct APICState APICState;
 
 struct APICState {
     SysBusDevice busdev;
+    MemoryRegion io_memory;
     void *cpu_env;
     uint32_t apicbase;
     uint8_t id;
@@ -222,8 +224,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
 }
 
 static void apic_bus_deliver(const uint32_t *deliver_bitmask,
-                             uint8_t delivery_mode,
-                             uint8_t vector_num, uint8_t polarity,
+                             uint8_t delivery_mode, uint8_t vector_num,
                              uint8_t trigger_mode)
 {
     APICState *apic_iter;
@@ -280,18 +281,16 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
                  apic_set_irq(apic_iter, vector_num, trigger_mode) );
 }
 
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
-                      uint8_t delivery_mode, uint8_t vector_num,
-                      uint8_t polarity, uint8_t trigger_mode)
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
+                      uint8_t vector_num, uint8_t trigger_mode)
 {
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
 
     trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
-                           polarity, trigger_mode);
+                           trigger_mode);
 
     apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
-                     trigger_mode);
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
 void cpu_set_apic_base(DeviceState *d, uint64_t val)
@@ -401,6 +400,9 @@ static void apic_update_irq(APICState *s)
     }
     if (apic_irq_pending(s) > 0) {
         cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+    } else if (apic_accept_pic_intr(&s->busdev.qdev) &&
+               pic_get_output(isa_pic)) {
+        apic_deliver_pic_intr(&s->busdev.qdev, 1);
     }
 }
 
@@ -548,7 +550,7 @@ void apic_sipi(DeviceState *d)
 
 static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
                          uint8_t delivery_mode, uint8_t vector_num,
-                         uint8_t polarity, uint8_t trigger_mode)
+                         uint8_t trigger_mode)
 {
     APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
@@ -591,8 +593,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
             return;
     }
 
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
-                     trigger_mode);
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
 int apic_get_interrupt(DeviceState *d)
@@ -641,7 +642,7 @@ static uint32_t apic_get_current_count(APICState *s)
 {
     int64_t d;
     uint32_t val;
-    d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
+    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
         s->count_shift;
     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
         /* periodic */
@@ -794,7 +795,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
     uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
     uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
     /* XXX: Ignore redirection hint. */
-    apic_deliver_irq(dest, dest_mode, delivery, vector, 0, trigger_mode);
+    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
 }
 
 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -855,7 +856,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         s->icr[0] = val;
         apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
                      (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
-                     (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
+                     (s->icr[0] >> 15) & 1);
         break;
     case 0x31:
         s->icr[1] = val;
@@ -865,12 +866,12 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
             int n = index - 0x32;
             s->lvt[n] = val;
             if (n == APIC_LVT_TIMER)
-                apic_timer_update(s, qemu_get_clock(vm_clock));
+                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
         }
         break;
     case 0x38:
         s->initial_count = val;
-        s->initial_count_load_time = qemu_get_clock(vm_clock);
+        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
         apic_timer_update(s, s->initial_count_load_time);
         break;
     case 0x39:
@@ -979,33 +980,27 @@ static void apic_reset(DeviceState *d)
     }
 }
 
-static CPUReadMemoryFunc * const apic_mem_read[3] = {
-    apic_mem_readb,
-    apic_mem_readw,
-    apic_mem_readl,
-};
-
-static CPUWriteMemoryFunc * const apic_mem_write[3] = {
-    apic_mem_writeb,
-    apic_mem_writew,
-    apic_mem_writel,
+static const MemoryRegionOps apic_io_ops = {
+    .old_mmio = {
+        .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
+        .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int apic_init1(SysBusDevice *dev)
 {
     APICState *s = FROM_SYSBUS(APICState, dev);
-    int apic_io_memory;
     static int last_apic_idx;
 
     if (last_apic_idx >= MAX_APICS) {
         return -1;
     }
-    apic_io_memory = cpu_register_io_memory(apic_mem_read,
-                                            apic_mem_write, NULL,
-                                            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MSI_ADDR_SIZE, apic_io_memory);
+    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
+                          MSI_ADDR_SIZE);
+    sysbus_init_mmio_region(dev, &s->io_memory);
 
-    s->timer = qemu_new_timer(vm_clock, apic_timer, s);
+    s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
     s->idx = last_apic_idx++;
     local_apics[s->idx] = s;
     return 0;
index 8a0c9d0bf6212b058004db9562f18b10a8562893..a5c910fe0acff88409b4f74ea54a36792431c519 100644 (file)
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -4,10 +4,8 @@
 #include "qemu-common.h"
 
 /* apic.c */
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
-                             uint8_t delivery_mode,
-                             uint8_t vector_num, uint8_t polarity,
-                             uint8_t trigger_mode);
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
+                      uint8_t vector_num, uint8_t trigger_mode);
 int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
 int apic_get_interrupt(DeviceState *s);
index 23ed3287b454a7831d6bc3e17b1d01974821bf58..c47b592747a49e3862cb4edcd13e4c9017506fcd 100644 (file)
@@ -170,7 +170,7 @@ static void applesmc_add_key(struct AppleSMCStatus *s, const char *key,
 {
     struct AppleSMCData *def;
 
-    def = qemu_mallocz(sizeof(struct AppleSMCData));
+    def = g_malloc0(sizeof(struct AppleSMCData));
     def->key = key;
     def->len = len;
     def->data = data;
index 010acb4cf96a57a336bd9db9068ada7a4a5c8610..af403a159a3c5547d49c41d9ddc998dcf44a612f 100644 (file)
@@ -4,20 +4,23 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  *
  */
 
 #ifndef ARM_MISC_H
 #define ARM_MISC_H 1
 
+#include "memory.h"
+
 /* The CPU is also modeled as an interrupt controller.  */
 #define ARM_PIC_CPU_IRQ 0
 #define ARM_PIC_CPU_FIQ 1
 qemu_irq *arm_pic_init_cpu(CPUState *env);
 
 /* armv7m.c */
-qemu_irq *armv7m_init(int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
+                      int flash_size, int sram_size,
                       const char *kernel_filename, const char *cpu_model);
 
 /* arm_boot.c */
@@ -31,7 +34,7 @@ struct arm_boot_info {
     target_phys_addr_t smp_priv_base;
     int nb_cpus;
     int board_id;
-    int (*atag_board)(struct arm_boot_info *info, void *p);
+    int (*atag_board)(const struct arm_boot_info *info, void *p);
     /* Used internally by arm_boot.c */
     int is_linux;
     target_phys_addr_t initrd_size;
index 3bbd8856cf7e951a005efa549f0687087f4730c4..974a0d8262dd47179e28c685f74ae35558e66672 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 /* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
@@ -48,12 +48,6 @@ static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
     }
 }
 
-static void mpcore_rirq_map(SysBusDevice *dev, target_phys_addr_t base)
-{
-    mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
-    sysbus_mmio_map(s->priv, 0, base);
-}
-
 static int realview_mpcore_init(SysBusDevice *dev)
 {
     mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
@@ -79,7 +73,7 @@ static int realview_mpcore_init(SysBusDevice *dev)
         }
     }
     qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
-    sysbus_init_mmio_cb(dev, 0x2000, mpcore_rirq_map);
+    sysbus_init_mmio_region(dev, sysbus_mmio_get_region(s->priv, 0));
     return 0;
 }
 
index 620550b5abb07c3dccd7e8d2f7bd626db7de8072..215d5dec6470e59f92f0afc0972bea8a1f0ed7b9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
@@ -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[] = {
@@ -49,7 +49,7 @@ static uint32_t smpboot[] = {
     p += 4;                       \
 } while (0)
 
-static void set_kernel_args(struct arm_boot_info *info,
+static void set_kernel_args(const struct arm_boot_info *info,
                 int initrd_size, target_phys_addr_t base)
 {
     target_phys_addr_t p;
@@ -102,7 +102,7 @@ static void set_kernel_args(struct arm_boot_info *info,
     WRITE_WORD(p, 0);
 }
 
-static void set_kernel_args_old(struct arm_boot_info *info,
+static void set_kernel_args_old(const struct arm_boot_info *info,
                 int initrd_size, target_phys_addr_t base)
 {
     target_phys_addr_t p;
@@ -175,10 +175,10 @@ static void set_kernel_args_old(struct arm_boot_info *info,
     }
 }
 
-static void main_cpu_reset(void *opaque)
+static void do_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
-    struct arm_boot_info *info = env->boot_info;
+    const struct arm_boot_info *info = env->boot_info;
 
     cpu_reset(env);
     if (info) {
@@ -187,16 +187,20 @@ static void main_cpu_reset(void *opaque)
             env->regs[15] = info->entry & 0xfffffffe;
             env->thumb = info->entry & 1;
         } else {
-            env->regs[15] = info->loader_start;
-            if (old_param) {
-                set_kernel_args_old(info, info->initrd_size,
+            if (env == first_cpu) {
+                env->regs[15] = info->loader_start;
+                if (old_param) {
+                    set_kernel_args_old(info, info->initrd_size,
+                                        info->loader_start);
+                } else {
+                    set_kernel_args(info, info->initrd_size,
                                     info->loader_start);
+                }
             } else {
-                set_kernel_args(info, info->initrd_size, info->loader_start);
+                env->regs[15] = info->smp_loader_start;
             }
         }
     }
-    /* TODO:  Reset secondary CPUs.  */
 }
 
 void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
@@ -217,7 +221,6 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
 
     if (info->nb_cpus == 0)
         info->nb_cpus = 1;
-    env->boot_info = info;
 
 #ifdef TARGET_WORDS_BIGENDIAN
     big_endian = 1;
@@ -279,5 +282,9 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
         info->initrd_size = initrd_size;
     }
     info->is_linux = is_linux;
-    qemu_register_reset(main_cpu_reset, env);
+
+    for (; env; env = env->next_cpu) {
+        env->boot_info = info;
+        qemu_register_reset(do_cpu_reset, env);
+    }
 }
index e6b195324b7b8182a2d958d970efcdeef4d14232..f3f35164d0454d6ba55aebe6e153ecd61c791d55 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 /* This file contains implementation code for the RealView EB interrupt
@@ -37,9 +37,8 @@ static const uint8_t gic_id[] =
 
 typedef struct gic_irq_state
 {
-    /* ??? The documentation seems to imply the enable bits are global, even
-       for per-cpu interrupts.  This seems strange.  */
-    unsigned enabled:1;
+    /* The enable bits are only banked for per-cpu interrupts.  */
+    unsigned enabled:NCPU;
     unsigned pending:NCPU;
     unsigned active:NCPU;
     unsigned level:NCPU;
@@ -54,9 +53,9 @@ typedef struct gic_irq_state
 #define NUM_CPU(s) 1
 #endif
 
-#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
-#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
-#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
+#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
+#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
+#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
 #define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
 #define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
 #define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
@@ -104,7 +103,7 @@ typedef struct gic_state
     int num_cpu;
 #endif
 
-    int iomemtype;
+    MemoryRegion iomem;
 } gic_state;
 
 /* TODO: Many places that call this routine could be optimized.  */
@@ -128,7 +127,7 @@ static void gic_update(gic_state *s)
         best_prio = 0x100;
         best_irq = 1023;
         for (irq = 0; irq < GIC_NIRQ; irq++) {
-            if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {
+            if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                     best_prio = GIC_GET_PRIORITY(irq, cpu);
                     best_irq = irq;
@@ -171,7 +170,7 @@ static void gic_set_irq(void *opaque, int irq, int level)
 
     if (level) {
         GIC_SET_LEVEL(irq, ALL_CPU_MASK);
-        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
+        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) {
             DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
             GIC_SET_PENDING(irq, GIC_TARGET(irq));
         }
@@ -221,7 +220,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq)
     if (irq != 1023) {
         /* Mark level triggered interrupts as pending if they are still
            raised.  */
-        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
+        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
                 && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
             DPRINTF("Set %d pending mask %x\n", irq, cm);
             GIC_SET_PENDING(irq, cm);
@@ -280,7 +279,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
             goto bad_reg;
         res = 0;
         for (i = 0; i < 8; i++) {
-            if (GIC_TEST_ENABLED(irq + i)) {
+            if (GIC_TEST_ENABLED(irq + i, cm)) {
                 res |= (1 << i);
             }
         }
@@ -412,9 +411,12 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
         for (i = 0; i < 8; i++) {
             if (value & (1 << i)) {
                 int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
-                if (!GIC_TEST_ENABLED(irq + i))
+                int cm = (irq < 32) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (!GIC_TEST_ENABLED(irq + i, cm)) {
                     DPRINTF("Enabled IRQ %d\n", irq + i);
-                GIC_SET_ENABLED(irq + i);
+                }
+                GIC_SET_ENABLED(irq + i, cm);
                 /* If a raised level triggered IRQ enabled then mark
                    is as pending.  */
                 if (GIC_TEST_LEVEL(irq + i, mask)
@@ -433,9 +435,12 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
           value = 0;
         for (i = 0; i < 8; i++) {
             if (value & (1 << i)) {
-                if (GIC_TEST_ENABLED(irq + i))
+                int cm = (irq < 32) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (GIC_TEST_ENABLED(irq + i, cm)) {
                     DPRINTF("Disabled IRQ %d\n", irq + i);
-                GIC_CLEAR_ENABLED(irq + i);
+                }
+                GIC_CLEAR_ENABLED(irq + i, cm);
             }
         }
     } else if (offset < 0x280) {
@@ -549,10 +554,10 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
             mask = (value >> 16) & ALL_CPU_MASK;
             break;
         case 1:
-            mask = 1 << cpu;
+            mask = ALL_CPU_MASK ^ (1 << cpu);
             break;
         case 2:
-            mask = ALL_CPU_MASK ^ (1 << cpu);
+            mask = 1 << cpu;
             break;
         default:
             DPRINTF("Bad Soft Int target filter\n");
@@ -567,16 +572,12 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
     gic_dist_writew(opaque, offset + 2, value >> 16);
 }
 
-static CPUReadMemoryFunc * const gic_dist_readfn[] = {
-   gic_dist_readb,
-   gic_dist_readw,
-   gic_dist_readl
-};
-
-static CPUWriteMemoryFunc * const gic_dist_writefn[] = {
-   gic_dist_writeb,
-   gic_dist_writew,
-   gic_dist_writel
+static const MemoryRegionOps gic_dist_ops = {
+    .old_mmio = {
+        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
+        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 #ifndef NVIC
@@ -642,7 +643,7 @@ static void gic_reset(gic_state *s)
 #endif
     }
     for (i = 0; i < 16; i++) {
-        GIC_SET_ENABLED(i);
+        GIC_SET_ENABLED(i, ALL_CPU_MASK);
         GIC_SET_TRIGGER(i);
     }
 #ifdef NVIC
@@ -662,9 +663,6 @@ static void gic_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, s->enabled);
     for (i = 0; i < NUM_CPU(s); i++) {
         qemu_put_be32(f, s->cpu_enabled[i]);
-#ifndef NVIC
-        qemu_put_be32(f, s->irq_target[i]);
-#endif
         for (j = 0; j < 32; j++)
             qemu_put_be32(f, s->priority1[j][i]);
         for (j = 0; j < GIC_NIRQ; j++)
@@ -678,6 +676,9 @@ static void gic_save(QEMUFile *f, void *opaque)
         qemu_put_be32(f, s->priority2[i]);
     }
     for (i = 0; i < GIC_NIRQ; i++) {
+#ifndef NVIC
+        qemu_put_be32(f, s->irq_target[i]);
+#endif
         qemu_put_byte(f, s->irq_state[i].enabled);
         qemu_put_byte(f, s->irq_state[i].pending);
         qemu_put_byte(f, s->irq_state[i].active);
@@ -693,15 +694,12 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
     int i;
     int j;
 
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
 
     s->enabled = qemu_get_be32(f);
     for (i = 0; i < NUM_CPU(s); i++) {
         s->cpu_enabled[i] = qemu_get_be32(f);
-#ifndef NVIC
-        s->irq_target[i] = qemu_get_be32(f);
-#endif
         for (j = 0; j < 32; j++)
             s->priority1[j][i] = qemu_get_be32(f);
         for (j = 0; j < GIC_NIRQ; j++)
@@ -715,6 +713,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
         s->priority2[i] = qemu_get_be32(f);
     }
     for (i = 0; i < GIC_NIRQ; i++) {
+#ifndef NVIC
+        s->irq_target[i] = qemu_get_be32(f);
+#endif
         s->irq_state[i].enabled = qemu_get_byte(f);
         s->irq_state[i].pending = qemu_get_byte(f);
         s->irq_state[i].active = qemu_get_byte(f);
@@ -741,9 +742,7 @@ static void gic_init(gic_state *s)
     for (i = 0; i < NUM_CPU(s); i++) {
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
-    s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
-                                          gic_dist_writefn, s,
-                                          DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
     gic_reset(s);
-    register_savevm(NULL, "arm_gic", -1, 1, gic_save, gic_load, s);
+    register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
 }
index f44568cebbf9a44541293a0c7f2da5603b5b035d..a2e8a733014db6c5c0896e0eefc2c8f79626bb73 100644 (file)
@@ -4,23 +4,12 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL
+ * This code is licensed under the LGPL
  */
 
 #include "hw.h"
-#include "pc.h"
 #include "arm-misc.h"
 
-/* Stub functions for hardware that doesn't exist.  */
-void pic_info(Monitor *mon)
-{
-}
-
-void irq_info(Monitor *mon)
-{
-}
-
-
 /* Input 0 is IRQ and input 1 is FIQ.  */
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
 {
@@ -39,7 +28,7 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level)
             cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
         break;
     default:
-        hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq);
+        hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
     }
 }
 
index d8b062c1bf7dd0bc53bc9c9d282ac29b146a3edf..477fc6fd474dcbdd681429ce0f92fc68ef87d32e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
@@ -17,6 +17,9 @@
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq pl110_mux_ctrl;
+
     uint32_t sys_id;
     uint32_t leds;
     uint16_t lockval;
@@ -26,11 +29,16 @@ typedef struct {
     uint32_t nvflags;
     uint32_t resetlevel;
     uint32_t proc_id;
+    uint32_t sys_mci;
+    uint32_t sys_cfgdata;
+    uint32_t sys_cfgctrl;
+    uint32_t sys_cfgstat;
+    uint32_t sys_clcd;
 } arm_sysctl_state;
 
 static const VMStateDescription vmstate_arm_sysctl = {
     .name = "realview_sysctl",
-    .version_id = 1,
+    .version_id = 3,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(leds, arm_sysctl_state),
@@ -40,10 +48,31 @@ static const VMStateDescription vmstate_arm_sysctl = {
         VMSTATE_UINT32(flags, arm_sysctl_state),
         VMSTATE_UINT32(nvflags, arm_sysctl_state),
         VMSTATE_UINT32(resetlevel, arm_sysctl_state),
+        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
         VMSTATE_END_OF_LIST()
     }
 };
 
+/* The PB926 actually uses a different format for
+ * its SYS_ID register. Fortunately the bits which are
+ * board type on later boards are distinct.
+ */
+#define BOARD_ID_PB926 0x100
+#define BOARD_ID_EB 0x140
+#define BOARD_ID_PBA8 0x178
+#define BOARD_ID_PBX 0x182
+#define BOARD_ID_VEXPRESS 0x190
+
+static int board_id(arm_sysctl_state *s)
+{
+    /* Extract the board ID field from the SYS_ID register value */
+    return (s->sys_id >> 16) & 0xfff;
+}
+
 static void arm_sysctl_reset(DeviceState *d)
 {
     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d));
@@ -54,9 +83,17 @@ static void arm_sysctl_reset(DeviceState *d)
     s->cfgdata2 = 0;
     s->flags = 0;
     s->resetlevel = 0;
+    if (board_id(s) == BOARD_ID_VEXPRESS) {
+        /* On VExpress this register will RAZ/WI */
+        s->sys_clcd = 0;
+    } else {
+        /* All others: CLCDID 0x1f, indicating VGA */
+        s->sys_clcd = 0x1f00;
+    }
 }
 
-static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
+static uint64_t arm_sysctl_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
 {
     arm_sysctl_state *s = (arm_sysctl_state *)opaque;
 
@@ -88,21 +125,25 @@ static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
     case 0x38: /* NVFLAGS */
         return s->nvflags;
     case 0x40: /* RESETCTL */
+        if (board_id(s) == BOARD_ID_VEXPRESS) {
+            /* reserved: RAZ/WI */
+            return 0;
+        }
         return s->resetlevel;
     case 0x44: /* PCICTL */
         return 1;
     case 0x48: /* MCI */
-        return 0;
+        return s->sys_mci;
     case 0x4c: /* FLASH */
         return 0;
     case 0x50: /* CLCD */
-        return 0x1000;
+        return s->sys_clcd;
     case 0x54: /* CLCDSER */
         return 0;
     case 0x58: /* BOOTCS */
         return 0;
     case 0x5c: /* 24MHz */
-        return muldiv64(qemu_get_clock(vm_clock), 24000000, get_ticks_per_sec());
+        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
     case 0x60: /* MISC */
         return 0;
     case 0x84: /* PROCID0 */
@@ -126,14 +167,30 @@ static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
     case 0xcc: /* SYS_TEST_OSC3 */
     case 0xd0: /* SYS_TEST_OSC4 */
         return 0;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgdata;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgctrl;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgstat;
     default:
+    bad_reg:
         printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
         return 0;
     }
 }
 
 static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
-                          uint32_t val)
+                             uint64_t val, unsigned size)
 {
     arm_sysctl_state *s = (arm_sysctl_state *)opaque;
 
@@ -174,17 +231,68 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
         s->nvflags &= ~val;
         break;
     case 0x40: /* RESETCTL */
-        if (s->lockval == LOCK_VALUE) {
-            s->resetlevel = val;
-            if (val & 0x100)
-                qemu_system_reset_request ();
+        switch (board_id(s)) {
+        case BOARD_ID_PB926:
+            if (s->lockval == LOCK_VALUE) {
+                s->resetlevel = val;
+                if (val & 0x100) {
+                    qemu_system_reset_request();
+                }
+            }
+            break;
+        case BOARD_ID_PBX:
+        case BOARD_ID_PBA8:
+            if (s->lockval == LOCK_VALUE) {
+                s->resetlevel = val;
+                if (val & 0x04) {
+                    qemu_system_reset_request();
+                }
+            }
+            break;
+        case BOARD_ID_VEXPRESS:
+        case BOARD_ID_EB:
+        default:
+            /* reserved: RAZ/WI */
+            break;
         }
         break;
     case 0x44: /* PCICTL */
         /* nothing to do.  */
         break;
     case 0x4c: /* FLASH */
+        break;
     case 0x50: /* CLCD */
+        switch (board_id(s)) {
+        case BOARD_ID_PB926:
+            /* On 926 bits 13:8 are R/O, bits 1:0 control
+             * the mux that defines how to interpret the PL110
+             * graphics format, and other bits are r/w but we
+             * don't implement them to do anything.
+             */
+            s->sys_clcd &= 0x3f00;
+            s->sys_clcd |= val & ~0x3f00;
+            qemu_set_irq(s->pl110_mux_ctrl, val & 3);
+            break;
+        case BOARD_ID_EB:
+            /* The EB is the same except that there is no mux since
+             * the EB has a PL111.
+             */
+            s->sys_clcd &= 0x3f00;
+            s->sys_clcd |= val & ~0x3f00;
+            break;
+        case BOARD_ID_PBA8:
+        case BOARD_ID_PBX:
+            /* On PBA8 and PBX bit 7 is r/w and all other bits
+             * are either r/o or RAZ/WI.
+             */
+            s->sys_clcd &= (1 << 7);
+            s->sys_clcd |= val & ~(1 << 7);
+            break;
+        case BOARD_ID_VEXPRESS:
+        default:
+            /* On VExpress this register is unimplemented and will RAZ/WI */
+            break;
+        }
     case 0x54: /* CLCDSER */
     case 0x64: /* DMAPSR0 */
     case 0x68: /* DMAPSR1 */
@@ -200,34 +308,84 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
     case 0x98: /* OSCRESET3 */
     case 0x9c: /* OSCRESET4 */
         break;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgdata = val;
+        return;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgctrl = val & ~(3 << 18);
+        s->sys_cfgstat = 1;            /* complete */
+        switch (s->sys_cfgctrl) {
+        case 0xc0800000:            /* SYS_CFG_SHUTDOWN to motherboard */
+            qemu_system_shutdown_request();
+            break;
+        case 0xc0900000:            /* SYS_CFG_REBOOT to motherboard */
+            qemu_system_reset_request();
+            break;
+        default:
+            s->sys_cfgstat |= 2;        /* error */
+        }
+        return;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgstat = val & 3;
+        return;
     default:
+    bad_reg:
         printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
         return;
     }
 }
 
-static CPUReadMemoryFunc * const arm_sysctl_readfn[] = {
-   arm_sysctl_read,
-   arm_sysctl_read,
-   arm_sysctl_read
+static const MemoryRegionOps arm_sysctl_ops = {
+    .read = arm_sysctl_read,
+    .write = arm_sysctl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const arm_sysctl_writefn[] = {
-   arm_sysctl_write,
-   arm_sysctl_write,
-   arm_sysctl_write
-};
+static void arm_sysctl_gpio_set(void *opaque, int line, int level)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+    switch (line) {
+    case ARM_SYSCTL_GPIO_MMC_WPROT:
+    {
+        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
+         * for all later boards it is bit 1.
+         */
+        int bit = 2;
+        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
+            bit = 4;
+        }
+        s->sys_mci &= ~bit;
+        if (level) {
+            s->sys_mci |= bit;
+        }
+        break;
+    }
+    case ARM_SYSCTL_GPIO_MMC_CARDIN:
+        s->sys_mci &= ~1;
+        if (level) {
+            s->sys_mci |= 1;
+        }
+        break;
+    }
+}
 
 static int arm_sysctl_init1(SysBusDevice *dev)
 {
     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
-    int iomemtype;
 
-    iomemtype = cpu_register_io_memory(arm_sysctl_readfn,
-                                       arm_sysctl_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
-    /* ??? Save/restore.  */
+    memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
+    qdev_init_gpio_out(&s->busdev.qdev, &s->pl110_mux_ctrl, 1);
     return 0;
 }
 
index 82f05dec84fa523d39f1bb13be77878b5c6c3150..66db81d5b7e9be9210bfa5bc120e4878a7c67821 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005-2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -140,41 +140,32 @@ 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)
 {
     arm_timer_state *s;
     QEMUBH *bh;
 
-    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
+    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
     s->freq = freq;
     s->control = TIMER_CTRL_IE;
 
     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;
 }
 
@@ -185,6 +176,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     arm_timer_state *timer[2];
     int level[2];
     qemu_irq irq;
@@ -199,7 +191,8 @@ static void sp804_set_irq(void *opaque, int irq, int level)
     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
-static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
+static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
+                           unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
@@ -212,7 +205,7 @@ static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
-                        uint32_t value)
+                        uint64_t value, unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
@@ -223,40 +216,25 @@ static void sp804_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const sp804_readfn[] = {
-   sp804_read,
-   sp804_read,
-   sp804_read
+static const MemoryRegionOps sp804_ops = {
+    .read = sp804_read,
+    .write = sp804_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const sp804_writefn[] = {
-   sp804_write,
-   sp804_write,
-   sp804_write
+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 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 int sp804_init(SysBusDevice *dev)
 {
-    int iomemtype;
     sp804_state *s = FROM_SYSBUS(sp804_state, dev);
     qemu_irq *qi;
 
@@ -268,10 +246,9 @@ static int sp804_init(SysBusDevice *dev)
     s->timer[1] = arm_timer_init(1000000);
     s->timer[0]->irq = qi[0];
     s->timer[1]->irq = qi[1];
-    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);
+    memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
     return 0;
 }
 
@@ -280,17 +257,19 @@ static int sp804_init(SysBusDevice *dev)
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     arm_timer_state *timer[3];
 } icp_pit_state;
 
-static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
+static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
+                             unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
-    if (n > 3) {
+    if (n > 2) {
         hw_error("sp804_read: Bad timer %d\n", n);
     }
 
@@ -298,35 +277,27 @@ static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
-                          uint32_t value)
+                          uint64_t value, unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     n = offset >> 8;
-    if (n > 3) {
+    if (n > 2) {
         hw_error("sp804_write: Bad timer %d\n", n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
 }
 
-
-static CPUReadMemoryFunc * const icp_pit_readfn[] = {
-   icp_pit_read,
-   icp_pit_read,
-   icp_pit_read
-};
-
-static CPUWriteMemoryFunc * const icp_pit_writefn[] = {
-   icp_pit_write,
-   icp_pit_write,
-   icp_pit_write
+static const MemoryRegionOps icp_pit_ops = {
+    .read = icp_pit_read,
+    .write = icp_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int icp_pit_init(SysBusDevice *dev)
 {
-    int iomemtype;
     icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
 
     /* Timer 0 runs at the system clock speed (40MHz).  */
@@ -339,10 +310,8 @@ static int icp_pit_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->timer[1]->irq);
     sysbus_init_irq(dev, &s->timer[2]->irq);
 
-    iomemtype = cpu_register_io_memory(icp_pit_readfn,
-                                       icp_pit_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &icp_pit_ops, s, "icp_pit", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     /* This device has no state to save/restore.  The component timers will
        save themselves.  */
     return 0;
index 304cd34bc2a007f74d82130531e722d300531667..28d41b82a62b55b0bcc5642cabee9e8d8feb709e 100644 (file)
@@ -4,18 +4,17 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
 #include "arm-misc.h"
-#include "sysemu.h"
 #include "loader.h"
 #include "elf.h"
 
 /* Bitbanded IO.  Each word corresponds to a single bit.  */
 
-/* Get the byte address of the real memory for a bitband acess.  */
+/* Get the byte address of the real memory for a bitband access.  */
 static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
 {
     uint32_t res;
@@ -107,31 +106,27 @@ static void bitband_writel(void *opaque, target_phys_addr_t offset,
     cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
 }
 
-static CPUReadMemoryFunc * const bitband_readfn[] = {
-   bitband_readb,
-   bitband_readw,
-   bitband_readl
-};
-
-static CPUWriteMemoryFunc * const bitband_writefn[] = {
-   bitband_writeb,
-   bitband_writew,
-   bitband_writel
+static const MemoryRegionOps bitband_ops = {
+    .old_mmio = {
+        .read = { bitband_readb, bitband_readw, bitband_readl, },
+        .write = { bitband_writeb, bitband_writew, bitband_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t base;
 } BitBandState;
 
 static int bitband_init(SysBusDevice *dev)
 {
     BitBandState *s = FROM_SYSBUS(BitBandState, dev);
-    int iomemtype;
 
-    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
-                                       &s->base, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x02000000, iomemtype);
+    memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband",
+                          0x02000000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -161,7 +156,8 @@ static void armv7m_reset(void *opaque)
    flash_size and sram_size are in kb.
    Returns the NVIC array.  */
 
-qemu_irq *armv7m_init(int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
+                      int flash_size, int sram_size,
                       const char *kernel_filename, const char *cpu_model)
 {
     CPUState *env;
@@ -174,6 +170,9 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     uint64_t lowaddr;
     int i;
     int big_endian;
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *hack = g_new(MemoryRegion, 1);
 
     flash_size *= 1024;
     sram_size *= 1024;
@@ -199,12 +198,11 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
 #endif
 
     /* Flash programming is done via the SCU, so pretend it is ROM.  */
-    cpu_register_physical_memory(0, flash_size,
-                                 qemu_ram_alloc(NULL, "armv7m.flash",
-                                                flash_size) | IO_MEM_ROM);
-    cpu_register_physical_memory(0x20000000, sram_size,
-                                 qemu_ram_alloc(NULL, "armv7m.sram",
-                                                sram_size) | IO_MEM_RAM);
+    memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(address_space_mem, 0, flash);
+    memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size);
+    memory_region_add_subregion(address_space_mem, 0x20000000, sram);
     armv7m_bitband_init();
 
     nvic = qdev_create(NULL, "armv7m_nvic");
@@ -237,9 +235,8 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     /* Hack to map an additional page of ram at the top of the address
        space.  This stops qemu complaining about executing code outside RAM
        when returning from an exception.  */
-    cpu_register_physical_memory(0xfffff000, 0x1000,
-                                 qemu_ram_alloc(NULL, "armv7m.hack", 
-                                                0x1000) | IO_MEM_RAM);
+    memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000);
+    memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
 
     qemu_register_reset(armv7m_reset, env);
     return pic;
index 6c7ce01228c31a300bfa72a2afdb184657a37a28..bf8c3c50dc0c1ee221ca887f369f4ecddf4080c7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  *
  * The ARMv7M System controller is fairly tightly tied in with the
  * NVIC.  Much of that is also implemented here.
@@ -13,6 +13,7 @@
 #include "sysbus.h"
 #include "qemu-timer.h"
 #include "arm-misc.h"
+#include "exec-memory.h"
 
 /* 32 internal lines (16 used for system exceptions) plus 64 external
    interrupt lines.  */
@@ -64,7 +65,7 @@ static inline int64_t systick_scale(nvic_state *s)
 static void systick_reload(nvic_state *s, int reset)
 {
     if (reset)
-        s->systick.tick = qemu_get_clock(vm_clock);
+        s->systick.tick = qemu_get_clock_ns(vm_clock);
     s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
     qemu_mod_timer(s->systick.timer, s->systick.tick);
 }
@@ -136,7 +137,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
             int64_t t;
             if ((s->systick.control & SYSTICK_ENABLE) == 0)
                 return 0;
-            t = qemu_get_clock(vm_clock);
+            t = qemu_get_clock_ns(vm_clock);
             if (t >= s->systick.tick)
                 return 0;
             val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
@@ -273,7 +274,7 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
         s->systick.control &= 0xfffffff8;
         s->systick.control |= value & 7;
         if ((oldval ^ value) & SYSTICK_ENABLE) {
-            int64_t now = qemu_get_clock(vm_clock);
+            int64_t now = qemu_get_clock_ns(vm_clock);
             if (value & SYSTICK_ENABLE) {
                 if (s->systick.tick) {
                     s->systick.tick += now;
@@ -365,39 +366,28 @@ 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)
 {
     nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
 
     gic_init(&s->gic);
-    cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
-    s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
-    register_savevm(&dev->qdev, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
+    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
+    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
     return 0;
 }
 
index 8e930b21aefe1094da5c72f5a54f40787a6e8099..d60c3498ee408b221dfea281510dcefd30af07aa 100644 (file)
@@ -11,7 +11,7 @@ int Adlib_init(qemu_irq *pic);
 int GUS_init(qemu_irq *pic);
 
 /* ac97.c */
-int ac97_init(PCIBus *buf);
+int ac97_init(PCIBus *bus);
 
 /* cs4231a.c */
 int cs4231a_init(qemu_irq *pic);
index 57b5e2f04109aae1265d4299754bdf7f3d6b6425..73eb39d43bc38b3445ad10e295a9db6d739500b8 100644 (file)
 #include "net.h"
 #include "flash.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "etraxfs.h"
 #include "loader.h"
 #include "elf.h"
 #include "cris-boot.h"
+#include "blockdev.h"
+#include "exec-memory.h"
 
 #define D(x)
 #define DNAND(x)
 
 struct nand_state_t
 {
-    NANDFlashState *nand;
+    DeviceState *nand;
     unsigned int rdy:1;
     unsigned int ale:1;
     unsigned int cle:1;
@@ -252,14 +253,16 @@ void axisdev88_init (ram_addr_t ram_size,
     CPUState *env;
     DeviceState *dev;
     SysBusDevice *s;
+    DriveInfo *nand;
     qemu_irq irq[30], nmi[2], *cpu_irq;
     void *etraxfs_dmac;
-    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
+    struct etraxfs_dma_client *dma_eth;
     int i;
     int nand_regs;
     int gpio_regs;
-    ram_addr_t phys_ram;
-    ram_addr_t phys_intmem;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -268,18 +271,18 @@ void axisdev88_init (ram_addr_t ram_size,
     env = cpu_init(cpu_model);
 
     /* allocate RAM */
-    phys_ram = qemu_ram_alloc(NULL, "axisdev88.ram", ram_size);
-    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
+    memory_region_init_ram(phys_ram, NULL, "axisdev88.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
 
     /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
        internal memory.  */
-    phys_intmem = qemu_ram_alloc(NULL, "axisdev88.chipram", INTMEM_SIZE);
-    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
-                                 phys_intmem | IO_MEM_RAM);
-
+    memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE);
+    memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
 
       /* Attach a NAND flash to CS1.  */
-    nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+    nand = drive_get(IF_MTD, 0, 0);
+    nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
+                                NAND_MFR_STMICRO, 0x39);
     nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
                                        DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
@@ -312,16 +315,18 @@ void axisdev88_init (ram_addr_t ram_size,
     }
 
     /* Add the two ethernet blocks.  */
-    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
-    if (nb_nics > 1)
-        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
+    dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
+    etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
+    }
 
     /* The DMA Connector block is missing, hardwire things for now.  */
-    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
-    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
-    if (eth[1]) {
-        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
-        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
+        etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
     }
 
     /* 2 timers.  */
@@ -347,6 +352,7 @@ static QEMUMachine axisdev88_machine = {
     .name = "axis-dev88",
     .desc = "AXIS devboard 88",
     .init = axisdev88_init,
+    .is_default = 1,
 };
 
 static void axisdev88_machine_init(void)
index 21326ae82bf3e584e2529af002a793825304ef21..86d780a617e3157cf0309af8e81d664738d04574 100644 (file)
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -223,7 +223,7 @@ static void baum_accept_input(struct CharDriverState *chr)
 
     if (!baum->out_buf_used)
         return;
-    room = qemu_chr_can_read(chr);
+    room = qemu_chr_be_can_write(chr);
     if (!room)
         return;
     if (room > baum->out_buf_used)
@@ -231,12 +231,12 @@ static void baum_accept_input(struct CharDriverState *chr)
 
     first = BUF_SIZE - baum->out_buf_ptr;
     if (room > first) {
-        qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first);
+        qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first);
         baum->out_buf_ptr = 0;
         baum->out_buf_used -= first;
         room -= first;
     }
-    qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room);
+    qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room);
     baum->out_buf_ptr += room;
     baum->out_buf_used -= room;
 }
@@ -250,16 +250,16 @@ static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len
     while (len--)
         if ((*cur++ = *buf++) == ESC)
             *cur++ = ESC;
-    room = qemu_chr_can_read(baum->chr);
+    room = qemu_chr_be_can_write(baum->chr);
     len = cur - io_buf;
     if (len <= room) {
         /* Fits */
-        qemu_chr_read(baum->chr, io_buf, len);
+        qemu_chr_be_write(baum->chr, io_buf, len);
     } else {
         int first;
         uint8_t out;
         /* Can't fit all, send what can be, and store the rest. */
-        qemu_chr_read(baum->chr, io_buf, room);
+        qemu_chr_be_write(baum->chr, io_buf, room);
         len -= room;
         cur = io_buf + room;
         if (len > BUF_SIZE - baum->out_buf_used) {
@@ -335,7 +335,7 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
         int i;
 
         /* Allow 100ms to complete the DisplayData packet */
-        qemu_mod_timer(baum->cellCount_timer, qemu_get_clock(vm_clock) +
+        qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) +
                        get_ticks_per_sec() / 10);
         for (i = 0; i < baum->x * baum->y ; i++) {
             EAT(c);
@@ -468,20 +468,6 @@ static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
     return orig_len;
 }
 
-/* The other end sent us some event */
-static void baum_send_event(CharDriverState *chr, int event)
-{
-    BaumDriverState *baum = chr->opaque;
-    switch (event) {
-    case CHR_EVENT_BREAK:
-        break;
-    case CHR_EVENT_OPENED:
-        /* Reset state */
-        baum->in_buf_used = 0;
-        break;
-    }
-}
-
 /* Send the key code to the other end */
 static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
     uint8_t packet[] = { type, value };
@@ -559,7 +545,7 @@ static void baum_chr_read(void *opaque)
     if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
         brlapi_perror("baum: brlapi_readKey");
         brlapi__closeConnection(baum->brlapi);
-        qemu_free(baum->brlapi);
+        g_free(baum->brlapi);
         baum->brlapi = NULL;
     }
 }
@@ -571,12 +557,12 @@ static void baum_close(struct CharDriverState *chr)
     qemu_free_timer(baum->cellCount_timer);
     if (baum->brlapi) {
         brlapi__closeConnection(baum->brlapi);
-        qemu_free(baum->brlapi);
+        g_free(baum->brlapi);
     }
-    qemu_free(baum);
+    g_free(baum);
 }
 
-CharDriverState *chr_baum_init(QemuOpts *opts)
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
 {
     BaumDriverState *baum;
     CharDriverState *chr;
@@ -586,16 +572,15 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
 #endif
     int tty;
 
-    baum = qemu_mallocz(sizeof(BaumDriverState));
-    baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
+    baum = g_malloc0(sizeof(BaumDriverState));
+    baum->chr = chr = g_malloc0(sizeof(CharDriverState));
 
     chr->opaque = baum;
     chr->chr_write = baum_write;
-    chr->chr_send_event = baum_send_event;
     chr->chr_accept_input = baum_accept_input;
     chr->chr_close = baum_close;
 
-    handle = qemu_mallocz(brlapi_getHandleSize());
+    handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
 
     baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
@@ -604,7 +589,7 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
         goto fail_handle;
     }
 
-    baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum);
+    baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum);
 
     if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
         brlapi_perror("baum_init: brlapi_getDisplaySize");
@@ -629,14 +614,15 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
 
     qemu_chr_generic_open(chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 
 fail:
     qemu_free_timer(baum->cellCount_timer);
     brlapi__closeConnection(handle);
 fail_handle:
-    qemu_free(handle);
-    qemu_free(chr);
-    qemu_free(baum);
-    return NULL;
+    g_free(handle);
+    g_free(chr);
+    g_free(baum);
+    return -EIO;
 }
index 8af710fa21069accb1fef8e62dd2a4fb390314b5..3f28cc339a249d34f81d8672c68b7b4e2db82e0b 100644 (file)
--- a/hw/baum.h
+++ b/hw/baum.h
@@ -23,4 +23,4 @@
  */
 
 /* char device */
-CharDriverState *chr_baum_init(QemuOpts *opts);
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);
index 4ee99a18b94a7610baeb081e202b04c054523d5c..431359d615c1c3e76ad11cb4c904e6346e3e34ec 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2008 Jan Kiszka
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 #include "hw.h"
 #include "bitbang_i2c.h"
@@ -38,7 +38,8 @@ typedef enum bitbang_i2c_state {
     RECEIVING_BIT2,
     RECEIVING_BIT1,
     RECEIVING_BIT0,
-    SENDING_ACK
+    SENDING_ACK,
+    SENT_NACK
 } bitbang_i2c_state;
 
 struct bitbang_i2c_interface {
@@ -115,6 +116,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
     }
     switch (i2c->state) {
     case STOPPED:
+    case SENT_NACK:
         return bitbang_i2c_ret(i2c, 1);
 
     case SENDING_BIT7 ... SENDING_BIT0:
@@ -155,6 +157,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
         i2c->state = RECEIVING_BIT7;
         if (data != 0) {
             DPRINTF("NACKED\n");
+            i2c->state = SENT_NACK;
             i2c_nack(i2c->bus);
         } else {
             DPRINTF("ACKED\n");
@@ -168,7 +171,7 @@ bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
 {
     bitbang_i2c_interface *s;
 
-    s = qemu_mallocz(sizeof(bitbang_i2c_interface));
+    s = g_malloc0(sizeof(bitbang_i2c_interface));
 
     s->bus = bus;
     s->last_data = 1;
index 5f329ad13fee46115f486dbfd52e5ac96a9afa25..b2c1b22844c2bbf1d8cec23a849ff194c00ecd19 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "console.h"
 #include "devices.h"
 #include "vga_int.h"
@@ -189,7 +188,7 @@ static int blizzard_transfer_setup(BlizzardState *s)
     s->data.len = s->bpp * s->data.dx * s->data.dy;
     s->data.pitch = s->data.dx;
     if (s->data.len > s->data.buflen) {
-        s->data.buf = qemu_realloc(s->data.buf, s->data.len);
+        s->data.buf = g_realloc(s->data.buf, s->data.len);
         s->data.buflen = s->data.len;
     }
     s->data.ptr = s->data.buf;
@@ -954,9 +953,9 @@ static void blizzard_screen_dump(void *opaque, const char *filename) {
 
 void *s1d13745_init(qemu_irq gpio_int)
 {
-    BlizzardState *s = (BlizzardState *) qemu_mallocz(sizeof(*s));
+    BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
 
-    s->fb = qemu_malloc(0x180000);
+    s->fb = g_malloc(0x180000);
 
     s->state = graphic_console_init(blizzard_update_display,
                                  blizzard_invalidate_display,
@@ -965,7 +964,7 @@ void *s1d13745_init(qemu_irq gpio_int)
     switch (ds_get_bits_per_pixel(s->state)) {
     case 0:
         s->line_fn_tab[0] = s->line_fn_tab[1] =
-                qemu_mallocz(sizeof(blizzard_fn_t) * 0x10);
+                g_malloc0(sizeof(blizzard_fn_t) * 0x10);
         break;
     case 8:
         s->line_fn_tab[0] = blizzard_draw_fn_8;
index 6f0f0d79259e3601e1c6cb5f002379e4b2284eb1..716fd7b1a66627509ef87ef62a3b49537539d004 100644 (file)
@@ -27,6 +27,7 @@ typedef struct QEMUMachine {
         no_cdrom:1,
         no_sdcard:1;
     int is_default;
+    const char *default_machine_opts;
     GlobalProperty *compat_props;
     struct QEMUMachine *next;
 } QEMUMachine;
index 65a4a637bf508d1022df542f7e8ad07e19d7ab8c..fdb8198f62580f3e91f112e62722ff429ce29c6c 100644 (file)
@@ -42,6 +42,7 @@
 #include "mips.h"
 #include "pci_host.h"
 #include "sysemu.h"
+#include "exec-memory.h"
 
 //#define DEBUG_BONITO
 
@@ -240,7 +241,7 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 
     saddr = (addr - BONITO_REGBASE) >> 2;
 
-    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x \n", addr, val, saddr);
+    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
     switch (saddr) {
     case BONITO_BONPONCFG:
     case BONITO_IODEVCFG:
@@ -286,10 +287,10 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         break;
     case BONITO_INTEN:
     case BONITO_INTISR:
-        DPRINTF("write to readonly bonito register %x \n", saddr);
+        DPRINTF("write to readonly bonito register %x\n", saddr);
         break;
     default:
-        DPRINTF("write to unknown bonito register %x \n", saddr);
+        DPRINTF("write to unknown bonito register %x\n", saddr);
         break;
     }
 }
@@ -301,7 +302,7 @@ static uint32_t bonito_readl(void *opaque, target_phys_addr_t addr)
 
     saddr = (addr - BONITO_REGBASE) >> 2;
 
-    DPRINTF("bonito_readl "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
     switch (saddr) {
     case BONITO_INTISR:
         return s->regs[saddr];
@@ -327,7 +328,7 @@ static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr,
 {
     PCIBonitoState *s = opaque;
 
-    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
     s->dev.config_write(&s->dev, addr, val, 4);
 }
 
@@ -442,7 +443,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
         exit(1);
     }
     pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno);
-    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d \n",
+    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
         cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno);
 
     return pciaddr;
@@ -455,7 +456,7 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val);
     pciaddr = bonito_sbridge_pciaddr(s, addr);
 
     if (pciaddr == 0xffffffff) {
@@ -479,7 +480,7 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
     assert((addr&0x1)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -505,7 +506,7 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
     assert((addr&0x3)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -530,7 +531,7 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr);
     pciaddr = bonito_sbridge_pciaddr(s, addr);
 
     if (pciaddr == 0xffffffff) {
@@ -554,7 +555,7 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
     assert((addr&0x1)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -580,7 +581,7 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
     assert((addr&0x3) == 0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -691,11 +692,7 @@ static int bonito_initfn(PCIDevice *dev)
     PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
 
     /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
-    pci_config_set_vendor_id(dev->config, 0xdf53);
-    pci_config_set_device_id(dev->config, 0x00d5);
-    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
     pci_config_set_prog_interface(dev->config, 0x00);
-    pci_config_set_revision(dev->config, 0x01);
 
     /* set the north bridge register mapping */
     s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s,
@@ -777,7 +774,9 @@ PCIBus *bonito_init(qemu_irq *pic)
     dev = qdev_create(NULL, "Bonito-pcihost");
     pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
     b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
-                         pci_bonito_map_irq, pic, 0x28, 32);
+                         pci_bonito_map_irq, pic, get_system_memory(),
+                         get_system_io(),
+                         0x28, 32);
     pcihost->bus = b;
     qdev_init_nofail(dev);
 
@@ -796,6 +795,11 @@ static PCIDeviceInfo bonito_info = {
     .qdev.vmsd    = &vmstate_bonito,
     .qdev.no_user = 1,
     .init         = bonito_initfn,
+    /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
+    .vendor_id    = 0xdf53,
+    .device_id    = 0x00d5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_BRIDGE_HOST,
 };
 
 static SysBusDeviceInfo bonito_pcihost_info = {
index 982577d1bb95612be2156ec56b69e11732a8f92b..0dcf897421e90eb3938afc7092b5d2162333f84e 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"
 
@@ -88,7 +87,7 @@ static inline void csrhci_fifo_wake(struct csrhci_s *s)
     }
 
     if (s->out_len)
-        qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay);
+        qemu_mod_timer(s->out_tm, qemu_get_clock_ns(vm_clock) + s->baud_delay);
 }
 
 #define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
@@ -435,7 +434,7 @@ qemu_irq *csrhci_pins_get(CharDriverState *chr)
 CharDriverState *uart_hci_init(qemu_irq wakeup)
 {
     struct csrhci_s *s = (struct csrhci_s *)
-            qemu_mallocz(sizeof(struct csrhci_s));
+            g_malloc0(sizeof(struct csrhci_s));
 
     s->chr.opaque = s;
     s->chr.chr_write = csrhci_write;
@@ -446,7 +445,7 @@ CharDriverState *uart_hci_init(qemu_irq wakeup)
     s->hci->evt_recv = csrhci_out_hci_packet_event;
     s->hci->acl_recv = csrhci_out_hci_packet_acl;
 
-    s->out_tm = qemu_new_timer(vm_clock, csrhci_out_tick, s);
+    s->out_tm = qemu_new_timer_ns(vm_clock, csrhci_out_tick, s);
     s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
     csrhci_reset(s);
 
index f1ee92cfd4186cedc18bf364a914fd33cbe0f316..a3a7fb49e2ec9e9c2e4cdc5add2323feba0b8188 100644 (file)
@@ -576,7 +576,7 @@ static void bt_hci_inquiry_result(struct bt_hci_s *hci,
 
 static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
 {
-    qemu_mod_timer(timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) +
                    muldiv64(period << 7, get_ticks_per_sec(), 100));
 }
 
@@ -657,7 +657,7 @@ static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
     if (master) {
         link->acl_mode = acl_active;
         hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
-                qemu_new_timer(vm_clock, bt_hci_mode_tick, link);
+                qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link);
     }
 }
 
@@ -721,7 +721,7 @@ static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
 static void bt_hci_connection_accept(struct bt_hci_s *hci,
                 struct bt_device_s *host)
 {
-    struct bt_hci_link_s *link = qemu_mallocz(sizeof(struct bt_hci_link_s));
+    struct bt_hci_link_s *link = g_malloc0(sizeof(struct bt_hci_link_s));
     evt_conn_complete params;
     uint16_t handle;
     uint8_t status = HCI_SUCCESS;
@@ -736,7 +736,7 @@ static void bt_hci_connection_accept(struct bt_hci_s *hci,
             tries);
 
     if (!tries) {
-        qemu_free(link);
+        g_free(link);
         bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
         status = HCI_NO_CONNECTION;
         goto complete;
@@ -893,7 +893,7 @@ static void bt_hci_disconnect(struct bt_hci_s *hci,
 
     /* We are the slave, we get to clean this burden */
     link = (struct bt_hci_link_s *) btlink;
-    qemu_free(link);
+    g_free(link);
 
 complete:
     bt_hci_lmp_link_teardown(hci, handle);
@@ -928,7 +928,7 @@ static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
     uint16_t handle = link->handle;
     evt_disconn_complete params;
 
-    qemu_free(link);
+    g_free(link);
 
     bt_hci_lmp_link_teardown(hci, handle);
 
@@ -1084,7 +1084,7 @@ static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
 
     bt_hci_event_status(hci, HCI_SUCCESS);
 
-    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) +
                    muldiv64(interval * 625, get_ticks_per_sec(), 1000000));
     bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
 
@@ -1138,7 +1138,7 @@ static void bt_hci_reset(struct bt_hci_s *hci)
     hci->device.inquiry_scan = 0;
     hci->device.page_scan = 0;
     if (hci->device.lmp_name)
-        qemu_free((void *) hci->device.lmp_name);
+        g_free((void *) hci->device.lmp_name);
     hci->device.lmp_name = NULL;
     hci->device.class[0] = 0x00;
     hci->device.class[1] = 0x00;
@@ -1816,8 +1816,8 @@ static void bt_submit_hci(struct HCIInfo *info,
         LENGTH_CHECK(change_local_name);
 
         if (hci->device.lmp_name)
-            qemu_free((void *) hci->device.lmp_name);
-        hci->device.lmp_name = qemu_strndup(PARAM(change_local_name, name),
+            g_free((void *) hci->device.lmp_name);
+        hci->device.lmp_name = g_strndup(PARAM(change_local_name, name),
                         sizeof(PARAM(change_local_name, name)));
         bt_hci_event_complete_status(hci, HCI_SUCCESS);
         break;
@@ -2143,12 +2143,12 @@ static void bt_hci_destroy(struct bt_device_s *dev)
 
 struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
 {
-    struct bt_hci_s *s = qemu_mallocz(sizeof(struct bt_hci_s));
+    struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s));
 
-    s->lm.inquiry_done = qemu_new_timer(vm_clock, bt_hci_inquiry_done, s);
-    s->lm.inquiry_next = qemu_new_timer(vm_clock, bt_hci_inquiry_next, s);
+    s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s);
+    s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s);
     s->conn_accept_timer =
-            qemu_new_timer(vm_clock, bt_hci_conn_accept_timeout, s);
+            qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s);
 
     s->evt_packet = bt_hci_evt_packet;
     s->evt_submit = bt_hci_evt_submit;
@@ -2188,7 +2188,7 @@ static void bt_hci_done(struct HCIInfo *info)
     bt_device_done(&hci->device);
 
     if (hci->device.lmp_name)
-        qemu_free((void *) hci->device.lmp_name);
+        g_free((void *) hci->device.lmp_name);
 
     /* Be gentle and send DISCONNECT to all connected peers and those
      * currently waiting for us to accept or reject a connection request.
@@ -2217,5 +2217,5 @@ static void bt_hci_done(struct HCIInfo *info)
     qemu_free_timer(hci->lm.inquiry_next);
     qemu_free_timer(hci->conn_accept_timer);
 
-    qemu_free(hci);
+    g_free(hci);
 }
index abdfd35e8647f1a1cda651bf34112b33265d5d0e..8d7a3dae219d20756946e79c5eb62e6595aebcdc 100644 (file)
@@ -19,7 +19,9 @@
  */
 
 #include "qemu-common.h"
-#include "usb.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "hid.h"
 #include "bt.h"
 
 enum hid_transaction_req {
@@ -86,7 +88,7 @@ struct bt_hid_device_s {
     struct bt_l2cap_device_s btdev;
     struct bt_l2cap_conn_params_s *control;
     struct bt_l2cap_conn_params_s *interrupt;
-    USBDevice *usbdev;
+    HIDState hid;
 
     int proto;
     int connected;
@@ -111,7 +113,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
     bt_l2cap_device_done(&s->btdev);
     bt_l2cap_device_init(&s->btdev, net);
 
-    s->usbdev->info->handle_reset(s->usbdev);
+    hid_reset(&s->hid);
     s->proto = BT_HID_PROTO_REPORT;
     s->state = bt_state_ready;
     s->dataother.len = 0;
@@ -124,23 +126,16 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
 
 static int bt_hid_out(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
     if (s->data_type == BT_DATA_OUTPUT) {
-        p.pid = USB_TOKEN_OUT;
-        p.devep = 1;
-        p.data = s->dataout.buffer;
-        p.len = s->dataout.len;
-        s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
-
-        return s->dataout.len;
+        /* nothing */
+        ;
     }
 
     if (s->data_type == BT_DATA_FEATURE) {
         /* XXX:
          * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
          * or a SET_REPORT? */
-        p.devep = 0;
+        ;
     }
 
     return -1;
@@ -148,14 +143,8 @@ static int bt_hid_out(struct bt_hid_device_s *s)
 
 static int bt_hid_in(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
-    p.pid = USB_TOKEN_IN;
-    p.devep = 1;
-    p.data = s->datain.buffer;
-    p.len = sizeof(s->datain.buffer);
-    s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
-
+    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
+                                      sizeof(s->datain.buffer));
     return s->datain.len;
 }
 
@@ -323,8 +312,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
         s->proto = parameter;
-        s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
-                                        NULL);
+        s->hid.protocol = parameter;
         ret = BT_HS_SUCCESSFUL;
         break;
 
@@ -333,8 +321,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             ret = BT_HS_ERR_INVALID_PARAMETER;
             break;
         }
-        s->usbdev->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
-                        s->control->sdu_out(s->control, 1));
+        *s->control->sdu_out(s->control, 1) = s->hid.idle;
         s->control->sdu_submit(s->control);
         break;
 
@@ -344,11 +331,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
 
-        /* We don't need to know about the Idle Rate here really,
-         * so just pass it on to the device.  */
-        ret = s->usbdev->info->handle_control(s->usbdev,
-                        SET_IDLE, data[1], 0, 0, NULL) ?
-                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+        s->hid.idle = data[1];
         /* XXX: Does this generate a handshake? */
         break;
 
@@ -385,9 +368,10 @@ static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
     bt_hid_control_transaction(hid, data, len);
 }
 
-static void bt_hid_datain(void *opaque)
+static void bt_hid_datain(HIDState *hs)
 {
-    struct bt_hid_device_s *hid = opaque;
+    struct bt_hid_device_s *hid =
+        container_of(hs, struct bt_hid_device_s, hid);
 
     /* If suspended, wake-up and send a wake-up event first.  We might
      * want to also inspect the input report and ignore event like
@@ -450,7 +434,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
     hid->btdev.device.inquiry_scan = !hid->connected;
 
     if (hid->connected && !prev) {
-        hid->usbdev->info->handle_reset(hid->usbdev);
+        hid_reset(&hid->hid);
         hid->proto = BT_HID_PROTO_REPORT;
     }
 
@@ -518,9 +502,9 @@ static void bt_hid_destroy(struct bt_device_s *dev)
         bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
     bt_l2cap_device_done(&hid->btdev);
 
-    hid->usbdev->info->handle_destroy(hid->usbdev);
+    hid_free(&hid->hid);
 
-    qemu_free(hid);
+    g_free(hid);
 }
 
 enum peripheral_minor_class {
@@ -531,9 +515,9 @@ enum peripheral_minor_class {
 };
 
 static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
-                USBDevice *dev, enum peripheral_minor_class minor)
+                                       enum peripheral_minor_class minor)
 {
-    struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
+    struct bt_hid_device_s *s = g_malloc0(sizeof(*s));
     uint32_t class =
             /* Format type */
             (0 << 0) |
@@ -551,9 +535,8 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
     bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
                     BT_HID_MTU, bt_hid_new_interrupt_ch);
 
-    s->usbdev = dev;
-    s->btdev.device.lmp_name = s->usbdev->product_desc;
-    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
+    s->btdev.device.lmp_name = "BT Keyboard";
 
     s->btdev.device.handle_destroy = bt_hid_destroy;
 
@@ -566,6 +549,5 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
 
 struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
 {
-    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
-    return bt_hid_init(net, dev, class_keyboard);
+    return bt_hid_init(net, class_keyboard);
 }
index 7e2f668e5a327afc78dbddf76858b67bcdea572f..2ccba6071c89dd04c36b0c09b85c8a81b3fe75b7 100644 (file)
@@ -410,7 +410,7 @@ static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
 
         if (psm_info) {
             /* Device supports this use-case.  */
-            ch = qemu_mallocz(sizeof(*ch));
+            ch = g_malloc0(sizeof(*ch));
             ch->params.sdu_out = l2cap_bframe_out;
             ch->params.sdu_submit = l2cap_bframe_submit;
             ch->frame_in = l2cap_bframe_in;
@@ -428,7 +428,7 @@ static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
                 result = L2CAP_CR_SUCCESS;
                 status = L2CAP_CS_NO_INFO;
             } else {
-                qemu_free(ch);
+                g_free(ch);
 
                 result = L2CAP_CR_NO_MEM;
                 status = L2CAP_CS_NO_INFO;
@@ -473,7 +473,7 @@ static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
         l2cap->cid[cid] = NULL;
 
         ch->params.close(ch->params.opaque);
-        qemu_free(ch);
+        g_free(ch);
     }
 
     l2cap_disconnection_response(l2cap, cid, source_cid);
@@ -1218,13 +1218,13 @@ static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
     for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
         if (l2cap->cid[cid]) {
             l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
-            qemu_free(l2cap->cid[cid]);
+            g_free(l2cap->cid[cid]);
         }
 
     if (l2cap->role)
-        qemu_free(l2cap);
+        g_free(l2cap);
     else
-        qemu_free(l2cap->link);
+        g_free(l2cap->link);
 }
 
 /* L2CAP glue to lower layers in bluetooth stack (LMP) */
@@ -1236,7 +1236,7 @@ static void l2cap_lmp_connection_request(struct bt_link_s *link)
 
     /* Always accept - we only get called if (dev->device->page_scan).  */
 
-    l2cap = qemu_mallocz(sizeof(struct slave_l2cap_instance_s));
+    l2cap = g_malloc0(sizeof(struct slave_l2cap_instance_s));
     l2cap->link.slave = &dev->device;
     l2cap->link.host = link->host;
     l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
@@ -1257,7 +1257,7 @@ static void l2cap_lmp_connection_complete(struct bt_link_s *link)
         return;
     }
 
-    l2cap = qemu_mallocz(sizeof(struct l2cap_instance_s));
+    l2cap = g_malloc0(sizeof(struct l2cap_instance_s));
     l2cap_init(l2cap, link, 1);
 
     link->acl_mode = acl_active;
@@ -1353,7 +1353,7 @@ void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
         exit(-1);
     }
 
-    new_psm = qemu_mallocz(sizeof(*new_psm));
+    new_psm = g_malloc0(sizeof(*new_psm));
     new_psm->psm = psm;
     new_psm->min_mtu = min_mtu;
     new_psm->new_channel = new_channel;
index cdf2d95d52e52fe280a560ad7dd52ac6416222b6..3e390ab5b98124b6329bfc4d2cb6cb48c2ffc81e 100644 (file)
@@ -567,12 +567,12 @@ static void bt_l2cap_sdp_close_ch(void *opaque)
     int i;
 
     for (i = 0; i < sdp->services; i ++) {
-        qemu_free(sdp->service_list[i].attribute_list->pair);
-        qemu_free(sdp->service_list[i].attribute_list);
-        qemu_free(sdp->service_list[i].uuid);
+        g_free(sdp->service_list[i].attribute_list->pair);
+        g_free(sdp->service_list[i].attribute_list);
+        g_free(sdp->service_list[i].uuid);
     }
-    qemu_free(sdp->service_list);
-    qemu_free(sdp);
+    g_free(sdp->service_list);
+    g_free(sdp);
 }
 
 struct sdp_def_service_s {
@@ -709,10 +709,10 @@ static void sdp_service_record_build(struct sdp_service_record_s *record,
     }
     record->uuids = 1 << ffs(record->uuids - 1);
     record->attribute_list =
-            qemu_mallocz(record->attributes * sizeof(*record->attribute_list));
+            g_malloc0(record->attributes * sizeof(*record->attribute_list));
     record->uuid =
-            qemu_mallocz(record->uuids * sizeof(*record->uuid));
-    data = qemu_malloc(len);
+            g_malloc0(record->uuids * sizeof(*record->uuid));
+    data = g_malloc(len);
 
     record->attributes = 0;
     uuid = record->uuid;
@@ -753,7 +753,7 @@ static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
     while (service[sdp->services])
         sdp->services ++;
     sdp->service_list =
-            qemu_mallocz(sdp->services * sizeof(*sdp->service_list));
+            g_malloc0(sdp->services * sizeof(*sdp->service_list));
 
     sdp->services = 0;
     while (*service) {
@@ -942,7 +942,7 @@ SERVICE(pnp,
 static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
                 struct bt_l2cap_conn_params_s *params)
 {
-    struct bt_l2cap_sdp_state_s *sdp = qemu_mallocz(sizeof(*sdp));
+    struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp));
     struct sdp_def_service_s *services[] = {
         &sdp_service_sdp_s,
         &sdp_service_hid_s,
diff --git a/hw/bt.c b/hw/bt.c
index 34bf004572af48d8c15bbda121d90137dc9db052..dc99fc28fabe2be33bf14638c5c94f67735eae34 100644 (file)
--- a/hw/bt.c
+++ b/hw/bt.c
@@ -54,7 +54,7 @@ static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
 /* Slaves that don't hold any additional per link state can use these */
 static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
 {
-    struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s));
+    struct bt_link_s *link = g_malloc0(sizeof(struct bt_link_s));
 
     link->slave = req->slave;
     link->host = req->host;
@@ -65,13 +65,13 @@ static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
 
 static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
 {
-    qemu_free(link);
+    g_free(link);
 }
 
 static void bt_dummy_destroy(struct bt_device_s *device)
 {
     bt_device_done(device);
-    qemu_free(device);
+    g_free(device);
 }
 
 static int bt_dev_idx = 0;
diff --git a/hw/bt.h b/hw/bt.h
index 4a702adef756c58bf07bd28fe5a127d0e6681103..a48b8d4b133783cccdac9f5eb85edd11e59413e7 100644 (file)
--- a/hw/bt.h
+++ b/hw/bt.h
@@ -26,7 +26,7 @@
 /* BD Address */
 typedef struct {
     uint8_t b[6];
-} __attribute__((packed)) bdaddr_t;
+} QEMU_PACKED bdaddr_t;
 
 #define BDADDR_ANY     (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
 #define BDADDR_ALL     (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
@@ -446,13 +446,13 @@ typedef struct {
     uint8_t    lap[3];
     uint8_t    length;         /* 1.28s units */
     uint8_t    num_rsp;
-} __attribute__ ((packed)) inquiry_cp;
+} QEMU_PACKED inquiry_cp;
 #define INQUIRY_CP_SIZE 5
 
 typedef struct {
     uint8_t            status;
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) status_bdaddr_rp;
+} QEMU_PACKED status_bdaddr_rp;
 #define STATUS_BDADDR_RP_SIZE 7
 
 #define OCF_INQUIRY_CANCEL             0x0002
@@ -464,7 +464,7 @@ typedef struct {
     uint8_t    lap[3];
     uint8_t    length;         /* 1.28s units */
     uint8_t    num_rsp;
-} __attribute__ ((packed)) periodic_inquiry_cp;
+} QEMU_PACKED periodic_inquiry_cp;
 #define PERIODIC_INQUIRY_CP_SIZE 9
 
 #define OCF_EXIT_PERIODIC_INQUIRY      0x0004
@@ -477,55 +477,55 @@ typedef struct {
     uint8_t    pscan_mode;
     uint16_t   clock_offset;
     uint8_t    role_switch;
-} __attribute__ ((packed)) create_conn_cp;
+} QEMU_PACKED create_conn_cp;
 #define CREATE_CONN_CP_SIZE 13
 
 #define OCF_DISCONNECT                 0x0006
 typedef struct {
     uint16_t   handle;
     uint8_t    reason;
-} __attribute__ ((packed)) disconnect_cp;
+} QEMU_PACKED disconnect_cp;
 #define DISCONNECT_CP_SIZE 3
 
 #define OCF_ADD_SCO                    0x0007
 typedef struct {
     uint16_t   handle;
     uint16_t   pkt_type;
-} __attribute__ ((packed)) add_sco_cp;
+} QEMU_PACKED add_sco_cp;
 #define ADD_SCO_CP_SIZE 4
 
 #define OCF_CREATE_CONN_CANCEL         0x0008
 typedef struct {
     uint8_t    status;
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) create_conn_cancel_cp;
+} QEMU_PACKED create_conn_cancel_cp;
 #define CREATE_CONN_CANCEL_CP_SIZE 6
 
 typedef struct {
     uint8_t    status;
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) create_conn_cancel_rp;
+} QEMU_PACKED create_conn_cancel_rp;
 #define CREATE_CONN_CANCEL_RP_SIZE 7
 
 #define OCF_ACCEPT_CONN_REQ            0x0009
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    role;
-} __attribute__ ((packed)) accept_conn_req_cp;
+} QEMU_PACKED accept_conn_req_cp;
 #define ACCEPT_CONN_REQ_CP_SIZE        7
 
 #define OCF_REJECT_CONN_REQ            0x000A
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    reason;
-} __attribute__ ((packed)) reject_conn_req_cp;
+} QEMU_PACKED reject_conn_req_cp;
 #define REJECT_CONN_REQ_CP_SIZE        7
 
 #define OCF_LINK_KEY_REPLY             0x000B
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    link_key[16];
-} __attribute__ ((packed)) link_key_reply_cp;
+} QEMU_PACKED link_key_reply_cp;
 #define LINK_KEY_REPLY_CP_SIZE 22
 
 #define OCF_LINK_KEY_NEG_REPLY         0x000C
@@ -535,7 +535,7 @@ typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    pin_len;
     uint8_t    pin_code[16];
-} __attribute__ ((packed)) pin_code_reply_cp;
+} QEMU_PACKED pin_code_reply_cp;
 #define PIN_CODE_REPLY_CP_SIZE 23
 
 #define OCF_PIN_CODE_NEG_REPLY         0x000E
@@ -544,32 +544,32 @@ typedef struct {
 typedef struct {
     uint16_t    handle;
     uint16_t    pkt_type;
-} __attribute__ ((packed)) set_conn_ptype_cp;
+} QEMU_PACKED set_conn_ptype_cp;
 #define SET_CONN_PTYPE_CP_SIZE 4
 
 #define OCF_AUTH_REQUESTED             0x0011
 typedef struct {
     uint16_t    handle;
-} __attribute__ ((packed)) auth_requested_cp;
+} QEMU_PACKED auth_requested_cp;
 #define AUTH_REQUESTED_CP_SIZE 2
 
 #define OCF_SET_CONN_ENCRYPT           0x0013
 typedef struct {
     uint16_t   handle;
     uint8_t    encrypt;
-} __attribute__ ((packed)) set_conn_encrypt_cp;
+} QEMU_PACKED set_conn_encrypt_cp;
 #define SET_CONN_ENCRYPT_CP_SIZE 3
 
 #define OCF_CHANGE_CONN_LINK_KEY       0x0015
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) change_conn_link_key_cp;
+} QEMU_PACKED change_conn_link_key_cp;
 #define CHANGE_CONN_LINK_KEY_CP_SIZE 2
 
 #define OCF_MASTER_LINK_KEY            0x0017
 typedef struct {
     uint8_t    key_flag;
-} __attribute__ ((packed)) master_link_key_cp;
+} QEMU_PACKED master_link_key_cp;
 #define MASTER_LINK_KEY_CP_SIZE 1
 
 #define OCF_REMOTE_NAME_REQ            0x0019
@@ -578,50 +578,50 @@ typedef struct {
     uint8_t    pscan_rep_mode;
     uint8_t    pscan_mode;
     uint16_t   clock_offset;
-} __attribute__ ((packed)) remote_name_req_cp;
+} QEMU_PACKED remote_name_req_cp;
 #define REMOTE_NAME_REQ_CP_SIZE 10
 
 #define OCF_REMOTE_NAME_REQ_CANCEL     0x001A
 typedef struct {
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) remote_name_req_cancel_cp;
+} QEMU_PACKED remote_name_req_cancel_cp;
 #define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6
 
 typedef struct {
     uint8_t            status;
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) remote_name_req_cancel_rp;
+} QEMU_PACKED remote_name_req_cancel_rp;
 #define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7
 
 #define OCF_READ_REMOTE_FEATURES       0x001B
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_remote_features_cp;
+} QEMU_PACKED read_remote_features_cp;
 #define READ_REMOTE_FEATURES_CP_SIZE 2
 
 #define OCF_READ_REMOTE_EXT_FEATURES   0x001C
 typedef struct {
     uint16_t   handle;
     uint8_t    page_num;
-} __attribute__ ((packed)) read_remote_ext_features_cp;
+} QEMU_PACKED read_remote_ext_features_cp;
 #define READ_REMOTE_EXT_FEATURES_CP_SIZE 3
 
 #define OCF_READ_REMOTE_VERSION                0x001D
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_remote_version_cp;
+} QEMU_PACKED read_remote_version_cp;
 #define READ_REMOTE_VERSION_CP_SIZE 2
 
 #define OCF_READ_CLOCK_OFFSET          0x001F
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_clock_offset_cp;
+} QEMU_PACKED read_clock_offset_cp;
 #define READ_CLOCK_OFFSET_CP_SIZE 2
 
 #define OCF_READ_LMP_HANDLE            0x0020
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_lmp_handle_cp;
+} QEMU_PACKED read_lmp_handle_cp;
 #define READ_LMP_HANDLE_CP_SIZE 2
 
 typedef struct {
@@ -629,7 +629,7 @@ typedef struct {
     uint16_t   handle;
     uint8_t    lmp_handle;
     uint32_t   reserved;
-} __attribute__ ((packed)) read_lmp_handle_rp;
+} QEMU_PACKED read_lmp_handle_rp;
 #define READ_LMP_HANDLE_RP_SIZE 8
 
 #define OCF_SETUP_SYNC_CONN            0x0028
@@ -641,7 +641,7 @@ typedef struct {
     uint16_t   voice_setting;
     uint8_t    retrans_effort;
     uint16_t   pkt_type;
-} __attribute__ ((packed)) setup_sync_conn_cp;
+} QEMU_PACKED setup_sync_conn_cp;
 #define SETUP_SYNC_CONN_CP_SIZE 17
 
 #define OCF_ACCEPT_SYNC_CONN_REQ       0x0029
@@ -653,14 +653,14 @@ typedef struct {
     uint16_t   voice_setting;
     uint8_t    retrans_effort;
     uint16_t   pkt_type;
-} __attribute__ ((packed)) accept_sync_conn_req_cp;
+} QEMU_PACKED accept_sync_conn_req_cp;
 #define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21
 
 #define OCF_REJECT_SYNC_CONN_REQ       0x002A
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    reason;
-} __attribute__ ((packed)) reject_sync_conn_req_cp;
+} QEMU_PACKED reject_sync_conn_req_cp;
 #define REJECT_SYNC_CONN_REQ_CP_SIZE 7
 
 /* Link Policy */
@@ -671,7 +671,7 @@ typedef struct {
     uint16_t   handle;
     uint16_t   max_interval;
     uint16_t   min_interval;
-} __attribute__ ((packed)) hold_mode_cp;
+} QEMU_PACKED hold_mode_cp;
 #define HOLD_MODE_CP_SIZE 6
 
 #define OCF_SNIFF_MODE                 0x0003
@@ -681,13 +681,13 @@ typedef struct {
     uint16_t   min_interval;
     uint16_t   attempt;
     uint16_t   timeout;
-} __attribute__ ((packed)) sniff_mode_cp;
+} QEMU_PACKED sniff_mode_cp;
 #define SNIFF_MODE_CP_SIZE 10
 
 #define OCF_EXIT_SNIFF_MODE            0x0004
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) exit_sniff_mode_cp;
+} QEMU_PACKED exit_sniff_mode_cp;
 #define EXIT_SNIFF_MODE_CP_SIZE 2
 
 #define OCF_PARK_MODE                  0x0005
@@ -695,13 +695,13 @@ typedef struct {
     uint16_t   handle;
     uint16_t   max_interval;
     uint16_t   min_interval;
-} __attribute__ ((packed)) park_mode_cp;
+} QEMU_PACKED park_mode_cp;
 #define PARK_MODE_CP_SIZE 6
 
 #define OCF_EXIT_PARK_MODE             0x0006
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) exit_park_mode_cp;
+} QEMU_PACKED exit_park_mode_cp;
 #define EXIT_PARK_MODE_CP_SIZE 2
 
 #define OCF_QOS_SETUP                  0x0007
@@ -711,56 +711,56 @@ typedef struct {
     uint32_t   peak_bandwidth;         /* Byte per seconds */
     uint32_t   latency;                /* Microseconds */
     uint32_t   delay_variation;        /* Microseconds */
-} __attribute__ ((packed)) hci_qos;
+} QEMU_PACKED hci_qos;
 #define HCI_QOS_CP_SIZE 17
 typedef struct {
     uint16_t   handle;
     uint8_t    flags;                  /* Reserved */
     hci_qos    qos;
-} __attribute__ ((packed)) qos_setup_cp;
+} QEMU_PACKED qos_setup_cp;
 #define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
 
 #define OCF_ROLE_DISCOVERY             0x0009
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) role_discovery_cp;
+} QEMU_PACKED role_discovery_cp;
 #define ROLE_DISCOVERY_CP_SIZE 2
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    role;
-} __attribute__ ((packed)) role_discovery_rp;
+} QEMU_PACKED role_discovery_rp;
 #define ROLE_DISCOVERY_RP_SIZE 4
 
 #define OCF_SWITCH_ROLE                        0x000B
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    role;
-} __attribute__ ((packed)) switch_role_cp;
+} QEMU_PACKED switch_role_cp;
 #define SWITCH_ROLE_CP_SIZE 7
 
 #define OCF_READ_LINK_POLICY           0x000C
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_link_policy_cp;
+} QEMU_PACKED read_link_policy_cp;
 #define READ_LINK_POLICY_CP_SIZE 2
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint16_t   policy;
-} __attribute__ ((packed)) read_link_policy_rp;
+} QEMU_PACKED read_link_policy_rp;
 #define READ_LINK_POLICY_RP_SIZE 5
 
 #define OCF_WRITE_LINK_POLICY          0x000D
 typedef struct {
     uint16_t   handle;
     uint16_t   policy;
-} __attribute__ ((packed)) write_link_policy_cp;
+} QEMU_PACKED write_link_policy_cp;
 #define WRITE_LINK_POLICY_CP_SIZE 4
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-} __attribute__ ((packed)) write_link_policy_rp;
+} QEMU_PACKED write_link_policy_rp;
 #define WRITE_LINK_POLICY_RP_SIZE 3
 
 #define OCF_READ_DEFAULT_LINK_POLICY   0x000E
@@ -776,7 +776,7 @@ typedef struct {
     uint16_t   max_local_latency;
     uint16_t   min_remote_timeout;
     uint16_t   min_local_timeout;
-} __attribute__ ((packed)) sniff_subrate_cp;
+} QEMU_PACKED sniff_subrate_cp;
 #define SNIFF_SUBRATE_CP_SIZE 10
 
 /* Host Controller and Baseband */
@@ -785,7 +785,7 @@ typedef struct {
 #define OCF_SET_EVENT_MASK             0x0001
 typedef struct {
     uint8_t    mask[8];
-} __attribute__ ((packed)) set_event_mask_cp;
+} QEMU_PACKED set_event_mask_cp;
 #define SET_EVENT_MASK_CP_SIZE 8
 
 #define OCF_RESET                      0x0003
@@ -795,7 +795,7 @@ typedef struct {
     uint8_t    flt_type;
     uint8_t    cond_type;
     uint8_t    condition[0];
-} __attribute__ ((packed)) set_event_flt_cp;
+} QEMU_PACKED set_event_flt_cp;
 #define SET_EVENT_FLT_CP_SIZE 2
 
 enum bt_filter_type {
@@ -821,26 +821,26 @@ enum conn_setup_cond {
 #define OCF_FLUSH                      0x0008
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) flush_cp;
+} QEMU_PACKED flush_cp;
 #define FLUSH_CP_SIZE 2
 
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-} __attribute__ ((packed)) flush_rp;
+} QEMU_PACKED flush_rp;
 #define FLUSH_RP_SIZE 3
 
 #define OCF_READ_PIN_TYPE              0x0009
 typedef struct {
     uint8_t    status;
     uint8_t    pin_type;
-} __attribute__ ((packed)) read_pin_type_rp;
+} QEMU_PACKED read_pin_type_rp;
 #define READ_PIN_TYPE_RP_SIZE 2
 
 #define OCF_WRITE_PIN_TYPE             0x000A
 typedef struct {
     uint8_t    pin_type;
-} __attribute__ ((packed)) write_pin_type_cp;
+} QEMU_PACKED write_pin_type_cp;
 #define WRITE_PIN_TYPE_CP_SIZE 1
 
 #define OCF_CREATE_NEW_UNIT_KEY                0x000B
@@ -849,89 +849,89 @@ typedef struct {
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    read_all;
-} __attribute__ ((packed)) read_stored_link_key_cp;
+} QEMU_PACKED read_stored_link_key_cp;
 #define READ_STORED_LINK_KEY_CP_SIZE 7
 typedef struct {
     uint8_t    status;
     uint16_t   max_keys;
     uint16_t   num_keys;
-} __attribute__ ((packed)) read_stored_link_key_rp;
+} QEMU_PACKED read_stored_link_key_rp;
 #define READ_STORED_LINK_KEY_RP_SIZE 5
 
 #define OCF_WRITE_STORED_LINK_KEY      0x0011
 typedef struct {
     uint8_t    num_keys;
     /* variable length part */
-} __attribute__ ((packed)) write_stored_link_key_cp;
+} QEMU_PACKED write_stored_link_key_cp;
 #define WRITE_STORED_LINK_KEY_CP_SIZE 1
 typedef struct {
     uint8_t    status;
     uint8_t    num_keys;
-} __attribute__ ((packed)) write_stored_link_key_rp;
+} QEMU_PACKED write_stored_link_key_rp;
 #define READ_WRITE_LINK_KEY_RP_SIZE 2
 
 #define OCF_DELETE_STORED_LINK_KEY     0x0012
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    delete_all;
-} __attribute__ ((packed)) delete_stored_link_key_cp;
+} QEMU_PACKED delete_stored_link_key_cp;
 #define DELETE_STORED_LINK_KEY_CP_SIZE 7
 typedef struct {
     uint8_t    status;
     uint16_t   num_keys;
-} __attribute__ ((packed)) delete_stored_link_key_rp;
+} QEMU_PACKED delete_stored_link_key_rp;
 #define DELETE_STORED_LINK_KEY_RP_SIZE 3
 
 #define OCF_CHANGE_LOCAL_NAME          0x0013
 typedef struct {
     char       name[248];
-} __attribute__ ((packed)) change_local_name_cp;
+} QEMU_PACKED change_local_name_cp;
 #define CHANGE_LOCAL_NAME_CP_SIZE 248 
 
 #define OCF_READ_LOCAL_NAME            0x0014
 typedef struct {
     uint8_t    status;
     char       name[248];
-} __attribute__ ((packed)) read_local_name_rp;
+} QEMU_PACKED read_local_name_rp;
 #define READ_LOCAL_NAME_RP_SIZE 249 
 
 #define OCF_READ_CONN_ACCEPT_TIMEOUT   0x0015
 typedef struct {
     uint8_t    status;
     uint16_t   timeout;
-} __attribute__ ((packed)) read_conn_accept_timeout_rp;
+} QEMU_PACKED read_conn_accept_timeout_rp;
 #define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3
 
 #define OCF_WRITE_CONN_ACCEPT_TIMEOUT  0x0016
 typedef struct {
     uint16_t   timeout;
-} __attribute__ ((packed)) write_conn_accept_timeout_cp;
+} QEMU_PACKED write_conn_accept_timeout_cp;
 #define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2
 
 #define OCF_READ_PAGE_TIMEOUT          0x0017
 typedef struct {
     uint8_t    status;
     uint16_t   timeout;
-} __attribute__ ((packed)) read_page_timeout_rp;
+} QEMU_PACKED read_page_timeout_rp;
 #define READ_PAGE_TIMEOUT_RP_SIZE 3
 
 #define OCF_WRITE_PAGE_TIMEOUT         0x0018
 typedef struct {
     uint16_t   timeout;
-} __attribute__ ((packed)) write_page_timeout_cp;
+} QEMU_PACKED write_page_timeout_cp;
 #define WRITE_PAGE_TIMEOUT_CP_SIZE 2
 
 #define OCF_READ_SCAN_ENABLE           0x0019
 typedef struct {
     uint8_t    status;
     uint8_t    enable;
-} __attribute__ ((packed)) read_scan_enable_rp;
+} QEMU_PACKED read_scan_enable_rp;
 #define READ_SCAN_ENABLE_RP_SIZE 2
 
 #define OCF_WRITE_SCAN_ENABLE          0x001A
 typedef struct {
     uint8_t    scan_enable;
-} __attribute__ ((packed)) write_scan_enable_cp;
+} QEMU_PACKED write_scan_enable_cp;
 #define WRITE_SCAN_ENABLE_CP_SIZE 1
 
 enum scan_enable_bits {
@@ -945,14 +945,14 @@ typedef struct {
     uint8_t    status;
     uint16_t   interval;
     uint16_t   window;
-} __attribute__ ((packed)) read_page_activity_rp;
+} QEMU_PACKED read_page_activity_rp;
 #define READ_PAGE_ACTIVITY_RP_SIZE 5
 
 #define OCF_WRITE_PAGE_ACTIVITY                0x001C
 typedef struct {
     uint16_t   interval;
     uint16_t   window;
-} __attribute__ ((packed)) write_page_activity_cp;
+} QEMU_PACKED write_page_activity_cp;
 #define WRITE_PAGE_ACTIVITY_CP_SIZE 4
 
 #define OCF_READ_INQ_ACTIVITY          0x001D
@@ -960,14 +960,14 @@ typedef struct {
     uint8_t    status;
     uint16_t   interval;
     uint16_t   window;
-} __attribute__ ((packed)) read_inq_activity_rp;
+} QEMU_PACKED read_inq_activity_rp;
 #define READ_INQ_ACTIVITY_RP_SIZE 5
 
 #define OCF_WRITE_INQ_ACTIVITY         0x001E
 typedef struct {
     uint16_t   interval;
     uint16_t   window;
-} __attribute__ ((packed)) write_inq_activity_cp;
+} QEMU_PACKED write_inq_activity_cp;
 #define WRITE_INQ_ACTIVITY_CP_SIZE 4
 
 #define OCF_READ_AUTH_ENABLE           0x001F
@@ -989,26 +989,26 @@ typedef struct {
 typedef struct {
     uint8_t    status;
     uint8_t    dev_class[3];
-} __attribute__ ((packed)) read_class_of_dev_rp;
+} QEMU_PACKED read_class_of_dev_rp;
 #define READ_CLASS_OF_DEV_RP_SIZE 4 
 
 #define OCF_WRITE_CLASS_OF_DEV         0x0024
 typedef struct {
     uint8_t    dev_class[3];
-} __attribute__ ((packed)) write_class_of_dev_cp;
+} QEMU_PACKED write_class_of_dev_cp;
 #define WRITE_CLASS_OF_DEV_CP_SIZE 3
 
 #define OCF_READ_VOICE_SETTING         0x0025
 typedef struct {
     uint8_t    status;
     uint16_t   voice_setting;
-} __attribute__ ((packed)) read_voice_setting_rp;
+} QEMU_PACKED read_voice_setting_rp;
 #define READ_VOICE_SETTING_RP_SIZE 3
 
 #define OCF_WRITE_VOICE_SETTING                0x0026
 typedef struct {
     uint16_t   voice_setting;
-} __attribute__ ((packed)) write_voice_setting_cp;
+} QEMU_PACKED write_voice_setting_cp;
 #define WRITE_VOICE_SETTING_CP_SIZE 2
 
 #define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT       0x0027
@@ -1027,13 +1027,13 @@ typedef struct {
 typedef struct {
     uint16_t   handle;
     uint8_t    type;
-} __attribute__ ((packed)) read_transmit_power_level_cp;
+} QEMU_PACKED read_transmit_power_level_cp;
 #define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
     int8_t     level;
-} __attribute__ ((packed)) read_transmit_power_level_rp;
+} QEMU_PACKED read_transmit_power_level_rp;
 #define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4
 
 #define OCF_HOST_BUFFER_SIZE           0x0033
@@ -1042,7 +1042,7 @@ typedef struct {
     uint8_t    sco_mtu;
     uint16_t   acl_max_pkt;
     uint16_t   sco_max_pkt;
-} __attribute__ ((packed)) host_buffer_size_cp;
+} QEMU_PACKED host_buffer_size_cp;
 #define HOST_BUFFER_SIZE_CP_SIZE 7
 
 #define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS   0x0035
@@ -1052,19 +1052,19 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint16_t   link_sup_to;
-} __attribute__ ((packed)) read_link_supervision_timeout_rp;
+} QEMU_PACKED read_link_supervision_timeout_rp;
 #define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5
 
 #define OCF_WRITE_LINK_SUPERVISION_TIMEOUT     0x0037
 typedef struct {
     uint16_t   handle;
     uint16_t   link_sup_to;
-} __attribute__ ((packed)) write_link_supervision_timeout_cp;
+} QEMU_PACKED write_link_supervision_timeout_cp;
 #define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-} __attribute__ ((packed)) write_link_supervision_timeout_rp;
+} QEMU_PACKED write_link_supervision_timeout_rp;
 #define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3
 
 #define OCF_READ_NUM_SUPPORTED_IAC     0x0038
@@ -1075,14 +1075,14 @@ typedef struct {
     uint8_t    status;
     uint8_t    num_current_iac;
     uint8_t    lap[MAX_IAC_LAP][3];
-} __attribute__ ((packed)) read_current_iac_lap_rp;
+} QEMU_PACKED read_current_iac_lap_rp;
 #define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
 
 #define OCF_WRITE_CURRENT_IAC_LAP      0x003A
 typedef struct {
     uint8_t    num_current_iac;
     uint8_t    lap[MAX_IAC_LAP][3];
-} __attribute__ ((packed)) write_current_iac_lap_cp;
+} QEMU_PACKED write_current_iac_lap_cp;
 #define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP
 
 #define OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B
@@ -1096,45 +1096,45 @@ typedef struct {
 #define OCF_SET_AFH_CLASSIFICATION     0x003F
 typedef struct {
     uint8_t    map[10];
-} __attribute__ ((packed)) set_afh_classification_cp;
+} QEMU_PACKED set_afh_classification_cp;
 #define SET_AFH_CLASSIFICATION_CP_SIZE 10
 typedef struct {
     uint8_t    status;
-} __attribute__ ((packed)) set_afh_classification_rp;
+} QEMU_PACKED set_afh_classification_rp;
 #define SET_AFH_CLASSIFICATION_RP_SIZE 1
 
 #define OCF_READ_INQUIRY_SCAN_TYPE     0x0042
 typedef struct {
     uint8_t    status;
     uint8_t    type;
-} __attribute__ ((packed)) read_inquiry_scan_type_rp;
+} QEMU_PACKED read_inquiry_scan_type_rp;
 #define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2
 
 #define OCF_WRITE_INQUIRY_SCAN_TYPE    0x0043
 typedef struct {
     uint8_t    type;
-} __attribute__ ((packed)) write_inquiry_scan_type_cp;
+} QEMU_PACKED write_inquiry_scan_type_cp;
 #define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1
 typedef struct {
     uint8_t    status;
-} __attribute__ ((packed)) write_inquiry_scan_type_rp;
+} QEMU_PACKED write_inquiry_scan_type_rp;
 #define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1
 
 #define OCF_READ_INQUIRY_MODE          0x0044
 typedef struct {
     uint8_t    status;
     uint8_t    mode;
-} __attribute__ ((packed)) read_inquiry_mode_rp;
+} QEMU_PACKED read_inquiry_mode_rp;
 #define READ_INQUIRY_MODE_RP_SIZE 2
 
 #define OCF_WRITE_INQUIRY_MODE         0x0045
 typedef struct {
     uint8_t    mode;
-} __attribute__ ((packed)) write_inquiry_mode_cp;
+} QEMU_PACKED write_inquiry_mode_cp;
 #define WRITE_INQUIRY_MODE_CP_SIZE 1
 typedef struct {
     uint8_t    status;
-} __attribute__ ((packed)) write_inquiry_mode_rp;
+} QEMU_PACKED write_inquiry_mode_rp;
 #define WRITE_INQUIRY_MODE_RP_SIZE 1
 
 #define OCF_READ_PAGE_SCAN_TYPE                0x0046
@@ -1145,17 +1145,17 @@ typedef struct {
 typedef struct {
     uint8_t    status;
     uint8_t    mode;
-} __attribute__ ((packed)) read_afh_mode_rp;
+} QEMU_PACKED read_afh_mode_rp;
 #define READ_AFH_MODE_RP_SIZE 2
 
 #define OCF_WRITE_AFH_MODE             0x0049
 typedef struct {
     uint8_t    mode;
-} __attribute__ ((packed)) write_afh_mode_cp;
+} QEMU_PACKED write_afh_mode_cp;
 #define WRITE_AFH_MODE_CP_SIZE 1
 typedef struct {
     uint8_t    status;
-} __attribute__ ((packed)) write_afh_mode_rp;
+} QEMU_PACKED write_afh_mode_rp;
 #define WRITE_AFH_MODE_RP_SIZE 1
 
 #define OCF_READ_EXT_INQUIRY_RESPONSE  0x0051
@@ -1163,18 +1163,18 @@ typedef struct {
     uint8_t    status;
     uint8_t    fec;
     uint8_t    data[240];
-} __attribute__ ((packed)) read_ext_inquiry_response_rp;
+} QEMU_PACKED read_ext_inquiry_response_rp;
 #define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
 
 #define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052
 typedef struct {
     uint8_t    fec;
     uint8_t    data[240];
-} __attribute__ ((packed)) write_ext_inquiry_response_cp;
+} QEMU_PACKED write_ext_inquiry_response_cp;
 #define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
 typedef struct {
     uint8_t    status;
-} __attribute__ ((packed)) write_ext_inquiry_response_rp;
+} QEMU_PACKED write_ext_inquiry_response_rp;
 #define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1
 
 /* Informational Parameters */
@@ -1188,34 +1188,34 @@ typedef struct {
     uint8_t    lmp_ver;
     uint16_t   manufacturer;
     uint16_t   lmp_subver;
-} __attribute__ ((packed)) read_local_version_rp;
+} QEMU_PACKED read_local_version_rp;
 #define READ_LOCAL_VERSION_RP_SIZE 9
 
 #define OCF_READ_LOCAL_COMMANDS                0x0002
 typedef struct {
     uint8_t    status;
     uint8_t    commands[64];
-} __attribute__ ((packed)) read_local_commands_rp;
+} QEMU_PACKED read_local_commands_rp;
 #define READ_LOCAL_COMMANDS_RP_SIZE 65
 
 #define OCF_READ_LOCAL_FEATURES                0x0003
 typedef struct {
     uint8_t    status;
     uint8_t    features[8];
-} __attribute__ ((packed)) read_local_features_rp;
+} QEMU_PACKED read_local_features_rp;
 #define READ_LOCAL_FEATURES_RP_SIZE 9
 
 #define OCF_READ_LOCAL_EXT_FEATURES    0x0004
 typedef struct {
     uint8_t    page_num;
-} __attribute__ ((packed)) read_local_ext_features_cp;
+} QEMU_PACKED read_local_ext_features_cp;
 #define READ_LOCAL_EXT_FEATURES_CP_SIZE 1
 typedef struct {
     uint8_t    status;
     uint8_t    page_num;
     uint8_t    max_page_num;
     uint8_t    features[8];
-} __attribute__ ((packed)) read_local_ext_features_rp;
+} QEMU_PACKED read_local_ext_features_rp;
 #define READ_LOCAL_EXT_FEATURES_RP_SIZE 11
 
 #define OCF_READ_BUFFER_SIZE           0x0005
@@ -1225,21 +1225,21 @@ typedef struct {
     uint8_t    sco_mtu;
     uint16_t   acl_max_pkt;
     uint16_t   sco_max_pkt;
-} __attribute__ ((packed)) read_buffer_size_rp;
+} QEMU_PACKED read_buffer_size_rp;
 #define READ_BUFFER_SIZE_RP_SIZE 8
 
 #define OCF_READ_COUNTRY_CODE          0x0007
 typedef struct {
     uint8_t    status;
     uint8_t    country_code;
-} __attribute__ ((packed)) read_country_code_rp;
+} QEMU_PACKED read_country_code_rp;
 #define READ_COUNTRY_CODE_RP_SIZE 2
 
 #define OCF_READ_BD_ADDR               0x0009
 typedef struct {
     uint8_t    status;
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) read_bd_addr_rp;
+} QEMU_PACKED read_bd_addr_rp;
 #define READ_BD_ADDR_RP_SIZE 7
 
 /* Status params */
@@ -1250,27 +1250,27 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    counter;
-} __attribute__ ((packed)) read_failed_contact_counter_rp;
+} QEMU_PACKED read_failed_contact_counter_rp;
 #define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4
 
 #define OCF_RESET_FAILED_CONTACT_COUNTER       0x0002
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-} __attribute__ ((packed)) reset_failed_contact_counter_rp;
+} QEMU_PACKED reset_failed_contact_counter_rp;
 #define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
 
 #define OCF_READ_LINK_QUALITY          0x0003
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) read_link_quality_cp;
+} QEMU_PACKED read_link_quality_cp;
 #define READ_LINK_QUALITY_CP_SIZE 4
 
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    link_quality;
-} __attribute__ ((packed)) read_link_quality_rp;
+} QEMU_PACKED read_link_quality_rp;
 #define READ_LINK_QUALITY_RP_SIZE 4
 
 #define OCF_READ_RSSI                  0x0005
@@ -1278,7 +1278,7 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     int8_t     rssi;
-} __attribute__ ((packed)) read_rssi_rp;
+} QEMU_PACKED read_rssi_rp;
 #define READ_RSSI_RP_SIZE 4
 
 #define OCF_READ_AFH_MAP               0x0006
@@ -1287,21 +1287,21 @@ typedef struct {
     uint16_t   handle;
     uint8_t    mode;
     uint8_t    map[10];
-} __attribute__ ((packed)) read_afh_map_rp;
+} QEMU_PACKED read_afh_map_rp;
 #define READ_AFH_MAP_RP_SIZE 14
 
 #define OCF_READ_CLOCK                 0x0007
 typedef struct {
     uint16_t   handle;
     uint8_t    which_clock;
-} __attribute__ ((packed)) read_clock_cp;
+} QEMU_PACKED read_clock_cp;
 #define READ_CLOCK_CP_SIZE 3
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint32_t   clock;
     uint16_t   accuracy;
-} __attribute__ ((packed)) read_clock_rp;
+} QEMU_PACKED read_clock_rp;
 #define READ_CLOCK_RP_SIZE 9
 
 /* Testing commands */
@@ -1323,7 +1323,7 @@ typedef struct {
     uint8_t    pscan_mode;
     uint8_t    dev_class[3];
     uint16_t   clock_offset;
-} __attribute__ ((packed)) inquiry_info;
+} QEMU_PACKED inquiry_info;
 #define INQUIRY_INFO_SIZE 14
 
 #define EVT_CONN_COMPLETE              0x03
@@ -1333,7 +1333,7 @@ typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    link_type;
     uint8_t    encr_mode;
-} __attribute__ ((packed)) evt_conn_complete;
+} QEMU_PACKED evt_conn_complete;
 #define EVT_CONN_COMPLETE_SIZE 11
 
 #define EVT_CONN_REQUEST               0x04
@@ -1341,7 +1341,7 @@ typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    dev_class[3];
     uint8_t    link_type;
-} __attribute__ ((packed)) evt_conn_request;
+} QEMU_PACKED evt_conn_request;
 #define EVT_CONN_REQUEST_SIZE 10
 
 #define EVT_DISCONN_COMPLETE           0x05
@@ -1349,14 +1349,14 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    reason;
-} __attribute__ ((packed)) evt_disconn_complete;
+} QEMU_PACKED evt_disconn_complete;
 #define EVT_DISCONN_COMPLETE_SIZE 4
 
 #define EVT_AUTH_COMPLETE              0x06
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-} __attribute__ ((packed)) evt_auth_complete;
+} QEMU_PACKED evt_auth_complete;
 #define EVT_AUTH_COMPLETE_SIZE 3
 
 #define EVT_REMOTE_NAME_REQ_COMPLETE   0x07
@@ -1364,7 +1364,7 @@ typedef struct {
     uint8_t    status;
     bdaddr_t   bdaddr;
     char       name[248];
-} __attribute__ ((packed)) evt_remote_name_req_complete;
+} QEMU_PACKED evt_remote_name_req_complete;
 #define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
 
 #define EVT_ENCRYPT_CHANGE             0x08
@@ -1372,14 +1372,14 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    encrypt;
-} __attribute__ ((packed)) evt_encrypt_change;
+} QEMU_PACKED evt_encrypt_change;
 #define EVT_ENCRYPT_CHANGE_SIZE 5
 
 #define EVT_CHANGE_CONN_LINK_KEY_COMPLETE      0x09
 typedef struct {
     uint8_t    status;
     uint16_t   handle;
-}  __attribute__ ((packed)) evt_change_conn_link_key_complete;
+}  QEMU_PACKED evt_change_conn_link_key_complete;
 #define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3
 
 #define EVT_MASTER_LINK_KEY_COMPLETE           0x0A
@@ -1387,7 +1387,7 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    key_flag;
-} __attribute__ ((packed)) evt_master_link_key_complete;
+} QEMU_PACKED evt_master_link_key_complete;
 #define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4
 
 #define EVT_READ_REMOTE_FEATURES_COMPLETE      0x0B
@@ -1395,7 +1395,7 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint8_t    features[8];
-} __attribute__ ((packed)) evt_read_remote_features_complete;
+} QEMU_PACKED evt_read_remote_features_complete;
 #define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
 
 #define EVT_READ_REMOTE_VERSION_COMPLETE       0x0C
@@ -1405,7 +1405,7 @@ typedef struct {
     uint8_t    lmp_ver;
     uint16_t   manufacturer;
     uint16_t   lmp_subver;
-} __attribute__ ((packed)) evt_read_remote_version_complete;
+} QEMU_PACKED evt_read_remote_version_complete;
 #define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
 
 #define EVT_QOS_SETUP_COMPLETE         0x0D
@@ -1414,14 +1414,14 @@ typedef struct {
     uint16_t   handle;
     uint8_t    flags;                  /* Reserved */
     hci_qos    qos;
-} __attribute__ ((packed)) evt_qos_setup_complete;
+} QEMU_PACKED evt_qos_setup_complete;
 #define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
 
 #define EVT_CMD_COMPLETE               0x0E
 typedef struct {
     uint8_t    ncmd;
     uint16_t   opcode;
-} __attribute__ ((packed)) evt_cmd_complete;
+} QEMU_PACKED evt_cmd_complete;
 #define EVT_CMD_COMPLETE_SIZE 3
 
 #define EVT_CMD_STATUS                         0x0F
@@ -1429,19 +1429,19 @@ typedef struct {
     uint8_t    status;
     uint8_t    ncmd;
     uint16_t   opcode;
-} __attribute__ ((packed)) evt_cmd_status;
+} QEMU_PACKED evt_cmd_status;
 #define EVT_CMD_STATUS_SIZE 4
 
 #define EVT_HARDWARE_ERROR             0x10
 typedef struct {
     uint8_t    code;
-} __attribute__ ((packed)) evt_hardware_error;
+} QEMU_PACKED evt_hardware_error;
 #define EVT_HARDWARE_ERROR_SIZE 1
 
 #define EVT_FLUSH_OCCURRED             0x11
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) evt_flush_occured;
+} QEMU_PACKED evt_flush_occurred;
 #define EVT_FLUSH_OCCURRED_SIZE 2
 
 #define EVT_ROLE_CHANGE                        0x12
@@ -1449,7 +1449,7 @@ typedef struct {
     uint8_t    status;
     bdaddr_t   bdaddr;
     uint8_t    role;
-} __attribute__ ((packed)) evt_role_change;
+} QEMU_PACKED evt_role_change;
 #define EVT_ROLE_CHANGE_SIZE 8
 
 #define EVT_NUM_COMP_PKTS              0x13
@@ -1459,7 +1459,7 @@ typedef struct {
         uint16_t handle;
         uint16_t num_packets;
     } connection[0];
-} __attribute__ ((packed)) evt_num_comp_pkts;
+} QEMU_PACKED evt_num_comp_pkts;
 #define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl))
 
 #define EVT_MODE_CHANGE                        0x14
@@ -1468,26 +1468,26 @@ typedef struct {
     uint16_t   handle;
     uint8_t    mode;
     uint16_t   interval;
-} __attribute__ ((packed)) evt_mode_change;
+} QEMU_PACKED evt_mode_change;
 #define EVT_MODE_CHANGE_SIZE 6
 
 #define EVT_RETURN_LINK_KEYS           0x15
 typedef struct {
     uint8_t    num_keys;
     /* variable length part */
-} __attribute__ ((packed)) evt_return_link_keys;
+} QEMU_PACKED evt_return_link_keys;
 #define EVT_RETURN_LINK_KEYS_SIZE 1
 
 #define EVT_PIN_CODE_REQ               0x16
 typedef struct {
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) evt_pin_code_req;
+} QEMU_PACKED evt_pin_code_req;
 #define EVT_PIN_CODE_REQ_SIZE 6
 
 #define EVT_LINK_KEY_REQ               0x17
 typedef struct {
     bdaddr_t   bdaddr;
-} __attribute__ ((packed)) evt_link_key_req;
+} QEMU_PACKED evt_link_key_req;
 #define EVT_LINK_KEY_REQ_SIZE 6
 
 #define EVT_LINK_KEY_NOTIFY            0x18
@@ -1495,7 +1495,7 @@ typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    link_key[16];
     uint8_t    key_type;
-} __attribute__ ((packed)) evt_link_key_notify;
+} QEMU_PACKED evt_link_key_notify;
 #define EVT_LINK_KEY_NOTIFY_SIZE 23
 
 #define EVT_LOOPBACK_COMMAND           0x19
@@ -1503,14 +1503,14 @@ typedef struct {
 #define EVT_DATA_BUFFER_OVERFLOW       0x1A
 typedef struct {
     uint8_t    link_type;
-} __attribute__ ((packed)) evt_data_buffer_overflow;
+} QEMU_PACKED evt_data_buffer_overflow;
 #define EVT_DATA_BUFFER_OVERFLOW_SIZE 1
 
 #define EVT_MAX_SLOTS_CHANGE           0x1B
 typedef struct {
     uint16_t   handle;
     uint8_t    max_slots;
-} __attribute__ ((packed)) evt_max_slots_change;
+} QEMU_PACKED evt_max_slots_change;
 #define EVT_MAX_SLOTS_CHANGE_SIZE 3
 
 #define EVT_READ_CLOCK_OFFSET_COMPLETE 0x1C
@@ -1518,7 +1518,7 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint16_t   clock_offset;
-} __attribute__ ((packed)) evt_read_clock_offset_complete;
+} QEMU_PACKED evt_read_clock_offset_complete;
 #define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5
 
 #define EVT_CONN_PTYPE_CHANGED         0x1D
@@ -1526,20 +1526,20 @@ typedef struct {
     uint8_t    status;
     uint16_t   handle;
     uint16_t   ptype;
-} __attribute__ ((packed)) evt_conn_ptype_changed;
+} QEMU_PACKED evt_conn_ptype_changed;
 #define EVT_CONN_PTYPE_CHANGED_SIZE 5
 
 #define EVT_QOS_VIOLATION              0x1E
 typedef struct {
     uint16_t   handle;
-} __attribute__ ((packed)) evt_qos_violation;
+} QEMU_PACKED evt_qos_violation;
 #define EVT_QOS_VIOLATION_SIZE 2
 
 #define EVT_PSCAN_REP_MODE_CHANGE      0x20
 typedef struct {
     bdaddr_t   bdaddr;
     uint8_t    pscan_rep_mode;
-} __attribute__ ((packed)) evt_pscan_rep_mode_change;
+} QEMU_PACKED evt_pscan_rep_mode_change;
 #define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7
 
 #define EVT_FLOW_SPEC_COMPLETE         0x21
@@ -1549,7 +1549,7 @@ typedef struct {
     uint8_t    flags;
     uint8_t    direction;
     hci_qos    qos;
-} __attribute__ ((packed)) evt_flow_spec_complete;
+} QEMU_PACKED evt_flow_spec_complete;
 #define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE)
 
 #define EVT_INQUIRY_RESULT_WITH_RSSI   0x22
@@ -1561,7 +1561,7 @@ typedef struct {
     uint8_t    dev_class[3];
     uint16_t   clock_offset;
     int8_t     rssi;
-} __attribute__ ((packed)) inquiry_info_with_rssi;
+} QEMU_PACKED inquiry_info_with_rssi;
 #define INQUIRY_INFO_WITH_RSSI_SIZE 15
 typedef struct {
     uint8_t    num_responses;
@@ -1572,7 +1572,7 @@ typedef struct {
     uint8_t    dev_class[3];
     uint16_t   clock_offset;
     int8_t     rssi;
-} __attribute__ ((packed)) inquiry_info_with_rssi_and_pscan_mode;
+} QEMU_PACKED inquiry_info_with_rssi_and_pscan_mode;
 #define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16
 
 #define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE  0x23
@@ -1582,7 +1582,7 @@ typedef struct {
     uint8_t    page_num;
     uint8_t    max_page_num;
     uint8_t    features[8];
-} __attribute__ ((packed)) evt_read_remote_ext_features_complete;
+} QEMU_PACKED evt_read_remote_ext_features_complete;
 #define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13
 
 #define EVT_SYNC_CONN_COMPLETE         0x2C
@@ -1596,7 +1596,7 @@ typedef struct {
     uint16_t   rx_pkt_len;
     uint16_t   tx_pkt_len;
     uint8_t    air_mode;
-} __attribute__ ((packed)) evt_sync_conn_complete;
+} QEMU_PACKED evt_sync_conn_complete;
 #define EVT_SYNC_CONN_COMPLETE_SIZE 17
 
 #define EVT_SYNC_CONN_CHANGED          0x2D
@@ -1607,7 +1607,7 @@ typedef struct {
     uint8_t    retrans_window;
     uint16_t   rx_pkt_len;
     uint16_t   tx_pkt_len;
-} __attribute__ ((packed)) evt_sync_conn_changed;
+} QEMU_PACKED evt_sync_conn_changed;
 #define EVT_SYNC_CONN_CHANGED_SIZE 9
 
 #define EVT_SNIFF_SUBRATE              0x2E
@@ -1618,7 +1618,7 @@ typedef struct {
     uint16_t   max_local_latency;
     uint16_t   min_remote_timeout;
     uint16_t   min_local_timeout;
-} __attribute__ ((packed)) evt_sniff_subrate;
+} QEMU_PACKED evt_sniff_subrate;
 #define EVT_SNIFF_SUBRATE_SIZE 11
 
 #define EVT_EXTENDED_INQUIRY_RESULT    0x2F
@@ -1630,7 +1630,7 @@ typedef struct {
     uint16_t   clock_offset;
     int8_t     rssi;
     uint8_t    data[240];
-} __attribute__ ((packed)) extended_inquiry_info;
+} QEMU_PACKED extended_inquiry_info;
 #define EXTENDED_INQUIRY_INFO_SIZE 254
 
 #define EVT_TESTING                    0xFE
@@ -1656,22 +1656,22 @@ typedef struct {
 struct hci_command_hdr {
     uint16_t   opcode;         /* OCF & OGF */
     uint8_t    plen;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 struct hci_event_hdr {
     uint8_t    evt;
     uint8_t    plen;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 struct hci_acl_hdr {
     uint16_t   handle;         /* Handle & Flags(PB, BC) */
     uint16_t   dlen;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 struct hci_sco_hdr {
     uint16_t   handle;
     uint8_t    dlen;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 /* L2CAP layer defines */
 
@@ -1718,25 +1718,25 @@ typedef struct {
     uint16_t   len;
     uint16_t   cid;
     uint8_t    data[0];
-} __attribute__ ((packed)) l2cap_hdr;
+} QEMU_PACKED l2cap_hdr;
 #define L2CAP_HDR_SIZE 4
 
 typedef struct {
     uint8_t    code;
     uint8_t    ident;
     uint16_t   len;
-} __attribute__ ((packed)) l2cap_cmd_hdr;
+} QEMU_PACKED l2cap_cmd_hdr;
 #define L2CAP_CMD_HDR_SIZE 4
 
 typedef struct {
     uint16_t   reason;
-} __attribute__ ((packed)) l2cap_cmd_rej;
+} QEMU_PACKED l2cap_cmd_rej;
 #define L2CAP_CMD_REJ_SIZE 2
 
 typedef struct {
     uint16_t   dcid;
     uint16_t   scid;
-} __attribute__ ((packed)) l2cap_cmd_rej_cid;
+} QEMU_PACKED l2cap_cmd_rej_cid;
 #define L2CAP_CMD_REJ_CID_SIZE 4
 
 /* reject reason */
@@ -1749,7 +1749,7 @@ enum bt_l2cap_rej_reason {
 typedef struct {
     uint16_t   psm;
     uint16_t   scid;
-} __attribute__ ((packed)) l2cap_conn_req;
+} QEMU_PACKED l2cap_conn_req;
 #define L2CAP_CONN_REQ_SIZE 4
 
 typedef struct {
@@ -1757,7 +1757,7 @@ typedef struct {
     uint16_t   scid;
     uint16_t   result;
     uint16_t   status;
-} __attribute__ ((packed)) l2cap_conn_rsp;
+} QEMU_PACKED l2cap_conn_rsp;
 #define L2CAP_CONN_RSP_SIZE 8
 
 /* connect result */
@@ -1780,7 +1780,7 @@ typedef struct {
     uint16_t   dcid;
     uint16_t   flags;
     uint8_t    data[0];
-} __attribute__ ((packed)) l2cap_conf_req;
+} QEMU_PACKED l2cap_conf_req;
 #define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen))
 
 typedef struct {
@@ -1788,7 +1788,7 @@ typedef struct {
     uint16_t   flags;
     uint16_t   result;
     uint8_t    data[0];
-} __attribute__ ((packed)) l2cap_conf_rsp;
+} QEMU_PACKED l2cap_conf_rsp;
 #define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen)
 
 enum bt_l2cap_conf_res {
@@ -1802,7 +1802,7 @@ typedef struct {
     uint8_t    type;
     uint8_t    len;
     uint8_t    val[0];
-} __attribute__ ((packed)) l2cap_conf_opt;
+} QEMU_PACKED l2cap_conf_opt;
 #define L2CAP_CONF_OPT_SIZE 2
 
 enum bt_l2cap_conf_val {
@@ -1821,7 +1821,7 @@ typedef struct {
     uint32_t   peak_bandwidth;
     uint32_t   latency;
     uint32_t   delay_variation;
-} __attribute__ ((packed)) l2cap_conf_opt_qos;
+} QEMU_PACKED l2cap_conf_opt_qos;
 #define L2CAP_CONF_OPT_QOS_SIZE 22
 
 enum bt_l2cap_conf_opt_qos_st {
@@ -1841,25 +1841,25 @@ enum bt_l2cap_mode {
 typedef struct {
     uint16_t   dcid;
     uint16_t   scid;
-} __attribute__ ((packed)) l2cap_disconn_req;
+} QEMU_PACKED l2cap_disconn_req;
 #define L2CAP_DISCONN_REQ_SIZE 4
 
 typedef struct {
     uint16_t   dcid;
     uint16_t   scid;
-} __attribute__ ((packed)) l2cap_disconn_rsp;
+} QEMU_PACKED l2cap_disconn_rsp;
 #define L2CAP_DISCONN_RSP_SIZE 4
 
 typedef struct {
     uint16_t   type;
-} __attribute__ ((packed)) l2cap_info_req;
+} QEMU_PACKED l2cap_info_req;
 #define L2CAP_INFO_REQ_SIZE 2
 
 typedef struct {
     uint16_t   type;
     uint16_t   result;
     uint8_t    data[0];
-} __attribute__ ((packed)) l2cap_info_rsp;
+} QEMU_PACKED l2cap_info_rsp;
 #define L2CAP_INFO_RSP_SIZE 4
 
 /* info type */
index 8ae24e01de2641e2f2c759689f7eb4dcf9f1d6f2..7216899a093e9c63e8e05c074fb482482a862e85 100644 (file)
--- a/hw/cbus.c
+++ b/hw/cbus.c
@@ -132,7 +132,7 @@ static void cbus_sel(void *opaque, int line, int level)
 
 CBus *cbus_init(qemu_irq dat)
 {
-    CBusPriv *s = (CBusPriv *) qemu_mallocz(sizeof(*s));
+    CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s));
 
     s->dat_out = dat;
     s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
@@ -387,7 +387,7 @@ static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
 
 void *retu_init(qemu_irq irq, int vilma)
 {
-    CBusRetu *s = (CBusRetu *) qemu_mallocz(sizeof(*s));
+    CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s));
 
     s->irq = irq;
     s->irqen = 0xffff;
@@ -603,7 +603,7 @@ static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
 
 void *tahvo_init(qemu_irq irq, int betty)
 {
-    CBusTahvo *s = (CBusTahvo *) qemu_mallocz(sizeof(*s));
+    CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s));
 
     s->irq = irq;
     s->irqen = 0xffff;
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
new file mode 100644 (file)
index 0000000..092301b
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * CCID Card Device. Emulated card.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed 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 *)g_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 *)g_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 *)g_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 *)g_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");
+                g_free(event);
+                continue;
+            }
+            if (card->reader == NULL) {
+                DPRINTF(card, 1, "reader is NULL\n");
+                g_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);
+            }
+            g_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;
+        }
+        g_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..9f51c6c
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * 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_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
+    qemu_chr_fe_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);
+            break;
+        }
+        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_delete(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..9e3abe1
--- /dev/null
+++ b/hw/ccid.h
@@ -0,0 +1,58 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed 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;
+    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 */
index 5f45b5dee73dd2965a86a5f8083b927ffc4c3e71..c7e365b2a67ba2cb043065493f6712f4739d3d08 100644 (file)
@@ -31,7 +31,6 @@
 #include "pci.h"
 #include "console.h"
 #include "vga_int.h"
-#include "kvm.h"
 #include "loader.h"
 
 /*
 
 #define CIRRUS_PNPMMIO_SIZE         0x1000
 
-#define ABS(a) ((signed)(a) > 0 ? a : -a)
-
 #define BLTUNSAFE(s) \
     ( \
         ( /* check dst is within bounds */ \
@@ -201,9 +198,14 @@ typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
 typedef struct CirrusVGAState {
     VGACommonState vga;
 
-    int cirrus_linear_io_addr;
-    int cirrus_linear_bitblt_io_addr;
-    int cirrus_mmio_io_addr;
+    MemoryRegion cirrus_linear_io;
+    MemoryRegion cirrus_linear_bitblt_io;
+    MemoryRegion cirrus_mmio_io;
+    MemoryRegion pci_bar;
+    bool linear_vram;  /* vga.vram mapped over cirrus_linear_io */
+    MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
+    MemoryRegion low_mem;           /* always mapped, overridden by: */
+    MemoryRegion *cirrus_bank[2];   /*   aliases at 0xa0000-0xb0000  */
     uint32_t cirrus_addr_mask;
     uint32_t linear_mmio_mask;
     uint8_t cirrus_shadow_gr0;
@@ -613,7 +615,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
        off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
        off_cur &= TARGET_PAGE_MASK;
        while (off_cur < off_cur_end) {
-           cpu_physical_memory_set_dirty(s->vga.vram_offset + off_cur);
+           memory_region_set_dirty(&s->vga.vram, off_cur);
            off_cur += TARGET_PAGE_SIZE;
        }
        off_begin += off_pitch;
@@ -1178,12 +1180,6 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
     }
 
     if (limit > 0) {
-        /* Thinking about changing bank base? First, drop the dirty bitmap information
-         * on the current location, otherwise we lose this pointer forever */
-        if (s->vga.lfb_vram_mapped) {
-            target_phys_addr_t base_addr = isa_mem_base + 0xa0000 + bank_index * 0x8000;
-            cpu_physical_sync_dirty_bitmap(base_addr, base_addr + 0x8000);
-        }
        s->cirrus_bank_base[bank_index] = offset;
        s->cirrus_bank_limit[bank_index] = limit;
     } else {
@@ -1922,8 +1918,8 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
        val <<= 1;
        dst++;
     }
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 7);
+    memory_region_set_dirty(&s->vga.vram, offset);
+    memory_region_set_dirty(&s->vga.vram, offset + 7);
 }
 
 static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
@@ -1947,8 +1943,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
        val <<= 1;
        dst += 2;
     }
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 15);
+    memory_region_set_dirty(&s->vga.vram, offset);
+    memory_region_set_dirty(&s->vga.vram, offset + 15);
 }
 
 /***************************************
@@ -1957,7 +1953,9 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
  *
  ***************************************/
 
-static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_vga_mem_read(void *opaque,
+                                    target_phys_addr_t addr,
+                                    uint32_t size)
 {
     CirrusVGAState *s = opaque;
     unsigned bank_index;
@@ -1965,11 +1963,9 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t val;
 
     if ((s->vga.sr[0x07] & 0x01) == 0) {
-       return vga_mem_readb(s, addr);
+        return vga_mem_readb(&s->vga, addr);
     }
 
-    addr &= 0x1ffff;
-
     if (addr < 0x10000) {
        /* XXX handle bitblt */
        /* video memory */
@@ -2001,28 +1997,10 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_vga_mem_readb(opaque, addr);
-    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_vga_mem_readb(opaque, addr);
-    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-    v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
-    v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
-                                  uint32_t mem_value)
+static void cirrus_vga_mem_write(void *opaque,
+                                 target_phys_addr_t addr,
+                                 uint64_t mem_value,
+                                 uint32_t size)
 {
     CirrusVGAState *s = opaque;
     unsigned bank_index;
@@ -2030,12 +2008,10 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
     unsigned mode;
 
     if ((s->vga.sr[0x07] & 0x01) == 0) {
-       vga_mem_writeb(s, addr, mem_value);
+        vga_mem_writeb(&s->vga, addr, mem_value);
         return;
     }
 
-    addr &= 0x1ffff;
-
     if (addr < 0x10000) {
        if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
            /* bitblt */
@@ -2058,8 +2034,7 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
                mode = s->vga.gr[0x05] & 0x7;
                if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
                    *(s->vga.vram_ptr + bank_offset) = mem_value;
-                   cpu_physical_memory_set_dirty(s->vga.vram_offset +
-                                                 bank_offset);
+                   memory_region_set_dirty(&s->vga.vram, bank_offset);
                } else {
                    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
                        cirrus_mem_writeb_mode4and5_8bpp(s, mode,
@@ -2086,30 +2061,14 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = {
-    cirrus_vga_mem_readb,
-    cirrus_vga_mem_readw,
-    cirrus_vga_mem_readl,
-};
-
-static CPUWriteMemoryFunc * const cirrus_vga_mem_write[3] = {
-    cirrus_vga_mem_writeb,
-    cirrus_vga_mem_writew,
-    cirrus_vga_mem_writel,
+static const MemoryRegionOps cirrus_vga_mem_ops = {
+    .read = cirrus_vga_mem_read,
+    .write = cirrus_vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 /***************************************
@@ -2288,7 +2247,8 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
  *
  ***************************************/
 
-static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     CirrusVGAState *s = opaque;
     uint32_t ret;
@@ -2316,28 +2276,8 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_readb(opaque, addr);
-    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_readb(opaque, addr);
-    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-    v |= cirrus_linear_readb(opaque, addr + 2) << 16;
-    v |= cirrus_linear_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
+static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned size)
 {
     CirrusVGAState *s = opaque;
     unsigned mode;
@@ -2366,7 +2306,7 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
        mode = s->vga.gr[0x05] & 0x7;
        if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
            *(s->vga.vram_ptr + addr) = (uint8_t) val;
-           cpu_physical_memory_set_dirty(s->vga.vram_offset + addr);
+           memory_region_set_dirty(&s->vga.vram, addr);
        } else {
            if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
                cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
@@ -2377,35 +2317,6 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    cirrus_linear_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    cirrus_linear_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-
-static CPUReadMemoryFunc * const cirrus_linear_read[3] = {
-    cirrus_linear_readb,
-    cirrus_linear_readw,
-    cirrus_linear_readl,
-};
-
-static CPUWriteMemoryFunc * const cirrus_linear_write[3] = {
-    cirrus_linear_writeb,
-    cirrus_linear_writew,
-    cirrus_linear_writel,
-};
-
 /***************************************
  *
  *  system to screen memory access
@@ -2413,37 +2324,23 @@ static CPUWriteMemoryFunc * const cirrus_linear_write[3] = {
  ***************************************/
 
 
-static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_linear_bitblt_read(void *opaque,
+                                          target_phys_addr_t addr,
+                                          unsigned size)
 {
+    CirrusVGAState *s = opaque;
     uint32_t ret;
 
     /* XXX handle bitblt */
+    (void)s;
     ret = 0xff;
     return ret;
 }
 
-static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_bitblt_readb(opaque, addr);
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_bitblt_readb(opaque, addr);
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
+static void cirrus_linear_bitblt_write(void *opaque,
+                                       target_phys_addr_t addr,
+                                       uint64_t val,
+                                       unsigned size)
 {
     CirrusVGAState *s = opaque;
 
@@ -2456,77 +2353,70 @@ static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-
-static CPUReadMemoryFunc * const cirrus_linear_bitblt_read[3] = {
-    cirrus_linear_bitblt_readb,
-    cirrus_linear_bitblt_readw,
-    cirrus_linear_bitblt_readl,
-};
-
-static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = {
-    cirrus_linear_bitblt_writeb,
-    cirrus_linear_bitblt_writew,
-    cirrus_linear_bitblt_writel,
+static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
+    .read = cirrus_linear_bitblt_read,
+    .write = cirrus_linear_bitblt_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
-static void map_linear_vram(CirrusVGAState *s)
+static void unmap_bank(CirrusVGAState *s, unsigned bank)
 {
-    if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
-        s->vga.map_addr = s->vga.lfb_addr;
-        s->vga.map_end = s->vga.lfb_end;
-        cpu_register_physical_memory(s->vga.map_addr, s->vga.map_end - s->vga.map_addr, s->vga.vram_offset);
+    if (s->cirrus_bank[bank]) {
+        memory_region_del_subregion(&s->low_mem_container,
+                                    s->cirrus_bank[bank]);
+        memory_region_destroy(s->cirrus_bank[bank]);
+        g_free(s->cirrus_bank[bank]);
+        s->cirrus_bank[bank] = NULL;
     }
+}
 
-    if (!s->vga.map_addr)
-        return;
-
-    s->vga.lfb_vram_mapped = 0;
+static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
+{
+    MemoryRegion *mr;
+    static const char *names[] = { "vga.bank0", "vga.bank1" };
 
     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
         && !((s->vga.sr[0x07] & 0x01) == 0)
         && !((s->vga.gr[0x0B] & 0x14) == 0x14)
         && !(s->vga.gr[0x0B] & 0x02)) {
 
-        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
-                                    (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
-        cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
-                                    (s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
-
-        s->vga.lfb_vram_mapped = 1;
-    }
-    else {
-        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
-                                     s->vga.vga_io_memory);
+        mr = g_malloc(sizeof(*mr));
+        memory_region_init_alias(mr, names[bank], &s->vga.vram,
+                                 s->cirrus_bank_base[bank], 0x8000);
+        memory_region_add_subregion_overlap(
+            &s->low_mem_container,
+            0x8000 * bank,
+            mr,
+            1);
+        unmap_bank(s, bank);
+        s->cirrus_bank[bank] = mr;
+    } else {
+        unmap_bank(s, bank);
     }
+}
 
-    vga_dirty_log_start(&s->vga);
+static void map_linear_vram(CirrusVGAState *s)
+{
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
+        s->linear_vram = true;
+        memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
+    }
+    map_linear_vram_bank(s, 0);
+    map_linear_vram_bank(s, 1);
 }
 
 static void unmap_linear_vram(CirrusVGAState *s)
 {
-    if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
-        s->vga.map_addr = s->vga.map_end = 0;
-         cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
-                                      s->cirrus_linear_io_addr);
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
+        s->linear_vram = false;
+        memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
     }
-    cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
-                                 s->vga.vga_io_memory);
+    unmap_bank(s, 0);
+    unmap_bank(s, 1);
 }
 
 /* Compute the memory access functions */
@@ -2534,6 +2424,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
 {
     unsigned mode;
 
+    memory_region_transaction_begin();
     if ((s->vga.sr[0x17] & 0x44) == 0x44) {
         goto generic_io;
     } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
@@ -2553,6 +2444,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
             unmap_linear_vram(s);
         }
     }
+    memory_region_transaction_commit();
 }
 
 
@@ -2760,12 +2652,11 @@ static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  *
  ***************************************/
 
-static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     CirrusVGAState *s = opaque;
 
-    addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
     if (addr >= 0x100) {
         return cirrus_mmio_blt_read(s, addr - 0x100);
     } else {
@@ -2773,33 +2664,11 @@ static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
     }
 }
 
-static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_mmio_readb(opaque, addr);
-    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_mmio_readb(opaque, addr);
-    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-    v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
-    v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
+static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t val, unsigned size)
 {
     CirrusVGAState *s = opaque;
 
-    addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
     if (addr >= 0x100) {
        cirrus_mmio_blt_write(s, addr - 0x100, val);
     } else {
@@ -2807,33 +2676,14 @@ static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
-{
-    cirrus_mmio_writeb(opaque, addr, val & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
-{
-    cirrus_mmio_writeb(opaque, addr, val & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-
-static CPUReadMemoryFunc * const cirrus_mmio_read[3] = {
-    cirrus_mmio_readb,
-    cirrus_mmio_readw,
-    cirrus_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const cirrus_mmio_write[3] = {
-    cirrus_mmio_writeb,
-    cirrus_mmio_writew,
-    cirrus_mmio_writel,
+static const MemoryRegionOps cirrus_mmio_io_ops = {
+    .read = cirrus_mmio_read,
+    .write = cirrus_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 /* load/save state */
@@ -2942,7 +2792,18 @@ static void cirrus_reset(void *opaque)
     s->cirrus_hidden_dac_data = 0;
 }
 
-static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
+static const MemoryRegionOps cirrus_linear_io_ops = {
+    .read = cirrus_linear_read,
+    .write = cirrus_linear_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
+                               MemoryRegion *system_memory)
 {
     int i;
     static int inited;
@@ -2988,28 +2849,33 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s);
     register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s);
 
-    s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read,
-                                                  cirrus_vga_mem_write, s,
-                                                  DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 s->vga.vga_io_memory);
-    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    memory_region_init(&s->low_mem_container,
+                       "cirrus-lowmem-container",
+                       0x20000);
+
+    memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
+                          "cirrus-low-memory", 0x20000);
+    memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
+    memory_region_add_subregion_overlap(system_memory,
+                                        isa_mem_base + 0x000a0000,
+                                        &s->low_mem_container,
+                                        1);
+    memory_region_set_coalescing(&s->low_mem);
 
     /* I/O handler for LFB */
-    s->cirrus_linear_io_addr =
-        cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
+                          "cirrus-linear-io", VGA_RAM_SIZE);
 
     /* I/O handler for LFB */
-    s->cirrus_linear_bitblt_io_addr =
-        cpu_register_io_memory(cirrus_linear_bitblt_read,
-                               cirrus_linear_bitblt_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_linear_bitblt_io,
+                          &cirrus_linear_bitblt_io_ops,
+                          s,
+                          "cirrus-bitblt-mmio",
+                          0x400000);
 
     /* I/O handler for memory-mapped I/O */
-    s->cirrus_mmio_io_addr =
-        cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s,
+                          "cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
 
     s->real_vram_size =
         (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
@@ -3025,7 +2891,6 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     s->vga.cursor_draw_line = cirrus_cursor_draw_line;
 
     qemu_register_reset(cirrus_reset, s);
-    cirrus_reset(s);
 }
 
 /***************************************
@@ -3034,14 +2899,14 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
  *
  ***************************************/
 
-void isa_cirrus_vga_init(void)
+void isa_cirrus_vga_init(MemoryRegion *system_memory)
 {
     CirrusVGAState *s;
 
-    s = qemu_mallocz(sizeof(CirrusVGAState));
+    s = g_malloc0(sizeof(CirrusVGAState));
 
     vga_common_init(&s->vga, VGA_RAM_SIZE);
-    cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
+    cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory);
     s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
                                      s->vga.screen_dump, s->vga.text_update,
                                      &s->vga);
@@ -3056,76 +2921,36 @@ void isa_cirrus_vga_init(void)
  *
  ***************************************/
 
-static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
-                              pcibus_t addr, pcibus_t size, int type)
-{
-    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
-    /* XXX: add byte swapping apertures */
-    cpu_register_physical_memory(addr, s->vga.vram_size,
-                                s->cirrus_linear_io_addr);
-    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
-                                s->cirrus_linear_bitblt_io_addr);
-
-    s->vga.map_addr = s->vga.map_end = 0;
-    s->vga.lfb_addr = addr & TARGET_PAGE_MASK;
-    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
-    /* account for overflow */
-    if (s->vga.lfb_end < addr + VGA_RAM_SIZE)
-        s->vga.lfb_end = addr + VGA_RAM_SIZE;
-
-    vga_dirty_log_start(&s->vga);
-}
-
-static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
-                               pcibus_t addr, pcibus_t size, int type)
-{
-    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
-    cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
-                                s->cirrus_mmio_io_addr);
-}
-
-static void pci_cirrus_write_config(PCIDevice *d,
-                                    uint32_t address, uint32_t val, int len)
-{
-    PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
-    CirrusVGAState *s = &pvs->cirrus_vga;
-
-    pci_default_write_config(d, address, val, len);
-    if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED)
-        s->vga.map_addr = 0;
-    cirrus_update_memory_access(s);
-}
-
 static int pci_cirrus_vga_initfn(PCIDevice *dev)
 {
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
      CirrusVGAState *s = &d->cirrus_vga;
-     uint8_t *pci_conf = d->dev.config;
-     int device_id = CIRRUS_ID_CLGD5446;
+     PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
+     int16_t device_id = info->device_id;
 
      /* setup VGA */
      vga_common_init(&s->vga, VGA_RAM_SIZE);
-     cirrus_init_common(s, device_id, 1);
+     cirrus_init_common(s, device_id, 1, pci_address_space(dev));
      s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
                                       s->vga.screen_dump, s->vga.text_update,
                                       &s->vga);
 
      /* setup PCI */
-     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CIRRUS);
-     pci_config_set_device_id(pci_conf, device_id);
-     pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
+
+    memory_region_init(&s->pci_bar, "cirrus-pci-bar0", 0x2000000);
+
+    /* XXX: add byte swapping apertures */
+    memory_region_add_subregion(&s->pci_bar, 0, &s->cirrus_linear_io);
+    memory_region_add_subregion(&s->pci_bar, 0x1000000,
+                                &s->cirrus_linear_bitblt_io);
 
      /* setup memory space */
      /* memory #0 LFB */
      /* memory #1 memory-mapped I/O */
      /* XXX: s->vga.vram_size must be a power of two */
-     pci_register_bar(&d->dev, 0, 0x2000000,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->pci_bar);
      if (device_id == CIRRUS_ID_CLGD5446) {
-         pci_register_bar(&d->dev, 1, CIRRUS_PNPMMIO_SIZE,
-                          PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
+         pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
      }
      return 0;
 }
@@ -3143,7 +2968,9 @@ static PCIDeviceInfo cirrus_vga_info = {
     .no_hotplug   = 1,
     .init         = pci_cirrus_vga_initfn,
     .romfile      = VGABIOS_CIRRUS_FILENAME,
-    .config_write = pci_cirrus_write_config,
+    .vendor_id    = PCI_VENDOR_ID_CIRRUS,
+    .device_id    = CIRRUS_ID_CLGD5446,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
 };
 
 static void cirrus_vga_register(void)
diff --git a/hw/collie.c b/hw/collie.c
new file mode 100644 (file)
index 0000000..8dd6e4e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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"
+#include "exec-memory.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;
+    MemoryRegion *sysmem = get_system_memory();
+
+    if (!cpu_model) {
+        cpu_model = "sa1110";
+    }
+
+    s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    dinfo = drive_get(IF_PFLASH, 0, 1);
+    pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
+                    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 a92d445f2945f565541de40b0392a8d2d2cd624f..06ae4849500385c306d6c6453eee5e59b9b72ab3 100644 (file)
  * THE SOFTWARE.
  */
 
+#include "sysbus.h"
 #include "hw.h"
-#include "pc.h"
 #include "etraxfs.h"
 
 #define D(x)
 
-void pic_info(Monitor *mon)
-{}
-void irq_info(Monitor *mon)
-{}
-
 static void cris_pic_cpu_handler(void *opaque, int irq, int level)
 {
     CPUState *env = (CPUState *)opaque;
index 598f0322d9b4325813f262b3e222a933d8145417..a7e03a313ceaaecebf84fe668e1ec750925a7b0a 100644 (file)
@@ -59,6 +59,7 @@ static struct {
 typedef struct CSState {
     ISADevice dev;
     QEMUSoundCard card;
+    MemoryRegion ioports;
     qemu_irq pic;
     uint32_t regs[CS_REGS];
     uint8_t dregs[CS_DREGS];
@@ -74,14 +75,6 @@ typedef struct CSState {
     int16_t *tab;
 } CSState;
 
-#define IO_READ_PROTO(name)                             \
-    static uint32_t name (void *opaque, uint32_t addr)
-
-#define IO_WRITE_PROTO(name)                                            \
-    static void name (void *opaque, uint32_t addr, uint32_t val)
-
-#define GET_SADDR(addr) (addr & 3)
-
 #define MODE2 (1 << 6)
 #define MCE (1 << 6)
 #define PMCE (1 << 4)
@@ -353,12 +346,12 @@ static void cs_reset_voices (CSState *s, uint32_t val)
     }
 }
 
-IO_READ_PROTO (cs_read)
+static uint64_t cs_read (void *opaque, target_phys_addr_t addr, unsigned size)
 {
     CSState *s = opaque;
     uint32_t saddr, iaddr, ret;
 
-    saddr = GET_SADDR (addr);
+    saddr = addr;
     iaddr = ~0U;
 
     switch (saddr) {
@@ -390,12 +383,14 @@ IO_READ_PROTO (cs_read)
     return ret;
 }
 
-IO_WRITE_PROTO (cs_write)
+static void cs_write (void *opaque, target_phys_addr_t addr,
+                      uint64_t val64, unsigned size)
 {
     CSState *s = opaque;
-    uint32_t saddr, iaddr;
+    uint32_t saddr, iaddr, val;
 
-    saddr = GET_SADDR (addr);
+    saddr = addr;
+    val = val64;
 
     switch (saddr) {
     case Index_Address:
@@ -637,18 +632,23 @@ static const VMStateDescription vmstate_cs4231a = {
     }
 };
 
+static const MemoryRegionOps cs_ioport_ops = {
+    .read = cs_read,
+    .write = cs_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    }
+};
+
 static int cs4231a_initfn (ISADevice *dev)
 {
     CSState *s = DO_UPCAST (CSState, dev, dev);
-    int i;
 
     isa_init_irq (dev, &s->pic, s->irq);
 
-    for (i = 0; i < 4; i++) {
-        isa_init_ioport(dev, i);
-        register_ioport_write (s->port + i, 1, 1, cs_write, s);
-        register_ioport_read (s->port + i, 1, 1, cs_read, s);
-    }
+    memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
+    isa_register_ioport (dev, &s->ioports, s->port);
 
     DMA_register_channel (s->dma, cs_dma_read, s);
 
index e4c178dd2ad00c8eb83be60ef3e7fefe9e08acfc..40774360df4bacc34e9e4cef3f8a894683a5f9ae 100644 (file)
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -24,6 +24,7 @@
  */
 #include "hw.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 
@@ -117,6 +118,7 @@ typedef struct CUDATimer {
 } CUDATimer;
 
 typedef struct CUDAState {
+    MemoryRegion mem;
     /* cuda registers */
     uint8_t b;      /* B-side data */
     uint8_t a;      /* A-side data */
@@ -170,7 +172,7 @@ static unsigned int get_counter(CUDATimer *s)
     int64_t d;
     unsigned int counter;
 
-    d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->load_time,
                  CUDA_TIMER_FREQ, get_ticks_per_sec());
     if (s->index == 0) {
         /* the timer goes down from latch to -1 (period of latch + 2) */
@@ -189,7 +191,7 @@ static unsigned int get_counter(CUDATimer *s)
 static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
 {
     CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
-    ti->load_time = qemu_get_clock(vm_clock);
+    ti->load_time = qemu_get_clock_ns(vm_clock);
     ti->counter_value = val;
     cuda_timer_update(s, ti, ti->load_time);
 }
@@ -346,7 +348,7 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         break;
     case 4:
         s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
         break;
     case 5:
         s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
@@ -355,12 +357,12 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         break;
     case 6:
         s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
         break;
     case 7:
         s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
         s->ifr &= ~T1_INT;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
         break;
     case 8:
         s->timers[1].latch = val;
@@ -374,7 +376,7 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         break;
     case 11:
         s->acr = val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
         cuda_update(s);
         break;
     case 12:
@@ -506,7 +508,7 @@ static void cuda_adb_poll(void *opaque)
         cuda_send_packet_to_host(s, obuf, olen + 2);
     }
     qemu_mod_timer(s->adb_poll_timer,
-                   qemu_get_clock(vm_clock) +
+                   qemu_get_clock_ns(vm_clock) +
                    (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
 }
 
@@ -524,7 +526,7 @@ static void cuda_receive_packet(CUDAState *s,
             s->autopoll = autopoll;
             if (autopoll) {
                 qemu_mod_timer(s->adb_poll_timer,
-                               qemu_get_clock(vm_clock) +
+                               qemu_get_clock_ns(vm_clock) +
                                (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
             } else {
                 qemu_del_timer(s->adb_poll_timer);
@@ -536,14 +538,14 @@ static void cuda_receive_packet(CUDAState *s,
         break;
     case CUDA_SET_TIME:
         ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
-        s->tick_offset = ti - (qemu_get_clock(vm_clock) / get_ticks_per_sec());
+        s->tick_offset = ti - (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
         obuf[0] = CUDA_PACKET;
         obuf[1] = 0;
         obuf[2] = 0;
         cuda_send_packet_to_host(s, obuf, 3);
         break;
     case CUDA_GET_TIME:
-        ti = s->tick_offset + (qemu_get_clock(vm_clock) / get_ticks_per_sec());
+        ti = s->tick_offset + (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
         obuf[0] = CUDA_PACKET;
         obuf[1] = 0;
         obuf[2] = 0;
@@ -632,92 +634,72 @@ static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static CPUWriteMemoryFunc * const cuda_write[] = {
-    &cuda_writeb,
-    &cuda_writew,
-    &cuda_writel,
+static MemoryRegionOps cuda_ops = {
+    .old_mmio = {
+        .write = {
+            cuda_writeb,
+            cuda_writew,
+            cuda_writel,
+        },
+        .read = {
+            cuda_readb,
+            cuda_readw,
+            cuda_readl,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const cuda_read[] = {
-    &cuda_readb,
-    &cuda_readw,
-    &cuda_readl,
-};
-
-static void cuda_save_timer(QEMUFile *f, CUDATimer *s)
-{
-    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)
+static bool cuda_timer_exist(void *opaque, int version_id)
 {
-    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)
 {
@@ -746,7 +728,7 @@ static void cuda_reset(void *opaque)
     set_counter(s, &s->timers[1], 0xffff);
 }
 
-void cuda_init (int *cuda_mem_index, qemu_irq irq)
+void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq)
 {
     struct tm tm;
     CUDAState *s = &cuda_state;
@@ -754,16 +736,17 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq)
     s->irq = irq;
 
     s->timers[0].index = 0;
-    s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
+    s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s);
 
     s->timers[1].index = 1;
 
     qemu_get_timedate(&tm, 0);
     s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
 
-    s->adb_poll_timer = qemu_new_timer(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);
+    s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
+    memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000);
+
+    *cuda_mem = &s->mem;
+    vmstate_register(NULL, -1, &vmstate_cuda, s);
     qemu_register_reset(cuda_reset, s);
 }
index 5ee6821206daff7f923a6c992c3464d700952ab8..c9ee6d90b096090112a98deac881fed5678f325e 100644 (file)
@@ -51,7 +51,7 @@ static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
 #endif
 
-    qemu_chr_write(s->chr, &ch, 1);
+    qemu_chr_fe_write(s->chr, &ch, 1);
 }
 
 
index bf88f2ac8025450eb6f246df44464e7736d64b19..1aec06611c04a987cabe48ffcbf8bf492a9244a4 100644 (file)
@@ -50,28 +50,16 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
     return irq_num;
 }
 
-static int dec_21154_initfn(PCIDevice *dev)
-{
-    int rc;
-
-    rc = pci_bridge_initfn(dev);
-    if (rc < 0) {
-        return rc;
-    }
-
-    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC);
-    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154);
-    return 0;
-}
-
 static PCIDeviceInfo dec_21154_pci_bridge_info = {
     .qdev.name = "dec-21154-p2p-bridge",
     .qdev.desc = "DEC 21154 PCI-PCI bridge",
     .qdev.size = sizeof(PCIBridge),
     .qdev.vmsd = &vmstate_pci_device,
     .qdev.reset = pci_bridge_reset,
-    .init = dec_21154_initfn,
+    .init = pci_bridge_initfn,
     .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
     .config_write = pci_bridge_write_config,
     .is_bridge = 1,
 };
@@ -92,26 +80,21 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
 static int pci_dec_21154_init_device(SysBusDevice *dev)
 {
     DECState *s;
-    int pci_mem_config, pci_mem_data;
 
     s = FROM_SYSBUS(DECState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
-                                               DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-data-idx", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
 static int dec_21154_pci_host_init(PCIDevice *d)
 {
     /* PCI2PCI bridge same values as PearPC - check this */
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
-    pci_set_byte(d->config + PCI_REVISION_ID, 0x02);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
     return 0;
 }
 
@@ -119,6 +102,10 @@ static PCIDeviceInfo dec_21154_pci_host_info = {
     .qdev.name = "dec-21154",
     .qdev.size = sizeof(PCIDevice),
     .init      = dec_21154_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
+    .revision = 0x02,
+    .class_id = PCI_CLASS_BRIDGE_PCI,
     .is_bridge  = 1,
 };
 
index c788373c8c958a3ca2670120b4f7b506d5c0aaa2..1a55c1e9053208cf6f0d6905aee7e4cb72a7e97c 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef QEMU_DEVICES_H
 #define QEMU_DEVICES_H
 
+/* ??? Not all users of this file can include cpu-common.h.  */
+struct MemoryRegion;
+
 /* Devices that have nowhere better to go.  */
 
 /* smc91c111.c */
@@ -47,24 +50,19 @@ void *tahvo_init(qemu_irq irq, int betty);
 
 void retu_key_event(void *retu, int state);
 
-/* tusb6010.c */
-typedef struct TUSBState TUSBState;
-TUSBState *tusb6010_init(qemu_irq intr);
-int tusb6010_sync_io(TUSBState *s);
-int tusb6010_async_io(TUSBState *s);
-void tusb6010_power(TUSBState *s, int on);
-
 /* tc6393xb.c */
 typedef struct TC6393xbState TC6393xbState;
 #define TC6393XB_RAM   0x110000 /* amount of ram for Video and USB */
-TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq);
+TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
+                             uint32_t base, qemu_irq irq);
 void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
                     qemu_irq handler);
 qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
 qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
 
 /* sm501.c */
-void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq,
                 CharDriverState *chr);
 
 #endif
index 8a7302a42f6387e0c27ebcd635b066753c455134..0a9322daa3df807f3486799744c92ae0cd94af23 100644 (file)
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -358,6 +358,14 @@ static void DMA_run (void)
     struct dma_cont *d;
     int icont, ichan;
     int rearm = 0;
+    static int running = 0;
+
+    if (running) {
+        rearm = 1;
+        goto out;
+    } else {
+        running = 1;
+    }
 
     d = dma_controllers;
 
@@ -374,6 +382,8 @@ static void DMA_run (void)
         }
     }
 
+    running = 0;
+out:
     if (rearm)
         qemu_bh_schedule_idle(dma_bh);
 }
index 0ef8abe839c1c5d4fdf1adfab2a5ec6852f33572..f66844b108fa93ee3582724413c7b489ccc5f036 100644 (file)
@@ -290,7 +290,7 @@ static void set_next_tick(dp8393xState *s)
     }
 
     ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
-    s->wt_last_update = qemu_get_clock(vm_clock);
+    s->wt_last_update = qemu_get_clock_ns(vm_clock);
     delay = get_ticks_per_sec() * ticks / 5000000;
     qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
 }
@@ -305,7 +305,7 @@ static void update_wt_regs(dp8393xState *s)
         return;
     }
 
-    elapsed = s->wt_last_update - qemu_get_clock(vm_clock);
+    elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
     val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
     val -= elapsed / 5000000;
     s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
@@ -870,7 +870,7 @@ static void nic_cleanup(VLANClientState *nc)
     qemu_del_timer(s->watchdog);
     qemu_free_timer(s->watchdog);
 
-    qemu_free(s);
+    g_free(s);
 }
 
 static NetClientInfo net_dp83932_info = {
@@ -889,16 +889,16 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
 
     qemu_check_nic_model(nd, "dp83932");
 
-    s = qemu_mallocz(sizeof(dp8393xState));
+    s = g_malloc0(sizeof(dp8393xState));
 
     s->mem_opaque = mem_opaque;
     s->memory_rw = memory_rw;
     s->it_shift = it_shift;
     s->irq = irq;
-    s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
+    s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
     s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
 
-    memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(s->conf.macaddr));
+    s->conf.macaddr = nd->macaddr;
     s->conf.vlan = nd->vlan;
     s->conf.peer = nd->netdev;
 
index b1c52321fe8f83e1fdf58c436a60bd00f3f84f87..6852a61d0864fb6aa67072c7005536fe09dfdb91 100644 (file)
  * THE SOFTWARE.
  */
 
-#include "hw.h"
-#include "mips.h"
-#include "nvram.h"
+#include "sysbus.h"
+#include "trace.h"
 
-//#define DEBUG_NVRAM
-
-typedef struct ds1225y_t
-{
+typedef struct {
+    DeviceState qdev;
     uint32_t chip_size;
-    QEMUFile *file;
+    char *filename;
+    FILE *file;
     uint8_t *contents;
-    uint8_t protection;
-} ds1225y_t;
-
+} NvRamState;
 
 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
 {
-    ds1225y_t *s = opaque;
+    NvRamState *s = opaque;
     uint32_t val;
 
     val = s->contents[addr];
-
-#ifdef DEBUG_NVRAM
-    printf("nvram: read 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+    trace_nvram_read(addr, val);
     return val;
 }
 
@@ -70,17 +63,16 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
 
 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    ds1225y_t *s = opaque;
+    NvRamState *s = opaque;
 
-#ifdef DEBUG_NVRAM
-    printf("nvram: write 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+    val &= 0xff;
+    trace_nvram_write(addr, s->contents[addr], val);
 
-    s->contents[addr] = val & 0xff;
+    s->contents[addr] = val;
     if (s->file) {
-        qemu_fseek(s->file, addr, SEEK_SET);
-        qemu_put_byte(s->file, (int)val);
-        qemu_fflush(s->file);
+        fseek(s->file, addr, SEEK_SET);
+        fputc(val, s->file);
+        fflush(s->file);
     }
 }
 
@@ -98,34 +90,6 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
     nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff);
 }
 
-static void nvram_writeb_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    ds1225y_t *s = opaque;
-
-    if (s->protection != 7) {
-#ifdef DEBUG_NVRAM
-    printf("nvram: prevent write of 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
-        return;
-    }
-
-    nvram_writeb(opaque, addr, val);
-}
-
-static void nvram_writew_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    nvram_writeb_protected(opaque, addr, val & 0xff);
-    nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void nvram_writel_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    nvram_writeb_protected(opaque, addr, val & 0xff);
-    nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
-    nvram_writeb_protected(opaque, addr + 2, (val >> 16) & 0xff);
-    nvram_writeb_protected(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
 static CPUReadMemoryFunc * const nvram_read[] = {
     &nvram_readb,
     &nvram_readw,
@@ -138,45 +102,87 @@ static CPUWriteMemoryFunc * const nvram_write[] = {
     &nvram_writel,
 };
 
-static CPUWriteMemoryFunc * const nvram_write_protected[] = {
-    &nvram_writeb_protected,
-    &nvram_writew_protected,
-    &nvram_writel_protected,
+static int nvram_post_load(void *opaque, int version_id)
+{
+    NvRamState *s = opaque;
+
+    /* Close file, as filename may has changed in load/store process */
+    if (s->file) {
+        fclose(s->file);
+    }
+
+    /* Write back nvram contents */
+    s->file = fopen(s->filename, "wb");
+    if (s->file) {
+        /* Write back contents, as 'wb' mode cleaned the file */
+        if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
+            printf("nvram_post_load: short write\n");
+        }
+        fflush(s->file);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_nvram = {
+    .name = "nvram",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = nvram_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
+                              vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
 };
 
-/* Initialisation routine */
-void *ds1225y_init(target_phys_addr_t mem_base, const char *filename)
+typedef struct {
+    SysBusDevice busdev;
+    NvRamState nvram;
+} SysBusNvRamState;
+
+static int nvram_sysbus_initfn(SysBusDevice *dev)
 {
-    ds1225y_t *s;
-    int mem_indexRW, mem_indexRP;
-    QEMUFile *file;
+    NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
+    FILE *file;
+    int s_io;
+
+    s->contents = g_malloc0(s->chip_size);
 
-    s = qemu_mallocz(sizeof(ds1225y_t));
-    s->chip_size = 0x2000; /* Fixed for ds1225y chip: 8 KiB */
-    s->contents = qemu_mallocz(s->chip_size);
-    s->protection = 7;
+    s_io = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                  DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, s->chip_size, s_io);
 
     /* Read current file */
-    file = qemu_fopen(filename, "rb");
+    file = fopen(s->filename, "rb");
     if (file) {
         /* Read nvram contents */
-        qemu_get_buffer(file, s->contents, s->chip_size);
-        qemu_fclose(file);
-    }
-    s->file = qemu_fopen(filename, "wb");
-    if (s->file) {
-        /* Write back contents, as 'wb' mode cleaned the file */
-        qemu_put_buffer(s->file, s->contents, s->chip_size);
-        qemu_fflush(s->file);
+        if (fread(s->contents, s->chip_size, 1, file) != 1) {
+            printf("nvram_sysbus_initfn: short read\n");
+        }
+        fclose(file);
     }
+    nvram_post_load(s, 0);
 
-    /* Read/write memory */
-    mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW);
-    /* Read/write protected memory */
-    mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP);
-    return s;
+    return 0;
 }
+
+static SysBusDeviceInfo nvram_sysbus_info = {
+    .qdev.name  = "ds1225y",
+    .qdev.size  = sizeof(SysBusNvRamState),
+    .qdev.vmsd  = &vmstate_nvram,
+    .init       = nvram_sysbus_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+        DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void nvram_register(void)
+{
+    sysbus_register_withprop(&nvram_sysbus_info);
+}
+
+device_init(nvram_register)
index 6f5ae5e6c189f5fd26473e7a41fe5fd18200e8c7..3522af5b5a3af7f083f7e0fa367e6e3d158c3760 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 
 #include "i2c.h"
index 61efb39896a673e842c38dac786ce8545515dd95..30146b9c9d6c2d70a624c3000fb15dad19e9d5a1 100644 (file)
@@ -3,14 +3,14 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 
 #include "hw.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 
@@ -22,6 +22,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
                      const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     int kernel_size;
     uint64_t elf_entry;
     target_phys_addr_t entry;
@@ -38,8 +40,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
     env->vbr = 0;
 
     /* RAM at address zero */
-    cpu_register_physical_memory(0, ram_size,
-        qemu_ram_alloc(NULL, "dummy_m68k.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "dummy_m68k.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Load kernel.  */
     if (kernel_filename) {
index af101bd7b762280152573cd50e015e2687ee2291..e164d79b8773efc92199ef2986c348579bf15f1d 100644 (file)
@@ -31,6 +31,7 @@
 #include "net/checksum.h"
 #include "loader.h"
 #include "sysemu.h"
+#include "dma.h"
 
 #include "e1000_hw.h"
 
@@ -82,7 +83,8 @@ typedef struct E1000State_st {
     PCIDevice dev;
     NICState *nic;
     NICConf conf;
-    int mmio_index;
+    MemoryRegion mmio;
+    MemoryRegion io;
 
     uint32_t mac_reg[0x8000];
     uint16_t phy_reg[0x20];
@@ -150,14 +152,6 @@ static const char phy_regcap[0x20] = {
     [PHY_ID2] = PHY_R,         [M88E1000_PHY_SPEC_STATUS] = PHY_R
 };
 
-static void
-ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
-           pcibus_t size, int type)
-{
-    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
-           " size=0x%08"FMT_PCIBUS"\n", addr, size);
-}
-
 static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
 {
@@ -446,7 +440,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         return;
     } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
         // data descriptor
-        tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+        if (tp->size == 0) {
+            tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+        }
         tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
     } else {
         // legacy descriptor
@@ -470,7 +466,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
             bytes = split_size;
             if (tp->size + bytes > msh)
                 bytes = msh - tp->size;
-            cpu_physical_memory_read(addr, tp->data + tp->size, bytes);
+
+            bytes = MIN(sizeof(tp->data) - tp->size, bytes);
+            pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
             if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
                 memmove(tp->header, tp->data, hdr);
             tp->size = sz;
@@ -485,7 +483,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         // context descriptor TSE is not set, while data descriptor TSE is set
         DBGOUT(TXERR, "TCP segmentaion Error\n");
     } else {
-        cpu_physical_memory_read(addr, tp->data + tp->size, split_size);
+        split_size = MIN(sizeof(tp->data) - tp->size, split_size);
+        pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
         tp->size += split_size;
     }
 
@@ -501,7 +500,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
 }
 
 static uint32_t
-txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp)
+txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
 {
     uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
 
@@ -510,15 +509,23 @@ txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp)
     txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
                 ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
     dp->upper.data = cpu_to_le32(txd_upper);
-    cpu_physical_memory_write(base + ((char *)&dp->upper - (char *)dp),
-                              (void *)&dp->upper, sizeof(dp->upper));
+    pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
+                  (void *)&dp->upper, sizeof(dp->upper));
     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)
 {
-    target_phys_addr_t base;
+    dma_addr_t base;
     struct e1000_tx_desc desc;
     uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
 
@@ -528,16 +535,16 @@ 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));
+        pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc));
 
         DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
                (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
                desc.upper.data);
 
         process_tx_desc(s, &desc);
-        cause |= txdesc_writeback(base, &desc);
+        cause |= txdesc_writeback(s, base, &desc);
 
         if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
             s->mac_reg[TDH] = 0;
@@ -614,21 +621,50 @@ e1000_set_link_status(VLANClientState *nc)
     E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
     uint32_t old_status = s->mac_reg[STATUS];
 
-    if (nc->link_down)
+    if (nc->link_down) {
         s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
-    else
+        s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+    } else {
         s->mac_reg[STATUS] |= E1000_STATUS_LU;
+        s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
+    }
 
     if (s->mac_reg[STATUS] != old_status)
         set_ics(s, 0, E1000_ICR_LSC);
 }
 
+static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
+{
+    int bufs;
+    /* Fast-path short packets */
+    if (total_size <= s->rxbuf_size) {
+        return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
+    }
+    if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
+        bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
+        bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
+            s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else {
+        return false;
+    }
+    return total_size <= bufs * s->rxbuf_size;
+}
+
 static int
 e1000_can_receive(VLANClientState *nc)
 {
     E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    return (s->mac_reg[RCTL] & E1000_RCTL_EN);
+    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
@@ -636,12 +672,15 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 {
     E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
     struct e1000_rx_desc desc;
-    target_phys_addr_t base;
+    dma_addr_t base;
     unsigned int n, rdt;
     uint32_t rdh_start;
     uint16_t vlan_special = 0;
     uint8_t vlan_status = 0, vlan_offset = 0;
     uint8_t min_buf[MIN_BUF_SIZE];
+    size_t desc_offset;
+    size_t desc_size;
+    size_t total_size;
 
     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
         return -1;
@@ -654,12 +693,6 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
         size = sizeof(min_buf);
     }
 
-    if (size > s->rxbuf_size) {
-        DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
-               (unsigned long)size, s->rxbuf_size);
-        return -1;
-    }
-
     if (!receive_filter(s, buf, size))
         return size;
 
@@ -672,25 +705,44 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
     }
 
     rdh_start = s->mac_reg[RDH];
-    do {
-        if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
+    desc_offset = 0;
+    total_size = size + fcs_len(s);
+    if (!e1000_has_rxbufs(s, total_size)) {
             set_ics(s, 0, E1000_ICS_RXO);
             return -1;
+    }
+    do {
+        desc_size = total_size - desc_offset;
+        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];
-        cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
+        base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
+        pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc));
         desc.special = vlan_special;
         desc.status |= (vlan_status | E1000_RXD_STAT_DD);
         if (desc.buffer_addr) {
-            cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
-                                      (void *)(buf + vlan_offset), size);
-            desc.length = cpu_to_le16(size + fcs_len(s));
-            desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
+            if (desc_offset < size) {
+                size_t copy_size = size - desc_offset;
+                if (copy_size > s->rxbuf_size) {
+                    copy_size = s->rxbuf_size;
+                }
+                pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
+                                 (void *)(buf + desc_offset + vlan_offset),
+                                 copy_size);
+            }
+            desc_offset += desc_size;
+            desc.length = cpu_to_le16(desc_size);
+            if (desc_offset >= total_size) {
+                desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
+            } else {
+                /* Guest zeroing out status is not a hardware requirement.
+                   Clear EOP in case guest didn't do it. */
+                desc.status &= ~E1000_RXD_STAT_EOP;
+            }
         } else { // as per intel docs; skip descriptors with null buf addr
             DBGOUT(RX, "Null RX descriptor!!\n");
         }
-        cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
+        pci_dma_write(&s->dev, base, (void *)&desc, sizeof(desc));
 
         if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
             s->mac_reg[RDH] = 0;
@@ -702,7 +754,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
             set_ics(s, 0, E1000_ICS_RXO);
             return -1;
         }
-    } while (desc.buffer_addr == 0);
+    } while (desc_offset < total_size);
 
     s->mac_reg[GPRC]++;
     s->mac_reg[TPR]++;
@@ -853,7 +905,8 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
 enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
 
 static void
-e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+e1000_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val,
+                 unsigned size)
 {
     E1000State *s = opaque;
     unsigned int index = (addr & 0x1ffff) >> 2;
@@ -861,31 +914,15 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     if (index < NWRITEOPS && macreg_writeops[index]) {
         macreg_writeops[index](s, index, val);
     } else if (index < NREADOPS && macreg_readops[index]) {
-        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
+        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
     } else {
-        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
+        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
                index<<2, val);
     }
 }
 
-static void
-e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    // emulate hw without byte enables: no RMW
-    e1000_mmio_writel(opaque, addr & ~3,
-                      (val & 0xffff) << (8*(addr & 3)));
-}
-
-static void
-e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    // emulate hw without byte enables: no RMW
-    e1000_mmio_writel(opaque, addr & ~3,
-                      (val & 0xff) << (8*(addr & 3)));
-}
-
-static uint32_t
-e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t
+e1000_mmio_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     E1000State *s = opaque;
     unsigned int index = (addr & 0x1ffff) >> 2;
@@ -898,20 +935,39 @@ e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static uint32_t
-e1000_mmio_readb(void *opaque, target_phys_addr_t addr)
+static const MemoryRegionOps e1000_mmio_ops = {
+    .read = e1000_mmio_read,
+    .write = e1000_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t e1000_io_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
-    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
-            (8 * (addr & 3))) & 0xff;
+    E1000State *s = opaque;
+
+    (void)s;
+    return 0;
 }
 
-static uint32_t
-e1000_mmio_readw(void *opaque, target_phys_addr_t addr)
+static void e1000_io_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
-    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
-            (8 * (addr & 3))) & 0xffff;
+    E1000State *s = opaque;
+
+    (void)s;
 }
 
+static const MemoryRegionOps e1000_io_ops = {
+    .read = e1000_io_read,
+    .write = e1000_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static bool is_version_1(void *opaque, int version_id)
 {
     return version_id == 1;
@@ -1031,36 +1087,22 @@ static const uint32_t mac_reg_init[] = {
 
 /* PCI interface */
 
-static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
-    e1000_mmio_writeb, e1000_mmio_writew,      e1000_mmio_writel
-};
-
-static CPUReadMemoryFunc * const e1000_mmio_read[] = {
-    e1000_mmio_readb,  e1000_mmio_readw,       e1000_mmio_readl
-};
-
 static void
-e1000_mmio_map(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+e1000_mmio_setup(E1000State *d)
 {
-    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
     int i;
     const uint32_t excluded_regs[] = {
         E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
         E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
     };
 
-
-    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-
-    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
-    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
-
+    memory_region_init_io(&d->mmio, &e1000_mmio_ops, d, "e1000-mmio",
+                          PNPMMIO_SIZE);
+    memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
     for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
-        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
-                                     excluded_regs[i + 1] -
-                                     excluded_regs[i] - 4);
+        memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
+                                     excluded_regs[i+1] - excluded_regs[i] - 4);
+    memory_region_init_io(&d->io, &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
 }
 
 static void
@@ -1076,7 +1118,8 @@ pci_e1000_uninit(PCIDevice *dev)
 {
     E1000State *d = DO_UPCAST(E1000State, dev, dev);
 
-    cpu_unregister_io_memory(d->mmio_index);
+    memory_region_destroy(&d->mmio);
+    memory_region_destroy(&d->io);
     qemu_del_vlan_client(&d->nic->nc);
     return 0;
 }
@@ -1112,26 +1155,16 @@ static int pci_e1000_init(PCIDevice *pci_dev)
 
     pci_conf = d->dev.config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, E1000_DEVID);
-    /* TODO: we have no capabilities, so why is this bit set? */
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
-    pci_conf[PCI_REVISION_ID] = 0x03;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
 
-    /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
 
-    d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
-            e1000_mmio_write, d, DEVICE_LITTLE_ENDIAN);
+    e1000_mmio_setup(d);
 
-    pci_register_bar(&d->dev, 0, PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
 
-    pci_register_bar(&d->dev, 1, IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+    pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
 
     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
@@ -1168,7 +1201,11 @@ static PCIDeviceInfo e1000_info = {
     .qdev.vmsd  = &vmstate_e1000,
     .init       = pci_e1000_init,
     .exit       = pci_e1000_uninit,
-    .romfile    = "pxe-e1000.bin",
+    .romfile    = "pxe-e1000.rom",
+    .vendor_id  = PCI_VENDOR_ID_INTEL,
+    .device_id  = E1000_DEVID,
+    .revision   = 0x03,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(E1000State, conf),
         DEFINE_PROP_END_OF_LIST(),
index 9bd8a4bdfde7fe412d8ede9aac89057cf4021ec1..2e341ac27e09cc7ed1175712eb744ec005727e02 100644 (file)
 #define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
 #define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
 
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001        /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002        /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004        /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008        /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010        /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020        /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040        /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100        /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200        /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400        /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800        /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000        /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000        /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000        /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000        /* 100T4 Capable */
+
 /* Interrupt Cause Read */
 #define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
 #define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
index edf48f61d1000f4cb632358dd24b1605a7d32f4c..29ec5b44f8d16b97fc07a7095733a84d63344ff1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU i8255x (PRO100) emulation
  *
- * Copyright (C) 2006-2010 Stefan Weil
+ * Copyright (C) 2006-2011 Stefan Weil
  *
  * Portions of the code are copies from grub / etherboot eepro100.c
  * and linux e100.c.
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Tested features (i82559):
- *      PXE boot (i386) ok
+ *      PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
  *      Linux networking (i386) ok
  *
  * Untested:
- *      non-i386 platforms
  *      Windows networking
  *
  * References:
 #include "net.h"
 #include "eeprom93xx.h"
 #include "sysemu.h"
+#include "dma.h"
+
+/* QEMU sends frames smaller than 60 bytes to ethernet nics.
+ * Such frames are rejected by real nics and their emulations.
+ * To avoid this behaviour, other nic emulations pad received
+ * frames. The following definition enables this padding for
+ * eepro100, too. We keep the define around in case it might
+ * become useful the future if the core networking is ever
+ * changed to pad short packets itself. */
+#define CONFIG_PAD_RECEIVED_FRAMES
 
 #define KiB 1024
 
 typedef struct {
     PCIDeviceInfo pci;
     uint32_t device;
-    uint16_t device_id;
-    uint8_t revision;
     uint8_t stats_size;
     bool has_extended_tcb_support;
     bool power_management;
@@ -130,7 +137,7 @@ typedef struct {
 
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
-enum speedo_offsets {
+typedef enum {
     SCBStatus = 0,              /* Status Word. */
     SCBAck = 1,
     SCBCmd = 2,                 /* Rx/Command Unit command and status. */
@@ -145,7 +152,7 @@ enum speedo_offsets {
     SCBpmdr = 27,               /* Power Management Driver. */
     SCBgctrl = 28,              /* General Control. */
     SCBgstat = 29,              /* General Status. */
-};
+} E100RegisterOffset;
 
 /* A speedo3 transmit buffer descriptor with two buffers... */
 typedef struct {
@@ -173,7 +180,7 @@ typedef struct {
     uint32_t rx_buf_addr;       /* void * */
     uint16_t count;
     uint16_t size;
-    char packet[MAX_ETH_FRAME_SIZE + 4];
+    /* Ethernet frame data follows. */
 } eepro100_rx_t;
 
 typedef enum {
@@ -222,17 +229,17 @@ typedef struct {
     PCIDevice dev;
     /* Hash register (multicast mask array, multiple individual addresses). */
     uint8_t mult[8];
-    int mmio_index;
+    MemoryRegion mmio_bar;
+    MemoryRegion io_bar;
+    MemoryRegion flash_bar;
     NICState *nic;
     NICConf conf;
     uint8_t scb_stat;           /* SCB stat/ack byte */
     uint8_t int_stat;           /* PCI interrupt status */
     /* region must not be saved by nic_save. */
-    uint32_t region[3];         /* PCI region addresses */
     uint16_t mdimem[32];
     eeprom_t *eeprom;
     uint32_t device;            /* device variant */
-    uint32_t pointer;
     /* (cu_base + cu_offset) address the next command block in the command block list. */
     uint32_t cu_base;           /* CU base address */
     uint32_t cu_offset;         /* CU address offset */
@@ -249,11 +256,13 @@ typedef struct {
     /* Statistical counters. Also used for wake-up packet (i82559). */
     eepro100_stats_t statistics;
 
+    /* Data in mem is always in the byte order of the controller (le).
+     * It must be dword aligned to allow direct access to 32 bit values. */
+    uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));;
+
     /* Configuration bytes. */
     uint8_t configuration[22];
 
-    /* Data in mem is always in the byte order of the controller (le). */
-    uint8_t mem[PCI_MEM_SIZE];
     /* vmstate for each particular nic */
     VMStateDescription *vmstate;
 
@@ -307,13 +316,6 @@ static const uint16_t eepro100_mdi_mask[] = {
     0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 };
 
-/* XXX: optimize */
-static void stl_le_phys(target_phys_addr_t addr, uint32_t val)
-{
-    val = cpu_to_le32(val);
-    cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val));
-}
-
 #define POLYNOMIAL 0x04c11db6
 
 /* From FreeBSD */
@@ -339,6 +341,36 @@ static unsigned compute_mcast_idx(const uint8_t * ep)
     return (crc & BITS(7, 2)) >> 2;
 }
 
+/* Read a 16 bit control/status (CSR) register. */
+static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    return le16_to_cpup((uint16_t *)&s->mem[addr]);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    return le32_to_cpup((uint32_t *)&s->mem[addr]);
+}
+
+/* Write a 16 bit control/status (CSR) register. */
+static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
+                            uint16_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    cpu_to_le16w((uint16_t *)&s->mem[addr], val);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
+                            uint32_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    cpu_to_le32w((uint32_t *)&s->mem[addr], val);
+}
+
 #if defined(DEBUG_EEPRO100)
 static const char *nic_dump(const uint8_t * buf, unsigned size)
 {
@@ -462,16 +494,9 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
 
     TRACE(OTHER, logout("%p\n", s));
 
-    /* PCI Vendor ID */
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    /* PCI Device ID */
-    pci_config_set_device_id(pci_conf, e100_device->device_id);
     /* PCI Status */
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
                                         PCI_STATUS_FAST_BACK);
-    /* PCI Revision ID */
-    pci_config_set_revision(pci_conf, e100_device->revision);
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     /* PCI Latency Timer */
     pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
     /* Capability Pointer is set by PCI framework. */
@@ -499,12 +524,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
     case i82559ER:
     case i82562:
     case i82801:
-        break;
     case i82559C:
-#if EEPROM_SIZE > 0
-        pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_INTEL);
-        pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
-#endif
         break;
     default:
         logout("Device %X is undefined!\n", device);
@@ -590,8 +610,7 @@ static void nic_selective_reset(EEPRO100State * s)
     TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
 
     memset(s->mem, 0, sizeof(s->mem));
-    uint32_t val = BIT(21);
-    memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
+    e100_write_reg4(s, SCBCtrlMDI, BIT(21));
 
     assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
     memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
@@ -694,22 +713,26 @@ static void dump_statistics(EEPRO100State * s)
      * values which really matter.
      * Number of data should check configuration!!!
      */
-    cpu_physical_memory_write(s->statsaddr,
-                              (uint8_t *) & s->statistics, s->stats_size);
-    stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
-    stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
-    stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
-    stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
+    pci_dma_write(&s->dev, s->statsaddr,
+                  (uint8_t *) &s->statistics, s->stats_size);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 0,
+                   s->statistics.tx_good_frames);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 36,
+                   s->statistics.rx_good_frames);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 48,
+                   s->statistics.rx_resource_errors);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 60,
+                   s->statistics.rx_short_frame_errors);
 #if 0
-    stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
-    stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
+    stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames);
+    stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames);
     missing("CU dump statistical counters");
 #endif
 }
 
 static void read_cb(EEPRO100State *s)
 {
-    cpu_physical_memory_read(s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
+    pci_dma_read(&s->dev, s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
     s->tx.status = le16_to_cpu(s->tx.status);
     s->tx.command = le16_to_cpu(s->tx.command);
     s->tx.link = le32_to_cpu(s->tx.link);
@@ -739,18 +762,17 @@ static void tx_command(EEPRO100State *s)
     }
     assert(tcb_bytes <= sizeof(buf));
     while (size < tcb_bytes) {
-        uint32_t tx_buffer_address = ldl_phys(tbd_address);
-        uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+        uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
+        uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
 #if 0
-        uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+        uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
 #endif
         tbd_address += 8;
         TRACE(RXTX, logout
             ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
              tx_buffer_address, tx_buffer_size));
         tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-        cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                 tx_buffer_size);
+        pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size);
         size += tx_buffer_size;
     }
     if (tbd_array == 0xffffffff) {
@@ -761,16 +783,19 @@ static void tx_command(EEPRO100State *s)
         if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
             /* Extended Flexible TCB. */
             for (; tbd_count < 2; tbd_count++) {
-                uint32_t tx_buffer_address = ldl_phys(tbd_address);
-                uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
-                uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+                uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev,
+                                                            tbd_address);
+                uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev,
+                                                          tbd_address + 4);
+                uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev,
+                                                        tbd_address + 6);
                 tbd_address += 8;
                 TRACE(RXTX, logout
                     ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
                      tx_buffer_address, tx_buffer_size));
                 tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-                cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                         tx_buffer_size);
+                pci_dma_read(&s->dev, tx_buffer_address,
+                             &buf[size], tx_buffer_size);
                 size += tx_buffer_size;
                 if (tx_buffer_el & 1) {
                     break;
@@ -779,16 +804,16 @@ static void tx_command(EEPRO100State *s)
         }
         tbd_address = tbd_array;
         for (; tbd_count < s->tx.tbd_count; tbd_count++) {
-            uint32_t tx_buffer_address = ldl_phys(tbd_address);
-            uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
-            uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+            uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
+            uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
+            uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
             tbd_address += 8;
             TRACE(RXTX, logout
                 ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
                  tx_buffer_address, tx_buffer_size));
             tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-            cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                     tx_buffer_size);
+            pci_dma_read(&s->dev, tx_buffer_address,
+                         &buf[size], tx_buffer_size);
             size += tx_buffer_size;
             if (tx_buffer_el & 1) {
                 break;
@@ -813,7 +838,7 @@ static void set_multicast_list(EEPRO100State *s)
     TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
     for (i = 0; i < multicast_count; i += 6) {
         uint8_t multicast_addr[6];
-        cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6);
+        pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
         TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
         unsigned mcast_idx = compute_mcast_idx(multicast_addr);
         assert(mcast_idx < 64);
@@ -847,12 +872,12 @@ static void action_command(EEPRO100State *s)
             /* Do nothing. */
             break;
         case CmdIASetup:
-            cpu_physical_memory_read(s->cb_address + 8, &s->conf.macaddr.a[0], 6);
+            pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6);
             TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
             break;
         case CmdConfigure:
-            cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
-                                     sizeof(s->configuration));
+            pci_dma_read(&s->dev, s->cb_address + 8,
+                         &s->configuration[0], sizeof(s->configuration));
             TRACE(OTHER, logout("configuration: %s\n",
                                 nic_dump(&s->configuration[0], 16)));
             TRACE(OTHER, logout("configuration: %s\n",
@@ -889,7 +914,8 @@ static void action_command(EEPRO100State *s)
             break;
         }
         /* Write new status. */
-        stw_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
+        stw_le_pci_dma(&s->dev, s->cb_address,
+                       s->tx.status | ok_status | STATUS_C);
         if (bit_i) {
             /* CU completed action. */
             eepro100_cx_interrupt(s);
@@ -928,7 +954,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
             logout("unexpected CU state is %u\n", cu_state);
         }
         set_cu_state(s, cu_active);
-        s->cu_offset = s->pointer;
+        s->cu_offset = e100_read_reg4(s, SCBPointer);
         action_command(s);
         break;
     case CU_RESUME:
@@ -949,25 +975,33 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
         break;
     case CU_STATSADDR:
         /* Load dump counters address. */
-        s->statsaddr = s->pointer;
-        TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
+        s->statsaddr = e100_read_reg4(s, SCBPointer);
+        TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
+        if (s->statsaddr & 3) {
+            /* Memory must be Dword aligned. */
+            logout("unaligned dump counters address\n");
+            /* Handling of misaligned addresses is undefined.
+             * Here we align the address by ignoring the lower bits. */
+            /* TODO: Test unaligned dump counter address on real hardware. */
+            s->statsaddr &= ~3;
+        }
         break;
     case CU_SHOWSTATS:
         /* Dump statistical counters. */
         TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
         dump_statistics(s);
-        stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
+        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005);
         break;
     case CU_CMD_BASE:
         /* Load CU base. */
         TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
-        s->cu_base = s->pointer;
+        s->cu_base = e100_read_reg4(s, SCBPointer);
         break;
     case CU_DUMPSTATS:
         /* Dump and reset statistical counters. */
         TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
         dump_statistics(s);
-        stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
+        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007);
         memset(&s->statistics, 0, sizeof(s->statistics));
         break;
     case CU_SRESUME:
@@ -994,7 +1028,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
 #endif
         }
         set_ru_state(s, ru_ready);
-        s->ru_offset = s->pointer;
+        s->ru_offset = e100_read_reg4(s, SCBPointer);
         TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
         break;
     case RX_RESUME:
@@ -1018,7 +1052,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
     case RX_ADDR_LOAD:
         /* Load RU base. */
         TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
-        s->ru_base = s->pointer;
+        s->ru_base = e100_read_reg4(s, SCBPointer);
         break;
     default:
         logout("val=0x%02x (undefined RU command)\n", val);
@@ -1050,8 +1084,7 @@ static void eepro100_write_command(EEPRO100State * s, uint8_t val)
 
 static uint16_t eepro100_read_eeprom(EEPRO100State * s)
 {
-    uint16_t val;
-    memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
+    uint16_t val = e100_read_reg2(s, SCBeeprom);
     if (eeprom93xx_read(s->eeprom)) {
         val |= EEPROM_DO;
     } else {
@@ -1065,7 +1098,7 @@ static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
 {
     TRACE(EEPROM, logout("val=0x%02x\n", val));
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
 #if 0
     val = SET_MASKED(val, 0x31, eeprom->value);
 #endif
@@ -1076,12 +1109,6 @@ static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
     eeprom93xx_write(eeprom, eecs, eesk, eedi);
 }
 
-static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
-{
-    s->pointer = le32_to_cpu(val);
-    TRACE(OTHER, logout("val=0x%08x\n", val));
-}
-
 /*****************************************************************************
  *
  * MDI emulation.
@@ -1121,8 +1148,7 @@ static const char *reg2name(uint8_t reg)
 
 static uint32_t eepro100_read_mdi(EEPRO100State * s)
 {
-    uint32_t val;
-    memcpy(&val, &s->mem[0x10], sizeof(val));
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
 
 #ifdef DEBUG_EEPRO100
     uint8_t raiseint = (val & BIT(29)) >> 29;
@@ -1139,8 +1165,9 @@ static uint32_t eepro100_read_mdi(EEPRO100State * s)
     return val;
 }
 
-static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
+static void eepro100_write_mdi(EEPRO100State *s)
 {
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
     uint8_t raiseint = (val & BIT(29)) >> 29;
     uint8_t opcode = (val & BITS(27, 26)) >> 26;
     uint8_t phy = (val & BITS(25, 21)) >> 21;
@@ -1231,7 +1258,7 @@ static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
         }
     }
     val = (val & 0xffff0000) + data;
-    memcpy(&s->mem[0x10], &val, sizeof(val));
+    e100_write_reg4(s, SCBCtrlMDI, val);
 }
 
 /*****************************************************************************
@@ -1256,9 +1283,9 @@ static uint32_t eepro100_read_port(EEPRO100State * s)
     return 0;
 }
 
-static void eepro100_write_port(EEPRO100State * s, uint32_t val)
+static void eepro100_write_port(EEPRO100State *s)
 {
-    val = le32_to_cpu(val);
+    uint32_t val = e100_read_reg4(s, SCBPort);
     uint32_t address = (val & ~PORT_SELECTION_MASK);
     uint8_t selection = (val & PORT_SELECTION_MASK);
     switch (selection) {
@@ -1268,10 +1295,10 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
     case PORT_SELFTEST:
         TRACE(OTHER, logout("selftest address=0x%08x\n", address));
         eepro100_selftest_t data;
-        cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
+        pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data));
         data.st_sign = 0xffffffff;
         data.st_result = 0;
-        cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
+        pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data));
         break;
     case PORT_SELECTIVE_RESET:
         TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
@@ -1293,7 +1320,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
 {
     uint8_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&val, &s->mem[addr], sizeof(val));
+        val = s->mem[addr];
     }
 
     switch (addr) {
@@ -1316,10 +1343,20 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
     case SCBeeprom:
         val = eepro100_read_eeprom(s);
         break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+    case SCBCtrlMDI + 3:
+        val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
     case SCBpmdr:       /* Power Management Driver Register */
         val = 0;
         TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
+    case SCBgctrl:      /* General Control Register */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
     case SCBgstat:      /* General Status Register */
         /* 100 Mbps full duplex, valid link */
         val = 0x07;
@@ -1336,7 +1373,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
 {
     uint16_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&val, &s->mem[addr], sizeof(val));
+        val = e100_read_reg2(s, addr);
     }
 
     switch (addr) {
@@ -1348,6 +1385,11 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
         val = eepro100_read_eeprom(s);
         TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 2:
+        val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
     default:
         logout("addr=%s val=0x%04x\n", regname(addr), val);
         missing("unknown word read");
@@ -1359,7 +1401,7 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
 {
     uint32_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&val, &s->mem[addr], sizeof(val));
+        val = e100_read_reg4(s, addr);
     }
 
     switch (addr) {
@@ -1367,15 +1409,16 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
         TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBPointer:
-#if 0
-        val = eepro100_read_pointer(s);
-#endif
         TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBPort:
         val = eepro100_read_port(s);
         TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
+    case SCBflash:
+        val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
     case SCBCtrlMDI:
         val = eepro100_read_mdi(s);
         break;
@@ -1390,27 +1433,43 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
 {
     /* SCBStatus is readonly. */
     if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&s->mem[addr], &val, sizeof(val));
+        s->mem[addr] = val;
     }
 
-    TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-
     switch (addr) {
     case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBAck:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         eepro100_acknowledge(s);
         break;
     case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         eepro100_write_command(s, val);
         break;
     case SCBIntmask:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         if (val & BIT(1)) {
             eepro100_swi_interrupt(s);
         }
         eepro100_interrupt(s, 0);
         break;
+    case SCBPointer:
+    case SCBPointer + 1:
+    case SCBPointer + 2:
+    case SCBPointer + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort:
+    case SCBPort + 1:
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
     case SCBPort + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
     case SCBFlow:       /* does not exist on 82557 */
     case SCBFlow + 1:
     case SCBFlow + 2:
@@ -1418,8 +1477,18 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
         TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         eepro100_write_eeprom(s->eeprom, val);
         break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
     default:
         logout("addr=%s val=0x%02x\n", regname(addr), val);
         missing("unknown byte write");
@@ -1430,23 +1499,42 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
 {
     /* SCBStatus is readonly. */
     if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&s->mem[addr], &val, sizeof(val));
+        e100_write_reg2(s, addr, val);
     }
 
-    TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-
     switch (addr) {
     case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         s->mem[SCBAck] = (val >> 8);
         eepro100_acknowledge(s);
         break;
     case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         eepro100_write_command(s, val);
         eepro100_write1(s, SCBIntmask, val >> 8);
         break;
+    case SCBPointer:
+    case SCBPointer + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
     case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         eepro100_write_eeprom(s->eeprom, val);
         break;
+    case SCBCtrlMDI:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
     default:
         logout("addr=%s val=0x%04x\n", regname(addr), val);
         missing("unknown word write");
@@ -1456,19 +1544,25 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
 static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
 {
     if (addr <= sizeof(s->mem) - sizeof(val)) {
-        memcpy(&s->mem[addr], &val, sizeof(val));
+        e100_write_reg4(s, addr, val);
     }
 
     switch (addr) {
     case SCBPointer:
-        eepro100_write_pointer(s, val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBPort:
         TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        eepro100_write_port(s, val);
+        eepro100_write_port(s);
+        break;
+    case SCBflash:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        val = val >> 16;
+        eepro100_write_eeprom(s->eeprom, val);
         break;
     case SCBCtrlMDI:
-        eepro100_write_mdi(s, val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        eepro100_write_mdi(s);
         break;
     default:
         logout("addr=%s val=0x%08x\n", regname(addr), val);
@@ -1476,165 +1570,38 @@ static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
     }
 }
 
-/*****************************************************************************
- *
- * Port mapped I/O.
- *
- ****************************************************************************/
-
-static uint32_t ioport_read1(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read1(s, addr - s->region[1]);
-}
-
-static uint32_t ioport_read2(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-    return eepro100_read2(s, addr - s->region[1]);
-}
-
-static uint32_t ioport_read4(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-    return eepro100_read4(s, addr - s->region[1]);
-}
-
-static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write1(s, addr - s->region[1], val);
-}
-
-static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-    eepro100_write2(s, addr - s->region[1], val);
-}
-
-static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-    eepro100_write4(s, addr - s->region[1], val);
-}
-
-/***********************************************************/
-/* PCI EEPRO100 definitions */
-
-static void pci_map(PCIDevice * pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
-          "size=0x%08"FMT_PCIBUS", type=%d\n",
-          region_num, addr, size, type));
-
-    assert(region_num == 1);
-    register_ioport_write(addr, size, 1, ioport_write1, s);
-    register_ioport_read(addr, size, 1, ioport_read1, s);
-    register_ioport_write(addr, size, 2, ioport_write2, s);
-    register_ioport_read(addr, size, 2, ioport_read2, s);
-    register_ioport_write(addr, size, 4, ioport_write4, s);
-    register_ioport_read(addr, size, 4, ioport_read4, s);
-
-    s->region[region_num] = addr;
-}
-
-/*****************************************************************************
- *
- * Memory mapped I/O.
- *
- ****************************************************************************/
-
-static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write1(s, addr, val);
-}
-
-static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t eepro100_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write2(s, addr, val);
-}
-
-static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write4(s, addr, val);
-}
 
-static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read1(s, addr);
+    switch (size) {
+    case 1: return eepro100_read1(s, addr);
+    case 2: return eepro100_read2(s, addr);
+    case 4: return eepro100_read4(s, addr);
+    default: abort();
+    }
 }
 
-static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
+static void eepro100_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t data, unsigned size)
 {
     EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read2(s, addr);
-}
 
-static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read4(s, addr);
+    switch (size) {
+    case 1: return eepro100_write1(s, addr, data);
+    case 2: return eepro100_write2(s, addr, data);
+    case 4: return eepro100_write4(s, addr, data);
+    default: abort();
+    }
 }
 
-static CPUWriteMemoryFunc * const pci_mmio_write[] = {
-    pci_mmio_writeb,
-    pci_mmio_writew,
-    pci_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pci_mmio_read[] = {
-    pci_mmio_readb,
-    pci_mmio_readw,
-    pci_mmio_readl
+static const MemoryRegionOps eepro100_ops = {
+    .read = eepro100_read,
+    .write = eepro100_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
-                         pcibus_t addr, pcibus_t size, int type)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
-          "size=0x%08"FMT_PCIBUS", type=%d\n",
-          region_num, addr, size, type));
-
-    assert(region_num == 0 || region_num == 2);
-
-    /* Map control / status registers and flash. */
-    cpu_register_physical_memory(addr, size, s->mmio_index);
-    s->region[region_num] = addr;
-}
-
 static int nic_can_receive(VLANClientState *nc)
 {
     EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1653,19 +1620,32 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
      */
     EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
     uint16_t rfd_status = 0xa000;
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    uint8_t min_buf[60];
+#endif
     static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+#endif
+
     if (s->configuration[8] & 0x80) {
         /* CSMA is disabled. */
         logout("%p received while CSMA is disabled\n", s);
         return -1;
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
     } else if (size < 64 && (s->configuration[7] & BIT(0))) {
         /* Short frame and configuration byte 7/0 (discard short receive) set:
          * Short frame is discarded */
         logout("%p received short frame (%zu byte)\n", s, size);
         s->statistics.rx_short_frame_errors++;
-#if 0
         return -1;
 #endif
     } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
@@ -1734,8 +1714,8 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
     }
     /* !!! */
     eepro100_rx_t rx;
-    cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
-                             offsetof(eepro100_rx_t, packet));
+    pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
+                 (uint8_t *) &rx, sizeof(eepro100_rx_t));
     uint16_t rfd_command = le16_to_cpu(rx.command);
     uint16_t rfd_size = le16_to_cpu(rx.size);
 
@@ -1744,14 +1724,17 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
             "(%zu bytes); data truncated\n", rfd_size, size);
         size = rfd_size;
     }
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
     if (size < 64) {
         rfd_status |= 0x0080;
     }
+#endif
     TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
           rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
-    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
-             rfd_status);
-    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
+    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
+                offsetof(eepro100_rx_t, status), rfd_status);
+    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
+                offsetof(eepro100_rx_t, count), size);
     /* Early receive interrupt not supported. */
 #if 0
     eepro100_er_interrupt(s);
@@ -1765,8 +1748,8 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
 #if 0
     assert(!(s->configuration[17] & BIT(0)));
 #endif
-    cpu_physical_memory_write(s->ru_base + s->ru_offset +
-                              offsetof(eepro100_rx_t, packet), buf, size);
+    pci_dma_write(&s->dev, s->ru_base + s->ru_offset +
+                  sizeof(eepro100_rx_t), buf, size);
     s->statistics.rx_good_frames++;
     eepro100_fr_interrupt(s);
     s->ru_offset = le32_to_cpu(rx.link);
@@ -1801,7 +1784,6 @@ static const VMStateDescription vmstate_eepro100 = {
         /* The eeprom should be saved and restored by its own routines. */
         VMSTATE_UINT32(device, EEPRO100State),
         /* TODO check device. */
-        VMSTATE_UINT32(pointer, EEPRO100State),
         VMSTATE_UINT32(cu_base, EEPRO100State),
         VMSTATE_UINT32(cu_offset, EEPRO100State),
         VMSTATE_UINT32(ru_base, EEPRO100State),
@@ -1846,7 +1828,9 @@ static int pci_nic_uninit(PCIDevice *pci_dev)
 {
     EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
 
-    cpu_unregister_io_memory(s->mmio_index);
+    memory_region_destroy(&s->mmio_bar);
+    memory_region_destroy(&s->io_bar);
+    memory_region_destroy(&s->flash_bar);
     vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
     eeprom93xx_free(&pci_dev->qdev, s->eeprom);
     qemu_del_vlan_client(&s->nic->nc);
@@ -1878,21 +1862,19 @@ static int e100_nic_init(PCIDevice *pci_dev)
     s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
 
     /* Handler for memory-mapped I/O */
-    s->mmio_index =
-        cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
-                               DEVICE_NATIVE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY |
-                           PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
-    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
-                           pci_map);
-    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           pci_mmio_map);
+    memory_region_init_io(&s->mmio_bar, &eepro100_ops, s, "eepro100-mmio",
+                          PCI_MEM_SIZE);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
+    memory_region_init_io(&s->io_bar, &eepro100_ops, s, "eepro100-io",
+                          PCI_IO_SIZE);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    /* FIXME: flash aliases to mmio?! */
+    memory_region_init_io(&s->flash_bar, &eepro100_ops, s, "eepro100-flash",
+                          PCI_FLASH_SIZE);
+    pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
-    assert(s->region[1] == 0);
 
     nic_reset(s);
 
@@ -1904,7 +1886,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
 
     qemu_register_reset(nic_reset, s);
 
-    s->vmstate = qemu_malloc(sizeof(vmstate_eepro100));
+    s->vmstate = g_malloc(sizeof(vmstate_eepro100));
     memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
     s->vmstate->name = s->nic->nc.model;
     vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
@@ -1920,9 +1902,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.desc = "Intel i82550 Ethernet",
         .device = i82550,
         /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0c, 0x0d, 0x0e. */
-        .revision = 0x0e,
+        .pci.revision = 0x0e,
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         /* TODO: check extended tcb support. */
@@ -1932,9 +1914,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82551",
         .pci.qdev.desc = "Intel i82551 Ethernet",
         .device = i82551,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0f, 0x10. */
-        .revision = 0x0f,
+        .pci.revision = 0x0f,
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         .has_extended_tcb_support = true,
@@ -1943,29 +1925,29 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82557a",
         .pci.qdev.desc = "Intel i82557A Ethernet",
         .device = i82557A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x01,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x01,
         .power_management = false,
     },{
         .pci.qdev.name = "i82557b",
         .pci.qdev.desc = "Intel i82557B Ethernet",
         .device = i82557B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x02,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x02,
         .power_management = false,
     },{
         .pci.qdev.name = "i82557c",
         .pci.qdev.desc = "Intel i82557C Ethernet",
         .device = i82557C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x03,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x03,
         .power_management = false,
     },{
         .pci.qdev.name = "i82558a",
         .pci.qdev.desc = "Intel i82558A Ethernet",
         .device = i82558A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x04,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x04,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -1973,8 +1955,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82558b",
         .pci.qdev.desc = "Intel i82558B Ethernet",
         .device = i82558B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x05,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x05,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -1982,8 +1964,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559a",
         .pci.qdev.desc = "Intel i82559A Ethernet",
         .device = i82559A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x06,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x06,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -1991,8 +1973,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559b",
         .pci.qdev.desc = "Intel i82559B Ethernet",
         .device = i82559B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x07,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x07,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -2000,12 +1982,16 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559c",
         .pci.qdev.desc = "Intel i82559C Ethernet",
         .device = i82559C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
 #if 0
-        .revision = 0x08,
+        .pci.revision = 0x08,
 #endif
         /* TODO: Windows wants revision id 0x0c. */
-        .revision = 0x0c,
+        .pci.revision = 0x0c,
+#if EEPROM_SIZE > 0
+        .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+        .pci.subsystem_id = 0x0040,
+#endif
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -2013,8 +1999,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559er",
         .pci.qdev.desc = "Intel i82559ER Ethernet",
         .device = i82559ER,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        .revision = 0x09,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.revision = 0x09,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -2023,9 +2009,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.desc = "Intel i82562 Ethernet",
         .device = i82562,
         /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* TODO: wrong revision id. */
-        .revision = 0x0e,
+        .pci.revision = 0x0e,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -2034,8 +2020,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82801",
         .pci.qdev.desc = "Intel i82801 Ethernet",
         .device = i82801,
-        .device_id = 0x2449,
-        .revision = 0x03,
+        .pci.device_id = 0x2449,
+        .pci.revision = 0x03,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
@@ -2054,7 +2040,9 @@ 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->vendor_id = PCI_VENDOR_ID_INTEL;
+        pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
+        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 660b28f2253b734ad7563acd919e09b7e9000274..4c7158d1a59a753bf2eeacfd63c0a7aa75b61355 100644 (file)
@@ -75,7 +75,7 @@ struct _eeprom_t {
     uint8_t  tick;
     uint8_t  address;
     uint8_t  command;
-    uint8_t  writeable;
+    uint8_t  writable;
 
     uint8_t eecs;
     uint8_t eesk;
@@ -130,7 +130,7 @@ static const VMStateDescription vmstate_eeprom = {
         VMSTATE_UINT8(tick, eeprom_t),
         VMSTATE_UINT8(address, eeprom_t),
         VMSTATE_UINT8(command, eeprom_t),
-        VMSTATE_UINT8(writeable, eeprom_t),
+        VMSTATE_UINT8(writable, eeprom_t),
 
         VMSTATE_UINT8(eecs, eeprom_t),
         VMSTATE_UINT8(eesk, eeprom_t),
@@ -165,7 +165,7 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
         address = 0x0;
     } else if (eeprom->eecs && ! eecs) {
         /* End chip select cycle. This triggers write / erase. */
-        if (eeprom->writeable) {
+        if (eeprom->writable) {
             uint8_t subcommand = address >> (eeprom->addrbits - 2);
             if (command == 0 && subcommand == 2) {
                 /* Erase all. */
@@ -232,7 +232,7 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
                     switch (address >> (eeprom->addrbits - 2)) {
                         case 0:
                             logout("write disable command\n");
-                            eeprom->writeable = 0;
+                            eeprom->writable = 0;
                             break;
                         case 1:
                             logout("write all command\n");
@@ -242,7 +242,7 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
                             break;
                         case 3:
                             logout("write enable command\n");
-                            eeprom->writeable = 1;
+                            eeprom->writable = 1;
                             break;
                     }
                 } else {
@@ -310,7 +310,7 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
             addrbits = 6;
     }
 
-    eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2);
+    eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2);
     eeprom->size = nwords;
     eeprom->addrbits = addrbits;
     /* Output DO is tristate, read results in 1. */
@@ -325,7 +325,7 @@ void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
     /* Destroy EEPROM. */
     logout("eeprom = 0x%p\n", eeprom);
     vmstate_unregister(dev, &vmstate_eeprom, eeprom);
-    qemu_free(eeprom);
+    g_free(eeprom);
 }
 
 uint16_t *eeprom93xx_data(eeprom_t *eeprom)
index 0bd72350b4398744857e799462268c91180e9948..6af357fc1309f0fe042ce90b61e7e1d825cec50d 100644 (file)
@@ -150,7 +150,7 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
         i++;
     }
     if (nsyms) {
-        syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+        syms = g_realloc(syms, nsyms * sizeof(*syms));
 
         qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
         for (i = 0; i < nsyms - 1; i++) {
@@ -159,7 +159,7 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
             }
         }
     } else {
-        qemu_free(syms);
+        g_free(syms);
         syms = NULL;
     }
 
@@ -173,19 +173,19 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
         goto fail;
 
     /* Commit */
-    s = qemu_mallocz(sizeof(*s));
+    s = g_malloc0(sizeof(*s));
     s->lookup_symbol = glue(lookup_symbol, SZ);
     glue(s->disas_symtab.elf, SZ) = syms;
     s->disas_num_syms = nsyms;
     s->disas_strtab = str;
     s->next = syminfos;
     syminfos = s;
-    qemu_free(shdr_table);
+    g_free(shdr_table);
     return 0;
  fail:
-    qemu_free(syms);
-    qemu_free(str);
-    qemu_free(shdr_table);
+    g_free(syms);
+    g_free(str);
+    g_free(shdr_table);
     return -1;
 }
 
@@ -238,7 +238,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
 
     size = ehdr.e_phnum * sizeof(phdr[0]);
     lseek(fd, ehdr.e_phoff, SEEK_SET);
-    phdr = qemu_mallocz(size);
+    phdr = g_malloc0(size);
     if (!phdr)
         goto fail;
     if (read(fd, phdr, size) != size)
@@ -256,7 +256,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
         if (ph->p_type == PT_LOAD) {
             mem_size = ph->p_memsz;
             /* XXX: avoid allocating */
-            data = qemu_mallocz(mem_size);
+            data = g_malloc0(mem_size);
             if (ph->p_filesz > 0) {
                 if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
                     goto fail;
@@ -280,18 +280,18 @@ static int glue(load_elf, SZ)(const char *name, int fd,
             if ((addr + mem_size) > high)
                 high = addr + mem_size;
 
-            qemu_free(data);
+            g_free(data);
             data = NULL;
         }
     }
-    qemu_free(phdr);
+    g_free(phdr);
     if (lowaddr)
         *lowaddr = (uint64_t)(elf_sword)low;
     if (highaddr)
         *highaddr = (uint64_t)(elf_sword)high;
     return total_size;
  fail:
-    qemu_free(data);
-    qemu_free(phdr);
+    g_free(data);
+    g_free(phdr);
     return -1;
 }
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 40cb48cbb8638431f639a7d50bfb4608cb00d5f0..c5c16b048426dca1b280d76e1aa0098a9b4cea4e 100644 (file)
@@ -30,6 +30,7 @@
 #include "audiodev.h"
 #include "audio/audio.h"
 #include "pci.h"
+#include "dma.h"
 
 /* Missing stuff:
    SCTRL_P[12](END|ST)INC
@@ -268,6 +269,7 @@ struct chan {
 typedef struct ES1370State {
     PCIDevice dev;
     QEMUSoundCard card;
+    MemoryRegion io;
     struct chan chan[NB_CHANNELS];
     SWVoiceOut *dac_voice[2];
     SWVoiceIn *adc_voice;
@@ -775,7 +777,6 @@ IO_READ_PROTO (es1370_readl)
     return val;
 }
 
-
 static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
                                    int max, int *irq)
 {
@@ -802,7 +803,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
             if (!acquired)
                 break;
 
-            cpu_physical_memory_write (addr, tmpbuf, acquired);
+            pci_dma_write (&s->dev, addr, tmpbuf, acquired);
 
             temp -= acquired;
             addr += acquired;
@@ -816,7 +817,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
             int copied, to_copy;
 
             to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
-            cpu_physical_memory_read (addr, tmpbuf, to_copy);
+            pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
             copied = AUD_write (voice, tmpbuf, to_copy);
             if (!copied)
                 break;
@@ -906,23 +907,20 @@ static void es1370_adc_callback (void *opaque, int avail)
     es1370_run_channel (s, ADC_CHANNEL, avail);
 }
 
-static void es1370_map (PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
-{
-    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
-
-    (void) region_num;
-    (void) size;
-    (void) type;
-
-    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
-    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
-    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
+static const MemoryRegionPortio es1370_portio[] = {
+    { 0, 0x40 * 4, 1, .write = es1370_writeb, },
+    { 0, 0x40 * 2, 2, .write = es1370_writew, },
+    { 0, 0x40, 4, .write = es1370_writel, },
+    { 0, 0x40 * 4, 1, .read = es1370_readb, },
+    { 0, 0x40 * 2, 2, .read = es1370_readw, },
+    { 0, 0x40, 4, .read = es1370_readl, },
+    PORTIO_END_OF_LIST()
+};
 
-    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
-    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
-    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
-}
+static const MemoryRegionOps es1370_io_ops = {
+    .old_portio = es1370_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
 static const VMStateDescription vmstate_es1370_channel = {
     .name = "es1370_channel",
@@ -998,32 +996,20 @@ static int es1370_initfn (PCIDevice *dev)
     ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
     uint8_t *c = s->dev.config;
 
-    pci_config_set_vendor_id (c, PCI_VENDOR_ID_ENSONIQ);
-    pci_config_set_device_id (c, PCI_DEVICE_ID_ENSONIQ_ES1370);
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
-    pci_config_set_class (c, PCI_CLASS_MULTIMEDIA_AUDIO);
 
-#if 1
-    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x42;
-    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x49;
-    c[PCI_SUBSYSTEM_ID] = 0x4c;
-    c[PCI_SUBSYSTEM_ID + 1] = 0x4c;
-#else
-    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x74;
-    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x12;
-    c[PCI_SUBSYSTEM_ID] = 0x71;
-    c[PCI_SUBSYSTEM_ID + 1] = 0x13;
+#if 0
     c[PCI_CAPABILITY_LIST] = 0xdc;
     c[PCI_INTERRUPT_LINE] = 10;
     c[0xdc] = 0x00;
 #endif
 
-    /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 1;
     c[PCI_MIN_GNT] = 0x0c;
     c[PCI_MAX_LAT] = 0x80;
 
-    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
+    memory_region_init_io (&s->io, &es1370_io_ops, s, "es1370", 256);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     qemu_register_reset (es1370_on_reset, s);
 
     AUD_register_card ("es1370", &s->card);
@@ -1031,6 +1017,14 @@ static int es1370_initfn (PCIDevice *dev)
     return 0;
 }
 
+static int es1370_exitfn(PCIDevice *dev)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
+
+    memory_region_destroy (&s->io);
+    return 0;
+}
+
 int es1370_init (PCIBus *bus)
 {
     pci_create_simple (bus, -1, "ES1370");
@@ -1043,6 +1037,17 @@ static PCIDeviceInfo es1370_info = {
     .qdev.size    = sizeof (ES1370State),
     .qdev.vmsd    = &vmstate_es1370,
     .init         = es1370_initfn,
+    .exit         = es1370_exitfn,
+    .vendor_id    = PCI_VENDOR_ID_ENSONIQ,
+    .device_id    = PCI_DEVICE_ID_ENSONIQ_ES1370,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
+#if 1
+    .subsystem_vendor_id = 0x4942,
+    .subsystem_id = 0x4c4c,
+#else
+    .subsystem_vendor_id = 0x1274,
+    .subsystem_id = 0x1371,
+#endif
 };
 
 static void es1370_register (void)
index f6fd9192eaf28f3ca53a92f04f7848e7f81788c5..13c7e66b368df93f621c8f30f477b504ee7d2659 100644 (file)
--- a/hw/escc.c
+++ b/hw/escc.c
 #include "escc.h"
 #include "qemu-char.h"
 #include "console.h"
-
-/* debug serial */
-//#define DEBUG_SERIAL
-
-/* debug keyboard */
-//#define DEBUG_KBD
-
-/* debug mouse */
-//#define DEBUG_MOUSE
+#include "trace.h"
 
 /*
  * Chipset docs:
  *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
  */
 
-#ifdef DEBUG_SERIAL
-#define SER_DPRINTF(fmt, ...)                                   \
-    do { printf("SER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define SER_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_KBD
-#define KBD_DPRINTF(fmt, ...)                                   \
-    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define KBD_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_MOUSE
-#define MS_DPRINTF(fmt, ...)                                    \
-    do { printf("MSC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define MS_DPRINTF(fmt, ...)
-#endif
-
 typedef enum {
     chn_a, chn_b,
 } ChnID;
@@ -108,25 +81,26 @@ typedef struct {
 #define SERIAL_REGS 16
 typedef struct ChannelState {
     qemu_irq irq;
-    uint32_t reg;
     uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
-    ChnID chn; // this channel, A (base+4) or B (base+0)
-    ChnType type;
     struct ChannelState *otherchn;
-    uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
+    uint32_t reg;
+    uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
     SERIOQueue queue;
     CharDriverState *chr;
     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
     int disabled;
     int clock;
     uint32_t vmstate_dummy;
+    ChnID chn; // this channel, A (base+4) or B (base+0)
+    ChnType type;
+    uint8_t rx, tx;
 } ChannelState;
 
 struct SerialState {
     SysBusDevice busdev;
     struct ChannelState chn[2];
     uint32_t it_shift;
-    int mmio_index;
+    MemoryRegion mmio;
     uint32_t disabled;
     uint32_t frequency;
 };
@@ -249,7 +223,7 @@ static void put_queue(void *opaque, int b)
     ChannelState *s = opaque;
     SERIOQueue *q = &s->queue;
 
-    SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
+    trace_escc_put_queue(CHN_C(s), b);
     if (q->count >= SERIO_QUEUE_SIZE)
         return;
     q->data[q->wptr] = b;
@@ -273,7 +247,7 @@ static uint32_t get_queue(void *opaque)
             q->rptr = 0;
         q->count--;
     }
-    SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+    trace_escc_get_queue(CHN_C(s), val);
     if (q->count > 0)
         serial_receive_byte(s, 0);
     return val;
@@ -300,7 +274,7 @@ static void escc_update_irq(ChannelState *s)
     irq = escc_update_irq_chn(s);
     irq |= escc_update_irq_chn(s->otherchn);
 
-    SER_DPRINTF("IRQ = %d\n", irq);
+    trace_escc_update_irq(irq);
     qemu_set_irq(s->irq, irq);
 }
 
@@ -485,12 +459,12 @@ static void escc_update_parameters(ChannelState *s)
     ssp.parity = parity;
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
-    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
-                speed, parity, data_bits, stop_bits);
-    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
-static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void escc_mem_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -503,8 +477,7 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     s = &serial->chn[channel];
     switch (saddr) {
     case SERIAL_CTRL:
-        SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
-                    val & 0xff);
+        trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
         newreg = 0;
         switch (s->reg) {
         case W_CMD:
@@ -574,11 +547,11 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             s->reg = 0;
         break;
     case SERIAL_DATA:
-        SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
+        trace_escc_mem_writeb_data(CHN_C(s), val);
         s->tx = val;
         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
             if (s->chr)
-                qemu_chr_write(s->chr, &s->tx, 1);
+                qemu_chr_fe_write(s->chr, &s->tx, 1);
             else if (s->type == kbd && !s->disabled) {
                 handle_kbd_command(s, val);
             }
@@ -592,7 +565,8 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -605,8 +579,7 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
     s = &serial->chn[channel];
     switch (saddr) {
     case SERIAL_CTRL:
-        SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
-                    s->rregs[s->reg]);
+        trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
         ret = s->rregs[s->reg];
         s->reg = 0;
         return ret;
@@ -617,7 +590,7 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
             ret = get_queue(s);
         else
             ret = s->rx;
-        SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
+        trace_escc_mem_readb_data(CHN_C(s), ret);
         if (s->chr)
             qemu_chr_accept_input(s->chr);
         return ret;
@@ -627,6 +600,16 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static const MemoryRegionOps escc_mem_ops = {
+    .read = escc_mem_read,
+    .write = escc_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
 static int serial_can_receive(void *opaque)
 {
     ChannelState *s = opaque;
@@ -643,7 +626,7 @@ static int serial_can_receive(void *opaque)
 
 static void serial_receive_byte(ChannelState *s, int ch)
 {
-    SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
+    trace_escc_serial_receive_byte(CHN_C(s), ch);
     s->rregs[R_STATUS] |= STATUS_RXAV;
     s->rx = ch;
     set_rxint(s);
@@ -668,18 +651,6 @@ static void serial_event(void *opaque, int event)
         serial_receive_break(s);
 }
 
-static CPUReadMemoryFunc * const escc_mem_read[3] = {
-    escc_mem_readb,
-    NULL,
-    NULL,
-};
-
-static CPUWriteMemoryFunc * const escc_mem_write[3] = {
-    escc_mem_writeb,
-    NULL,
-    NULL,
-};
-
 static const VMStateDescription vmstate_escc_chn = {
     .name ="escc_chn",
     .version_id = 2,
@@ -712,7 +683,7 @@ static const VMStateDescription vmstate_escc = {
     }
 };
 
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
               CharDriverState *chrA, CharDriverState *chrB,
               int clock, int it_shift)
 {
@@ -737,7 +708,7 @@ int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
     }
 
     d = FROM_SYSBUS(SerialState, s);
-    return d->mmio_index;
+    return &d->mmio;
 }
 
 static const uint8_t keycodes[128] = {
@@ -767,8 +738,7 @@ static void sunkbd_event(void *opaque, int ch)
     ChannelState *s = opaque;
     int release = ch & 0x80;
 
-    KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
-                "press");
+    trace_escc_sunkbd_event_in(ch);
     switch (ch) {
     case 58: // Caps lock press
         s->caps_lock_mode ^= 1;
@@ -802,13 +772,13 @@ static void sunkbd_event(void *opaque, int ch)
     } else {
         ch = keycodes[ch & 0x7f];
     }
-    KBD_DPRINTF("Translated keycode %2.2x\n", ch);
+    trace_escc_sunkbd_event_out(ch);
     put_queue(s, ch | release);
 }
 
 static void handle_kbd_command(ChannelState *s, int val)
 {
-    KBD_DPRINTF("Command %d\n", val);
+    trace_escc_kbd_command(val);
     if (s->led_mode) { // Ignore led byte
         s->led_mode = 0;
         return;
@@ -840,8 +810,7 @@ static void sunmouse_event(void *opaque,
     ChannelState *s = opaque;
     int ch;
 
-    MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
-
+    trace_escc_sunmouse_event(dx, dy, buttons_state);
     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
 
     if (buttons_state & MOUSE_EVENT_LBUTTON)
@@ -901,7 +870,6 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
 static int escc_init1(SysBusDevice *dev)
 {
     SerialState *s = FROM_SYSBUS(SerialState, dev);
-    int io;
     unsigned int i;
 
     s->chn[0].disabled = s->disabled;
@@ -918,10 +886,9 @@ static int escc_init1(SysBusDevice *dev)
     s->chn[0].otherchn = &s->chn[1];
     s->chn[1].otherchn = &s->chn[0];
 
-    io = cpu_register_io_memory(escc_mem_read, escc_mem_write, s,
-                                DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, ESCC_SIZE << s->it_shift, io);
-    s->mmio_index = io;
+    memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
+                          ESCC_SIZE << s->it_shift);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     if (s->chn[0].type == mouse) {
         qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
index 015b9d0089ebd0ec779d780d62a9aa4dc30d6109..d1da46fd06c7bff4d6add21fad20d487af4284e0 100644 (file)
--- a/hw/escc.h
+++ b/hw/escc.h
@@ -1,6 +1,6 @@
 /* escc.c */
 #define ESCC_SIZE 4
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
               CharDriverState *chrA, CharDriverState *chrB,
               int clock, int it_shift);
 
index fa9d2a270667d67499b88e44e07e063e37609f65..b698a43fe6ede5e4fe9a9431a718905d7e8c5394 100644 (file)
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -25,9 +25,7 @@
 #include "sysbus.h"
 #include "scsi.h"
 #include "esp.h"
-
-/* debug ESP card */
-//#define DEBUG_ESP
+#include "trace.h"
 
 /*
  * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
  */
 
-#ifdef DEBUG_ESP
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("ESP: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
 #define ESP_ERROR(fmt, ...)                                             \
     do { printf("ESP ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
 
@@ -54,17 +45,18 @@ typedef struct ESPState ESPState;
 
 struct ESPState {
     SysBusDevice busdev;
-    uint32_t it_shift;
-    qemu_irq irq;
     uint8_t rregs[ESP_REGS];
     uint8_t wregs[ESP_REGS];
+    qemu_irq irq;
+    uint32_t it_shift;
     int32_t ti_size;
     uint32_t ti_rptr, ti_wptr;
-    uint8_t ti_buf[TI_BUFSZ];
-    uint32_t sense;
+    uint32_t status;
     uint32_t dma;
+    uint8_t ti_buf[TI_BUFSZ];
     SCSIBus bus;
     SCSIDevice *current_dev;
+    SCSIRequest *current_req;
     uint8_t cmdbuf[TI_BUFSZ];
     uint32_t cmdlen;
     uint32_t do_cmd;
@@ -74,13 +66,14 @@ struct ESPState {
     /* The size of the current DMA transfer.  Zero if no transfer is in
        progress.  */
     uint32_t dma_counter;
-    uint8_t *async_buf;
+    int dma_enabled;
+
     uint32_t async_len;
+    uint8_t *async_buf;
 
     ESPDMAMemoryReadWriteFunc dma_memory_read;
     ESPDMAMemoryReadWriteFunc dma_memory_write;
     void *dma_opaque;
-    int dma_enabled;
     void (*dma_cb)(ESPState *s);
 };
 
@@ -156,7 +149,7 @@ static void esp_raise_irq(ESPState *s)
     if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
         s->rregs[ESP_RSTAT] |= STAT_INT;
         qemu_irq_raise(s->irq);
-        DPRINTF("Raise IRQ\n");
+        trace_esp_raise_irq();
     }
 }
 
@@ -165,7 +158,7 @@ static void esp_lower_irq(ESPState *s)
     if (s->rregs[ESP_RSTAT] & STAT_INT) {
         s->rregs[ESP_RSTAT] &= ~STAT_INT;
         qemu_irq_lower(s->irq);
-        DPRINTF("Lower IRQ\n");
+        trace_esp_lower_irq();
     }
 }
 
@@ -176,17 +169,28 @@ static void esp_dma_enable(void *opaque, int irq, int level)
 
     if (level) {
         s->dma_enabled = 1;
-        DPRINTF("Raise enable\n");
+        trace_esp_dma_enable();
         if (s->dma_cb) {
             s->dma_cb(s);
             s->dma_cb = NULL;
         }
     } else {
-        DPRINTF("Lower enable\n");
+        trace_esp_dma_disable();
         s->dma_enabled = 0;
     }
 }
 
+static void esp_request_cancelled(SCSIRequest *req)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    if (req == s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
 static uint32_t get_cmd(ESPState *s, uint8_t *buf)
 {
     uint32_t dmalen;
@@ -199,21 +203,22 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
     } else {
         dmalen = s->ti_size;
         memcpy(buf, s->ti_buf, dmalen);
-        buf[0] = 0;
+        buf[0] = buf[2] >> 5;
     }
-    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
+    trace_esp_get_cmd(dmalen, target);
 
     s->ti_size = 0;
     s->ti_rptr = 0;
     s->ti_wptr = 0;
 
-    if (s->current_dev) {
+    if (s->current_req) {
         /* Started a new command before the old one finished.  Cancel it.  */
-        s->current_dev->info->cancel_io(s->current_dev, 0);
+        scsi_req_cancel(s->current_req);
         s->async_len = 0;
     }
 
-    if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) {
+    s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
+    if (!s->current_dev) {
         // No such drive
         s->rregs[ESP_RSTAT] = 0;
         s->rregs[ESP_RINTR] = INTR_DC;
@@ -221,7 +226,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
         esp_raise_irq(s);
         return 0;
     }
-    s->current_dev = s->bus.devs[target];
     return dmalen;
 }
 
@@ -229,10 +233,13 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
 {
     int32_t datalen;
     int lun;
+    SCSIDevice *current_lun;
 
-    DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
+    trace_esp_do_busid_cmd(busid);
     lun = busid & 7;
-    datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun);
+    current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
+    s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
+    datalen = scsi_req_enqueue(s->current_req);
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
@@ -240,11 +247,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
         s->dma_counter = 0;
         if (datalen > 0) {
             s->rregs[ESP_RSTAT] |= STAT_DI;
-            s->current_dev->info->read_data(s->current_dev, 0);
         } else {
             s->rregs[ESP_RSTAT] |= STAT_DO;
-            s->current_dev->info->write_data(s->current_dev, 0);
         }
+        scsi_req_continue(s->current_req);
     }
     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
     s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -295,7 +301,7 @@ static void handle_satn_stop(ESPState *s)
     }
     s->cmdlen = get_cmd(s, s->cmdbuf);
     if (s->cmdlen) {
-        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
+        trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@@ -306,8 +312,8 @@ static void handle_satn_stop(ESPState *s)
 
 static void write_response(ESPState *s)
 {
-    DPRINTF("Transfer status (sense=%d)\n", s->sense);
-    s->ti_buf[0] = s->sense;
+    trace_esp_write_response(s->status);
+    s->ti_buf[0] = s->status;
     s->ti_buf[1] = 0;
     if (s->dma) {
         s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
@@ -342,7 +348,7 @@ static void esp_do_dma(ESPState *s)
     to_device = (s->ti_size < 0);
     len = s->dma_left;
     if (s->do_cmd) {
-        DPRINTF("command len %d + %d\n", s->cmdlen, len);
+        trace_esp_do_dma(s->cmdlen, len);
         s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         s->ti_size = 0;
         s->cmdlen = 0;
@@ -370,53 +376,56 @@ static void esp_do_dma(ESPState *s)
     else
         s->ti_size -= len;
     if (s->async_len == 0) {
-        if (to_device) {
-            // ti_size is negative
-            s->current_dev->info->write_data(s->current_dev, 0);
-        } else {
-            s->current_dev->info->read_data(s->current_dev, 0);
-            /* If there is still data to be read from the device then
-               complete the DMA operation immediately.  Otherwise defer
-               until the scsi layer has completed.  */
-            if (s->dma_left == 0 && s->ti_size > 0) {
-                esp_dma_done(s);
-            }
+        scsi_req_continue(s->current_req);
+        /* If there is still data to be read from the device then
+           complete the DMA operation immediately.  Otherwise defer
+           until the scsi layer has completed.  */
+        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
+            return;
         }
-    } else {
-        /* Partially filled a scsi buffer. Complete immediately.  */
-        esp_dma_done(s);
     }
+
+    /* Partially filled a scsi buffer. Complete immediately.  */
+    esp_dma_done(s);
 }
 
-static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag,
-                                 uint32_t arg)
+static void esp_command_complete(SCSIRequest *req, uint32_t status)
 {
-    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent);
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
 
-    if (reason == SCSI_REASON_DONE) {
-        DPRINTF("SCSI Command complete\n");
-        if (s->ti_size != 0)
-            DPRINTF("SCSI command completed unexpectedly\n");
-        s->ti_size = 0;
-        s->dma_left = 0;
-        s->async_len = 0;
-        if (arg)
-            DPRINTF("Command failed\n");
-        s->sense = arg;
-        s->rregs[ESP_RSTAT] = STAT_ST;
-        esp_dma_done(s);
+    trace_esp_command_complete();
+    if (s->ti_size != 0) {
+        trace_esp_command_complete_unexpected();
+    }
+    s->ti_size = 0;
+    s->dma_left = 0;
+    s->async_len = 0;
+    if (status) {
+        trace_esp_command_complete_fail();
+    }
+    s->status = status;
+    s->rregs[ESP_RSTAT] = STAT_ST;
+    esp_dma_done(s);
+    if (s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
         s->current_dev = NULL;
-    } else {
-        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
-        s->async_len = arg;
-        s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0);
-        if (s->dma_left) {
-            esp_do_dma(s);
-        } else if (s->dma_counter != 0 && s->ti_size <= 0) {
-            /* If this was the last part of a DMA transfer then the
-               completion interrupt is deferred to here.  */
-            esp_dma_done(s);
-        }
+    }
+}
+
+static void esp_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    trace_esp_transfer_data(s->dma_left, s->ti_size);
+    s->async_len = len;
+    s->async_buf = scsi_req_get_buf(req);
+    if (s->dma_left) {
+        esp_do_dma(s);
+    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
+        /* If this was the last part of a DMA transfer then the
+           completion interrupt is deferred to here.  */
+        esp_dma_done(s);
     }
 }
 
@@ -436,13 +445,13 @@ static void handle_ti(ESPState *s)
         minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
     else
         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
-    DPRINTF("Transfer Information len %d\n", minlen);
+    trace_esp_handle_ti(minlen);
     if (s->dma) {
         s->dma_left = minlen;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
     } else if (s->do_cmd) {
-        DPRINTF("command len %d\n", s->cmdlen);
+        trace_esp_handle_ti_cmd(s->cmdlen);
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
@@ -501,7 +510,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t saddr, old_val;
 
     saddr = addr >> s->it_shift;
-    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
+    trace_esp_mem_readb(saddr, s->rregs[saddr]);
     switch (saddr) {
     case ESP_FIFO:
         if (s->ti_size > 0) {
@@ -542,8 +551,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     uint32_t saddr;
 
     saddr = addr >> s->it_shift;
-    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr],
-            val);
+    trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
     switch (saddr) {
     case ESP_TCLO:
     case ESP_TCMID:
@@ -571,21 +579,21 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         }
         switch(val & CMD_CMD) {
         case CMD_NOP:
-            DPRINTF("NOP (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_nop(val);
             break;
         case CMD_FLUSH:
-            DPRINTF("Flush FIFO (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_flush(val);
             //s->ti_size = 0;
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
             break;
         case CMD_RESET:
-            DPRINTF("Chip reset (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_reset(val);
             esp_soft_reset(&s->busdev.qdev);
             break;
         case CMD_BUSRESET:
-            DPRINTF("Bus reset (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_bus_reset(val);
             s->rregs[ESP_RINTR] = INTR_RST;
             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
                 esp_raise_irq(s);
@@ -595,41 +603,41 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             handle_ti(s);
             break;
         case CMD_ICCS:
-            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_iccs(val);
             write_response(s);
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSTAT] |= STAT_MI;
             break;
         case CMD_MSGACC:
-            DPRINTF("Message Accepted (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_msgacc(val);
             s->rregs[ESP_RINTR] = INTR_DC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
             esp_raise_irq(s);
             break;
         case CMD_PAD:
-            DPRINTF("Transfer padding (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_pad(val);
             s->rregs[ESP_RSTAT] = STAT_TC;
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             break;
         case CMD_SATN:
-            DPRINTF("Set ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_satn(val);
             break;
         case CMD_SEL:
-            DPRINTF("Select without ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_sel(val);
             handle_s_without_atn(s);
             break;
         case CMD_SELATN:
-            DPRINTF("Select with ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_selatn(val);
             handle_satn(s);
             break;
         case CMD_SELATNS:
-            DPRINTF("Select with ATN & stop (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_selatns(val);
             handle_satn_stop(s);
             break;
         case CMD_ENSEL:
-            DPRINTF("Enable selection (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_ensel(val);
             s->rregs[ESP_RINTR] = 0;
             break;
         default:
@@ -678,7 +686,7 @@ static const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32(ti_rptr, ESPState),
         VMSTATE_UINT32(ti_wptr, ESPState),
         VMSTATE_BUFFER(ti_buf, ESPState),
-        VMSTATE_UINT32(sense, ESPState),
+        VMSTATE_UINT32(status, ESPState),
         VMSTATE_UINT32(dma, ESPState),
         VMSTATE_BUFFER(cmdbuf, ESPState),
         VMSTATE_UINT32(cmdlen, ESPState),
@@ -714,6 +722,16 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
     *dma_enable = qdev_get_gpio_in(dev, 1);
 }
 
+static const struct SCSIBusInfo esp_scsi_info = {
+    .tcq = false,
+    .max_target = ESP_MAX_DEVS,
+    .max_lun = 7,
+
+    .transfer_data = esp_transfer_data,
+    .complete = esp_command_complete,
+    .cancel = esp_request_cancelled
+};
+
 static int esp_init1(SysBusDevice *dev)
 {
     ESPState *s = FROM_SYSBUS(ESPState, dev);
@@ -728,7 +746,7 @@ static int esp_init1(SysBusDevice *dev)
 
     qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
 
-    scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
+    scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info);
     return scsi_bus_legacy_handle_cmdline(&s->bus);
 }
 
index 01fb9d3e8280e2b7c9b3f83a77fda086892901b5..24e8fd880b3b9138c6ce08e30cd1808233363122 100644 (file)
  * THE SOFTWARE.
  */
 
+#include "net.h"
 #include "etraxfs_dma.h"
 
 qemu_irq *cris_pic_init_cpu(CPUState *env);
-void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr);
+
+/* Instantiate an ETRAXFS Ethernet MAC.  */
+static inline DeviceState *
+etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
+                 void *dma_out, void *dma_in)
+{
+    DeviceState *dev;
+    qemu_check_nic_model(nd, "fseth");
+
+    dev = qdev_create(NULL, "etraxfs-eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
+    qdev_prop_set_ptr(dev, "dma_out", dma_out);
+    qdev_prop_set_ptr(dev, "dma_in", dma_in);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    return dev;
+}
index c205ec1b8f443f297f7232c0b8e34d9698c7c7a7..02d01836ceaec2de9fdaf81a5a4f5f86de40004a 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <sys/time.h>
 #include "hw.h"
+#include "exec-memory.h"
 #include "qemu-common.h"
 #include "sysemu.h"
 
@@ -185,7 +186,7 @@ struct fs_dma_channel
 
 struct fs_dma_ctrl
 {
-       int map;
+       MemoryRegion mmio;
        int nr_channels;
        struct fs_dma_channel *channels;
 
@@ -562,13 +563,17 @@ static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr)
         return 0;
 }
 
-static uint32_t
-dma_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+dma_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
         struct fs_dma_ctrl *ctrl = opaque;
        int c;
        uint32_t r = 0;
 
+       if (size != 4) {
+               dma_rinvalid(opaque, addr);
+       }
+
        /* Make addr relative to this channel and bounded to nr regs.  */
        c = fs_channel(addr);
        addr &= 0xff;
@@ -599,20 +604,24 @@ dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
 static void
 dma_update_state(struct fs_dma_ctrl *ctrl, int c)
 {
-       if ((ctrl->channels[c].regs[RW_CFG] & 1) != 3) {
-               if (ctrl->channels[c].regs[RW_CFG] & 2)
-                       ctrl->channels[c].state = STOPPED;
-               if (!(ctrl->channels[c].regs[RW_CFG] & 1))
-                       ctrl->channels[c].state = RST;
-       }
+       if (ctrl->channels[c].regs[RW_CFG] & 2)
+               ctrl->channels[c].state = STOPPED;
+       if (!(ctrl->channels[c].regs[RW_CFG] & 1))
+               ctrl->channels[c].state = RST;
 }
 
 static void
-dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+dma_write(void *opaque, target_phys_addr_t addr,
+         uint64_t val64, unsigned int size)
 {
         struct fs_dma_ctrl *ctrl = opaque;
+       uint32_t value = val64;
        int c;
 
+       if (size != 4) {
+               dma_winvalid(opaque, addr, value);
+       }
+
         /* Make addr relative to this channel and bounded to nr regs.  */
        c = fs_channel(addr);
         addr &= 0xff;
@@ -668,16 +677,14 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
         }
 }
 
-static CPUReadMemoryFunc * const dma_read[] = {
-       &dma_rinvalid,
-       &dma_rinvalid,
-       &dma_readl,
-};
-
-static CPUWriteMemoryFunc * const dma_write[] = {
-       &dma_winvalid,
-       &dma_winvalid,
-       &dma_writel,
+static const MemoryRegionOps dma_ops = {
+       .read = dma_read,
+       .write = dma_write,
+       .endianness = DEVICE_NATIVE_ENDIAN,
+       .valid = {
+               .min_access_size = 1,
+               .max_access_size = 4
+       }
 };
 
 static int etraxfs_dmac_run(void *opaque)
@@ -732,7 +739,7 @@ static void DMA_run(void *opaque)
     struct fs_dma_ctrl *etraxfs_dmac = opaque;
     int p = 1;
 
-    if (vm_running)
+    if (runstate_is_running())
         p = etraxfs_dmac_run(etraxfs_dmac);
 
     if (p)
@@ -743,14 +750,16 @@ void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels)
 {
        struct fs_dma_ctrl *ctrl = NULL;
 
-       ctrl = qemu_mallocz(sizeof *ctrl);
+       ctrl = g_malloc0(sizeof *ctrl);
 
         ctrl->bh = qemu_bh_new(DMA_run, ctrl);
 
        ctrl->nr_channels = nr_channels;
-       ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels);
+       ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
+
+       memory_region_init_io(&ctrl->mmio, &dma_ops, ctrl, "etraxfs-dma",
+                             nr_channels * 0x2000);
+       memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
 
-       ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl, DEVICE_NATIVE_ENDIAN);
-       cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map);
        return ctrl;
 }
index 6aa4007203d1d3a0fbf072e648627e5f5919234d..246a279b206e0253f2ba36bebcb352a57fa27e71 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include <stdio.h>
-#include "hw.h"
+#include "sysbus.h"
 #include "net.h"
 #include "etraxfs.h"
 
@@ -319,6 +319,8 @@ static void mdio_cycle(struct qemu_mdio *bus)
 
 struct fs_eth
 {
+       SysBusDevice busdev;
+       MemoryRegion mmio;
        NICState *nic;
        NICConf conf;
        int ethregs;
@@ -327,8 +329,14 @@ struct fs_eth
        uint8_t macaddr[2][6];
        uint32_t regs[FS_ETH_MAX_REGS];
 
-       struct etraxfs_dma_client *dma_out;
-       struct etraxfs_dma_client *dma_in;
+       union {
+               void *vdma_out;
+               struct etraxfs_dma_client *dma_out;
+       };
+       union {
+               void *vdma_in;
+               struct etraxfs_dma_client *dma_in;
+       };
 
        /* MDIO bus.  */
        struct qemu_mdio mdio_bus;
@@ -366,7 +374,8 @@ static void eth_validate_duplex(struct fs_eth *eth)
        }
 }
 
-static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+eth_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
        struct fs_eth *eth = opaque;
        uint32_t r = 0;
@@ -410,9 +419,11 @@ static void eth_update_ma(struct fs_eth *eth, int ma)
 }
 
 static void
-eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+eth_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
        struct fs_eth *eth = opaque;
+       uint32_t value = val64;
 
        addr >>= 2;
        switch (addr)
@@ -546,14 +557,14 @@ static void eth_set_link(VLANClientState *nc)
        eth->phy.link = !nc->link_down;
 }
 
-static CPUReadMemoryFunc * const eth_read[] = {
-       NULL, NULL,
-       &eth_readl,
-};
-
-static CPUWriteMemoryFunc * const eth_write[] = {
-       NULL, NULL,
-       &eth_writel,
+static const MemoryRegionOps eth_ops = {
+       .read = eth_read,
+       .write = eth_write,
+       .endianness = DEVICE_LITTLE_ENDIAN,
+       .valid = {
+               .min_access_size = 4,
+               .max_access_size = 4
+       }
 };
 
 static void eth_cleanup(VLANClientState *nc)
@@ -562,8 +573,12 @@ static void eth_cleanup(VLANClientState *nc)
 
         cpu_unregister_io_memory(eth->ethregs);
 
-        qemu_free(eth->dma_out);
-        qemu_free(eth);
+       /* Disconnect the client.  */
+       eth->dma_out->client.push = NULL;
+       eth->dma_out->client.opaque = NULL;
+       eth->dma_in->client.opaque = NULL;
+       eth->dma_in->client.pull = NULL;
+        g_free(eth);
 }
 
 static NetClientInfo net_etraxfs_info = {
@@ -575,39 +590,48 @@ static NetClientInfo net_etraxfs_info = {
        .link_status_changed = eth_set_link,
 };
 
-void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
+static int fs_eth_init(SysBusDevice *dev)
 {
-       struct etraxfs_dma_client *dma = NULL;  
-       struct fs_eth *eth = NULL;
+       struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
 
-       qemu_check_nic_model(nd, "fseth");
-
-       dma = qemu_mallocz(sizeof *dma * 2);
-       eth = qemu_mallocz(sizeof *eth);
-
-       dma[0].client.push = eth_tx_push;
-       dma[0].client.opaque = eth;
-       dma[1].client.opaque = eth;
-       dma[1].client.pull = NULL;
+       if (!s->dma_out || !s->dma_in) {
+               hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+       }
 
-       eth->dma_out = dma;
-       eth->dma_in = dma + 1;
+       s->dma_out->client.push = eth_tx_push;
+       s->dma_out->client.opaque = s;
+       s->dma_in->client.opaque = s;
+       s->dma_in->client.pull = NULL;
 
-       /* Connect the phy.  */
-       eth->phyaddr = phyaddr & 0x1f;
-       tdk_init(&eth->phy);
-       mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
+       memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
+       sysbus_init_mmio_region(dev, &s->mmio);
 
-       eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth,
-                                              DEVICE_NATIVE_ENDIAN);
-       cpu_register_physical_memory (base, 0x5c, eth->ethregs);
+       qemu_macaddr_default_if_unset(&s->conf.macaddr);
+       s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
+                             dev->qdev.info->name, dev->qdev.id, s);
+       qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
-       memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
-       eth->conf.vlan = nd->vlan;
-       eth->conf.peer = nd->netdev;
+       tdk_init(&s->phy);
+       mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
+       return 0;
+}
 
-       eth->nic = qemu_new_nic(&net_etraxfs_info, &eth->conf,
-                               nd->model, nd->name, eth);
+static SysBusDeviceInfo etraxfs_eth_info = {
+       .init = fs_eth_init,
+       .qdev.name  = "etraxfs-eth",
+       .qdev.size  = sizeof(struct fs_eth),
+       .qdev.props = (Property[]) {
+               DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+               DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+               DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+               DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+               DEFINE_PROP_END_OF_LIST(),
+       }
+};
 
-       return dma;
+static void etraxfs_eth_register(void)
+{
+       sysbus_register_withprop(&etraxfs_eth_info);
 }
+
+device_init(etraxfs_eth_register)
index 4feffda6083da160fd6c8426a5315a24757e4a3a..47a56d753c66baf172ccca29d2c9ea685da78ea5 100644 (file)
@@ -39,6 +39,7 @@
 struct etrax_pic
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     void *interrupt_vector;
     qemu_irq parent_irq;
     qemu_irq parent_nmi;
@@ -77,7 +78,8 @@ static void pic_update(struct etrax_pic *fs)
     qemu_set_irq(fs->parent_irq, !!vector);
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+pic_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_pic *fs = opaque;
     uint32_t rval;
@@ -87,8 +89,8 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
     return rval;
 }
 
-static void
-pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void pic_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t value, unsigned int size)
 {
     struct etrax_pic *fs = opaque;
     D(printf("%s addr=%x val=%x\n", __func__, addr, value));
@@ -99,14 +101,14 @@ pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    NULL, NULL,
-    &pic_readl,
-};
-
-static CPUWriteMemoryFunc * const pic_write[] = {
-    NULL, NULL,
-    &pic_writel,
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void nmi_handler(void *opaque, int irq, int level)
@@ -139,15 +141,13 @@ static void irq_handler(void *opaque, int irq, int level)
 static int etraxfs_pic_init(SysBusDevice *dev)
 {
     struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
-    int intr_vect_regs;
 
     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
     sysbus_init_irq(dev, &s->parent_irq);
     sysbus_init_irq(dev, &s->parent_nmi);
 
-    intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s,
-                                            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
+    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
     return 0;
 }
 
index 2787ebd5c83ff5f5ea0f959af781864de9824e4f..298b9857ca47ba687b5f46e7d8756e55feb09a14 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "sysbus.h"
 #include "qemu-char.h"
+#include "qemu-log.h"
 
 #define D(x)
 
@@ -46,6 +47,7 @@
 struct etrax_serial
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -72,7 +74,8 @@ static void ser_update_irq(struct etrax_serial *s)
     qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
 }
 
-static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+ser_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_serial *s = opaque;
     D(CPUState *env = s->env);
@@ -100,25 +103,27 @@ static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
             break;
         default:
             r = s->regs[addr];
-            D(printf ("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
+            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
             break;
     }
     return r;
 }
 
 static void
-ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+ser_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct etrax_serial *s = opaque;
-    unsigned char ch = value;
+    uint32_t value = val64;
+    unsigned char ch = val64;
     D(CPUState *env = s->env);
 
-    D(printf ("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
+    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
     addr >>= 2;
     switch (addr)
     {
         case RW_DOUT:
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
             s->regs[R_INTR] |= 3;
             s->pending_tx = 1;
             s->regs[addr] = value;
@@ -127,7 +132,8 @@ ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
             if (s->pending_tx) {
                 value &= ~1;
                 s->pending_tx = 0;
-                D(printf("fixedup value=%x r_intr=%x\n", value, s->regs[R_INTR]));
+                D(qemu_log("fixedup value=%x r_intr=%x\n",
+                           value, s->regs[R_INTR]));
             }
             s->regs[addr] = value;
             s->regs[R_INTR] &= ~value;
@@ -140,14 +146,14 @@ ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     ser_update_irq(s);
 }
 
-static CPUReadMemoryFunc * const ser_read[] = {
-    NULL, NULL,
-    &ser_readl,
-};
-
-static CPUWriteMemoryFunc * const ser_write[] = {
-    NULL, NULL,
-    &ser_writel,
+static const MemoryRegionOps ser_ops = {
+    .read = ser_read,
+    .write = ser_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void serial_receive(void *opaque, const uint8_t *buf, int size)
@@ -157,7 +163,7 @@ static void serial_receive(void *opaque, const uint8_t *buf, int size)
 
     /* Got a byte.  */
     if (s->rx_fifo_len >= 16) {
-        printf("WARNING: UART dropped char.\n");
+        qemu_log("WARNING: UART dropped char.\n");
         return;
     }
 
@@ -190,19 +196,26 @@ static void serial_event(void *opaque, int event)
 
 }
 
-static int etraxfs_ser_init(SysBusDevice *dev)
+static void etraxfs_ser_reset(DeviceState *d)
 {
-    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
-    int ser_regs;
+    struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
 
     /* transmitter begins ready and idle.  */
     s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
     s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
 
+    s->regs[RW_REC_CTRL] = 0x10000;
+
+}
+
+static int etraxfs_ser_init(SysBusDevice *dev)
+{
+    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
+
     sysbus_init_irq(dev, &s->irq);
-    ser_regs = cpu_register_io_memory(ser_read, ser_write, s,
-                                      DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, ser_regs);
+    memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
+
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr)
         qemu_chr_add_handlers(s->chr,
@@ -211,10 +224,16 @@ static int etraxfs_ser_init(SysBusDevice *dev)
     return 0;
 }
 
+static SysBusDeviceInfo etraxfs_ser_info = {
+    .init = etraxfs_ser_init,
+    .qdev.name  = "etraxfs,serial",
+    .qdev.size  = sizeof(struct etrax_serial),
+    .qdev.reset = etraxfs_ser_reset,
+};
+
 static void etraxfs_serial_register(void)
 {
-    sysbus_register_dev("etraxfs,serial", sizeof (struct etrax_serial),
-                etraxfs_ser_init);
+    sysbus_register_withprop(&etraxfs_ser_info);
 }
 
 device_init(etraxfs_serial_register)
index 133741b4f518b32423b301fcb9e2a7c15c5cf210..57dc7397101e599b554dbf7f8a05c0a11600f6d9 100644 (file)
@@ -43,6 +43,7 @@
 
 struct etrax_timer {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     qemu_irq nmi;
 
@@ -72,7 +73,8 @@ struct etrax_timer {
     uint32_t r_masked_intr;
 };
 
-static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_timer *t = opaque;
     uint32_t r = 0;
@@ -85,7 +87,7 @@ static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
         r = ptimer_get_count(t->ptimer_t1);
         break;
     case R_TIME:
-        r = qemu_get_clock(vm_clock) / 10;
+        r = qemu_get_clock_ns(vm_clock) / 10;
         break;
     case RW_INTR_MASK:
         r = t->rw_intr_mask;
@@ -239,9 +241,11 @@ static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
 }
 
 static void
-timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+timer_write(void *opaque, target_phys_addr_t addr,
+            uint64_t val64, unsigned int size)
 {
     struct etrax_timer *t = opaque;
+    uint32_t value = val64;
 
     switch (addr)
     {
@@ -281,14 +285,14 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const timer_read[] = {
-    NULL, NULL,
-    &timer_readl,
-};
-
-static CPUWriteMemoryFunc * const timer_write[] = {
-    NULL, NULL,
-    &timer_writel,
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void etraxfs_timer_reset(void *opaque)
@@ -307,7 +311,6 @@ static void etraxfs_timer_reset(void *opaque)
 static int etraxfs_timer_init(SysBusDevice *dev)
 {
     struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
-    int timer_regs;
 
     t->bh_t0 = qemu_bh_new(timer0_hit, t);
     t->bh_t1 = qemu_bh_new(timer1_hit, t);
@@ -319,10 +322,8 @@ static int etraxfs_timer_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &t->irq);
     sysbus_init_irq(dev, &t->nmi);
 
-    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
-                                        DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x5c, timer_regs);
-
+    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
+    sysbus_init_mmio_region(dev, &t->mmio);
     qemu_register_reset(etraxfs_timer_reset, t);
     return 0;
 }
index 4bbcc4715f9e4fcd7962344229ac6a74e0b95827..ecaad0965c69ac4380c79d079d05d107c68142c7 100644 (file)
--- a/hw/fdc.c
+++ b/hw/fdc.c
 #define FD_RESET_SENSEI_COUNT  4   /* Number of sense interrupts on RESET */
 
 /* Floppy disk drive emulation */
-typedef enum FDiskType {
-    FDRIVE_DISK_288   = 0x01, /* 2.88 MB disk           */
-    FDRIVE_DISK_144   = 0x02, /* 1.44 MB disk           */
-    FDRIVE_DISK_720   = 0x03, /* 720 kB disk            */
-    FDRIVE_DISK_USER  = 0x04, /* User defined geometry  */
-    FDRIVE_DISK_NONE  = 0x05, /* No disk                */
-} FDiskType;
-
-typedef enum FDriveType {
-    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
-    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
-    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
-    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
-} FDriveType;
-
 typedef enum FDiskFlags {
     FDISK_DBL_SIDES  = 0x01,
 } FDiskFlags;
@@ -97,6 +82,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)
@@ -178,111 +164,23 @@ static void fd_recalibrate(FDrive *drv)
     drv->sect = 1;
 }
 
-/* Recognize floppy formats */
-typedef struct FDFormat {
-    FDriveType drive;
-    FDiskType  disk;
-    uint8_t last_sect;
-    uint8_t max_track;
-    uint8_t max_head;
-    const char *str;
-} FDFormat;
-
-static const FDFormat fd_formats[] = {
-    /* First entry is default format */
-    /* 1.44 MB 3"1/2 floppy disks */
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1,  "1.6 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
-    /* 2.88 MB 3"1/2 floppy disks */
-    { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
-    { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
-    { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1,  "3.2 MB 3\"1/2", },
-    { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
-    { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
-    /* 720 kB 3"1/2 floppy disks */
-    { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 1,  "720 kB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1,  "800 kB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1,  "820 kB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1,  "830 kB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
-    { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
-    /* 1.2 MB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1,  "1.2 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1,  "1.6 MB 5\"1/4", },
-    /* 720 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 80, 1,  "720 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1,  "880 kB 5\"1/4", },
-    /* 360 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 1,  "360 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 0,  "180 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1,  "410 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1,  "420 kB 5\"1/4", },
-    /* 320 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 1,  "320 kB 5\"1/4", },
-    { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 0,  "160 kB 5\"1/4", },
-    /* 360 kB must match 5"1/4 better than 3"1/2... */
-    { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 0,  "360 kB 3\"1/2", },
-    /* end */
-    { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
-};
-
 /* Revalidate a disk drive after a disk change */
 static void fd_revalidate(FDrive *drv)
 {
-    const FDFormat *parse;
-    uint64_t nb_sectors, size;
-    int i, first_match, match;
     int nb_heads, max_track, last_sect, ro;
+    FDriveType drive;
 
     FLOPPY_DPRINTF("revalidate\n");
     if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
         ro = bdrv_is_read_only(drv->bs);
-        bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
+        bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
+                                      &last_sect, drv->drive, &drive);
         if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
             FLOPPY_DPRINTF("User defined disk (%d %d %d)",
                            nb_heads - 1, max_track, last_sect);
         } else {
-            bdrv_get_geometry(drv->bs, &nb_sectors);
-            match = -1;
-            first_match = -1;
-            for (i = 0;; i++) {
-                parse = &fd_formats[i];
-                if (parse->drive == FDRIVE_DRV_NONE)
-                    break;
-                if (drv->drive == parse->drive ||
-                    drv->drive == FDRIVE_DRV_NONE) {
-                    size = (parse->max_head + 1) * parse->max_track *
-                        parse->last_sect;
-                    if (nb_sectors == size) {
-                        match = i;
-                        break;
-                    }
-                    if (first_match == -1)
-                        first_match = i;
-                }
-            }
-            if (match == -1) {
-                if (first_match == -1)
-                    match = 1;
-                else
-                    match = first_match;
-                parse = &fd_formats[match];
-            }
-            nb_heads = parse->max_head + 1;
-            max_track = parse->max_track;
-            last_sect = parse->last_sect;
-            drv->drive = parse->drive;
-            FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
-                           nb_heads, max_track, last_sect, ro ? "ro" : "rw");
+            FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
+                           max_track, last_sect, ro ? "ro" : "rw");
         }
         if (nb_heads == 1) {
             drv->flags &= ~FDISK_DBL_SIDES;
@@ -292,6 +190,7 @@ static void fd_revalidate(FDrive *drv)
         drv->max_track = max_track;
         drv->last_sect = last_sect;
         drv->ro = ro;
+        drv->drive = drive;
     } else {
         FLOPPY_DPRINTF("No disk in drive\n");
         drv->last_sect = 0;
@@ -303,6 +202,8 @@ static void fd_revalidate(FDrive *drv)
 /********************************************************/
 /* Intel 82078 floppy disk controller emulation          */
 
+typedef struct FDCtrl FDCtrl;
+
 static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
 static void fdctrl_reset_fifo(FDCtrl *fdctrl);
 static int fdctrl_transfer_handler (void *opaque, int nchan,
@@ -472,13 +373,13 @@ enum {
 #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
 
 struct FDCtrl {
-    /* Controller's identification */
-    uint8_t version;
-    /* HW */
     qemu_irq irq;
-    int dma_chann;
     /* Controller state */
     QEMUTimer *result_timer;
+    int dma_chann;
+    /* Controller's identification */
+    uint8_t version;
+    /* HW */
     uint8_t sra;
     uint8_t srb;
     uint8_t dor;
@@ -499,21 +400,21 @@ struct FDCtrl {
     uint8_t data_dir;
     uint8_t eot; /* last wanted sector */
     /* States kept only to be returned back */
-    /* Timers state */
-    uint8_t timer0;
-    uint8_t timer1;
     /* precompensation */
     uint8_t precomp_trk;
     uint8_t config;
     uint8_t lock;
     /* Power down config (also with status regB access mode */
     uint8_t pwrd;
-    /* Sun4m quirks? */
-    int sun4m;
     /* Floppy drives */
     uint8_t num_floppies;
+    /* Sun4m quirks? */
+    int sun4m;
     FDrive drives[MAX_FD];
     int reset_sensei;
+    /* Timers state */
+    uint8_t timer0;
+    uint8_t timer1;
 };
 
 typedef struct FDCtrlSysBus {
@@ -533,6 +434,7 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
     FDCtrl *fdctrl = opaque;
     uint32_t retval;
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_SRA:
         retval = fdctrl_read_statusA(fdctrl);
@@ -570,6 +472,7 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
 
     FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_DOR:
         fdctrl_write_dor(fdctrl, value);
@@ -588,16 +491,6 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
     }
 }
 
-static uint32_t fdctrl_read_port (void *opaque, uint32_t reg)
-{
-    return fdctrl_read(opaque, reg & 7);
-}
-
-static void fdctrl_write_port (void *opaque, uint32_t reg, uint32_t value)
-{
-    fdctrl_write(opaque, reg & 7, value);
-}
-
 static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
 {
     return fdctrl_read(opaque, (uint32_t)reg);
@@ -633,16 +526,42 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
     NULL,
 };
 
+static bool fdrive_media_changed_needed(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    return (drive->bs != NULL && drive->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,
+    .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 */
+        }
     }
 };
 
@@ -728,12 +647,6 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level)
     }
 }
 
-/* XXX: may change if moved to bdrv */
-int fdctrl_get_drive_type(FDCtrl *fdctrl, int drive_num)
-{
-    return fdctrl->drives[drive_num].drive;
-}
-
 /* Change IRQ state */
 static void fdctrl_reset_irq(FDCtrl *fdctrl)
 {
@@ -976,7 +889,15 @@ static int fdctrl_media_changed(FDrive *drv)
 
     if (!drv->bs)
         return 0;
-    ret = bdrv_media_changed(drv->bs);
+    if (drv->media_changed) {
+        drv->media_changed = 0;
+        ret = 1;
+    } else {
+        ret = bdrv_media_changed(drv->bs);
+        if (ret < 0) {
+            ret = 0;            /* we don't know, assume no */
+        }
+    }
     if (ret) {
         fd_revalidate(drv);
     }
@@ -1529,7 +1450,7 @@ static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
     /* XXX: should set main status register to busy */
     cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
     qemu_mod_timer(fdctrl->result_timer,
-                   qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 50));
+                   qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
 }
 
 static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
@@ -1848,6 +1769,17 @@ static void fdctrl_result_timer(void *opaque)
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
 
+static void fdctrl_change_cb(void *opaque, bool load)
+{
+    FDrive *drive = opaque;
+
+    drive->media_changed = 1;
+}
+
+static const BlockDevOps fdctrl_block_ops = {
+    .change_media_cb = fdctrl_change_cb,
+};
+
 /* Init functions */
 static int fdctrl_connect_drives(FDCtrl *fdctrl)
 {
@@ -1871,29 +1803,15 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
         fd_init(drive);
         fd_revalidate(drive);
         if (drive->bs) {
-            bdrv_set_removable(drive->bs, 1);
+            drive->media_changed = 1;
+            bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
         }
     }
     return 0;
 }
 
-FDCtrl *fdctrl_init_isa(DriveInfo **fds)
-{
-    ISADevice *dev;
-
-    dev = isa_create("isa-fdc");
-    if (fds[0]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
-    }
-    if (fds[1]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
-    }
-    qdev_init_nofail(&dev->qdev);
-    return &(DO_UPCAST(FDCtrlISABus, busdev, dev)->state);
-}
-
-FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
-                           target_phys_addr_t mmio_base, DriveInfo **fds)
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        target_phys_addr_t mmio_base, DriveInfo **fds)
 {
     FDCtrl *fdctrl;
     DeviceState *dev;
@@ -1912,16 +1830,13 @@ FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
     qdev_init_nofail(dev);
     sysbus_connect_irq(&sys->busdev, 0, irq);
     sysbus_mmio_map(&sys->busdev, 0, mmio_base);
-
-    return fdctrl;
 }
 
-FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
-                          DriveInfo **fds, qemu_irq *fdc_tc)
+void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc)
 {
     DeviceState *dev;
     FDCtrlSysBus *sys;
-    FDCtrl *fdctrl;
 
     dev = qdev_create(NULL, "SUNW,fdtwo");
     if (fds[0]) {
@@ -1929,12 +1844,9 @@ FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
     }
     qdev_init_nofail(dev);
     sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
-    fdctrl = &sys->state;
     sysbus_connect_irq(&sys->busdev, 0, irq);
     sysbus_mmio_map(&sys->busdev, 0, io_base);
     *fdc_tc = qdev_get_gpio_in(dev, 0);
-
-    return fdctrl;
 }
 
 static int fdctrl_init_common(FDCtrl *fdctrl)
@@ -1957,7 +1869,7 @@ static int fdctrl_init_common(FDCtrl *fdctrl)
     FLOPPY_DPRINTF("init controller\n");
     fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
     fdctrl->fifo_size = 512;
-    fdctrl->result_timer = qemu_new_timer(vm_clock,
+    fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
                                           fdctrl_result_timer, fdctrl);
 
     fdctrl->version = 0x90; /* Intel 82078 controller */
@@ -1969,6 +1881,12 @@ static int fdctrl_init_common(FDCtrl *fdctrl)
     return fdctrl_connect_drives(fdctrl);
 }
 
+static const MemoryRegionPortio fdc_portio_list[] = {
+    { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
+    { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
+    PORTIO_END_OF_LIST(),
+};
+
 static int isabus_fdc_init1(ISADevice *dev)
 {
     FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
@@ -1978,16 +1896,7 @@ static int isabus_fdc_init1(ISADevice *dev)
     int dma_chann = 2;
     int ret;
 
-    register_ioport_read(iobase + 0x01, 5, 1,
-                         &fdctrl_read_port, fdctrl);
-    register_ioport_read(iobase + 0x07, 1, 1,
-                         &fdctrl_read_port, fdctrl);
-    register_ioport_write(iobase + 0x01, 5, 1,
-                          &fdctrl_write_port, fdctrl);
-    register_ioport_write(iobase + 0x07, 1, 1,
-                          &fdctrl_write_port, fdctrl);
-    isa_init_ioport_range(dev, iobase, 6);
-    isa_init_ioport(dev, iobase + 7);
+    isa_register_portio_list(dev, iobase, fdc_portio_list, fdctrl, "fdc");
 
     isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
     fdctrl->dma_chann = dma_chann;
@@ -2038,6 +1947,18 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
     return fdctrl_init_common(fdctrl);
 }
 
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int i;
+
+    for (i = 0; i < MAX_FD; i++) {
+        bs[i] = fdctrl->drives[i].bs;
+    }
+}
+
+
 static const VMStateDescription vmstate_isa_fdc ={
     .name = "fdc",
     .version_id = 2,
index 242730af8c2469ae51b1c2a12ec0af68a80aa5b3..506feb65572683fed4cdad7364bae868eb9ddac9 100644 (file)
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -1,16 +1,36 @@
 #ifndef HW_FDC_H
 #define HW_FDC_H
 
+#include "isa.h"
+#include "blockdev.h"
+
 /* fdc.c */
 #define MAX_FD 2
 
-typedef struct FDCtrl FDCtrl;
+static inline ISADevice *fdctrl_init_isa(DriveInfo **fds)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-fdc");
+    if (!dev) {
+        return NULL;
+    }
+
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
 
-FDCtrl *fdctrl_init_isa(DriveInfo **fds);
-FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
-                           target_phys_addr_t mmio_base, DriveInfo **fds);
-FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
-                          DriveInfo **fds, qemu_irq *fdc_tc);
-int fdctrl_get_drive_type(FDCtrl *fdctrl, int drive_num);
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        target_phys_addr_t mmio_base, DriveInfo **fds);
+void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc);
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev);
 
 #endif
index d7d103e66fb62d4deec4471d34deae31becba092..9c9e5265b70effd1fc6ea56ae19987bb618a4400 100644 (file)
@@ -1,15 +1,22 @@
 /* NOR flash devices */
+
+#include "memory.h"
+
 typedef struct pflash_t pflash_t;
 
 /* pflash_cfi01.c */
-pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi01_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs,
                                 uint32_t sector_len, int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
                                 uint16_t id2, uint16_t id3, int be);
 
 /* pflash_cfi02.c */
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi02_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int nb_mappings, int width,
                                 uint16_t id0, uint16_t id1,
@@ -17,15 +24,16 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
                                 uint16_t unlock_addr0, uint16_t unlock_addr1,
                                 int be);
 
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl);
+
 /* nand.c */
-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_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint8_t value);
-uint8_t nand_getio(NANDFlashState *s);
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd);
+void nand_getpins(DeviceState *dev, int *rb);
+void nand_setio(DeviceState *dev, uint32_t value);
+uint32_t nand_getio(DeviceState *dev);
+uint32_t nand_getbuswidth(DeviceState *dev);
 
 #define NAND_MFR_TOSHIBA       0x98
 #define NAND_MFR_SAMSUNG       0xec
@@ -37,10 +45,7 @@ uint8_t nand_getio(NANDFlashState *s);
 #define NAND_MFR_MICRON                0x2c
 
 /* onenand.c */
-void onenand_base_update(void *opaque, target_phys_addr_t new);
-void onenand_base_unmap(void *opaque);
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
-void *onenand_raw_otp(void *opaque);
+void *onenand_raw_otp(DeviceState *onenand_device);
 
 /* ecc.c */
 typedef struct {
index 3df1806a912001316f21059598e096988066cf38..5ad52ab7d2dee35b7df774902346827c178c9a59 100644 (file)
 #define PI 3.14159265358979323846
 #endif
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
 /* -------------------- for debug --------------------- */
 /* #define OPL_OUTPUT_LOG */
 #ifdef OPL_OUTPUT_LOG
@@ -595,14 +599,14 @@ static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
                OPL->AR_TABLE[i] = rate / ARRATE;
                OPL->DR_TABLE[i] = rate / DRRATE;
        }
-       for (i = 60;i < 76;i++)
+       for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++)
        {
                OPL->AR_TABLE[i] = EG_AED-1;
                OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
        }
 #if 0
        for (i = 0;i < 64 ;i++){        /* make for overflow area */
-               LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i,
+               LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i,
                        ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
                        ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
        }
index 24cdf25d0be762be55af1a75d1ebbba7a1261a78..56cf16e27a977f84b92c81abc6162ba5366d5deb 100644 (file)
@@ -78,6 +78,9 @@ void framebuffer_update_display(
     dest = ds_get_data(ds);
     if (dest_col_pitch < 0)
         dest -= dest_col_pitch * (cols - 1);
+    if (dest_row_pitch < 0) {
+        dest -= dest_row_pitch * (rows - 1);
+    }
     first = -1;
     addr = pd;
 
index 85c8c3c7bf8bb70a5bedd2b15ac7d4a6d6006e08..dbcb888bbd0481e28b9baece42bbcbe98036a06f 100644 (file)
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "fw_cfg.h"
 #include "sysbus.h"
+#include "qemu-error.h"
 
 /* debug firmware config */
 //#define DEBUG_FW_CFG
@@ -56,6 +57,130 @@ struct FWCfgState {
     Notifier machine_ready;
 };
 
+#define JPG_FILE 0
+#define BMP_FILE 1
+
+static char *read_splashfile(char *filename, int *file_sizep, int *file_typep)
+{
+    GError *err = NULL;
+    gboolean res;
+    gchar *content;
+    int file_type = -1;
+    unsigned int filehead = 0;
+    int bmp_bpp;
+
+    res = g_file_get_contents(filename, &content, (gsize *)file_sizep, &err);
+    if (res == FALSE) {
+        error_report("failed to read splash file '%s'", filename);
+        g_error_free(err);
+        return NULL;
+    }
+
+    /* check file size */
+    if (*file_sizep < 30) {
+        goto error;
+    }
+
+    /* check magic ID */
+    filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
+    if (filehead == 0xd8ff) {
+        file_type = JPG_FILE;
+    } else if (filehead == 0x4d42) {
+        file_type = BMP_FILE;
+    } else {
+        goto error;
+    }
+
+    /* check BMP bpp */
+    if (file_type == BMP_FILE) {
+        bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
+        if (bmp_bpp != 24) {
+            goto error;
+        }
+    }
+
+    /* return values */
+    *file_typep = file_type;
+
+    return content;
+
+error:
+    error_report("splash file '%s' format not recognized; must be JPEG "
+                 "or 24 bit BMP", filename);
+    g_free(content);
+    return NULL;
+}
+
+static void fw_cfg_bootsplash(FWCfgState *s)
+{
+    int boot_splash_time = -1;
+    const char *boot_splash_filename = NULL;
+    char *p;
+    char *filename, *file_data;
+    int file_size;
+    int file_type = -1;
+    const char *temp;
+
+    /* get user configuration */
+    QemuOptsList *plist = qemu_find_opts("boot-opts");
+    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
+    if (opts != NULL) {
+        temp = qemu_opt_get(opts, "splash");
+        if (temp != NULL) {
+            boot_splash_filename = temp;
+        }
+        temp = qemu_opt_get(opts, "splash-time");
+        if (temp != NULL) {
+            p = (char *)temp;
+            boot_splash_time = strtol(p, (char **)&p, 10);
+        }
+    }
+
+    /* insert splash time if user configurated */
+    if (boot_splash_time >= 0) {
+        /* validate the input */
+        if (boot_splash_time > 0xffff) {
+            error_report("splash time is big than 65535, force it to 65535.");
+            boot_splash_time = 0xffff;
+        }
+        /* use little endian format */
+        qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
+        qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
+        fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
+    }
+
+    /* insert splash file if user configurated */
+    if (boot_splash_filename != NULL) {
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
+        if (filename == NULL) {
+            error_report("failed to find file '%s'.", boot_splash_filename);
+            return;
+        }
+
+        /* loading file data */
+        file_data = read_splashfile(filename, &file_size, &file_type);
+        if (file_data == NULL) {
+            g_free(filename);
+            return;
+        }
+        if (boot_splash_filedata != NULL) {
+            g_free(boot_splash_filedata);
+        }
+        boot_splash_filedata = (uint8_t *)file_data;
+        boot_splash_filedata_size = file_size;
+
+        /* insert data */
+        if (file_type == JPG_FILE) {
+            fw_cfg_add_file(s, "bootsplash.jpg",
+                    boot_splash_filedata, boot_splash_filedata_size);
+        } else {
+            fw_cfg_add_file(s, "bootsplash.bmp",
+                    boot_splash_filedata, boot_splash_filedata_size);
+        }
+        g_free(filename);
+    }
+}
+
 static void fw_cfg_write(FWCfgState *s, uint8_t value)
 {
     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
@@ -63,7 +188,8 @@ static void fw_cfg_write(FWCfgState *s, uint8_t value)
 
     FW_CFG_DPRINTF("write %d\n", value);
 
-    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
+    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
+        s->cur_offset < e->len) {
         e->data[s->cur_offset++] = value;
         if (s->cur_offset == e->len) {
             e->callback(e->callback_opaque, e->data);
@@ -234,7 +360,7 @@ int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
 {
     uint16_t *copy;
 
-    copy = qemu_malloc(sizeof(value));
+    copy = g_malloc(sizeof(value));
     *copy = cpu_to_le16(value);
     return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
 }
@@ -243,7 +369,7 @@ int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
 {
     uint32_t *copy;
 
-    copy = qemu_malloc(sizeof(value));
+    copy = g_malloc(sizeof(value));
     *copy = cpu_to_le32(value);
     return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
 }
@@ -252,7 +378,7 @@ int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
 {
     uint64_t *copy;
 
-    copy = qemu_malloc(sizeof(value));
+    copy = g_malloc(sizeof(value));
     *copy = cpu_to_le64(value);
     return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
 }
@@ -285,7 +411,7 @@ int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
 
     if (!s->files) {
         int dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
-        s->files = qemu_mallocz(dsize);
+        s->files = g_malloc0(dsize);
         fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, (uint8_t*)s->files, dsize);
     }
 
@@ -316,7 +442,7 @@ int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
     return 1;
 }
 
-static void fw_cfg_machine_ready(struct Notifier* n)
+static void fw_cfg_machine_ready(struct Notifier *n, void *data)
 {
     uint32_t len;
     FWCfgState *s = container_of(n, FWCfgState, machine_ready);
@@ -352,7 +478,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
     fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
     fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
     fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
-
+    fw_cfg_bootsplash(s);
 
     s->machine_ready.notify = fw_cfg_machine_ready;
     qemu_add_machine_init_done_notifier(&s->machine_ready);
index a41e9887999e777893ae89013e4e97d2cfec2b97..f00ee27b1752d2b39ccde18acb194a1a6c1db275 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU G364 framebuffer Emulator.
  *
- * Copyright (c) 2007-2009 Herve Poussineau
+ * Copyright (c) 2007-2011 Herve Poussineau
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  */
 
 #include "hw.h"
-#include "mips.h"
 #include "console.h"
 #include "pixel_ops.h"
-
-//#define DEBUG_G364
-
-#ifdef DEBUG_G364
-#define DPRINTF(fmt, ...) \
-do { printf("g364: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "g364 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+#include "trace.h"
+#include "sysbus.h"
 
 typedef struct G364State {
     /* hardware */
     uint8_t *vram;
-    ram_addr_t vram_offset;
-    int vram_size;
+    uint32_t vram_size;
     qemu_irq irq;
+    MemoryRegion mem_vram;
+    MemoryRegion mem_ctrl;
     /* registers */
     uint8_t color_palette[256][3];
     uint8_t cursor_palette[3][3];
@@ -53,31 +44,34 @@ typedef struct G364State {
     int blanked;
 } G364State;
 
-#define REG_ID       0x000000
-#define REG_BOOT     0x080000
-#define REG_DISPLAY  0x080118
-#define REG_VDISPLAY 0x080150
-#define REG_CTLA     0x080300
-#define REG_TOP      0x080400
-#define REG_CURS_PAL 0x080508
-#define REG_CURS_POS 0x080638
-#define REG_CLR_PAL  0x080800
-#define REG_CURS_PAT 0x081000
-#define REG_RESET    0x180000
+#define REG_BOOT     0x000000
+#define REG_DISPLAY  0x000118
+#define REG_VDISPLAY 0x000150
+#define REG_CTLA     0x000300
+#define REG_TOP      0x000400
+#define REG_CURS_PAL 0x000508
+#define REG_CURS_POS 0x000638
+#define REG_CLR_PAL  0x000800
+#define REG_CURS_PAT 0x001000
+#define REG_RESET    0x100000
 
 #define CTLA_FORCE_BLANK 0x00000400
 #define CTLA_NO_CURSOR   0x00800000
 
-static inline int check_dirty(ram_addr_t page)
+#define G364_PAGE_SIZE 4096
+
+static inline int check_dirty(G364State *s, ram_addr_t page)
 {
-    return cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
 }
 
 static inline void reset_dirty(G364State *s,
                                ram_addr_t page_min, ram_addr_t page_max)
 {
-    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE - 1,
-                                    VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&s->mem_vram,
+                              page_min,
+                              page_max + G364_PAGE_SIZE - page_min - 1,
+                              DIRTY_MEMORY_VGA);
 }
 
 static void g364fb_draw_graphic8(G364State *s)
@@ -110,11 +104,12 @@ static void g364fb_draw_graphic8(G364State *s)
             w = 4;
             break;
         default:
-            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            hw_error("g364: unknown host depth %d",
+                     ds_get_bits_per_pixel(s->ds));
             return;
     }
 
-    page = s->vram_offset;
+    page = 0;
     page_min = (ram_addr_t)-1;
     page_max = 0;
 
@@ -135,7 +130,7 @@ static void g364fb_draw_graphic8(G364State *s)
     /* XXX: out of range in vram? */
     data_display = dd = ds_get_data(s->ds);
     while (y < s->height) {
-        if (check_dirty(page)) {
+        if (check_dirty(s, page)) {
             if (y < ymin)
                 ymin = ymax = y;
             if (page_min == (ram_addr_t)-1)
@@ -143,7 +138,7 @@ static void g364fb_draw_graphic8(G364State *s)
             page_max = page;
             if (x < xmin)
                 xmin = x;
-            for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+            for (i = 0; i < G364_PAGE_SIZE; i++) {
                 uint8_t index;
                 unsigned int color;
                 if (unlikely((y >= ycursor && y < ycursor + 64) &&
@@ -207,15 +202,15 @@ static void g364fb_draw_graphic8(G364State *s)
                 ymin = s->height;
                 ymax = 0;
             }
-            x += TARGET_PAGE_SIZE;
+            x += G364_PAGE_SIZE;
             dy = x / s->width;
             x = x % s->width;
             y += dy;
-            vram += TARGET_PAGE_SIZE;
+            vram += G364_PAGE_SIZE;
             data_display += dy * ds_get_linesize(s->ds);
             dd = data_display + x * w;
         }
-        page += TARGET_PAGE_SIZE;
+        page += G364_PAGE_SIZE;
     }
 
 done:
@@ -250,6 +245,8 @@ static void g364fb_update_display(void *opaque)
 {
     G364State *s = opaque;
 
+    qemu_flush_coalesced_mmio_buffer();
+
     if (s->width == 0 || s->height == 0)
         return;
 
@@ -262,7 +259,7 @@ static void g364fb_update_display(void *opaque)
     } else if (s->depth == 8) {
         g364fb_draw_graphic8(s);
     } else {
-        BADF("unknown guest depth %d\n", s->depth);
+        error_report("g364: unknown guest depth %d", s->depth);
     }
 
     qemu_irq_raise(s->irq);
@@ -274,14 +271,13 @@ static inline void g364fb_invalidate_display(void *opaque)
     int i;
 
     s->blanked = 0;
-    for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
+        memory_region_set_dirty(&s->mem_vram, i);
     }
 }
 
-static void g364fb_reset(void *opaque)
+static void g364fb_reset(G364State *s)
 {
-    G364State *s = opaque;
     qemu_irq_lower(s->irq);
 
     memset(s->color_palette, 0, sizeof(s->color_palette));
@@ -292,7 +288,7 @@ static void g364fb_reset(void *opaque)
     s->top_of_screen = 0;
     s->width = s->height = 0;
     memset(s->vram, 0, s->vram_size);
-    g364fb_invalidate_display(opaque);
+    g364fb_invalidate_display(s);
 }
 
 static void g364fb_screen_dump(void *opaque, const char *filename)
@@ -303,8 +299,10 @@ static void g364fb_screen_dump(void *opaque, const char *filename)
     uint8_t *data_buffer;
     FILE *f;
 
+    qemu_flush_coalesced_mmio_buffer();
+
     if (s->depth != 8) {
-        BADF("unknown guest depth %d\n", s->depth);
+        error_report("g364: unknown guest depth %d", s->depth);
         return;
     }
 
@@ -336,7 +334,9 @@ static void g364fb_screen_dump(void *opaque, const char *filename)
 }
 
 /* called for accesses to io ports */
-static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t g364fb_ctrl_read(void *opaque,
+                                 target_phys_addr_t addr,
+                                 unsigned int size)
 {
     G364State *s = opaque;
     uint32_t val;
@@ -353,9 +353,6 @@ static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
         val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
     } else {
         switch (addr) {
-            case REG_ID:
-                val = 0x10; /* Mips G364 */
-                break;
             case REG_DISPLAY:
                 val = s->width / 4;
                 break;
@@ -367,33 +364,19 @@ static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
                 break;
             default:
             {
-                BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
+                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
+                             addr);
                 val = 0;
                 break;
             }
         }
     }
 
-    DPRINTF("read 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+    trace_g364fb_read(addr, val);
 
     return val;
 }
 
-static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
-    if (addr & 0x2)
-        return v >> 16;
-    else
-        return v & 0xffff;
-}
-
-static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
-    return (v >> (8 * (addr & 0x3))) & 0xff;
-}
-
 static void g364fb_update_depth(G364State *s)
 {
     static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
@@ -410,16 +393,19 @@ static void g364_invalidate_cursor_position(G364State *s)
     start = ymin * ds_get_linesize(s->ds);
     end = (ymax + 1) * ds_get_linesize(s->ds);
 
-    for (i = start; i < end; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    for (i = start; i < end; i += G364_PAGE_SIZE) {
+        memory_region_set_dirty(&s->mem_vram, i);
     }
 }
 
-static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void g364fb_ctrl_write(void *opaque,
+                              target_phys_addr_t addr,
+                              uint64_t val,
+                              unsigned int size)
 {
     G364State *s = opaque;
 
-    DPRINTF("write 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+    trace_g364fb_write(addr, val);
 
     if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
         /* color palette */
@@ -442,120 +428,65 @@ static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t v
         g364fb_invalidate_display(s);
     } else {
         switch (addr) {
-            case REG_ID: /* Card identifier; read-only */
-            case REG_BOOT: /* Boot timing */
-            case 0x80108: /* Line timing: half sync */
-            case 0x80110: /* Line timing: back porch */
-            case 0x80120: /* Line timing: short display */
-            case 0x80128: /* Frame timing: broad pulse */
-            case 0x80130: /* Frame timing: v sync */
-            case 0x80138: /* Frame timing: v preequalise */
-            case 0x80140: /* Frame timing: v postequalise */
-            case 0x80148: /* Frame timing: v blank */
-            case 0x80158: /* Line timing: line time */
-            case 0x80160: /* Frame store: line start */
-            case 0x80168: /* vram cycle: mem init */
-            case 0x80170: /* vram cycle: transfer delay */
-            case 0x80200: /* vram cycle: mask register */
-                /* ignore */
-                break;
-            case REG_TOP:
-                s->top_of_screen = val;
-                g364fb_invalidate_display(s);
-                break;
-            case REG_DISPLAY:
-                s->width = val * 4;
-                break;
-            case REG_VDISPLAY:
-                s->height = val / 2;
-                break;
-            case REG_CTLA:
-                s->ctla = val;
-                g364fb_update_depth(s);
-                g364fb_invalidate_display(s);
-                break;
-            case REG_CURS_POS:
-                g364_invalidate_cursor_position(s);
-                s->cursor_position = val;
-                g364_invalidate_cursor_position(s);
-                break;
-            case REG_RESET:
-                g364fb_reset(s);
-                break;
-            default:
-                BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
-                break;
+        case REG_BOOT: /* Boot timing */
+        case 0x00108: /* Line timing: half sync */
+        case 0x00110: /* Line timing: back porch */
+        case 0x00120: /* Line timing: short display */
+        case 0x00128: /* Frame timing: broad pulse */
+        case 0x00130: /* Frame timing: v sync */
+        case 0x00138: /* Frame timing: v preequalise */
+        case 0x00140: /* Frame timing: v postequalise */
+        case 0x00148: /* Frame timing: v blank */
+        case 0x00158: /* Line timing: line time */
+        case 0x00160: /* Frame store: line start */
+        case 0x00168: /* vram cycle: mem init */
+        case 0x00170: /* vram cycle: transfer delay */
+        case 0x00200: /* vram cycle: mask register */
+            /* ignore */
+            break;
+        case REG_TOP:
+            s->top_of_screen = val;
+            g364fb_invalidate_display(s);
+            break;
+        case REG_DISPLAY:
+            s->width = val * 4;
+            break;
+        case REG_VDISPLAY:
+            s->height = val / 2;
+            break;
+        case REG_CTLA:
+            s->ctla = val;
+            g364fb_update_depth(s);
+            g364fb_invalidate_display(s);
+            break;
+        case REG_CURS_POS:
+            g364_invalidate_cursor_position(s);
+            s->cursor_position = val;
+            g364_invalidate_cursor_position(s);
+            break;
+        case REG_RESET:
+            g364fb_reset(s);
+            break;
+        default:
+            error_report("g364: invalid write of 0x%" PRIx64
+                         " at [" TARGET_FMT_plx "]", val, addr);
+            break;
         }
     }
     qemu_irq_lower(s->irq);
 }
 
-static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
-
-    if (addr & 0x2)
-        val = (val << 16) | (old_val & 0x0000ffff);
-    else
-        val = val | (old_val & 0xffff0000);
-    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
-}
-
-static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
-
-    switch (addr & 3) {
-    case 0:
-        val = val | (old_val & 0xffffff00);
-        break;
-    case 1:
-        val = (val << 8) | (old_val & 0xffff00ff);
-        break;
-    case 2:
-        val = (val << 16) | (old_val & 0xff00ffff);
-        break;
-    case 3:
-        val = (val << 24) | (old_val & 0x00ffffff);
-        break;
-    }
-    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
-}
-
-static CPUReadMemoryFunc * const g364fb_ctrl_read[3] = {
-    g364fb_ctrl_readb,
-    g364fb_ctrl_readw,
-    g364fb_ctrl_readl,
+static const MemoryRegionOps g364fb_ctrl_ops = {
+    .read = g364fb_ctrl_read,
+    .write = g364fb_ctrl_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
 };
 
-static CPUWriteMemoryFunc * const g364fb_ctrl_write[3] = {
-    g364fb_ctrl_writeb,
-    g364fb_ctrl_writew,
-    g364fb_ctrl_writel,
-};
-
-static int g364fb_load(QEMUFile *f, void *opaque, int version_id)
+static int g364fb_post_load(void *opaque, int version_id)
 {
     G364State *s = opaque;
-    unsigned int i, vram_size;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    vram_size = qemu_get_be32(f);
-    if (vram_size < s->vram_size)
-        return -EINVAL;
-    qemu_get_buffer(f, s->vram, s->vram_size);
-    for (i = 0; i < 256; i++)
-        qemu_get_buffer(f, s->color_palette[i], 3);
-    for (i = 0; i < 3; i++)
-        qemu_get_buffer(f, s->cursor_palette[i], 3);
-    qemu_get_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
-    s->cursor_position = qemu_get_be32(f);
-    s->ctla = qemu_get_be32(f);
-    s->top_of_screen = qemu_get_be32(f);
-    s->width = qemu_get_be32(f);
-    s->height = qemu_get_be32(f);
 
     /* force refresh */
     g364fb_update_depth(s);
@@ -564,52 +495,80 @@ static int g364fb_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void g364fb_save(QEMUFile *f, void *opaque)
-{
-    G364State *s = opaque;
-    int i;
-
-    qemu_put_be32(f, s->vram_size);
-    qemu_put_buffer(f, s->vram, s->vram_size);
-    for (i = 0; i < 256; i++)
-        qemu_put_buffer(f, s->color_palette[i], 3);
-    for (i = 0; i < 3; i++)
-        qemu_put_buffer(f, s->cursor_palette[i], 3);
-    qemu_put_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
-    qemu_put_be32(f, s->cursor_position);
-    qemu_put_be32(f, s->ctla);
-    qemu_put_be32(f, s->top_of_screen);
-    qemu_put_be32(f, s->width);
-    qemu_put_be32(f, s->height);
-}
+static const VMStateDescription vmstate_g364fb = {
+    .name = "g364fb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = g364fb_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
+        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
+        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
+        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
+        VMSTATE_UINT32(cursor_position, G364State),
+        VMSTATE_UINT32(ctla, G364State),
+        VMSTATE_UINT32(top_of_screen, G364State),
+        VMSTATE_UINT32(width, G364State),
+        VMSTATE_UINT32(height, G364State),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-int g364fb_mm_init(target_phys_addr_t vram_base,
-                   target_phys_addr_t ctrl_base, int it_shift,
-                   qemu_irq irq)
+static void g364fb_init(DeviceState *dev, G364State *s)
 {
-    G364State *s;
-    int io_ctrl;
-
-    s = qemu_mallocz(sizeof(G364State));
-
-    s->vram_size = 8 * 1024 * 1024;
-    s->vram_offset = qemu_ram_alloc(NULL, "g364fb.vram", s->vram_size);
-    s->vram = qemu_get_ram_ptr(s->vram_offset);
-    s->irq = irq;
-
-    qemu_register_reset(g364fb_reset, s);
-    register_savevm(NULL, "g364fb", 0, 1, g364fb_save, g364fb_load, s);
-    g364fb_reset(s);
+    s->vram = g_malloc0(s->vram_size);
 
     s->ds = graphic_console_init(g364fb_update_display,
                                  g364fb_invalidate_display,
                                  g364fb_screen_dump, NULL, s);
 
-    cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset);
+    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
+    memory_region_init_ram_ptr(&s->mem_vram, dev, "vram",
+                               s->vram_size, s->vram);
+    memory_region_set_coalescing(&s->mem_vram);
+}
 
-    io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s,
-                                     DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl);
+typedef struct {
+    SysBusDevice busdev;
+    G364State g364;
+} G364SysBusState;
+
+static int g364fb_sysbus_init(SysBusDevice *dev)
+{
+    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
+
+    g364fb_init(&dev->qdev, s);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_mmio_region(dev, &s->mem_ctrl);
+    sysbus_init_mmio_region(dev, &s->mem_vram);
 
     return 0;
 }
+
+static void g364fb_sysbus_reset(DeviceState *d)
+{
+    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
+    g364fb_reset(&s->g364);
+}
+
+static SysBusDeviceInfo g364fb_sysbus_info = {
+    .init = g364fb_sysbus_init,
+    .qdev.name = "sysbus-g364",
+    .qdev.desc = "G364 framebuffer",
+    .qdev.size = sizeof(G364SysBusState),
+    .qdev.vmsd = &vmstate_g364fb,
+    .qdev.reset = g364fb_sysbus_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+                          8 * 1024 * 1024),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void g364fb_register(void)
+{
+    sysbus_register_withprop(&g364fb_sysbus_info);
+}
+
+device_init(g364fb_register);
index bd3d6b0d9fd20f73fe88c2a51e11e681431c6319..94a608ef6defa1458e24e8d71e98c84c79001220 100644 (file)
@@ -41,6 +41,8 @@
 typedef struct GrackleState {
     SysBusDevice busdev;
     PCIHostState host_state;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
 } GrackleState;
 
 /* Don't know if this matches real hardware, but it agrees with OHW.  */
@@ -57,28 +59,13 @@ static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[irq_num + 0x15], level);
 }
 
-static void pci_grackle_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-
-    pci_device_save(d, f);
-}
-
-static int pci_grackle_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    return pci_device_load(d, f);
-}
-
 static void pci_grackle_reset(void *opaque)
 {
 }
 
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -88,10 +75,20 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(GrackleState, s);
+
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x7e000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_grackle_set_irq,
                                          pci_grackle_map_irq,
-                                         pic, 0, 4);
+                                         pic,
+                                         &d->pci_mmio,
+                                         address_space_io,
+                                         0, 4);
 
     pci_create_simple(d->host_state.bus, 0, "grackle");
 
@@ -104,30 +101,23 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
 static int pci_grackle_init_device(SysBusDevice *dev)
 {
     GrackleState *s;
-    int pci_mem_config, pci_mem_data;
 
     s = FROM_SYSBUS(GrackleState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
-                                               DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-data-idx", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
 
-    register_savevm(&dev->qdev, "grackle", 0, 1, pci_grackle_save,
-                    pci_grackle_load, &s->host_state);
     qemu_register_reset(pci_grackle_reset, &s->host_state);
     return 0;
 }
 
 static int grackle_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_MPC106);
-    d->config[0x08] = 0x00; // revision
     d->config[0x09] = 0x01;
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     return 0;
 }
 
@@ -135,6 +125,10 @@ static PCIDeviceInfo grackle_pci_host_info = {
     .qdev.name = "grackle",
     .qdev.size = sizeof(PCIDevice),
     .init      = grackle_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+    .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static void grackle_register_devices(void)
index 101b150aa55ecaaf45846ee793b85bd7d3dc052a..c90b810413f419fcf25529c6b4038028c77c6197 100644 (file)
@@ -114,7 +114,7 @@ grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
     switch (addr) {
     case DATA_OFFSET:
         c = value & 0xFF;
-        qemu_chr_write(uart->chr, &c, 1);
+        qemu_chr_fe_write(uart->chr, &c, 1);
         return;
 
     case STATUS_OFFSET:
@@ -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..85869b95eba6d776c8b72418d43539ae68d130de 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[] = {
@@ -346,7 +345,7 @@ static int grlib_gptimer_init(SysBusDevice *dev)
     assert(unit->nr_timers > 0);
     assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
 
-    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
+    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
 
     for (i = 0; i < unit->nr_timers; i++) {
         GPTimer *timer = &unit->timers[i];
index f47c491a48a8af737f595f36f92635f4d9739f72..9490a7830debec79a8eae9ae8783808ef20ceb0b 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[] = {
@@ -345,7 +345,7 @@ static int grlib_irqmp_init(SysBusDevice *dev)
                                         grlib_irqmp_write,
                                         irqmp, DEVICE_NATIVE_ENDIAN);
 
-    irqmp->state = qemu_mallocz(sizeof *irqmp->state);
+    irqmp->state = g_malloc0(sizeof *irqmp->state);
 
     if (irqmp_regs < 0) {
         return -1;
index 923073be945b5fa270c4a9826fb3c2c750df502c..432683aceaf6525b4265b72675af60435d2f8758 100644 (file)
@@ -27,6 +27,7 @@
 #include "pci.h"
 #include "pci_host.h"
 #include "pc.h"
+#include "exec-memory.h"
 
 //#define DEBUG
 
 #define PCI_MAPPING_ENTRY(regname)            \
     target_phys_addr_t regname ##_start;      \
     target_phys_addr_t regname ##_length;     \
-    int regname ##_handle
+    MemoryRegion regname ##_mem
 
 typedef struct GT64120State {
     SysBusDevice busdev;
@@ -268,17 +269,18 @@ static void gt64120_isd_mapping(GT64120State *s)
     target_phys_addr_t start = s->regs[GT_ISD] << 21;
     target_phys_addr_t length = 0x1000;
 
-    if (s->ISD_length)
-        cpu_register_physical_memory(s->ISD_start, s->ISD_length,
-                                     IO_MEM_UNASSIGNED);
+    if (s->ISD_length) {
+        memory_region_del_subregion(get_system_memory(), &s->ISD_mem);
+    }
     check_reserved_space(&start, &length);
     length = 0x1000;
     /* Map new address */
-    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx" -> "TARGET_FMT_plx"@"TARGET_FMT_plx", %x\n", s->ISD_length, s->ISD_start,
-            length, start, s->ISD_handle);
+    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
+        " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
+        s->ISD_length, s->ISD_start, length, start);
     s->ISD_start = start;
     s->ISD_length = length;
-    cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle);
+    memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
 }
 
 static void gt64120_pci_mapping(GT64120State *s)
@@ -289,18 +291,23 @@ static void gt64120_pci_mapping(GT64120State *s)
       /* Unmap old IO address */
       if (s->PCI0IO_length)
       {
-        cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED);
+          memory_region_del_subregion(get_system_memory(), &s->PCI0IO_mem);
+          memory_region_destroy(&s->PCI0IO_mem);
       }
       /* Map new IO address */
       s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
       s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
       isa_mem_base = s->PCI0IO_start;
-      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
+      if (s->PCI0IO_length) {
+          isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
+          memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
+                                      &s->PCI0IO_mem);
+      }
     }
 }
 
 static void gt64120_writel (void *opaque, target_phys_addr_t addr,
-                            uint32_t val)
+                            uint64_t val, unsigned size)
 {
     GT64120State *s = opaque;
     uint32_t saddr;
@@ -537,19 +544,19 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
         /* not really implemented */
         s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
         s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
-        DPRINTF("INTRCAUSE %x\n", val);
+        DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
         break;
     case GT_INTRMASK:
         s->regs[saddr] = val & 0x3c3ffffe;
-        DPRINTF("INTRMASK %x\n", val);
+        DPRINTF("INTRMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_ICMASK:
         s->regs[saddr] = val & 0x03fffffe;
-        DPRINTF("ICMASK %x\n", val);
+        DPRINTF("ICMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_SERR0MASK:
         s->regs[saddr] = val & 0x0000003f;
-        DPRINTF("SERR0MASK %x\n", val);
+        DPRINTF("SERR0MASK %" PRIx64 "\n", val);
         break;
 
     /* Reserved when only PCI_0 is configured. */
@@ -578,8 +585,8 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
     }
 }
 
-static uint32_t gt64120_readl (void *opaque,
-                               target_phys_addr_t addr)
+static uint64_t gt64120_readl (void *opaque,
+                               target_phys_addr_t addr, unsigned size)
 {
     GT64120State *s = opaque;
     uint32_t val;
@@ -850,16 +857,10 @@ static uint32_t gt64120_readl (void *opaque,
     return val;
 }
 
-static CPUWriteMemoryFunc * const gt64120_write[] = {
-    &gt64120_writel,
-    &gt64120_writel,
-    &gt64120_writel,
-};
-
-static CPUReadMemoryFunc * const gt64120_read[] = {
-    &gt64120_readl,
-    &gt64120_readl,
-    &gt64120_readl,
+static const MemoryRegionOps isd_mem_ops = {
+    .read = gt64120_readl,
+    .write = gt64120_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -1080,25 +1081,6 @@ static void gt64120_reset(void *opaque)
     gt64120_pci_mapping(s);
 }
 
-static void gt64120_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-    pci_device_save(d, f);
-}
-
-static int gt64120_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-    int ret;
-
-    if (version_id != 1)
-        return -EINVAL;
-    ret = pci_device_load(d, f);
-    if (ret < 0)
-        return ret;
-    return 0;
-}
-
 PCIBus *gt64120_register(qemu_irq *pic)
 {
     SysBusDevice *s;
@@ -1111,9 +1093,11 @@ PCIBus *gt64120_register(qemu_irq *pic)
     d = FROM_SYSBUS(GT64120State, s);
     d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                   gt64120_pci_set_irq, gt64120_pci_map_irq,
-                                  pic, PCI_DEVFN(18, 0), 4);
-    d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
-                                           DEVICE_NATIVE_ENDIAN);
+                                  pic,
+                                  get_system_memory(),
+                                  get_system_io(),
+                                  PCI_DEVFN(18, 0), 4);
+    memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
 
     pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
     return d->pci.bus;
@@ -1131,22 +1115,16 @@ static int gt64120_init(SysBusDevice *dev)
        does not fully work. */
     isa_mem_base = 0x10000000;
     qemu_register_reset(gt64120_reset, s);
-    register_savevm(&dev->qdev, "GT64120 PCI Bus", 0, 1,
-                    gt64120_save, gt64120_load, &s->pci);
     return 0;
 }
 
 static int gt64120_pci_init(PCIDevice *d)
 {
     /* FIXME: Malta specific hw assumptions ahead */
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MARVELL);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MARVELL_GT6412X);
     pci_set_word(d->config + PCI_COMMAND, 0);
     pci_set_word(d->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_byte(d->config + PCI_CLASS_REVISION, 0x10);
     pci_config_set_prog_interface(d->config, 0);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
@@ -1162,6 +1140,10 @@ static PCIDeviceInfo gt64120_pci_info = {
     .qdev.name = "gt64120_pci",
     .qdev.size = sizeof(PCIDevice),
     .init      = gt64120_pci_init,
+    .vendor_id = PCI_VENDOR_ID_MARVELL,
+    .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
+    .revision  = 0x10,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static void gt64120_pci_register_devices(void)
index ee63f634cc9b1b4f7a4e2c69843c1bca54b38fbc..686a5ed86d74e69bfb50f069fa5c6759a1792ecb 100644 (file)
 #include "pxa.h"
 #include "net.h"
 #include "flash.h"
-#include "sysemu.h"
 #include "devices.h"
 #include "boards.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 static const int sector_len = 128 * 1024;
 
@@ -50,11 +50,12 @@ static void connex_init(ram_addr_t ram_size,
     PXA2xxState *cpu;
     DriveInfo *dinfo;
     int be;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     uint32_t connex_rom = 0x01000000;
     uint32_t connex_ram = 0x04000000;
 
-    cpu = pxa255_init(connex_ram);
+    cpu = pxa255_init(address_space_mem, connex_ram);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     if (!dinfo) {
@@ -68,8 +69,7 @@ static void connex_init(ram_addr_t ram_size,
 #else
     be = 0;
 #endif
-    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "connext.rom",
-                                                          connex_rom),
+    if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
                                dinfo->bdrv, sector_len, connex_rom / sector_len,
                                2, 0, 0, 0, 0, be)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -89,11 +89,12 @@ static void verdex_init(ram_addr_t ram_size,
     PXA2xxState *cpu;
     DriveInfo *dinfo;
     int be;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     uint32_t verdex_rom = 0x02000000;
     uint32_t verdex_ram = 0x10000000;
 
-    cpu = pxa270_init(verdex_ram, cpu_model ?: "pxa270-c0");
+    cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0");
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     if (!dinfo) {
@@ -107,8 +108,7 @@ static void verdex_init(ram_addr_t ram_size,
 #else
     be = 0;
 #endif
-    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "verdex.rom",
-                                                          verdex_rom),
+    if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
                                dinfo->bdrv, sector_len, verdex_rom / sector_len,
                                2, 0, 0, 0, 0, be)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
index ff9e7c7e3b1eb5fabf6cf50403a00cc70ad67347..b5eb54879558e4dd194953c194b609855dc0a2c8 100644 (file)
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -232,9 +232,25 @@ static const VMStateDescription vmstate_gus = {
     }
 };
 
+static const MemoryRegionPortio gus_portio_list1[] = {
+    {0x000,  1, 1, .write = gus_writeb },
+    {0x000,  1, 2, .write = gus_writew },
+    {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
+    {0x006, 10, 2, .read = gus_readw, .write = gus_writew },
+    {0x100,  8, 1, .read = gus_readb, .write = gus_writeb },
+    {0x100,  8, 2, .read = gus_readw, .write = gus_writew },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio gus_portio_list2[] = {
+    {0, 1, 1, .read = gus_readb },
+    {0, 1, 2, .read = gus_readw },
+    PORTIO_END_OF_LIST(),
+};
+
 static int gus_initfn (ISADevice *dev)
 {
-    GUSState *s = DO_UPCAST(GUSState, dev, dev);
+    GUSState *s = DO_UPCAST (GUSState, dev, dev);
     struct audsettings as;
 
     AUD_register_card ("gus", &s->card);
@@ -260,28 +276,11 @@ static int gus_initfn (ISADevice *dev)
 
     s->shift = 2;
     s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
-    s->mixbuf = qemu_mallocz (s->samples << s->shift);
-
-    register_ioport_write (s->port, 1, 1, gus_writeb, s);
-    register_ioport_write (s->port, 1, 2, gus_writew, s);
-    isa_init_ioport_range(dev, s->port, 2);
-
-    register_ioport_read ((s->port + 0x100) & 0xf00, 1, 1, gus_readb, s);
-    register_ioport_read ((s->port + 0x100) & 0xf00, 1, 2, gus_readw, s);
-    isa_init_ioport_range(dev, (s->port + 0x100) & 0xf00, 2);
-
-    register_ioport_write (s->port + 6, 10, 1, gus_writeb, s);
-    register_ioport_write (s->port + 6, 10, 2, gus_writew, s);
-    register_ioport_read (s->port + 6, 10, 1, gus_readb, s);
-    register_ioport_read (s->port + 6, 10, 2, gus_readw, s);
-    isa_init_ioport_range(dev, s->port + 6, 10);
-
+    s->mixbuf = g_malloc0 (s->samples << s->shift);
 
-    register_ioport_write (s->port + 0x100, 8, 1, gus_writeb, s);
-    register_ioport_write (s->port + 0x100, 8, 2, gus_writew, s);
-    register_ioport_read (s->port + 0x100, 8, 1, gus_readb, s);
-    register_ioport_read (s->port + 0x100, 8, 2, gus_readw, s);
-    isa_init_ioport_range(dev, s->port + 0x100, 8);
+    isa_register_portio_list (dev, s->port, gus_portio_list1, s, "gus");
+    isa_register_portio_list (dev, (s->port + 0x100) & 0xf00,
+                              gus_portio_list2, s, "gus");
 
     DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
     s->emu.himemaddr = s->himem;
index c699d6fd8bf343aede51a2461f2ed6df58e38124..9b089e65b44a5eafac0d224d04460464e6dae9ea 100644 (file)
@@ -466,7 +466,8 @@ struct HDAAudioState {
     QEMUSoundCard card;
     const desc_codec *desc;
     HDAAudioStream st[4];
-    bool running[16];
+    bool running_compat[16];
+    bool running_real[2 * 16];
 
     /* properties */
     uint32_t debug;
@@ -663,7 +664,7 @@ static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
         st->channel = payload & 0x0f;
         dprint(a, 2, "%s: stream %d, channel %d\n",
                st->node->name, st->stream, st->channel);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
         hda_codec_response(hda, true, 0);
         break;
     case AC_VERB_GET_CONV:
@@ -746,16 +747,20 @@ fail:
     hda_codec_response(hda, true, 0);
 }
 
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
 {
     HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
     int s;
 
-    a->running[stnr] = running;
+    a->running_compat[stnr] = running;
+    a->running_real[output * 16 + stnr] = running;
     for (s = 0; s < ARRAY_SIZE(a->st); s++) {
         if (a->st[s].node == NULL) {
             continue;
         }
+        if (a->st[s].output != output) {
+            continue;
+        }
         if (a->st[s].stream != stnr) {
             continue;
         }
@@ -837,6 +842,12 @@ static int hda_audio_post_load(void *opaque, int version)
     int i;
 
     dprint(a, 1, "%s\n", __FUNCTION__);
+    if (version == 1) {
+        /* assume running_compat[] is for output streams */
+        for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
+            a->running_real[16 + i] = a->running_compat[i];
+    }
+
     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
         st = a->st + i;
         if (st->node == NULL)
@@ -844,7 +855,7 @@ static int hda_audio_post_load(void *opaque, int version)
         hda_codec_parse_fmt(st->format, &st->as);
         hda_audio_setup(st);
         hda_audio_set_amp(st);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
     }
     return 0;
 }
@@ -868,13 +879,14 @@ static const VMStateDescription vmstate_hda_audio_stream = {
 
 static const VMStateDescription vmstate_hda_audio = {
     .name = "hda-audio",
-    .version_id = 1,
+    .version_id = 2,
     .post_load = hda_audio_post_load,
     .fields = (VMStateField []) {
         VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
                              vmstate_hda_audio_stream,
                              HDAAudioStream),
-        VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
         VMSTATE_END_OF_LIST()
     }
 };
index b19b754b31c459e557edf859e3bbead005973b88..16f48d12e10368863a540e5e91c5bcdf5c401b1c 100644 (file)
@@ -43,6 +43,7 @@ typedef struct HeathrowPIC {
 } HeathrowPIC;
 
 typedef struct HeathrowPICS {
+    MemoryRegion mem;
     HeathrowPIC pics[2];
     qemu_irq *irqs;
 } HeathrowPICS;
@@ -62,7 +63,8 @@ static void heathrow_pic_update(HeathrowPICS *s)
     }
 }
 
-static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void pic_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t value, unsigned size)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -89,7 +91,8 @@ static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t pic_read(void *opaque, target_phys_addr_t addr,
+                         unsigned size)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -120,19 +123,12 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const pic_write[] = {
-    &pic_writel,
-    &pic_writel,
-    &pic_writel,
+static const MemoryRegionOps heathrow_pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    &pic_readl,
-    &pic_readl,
-    &pic_readl,
-};
-
-
 static void heathrow_pic_set_irq(void *opaque, int num, int level)
 {
     HeathrowPICS *s = opaque;
@@ -159,42 +155,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)
 {
@@ -212,19 +197,19 @@ static void heathrow_pic_reset(void *opaque)
     s->pics[1].level_triggered = 0x1ff00000;
 }
 
-qemu_irq *heathrow_pic_init(int *pmem_index,
+qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
                             int nb_cpus, qemu_irq **irqs)
 {
     HeathrowPICS *s;
 
-    s = qemu_mallocz(sizeof(HeathrowPICS));
+    s = g_malloc0(sizeof(HeathrowPICS));
     /* only 1 CPU */
     s->irqs = irqs[0];
-    *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
-                                         DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->mem, &heathrow_pic_ops, s,
+                          "heathrow-pic", 0x1000);
+    *pmem = &s->mem;
 
-    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/hid.c b/hw/hid.c
new file mode 100644 (file)
index 0000000..2ba716a
--- /dev/null
+++ b/hw/hid.c
@@ -0,0 +1,467 @@
+/*
+ * QEMU HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.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 "hw.h"
+#include "console.h"
+#include "qemu-timer.h"
+#include "hid.h"
+
+#define HID_USAGE_ERROR_ROLLOVER        0x01
+#define HID_USAGE_POSTFAIL              0x02
+#define HID_USAGE_ERROR_UNDEFINED       0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0;
+}
+
+void hid_set_next_idle(HIDState *hs, int64_t curtime)
+{
+    hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
+}
+
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
+    e->xdx = e->ydy = e->dz = 0;
+    e->buttons_state = buttons;
+}
+
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
+                                      int x1, int y1, int z1) {
+    if (xyrel) {
+        e->xdx += x1;
+        e->ydy += y1;
+    } else {
+        e->xdx = x1;
+        e->ydy = y1;
+        /* Windows drivers do not like the 0/0 position and ignore such
+         * events. */
+        if (!(x1 | y1)) {
+            e->xdx = 1;
+        }
+    }
+    e->dz += z1;
+}
+
+static void hid_pointer_event(void *opaque,
+                              int x1, int y1, int z1, int buttons_state)
+{
+    HIDState *hs = opaque;
+    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+    /* We combine events where feasible to keep the queue small.  We shouldn't
+     * combine anything with the first event of a particular button state, as
+     * that would change the location of the button state change.  When the
+     * queue is empty, a second event is needed because we don't know if
+     * the first event changed the button state.  */
+    if (hs->n == QUEUE_LENGTH) {
+        /* Queue full.  Discard old button state, combine motion normally.  */
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
+    } else if (hs->n < 2 ||
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
+        /* Cannot or should not combine, so add an empty item to the queue.  */
+        QUEUE_INCR(use_slot);
+        hs->n++;
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+    }
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
+                              x1, y1, z1);
+    hs->event(hs);
+}
+
+static void hid_keyboard_event(void *opaque, int keycode)
+{
+    HIDState *hs = opaque;
+    int slot;
+
+    if (hs->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+    hs->kbd.keycodes[slot] = keycode;
+    hs->event(hs);
+}
+
+static void hid_keyboard_process_keycode(HIDState *hs)
+{
+    uint8_t hid_code, key;
+    int i, keycode, slot;
+
+    if (hs->n == 0) {
+        return;
+    }
+    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+    keycode = hs->kbd.keycodes[slot];
+
+    key = keycode & 0x7f;
+    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
+                break;
+            }
+        }
+        if (i < 0) {
+            return;
+        }
+    } else {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                break;
+            }
+        }
+        if (i < 0) {
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin) {
+        return vmin;
+    } else if (val > vmax) {
+        return vmax;
+    } else {
+        return val;
+    }
+}
+
+void hid_pointer_activate(HIDState *hs)
+{
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+}
+
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+    int index;
+    HIDPointerEvent *e;
+
+    hid_pointer_activate(hs);
+
+    /* When the buffer is empty, return the last event.  Relative
+       movements will all be zero.  */
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &hs->ptr.queue[index & QUEUE_MASK];
+
+    if (hs->kind == HID_MOUSE) {
+        dx = int_clamp(e->xdx, -127, 127);
+        dy = int_clamp(e->ydy, -127, 127);
+        e->xdx -= dx;
+        e->ydy -= dy;
+    } else {
+        dx = e->xdx;
+        dy = e->ydy;
+    }
+    dz = int_clamp(e->dz, -127, 127);
+    e->dz -= dz;
+
+    b = 0;
+    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
+        b |= 0x01;
+    }
+    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
+        b |= 0x02;
+    }
+    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
+        b |= 0x04;
+    }
+
+    if (hs->n &&
+        !e->dz &&
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
+        /* that deals with this event */
+        QUEUE_INCR(hs->head);
+        hs->n--;
+    }
+
+    /* Appears we have to invert the wheel direction */
+    dz = 0 - dz;
+    l = 0;
+    switch (hs->kind) {
+    case HID_MOUSE:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx;
+        }
+        if (len > l) {
+            buf[l++] = dy;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    case HID_TABLET:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dx >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dy & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dy >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    default:
+        abort();
+    }
+
+    return l;
+}
+
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len < 2) {
+        return 0;
+    }
+
+    hid_keyboard_process_keycode(hs);
+
+    buf[0] = hs->kbd.modifiers & 0xff;
+    buf[1] = 0;
+    if (hs->kbd.keys > 6) {
+        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
+
+    return MIN(8, len);
+}
+
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        int ledstate = 0;
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
+            ledstate |= QEMU_SCROLL_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x01) {
+            ledstate |= QEMU_NUM_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x02) {
+            ledstate |= QEMU_CAPS_LOCK_LED;
+        }
+        kbd_put_ledstate(ledstate);
+    }
+    return 0;
+}
+
+void hid_reset(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
+    hs->protocol = 1;
+    hs->idle = 0;
+}
+
+void hid_free(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_remove_kbd_event_handler();
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
+    }
+}
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
+    hs->kind = kind;
+    hs->event = event;
+
+    if (hs->kind == HID_KEYBOARD) {
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+    } else if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        1, "QEMU HID Tablet");
+    }
+}
+
+static int hid_post_load(void *opaque, int version_id)
+{
+    HIDState *s = opaque;
+
+    if (s->idle) {
+        hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hid_ptr_queue = {
+    .name = "HIDPointerEventQueue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(xdx, HIDPointerEvent),
+        VMSTATE_INT32(ydy, HIDPointerEvent),
+        VMSTATE_INT32(dz, HIDPointerEvent),
+        VMSTATE_INT32(buttons_state, HIDPointerEvent),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_hid_ptr_device = {
+    .name = "HIDPointerDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
+                             vmstate_hid_ptr_queue, HIDPointerEvent),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+const VMStateDescription vmstate_hid_keyboard_device = {
+    .name = "HIDKeyboardDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_UINT16(kbd.modifiers, HIDState),
+        VMSTATE_UINT8(kbd.leds, HIDState),
+        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
+        VMSTATE_INT32(kbd.keys, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
diff --git a/hw/hid.h b/hw/hid.h
new file mode 100644 (file)
index 0000000..9ce03b1
--- /dev/null
+++ b/hw/hid.h
@@ -0,0 +1,59 @@
+#ifndef QEMU_HID_H
+#define QEMU_HID_H
+
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
+
+typedef struct HIDPointerEvent {
+    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+    int32_t dz, buttons_state;
+} HIDPointerEvent;
+
+#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_MASK      (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
+
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
+    int mouse_grabbed;
+    QEMUPutMouseEntry *eh_entry;
+} HIDMouseState;
+
+typedef struct HIDKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int32_t keys;
+} HIDKeyboardState;
+
+struct HIDState {
+    union {
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
+    };
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
+    int kind;
+    int32_t protocol;
+    uint8_t idle;
+    int64_t next_idle_clock;
+    HIDEventFunc event;
+};
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event);
+void hid_reset(HIDState *hs);
+void hid_free(HIDState *hs);
+
+bool hid_has_events(HIDState *hs);
+void hid_set_next_idle(HIDState *hs, int64_t curtime);
+void hid_pointer_activate(HIDState *hs);
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
+
+#endif /* QEMU_HID_H */
index c12064dae62a63ff3e96a1fbe002c33d71e96aff..6e6ea520bcd2d940586e9ed65b8e633fb32aac19 100644 (file)
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -74,8 +74,6 @@ typedef struct HPETState {
     uint8_t  hpet_id;           /* instance id */
 } HPETState;
 
-struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
-
 static uint32_t hpet_in_legacy_mode(HPETState *s)
 {
     return s->config & HPET_CFG_LEGACY;
@@ -145,7 +143,7 @@ static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
 
 static uint64_t hpet_get_ticks(HPETState *s)
 {
-    return ns_to_ticks(qemu_get_clock(vm_clock) + s->hpet_offset);
+    return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset);
 }
 
 /*
@@ -159,14 +157,14 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
 
         cmp = (uint32_t)t->cmp;
         diff = cmp - (uint32_t)current;
-        diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
+        diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
         return (uint64_t)diff;
     } else {
         uint64_t diff, cmp;
 
         cmp = t->cmp;
         diff = cmp - current;
-        diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
+        diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
         return diff;
     }
 }
@@ -194,7 +192,7 @@ static void update_irq(struct HPETTimer *timer, int set)
             qemu_irq_lower(s->irqs[route]);
         }
     } else if (timer_fsb_route(timer)) {
-        stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
+        stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
     } else if (timer->config & HPET_TN_TYPE_LEVEL) {
         s->isr |= mask;
         qemu_irq_raise(s->irqs[route]);
@@ -226,7 +224,7 @@ static int hpet_post_load(void *opaque, int version_id)
     HPETState *s = opaque;
 
     /* Recalculate the offset between the main counter and guest time */
-    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
 
     /* Push number of timers into capability returned via HPET_ID */
     s->capability &= ~HPET_ID_NUM_TIM_MASK;
@@ -300,11 +298,11 @@ static void hpet_timer(void *opaque)
         }
         diff = hpet_calculate_diff(t, cur_tick);
         qemu_mod_timer(t->qemu_timer,
-                       qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
+                       qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
     } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
         if (t->wrap_flag) {
             diff = hpet_calculate_diff(t, cur_tick);
-            qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) +
+            qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) +
                            (int64_t)ticks_to_ns(diff));
             t->wrap_flag = 0;
         }
@@ -333,7 +331,7 @@ static void hpet_set_timer(HPETTimer *t)
         }
     }
     qemu_mod_timer(t->qemu_timer,
-                   qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
+                   qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
 }
 
 static void hpet_del_timer(HPETTimer *t)
@@ -399,7 +397,7 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
         case HPET_CFG:
             return s->config;
         case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
+            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
             return 0;
         case HPET_COUNTER:
             if (hpet_enabled(s)) {
@@ -460,7 +458,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
         uint8_t timer_id = (addr - 0x100) / 0x20;
         HPETTimer *timer = &s->timer[timer_id];
 
-        DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
+        DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
         if (timer_id > s->num_timers) {
             DPRINTF("qemu: timer id out of range\n");
             return;
@@ -487,7 +485,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
             DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
             break;
         case HPET_TN_CMP: // comparator register
-            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
             if (timer->config & HPET_TN_32BIT) {
                 new_val = (uint32_t)new_val;
             }
@@ -549,7 +547,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
             if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
                 /* Enable main counter and interrupt generation. */
                 s->hpet_offset =
-                    ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+                    ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
                 for (i = 0; i < s->num_timers; i++) {
                     if ((&s->timer[i])->cmp != ~0ULL) {
                         hpet_set_timer(&s->timer[i]);
@@ -572,7 +570,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
             }
             break;
         case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG+4 write \n");
+            DPRINTF("qemu: invalid HPET_CFG+4 write\n");
             break;
         case HPET_STATUS:
             val = new_val & s->isr;
@@ -705,7 +703,7 @@ static int hpet_init(SysBusDevice *dev)
     }
     for (i = 0; i < HPET_MAX_TIMERS; i++) {
         timer = &s->timer[i];
-        timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
+        timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer);
         timer->tn = i;
         timer->state = s;
     }
index 8bf312ab21f38886f9aaee5a3e625308e3df6faf..6128702533b7d010d50914d2c152610ec723ff55 100644 (file)
@@ -59,13 +59,13 @@ struct hpet_fw_entry
     uint64_t address;
     uint16_t min_tick;
     uint8_t page_prot;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 struct hpet_fw_config
 {
     uint8_t count;
     struct hpet_fw_entry hpet[8];
-} __attribute__ ((packed));
+} QEMU_PACKED;
 
 extern struct hpet_fw_config hpet_cfg;
 #endif
diff --git a/hw/hw.h b/hw/hw.h
index 5e243295898ff7b041abd40f1a201a39af00e219..ed20f5a27a78a00520563e2feee4debf3e592e70 100644 (file)
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -85,8 +85,8 @@ uint64_t qemu_get_be64(QEMUFile *f);
 int qemu_file_rate_limit(QEMUFile *f);
 int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
 int64_t qemu_file_get_rate_limit(QEMUFile *f);
-int qemu_file_has_error(QEMUFile *f);
-void qemu_file_set_error(QEMUFile *f);
+int qemu_file_get_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f, int error);
 
 /* Try to send any outstanding data.  This function is useful when output is
  * halted due to rate limiting or EAGAIN errors occur as it can be used to
@@ -298,6 +298,8 @@ enum VMStateFlags {
     VMS_VARRAY_UINT16    = 0x080,  /* Array with size in uint16_t field */
     VMS_VBUFFER          = 0x100,  /* Buffer with size in int32_t field */
     VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
+    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
+    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
 };
 
 typedef struct {
@@ -322,6 +324,7 @@ typedef struct VMStateSubsection {
 
 struct VMStateDescription {
     const char *name;
+    int unmigratable;
     int version_id;
     int minimum_version_id;
     int minimum_version_id_old;
@@ -343,6 +346,7 @@ extern const VMStateInfo vmstate_info_int64;
 extern const VMStateInfo vmstate_info_uint8_equal;
 extern const VMStateInfo vmstate_info_uint16_equal;
 extern const VMStateInfo vmstate_info_int32_equal;
+extern const VMStateInfo vmstate_info_uint32_equal;
 extern const VMStateInfo vmstate_info_int32_le;
 
 extern const VMStateInfo vmstate_info_uint8;
@@ -396,6 +400,15 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .offset     = vmstate_offset_value(_state, _field, _type),       \
 }
 
+#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) {  \
+    .name       = (stringify(_field)),                               \
+    .info       = &(_info),                                          \
+    .field_exists = (_test),                                         \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_SINGLE|VMS_POINTER,                            \
+    .offset     = vmstate_offset_value(_state, _field, _type),       \
+}
+
 #define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
     .name       = (stringify(_field)),                               \
     .version_id = (_version),                                        \
@@ -426,6 +439,15 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .offset     = vmstate_offset_sub_array(_state, _field, _type, _start), \
 }
 
+#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_INT32,                                  \
+    .offset     = offsetof(_state, _field),                          \
+}
+
 #define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
     .name       = (stringify(_field)),                               \
     .version_id = (_version),                                        \
@@ -436,6 +458,16 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .offset     = vmstate_offset_pointer(_state, _field, _type),     \
 }
 
+#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_UINT32|VMS_POINTER,                     \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
 #define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
     .name       = (stringify(_field)),                               \
     .version_id = (_version),                                        \
@@ -475,19 +507,50 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .offset     = vmstate_offset_array(_state, _field, _type, _num), \
 }
 
-#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) { \
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .num          = (_num),                                          \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_ARRAY,                            \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
     .name       = (stringify(_field)),                               \
-    .num        = (_num),                                            \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
     .version_id = (_version),                                        \
     .vmsd       = &(_vmsd),                                          \
     .size       = sizeof(_type),                                     \
-    .flags      = VMS_STRUCT|VMS_ARRAY,                              \
-    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \
+    .offset     = offsetof(_state, _field),                          \
 }
 
-#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT,       \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
     .name       = (stringify(_field)),                               \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint8_t),  \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT,      \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
     .version_id = (_version),                                        \
     .vmsd       = &(_vmsd),                                          \
     .size       = sizeof(_type),                                     \
@@ -495,6 +558,16 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .offset     = offsetof(_state, _field),                          \
 }
 
+#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \
+    .offset     = offsetof(_state, _field),                          \
+}
+
 #define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
     .name         = (stringify(_field)),                             \
     .version_id   = (_version),                                      \
@@ -566,6 +639,14 @@ extern const VMStateDescription vmstate_pci_device;
     .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
 }
 
+#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pci_device,                               \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, PCIDevice), \
+}
+
 extern const VMStateDescription vmstate_pcie_device;
 
 #define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
@@ -609,6 +690,37 @@ 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), \
+}
+
+extern const VMStateDescription vmstate_hid_keyboard_device;
+
+#define VMSTATE_HID_KEYBOARD_DEVICE(_field, _state) {                \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_keyboard_device,                      \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
+extern const VMStateDescription vmstate_hid_ptr_device;
+
+#define VMSTATE_HID_POINTER_DEVICE(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_ptr_device,                           \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
 /* _f : field name
    _f_n : num of elements field_name
    _n : num of elements
@@ -625,6 +737,10 @@ extern const VMStateDescription vmstate_usb_device;
 #define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
     VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
 
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+    VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
+            _vmsd, _type)
+
 #define VMSTATE_BOOL_V(_f, _s, _v)                                    \
     VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
 
@@ -679,30 +795,30 @@ extern const VMStateDescription vmstate_usb_device;
 #define VMSTATE_INT32_EQUAL(_f, _s)                                   \
     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
 
+#define VMSTATE_UINT32_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+
 #define VMSTATE_INT32_LE(_f, _s)                                   \
     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
 
+#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
 #define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
     VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
 
 #define VMSTATE_UINT32_TEST(_f, _s, _t)                                  \
     VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
 
-#define VMSTATE_TIMER_V(_f, _s, _v)                                   \
-    VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
+#define VMSTATE_TIMER_TEST(_f, _s, _test)                             \
+    VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
 
 #define VMSTATE_TIMER(_f, _s)                                         \
-    VMSTATE_TIMER_V(_f, _s, 0)
+    VMSTATE_TIMER_TEST(_f, _s, NULL)
 
 #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)
 
@@ -751,6 +867,12 @@ extern const VMStateDescription vmstate_usb_device;
 #define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_INT64_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+
 #define VMSTATE_BUFFER_V(_f, _s, _v)                                  \
     VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
 
index f80d12db4f8f58a9dcb92489e4cfcf242c35f95c..9bcf3e1d31a89d0db8676c5778ec14e234c35b83 100644 (file)
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 #include "i2c.h"
@@ -84,7 +84,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
     DeviceState *qdev;
     i2c_slave *slave = NULL;
 
-    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
         if (candidate->address == address) {
             slave = candidate;
index 83fd91714af34ed9295982a44e8f117d43e02d16..9381d01589d6d815a0c14987e360e14b640e0868 100644 (file)
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -59,11 +59,6 @@ void i2c_register_slave(I2CSlaveInfo *type);
 
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
 
-/* max7310.c */
-void max7310_reset(i2c_slave *i2c);
-qemu_irq *max7310_gpio_in_get(i2c_slave *i2c);
-void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler);
-
 /* wm8750.c */
 void wm8750_data_req_set(DeviceState *dev,
                 void (*data_req)(void *, int, int), void *opaque);
@@ -77,6 +72,6 @@ void wm8750_set_bclk_in(void *opaque, int new_hz);
 void tmp105_set(i2c_slave *i2c, int temp);
 
 /* lm832x.c */
-void lm832x_key_event(i2c_slave *i2c, int key, int state);
+void lm832x_key_event(DeviceState *dev, int key, int state);
 
 #endif
index 06b225cf4c2ec128c733b65c62eaa6221c0da3cc..12571efc2a3b14e9c5011f539dfcf1cf7636f9e9 100644 (file)
@@ -53,9 +53,13 @@ typedef struct PITChannelState {
     qemu_irq irq;
 } PITChannelState;
 
-struct PITState {
+typedef struct PITState {
+    ISADevice dev;
+    MemoryRegion ioports;
+    uint32_t irq;
+    uint32_t iobase;
     PITChannelState channels[3];
-};
+} PITState;
 
 static PITState pit_state;
 
@@ -66,7 +70,7 @@ static int pit_get_count(PITChannelState *s)
     uint64_t d;
     int counter;
 
-    d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ,
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
                  get_ticks_per_sec());
     switch(s->mode) {
     case 0:
@@ -119,8 +123,9 @@ static int pit_get_out1(PITChannelState *s, int64_t current_time)
     return out;
 }
 
-int pit_get_out(PITState *pit, int channel, int64_t current_time)
+int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
 {
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
     return pit_get_out1(s, current_time);
 }
@@ -179,8 +184,9 @@ static int64_t pit_get_next_transition_time(PITChannelState *s,
 }
 
 /* val must be 0 or 1 */
-void pit_set_gate(PITState *pit, int channel, int val)
+void pit_set_gate(ISADevice *dev, int channel, int val)
 {
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
 
     switch(s->mode) {
@@ -193,7 +199,7 @@ void pit_set_gate(PITState *pit, int channel, int val)
     case 5:
         if (s->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock(vm_clock);
+            s->count_load_time = qemu_get_clock_ns(vm_clock);
             pit_irq_timer_update(s, s->count_load_time);
         }
         break;
@@ -201,7 +207,7 @@ void pit_set_gate(PITState *pit, int channel, int val)
     case 3:
         if (s->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock(vm_clock);
+            s->count_load_time = qemu_get_clock_ns(vm_clock);
             pit_irq_timer_update(s, s->count_load_time);
         }
         /* XXX: disable/enable counting */
@@ -210,20 +216,23 @@ void pit_set_gate(PITState *pit, int channel, int val)
     s->gate = val;
 }
 
-int pit_get_gate(PITState *pit, int channel)
+int pit_get_gate(ISADevice *dev, int channel)
 {
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
     return s->gate;
 }
 
-int pit_get_initial_count(PITState *pit, int channel)
+int pit_get_initial_count(ISADevice *dev, int channel)
 {
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
     return s->count;
 }
 
-int pit_get_mode(PITState *pit, int channel)
+int pit_get_mode(ISADevice *dev, int channel)
 {
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
     return s->mode;
 }
@@ -232,7 +241,7 @@ static inline void pit_load_count(PITChannelState *s, int val)
 {
     if (val == 0)
         val = 0x10000;
-    s->count_load_time = qemu_get_clock(vm_clock);
+    s->count_load_time = qemu_get_clock_ns(vm_clock);
     s->count = val;
     pit_irq_timer_update(s, s->count_load_time);
 }
@@ -266,7 +275,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                     if (!(val & 0x10) && !s->status_latched) {
                         /* status latch */
                         /* XXX: add BCD and null count */
-                        s->status =  (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
+                        s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
                             (s->rw_mode << 4) |
                             (s->mode << 1) |
                             s->bcd;
@@ -462,9 +471,9 @@ static const VMStateDescription vmstate_pit = {
     }
 };
 
-static void pit_reset(void *opaque)
+static void pit_reset(DeviceState *dev)
 {
-    PITState *pit = opaque;
+    PITState *pit = container_of(dev, PITState, dev.qdev);
     PITChannelState *s;
     int i;
 
@@ -498,20 +507,50 @@ void hpet_pit_enable(void)
     pit_load_count(s, 0);
 }
 
-PITState *pit_init(int base, qemu_irq irq)
+static const MemoryRegionPortio pit_portio[] = {
+    { 0, 4, 1, .write = pit_ioport_write },
+    { 0, 3, 1, .read = pit_ioport_read },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps pit_ioport_ops = {
+    .old_portio = pit_portio
+};
+
+static int pit_initfn(ISADevice *dev)
 {
-    PITState *pit = &pit_state;
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s;
 
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
-    s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
-    s->irq = irq;
+    s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
+    s->irq = isa_get_irq(pit->irq);
 
-    vmstate_register(NULL, base, &vmstate_pit, pit);
-    qemu_register_reset(pit_reset, pit);
-    register_ioport_write(base, 4, 1, pit_ioport_write, pit);
-    register_ioport_read(base, 3, 1, pit_ioport_read, pit);
+    memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
+    isa_register_ioport(dev, &pit->ioports, pit->iobase);
 
-    return pit;
+    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+
+    return 0;
+}
+
+static ISADeviceInfo pit_info = {
+    .qdev.name     = "isa-pit",
+    .qdev.size     = sizeof(PITState),
+    .qdev.vmsd     = &vmstate_pit,
+    .qdev.reset    = pit_reset,
+    .qdev.no_user  = 1,
+    .init          = pit_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
+        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pit_register(void)
+{
+    isa_qdev_register(&pit_info);
 }
+device_init(pit_register)
index a8dbee647691a12e50fd542f07328c9355307655..ab519de5d8fef6120a5d7a2379769b358a4799ba 100644 (file)
@@ -40,7 +40,8 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
-typedef struct PicState {
+struct PicState {
+    ISADevice dev;
     uint8_t last_irr; /* edge detection */
     uint8_t irr; /* interrupt request register */
     uint8_t imr; /* interrupt mask register */
@@ -58,61 +59,39 @@ typedef struct PicState {
     uint8_t single_mode; /* true if slave pic is not initialized */
     uint8_t elcr; /* PIIX edge/trigger selection*/
     uint8_t elcr_mask;
-    PicState2 *pics_state;
-} PicState;
-
-struct PicState2 {
-    /* 0 is master pic, 1 is slave pic */
-    /* XXX: better separation between the two pics */
-    PicState pics[2];
-    qemu_irq parent_irq;
-    void *irq_request_opaque;
+    qemu_irq int_out[1];
+    uint32_t master; /* reflects /SP input pin */
+    uint32_t iobase;
+    uint32_t elcr_addr;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
 };
 
-#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
 static int irq_level[16];
 #endif
 #ifdef DEBUG_IRQ_COUNT
 static uint64_t irq_count[16];
 #endif
-PicState2 *isa_pic;
-
-/* set irq level. If an edge is detected, then the IRR is set to 1 */
-static inline void pic_set_irq1(PicState *s, int irq, int level)
-{
-    int mask;
-    mask = 1 << irq;
-    if (s->elcr & mask) {
-        /* level triggered */
-        if (level) {
-            s->irr |= mask;
-            s->last_irr |= mask;
-        } else {
-            s->irr &= ~mask;
-            s->last_irr &= ~mask;
-        }
-    } else {
-        /* edge triggered */
-        if (level) {
-            if ((s->last_irr & mask) == 0)
-                s->irr |= mask;
-            s->last_irr |= mask;
-        } else {
-            s->last_irr &= ~mask;
-        }
-    }
-}
+#ifdef DEBUG_IRQ_LATENCY
+static int64_t irq_time[16];
+#endif
+PicState *isa_pic;
+static PicState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
    number). Return 8 if no irq */
-static inline int get_priority(PicState *s, int mask)
+static int get_priority(PicState *s, int mask)
 {
     int priority;
-    if (mask == 0)
+
+    if (mask == 0) {
         return 8;
+    }
     priority = 0;
-    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
         priority++;
+    }
     return priority;
 }
 
@@ -123,16 +102,19 @@ static int pic_get_irq(PicState *s)
 
     mask = s->irr & ~s->imr;
     priority = get_priority(s, mask);
-    if (priority == 8)
+    if (priority == 8) {
         return -1;
+    }
     /* compute current priority. If special fully nested mode on the
        master, the IRQ coming from the slave is not taken into account
        for the priority computation. */
     mask = s->isr;
-    if (s->special_mask)
+    if (s->special_mask) {
         mask &= ~s->imr;
-    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+    }
+    if (s->special_fully_nested_mode && s->master) {
         mask &= ~(1 << 2);
+    }
     cur_priority = get_priority(s, mask);
     if (priority < cur_priority) {
         /* higher priority found: an irq should be generated */
@@ -142,130 +124,130 @@ static int pic_get_irq(PicState *s)
     }
 }
 
-/* raise irq to CPU if necessary. must be called every time the active
-   irq may change */
-/* XXX: should not export it, but it is needed for an APIC kludge */
-void pic_update_irq(PicState2 *s)
+/* Update INT output. Must be called every time the output may have changed. */
+static void pic_update_irq(PicState *s)
 {
-    int irq2, irq;
-
-    /* first look at slave pic */
-    irq2 = pic_get_irq(&s->pics[1]);
-    if (irq2 >= 0) {
-        /* if irq request by slave pic, signal master PIC */
-        pic_set_irq1(&s->pics[0], 2, 1);
-        pic_set_irq1(&s->pics[0], 2, 0);
-    }
-    /* look at requested irq */
-    irq = pic_get_irq(&s->pics[0]);
-    if (irq >= 0) {
-#if defined(DEBUG_PIC)
-        {
-            int i;
-            for(i = 0; i < 2; i++) {
-                printf("pic%d: imr=%x irr=%x padd=%d\n",
-                       i, s->pics[i].imr, s->pics[i].irr,
-                       s->pics[i].priority_add);
+    int irq;
 
-            }
-        }
-        printf("pic: cpu_interrupt\n");
-#endif
-        qemu_irq_raise(s->parent_irq);
-    }
-
-/* all targets should do this rather than acking the IRQ in the cpu */
-#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
-    else {
-        qemu_irq_lower(s->parent_irq);
+    irq = pic_get_irq(s);
+    if (irq >= 0) {
+        DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
+                s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
+        qemu_irq_raise(s->int_out[0]);
+    } else {
+        qemu_irq_lower(s->int_out[0]);
     }
-#endif
 }
 
-#ifdef DEBUG_IRQ_LATENCY
-int64_t irq_time[16];
-#endif
-
-static void i8259_set_irq(void *opaque, int irq, int level)
+/* set irq level. If an edge is detected, then the IRR is set to 1 */
+static void pic_set_irq(void *opaque, int irq, int level)
 {
-    PicState2 *s = opaque;
+    PicState *s = opaque;
+    int mask = 1 << irq;
 
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
+    defined(DEBUG_IRQ_LATENCY)
+    int irq_index = s->master ? irq : irq + 8;
+#endif
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
-    if (level != irq_level[irq]) {
-        DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
-        irq_level[irq] = level;
+    if (level != irq_level[irq_index]) {
+        DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
+        irq_level[irq_index] = level;
 #ifdef DEBUG_IRQ_COUNT
-       if (level == 1)
-           irq_count[irq]++;
+        if (level == 1) {
+            irq_count[irq_index]++;
+        }
 #endif
     }
 #endif
 #ifdef DEBUG_IRQ_LATENCY
     if (level) {
-        irq_time[irq] = qemu_get_clock(vm_clock);
+        irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
     }
 #endif
-    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+
+    if (s->elcr & mask) {
+        /* level triggered */
+        if (level) {
+            s->irr |= mask;
+            s->last_irr |= mask;
+        } else {
+            s->irr &= ~mask;
+            s->last_irr &= ~mask;
+        }
+    } else {
+        /* edge triggered */
+        if (level) {
+            if ((s->last_irr & mask) == 0) {
+                s->irr |= mask;
+            }
+            s->last_irr |= mask;
+        } else {
+            s->last_irr &= ~mask;
+        }
+    }
     pic_update_irq(s);
 }
 
 /* acknowledge interrupt 'irq' */
-static inline void pic_intack(PicState *s, int irq)
+static void pic_intack(PicState *s, int irq)
 {
     if (s->auto_eoi) {
-        if (s->rotate_on_auto_eoi)
+        if (s->rotate_on_auto_eoi) {
             s->priority_add = (irq + 1) & 7;
+        }
     } else {
         s->isr |= (1 << irq);
     }
     /* We don't clear a level sensitive interrupt here */
-    if (!(s->elcr & (1 << irq)))
+    if (!(s->elcr & (1 << irq))) {
         s->irr &= ~(1 << irq);
+    }
+    pic_update_irq(s);
 }
 
-int pic_read_irq(PicState2 *s)
+int pic_read_irq(PicState *s)
 {
     int irq, irq2, intno;
 
-    irq = pic_get_irq(&s->pics[0]);
+    irq = pic_get_irq(s);
     if (irq >= 0) {
-        pic_intack(&s->pics[0], irq);
         if (irq == 2) {
-            irq2 = pic_get_irq(&s->pics[1]);
+            irq2 = pic_get_irq(slave_pic);
             if (irq2 >= 0) {
-                pic_intack(&s->pics[1], irq2);
+                pic_intack(slave_pic, irq2);
             } else {
                 /* spurious IRQ on slave controller */
                 irq2 = 7;
             }
-            intno = s->pics[1].irq_base + irq2;
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
-            irq = irq2 + 8;
-#endif
+            intno = slave_pic->irq_base + irq2;
         } else {
-            intno = s->pics[0].irq_base + irq;
+            intno = s->irq_base + irq;
         }
+        pic_intack(s, irq);
     } else {
         /* spurious IRQ on host controller */
         irq = 7;
-        intno = s->pics[0].irq_base + irq;
+        intno = s->irq_base + irq;
     }
-    pic_update_irq(s);
 
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
+    if (irq == 2) {
+        irq = irq2 + 8;
+    }
+#endif
 #ifdef DEBUG_IRQ_LATENCY
     printf("IRQ%d latency=%0.3fus\n",
            irq,
-           (double)(qemu_get_clock(vm_clock) -
+           (double)(qemu_get_clock_ns(vm_clock) -
                     irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
 #endif
     DPRINTF("pic_interrupt: irq=%d\n", irq);
     return intno;
 }
 
-static void pic_reset(void *opaque)
+static void pic_init_reset(PicState *s)
 {
-    PicState *s = opaque;
-
     s->last_irr = 0;
     s->irr = 0;
     s->imr = 0;
@@ -282,36 +264,48 @@ static void pic_reset(void *opaque)
     s->init4 = 0;
     s->single_mode = 0;
     /* Note: ELCR is not reset */
+    pic_update_irq(s);
+}
+
+static void pic_reset(DeviceState *dev)
+{
+    PicState *s = container_of(dev, PicState, dev.qdev);
+
+    pic_init_reset(s);
+    s->elcr = 0;
 }
 
-static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
+                             uint64_t val64, unsigned size)
 {
     PicState *s = opaque;
+    uint32_t addr = addr64;
+    uint32_t val = val64;
     int priority, cmd, irq;
 
     DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
-    addr &= 1;
     if (addr == 0) {
         if (val & 0x10) {
-            /* init */
-            pic_reset(s);
-            /* deassert a pending interrupt */
-            qemu_irq_lower(s->pics_state->parent_irq);
+            pic_init_reset(s);
             s->init_state = 1;
             s->init4 = val & 1;
             s->single_mode = val & 2;
-            if (val & 0x08)
+            if (val & 0x08) {
                 hw_error("level sensitive irq not supported");
+            }
         } else if (val & 0x08) {
-            if (val & 0x04)
+            if (val & 0x04) {
                 s->poll = 1;
-            if (val & 0x02)
+            }
+            if (val & 0x02) {
                 s->read_reg_select = val & 1;
-            if (val & 0x40)
+            }
+            if (val & 0x40) {
                 s->special_mask = (val >> 5) & 1;
+            }
         } else {
             cmd = val >> 5;
-            switch(cmd) {
+            switch (cmd) {
             case 0:
             case 4:
                 s->rotate_on_auto_eoi = cmd >> 2;
@@ -322,25 +316,26 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                 if (priority != 8) {
                     irq = (priority + s->priority_add) & 7;
                     s->isr &= ~(1 << irq);
-                    if (cmd == 5)
+                    if (cmd == 5) {
                         s->priority_add = (irq + 1) & 7;
-                    pic_update_irq(s->pics_state);
+                    }
+                    pic_update_irq(s);
                 }
                 break;
             case 3:
                 irq = val & 7;
                 s->isr &= ~(1 << irq);
-                pic_update_irq(s->pics_state);
+                pic_update_irq(s);
                 break;
             case 6:
                 s->priority_add = (val + 1) & 7;
-                pic_update_irq(s->pics_state);
+                pic_update_irq(s);
                 break;
             case 7:
                 irq = val & 7;
                 s->isr &= ~(1 << irq);
                 s->priority_add = (irq + 1) & 7;
-                pic_update_irq(s->pics_state);
+                pic_update_irq(s);
                 break;
             default:
                 /* no operation */
@@ -348,11 +343,11 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             }
         }
     } else {
-        switch(s->init_state) {
+        switch (s->init_state) {
         case 0:
             /* normal mode */
             s->imr = val;
-            pic_update_irq(s->pics_state);
+            pic_update_irq(s);
             break;
         case 1:
             s->irq_base = val & 0xf8;
@@ -374,75 +369,50 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
-{
-    int ret;
-
-    ret = pic_get_irq(s);
-    if (ret >= 0) {
-        if (addr1 >> 7) {
-            s->pics_state->pics[0].isr &= ~(1 << 2);
-            s->pics_state->pics[0].irr &= ~(1 << 2);
-        }
-        s->irr &= ~(1 << ret);
-        s->isr &= ~(1 << ret);
-        if (addr1 >> 7 || ret != 2)
-            pic_update_irq(s->pics_state);
-    } else {
-        ret = 0x07;
-        pic_update_irq(s->pics_state);
-    }
-
-    return ret;
-}
-
-static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PicState *s = opaque;
-    unsigned int addr;
     int ret;
 
-    addr = addr1;
-    addr &= 1;
     if (s->poll) {
-        ret = pic_poll_read(s, addr1);
+        ret = pic_get_irq(s);
+        if (ret >= 0) {
+            pic_intack(s, ret);
+            ret |= 0x80;
+        } else {
+            ret = 0;
+        }
         s->poll = 0;
     } else {
         if (addr == 0) {
-            if (s->read_reg_select)
+            if (s->read_reg_select) {
                 ret = s->isr;
-            else
+            } else {
                 ret = s->irr;
+            }
         } else {
             ret = s->imr;
         }
     }
-    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr1, ret);
+    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
     return ret;
 }
 
-/* memory mapped interrupt status */
-/* XXX: may be the same than pic_read_irq() */
-uint32_t pic_intack_read(PicState2 *s)
+int pic_get_output(PicState *s)
 {
-    int ret;
-
-    ret = pic_poll_read(&s->pics[0], 0x00);
-    if (ret == 2)
-        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
-    /* Prepare for ISR read */
-    s->pics[0].read_reg_select = 1;
-
-    return ret;
+    return (pic_get_irq(s) >= 0);
 }
 
-static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t val, unsigned size)
 {
     PicState *s = opaque;
     s->elcr = val & s->elcr_mask;
 }
 
-static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     PicState *s = opaque;
     return s->elcr;
@@ -453,7 +423,7 @@ static const VMStateDescription vmstate_pic = {
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
+    .fields = (VMStateField[]) {
         VMSTATE_UINT8(last_irr, PicState),
         VMSTATE_UINT8(irr, PicState),
         VMSTATE_UINT8(imr, PicState),
@@ -474,17 +444,42 @@ static const VMStateDescription vmstate_pic = {
     }
 };
 
-/* XXX: add generic master/slave system */
-static void pic_init1(int io_addr, int elcr_addr, PicState *s)
+static const MemoryRegionOps pic_base_ioport_ops = {
+    .read = pic_ioport_read,
+    .write = pic_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps pic_elcr_ioport_ops = {
+    .read = elcr_ioport_read,
+    .write = elcr_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int pic_initfn(ISADevice *dev)
 {
-    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
-    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
-    if (elcr_addr >= 0) {
-        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
-        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
+    PicState *s = DO_UPCAST(PicState, dev, dev);
+
+    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
+    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
+
+    isa_register_ioport(NULL, &s->base_io, s->iobase);
+    if (s->elcr_addr != -1) {
+        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
     }
-    vmstate_register(NULL, io_addr, &vmstate_pic, s);
-    qemu_register_reset(pic_reset, s);
+
+    qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
+    qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
+
+    qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
+
+    return 0;
 }
 
 void pic_info(Monitor *mon)
@@ -492,11 +487,11 @@ void pic_info(Monitor *mon)
     int i;
     PicState *s;
 
-    if (!isa_pic)
+    if (!isa_pic) {
         return;
-
-    for(i=0;i<2;i++) {
-        s = &isa_pic->pics[i];
+    }
+    for (i = 0; i < 2; i++) {
+        s = i == 0 ? isa_pic : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -516,24 +511,69 @@ void irq_info(Monitor *mon)
     monitor_printf(mon, "IRQ statistics:\n");
     for (i = 0; i < 16; i++) {
         count = irq_count[i];
-        if (count > 0)
+        if (count > 0) {
             monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+        }
     }
 #endif
 }
 
 qemu_irq *i8259_init(qemu_irq parent_irq)
 {
-    PicState2 *s;
-
-    s = qemu_mallocz(sizeof(PicState2));
-    pic_init1(0x20, 0x4d0, &s->pics[0]);
-    pic_init1(0xa0, 0x4d1, &s->pics[1]);
-    s->pics[0].elcr_mask = 0xf8;
-    s->pics[1].elcr_mask = 0xde;
-    s->parent_irq = parent_irq;
-    s->pics[0].pics_state = s;
-    s->pics[1].pics_state = s;
-    isa_pic = s;
-    return qemu_allocate_irqs(i8259_set_irq, s, 16);
+    qemu_irq *irq_set;
+    ISADevice *dev;
+    int i;
+
+    irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
+
+    dev = isa_create("isa-i8259");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
+    qdev_prop_set_bit(&dev->qdev, "master", true);
+    qdev_init_nofail(&dev->qdev);
+
+    qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
+    for (i = 0 ; i < 8; i++) {
+        irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
+    }
+
+    isa_pic = DO_UPCAST(PicState, dev, dev);
+
+    dev = isa_create("isa-i8259");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
+    qdev_init_nofail(&dev->qdev);
+
+    qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
+    for (i = 0 ; i < 8; i++) {
+        irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
+    }
+
+    slave_pic = DO_UPCAST(PicState, dev, dev);
+
+    return irq_set;
+}
+
+static ISADeviceInfo i8259_info = {
+    .qdev.name     = "isa-i8259",
+    .qdev.size     = sizeof(PicState),
+    .qdev.vmsd     = &vmstate_pic,
+    .qdev.reset    = pic_reset,
+    .qdev.no_user  = 1,
+    .init          = pic_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", PicState, iobase,  -1),
+        DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr,  -1),
+        DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask,  -1),
+        DEFINE_PROP_BIT("master", PicState, master,  0, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pic_register(void)
+{
+    isa_qdev_register(&i8259_info);
 }
+device_init(pic_register)
index 73fb550574b8106d63d6d7dcab9cc2234056d616..9059aae28933bb8d5563e0fc7391a58d7901620b 100644 (file)
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -13,12 +13,13 @@ ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
 /* ide-pci.c */
 void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
                          int secondary_ide_enabled);
+PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 
 /* ide-macio.c */
-int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
+MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
                   void *dbdma, int channel, qemu_irq dma_irq);
 
 /* ide-mmio.c */
@@ -28,4 +29,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 */
index 98bdf7059a6e3ce791f791c9661ca03f74d888c1..0af201de2fce77aa528620abe0c6dd804398d90b 100644 (file)
@@ -276,12 +276,12 @@ static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
     }
 }
 
-static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
+static uint64_t ahci_mem_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
-    AHCIState *s = ptr;
+    AHCIState *s = opaque;
     uint32_t val = 0;
 
-    addr = addr & 0xfff;
     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
         switch (addr) {
         case HOST_CAP:
@@ -314,10 +314,10 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
 
 
 
-static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
-    AHCIState *s = ptr;
-    addr = addr & 0xfff;
+    AHCIState *s = opaque;
 
     /* Only aligned reads are allowed on AHCI */
     if (addr & 3) {
@@ -327,7 +327,7 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
     }
 
     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
-        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val);
 
         switch (addr) {
             case HOST_CAP: /* R/WO, RO */
@@ -364,18 +364,49 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
 
 }
 
-static CPUReadMemoryFunc * const ahci_readfn[3]={
-    ahci_mem_readl,
-    ahci_mem_readl,
-    ahci_mem_readl
+static MemoryRegionOps ahci_mem_ops = {
+    .read = ahci_mem_read,
+    .write = ahci_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const ahci_writefn[3]={
-    ahci_mem_writel,
-    ahci_mem_writel,
-    ahci_mem_writel
+static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register */
+        return s->idp_index;
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory read at location selected by index */
+        return ahci_mem_read(opaque, s->idp_index, size);
+    } else {
+        return 0;
+    }
+}
+
+static void ahci_idp_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register - mask off reserved bits */
+        s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory write at location selected by index */
+        ahci_mem_write(opaque, s->idp_index, val, size);
+    }
+}
+
+static MemoryRegionOps ahci_idp_ops = {
+    .read = ahci_idp_read,
+    .write = ahci_idp_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+
 static void ahci_reg_init(AHCIState *s)
 {
     int i;
@@ -505,10 +536,7 @@ static void ahci_reset_port(AHCIState *s, int port)
     ide_bus_reset(&d->port);
     ide_state->ncq_queues = AHCI_MAX_CMDS;
 
-    pr->irq_stat = 0;
-    pr->irq_mask = 0;
     pr->scr_stat = 0;
-    pr->scr_ctl = 0;
     pr->scr_err = 0;
     pr->scr_act = 0;
     d->busy_slot = -1;
@@ -716,6 +744,7 @@ static void ncq_cb(void *opaque, int ret)
     DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
             ncq_tfs->tag);
 
+    bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct);
     qemu_sglist_destroy(&ncq_tfs->sglist);
     ncq_tfs->used = 0;
 }
@@ -748,7 +777,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
     ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
                                 ncq_fis->sector_count_low;
 
-    DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
+    DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
+            "drive max %"PRId64"\n",
             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
             s->dev[port].port.ifs[0].nb_sectors - 1);
 
@@ -757,21 +787,30 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
 
     switch(ncq_fis->command) {
         case READ_FPDMA_QUEUED:
-            DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
+            DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", "
+                    "tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
-            ncq_tfs->is_read = 1;
 
-            DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            DPRINTF(port, "tag %d aio read %"PRId64"\n",
+                    ncq_tfs->tag, ncq_tfs->lba);
+
+            bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
+                            (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
+                            BDRV_ACCT_READ);
             ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
                                            &ncq_tfs->sglist, ncq_tfs->lba,
                                            ncq_cb, ncq_tfs);
             break;
         case WRITE_FPDMA_QUEUED:
-            DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
+            DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
-            ncq_tfs->is_read = 0;
 
-            DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            DPRINTF(port, "tag %d aio write %"PRId64"\n",
+                    ncq_tfs->tag, ncq_tfs->lba);
+
+            bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
+                            (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
+                            BDRV_ACCT_WRITE);
             ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
                                             &ncq_tfs->sglist, ncq_tfs->lba,
                                             ncq_cb, ncq_tfs);
@@ -884,8 +923,31 @@ static int handle_cmd(AHCIState *s, int port, int slot)
         }
 
         if (ide_state->drive_kind != IDE_CD) {
-            ide_set_sector(ide_state, (cmd_fis[6] << 16) | (cmd_fis[5] << 8) |
-                           cmd_fis[4]);
+            /*
+             * We set the sector depending on the sector defined in the FIS.
+             * Unfortunately, the spec isn't exactly obvious on this one.
+             *
+             * Apparently LBA48 commands set fis bytes 10,9,8,6,5,4 to the
+             * 48 bit sector number. ATA_CMD_READ_DMA_EXT is an example for
+             * such a command.
+             *
+             * Non-LBA48 commands however use 7[lower 4 bits],6,5,4 to define a
+             * 28-bit sector number. ATA_CMD_READ_DMA is an example for such
+             * a command.
+             *
+             * Since the spec doesn't explicitly state what each field should
+             * do, I simply assume non-used fields as reserved and OR everything
+             * together, independent of the command.
+             */
+            ide_set_sector(ide_state, ((uint64_t)cmd_fis[10] << 40)
+                                    | ((uint64_t)cmd_fis[9] << 32)
+                                    /* This is used for LBA48 commands */
+                                    | ((uint64_t)cmd_fis[8] << 24)
+                                    /* This is used for non-LBA48 commands */
+                                    | ((uint64_t)(cmd_fis[7] & 0xf) << 24)
+                                    | ((uint64_t)cmd_fis[6] << 16)
+                                    | ((uint64_t)cmd_fis[5] << 8)
+                                    | cmd_fis[4]);
         }
 
         /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
@@ -1066,9 +1128,11 @@ static int ahci_dma_set_inactive(IDEDMA *dma)
 
     ad->dma_cb = NULL;
 
-    /* maybe we still have something to process, check later */
-    ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
-    qemu_bh_schedule(ad->check_bh);
+    if (!ad->check_bh) {
+        /* maybe we still have something to process, check later */
+        ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
+        qemu_bh_schedule(ad->check_bh);
+    }
 
     return 0;
 }
@@ -1077,7 +1141,7 @@ static void ahci_irq_set(void *opaque, int n, int level)
 {
 }
 
-static void ahci_dma_restart_cb(void *opaque, int running, int reason)
+static void ahci_dma_restart_cb(void *opaque, int running, RunState state)
 {
 }
 
@@ -1104,10 +1168,12 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
     int i;
 
     s->ports = ports;
-    s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports);
+    s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
     ahci_reg_init(s);
-    s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
-                                    DEVICE_LITTLE_ENDIAN);
+    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
+    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", AHCI_MEM_BAR_SIZE);
+    memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32);
+
     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
 
     for (i = 0; i < s->ports; i++) {
@@ -1126,27 +1192,25 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
 
 void ahci_uninit(AHCIState *s)
 {
-    qemu_free(s->dev);
-}
-
-void ahci_pci_map(PCIDevice *pci_dev, int region_num,
-        pcibus_t addr, pcibus_t size, int type)
-{
-    struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev;
-    AHCIState *s = &d->ahci;
-
-    cpu_register_physical_memory(addr, size, s->mem);
+    memory_region_destroy(&s->mem);
+    memory_region_destroy(&s->idp);
+    g_free(s->dev);
 }
 
 void ahci_reset(void *opaque)
 {
     struct AHCIPCIState *d = opaque;
+    AHCIPortRegs *pr;
     int i;
 
     d->ahci.control_regs.irqstatus = 0;
     d->ahci.control_regs.ghc = 0;
 
     for (i = 0; i < d->ahci.ports; i++) {
+        pr = &d->ahci.dev[i].port_regs;
+        pr->irq_stat = 0;
+        pr->irq_mask = 0;
+        pr->scr_ctl = 0;
         ahci_reset_port(&d->ahci, i);
     }
 }
index a4560c41b60ae92157700c1ab5d45012611940a9..b223d2c05510a120f9ed35548e5abb99ca9c206f 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef HW_IDE_AHCI_H
 #define HW_IDE_AHCI_H
 
-#define AHCI_PCI_BAR              5
+#define AHCI_MEM_BAR_SIZE         0x1000
 #define AHCI_MAX_PORTS            32
 #define AHCI_MAX_SG               168 /* hardware max is 64K */
 #define AHCI_DMA_BOUNDARY         0xffffffff
 #define RES_FIS_SDBFIS                     0x58
 #define RES_FIS_UFIS                       0x60
 
+#define SATA_CAP_SIZE           0x8
+#define SATA_CAP_REV            0x2
+#define SATA_CAP_BAR            0x4
+
 typedef struct AHCIControlRegs {
     uint32_t    cap;
     uint32_t    ghc;
@@ -244,13 +248,13 @@ typedef struct AHCICmdHdr {
     uint32_t    status;
     uint64_t    tbl_addr;
     uint32_t    reserved[4];
-} __attribute__ ((packed)) AHCICmdHdr;
+} QEMU_PACKED AHCICmdHdr;
 
 typedef struct AHCI_SG {
     uint64_t    addr;
     uint32_t    reserved;
     uint32_t    flags_size;
-} __attribute__ ((packed)) AHCI_SG;
+} QEMU_PACKED AHCI_SG;
 
 typedef struct AHCIDevice AHCIDevice;
 
@@ -258,7 +262,7 @@ typedef struct NCQTransferState {
     AHCIDevice *drive;
     BlockDriverAIOCB *aiocb;
     QEMUSGList sglist;
-    int is_read;
+    BlockAcctCookie acct;
     uint16_t sector_count;
     uint64_t lba;
     uint8_t tag;
@@ -289,7 +293,10 @@ struct AHCIDevice {
 typedef struct AHCIState {
     AHCIDevice *dev;
     AHCIControlRegs control_regs;
-    int mem;
+    MemoryRegion mem;
+    MemoryRegion idp;       /* Index-Data Pair I/O port space */
+    unsigned idp_offset;    /* Offset of index in I/O port space */
+    uint32_t idp_index;     /* Current IDP index */
     int ports;
     qemu_irq irq;
 } AHCIState;
@@ -320,14 +327,11 @@ typedef struct NCQFrame {
     uint8_t reserved8;
     uint8_t reserved9;
     uint8_t reserved10;
-} __attribute__ ((packed)) NCQFrame;
+} QEMU_PACKED NCQFrame;
 
 void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
 void ahci_uninit(AHCIState *s);
 
-void ahci_pci_map(PCIDevice *pci_dev, int region_num,
-        pcibus_t addr, pcibus_t size, int type);
-
 void ahci_reset(void *opaque);
 
 #endif /* HW_IDE_AHCI_H */
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
new file mode 100644 (file)
index 0000000..8af1cfd
--- /dev/null
@@ -0,0 +1,1117 @@
+/*
+ * 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->tray_open && 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(IDEState *s, int lba, uint8_t *buf, int sector_size)
+{
+    int ret;
+
+    switch(sector_size) {
+    case 2048:
+        bdrv_acct_start(s->bs, &s->acct, 4 * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+        ret = bdrv_read(s->bs, (int64_t)lba << 2, buf, 4);
+        bdrv_acct_done(s->bs, &s->acct);
+        break;
+    case 2352:
+        bdrv_acct_start(s->bs, &s->acct, 4 * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+        ret = bdrv_read(s->bs, (int64_t)lba << 2, buf + 16, 4);
+        bdrv_acct_done(s->bs, &s->acct);
+        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, NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+    } else {
+        ide_atapi_cmd_error(s, 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, 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) {
+        bdrv_acct_start(s->bs, &s->acct, size, BDRV_ACCT_READ);
+        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 | (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);
+        goto eot;
+    }
+
+    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, NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+        goto eot;
+    }
+
+    return;
+eot:
+    bdrv_acct_done(s->bs, &s->acct);
+    s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+    ide_set_inactive(s);
+}
+
+/* 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;
+
+    bdrv_acct_start(s->bs, &s->acct, s->packet_transfer_size, BDRV_ACCT_READ);
+
+    /* 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)
+{
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->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) {
+        if (s->events.new_media) {
+            event_code = MEC_NEW_MEDIA;
+            s->events.new_media = false;
+        } else if (s->events.eject_request) {
+            event_code = MEC_EJECT_REQUESTED;
+            s->events.eject_request = 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;
+    } QEMU_PACKED *gesn_cdb;
+
+    struct {
+        uint16_t len;
+        uint8_t notification_class;
+        uint8_t supported_events;
+    } QEMU_PACKED *gesn_event_header;
+    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, 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.
+     * Notification class requests and supported event classes are bitmasks,
+     * but they are build from the same values as the "notification class"
+     * field.
+     */
+    gesn_event_header->supported_events = 1 << GESN_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 & (1 << GESN_MEDIA)) {
+        gesn_event_header->notification_class |= GESN_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 == UNIT_ATTENTION) {
+        s->sense_key = NO_SENSE;
+    }
+
+    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, 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;
+
+    max_len = ube16_to_cpu(buf + 7);
+    action = buf[2] >> 6;
+    code = buf[2] & 0x3f;
+
+    switch(action) {
+    case 0: /* current values */
+        switch(code) {
+        case MODE_PAGE_R_W_ERROR: /* error recovery */
+            cpu_to_ube16(&buf[0], 16 - 2);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            buf[8] = MODE_PAGE_R_W_ERROR;
+            buf[9] = 16 - 10;
+            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 MODE_PAGE_AUDIO_CTL:
+            cpu_to_ube16(&buf[0], 24 - 2);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            buf[8] = MODE_PAGE_AUDIO_CTL;
+            buf[9] = 24 - 10;
+            /* 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 MODE_PAGE_CAPABILITIES:
+            cpu_to_ube16(&buf[0], 30 - 2);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            buf[8] = MODE_PAGE_CAPABILITIES;
+            buf[9] = 30 - 10;
+            buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
+            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 (s->tray_locked) {
+                buf[14] |= 1 << 1;
+            }
+            buf[15] = 0x00; /* No volume & mute control, no changer */
+            cpu_to_ube16(&buf[16], 704); /* 4x read speed */
+            buf[18] = 0; /* Two volume levels */
+            buf[19] = 2;
+            cpu_to_ube16(&buf[20], 512); /* 512k buffer */
+            cpu_to_ube16(&buf[22], 704); /* 4x read speed current */
+            buf[24] = 0;
+            buf[25] = 0;
+            buf[26] = 0;
+            buf[27] = 0;
+            buf[28] = 0;
+            buf[29] = 0;
+            ide_atapi_cmd_reply(s, 30, 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, ILLEGAL_REQUEST,
+                            ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
+        break;
+    }
+    return;
+
+error_cmd:
+    ide_atapi_cmd_error(s, 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)
+{
+    s->tray_locked = buf[4] & 1;
+    bdrv_lock_medium(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, 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, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+        return;
+    }
+
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
+{
+    int sense;
+    bool start = buf[4] & 1;
+    bool loej = buf[4] & 2;     /* load on start, eject on !start */
+
+    if (loej) {
+        if (!start && !s->tray_open && s->tray_locked) {
+            sense = bdrv_is_inserted(s->bs)
+                ? NOT_READY : ILLEGAL_REQUEST;
+            ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+            return;
+        }
+        bdrv_eject(s->bs, !start);
+        s->tray_open = !start;
+    }
+
+    ide_atapi_cmd_ok(s);
+}
+
+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, 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, ILLEGAL_REQUEST,
+                                ASC_INCOMPATIBLE_FORMAT);
+            return;
+        } else if (!media_present(s)) {
+            ide_atapi_cmd_error(s, 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, 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, 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 },
+    [ 0x1b ] = { cmd_start_stop_unit,               0 }, /* [1] */
+    [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
+    [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
+    [ 0x28 ] = { cmd_read, /* (10) */               CHECK_READY },
+    [ 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) */               CHECK_READY },
+    [ 0xad ] = { cmd_read_dvd_structure,            CHECK_READY },
+    [ 0xbb ] = { cmd_set_speed,                     0 },
+    [ 0xbd ] = { cmd_mechanism_status,              0 },
+    [ 0xbe ] = { cmd_read_cd,                       CHECK_READY },
+    /* [1] handler detects and reports not ready condition itself */
+};
+
+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 == 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 (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+        ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+
+        s->cdrom_changed = 0;
+        s->sense_key = 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, 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, ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
+}
index 5d5464ae83f97fcd6ff170be97d37f3e85f012c7..5fe98b1bb37bda06bcc8eeaec9ad1233bb5b182b 100644 (file)
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
 
 static void cmd646_update_irq(PCIIDEState *d);
 
-static void ide_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    IDEBus *bus;
-
-    if (region_num <= 3) {
-        bus = &d->bus[(region_num >> 1)];
-        if (region_num & 1) {
-            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
-            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+    return ide_status_read(cmd646bar->bus, addr + 2);
+}
+
+static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return;
+    }
+    ide_cmd_write(cmd646bar->bus, addr + 2, data);
+}
+
+static MemoryRegionOps cmd646_cmd_ops = {
+    .read = cmd646_cmd_read,
+    .write = cmd646_cmd_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_read(cmd646bar->bus, addr);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_readw(cmd646bar->bus, addr);
+        } else {
+            return ide_data_readl(cmd646bar->bus, addr);
+        }
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void cmd646_data_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_write(cmd646bar->bus, addr, data);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_writew(cmd646bar->bus, addr, data);
         } else {
-            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
-            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
-
-            /* data ports */
-            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
-            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
-            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
-            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
+            return ide_data_writel(cmd646bar->bus, addr, data);
         }
     }
 }
 
-static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                   uint32_t addr)
+static MemoryRegionOps cmd646_data_ops = {
+    .read = cmd646_data_read,
+    .write = cmd646_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
+{
+    IDEBus *bus = &d->bus[bus_num];
+    CMD646BAR *bar = &d->cmd646_bar[bus_num];
+
+    bar->bus = bus;
+    bar->pci_dev = d;
+    memory_region_init_io(&bar->cmd, &cmd646_cmd_ops, bar, "cmd646-cmd", 4);
+    memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8);
+}
+
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -100,31 +159,22 @@ static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     return val;
 }
 
-static uint32_t bmdma_readb_0(void *opaque, uint32_t addr)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
 
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
-
-static uint32_t bmdma_readb_1(void *opaque, uint32_t addr)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
+    if (size != 1) {
+        return;
+    }
 
-static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                uint32_t addr, uint32_t val)
-{
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
     case 0:
-        bmdma_cmd_writeb(bm, addr, val);
+        bmdma_cmd_writeb(bm, val);
         break;
     case 1:
         pci_dev->dev.config[MRDMODE] =
@@ -143,42 +193,25 @@ static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     }
 }
 
-static void bmdma_writeb_0(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
-
-static void bmdma_writeb_1(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
+static MemoryRegionOps cmd646_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    BMDMAState *bm;
     int i;
 
+    memory_region_init(&d->bmdma_bar, "cmd646-bmdma", 16);
     for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-
-        if (i == 0) {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
-        } else {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
-        }
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        bm = &d->bmdma[i];
+        memory_region_init_io(&bm->extra_io, &cmd646_bmdma_ops, bm,
+                              "cmd646-bmdma-bus", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "cmd646-bmdma-ioport", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -226,25 +259,22 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     qemu_irq *irq;
     int i;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
-
-    pci_conf[PCI_REVISION_ID] = 0x07; // IDE controller revision
     pci_conf[PCI_CLASS_PROG] = 0x8f;
 
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
-
     pci_conf[0x51] = 0x04; // enable IDE0
     if (d->secondary) {
         /* XXX: if not enabled, really disable the seconday IDE controller */
         pci_conf[0x51] |= 0x08; /* enable IDE1 */
     }
 
-    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    setup_cmd646_bar(d, 0);
+    setup_cmd646_bar(d, 1);
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
+    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd);
+    pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data);
+    pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd);
+    bmdma_setup_bar(d);
+    pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     /* TODO: RST# value should be 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
@@ -254,7 +284,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
         ide_init2(&d->bus[i], irq[i]);
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -265,6 +295,24 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int pci_cmd646_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->cmd646_bar[i].cmd);
+        memory_region_destroy(&d->cmd646_bar[i].data);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
                          int secondary_ide_enabled)
 {
@@ -282,6 +330,11 @@ static PCIDeviceInfo cmd646_ide_info[] = {
         .qdev.name    = "cmd646-ide",
         .qdev.size    = sizeof(PCIIDEState),
         .init         = pci_cmd646_ide_initfn,
+        .exit         = pci_cmd646_ide_exitfn,
+        .vendor_id    = PCI_VENDOR_ID_CMD,
+        .device_id    = PCI_DEVICE_ID_CMD_646,
+        .revision     = 0x07, // IDE controller revision
+        .class_id     = PCI_CLASS_STORAGE_IDE,
         .qdev.props   = (Property[]) {
             DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
             DEFINE_PROP_END_OF_LIST(),
index dd63664c0defd4ef413be4a9a1356075fb94dd5b..93a1a689c49a7c99f0af3221f2dca2571518cd43 100644 (file)
 #include <hw/hw.h>
 #include <hw/pc.h>
 #include <hw/pci.h>
-#include <hw/scsi.h>
+#include <hw/isa.h>
 #include "qemu-error.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "dma.h"
 #include "blockdev.h"
+#include "block_int.h"
 
 #include <hw/ide/internal.h>
 
-static const int smart_attributes[][5] = {
-    /* id,  flags, val, wrst, thrsh */
-    { 0x01, 0x03, 0x64, 0x64, 0x06}, /* raw read */
-    { 0x03, 0x03, 0x64, 0x64, 0x46}, /* spin up */
-    { 0x04, 0x02, 0x64, 0x64, 0x14}, /* start stop count */
-    { 0x05, 0x03, 0x64, 0x64, 0x36}, /* remapped sectors */
-    { 0x00, 0x00, 0x00, 0x00, 0x00}
+/* These values were based on a Seagate ST3500418AS but have been modified
+   to make more sense in QEMU */
+static const int smart_attributes[][12] = {
+    /* id,  flags, hflags, val, wrst, raw (6 bytes), threshold */
+    /* raw read error rate*/
+    { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
+    /* spin up */
+    { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* start stop count */
+    { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14},
+    /* remapped sectors */
+    { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24},
+    /* power on hours */
+    { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* power cycle count */
+    { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* airflow-temperature-celsius */
+    { 190,  0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
+    /* end of list */
+    { 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 ide_dummy_transfer_stop(IDEState *s);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -74,17 +72,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);
@@ -94,7 +81,7 @@ static void ide_identify(IDEState *s)
 {
     uint16_t *p;
     unsigned int oldsize;
-    IDEDevice *dev;
+    IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
 
     if (s->identify_set) {
        memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
@@ -140,6 +127,9 @@ static void ide_identify(IDEState *s)
     put_le16(p + 66, 120);
     put_le16(p + 67, 120);
     put_le16(p + 68, 120);
+    if (dev && dev->conf.discard_granularity) {
+        put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
+    }
 
     if (s->ncq_queues) {
         put_le16(p + 75, s->ncq_queues - 1);
@@ -170,9 +160,12 @@ static void ide_identify(IDEState *s)
     put_le16(p + 101, s->nb_sectors >> 16);
     put_le16(p + 102, s->nb_sectors >> 32);
     put_le16(p + 103, s->nb_sectors >> 48);
-    dev = s->unit ? s->bus->slave : s->bus->master;
+
     if (dev && dev->conf.physical_block_size)
         put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+    if (dev && dev->conf.discard_granularity) {
+        put_le16(p + 169, 1); /* TRIM support */
+    }
 
     memcpy(s->identify_data, p, sizeof(s->identify_data));
     s->identify_set = 1;
@@ -315,6 +308,74 @@ static void ide_set_signature(IDEState *s)
     }
 }
 
+typedef struct TrimAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} TrimAIOCB;
+
+static void trim_aio_cancel(BlockDriverAIOCB *acb)
+{
+    TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
+
+    qemu_bh_delete(iocb->bh);
+    iocb->bh = NULL;
+    qemu_aio_release(iocb);
+}
+
+static AIOPool trim_aio_pool = {
+    .aiocb_size         = sizeof(TrimAIOCB),
+    .cancel             = trim_aio_cancel,
+};
+
+static void ide_trim_bh_cb(void *opaque)
+{
+    TrimAIOCB *iocb = opaque;
+
+    iocb->common.cb(iocb->common.opaque, iocb->ret);
+
+    qemu_bh_delete(iocb->bh);
+    iocb->bh = NULL;
+
+    qemu_aio_release(iocb);
+}
+
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    TrimAIOCB *iocb;
+    int i, j, ret;
+
+    iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
+    iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
+    iocb->ret = 0;
+
+    for (j = 0; j < qiov->niov; j++) {
+        uint64_t *buffer = qiov->iov[j].iov_base;
+
+        for (i = 0; i < qiov->iov[j].iov_len / 8; i++) {
+            /* 6-byte LBA + 2-byte range per entry */
+            uint64_t entry = le64_to_cpu(buffer[i]);
+            uint64_t sector = entry & 0x0000ffffffffffffULL;
+            uint16_t count = entry >> 48;
+
+            if (count == 0) {
+                break;
+            }
+
+            ret = bdrv_discard(bs, sector, count);
+            if (!iocb->ret) {
+                iocb->ret = ret;
+            }
+        }
+    }
+
+    qemu_bh_schedule(iocb->bh);
+
+    return &iocb->common;
+}
+
 static inline void ide_abort_command(IDEState *s)
 {
     s->status = READY_STAT | ERR_STAT;
@@ -322,8 +383,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;
@@ -334,7 +395,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;
@@ -414,7 +475,10 @@ void ide_sector_read(IDEState *s)
 #endif
         if (n > s->req_nb_sectors)
             n = s->req_nb_sectors;
+
+        bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
         ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
+        bdrv_acct_done(s->bs, &s->acct);
         if (ret != 0) {
             if (ide_handle_rw_error(s, -ret,
                 BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
@@ -434,7 +498,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);
@@ -446,7 +510,6 @@ void ide_dma_error(IDEState *s)
     s->error = ABRT_ERR;
     s->status = READY_STAT | ERR_STAT;
     ide_set_inactive(s);
-    s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
     ide_set_irq(s->bus);
 }
 
@@ -463,9 +526,10 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
         s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
-        s->bus->dma->ops->add_status(s->bus->dma, op);
+        s->bus->error_status = op;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(0);
+        vm_stop(RUN_STATE_IO_ERROR);
+        bdrv_iostatus_set_err(s->bs, error);
     } else {
         if (op & BM_STATUS_DMA_RETRY) {
             dma_buf_commit(s, 0);
@@ -489,8 +553,11 @@ handle_rw_error:
     if (ret < 0) {
         int op = BM_STATUS_DMA_RETRY;
 
-        if (s->is_read)
+        if (s->dma_cmd == IDE_DMA_READ)
             op |= BM_STATUS_RETRY_READ;
+        else if (s->dma_cmd == IDE_DMA_TRIM)
+            op |= BM_STATUS_RETRY_TRIM;
+
         if (ide_handle_rw_error(s, -ret, op)) {
             return;
         }
@@ -499,7 +566,7 @@ handle_rw_error:
     n = s->io_buffer_size >> 9;
     sector_num = ide_get_sector(s);
     if (n > 0) {
-        dma_buf_commit(s, s->is_read);
+        dma_buf_commit(s, ide_cmd_is_read(s));
         sector_num += n;
         ide_set_sector(s, sector_num);
         s->nsector -= n;
@@ -516,20 +583,30 @@ handle_rw_error:
     n = s->nsector;
     s->io_buffer_index = 0;
     s->io_buffer_size = n * 512;
-    if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0)
+    if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
+        /* The PRDs were too short. Reset the Active bit, but don't raise an
+         * interrupt. */
         goto eot;
+    }
 
 #ifdef DEBUG_AIO
-    printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
-           sector_num, n, s->is_read);
+    printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
+           sector_num, n, s->dma_cmd);
 #endif
 
-    if (s->is_read) {
+    switch (s->dma_cmd) {
+    case IDE_DMA_READ:
         s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
                                            ide_dma_cb, s);
-    } else {
+        break;
+    case IDE_DMA_WRITE:
         s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
                                             ide_dma_cb, s);
+        break;
+    case IDE_DMA_TRIM:
+        s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+                                         ide_issue_trim, ide_dma_cb, s, true);
+        break;
     }
 
     if (!s->bus->dma->aiocb) {
@@ -539,16 +616,32 @@ handle_rw_error:
     return;
 
 eot:
-   s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
-   ide_set_inactive(s);
+    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
+        bdrv_acct_done(s->bs, &s->acct);
+    }
+    ide_set_inactive(s);
 }
 
-static void ide_sector_start_dma(IDEState *s, int is_read)
+static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
 {
     s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
-    s->is_read = is_read;
+    s->dma_cmd = dma_cmd;
+
+    switch (dma_cmd) {
+    case IDE_DMA_READ:
+        bdrv_acct_start(s->bs, &s->acct, s->nsector * BDRV_SECTOR_SIZE,
+                        BDRV_ACCT_READ);
+        break;
+    case IDE_DMA_WRITE:
+        bdrv_acct_start(s->bs, &s->acct, s->nsector * BDRV_SECTOR_SIZE,
+                        BDRV_ACCT_WRITE);
+        break;
+    default:
+        break;
+    }
+
     s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
 }
 
@@ -571,7 +664,10 @@ void ide_sector_write(IDEState *s)
     n = s->nsector;
     if (n > s->req_nb_sectors)
         n = s->req_nb_sectors;
+
+    bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
     ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
+    bdrv_acct_done(s->bs, &s->acct);
 
     if (ret != 0) {
         if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
@@ -598,44 +694,12 @@ void ide_sector_write(IDEState *s)
            option _only_ to install Windows 2000. You must disable it
            for normal use. */
         qemu_mod_timer(s->sector_write_timer,
-                       qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 1000));
+                       qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 1000));
     } else {
         ide_set_irq(s->bus);
     }
 }
 
-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;
@@ -647,6 +711,7 @@ static void ide_flush_cb(void *opaque, int ret)
         }
     }
 
+    bdrv_acct_done(s->bs, &s->acct);
     s->status = READY_STAT | SEEK_STAT;
     ide_set_irq(s->bus);
 }
@@ -660,876 +725,13 @@ void ide_flush_cache(IDEState *s)
         return;
     }
 
+    bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
     acb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
     if (acb == NULL) {
         ide_flush_cb(s, -EIO);
     }
 }
 
-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;
@@ -1584,21 +786,36 @@ static void ide_cfata_metadata_write(IDEState *s)
 }
 
 /* called when the inserted state of the media has changed */
-static void cdrom_change_cb(void *opaque, int reason)
+static void ide_cd_change_cb(void *opaque, bool load)
 {
     IDEState *s = opaque;
     uint64_t nb_sectors;
 
-    if (!(reason & CHANGE_MEDIA)) {
-        return;
-    }
-
+    s->tray_open = !load;
     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 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;
+    s->events.eject_request = false;
+    ide_set_irq(s->bus);
+}
+
+static void ide_cd_eject_request_cb(void *opaque, bool force)
+{
+    IDEState *s = opaque;
+
+    s->events.eject_request = true;
+    if (force) {
+        s->tray_locked = false;
+    }
     ide_set_irq(s->bus);
 }
 
@@ -1700,6 +917,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
+#define HD_OK (1u << IDE_HD)
+#define CD_OK (1u << IDE_CD)
+#define CFA_OK (1u << IDE_CFATA)
+#define HD_CFA_OK (HD_OK | CFA_OK)
+#define ALL_OK (HD_OK | CD_OK | CFA_OK)
+
+/* See ACS-2 T13/2015-D Table B.2 Command codes */
+static const uint8_t ide_cmd_table[0x100] = {
+    /* NOP not implemented, mandatory for CD */
+    [CFA_REQ_EXT_ERROR_CODE]            = CFA_OK,
+    [WIN_DSM]                           = ALL_OK,
+    [WIN_DEVICE_RESET]                  = CD_OK,
+    [WIN_RECAL]                         = HD_CFA_OK,
+    [WIN_READ]                          = ALL_OK,
+    [WIN_READ_ONCE]                     = ALL_OK,
+    [WIN_READ_EXT]                      = HD_CFA_OK,
+    [WIN_READDMA_EXT]                   = HD_CFA_OK,
+    [WIN_READ_NATIVE_MAX_EXT]           = HD_CFA_OK,
+    [WIN_MULTREAD_EXT]                  = HD_CFA_OK,
+    [WIN_WRITE]                         = HD_CFA_OK,
+    [WIN_WRITE_ONCE]                    = HD_CFA_OK,
+    [WIN_WRITE_EXT]                     = HD_CFA_OK,
+    [WIN_WRITEDMA_EXT]                  = HD_CFA_OK,
+    [CFA_WRITE_SECT_WO_ERASE]           = CFA_OK,
+    [WIN_MULTWRITE_EXT]                 = HD_CFA_OK,
+    [WIN_WRITE_VERIFY]                  = HD_CFA_OK,
+    [WIN_VERIFY]                        = HD_CFA_OK,
+    [WIN_VERIFY_ONCE]                   = HD_CFA_OK,
+    [WIN_VERIFY_EXT]                    = HD_CFA_OK,
+    [WIN_SEEK]                          = HD_CFA_OK,
+    [CFA_TRANSLATE_SECTOR]              = CFA_OK,
+    [WIN_DIAGNOSE]                      = ALL_OK,
+    [WIN_SPECIFY]                       = HD_CFA_OK,
+    [WIN_STANDBYNOW2]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE2]                = ALL_OK,
+    [WIN_STANDBY2]                      = ALL_OK,
+    [WIN_SETIDLE2]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE2]               = ALL_OK,
+    [WIN_SLEEPNOW2]                     = ALL_OK,
+    [WIN_PACKETCMD]                     = CD_OK,
+    [WIN_PIDENTIFY]                     = CD_OK,
+    [WIN_SMART]                         = HD_CFA_OK,
+    [CFA_ACCESS_METADATA_STORAGE]       = CFA_OK,
+    [CFA_ERASE_SECTORS]                 = CFA_OK,
+    [WIN_MULTREAD]                      = HD_CFA_OK,
+    [WIN_MULTWRITE]                     = HD_CFA_OK,
+    [WIN_SETMULT]                       = HD_CFA_OK,
+    [WIN_READDMA]                       = HD_CFA_OK,
+    [WIN_READDMA_ONCE]                  = HD_CFA_OK,
+    [WIN_WRITEDMA]                      = HD_CFA_OK,
+    [WIN_WRITEDMA_ONCE]                 = HD_CFA_OK,
+    [CFA_WRITE_MULTI_WO_ERASE]          = CFA_OK,
+    [WIN_STANDBYNOW1]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE]                 = ALL_OK,
+    [WIN_STANDBY]                       = ALL_OK,
+    [WIN_SETIDLE1]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE1]               = ALL_OK,
+    [WIN_SLEEPNOW1]                     = ALL_OK,
+    [WIN_FLUSH_CACHE]                   = ALL_OK,
+    [WIN_FLUSH_CACHE_EXT]               = HD_CFA_OK,
+    [WIN_IDENTIFY]                      = ALL_OK,
+    [WIN_SETFEATURES]                   = ALL_OK,
+    [IBM_SENSE_CONDITION]               = CFA_OK,
+    [CFA_WEAR_LEVEL]                    = CFA_OK,
+    [WIN_READ_NATIVE_MAX]               = ALL_OK,
+};
+
+static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
+{
+    return cmd < ARRAY_SIZE(ide_cmd_table)
+        && (ide_cmd_table[cmd] & (1u << s->drive_kind));
+}
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val)
 {
@@ -1719,7 +1008,23 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
         return;
 
+    if (!ide_cmd_permitted(s, val)) {
+        goto abort_cmd;
+    }
+
     switch(val) {
+    case WIN_DSM:
+        switch (s->feature) {
+        case DSM_TRIM:
+            if (!s->bs) {
+                goto abort_cmd;
+            }
+            ide_sector_start_dma(s, IDE_DMA_TRIM);
+            break;
+        default:
+            goto abort_cmd;
+        }
+        break;
     case WIN_IDENTIFY:
         if (s->bs && s->drive_kind != IDE_CD) {
             if (s->drive_kind != IDE_CFATA)
@@ -1766,17 +1071,19 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
-       case WIN_READ_EXT:
+    case WIN_READ_EXT:
        lba48 = 1;
     case WIN_READ:
     case WIN_READ_ONCE:
-        if (!s->bs)
+        if (s->drive_kind == IDE_CD) {
+            ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
             goto abort_cmd;
+        }
        ide_cmd_lba48_transform(s, lba48);
         s->req_nb_sectors = 1;
         ide_sector_read(s);
         break;
-       case WIN_WRITE_EXT:
+    case WIN_WRITE_EXT:
        lba48 = 1;
     case WIN_WRITE:
     case WIN_WRITE_ONCE:
@@ -1789,7 +1096,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
         s->media_changed = 1;
         break;
-       case WIN_MULTREAD_EXT:
+    case WIN_MULTREAD_EXT:
        lba48 = 1;
     case WIN_MULTREAD:
         if (!s->mult_sectors)
@@ -1814,23 +1121,23 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
         s->media_changed = 1;
         break;
-       case WIN_READDMA_EXT:
+    case WIN_READDMA_EXT:
        lba48 = 1;
     case WIN_READDMA:
     case WIN_READDMA_ONCE:
         if (!s->bs)
             goto abort_cmd;
        ide_cmd_lba48_transform(s, lba48);
-        ide_sector_start_dma(s, 1);
+        ide_sector_start_dma(s, IDE_DMA_READ);
         break;
-       case WIN_WRITEDMA_EXT:
+    case WIN_WRITEDMA_EXT:
        lba48 = 1;
     case WIN_WRITEDMA:
     case WIN_WRITEDMA_ONCE:
         if (!s->bs)
             goto abort_cmd;
        ide_cmd_lba48_transform(s, lba48);
-        ide_sector_start_dma(s, 0);
+        ide_sector_start_dma(s, IDE_DMA_WRITE);
         s->media_changed = 1;
         break;
     case WIN_READ_NATIVE_MAX_EXT:
@@ -1843,6 +1150,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         break;
     case WIN_CHECKPOWERMODE1:
     case WIN_CHECKPOWERMODE2:
+        s->error = 0;
         s->nsector = 0xff; /* device active or idle */
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
@@ -1915,7 +1223,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     case WIN_STANDBYNOW1:
     case WIN_STANDBYNOW2:
     case WIN_IDLEIMMEDIATE:
-    case CFA_IDLEIMMEDIATE:
+    case WIN_IDLEIMMEDIATE2:
     case WIN_SETIDLE1:
     case WIN_SETIDLE2:
     case WIN_SLEEPNOW1:
@@ -1924,21 +1232,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case WIN_SEEK:
-        if(s->drive_kind == IDE_CD)
-            goto abort_cmd;
         /* XXX: Check that seek is within bounds */
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
         /* ATAPI commands */
     case WIN_PIDENTIFY:
-        if (s->drive_kind == IDE_CD) {
-            ide_atapi_identify(s);
-            s->status = READY_STAT | SEEK_STAT;
-            ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
-        } else {
-            ide_abort_command(s);
-        }
+        ide_atapi_identify(s);
+        s->status = READY_STAT | SEEK_STAT;
+        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
         ide_set_irq(s->bus);
         break;
     case WIN_DIAGNOSE:
@@ -1954,16 +1256,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
                           */
         ide_set_irq(s->bus);
         break;
-    case WIN_SRST:
-        if (s->drive_kind != IDE_CD)
-            goto abort_cmd;
+    case WIN_DEVICE_RESET:
         ide_set_signature(s);
         s->status = 0x00; /* NOTE: READY is _not_ set */
         s->error = 0x01;
         break;
     case WIN_PACKETCMD:
-        if (s->drive_kind != IDE_CD)
-            goto abort_cmd;
         /* overlapping commands not supported */
         if (s->feature & 0x02)
             goto abort_cmd;
@@ -1975,16 +1273,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         break;
     /* CF-ATA commands */
     case CFA_REQ_EXT_ERROR_CODE:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         s->error = 0x09;    /* miscellaneous error */
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
     case CFA_ERASE_SECTORS:
     case CFA_WEAR_LEVEL:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         if (val == CFA_WEAR_LEVEL)
             s->nsector = 0;
         if (val == CFA_ERASE_SECTORS)
@@ -1994,8 +1288,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case CFA_TRANSLATE_SECTOR:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         s->error = 0x00;
         s->status = READY_STAT | SEEK_STAT;
         memset(s->io_buffer, 0, 0x200);
@@ -2014,8 +1306,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case CFA_ACCESS_METADATA_STORAGE:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         switch (s->feature) {
         case 0x02:     /* Inquiry Metadata Storage */
             ide_cfata_metadata_inquiry(s);
@@ -2034,8 +1324,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case IBM_SENSE_CONDITION:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         switch (s->feature) {
         case 0x01:  /* sense temperature in device */
             s->nsector = 0x50;      /* +20 C */
@@ -2047,9 +1335,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
 
-       case WIN_SMART:
-       if (s->drive_kind == IDE_CD)
-               goto abort_cmd;
+    case WIN_SMART:
        if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
                goto abort_cmd;
        if (!s->smart_enabled && s->feature != SMART_ENABLE)
@@ -2097,7 +1383,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
                if (smart_attributes[n][0] == 0)
                        break;
                s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
-               s->io_buffer[2+1+(n*12)] = smart_attributes[n][4];
+               s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
                }
                for (n=0; n<511; n++) /* checksum */
                s->io_buffer[511] += s->io_buffer[n];
@@ -2110,12 +1396,13 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
                memset(s->io_buffer, 0, 0x200);
                s->io_buffer[0] = 0x01; /* smart struct version */
                for (n=0; n<30; n++) {
-               if (smart_attributes[n][0] == 0)
+                   if (smart_attributes[n][0] == 0) {
                        break;
-               s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
-               s->io_buffer[2+1+(n*12)] = smart_attributes[n][1];
-               s->io_buffer[2+3+(n*12)] = smart_attributes[n][2];
-               s->io_buffer[2+4+(n*12)] = smart_attributes[n][3];
+                   }
+                   int i;
+                   for(i = 0; i < 11; i++) {
+                       s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];
+                   }
                }
                s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);
                if (s->smart_selftest_count == 0) {
@@ -2203,6 +1490,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
        }
        break;
     default:
+        /* should not be reachable */
     abort_cmd:
         ide_abort_command(s);
         ide_set_irq(s->bus);
@@ -2339,15 +1627,36 @@ void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
     bus->cmd = val;
 }
 
+/*
+ * Returns true if the running PIO transfer is a PIO out (i.e. data is
+ * transferred from the device to the guest), false if it's a PIO in
+ */
+static bool ide_is_pio_out(IDEState *s)
+{
+    if (s->end_transfer_func == ide_sector_write ||
+        s->end_transfer_func == ide_atapi_cmd) {
+        return false;
+    } else if (s->end_transfer_func == ide_sector_read ||
+               s->end_transfer_func == ide_transfer_stop ||
+               s->end_transfer_func == ide_atapi_cmd_reply_end ||
+               s->end_transfer_func == ide_dummy_transfer_stop) {
+        return true;
+    }
+
+    abort();
+}
+
 void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     IDEBus *bus = opaque;
     IDEState *s = idebus_active_if(bus);
     uint8_t *p;
 
-    /* PIO data access allowed only when DRQ bit is set */
-    if (!(s->status & DRQ_STAT))
+    /* PIO data access allowed only when DRQ bit is set. The result of a write
+     * during PIO out is indeterminate, just ignore it. */
+    if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
         return;
+    }
 
     p = s->data_ptr;
     *(uint16_t *)p = le16_to_cpu(val);
@@ -2364,9 +1673,11 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
     uint8_t *p;
     int ret;
 
-    /* PIO data access allowed only when DRQ bit is set */
-    if (!(s->status & DRQ_STAT))
+    /* PIO data access allowed only when DRQ bit is set. The result of a read
+     * during PIO in is indeterminate, return 0 and don't move forward. */
+    if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
         return 0;
+    }
 
     p = s->data_ptr;
     ret = cpu_to_le16(*(uint16_t *)p);
@@ -2383,9 +1694,11 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
     IDEState *s = idebus_active_if(bus);
     uint8_t *p;
 
-    /* PIO data access allowed only when DRQ bit is set */
-    if (!(s->status & DRQ_STAT))
+    /* PIO data access allowed only when DRQ bit is set. The result of a write
+     * during PIO out is indeterminate, just ignore it. */
+    if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
         return;
+    }
 
     p = s->data_ptr;
     *(uint32_t *)p = le32_to_cpu(val);
@@ -2402,9 +1715,11 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
     uint8_t *p;
     int ret;
 
-    /* PIO data access allowed only when DRQ bit is set */
-    if (!(s->status & DRQ_STAT))
+    /* PIO data access allowed only when DRQ bit is set. The result of a read
+     * during PIO in is indeterminate, return 0 and don't move forward. */
+    if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
         return 0;
+    }
 
     p = s->data_ptr;
     ret = cpu_to_le32(*(uint32_t *)p);
@@ -2496,13 +1811,32 @@ void ide_bus_reset(IDEBus *bus)
     bus->dma->ops->reset(bus->dma);
 }
 
-int ide_init_drive(IDEState *s, BlockDriverState *bs,
+static bool ide_cd_is_tray_open(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_open;
+}
+
+static bool ide_cd_is_medium_locked(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps ide_cd_block_ops = {
+    .change_media_cb = ide_cd_change_cb,
+    .eject_request_cb = ide_cd_eject_request_cb,
+    .is_tray_open = ide_cd_is_tray_open,
+    .is_medium_locked = ide_cd_is_medium_locked,
+};
+
+int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
                    const char *version, const char *serial)
 {
     int cylinders, heads, secs;
     uint64_t nb_sectors;
 
     s->bs = bs;
+    s->drive_kind = kind;
+
     bdrv_get_geometry(bs, &nb_sectors);
     bdrv_guess_geometry(bs, &cylinders, &heads, &secs);
     if (cylinders < 1 || cylinders > 16383) {
@@ -2527,10 +1861,9 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs,
     s->smart_autosave = 1;
     s->smart_errors = 0;
     s->smart_selftest_count = 0;
-    if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) {
-        s->drive_kind = IDE_CD;
-        bdrv_set_change_cb(bs, cdrom_change_cb, s);
-        bs->buffer_alignment = 2048;
+    if (kind == IDE_CD) {
+        bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
+        bdrv_set_buffer_alignment(bs, 2048);
     } else {
         if (!bdrv_is_inserted(s->bs)) {
             error_report("Device needs media, but drive is empty");
@@ -2554,7 +1887,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs,
     }
 
     ide_reset(s);
-    bdrv_set_removable(bs, s->drive_kind == IDE_CD);
+    bdrv_iostatus_enable(bs);
     return 0;
 }
 
@@ -2567,10 +1900,14 @@ static void ide_init1(IDEBus *bus, int unit)
     s->unit = unit;
     s->drive_serial = drive_serial++;
     /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
-    s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4);
     s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
+    s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
+    memset(s->io_buffer, 0, s->io_buffer_total_len);
+
     s->smart_selftest_data = qemu_blockalign(s->bs, 512);
-    s->sector_write_timer = qemu_new_timer(vm_clock,
+    memset(s->smart_selftest_data, 0, 512);
+
+    s->sector_write_timer = qemu_new_timer_ns(vm_clock,
                                            ide_sector_write_timer_cb, s);
 }
 
@@ -2589,7 +1926,7 @@ static int ide_nop_int(IDEDMA *dma, int x)
     return 0;
 }
 
-static void ide_nop_restart(void *opaque, int x, int y)
+static void ide_nop_restart(void *opaque, int x, RunState y)
 {
 }
 
@@ -2633,11 +1970,13 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
         dinfo = i == 0 ? hd0 : hd1;
         ide_init1(bus, i);
         if (dinfo) {
-            if (ide_init_drive(&bus->ifs[i], dinfo->bdrv, NULL,
+            if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
+                               dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
                                *dinfo->serial ? dinfo->serial : NULL) < 0) {
                 error_report("Can't set up IDE drive %s", dinfo->id);
                 exit(1);
             }
+            bdrv_attach_dev_nofail(dinfo->bdrv, &bus->ifs[i]);
         } else {
             ide_reset(&bus->ifs[i]);
         }
@@ -2646,20 +1985,27 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
     bus->dma = &ide_dma_nop;
 }
 
-void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
+static const MemoryRegionPortio ide_portio_list[] = {
+    { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
+    { 0, 2, 2, .read = ide_data_readw, .write = ide_data_writew },
+    { 0, 4, 4, .read = ide_data_readl, .write = ide_data_writel },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio ide_portio2_list[] = {
+    { 0, 1, 1, .read = ide_status_read, .write = ide_cmd_write },
+    PORTIO_END_OF_LIST(),
+};
+
+void ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2)
 {
-    register_ioport_write(iobase, 8, 1, ide_ioport_write, bus);
-    register_ioport_read(iobase, 8, 1, ide_ioport_read, bus);
+    /* ??? Assume only ISA and PCI configurations, and that the PCI-ISA
+       bridge has been setup properly to always register with ISA.  */
+    isa_register_portio_list(dev, iobase, ide_portio_list, bus, "ide");
+
     if (iobase2) {
-        register_ioport_read(iobase2, 1, 1, ide_status_read, bus);
-        register_ioport_write(iobase2, 1, 1, ide_cmd_write, bus);
+        isa_register_portio_list(dev, iobase2, ide_portio2_list, bus, "ide");
     }
-
-    /* data ports */
-    register_ioport_write(iobase, 2, 2, ide_data_writew, bus);
-    register_ioport_read(iobase, 2, 2, ide_data_readw, bus);
-    register_ioport_write(iobase, 4, 4, ide_data_writel, bus);
-    register_ioport_read(iobase, 4, 4, ide_data_readl, bus);
 }
 
 static bool is_identify_set(void *opaque, int version_id)
@@ -2694,7 +2040,7 @@ static int ide_drive_post_load(void *opaque, int version_id)
     IDEState *s = opaque;
 
     if (version_id < 3) {
-        if (s->sense_key == SENSE_UNIT_ATTENTION &&
+        if (s->sense_key == UNIT_ATTENTION &&
             s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
             s->cdrom_changed = 1;
         }
@@ -2706,7 +2052,7 @@ static int ide_drive_pio_post_load(void *opaque, int version_id)
 {
     IDEState *s = opaque;
 
-    if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
+    if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
         return -EINVAL;
     }
     s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
@@ -2738,10 +2084,67 @@ static bool ide_drive_pio_state_needed(void *opaque)
 {
     IDEState *s = opaque;
 
-    return (s->status & DRQ_STAT) != 0;
+    return ((s->status & DRQ_STAT) != 0)
+        || (s->bus->error_status & BM_STATUS_PIO_RETRY);
+}
+
+static int ide_tray_state_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    bdrv_eject(s->bs, s->tray_open);
+    bdrv_lock_medium(s->bs, s->tray_locked);
+    return 0;
+}
+
+static bool ide_tray_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->tray_open || s->tray_locked;
+}
+
+static bool ide_atapi_gesn_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->events.new_media || s->events.eject_request;
 }
 
-const VMStateDescription vmstate_ide_drive_pio_state = {
+static bool ide_error_needed(void *opaque)
+{
+    IDEBus *bus = opaque;
+
+    return (bus->error_status != 0);
+}
+
+/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
+static 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),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ide_tray_state = {
+    .name = "ide_drive/tray_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ide_tray_state_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(tray_open, IDEState),
+        VMSTATE_BOOL(tray_locked, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ide_drive_pio_state = {
     .name = "ide_drive/pio_state",
     .version_id = 1,
     .minimum_version_id = 1,
@@ -2794,12 +2197,29 @@ const VMStateDescription vmstate_ide_drive = {
         {
             .vmsd = &vmstate_ide_drive_pio_state,
             .needed = ide_drive_pio_state_needed,
+        }, {
+            .vmsd = &vmstate_ide_tray_state,
+            .needed = ide_tray_state_needed,
+        }, {
+            .vmsd = &vmstate_ide_atapi_gesn_state,
+            .needed = ide_atapi_gesn_needed,
         }, {
             /* empty */
         }
     }
 };
 
+static const VMStateDescription vmstate_ide_error_status = {
+    .name ="ide_bus/error",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32(error_status, IDEBus),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_ide_bus = {
     .name = "ide_bus",
     .version_id = 1,
@@ -2809,5 +2229,27 @@ const VMStateDescription vmstate_ide_bus = {
         VMSTATE_UINT8(cmd, IDEBus),
         VMSTATE_UINT8(unit, IDEBus),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_error_status,
+            .needed = ide_error_needed,
+        }, {
+            /* empty */
+        }
     }
 };
+
+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 f242d7a81fe34892491db729a4d926d77391ac78..3f7510f52eb573afd8d39a90af36475e4d873df6 100644 (file)
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
 #include <hw/ide/ahci.h>
 
+#define ICH9_SATA_CAP_OFFSET    0xA8
+
+#define ICH9_IDP_BAR            4
+#define ICH9_MEM_BAR            5
+
+#define ICH9_IDP_INDEX          0x10
+#define ICH9_IDP_INDEX_LOG2     0x04
+
+static const VMStateDescription vmstate_ahci = {
+    .name = "ahci",
+    .unmigratable = 1,
+};
+
 static int pci_ich9_ahci_init(PCIDevice *dev)
 {
     struct AHCIPCIState *d;
+    int sata_cap_offset;
+    uint8_t *sata_cap;
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
-    pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR);
+    ahci_init(&d->ahci, &dev->qdev, 6);
 
-    pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA);
-    pci_config_set_revision(d->card.config, 0x02);
     pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
 
     d->card.config[PCI_CACHE_LINE_SIZE] = 0x08;  /* Cache line size */
@@ -94,15 +104,26 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
 
     qemu_register_reset(ahci_reset, d);
 
-    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
-    pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     ahci_pci_map);
-
     msi_init(dev, 0x50, 1, true, false);
-
-    ahci_init(&d->ahci, &dev->qdev, 6);
     d->ahci.irq = d->card.irq[0];
 
+    pci_register_bar(&d->card, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+                     &d->ahci.idp);
+    pci_register_bar(&d->card, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &d->ahci.mem);
+
+    sata_cap_offset = pci_add_capability(&d->card, PCI_CAP_ID_SATA,
+                                         ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE);
+    if (sata_cap_offset < 0) {
+        return sata_cap_offset;
+    }
+
+    sata_cap = d->card.config + sata_cap_offset;
+    pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
+    pci_set_long(sata_cap + SATA_CAP_BAR,
+                 (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4));
+    d->ahci.idp_offset = ICH9_IDP_INDEX;
+
     return 0;
 }
 
@@ -111,10 +132,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
     struct AHCIPCIState *d;
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
-    if (msi_enabled(dev)) {
-        msi_uninit(dev);
-    }
-
+    msi_uninit(dev);
     qemu_unregister_reset(ahci_reset, d);
     ahci_uninit(&d->ahci);
 
@@ -133,9 +151,14 @@ static PCIDeviceInfo ich_ahci_info[] = {
         .qdev.name    = "ich9-ahci",
         .qdev.alias   = "ahci",
         .qdev.size    = sizeof(AHCIPCIState),
+        .qdev.vmsd    = &vmstate_ahci,
         .init         = pci_ich9_ahci_init,
         .exit         = pci_ich9_uninit,
         .config_write = pci_ich9_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801IR,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_STORAGE_SATA,
     },{
         /* end of list */
     }
index d533fb63b3bfa89ff84eef9cc980cea4b889535e..00b28dfdbcf2b56753d176887246ecaab36c9db2 100644 (file)
@@ -7,8 +7,11 @@
  * non-internal declarations are in hw/ide.h
  */
 #include <hw/ide.h>
-#include "block_int.h"
+#include <hw/isa.h>
 #include "iorange.h"
+#include "dma.h"
+#include "sysemu.h"
+#include "hw/scsi-defs.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -54,107 +57,120 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define IDE_CMD_RESET           0x04
 #define IDE_CMD_DISABLE_IRQ     0x02
 
-/* ATA/ATAPI Commands pre T13 Spec */
+/* ACS-2 T13/2015-D Table B.2 Command codes */
 #define WIN_NOP                                0x00
-/*
- *     0x01->0x02 Reserved
- */
+/* reserved                             0x01..0x02 */
 #define CFA_REQ_EXT_ERROR_CODE         0x03 /* CFA Request Extended Error Code */
-/*
- *     0x04->0x07 Reserved
- */
-#define WIN_SRST                       0x08 /* ATAPI soft reset command */
+/* reserved                             0x04..0x05 */
+#define WIN_DSM                         0x06
+/* reserved                             0x07 */
 #define WIN_DEVICE_RESET               0x08
-/*
- *     0x09->0x0F Reserved
- */
-#define WIN_RECAL                      0x10
-#define WIN_RESTORE                    WIN_RECAL
-/*
- *     0x10->0x1F Reserved
- */
+/* reserved                             0x09..0x0a */
+/* REQUEST SENSE DATA EXT               0x0B */
+/* reserved                             0x0C..0x0F */
+#define WIN_RECAL                       0x10 /* obsolete since ATA4 */
+/* obsolete since ATA3, retired in ATA4 0x11..0x1F */
 #define WIN_READ                       0x20 /* 28-Bit */
-#define WIN_READ_ONCE                  0x21 /* 28-Bit without retries */
-#define WIN_READ_LONG                  0x22 /* 28-Bit */
-#define WIN_READ_LONG_ONCE             0x23 /* 28-Bit without retries */
+#define WIN_READ_ONCE                   0x21 /* 28-Bit w/o retries, obsolete since ATA5 */
+/* obsolete since ATA4                  0x22..0x23 */
 #define WIN_READ_EXT                   0x24 /* 48-Bit */
 #define WIN_READDMA_EXT                        0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT         0x26 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT          0x26 /* 48-Bit, obsolete since ACS2 */
 #define WIN_READ_NATIVE_MAX_EXT                0x27 /* 48-Bit */
-/*
- *     0x28
- */
+/* reserved                             0x28 */
 #define WIN_MULTREAD_EXT               0x29 /* 48-Bit */
-/*
- *     0x2A->0x2F Reserved
- */
+/* READ STREAM DMA EXT                  0x2A */
+/* READ STREAM EXT                      0x2B */
+/* reserved                             0x2C..0x2E */
+/* READ LOG EXT                         0x2F */
 #define WIN_WRITE                      0x30 /* 28-Bit */
-#define WIN_WRITE_ONCE                 0x31 /* 28-Bit without retries */
-#define WIN_WRITE_LONG                 0x32 /* 28-Bit */
-#define WIN_WRITE_LONG_ONCE            0x33 /* 28-Bit without retries */
+#define WIN_WRITE_ONCE                  0x31 /* 28-Bit w/o retries, obsolete since ATA5 */
+/* obsolete since ATA4                  0x32..0x33 */
 #define WIN_WRITE_EXT                  0x34 /* 48-Bit */
 #define WIN_WRITEDMA_EXT               0x35 /* 48-Bit */
 #define WIN_WRITEDMA_QUEUED_EXT                0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT                 0x37 /* 48-Bit, obsolete since ACS2 */
 #define WIN_SET_MAX_EXT                        0x37 /* 48-Bit */
 #define CFA_WRITE_SECT_WO_ERASE                0x38 /* CFA Write Sectors without erase */
 #define WIN_MULTWRITE_EXT              0x39 /* 48-Bit */
-/*
- *     0x3A->0x3B Reserved
- */
-#define WIN_WRITE_VERIFY               0x3C /* 28-Bit */
-/*
- *     0x3D->0x3F Reserved
- */
+/* WRITE STREAM DMA EXT                 0x3A */
+/* WRITE STREAM EXT                     0x3B */
+#define WIN_WRITE_VERIFY                0x3C /* 28-Bit, obsolete since ATA4 */
+/* WRITE DMA FUA EXT                    0x3D */
+/* obsolete since ACS2                  0x3E */
+/* WRITE LOG EXT                        0x3F */
 #define WIN_VERIFY                     0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_ONCE                        0x41 /* 28-Bit - without retries */
+#define WIN_VERIFY_ONCE                 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */
 #define WIN_VERIFY_EXT                 0x42 /* 48-Bit */
-/*
- *     0x43->0x4F Reserved
- */
-#define WIN_FORMAT                     0x50
-/*
- *     0x51->0x5F Reserved
- */
-#define WIN_INIT                       0x60
-/*
- *     0x61->0x5F Reserved
- */
-#define WIN_SEEK                       0x70 /* 0x70-0x7F Reserved */
+/* reserved                             0x43..0x44 */
+/* WRITE UNCORRECTABLE EXT              0x45 */
+/* reserved                             0x46 */
+/* READ LOG DMA EXT                     0x47 */
+/* reserved                             0x48..0x4F */
+/* obsolete since ATA4                  0x50 */
+/* CONFIGURE STREAM                     0x51 */
+/* reserved                             0x52..0x56 */
+/* WRITE LOG DMA EXT                    0x57 */
+/* reserved                             0x58..0x5A */
+/* TRUSTED NON DATA                     0x5B */
+/* TRUSTED RECEIVE                      0x5C */
+/* TRUSTED RECEIVE DMA                  0x5D */
+/* TRUSTED SEND                         0x5E */
+/* TRUSTED SEND DMA                     0x5F */
+/* READ FPDMA QUEUED                    0x60 */
+/* WRITE FPDMA QUEUED                   0x61 */
+/* reserved                             0x62->0x6F */
+#define WIN_SEEK                        0x70 /* obsolete since ATA7 */
+/* reserved                             0x71-0x7F */
+/* vendor specific                      0x80-0x86 */
 #define CFA_TRANSLATE_SECTOR           0x87 /* CFA Translate Sector */
+/* vendor specific                      0x88-0x8F */
 #define WIN_DIAGNOSE                   0x90
-#define WIN_SPECIFY                    0x91 /* set drive geometry translation */
+#define WIN_SPECIFY                     0x91 /* set drive geometry translation, obsolete since ATA6 */
 #define WIN_DOWNLOAD_MICROCODE         0x92
-#define WIN_STANDBYNOW2                        0x94
-#define CFA_IDLEIMMEDIATE              0x95 /* force drive to become "ready" */
-#define WIN_STANDBY2                   0x96
-#define WIN_SETIDLE2                   0x97
-#define WIN_CHECKPOWERMODE2            0x98
-#define WIN_SLEEPNOW2                  0x99
-/*
- *     0x9A VENDOR
- */
+/* DOWNLOAD MICROCODE DMA               0x93 */
+#define WIN_STANDBYNOW2                 0x94 /* retired in ATA4 */
+#define WIN_IDLEIMMEDIATE2              0x95 /* force drive to become "ready", retired in ATA4 */
+#define WIN_STANDBY2                    0x96 /* retired in ATA4 */
+#define WIN_SETIDLE2                    0x97 /* retired in ATA4 */
+#define WIN_CHECKPOWERMODE2             0x98 /* retired in ATA4 */
+#define WIN_SLEEPNOW2                   0x99 /* retired in ATA4 */
+/* vendor specific                      0x9A */
+/* reserved                             0x9B..0x9F */
 #define WIN_PACKETCMD                  0xA0 /* Send a packet command. */
 #define WIN_PIDENTIFY                  0xA1 /* identify ATAPI device   */
-#define WIN_QUEUED_SERVICE             0xA2
+#define WIN_QUEUED_SERVICE              0xA2 /* obsolete since ACS2 */
+/* reserved                             0xA3..0xAF */
 #define WIN_SMART                      0xB0 /* self-monitoring and reporting */
+/* Device Configuration Overlay         0xB1 */
+/* reserved                             0xB2..0xB3 */
+/* Sanitize Device                      0xB4 */
+/* reserved                             0xB5 */
+/* NV Cache                             0xB6 */
+/* reserved for CFA                     0xB7..0xBB */
 #define CFA_ACCESS_METADATA_STORAGE    0xB8
+/* reserved                             0xBC..0xBF */
 #define CFA_ERASE_SECTORS              0xC0 /* microdrives implement as NOP */
+/* vendor specific                      0xC1..0xC3 */
 #define WIN_MULTREAD                   0xC4 /* read sectors using multiple mode*/
 #define WIN_MULTWRITE                  0xC5 /* write sectors using multiple mode */
 #define WIN_SETMULT                    0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED             0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA_QUEUED              0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */
 #define WIN_READDMA                    0xC8 /* read sectors using DMA transfers */
-#define WIN_READDMA_ONCE               0xC9 /* 28-Bit - without retries */
+#define WIN_READDMA_ONCE                0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */
 #define WIN_WRITEDMA                   0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_ONCE              0xCB /* 28-Bit - without retries */
-#define WIN_WRITEDMA_QUEUED            0xCC /* write sectors using Queued DMA transfers */
+#define WIN_WRITEDMA_ONCE               0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */
+#define WIN_WRITEDMA_QUEUED            0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */
 #define CFA_WRITE_MULTI_WO_ERASE       0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS             0xDA
-#define WIN_ACKMEDIACHANGE             0xDB /* ATA-1, ATA-2 vendor */
-#define WIN_POSTBOOT                   0xDC
-#define WIN_PREBOOT                    0xDD
-#define WIN_DOORLOCK                   0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK                 0xDF /* unlock door on removable drives */
+/* WRITE MULTIPLE FUA EXT               0xCE */
+/* reserved                             0xCF..0xDO */
+/* CHECK MEDIA CARD TYPE                0xD1 */
+/* reserved for media card pass through 0xD2..0xD4 */
+/* reserved                             0xD5..0xD9 */
+#define WIN_GETMEDIASTATUS              0xDA /* obsolete since ATA8 */
+/* obsolete since ATA3, retired in ATA4 0xDB..0xDD */
+#define WIN_DOORLOCK                    0xDE /* lock door on removable drives, obsolete since ATA8 */
+#define WIN_DOORUNLOCK                  0xDF /* unlock door on removable drives, obsolete since ATA8 */
 #define WIN_STANDBYNOW1                        0xE0
 #define WIN_IDLEIMMEDIATE              0xE1 /* force drive to become "ready" */
 #define WIN_STANDBY                    0xE2 /* Set device in Standby Mode */
@@ -164,31 +180,34 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define WIN_SLEEPNOW1                  0xE6
 #define WIN_FLUSH_CACHE                        0xE7
 #define WIN_WRITE_BUFFER               0xE8 /* force write only 1 sector */
-#define WIN_WRITE_SAME                 0xE9 /* read ata-2 to use */
-       /* SET_FEATURES 0x22 or 0xDD */
+/* READ BUFFER DMA                      0xE9 */
 #define WIN_FLUSH_CACHE_EXT            0xEA /* 48-Bit */
+/* WRITE BUFFER DMA                     0xEB */
 #define WIN_IDENTIFY                   0xEC /* ask drive to identify itself    */
-#define WIN_MEDIAEJECT                 0xED
-#define WIN_IDENTIFY_DMA               0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_MEDIAEJECT                  0xED /* obsolete since ATA8 */
+/* obsolete since ATA4                  0xEE */
 #define WIN_SETFEATURES                        0xEF /* set special drive features */
-#define EXABYTE_ENABLE_NEST            0xF0
-#define IBM_SENSE_CONDITION            0xF0 /* measure disk temperature */
+#define IBM_SENSE_CONDITION             0xF0 /* measure disk temperature, vendor specific */
 #define WIN_SECURITY_SET_PASS          0xF1
 #define WIN_SECURITY_UNLOCK            0xF2
 #define WIN_SECURITY_ERASE_PREPARE     0xF3
 #define WIN_SECURITY_ERASE_UNIT                0xF4
 #define WIN_SECURITY_FREEZE_LOCK       0xF5
-#define CFA_WEAR_LEVEL                 0xF5 /* microdrives implement as NOP */
+#define CFA_WEAR_LEVEL                  0xF5 /* microdrives implement as NOP; not specified in T13! */
 #define WIN_SECURITY_DISABLE           0xF6
+/* vendor specific                      0xF7 */
 #define WIN_READ_NATIVE_MAX            0xF8 /* return the native maximum address */
 #define WIN_SET_MAX                    0xF9
-#define DISABLE_SEAGATE                        0xFB
+/* vendor specific                      0xFA..0xFF */
 
 /* set to 1 set disable mult support */
 #define MAX_MULT_SECTORS 16
 
 #define IDE_DMA_BUF_SECTORS 256
 
+/* feature values for Data Set Management */
+#define DSM_TRIM                        0x01
+
 #if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
 #error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
 #endif
@@ -262,71 +281,6 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define GPCMD_GET_MEDIA_STATUS             0xda
 #define GPCMD_MODE_SENSE_6                 0x1a
 
-/* Mode page codes for mode sense/set */
-#define GPMODE_R_W_ERROR_PAGE          0x01
-#define GPMODE_WRITE_PARMS_PAGE                0x05
-#define GPMODE_AUDIO_CTL_PAGE          0x0e
-#define GPMODE_POWER_PAGE              0x1a
-#define GPMODE_FAULT_FAIL_PAGE         0x1c
-#define GPMODE_TO_PROTECT_PAGE         0x1d
-#define GPMODE_CAPABILITIES_PAGE       0x2a
-#define GPMODE_ALL_PAGES               0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
- * of MODE_SENSE_POWER_PAGE */
-#define GPMODE_CDROM_PAGE              0x0d
-
-/*
- * Based on values from <linux/cdrom.h> but extending CD_MINS
- * to the maximum common size allowed by the Orange's Book ATIP
- *
- * 90 and 99 min CDs are also available but using them as the
- * upper limit reduces the effectiveness of the heuristic to
- * detect DVDs burned to less than 25% of their maximum capacity
- */
-
-/* Some generally useful CD-ROM information */
-#define CD_MINS                       80 /* max. minutes per CD */
-#define CD_SECS                       60 /* seconds per minute */
-#define CD_FRAMES                     75 /* frames per second */
-#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
-#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
-#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
-
-/*
- * The MMC values are not IDE specific and might need to be moved
- * to a common header if they are also needed for the SCSI emulation
- */
-
-/* Profile list from MMC-6 revision 1 table 91 */
-#define MMC_PROFILE_NONE                0x0000
-#define MMC_PROFILE_CD_ROM              0x0008
-#define MMC_PROFILE_CD_R                0x0009
-#define MMC_PROFILE_CD_RW               0x000A
-#define MMC_PROFILE_DVD_ROM             0x0010
-#define MMC_PROFILE_DVD_R_SR            0x0011
-#define MMC_PROFILE_DVD_RAM             0x0012
-#define MMC_PROFILE_DVD_RW_RO           0x0013
-#define MMC_PROFILE_DVD_RW_SR           0x0014
-#define MMC_PROFILE_DVD_R_DL_SR         0x0015
-#define MMC_PROFILE_DVD_R_DL_JR         0x0016
-#define MMC_PROFILE_DVD_RW_DL           0x0017
-#define MMC_PROFILE_DVD_DDR             0x0018
-#define MMC_PROFILE_DVD_PLUS_RW         0x001A
-#define MMC_PROFILE_DVD_PLUS_R          0x001B
-#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
-#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
-#define MMC_PROFILE_BD_ROM              0x0040
-#define MMC_PROFILE_BD_R_SRM            0x0041
-#define MMC_PROFILE_BD_R_RRM            0x0042
-#define MMC_PROFILE_BD_RE               0x0043
-#define MMC_PROFILE_HDDVD_ROM           0x0050
-#define MMC_PROFILE_HDDVD_R             0x0051
-#define MMC_PROFILE_HDDVD_RAM           0x0052
-#define MMC_PROFILE_HDDVD_RW            0x0053
-#define MMC_PROFILE_HDDVD_R_DL          0x0058
-#define MMC_PROFILE_HDDVD_RW_DL         0x005A
-#define MMC_PROFILE_INVALID             0xFFFF
-
 #define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
 #define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
 #define ATAPI_INT_REASON_REL            0x04
@@ -348,11 +302,6 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define CFA_INVALID_ADDRESS     0x21
 #define CFA_ADDRESS_OVERFLOW    0x2f
 
-#define SENSE_NONE            0
-#define SENSE_NOT_READY       2
-#define SENSE_ILLEGAL_REQUEST 5
-#define SENSE_UNIT_ATTENTION  6
-
 #define SMART_READ_DATA       0xd0
 #define SMART_READ_THRESH     0xd1
 #define SMART_ATTR_AUTOSAVE   0xd2
@@ -371,7 +320,21 @@ typedef void EndTransferFunc(IDEState *);
 typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *);
 typedef int DMAFunc(IDEDMA *);
 typedef int DMAIntFunc(IDEDMA *, int);
-typedef void DMARestartFunc(void *, int, int);
+typedef void DMARestartFunc(void *, int, RunState);
+
+struct unreported_events {
+    bool eject_request;
+    bool new_media;
+};
+
+enum ide_dma_cmd {
+    IDE_DMA_READ,
+    IDE_DMA_WRITE,
+    IDE_DMA_TRIM,
+};
+
+#define ide_cmd_is_read(s) \
+       ((s)->dma_cmd == IDE_DMA_READ)
 
 /* NOTE: IDEState represents in fact one drive */
 struct IDEState {
@@ -408,8 +371,11 @@ struct IDEState {
     BlockDriverState *bs;
     char version[9];
     /* ATAPI specific */
+    struct unreported_events events;
     uint8_t sense_key;
     uint8_t asc;
+    bool tray_open;
+    bool tray_locked;
     uint8_t cdrom_changed;
     int packet_transfer_size;
     int elementary_transfer_size;
@@ -417,6 +383,7 @@ struct IDEState {
     int lba;
     int cd_sector_size;
     int atapi_dma; /* true if dma is requested for the packet cmd */
+    BlockAcctCookie acct;
     /* ATA DMA state */
     int io_buffer_size;
     QEMUSGList sg;
@@ -439,7 +406,7 @@ struct IDEState {
     uint32_t mdata_size;
     uint8_t *mdata_storage;
     int media_changed;
-    int is_read;
+    enum ide_dma_cmd dma_cmd;
     /* SMART */
     uint8_t smart_enabled;
     uint8_t smart_autosave;
@@ -479,6 +446,8 @@ struct IDEBus {
     uint8_t unit;
     uint8_t cmd;
     qemu_irq irq;
+
+    int error_status;
 };
 
 struct IDEDevice {
@@ -498,10 +467,17 @@ struct IDEDeviceInfo {
 #define BM_STATUS_DMAING 0x01
 #define BM_STATUS_ERROR  0x02
 #define BM_STATUS_INT    0x04
+
+/* FIXME These are not status register bits */
 #define BM_STATUS_DMA_RETRY  0x08
 #define BM_STATUS_PIO_RETRY  0x10
 #define BM_STATUS_RETRY_READ  0x20
 #define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_STATUS_RETRY_TRIM 0x80
+
+#define BM_MIGRATION_COMPAT_STATUS_BITS \
+        (BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
+        BM_STATUS_RETRY_READ | BM_STATUS_RETRY_FLUSH)
 
 #define BM_CMD_START     0x01
 #define BM_CMD_READ      0x08
@@ -551,12 +527,12 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
 void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
 uint32_t ide_data_readl(void *opaque, uint32_t addr);
 
-int ide_init_drive(IDEState *s, BlockDriverState *bs,
+int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
                    const char *version, const char *serial);
 void ide_init2(IDEBus *bus, qemu_irq irq);
 void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
                                     DriveInfo *hd1, qemu_irq irq);
-void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
+void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2);
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val);
 void ide_dma_cb(void *opaque, int ret);
@@ -564,6 +540,18 @@ 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);
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+/* 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..01a9e59cb9678499d495883560bbdd29212d5111 100644 (file)
@@ -26,8 +26,6 @@
 #include <hw/pc.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
@@ -68,10 +66,8 @@ static int isa_ide_initfn(ISADevice *dev)
     ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
 
     ide_bus_new(&s->bus, &s->dev.qdev, 0);
-    ide_init_ioport(&s->bus, s->iobase, s->iobase2);
+    ide_init_ioport(&s->bus, dev, s->iobase, s->iobase2);
     isa_init_irq(dev, &s->irq, s->isairq);
-    isa_init_ioport_range(dev, s->iobase, 8);
-    isa_init_ioport(dev, s->iobase2);
     ide_init2(&s->bus, s->irq);
     vmstate_register(&dev->qdev, 0, &vmstate_ide_isa, s);
     return 0;
index c1b4caab5b4f80a9d8f17a26f1f685ad5394ade1..70b33422d2b1227f1742e7e4924a3f3e79dc6353 100644 (file)
@@ -26,8 +26,6 @@
 #include <hw/ppc_mac.h>
 #include <hw/mac_dbdma.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
@@ -36,6 +34,7 @@
 /* MacIO based PowerPC IDE */
 
 typedef struct MACIOIDEState {
+    MemoryRegion mem;
     IDEBus bus;
     BlockDriverAIOCB *aiocb;
 } MACIOIDEState;
@@ -52,8 +51,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
         m->aiocb = NULL;
         qemu_sglist_destroy(&s->sg);
         ide_atapi_io_error(s, ret);
-        io->dma_end(opaque);
-        return;
+        goto done;
     }
 
     if (s->io_buffer_size > 0) {
@@ -71,8 +69,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
         ide_atapi_cmd_ok(s);
 
     if (io->len == 0) {
-        io->dma_end(opaque);
-        return;
+        goto done;
     }
 
     /* launch next transfer */
@@ -90,11 +87,16 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
     if (!m->aiocb) {
         qemu_sglist_destroy(&s->sg);
         /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+        ide_atapi_cmd_error(s, NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
-        io->dma_end(opaque);
-        return;
+        goto done;
     }
+    return;
+
+done:
+    bdrv_acct_done(s->bs, &s->acct);
+    io->dma_end(opaque);
+    return;
 }
 
 static void pmac_ide_transfer_cb(void *opaque, int ret)
@@ -109,8 +111,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
         m->aiocb = NULL;
         qemu_sglist_destroy(&s->sg);
        ide_dma_error(s);
-        io->dma_end(io);
-        return;
+        goto done;
     }
 
     sector_num = ide_get_sector(s);
@@ -130,10 +131,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
     }
 
     /* end of DMA ? */
-
     if (io->len == 0) {
-        io->dma_end(io);
-       return;
+        goto done;
     }
 
     /* launch next transfer */
@@ -146,14 +145,29 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
     io->addr += io->len;
     io->len = 0;
 
-    if (s->is_read)
+    switch (s->dma_cmd) {
+    case IDE_DMA_READ:
         m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
                                 pmac_ide_transfer_cb, io);
-    else
+        break;
+    case IDE_DMA_WRITE:
         m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
                                  pmac_ide_transfer_cb, io);
+        break;
+    case IDE_DMA_TRIM:
+        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+                               ide_issue_trim, pmac_ide_transfer_cb, s, true);
+        break;
+    }
+
     if (!m->aiocb)
         pmac_ide_transfer_cb(io, -1);
+    return;
+done:
+    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
+        bdrv_acct_done(s->bs, &s->acct);
+    }
+    io->dma_end(io);
 }
 
 static void pmac_ide_transfer(DBDMA_io *io)
@@ -163,10 +177,22 @@ static void pmac_ide_transfer(DBDMA_io *io)
 
     s->io_buffer_size = 0;
     if (s->drive_kind == IDE_CD) {
+        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
         pmac_ide_atapi_transfer_cb(io, 0);
         return;
     }
 
+    switch (s->dma_cmd) {
+    case IDE_DMA_READ:
+        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
+        break;
+    case IDE_DMA_WRITE:
+        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
+        break;
+    default:
+        break;
+    }
+
     pmac_ide_transfer_cb(io, 0);
 }
 
@@ -273,16 +299,20 @@ static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const pmac_ide_write[] = {
-    pmac_ide_writeb,
-    pmac_ide_writew,
-    pmac_ide_writel,
-};
-
-static CPUReadMemoryFunc * const pmac_ide_read[] = {
-    pmac_ide_readb,
-    pmac_ide_readw,
-    pmac_ide_readl,
+static MemoryRegionOps pmac_ide_ops = {
+    .old_mmio = {
+        .write = {
+            pmac_ide_writeb,
+            pmac_ide_writew,
+            pmac_ide_writel,
+        },
+        .read = {
+            pmac_ide_readb,
+            pmac_ide_readw,
+            pmac_ide_readl,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pmac = {
@@ -307,23 +337,20 @@ static void pmac_ide_reset(void *opaque)
 /* hd_table must contain 4 block drivers */
 /* PowerMac uses memory mapped registers, not I/O. Return the memory
    I/O index to access the ide. */
-int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
-                  void *dbdma, int channel, qemu_irq dma_irq)
+MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
+                             void *dbdma, int channel, qemu_irq dma_irq)
 {
     MACIOIDEState *d;
-    int pmac_ide_memory;
 
-    d = qemu_mallocz(sizeof(MACIOIDEState));
+    d = g_malloc0(sizeof(MACIOIDEState));
     ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
 
     if (dbdma)
         DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
 
-    pmac_ide_memory = cpu_register_io_memory(pmac_ide_read,
-                                             pmac_ide_write, d,
-                                             DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000);
     vmstate_register(NULL, 0, &vmstate_pmac, d);
     qemu_register_reset(pmac_ide_reset, d);
 
-    return pmac_ide_memory;
+    return &d->mem;
 }
index 2ceeb87c0c6c2bd6b3c8d893746abd9000e1a482..9eee5b50ba9c6136e75ca6102de0a36ade58c2b7 100644 (file)
@@ -26,8 +26,6 @@
 #include <hw/pc.h>
 #include <hw/pcmcia.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
@@ -532,7 +530,7 @@ static int dscm1xxxx_detach(void *opaque)
 
 PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv)
 {
-    MicroDriveState *md = (MicroDriveState *) qemu_mallocz(sizeof(MicroDriveState));
+    MicroDriveState *md = (MicroDriveState *) g_malloc0(sizeof(MicroDriveState));
     md->card.state = md;
     md->card.attach = dscm1xxxx_attach;
     md->card.detach = dscm1xxxx_detach;
@@ -543,7 +541,7 @@ PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv)
                                    qemu_allocate_irqs(md_set_irq, md, 1)[0]);
     md->bus.ifs[0].drive_kind = IDE_CFATA;
     md->bus.ifs[0].mdata_size = METADATA_SIZE;
-    md->bus.ifs[0].mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
+    md->bus.ifs[0].mdata_storage = (uint8_t *) g_malloc0(METADATA_SIZE);
 
     vmstate_register(NULL, -1, &vmstate_microdrive, md);
 
index 82b24b673bbb88c7344e1480086d2694bcea828c..2ec21b01632114afcc071695c74895b9fc95b085 100644 (file)
@@ -24,8 +24,6 @@
  */
 #include <hw/hw.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
@@ -122,7 +120,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
                     qemu_irq irq, int shift,
                     DriveInfo *hd0, DriveInfo *hd1)
 {
-    MMIOState *s = qemu_mallocz(sizeof(MMIOState));
+    MMIOState *s = g_malloc0(sizeof(MMIOState));
     int mem1, mem2;
 
     ide_init2_with_non_qdev_drives(&s->bus, hd0, hd1, irq);
index 35168cb46970f70b904390637bc6d9cbd75155fb..49b823df79b656b8375a9c2c41ec5899d918cf84 100644 (file)
@@ -27,8 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
@@ -64,7 +62,8 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
     } prd;
     int l, len;
 
-    qemu_sglist_init(&s->sg, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1);
+    pci_dma_sglist_init(&s->sg, &bm->pci_dev->dev,
+                        s->nsector / (BMDMA_PAGE_SIZE / 512) + 1);
     s->io_buffer_size = 0;
     for(;;) {
         if (bm->cur_prd_len == 0) {
@@ -72,7 +71,7 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
             if (bm->cur_prd_last ||
                 (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
                 return s->io_buffer_size != 0;
-            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+            pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8);
             bm->cur_addr += 8;
             prd.addr = le32_to_cpu(prd.addr);
             prd.size = le32_to_cpu(prd.size);
@@ -114,7 +113,7 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write)
             if (bm->cur_prd_last ||
                 (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
                 return 0;
-            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+            pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8);
             bm->cur_addr += 8;
             prd.addr = le32_to_cpu(prd.addr);
             prd.size = le32_to_cpu(prd.size);
@@ -129,11 +128,11 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write)
             l = bm->cur_prd_len;
         if (l > 0) {
             if (is_write) {
-                cpu_physical_memory_write(bm->cur_prd_addr,
-                                          s->io_buffer + s->io_buffer_index, l);
+                pci_dma_write(&bm->pci_dev->dev, bm->cur_prd_addr,
+                              s->io_buffer + s->io_buffer_index, l);
             } else {
-                cpu_physical_memory_read(bm->cur_prd_addr,
-                                          s->io_buffer + s->io_buffer_index, l);
+                pci_dma_read(&bm->pci_dev->dev, bm->cur_prd_addr,
+                             s->io_buffer + s->io_buffer_index, l);
             }
             bm->cur_prd_addr += l;
             bm->cur_prd_len -= l;
@@ -170,7 +169,7 @@ static int bmdma_set_inactive(IDEDMA *dma)
     return 0;
 }
 
-static void bmdma_restart_dma(BMDMAState *bm, int is_read)
+static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
 {
     IDEState *s = bmdma_active_if(bm);
 
@@ -178,38 +177,53 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
     s->nsector = bm->nsector;
-    s->is_read = is_read;
+    s->dma_cmd = dma_cmd;
     bm->cur_addr = bm->addr;
     bm->dma_cb = ide_dma_cb;
     bmdma_start_dma(&bm->dma, s, bm->dma_cb);
 }
 
+/* TODO This should be common IDE code */
 static void bmdma_restart_bh(void *opaque)
 {
     BMDMAState *bm = opaque;
+    IDEBus *bus = bm->bus;
     int is_read;
+    int error_status;
 
     qemu_bh_delete(bm->bh);
     bm->bh = NULL;
 
-    is_read = !!(bm->status & BM_STATUS_RETRY_READ);
+    if (bm->unit == (uint8_t) -1) {
+        return;
+    }
+
+    is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
 
-    if (bm->status & BM_STATUS_DMA_RETRY) {
-        bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
-        bmdma_restart_dma(bm, is_read);
-    } else if (bm->status & BM_STATUS_PIO_RETRY) {
-        bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
+    /* The error status must be cleared before resubmitting the request: The
+     * request may fail again, and this case can only be distinguished if the
+     * called function can set a new error status. */
+    error_status = bus->error_status;
+    bus->error_status = 0;
+
+    if (error_status & BM_STATUS_DMA_RETRY) {
+        if (error_status & BM_STATUS_RETRY_TRIM) {
+            bmdma_restart_dma(bm, IDE_DMA_TRIM);
+        } else {
+            bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+        }
+    } else if (error_status & BM_STATUS_PIO_RETRY) {
         if (is_read) {
             ide_sector_read(bmdma_active_if(bm));
         } else {
             ide_sector_write(bmdma_active_if(bm));
         }
-    } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
+    } else if (error_status & BM_STATUS_RETRY_FLUSH) {
         ide_flush_cache(bmdma_active_if(bm));
     }
 }
 
-static void bmdma_restart_cb(void *opaque, int running, int reason)
+static void bmdma_restart_cb(void *opaque, int running, RunState state)
 {
     IDEDMA *dma = opaque;
     BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
@@ -273,9 +287,8 @@ static void bmdma_irq(void *opaque, int n, int level)
     qemu_set_irq(bm->irq, level);
 }
 
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
 {
-    BMDMAState *bm = opaque;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, val);
 #endif
@@ -297,12 +310,8 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
              */
             if (bm->bus->dma->aiocb) {
                 qemu_aio_flush();
-#ifdef DEBUG_IDE
-                if (bm->bus->dma->aiocb)
-                    printf("ide_dma_cancel: aiocb still pending");
-                if (bm->status & BM_STATUS_DMAING)
-                    printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
-#endif
+                assert(bm->bus->dma->aiocb == NULL);
+                assert((bm->status & BM_STATUS_DMAING) == 0);
             }
         } else {
             bm->cur_addr = bm->addr;
@@ -318,22 +327,24 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
     bm->cmd = val & 0x09;
 }
 
-static void bmdma_addr_read(IORange *ioport, uint64_t addr,
-                            unsigned width, uint64_t *data)
+static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
+                                unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     uint32_t mask = (1ULL << (width * 8)) - 1;
+    uint64_t data;
 
-    *data = (bm->addr >> (addr * 8)) & mask;
+    data = (bm->addr >> (addr * 8)) & mask;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, (unsigned)*data);
 #endif
+    return data;
 }
 
-static void bmdma_addr_write(IORange *ioport, uint64_t addr,
-                             unsigned width, uint64_t data)
+static void bmdma_addr_write(void *opaque, dma_addr_t addr,
+                             uint64_t data, unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     int shift = addr * 8;
     uint32_t mask = (1ULL << (width * 8)) - 1;
 
@@ -344,9 +355,10 @@ static void bmdma_addr_write(IORange *ioport, uint64_t addr,
     bm->addr |= ((data & mask) << shift) & ~3;
 }
 
-const IORangeOps bmdma_addr_ioport_ops = {
+MemoryRegionOps bmdma_addr_ioport_ops = {
     .read = bmdma_addr_read,
     .write = bmdma_addr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static bool ide_bmdma_current_needed(void *opaque)
@@ -356,6 +368,43 @@ static bool ide_bmdma_current_needed(void *opaque)
     return (bm->cur_prd_len != 0);
 }
 
+static bool ide_bmdma_status_needed(void *opaque)
+{
+    BMDMAState *bm = opaque;
+
+    /* Older versions abused some bits in the status register for internal
+     * error state. If any of these bits are set, we must add a subsection to
+     * transfer the real status register */
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    return ((bm->status & abused_bits) != 0);
+}
+
+static void ide_bmdma_pre_save(void *opaque)
+{
+    BMDMAState *bm = opaque;
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    bm->migration_compat_status =
+        (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
+}
+
+/* This function accesses bm->bus->error_status which is loaded only after
+ * BMDMA itself. This is why the function is called from ide_pci_post_load
+ * instead of being registered with VMState where it would run too early. */
+static int ide_bmdma_post_load(void *opaque, int version_id)
+{
+    BMDMAState *bm = opaque;
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    if (bm->status == 0) {
+        bm->status = bm->migration_compat_status & ~abused_bits;
+        bm->bus->error_status |= bm->migration_compat_status & abused_bits;
+    }
+
+    return 0;
+}
+
 static const VMStateDescription vmstate_bmdma_current = {
     .name = "ide bmdma_current",
     .version_id = 1,
@@ -370,15 +419,26 @@ static const VMStateDescription vmstate_bmdma_current = {
     }
 };
 
+const VMStateDescription vmstate_bmdma_status = {
+    .name ="ide bmdma/status",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(status, BMDMAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static const VMStateDescription vmstate_bmdma = {
     .name = "ide bmdma",
     .version_id = 3,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
+    .pre_save  = ide_bmdma_pre_save,
     .fields      = (VMStateField []) {
         VMSTATE_UINT8(cmd, BMDMAState),
-        VMSTATE_UINT8(status, BMDMAState),
+        VMSTATE_UINT8(migration_compat_status, BMDMAState),
         VMSTATE_UINT32(addr, BMDMAState),
         VMSTATE_INT64(sector_num, BMDMAState),
         VMSTATE_UINT32(nsector, BMDMAState),
@@ -389,6 +449,9 @@ static const VMStateDescription vmstate_bmdma = {
         {
             .vmsd = &vmstate_bmdma_current,
             .needed = ide_bmdma_current_needed,
+        }, {
+            .vmsd = &vmstate_bmdma_status,
+            .needed = ide_bmdma_status_needed,
         }, {
             /* empty */
         }
@@ -404,7 +467,9 @@ static int ide_pci_post_load(void *opaque, int version_id)
         /* current versions always store 0/1, but older version
            stored bigger values. We only need last bit */
         d->bmdma[i].unit &= 1;
+        ide_bmdma_post_load(&d->bmdma[i], -1);
     }
+
     return 0;
 }
 
@@ -451,7 +516,7 @@ static const struct IDEDMAOps bmdma_ops = {
     .reset = bmdma_reset,
 };
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm)
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
 {
     qemu_irq *irq;
 
@@ -464,4 +529,5 @@ void bmdma_init(IDEBus *bus, BMDMAState *bm)
     bm->irq = bus->irq;
     irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
     bus->irq = *irq;
+    bm->pci_dev = d;
 }
index cd72cbaeb963ea64bc59c2517304bad70be2d1c6..a694e546d7cda3951cd9bf8ea0143c78e7dd8acb 100644 (file)
@@ -19,16 +19,31 @@ typedef struct BMDMAState {
     BlockDriverCompletionFunc *dma_cb;
     int64_t sector_num;
     uint32_t nsector;
-    IORange addr_ioport;
+    MemoryRegion addr_ioport;
+    MemoryRegion extra_io;
     QEMUBH *bh;
     qemu_irq irq;
+
+    /* Bit 0-2 and 7:   BM status register
+     * Bit 3-6:         bus->error_status */
+    uint8_t migration_compat_status;
+    struct PCIIDEState *pci_dev;
 } BMDMAState;
 
+typedef struct CMD646BAR {
+    MemoryRegion cmd;
+    MemoryRegion data;
+    IDEBus *bus;
+    struct PCIIDEState *pci_dev;
+} CMD646BAR;
+
 typedef struct PCIIDEState {
     PCIDevice dev;
     IDEBus bus[2];
     BMDMAState bmdma[2];
     uint32_t secondary; /* used only for cmd646 */
+    MemoryRegion bmdma_bar;
+    CMD646BAR cmd646_bar[2]; /* used only for cmd646 */
 } PCIIDEState;
 
 
@@ -39,9 +54,9 @@ static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
 }
 
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm);
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
-extern const IORangeOps bmdma_addr_ioport_ops;
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
+extern MemoryRegionOps bmdma_addr_ioport_ops;
 void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
 
 extern const VMStateDescription vmstate_ide_pci;
index c3496448c3edcbfc7436a560b6b77377335d0890..08cbbe2032334370f868a5ae2a88dd10a9f7f135 100644 (file)
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -55,36 +58,46 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps piix_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "piix-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &piix_bmdma_ops, bm,
+                              "piix-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -109,8 +122,7 @@ static void piix3_reset(void *opaque)
 }
 
 static void pci_piix_init_ports(PCIIDEState *d) {
-    int i;
-    struct {
+    static const struct {
         int iobase;
         int iobase2;
         int isairq;
@@ -118,29 +130,32 @@ static void pci_piix_init_ports(PCIIDEState *d) {
         {0x1f0, 0x3f6, 14},
         {0x170, 0x376, 15},
     };
+    int i;
 
     for (i = 0; i < 2; i++) {
         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
-        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
+                        port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
     }
 }
 
-static int pci_piix_ide_initfn(PCIIDEState *d)
+static int pci_piix_ide_initfn(PCIDevice *dev)
 {
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
     uint8_t *pci_conf = d->dev.config;
 
     pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
 
     qemu_register_reset(piix3_reset, d);
 
-    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
@@ -149,22 +164,56 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
     return 0;
 }
 
-static int pci_piix3_ide_initfn(PCIDevice *dev)
+static int pci_piix3_xen_ide_unplug(DeviceState *dev)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    PCIDevice *pci_dev;
+    PCIIDEState *pci_ide;
+    DriveInfo *di;
+    int i = 0;
+
+    pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
+    pci_ide = DO_UPCAST(PCIIDEState, dev, pci_dev);
+
+    for (; i < 3; i++) {
+        di = drive_get_by_index(IF_IDE, i);
+        if (di != NULL && !di->media_cd) {
+            DeviceState *ds = bdrv_get_attached_dev(di->bdrv);
+            if (ds) {
+                bdrv_detach_dev(di->bdrv, ds);
+            }
+            bdrv_close(di->bdrv);
+            pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
+            drive_put_ref(di);
+        }
+    }
+    qdev_reset_all(&(pci_ide->dev.qdev));
+    return 0;
+}
 
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82371SB_1);
-    return pci_piix_ide_initfn(d);
+PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
+    dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
+    pci_ide_create_devs(dev, hd_table);
+    return dev;
 }
 
-static int pci_piix4_ide_initfn(PCIDevice *dev)
+static int pci_piix_ide_exitfn(PCIDevice *dev)
 {
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
 
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82371AB);
-    return pci_piix_ide_initfn(d);
+    return 0;
 }
 
 /* hd_table must contain 4 block drivers */
@@ -195,13 +244,29 @@ static PCIDeviceInfo piix_ide_info[] = {
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.no_user = 1,
         .no_hotplug   = 1,
-        .init         = pci_piix3_ide_initfn,
+        .init         = pci_piix_ide_initfn,
+        .exit         = pci_piix_ide_exitfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
+    },{
+        .qdev.name    = "piix3-ide-xen",
+        .qdev.size    = sizeof(PCIIDEState),
+        .qdev.no_user = 1,
+        .init         = pci_piix_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
     },{
         .qdev.name    = "piix4-ide",
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.no_user = 1,
         .no_hotplug   = 1,
-        .init         = pci_piix4_ide_initfn,
+        .init         = pci_piix_ide_initfn,
+        .exit         = pci_piix_ide_exitfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
     },{
         /* end of list */
     }
index 2bb5c27341130ae2712072e413bca0b10364f0ec..42071277bb34147ff931a2eeb360143b7cdad94b 100644 (file)
@@ -31,6 +31,10 @@ static struct BusInfo ide_bus_info = {
     .name  = "IDE",
     .size  = sizeof(IDEBus),
     .get_fw_dev_path = idebus_get_fw_dev_path,
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
 };
 
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
@@ -98,7 +102,7 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
 {
     DeviceState *dev;
 
-    dev = qdev_create(&bus->qbus, "ide-drive");
+    dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
     qdev_prop_set_uint32(dev, "unit", unit);
     qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
     qdev_init_nofail(dev);
@@ -118,13 +122,18 @@ typedef struct IDEDrive {
     IDEDevice dev;
 } IDEDrive;
 
-static int ide_drive_initfn(IDEDevice *dev)
+static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
 {
     IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
     IDEState *s = bus->ifs + dev->unit;
     const char *serial;
     DriveInfo *dinfo;
 
+    if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
+        error_report("discard_granularity must be 512 for ide");
+        return -1;
+    }
+
     serial = dev->serial;
     if (!serial) {
         /* try to fall back to value set with legacy -drive serial=... */
@@ -134,15 +143,15 @@ static int ide_drive_initfn(IDEDevice *dev)
         }
     }
 
-    if (ide_init_drive(s, dev->conf.bs, dev->version, serial) < 0) {
+    if (ide_init_drive(s, dev->conf.bs, kind, dev->version, serial) < 0) {
         return -1;
     }
 
     if (!dev->version) {
-        dev->version = qemu_strdup(s->version);
+        dev->version = g_strdup(s->version);
     }
     if (!dev->serial) {
-        dev->serial = qemu_strdup(s->drive_serial_str);
+        dev->serial = g_strdup(s->drive_serial_str);
     }
 
     add_boot_device_path(dev->conf.bootindex, &dev->qdev,
@@ -151,22 +160,68 @@ static int ide_drive_initfn(IDEDevice *dev)
     return 0;
 }
 
-static IDEDeviceInfo ide_drive_info = {
-    .qdev.name  = "ide-drive",
-    .qdev.fw_name  = "drive",
-    .qdev.size  = sizeof(IDEDrive),
-    .init       = ide_drive_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
-        DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),
-        DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),
-        DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial),
-        DEFINE_PROP_END_OF_LIST(),
+static int ide_hd_initfn(IDEDevice *dev)
+{
+    return ide_dev_initfn(dev, IDE_HD);
+}
+
+static int ide_cd_initfn(IDEDevice *dev)
+{
+    return ide_dev_initfn(dev, IDE_CD);
+}
+
+static int ide_drive_initfn(IDEDevice *dev)
+{
+    DriveInfo *dinfo = drive_get_by_blockdev(dev->conf.bs);
+
+    return ide_dev_initfn(dev, dinfo->media_cd ? IDE_CD : IDE_HD);
+}
+
+#define DEFINE_IDE_DEV_PROPERTIES()                     \
+    DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),        \
+    DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
+    DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial)
+
+static IDEDeviceInfo ide_dev_info[] = {
+    {
+        .qdev.name    = "ide-hd",
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE disk",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_hd_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "ide-cd",
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE CD-ROM",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_cd_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "ide-drive", /* legacy -device ide-drive */
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE disk or CD-ROM (legacy)",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_drive_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
     }
 };
 
-static void ide_drive_register(void)
+static void ide_dev_register(void)
 {
-    ide_qdev_register(&ide_drive_info);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
+        ide_qdev_register(&ide_dev_info[i]);
+    }
 }
-device_init(ide_drive_register);
+device_init(ide_dev_register);
index 04f3290960d398bff96fb24aba51d09b4f85fd3b..098f150bb2e991b011f9afc60a59f42529bd5a21 100644 (file)
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch (addr & 3) {
     case 0:
         val = bm->cmd;
@@ -56,13 +60,21 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch (addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
@@ -70,23 +82,25 @@ static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps via_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "via-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &via_bmdma_ops, bm,
+                              "via-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -132,8 +146,7 @@ static void via_reset(void *opaque)
 }
 
 static void vt82c686b_init_ports(PCIIDEState *d) {
-    int i;
-    struct {
+    static const struct {
         int iobase;
         int iobase2;
         int isairq;
@@ -141,13 +154,15 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
         {0x1f0, 0x3f6, 14},
         {0x170, 0x376, 15},
     };
+    int i;
 
     for (i = 0; i < 2; i++) {
         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
-        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
+                        port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -160,16 +175,12 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
     uint8_t *pci_conf = d->dev.config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE);
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
     pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
-    pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 
     qemu_register_reset(via_reset, d);
-    pci_register_bar(&d->dev, 4, 0x10,
-                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
@@ -178,6 +189,22 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int vt82c686b_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 {
     PCIDevice *dev;
@@ -191,6 +218,11 @@ static PCIDeviceInfo via_ide_info = {
     .qdev.size    = sizeof(PCIIDEState),
     .qdev.no_user = 1,
     .init         = vt82c686b_ide_initfn,
+    .exit         = vt82c686b_ide_exitfn,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_IDE,
+    .revision     = 0x06,
+    .class_id     = PCI_CLASS_STORAGE_IDE,
 };
 
 static void via_ide_register(void)
index b0499408213047c61628186ac69f784cfd26409d..9a289b47768e4d6d770438524b0715003490c961 100644 (file)
@@ -4,21 +4,23 @@
  * Copyright (c) 2005-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 
 #include "sysbus.h"
 #include "primecell.h"
 #include "devices.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "arm-misc.h"
 #include "net.h"
+#include "exec-memory.h"
+#include "sysemu.h"
 
 typedef struct {
     SysBusDevice busdev;
     uint32_t memsz;
-    uint32_t flash_offset;
+    MemoryRegion flash;
+    bool flash_mapped;
     uint32_t cm_osc;
     uint32_t cm_ctrl;
     uint32_t cm_lock;
@@ -109,9 +111,15 @@ static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
 static void integratorcm_do_remap(integratorcm_state *s, int flash)
 {
     if (flash) {
-        cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
+        if (s->flash_mapped) {
+            sysbus_del_memory(&s->busdev, &s->flash);
+            s->flash_mapped = false;
+        }
     } else {
-        cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
+        if (!s->flash_mapped) {
+            sysbus_add_memory_overlap(&s->busdev, 0, &s->flash, 1);
+            s->flash_mapped = true;
+        }
     }
     //??? tlb_flush (cpu_single_env, 1);
 }
@@ -119,15 +127,20 @@ static void integratorcm_do_remap(integratorcm_state *s, int flash)
 static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
 {
     if (value & 8) {
-        hw_error("Board reset\n");
+        qemu_system_reset_request();
     }
-    if ((s->cm_init ^ value) & 4) {
+    if ((s->cm_ctrl ^ value) & 4) {
         integratorcm_do_remap(s, (value & 4) == 0);
     }
-    if ((s->cm_init ^ value) & 1) {
-        printf("Green LED %s\n", (value & 1) ? "on" : "off");
+    if ((s->cm_ctrl ^ value) & 1) {
+        /* (value & 1) != 0 means the green "MISC LED" is lit.
+         * We don't have any nice place to display LEDs. printf is a bad
+         * idea because Linux uses the LED as a heartbeat and the output
+         * will swamp anything else on the terminal.
+         */
     }
-    s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
+    /* Note that the RESET bit [3] always reads as zero */
+    s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
 }
 
 static void integratorcm_update(integratorcm_state *s)
@@ -253,7 +266,8 @@ static int integratorcm_init(SysBusDevice *dev)
     }
     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
     s->cm_init = 0x00000112;
-    s->flash_offset = qemu_ram_alloc(NULL, "integrator.flash", 0x100000);
+    memory_region_init_ram(&s->flash, NULL, "integrator.flash", 0x100000);
+    s->flash_mapped = false;
 
     iomemtype = cpu_register_io_memory(integratorcm_readfn,
                                        integratorcm_writefn, s,
@@ -457,7 +471,9 @@ static void integratorcp_init(ram_addr_t ram_size,
                      const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
-    ram_addr_t ram_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
     qemu_irq pic[32];
     qemu_irq *cpu_pic;
     DeviceState *dev;
@@ -470,13 +486,14 @@ static void integratorcp_init(ram_addr_t ram_size,
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "integrator.ram", ram_size);
+    memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
     /* ??? RAM should repeat to fill physical memory space.  */
     /* SDRAM at address zero*/
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
     /* And again at address 0x80000000 */
-    cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
+    memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
 
     dev = qdev_create(NULL, "integrator_core");
     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
index b2b67082e7e2383e724c48830a064e5c805b35bd..10769e0f49829e844a052f4dae24e96405483824 100644 (file)
@@ -24,6 +24,7 @@
 #include "audiodev.h"
 #include "intel-hda.h"
 #include "intel-hda-defs.h"
+#include "dma.h"
 
 /* --------------------------------------------------------------------- */
 /* hda bus                                                               */
@@ -86,7 +87,7 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
-    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->cad == cad) {
             return cdev;
@@ -177,7 +178,7 @@ struct IntelHDAState {
     IntelHDAStream st[8];
 
     /* state */
-    int mmio_addr;
+    MemoryRegion mmio;
     uint32_t rirb_count;
     int64_t wall_base_ns;
 
@@ -224,19 +225,6 @@ static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase)
     return addr;
 }
 
-static void stl_phys_le(target_phys_addr_t addr, uint32_t value)
-{
-    uint32_t value_le = cpu_to_le32(value);
-    cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le));
-}
-
-static uint32_t ldl_phys_le(target_phys_addr_t addr)
-{
-    uint32_t value_le;
-    cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le));
-    return le32_to_cpu(value_le);
-}
-
 static void intel_hda_update_int_sts(IntelHDAState *d)
 {
     uint32_t sts = 0;
@@ -341,7 +329,7 @@ static void intel_hda_corb_run(IntelHDAState *d)
 
         rp = (d->corb_rp + 1) & 0xff;
         addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
-        verb = ldl_phys_le(addr + 4*rp);
+        verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
         d->corb_rp = rp;
 
         dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
@@ -373,8 +361,8 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res
     ex = (solicited ? 0 : (1 << 4)) | dev->cad;
     wp = (d->rirb_wp + 1) & 0xff;
     addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
-    stl_phys_le(addr + 8*wp, response);
-    stl_phys_le(addr + 8*wp + 4, ex);
+    stl_le_pci_dma(&d->pci, addr + 8*wp, response);
+    stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex);
     d->rirb_wp = wp;
 
     dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
@@ -402,18 +390,19 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
 {
     HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
     IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
-    IntelHDAStream *st = NULL;
     target_phys_addr_t addr;
     uint32_t s, copy, left;
+    IntelHDAStream *st;
     bool irq = false;
 
-    for (s = 0; s < ARRAY_SIZE(d->st); s++) {
-        if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
-            st = d->st + s;
+    st = output ? d->st + 4 : d->st;
+    for (s = 0; s < 4; s++) {
+        if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+            st = st + s;
             break;
         }
     }
-    if (st == NULL) {
+    if (s == 4) {
         return false;
     }
     if (st->bpl == NULL) {
@@ -438,8 +427,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
         dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
                st->be, st->bp, st->bpl[st->be].len, copy);
 
-        cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp,
-                               buf, copy, !output);
+        pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output);
         st->lpib += copy;
         st->bp += copy;
         buf += copy;
@@ -461,7 +449,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
     }
     if (d->dp_lbase & 0x01) {
         addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
-        stl_phys_le(addr + 8*s, st->lpib);
+        stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib);
     }
     dprint(d, 3, "dma: --\n");
 
@@ -480,10 +468,10 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
 
     addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
     st->bentries = st->lvi +1;
-    qemu_free(st->bpl);
-    st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+    g_free(st->bpl);
+    st->bpl = g_malloc(sizeof(bpl) * st->bentries);
     for (i = 0; i < st->bentries; i++, addr += 16) {
-        cpu_physical_memory_read(addr, buf, 16);
+        pci_dma_read(&d->pci, addr, buf, 16);
         st->bpl[i].addr  = le64_to_cpu(*(uint64_t *)buf);
         st->bpl[i].len   = le32_to_cpu(*(uint32_t *)(buf + 8));
         st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
@@ -497,15 +485,15 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
     st->bp    = 0;
 }
 
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
 {
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
-    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->info->stream) {
-            cdev->info->stream(cdev, stream, running);
+            cdev->info->stream(cdev, stream, running, output);
         }
     }
 }
@@ -579,6 +567,7 @@ static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t
 
 static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
 {
+    bool output = reg->stream >= 4;
     IntelHDAStream *st = d->st + reg->stream;
 
     if (st->ctl & 0x01) {
@@ -594,11 +583,11 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
             dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
                    reg->stream, stnr, st->cbl);
             intel_hda_parse_bdl(d, st);
-            intel_hda_notify_codecs(d, stnr, true);
+            intel_hda_notify_codecs(d, stnr, true, output);
         } else {
             /* stop */
             dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
-            intel_hda_notify_codecs(d, stnr, false);
+            intel_hda_notify_codecs(d, stnr, false, output);
         }
     }
     intel_hda_update_irq(d);
@@ -1097,26 +1086,22 @@ static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr)
     return intel_hda_reg_read(d, reg, 0xffffffff);
 }
 
-static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
-    intel_hda_mmio_readb,
-    intel_hda_mmio_readw,
-    intel_hda_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
-    intel_hda_mmio_writeb,
-    intel_hda_mmio_writew,
-    intel_hda_mmio_writel,
+static const MemoryRegionOps intel_hda_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            intel_hda_mmio_readb,
+            intel_hda_mmio_readw,
+            intel_hda_mmio_readl,
+        },
+        .write = {
+            intel_hda_mmio_writeb,
+            intel_hda_mmio_writew,
+            intel_hda_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void intel_hda_map(PCIDevice *pci, int region_num,
-                          pcibus_t addr, pcibus_t size, int type)
-{
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
-    cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
-}
-
 /* --------------------------------------------------------------------- */
 
 static void intel_hda_reset(DeviceState *dev)
@@ -1126,10 +1111,10 @@ static void intel_hda_reset(DeviceState *dev)
     HDACodecDevice *cdev;
 
     intel_hda_regs_reset(d);
-    d->wall_base_ns = qemu_get_clock(vm_clock);
+    d->wall_base_ns = qemu_get_clock_ns(vm_clock);
 
     /* reset codecs */
-    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (qdev->info->reset) {
             qdev->info->reset(qdev);
@@ -1146,20 +1131,14 @@ static int intel_hda_init(PCIDevice *pci)
 
     d->name = d->pci.qdev.info->name;
 
-    pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(conf, 0x2668);
-    pci_config_set_revision(conf, 1);
-    pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
     pci_config_set_interrupt_pin(conf, 1);
 
     /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
     conf[0x40] = 0x01;
 
-    d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
-                                          intel_hda_mmio_write, d,
-                                          DEVICE_NATIVE_ENDIAN);
-    pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     intel_hda_map);
+    memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
+                          "intel-hda", 0x4000);
+    pci_register_bar(&d->pci, 0, 0, &d->mmio);
     if (d->msi) {
         msi_init(&d->pci, 0x50, 1, true, false);
     }
@@ -1174,10 +1153,8 @@ static int intel_hda_exit(PCIDevice *pci)
 {
     IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
 
-    if (d->msi) {
-        msi_uninit(&d->pci);
-    }
-    cpu_unregister_io_memory(d->mmio_addr);
+    msi_uninit(&d->pci);
+    memory_region_destroy(&d->mmio);
     return 0;
 }
 
@@ -1276,6 +1253,10 @@ static PCIDeviceInfo intel_hda_info = {
     .init         = intel_hda_init,
     .exit         = intel_hda_exit,
     .config_write = intel_hda_write_config,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = 0x2668,
+    .revision     = 1,
+    .class_id     = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
     .qdev.props   = (Property[]) {
         DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
         DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
index 4e44e3894fb237da41e3f51e0ceef6abe347b402..65fd2a85bba6487aa8d413ce5ea20e7cc1f978c4 100644 (file)
@@ -34,7 +34,7 @@ struct HDACodecDeviceInfo {
     int (*init)(HDACodecDevice *dev);
     int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
-    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
index 569327d1e96fb6f83266e9b80480da6aee7ecf9d..61991d76797af0837e0a5249131be346cdd9b4e8 100644 (file)
@@ -104,7 +104,6 @@ static void ioapic_service(IOAPICState *s)
     uint64_t entry;
     uint8_t dest;
     uint8_t dest_mode;
-    uint8_t polarity;
 
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         mask = 1 << i;
@@ -116,7 +115,6 @@ static void ioapic_service(IOAPICState *s)
                 dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
                 delivery_mode =
                     (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
-                polarity = (entry >> IOAPIC_LVT_POLARITY_SHIFT) & 1;
                 if (trig_mode == IOAPIC_TRIGGER_EDGE) {
                     s->irr &= ~mask;
                 } else {
@@ -128,7 +126,7 @@ static void ioapic_service(IOAPICState *s)
                     vector = entry & IOAPIC_VECTOR_MASK;
                 }
                 apic_deliver_irq(dest, dest_mode, delivery_mode,
-                                 vector, polarity, trig_mode);
+                                 vector, trig_mode);
             }
         }
     }
@@ -150,6 +148,9 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
         uint32_t mask = 1 << vector;
         uint64_t entry = s->ioredtbl[vector];
 
+        if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
+            level = !level;
+        }
         if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
             IOAPIC_TRIGGER_LEVEL) {
             /* level triggered */
@@ -160,8 +161,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 cb2642ae534b64b0b4c3efb06b1d0a7e06773901..86e63dac74eaea29faf1d7b2447806d63b275f8a 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifndef HW_IOAPIC_H
+#define HW_IOAPIC_H
+
+#define IOAPIC_NUM_PINS 24
+
 void ioapic_eoi_broadcast(int vector);
+
+#endif /* !HW_IOAPIC_H */
index 95adf0978f9129abff8bf998a0b2b8c8783c1293..a6bfbb9173a47976d4905434fc4a48584ac2adaa 100644 (file)
@@ -104,12 +104,8 @@ static int ioh3420_initfn(PCIDevice *d)
         return rc;
     }
 
-    d->config[PCI_REVISION_ID] = PCI_DEVICE_ID_IOH_REV;
     pcie_port_init_reg(d);
 
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_IOH_EPORT);
-
     rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
                                IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
     if (rc < 0) {
@@ -217,6 +213,9 @@ static PCIDeviceInfo ioh3420_info = {
     .config_write = ioh3420_write_config,
     .init = ioh3420_initfn,
     .exit = ioh3420_exitfn,
+    .vendor_id = PCI_VENDOR_ID_INTEL,
+    .device_id = PCI_DEVICE_ID_IOH_EPORT,
+    .revision = PCI_DEVICE_ID_IOH_REV,
 
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
index 7703f62c6c486b7787985e4f17cc4c75cbef31f3..62f766eb6f14a67bd7f9a53609c66906ea3e7b9f 100644 (file)
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -44,8 +44,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
     struct IRQState *p;
     int i;
 
-    s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n);
-    p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n);
+    s = (qemu_irq *)g_malloc0(sizeof(qemu_irq) * n);
+    p = (struct IRQState *)g_malloc0(sizeof(struct IRQState) * n);
     for (i = 0; i < n; i++) {
         p->handler = handler;
         p->opaque = opaque;
@@ -58,8 +58,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
 
 void qemu_free_irqs(qemu_irq *s)
 {
-    qemu_free(s[0]);
-    qemu_free(s);
+    g_free(s[0]);
+    g_free(s);
 }
 
 static void qemu_notirq(void *opaque, int line, int level)
@@ -75,3 +75,32 @@ qemu_irq qemu_irq_invert(qemu_irq irq)
     qemu_irq_raise(irq);
     return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
 }
+
+static void qemu_splitirq(void *opaque, int line, int level)
+{
+    struct IRQState **irq = opaque;
+    irq[0]->handler(irq[0]->opaque, irq[0]->n, level);
+    irq[1]->handler(irq[1]->opaque, irq[1]->n, level);
+}
+
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
+{
+    qemu_irq *s = g_malloc0(2 * sizeof(qemu_irq));
+    s[0] = irq1;
+    s[1] = irq2;
+    return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
+}
+
+static void proxy_irq_handler(void *opaque, int n, int level)
+{
+    qemu_irq **target = opaque;
+
+    if (*target) {
+        qemu_set_irq((*target)[n], level);
+    }
+}
+
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
+{
+    return qemu_allocate_irqs(proxy_irq_handler, target, n);
+}
index 5daae449096a652739f8ff934c364ca5a7b4932d..64da2fd601763f02f8c6fdfa4354c7c5f1a3f270 100644 (file)
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -3,9 +3,7 @@
 
 /* Generic IRQ/GPIO pin infrastructure.  */
 
-/* FIXME: Rmove one of these.  */
 typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
-typedef void SetIRQFunc(void *opaque, int irq_num, int level);
 
 void qemu_set_irq(qemu_irq irq, int level);
 
@@ -32,4 +30,12 @@ void qemu_free_irqs(qemu_irq *s);
 /* Returns a new IRQ with opposite polarity.  */
 qemu_irq qemu_irq_invert(qemu_irq irq);
 
+/* Returns a new IRQ which feeds into both the passed IRQs */
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
+
+/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
+ * may be set later.
+ */
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
+
 #endif
index 9e33e71b9f2fafb3456d65a119a8767e037bbe8c..7c2c2619d013206a94a462ad71ec92ccd935a9a3 100644 (file)
  * 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"
+#include "exec-memory.h"
 
 struct ISABus {
     BusState qbus;
+    MemoryRegion *address_space_io;
     qemu_irq *irqs;
 };
 static ISABus *isabus;
@@ -39,7 +40,7 @@ static struct BusInfo isa_bus_info = {
     .get_fw_dev_path = isabus_get_fw_dev_path,
 };
 
-ISABus *isa_bus_new(DeviceState *dev)
+ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
 {
     if (isabus) {
         fprintf(stderr, "Can't create a second ISA bus\n");
@@ -51,6 +52,7 @@ ISABus *isa_bus_new(DeviceState *dev)
     }
 
     isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL));
+    isabus->address_space_io = address_space_io;
     return isabus;
 }
 
@@ -81,29 +83,32 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
     dev->nirqs++;
 }
 
-static void isa_init_ioport_one(ISADevice *dev, uint16_t ioport)
+static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
 {
-    assert(dev->nioports < ARRAY_SIZE(dev->ioports));
-    dev->ioports[dev->nioports++] = ioport;
+    if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
+        dev->ioport_id = ioport;
+    }
 }
 
-static int isa_cmp_ports(const void *p1, const void *p2)
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
 {
-    return *(uint16_t*)p1 - *(uint16_t*)p2;
+    memory_region_add_subregion(isabus->address_space_io, start, io);
+    isa_init_ioport(dev, start);
 }
 
-void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length)
+void isa_register_portio_list(ISADevice *dev, uint16_t start,
+                              const MemoryRegionPortio *pio_start,
+                              void *opaque, const char *name)
 {
-    int i;
-    for (i = start; i < start + length; i++) {
-        isa_init_ioport_one(dev, i);
-    }
-    qsort(dev->ioports, dev->nioports, sizeof(dev->ioports[0]), isa_cmp_ports);
-}
+    PortioList *piolist = g_new(PortioList, 1);
 
-void isa_init_ioport(ISADevice *dev, uint16_t ioport)
-{
-    isa_init_ioport_range(dev, ioport, 1);
+    /* START is how we should treat DEV, regardless of the actual
+       contents of the portio array.  This is how the old code
+       actually handled e.g. the FDC device.  */
+    isa_init_ioport(dev, start);
+
+    portio_list_init(piolist, pio_start, opaque, name);
+    portio_list_add(piolist, isabus->address_space_io, start);
 }
 
 static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
@@ -136,6 +141,18 @@ ISADevice *isa_create(const char *name)
     return DO_UPCAST(ISADevice, qdev, dev);
 }
 
+ISADevice *isa_try_create(const char *name)
+{
+    DeviceState *dev;
+
+    if (!isabus) {
+        hw_error("Tried to create isa device %s with no isa bus present.",
+                 name);
+    }
+    dev = qdev_try_create(&isabus->qbus, name);
+    return DO_UPCAST(ISADevice, qdev, dev);
+}
+
 ISADevice *isa_create_simple(const char *name)
 {
     ISADevice *dev;
@@ -184,11 +201,16 @@ static char *isabus_get_fw_dev_path(DeviceState *dev)
     int off;
 
     off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
-    if (d->nioports) {
-        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioports[0]);
+    if (d->ioport_id) {
+        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
     }
 
     return strdup(path);
 }
 
+MemoryRegion *isa_address_space(ISADevice *dev)
+{
+    return get_system_memory();
+}
+
 device_init(isabus_register_devices)
index f1335ff2d6f6191c2bc98effe99a6822797c571f..5eb9c78e9e7c853f0d2a2799bb21d02233ca654d 100644 (file)
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -4,8 +4,11 @@
 /* ISA bus */
 
 #include "ioport.h"
+#include "memory.h"
 #include "qdev.h"
 
+#define ISA_NUM_IRQS 16
+
 typedef struct ISABus ISABus;
 typedef struct ISADevice ISADevice;
 typedef struct ISADeviceInfo ISADeviceInfo;
@@ -14,8 +17,7 @@ struct ISADevice {
     DeviceState qdev;
     uint32_t isairq[2];
     int nirqs;
-    uint16_t ioports[32];
-    int nioports;
+    int ioport_id;
 };
 
 typedef int (*isa_qdev_initfn)(ISADevice *dev);
@@ -24,18 +26,49 @@ struct ISADeviceInfo {
     isa_qdev_initfn init;
 };
 
-ISABus *isa_bus_new(DeviceState *dev);
+ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
 void isa_bus_irqs(qemu_irq *irqs);
 qemu_irq isa_get_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
-void isa_init_ioport(ISADevice *dev, uint16_t ioport);
-void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
 void isa_qdev_register(ISADeviceInfo *info);
+MemoryRegion *isa_address_space(ISADevice *dev);
 ISADevice *isa_create(const char *name);
+ISADevice *isa_try_create(const char *name);
 ISADevice *isa_create_simple(const char *name);
 
+/**
+ * isa_register_ioport: Install an I/O port region on the ISA bus.
+ *
+ * Register an I/O port region via memory_region_add_subregion
+ * inside the ISA I/O address space.
+ *
+ * @dev: the ISADevice against which these are registered; may be NULL.
+ * @io: the #MemoryRegion being registered.
+ * @start: the base I/O port.
+ */
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start);
+
+/**
+ * isa_register_portio_list: Initialize a set of ISA io ports
+ *
+ * Several ISA devices have many dis-joint I/O ports.  Worse, these I/O
+ * ports can be interleaved with I/O ports from other devices.  This
+ * function makes it easy to create multiple MemoryRegions for a single
+ * device and use the legacy portio routines.
+ *
+ * @dev: the ISADevice against which these are registered; may be NULL.
+ * @start: the base I/O port against which the portio->offset is applied.
+ * @portio: the ports, sorted by offset.
+ * @opaque: passed into the old_portio callbacks.
+ * @name: passed into memory_region_init_io.
+ */
+void isa_register_portio_list(ISADevice *dev, uint16_t start,
+                              const MemoryRegionPortio *portio,
+                              void *opaque, const char *name);
+
 extern target_phys_addr_t isa_mem_base;
 
+void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size);
 void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size);
 
 /* dma.c */
index ca957fb0101d1e2dfd35ab2938d97d823bf0e109..fd755ab4a8853bd75567cefbbb595ea2d943eb9b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "hw.h"
 #include "isa.h"
+#include "exec-memory.h"
 
 static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
                                   uint32_t val)
@@ -58,25 +59,23 @@ static uint32_t isa_mmio_readl(void *opaque, target_phys_addr_t addr)
     return cpu_inl(addr & IOPORTS_MASK);
 }
 
-static CPUWriteMemoryFunc * const isa_mmio_write[] = {
-    &isa_mmio_writeb,
-    &isa_mmio_writew,
-    &isa_mmio_writel,
+static const MemoryRegionOps isa_mmio_ops = {
+    .old_mmio = {
+        .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel },
+        .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const isa_mmio_read[] = {
-    &isa_mmio_readb,
-    &isa_mmio_readw,
-    &isa_mmio_readl,
-};
+void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size)
+{
+    memory_region_init_io(mr, &isa_mmio_ops, NULL, "isa-mmio", size);
+}
 
 void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
 {
-    int isa_mmio_iomemtype;
+    MemoryRegion *mr = g_malloc(sizeof(*mr));
 
-    isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read,
-                                                isa_mmio_write,
-                                                NULL,
-                                                DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
+    isa_mmio_setup(mr, size);
+    memory_region_add_subregion(get_system_memory(), base, mr);
 }
index 7b19a81a47c9956f73bb132586b3d71825fce4a2..7b4dbf66a9c089709445d75980f71ecf1dc56d17 100644 (file)
@@ -18,6 +18,8 @@
 #include "pci.h"
 #include "msix.h"
 #include "kvm.h"
+#include "migration.h"
+#include "qerror.h"
 
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -56,11 +58,16 @@ typedef struct IVShmemState {
 
     CharDriverState **eventfd_chr;
     CharDriverState *server_chr;
-    int ivshmem_mmio_io_addr;
+    MemoryRegion ivshmem_mmio;
 
     pcibus_t mmio_addr;
-    pcibus_t shm_pci_addr;
-    uint64_t ivshmem_offset;
+    /* We might need to register the BAR before we actually have the memory.
+     * So prepare a container MemoryRegion for the BAR immediately and
+     * add a subregion when we have the memory.
+     */
+    MemoryRegion bar;
+    MemoryRegion ivshmem;
+    MemoryRegion msix_bar;
     uint64_t ivshmem_size; /* size of shared memory region */
     int shm_fd; /* shared memory file descriptor */
 
@@ -73,6 +80,8 @@ typedef struct IVShmemState {
     uint32_t features;
     EventfdEntry *eventfd_table;
 
+    Error *migration_blocker;
+
     char * shmobj;
     char * sizearg;
     char * role;
@@ -96,23 +105,6 @@ static inline bool is_power_of_two(uint64_t x) {
     return (x & (x - 1)) == 0;
 }
 
-static void ivshmem_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
-
-    s->shm_pci_addr = addr;
-
-    if (s->ivshmem_offset > 0) {
-        cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
-                                                            s->ivshmem_offset);
-    }
-
-    IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
-        PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
-
-}
-
 /* accessing registers - based on rtl8139 */
 static void ivshmem_update_irq(IVShmemState *s, int val)
 {
@@ -168,15 +160,8 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
     return ret;
 }
 
-static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
-                                                            uint32_t val)
-{
-
-    IVSHMEM_DPRINTF("We shouldn't be writing words\n");
-}
-
-static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
-                                                            uint32_t val)
+static void ivshmem_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     IVShmemState *s = opaque;
 
@@ -219,20 +204,8 @@ static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
-                                                                uint32_t val)
-{
-    IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
-}
-
-static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
-{
-
-    IVSHMEM_DPRINTF("We shouldn't be reading words\n");
-    return 0;
-}
-
-static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t ivshmem_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
 
     IVShmemState *s = opaque;
@@ -265,23 +238,14 @@ static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
-{
-    IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
-
-    return 0;
-}
-
-static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
-    ivshmem_io_readb,
-    ivshmem_io_readw,
-    ivshmem_io_readl,
-};
-
-static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
-    ivshmem_io_writeb,
-    ivshmem_io_writew,
-    ivshmem_io_writel,
+static const MemoryRegionOps ivshmem_mmio_ops = {
+    .read = ivshmem_io_read,
+    .write = ivshmem_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
@@ -371,12 +335,12 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
 
     ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 
-    s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
-                                                        s->ivshmem_size, ptr);
+    memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev, "ivshmem.bar2",
+                               s->ivshmem_size, ptr);
+    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
     /* region for shared memory */
-    pci_register_bar(&s->dev, 2, s->ivshmem_size,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 }
 
 static void close_guest_eventfds(IVShmemState *s, int posn)
@@ -391,7 +355,7 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
         close(s->peers[posn].eventfds[i]);
     }
 
-    qemu_free(s->peers[posn].eventfds);
+    g_free(s->peers[posn].eventfds);
     s->peers[posn].nb_eventfds = 0;
 }
 
@@ -401,8 +365,12 @@ static void setup_ioeventfds(IVShmemState *s) {
 
     for (i = 0; i <= s->max_peer; i++) {
         for (j = 0; j < s->peers[i].nb_eventfds; j++) {
-            kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
-                    s->mmio_addr + DOORBELL, (i << 16) | j, 1);
+            memory_region_add_eventfd(&s->ivshmem_mmio,
+                                      DOORBELL,
+                                      4,
+                                      true,
+                                      (i << 16) | j,
+                                      s->peers[i].eventfds[j]);
         }
     }
 }
@@ -419,7 +387,7 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
         s->nb_peers = s->nb_peers * 2;
 
     IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
-    s->peers = qemu_realloc(s->peers, s->nb_peers * sizeof(Peer));
+    s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
 
     /* zero out new pointers */
     for (j = old_nb_alloc; j < s->nb_peers; j++) {
@@ -437,7 +405,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
 
     memcpy(&incoming_posn, buf, sizeof(long));
     /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
-    tmp_fd = qemu_chr_get_msgfd(s->server_chr);
+    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
     IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
 
     /* make sure we have enough space for this guest */
@@ -483,18 +451,13 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
         /* mmap the region and map into the BAR2 */
         map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
                                                             incoming_fd, 0);
-        s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
-                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
+        memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev,
+                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
 
-        IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
-                         PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
+        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
                          s->ivshmem_offset, s->ivshmem_size);
 
-        if (s->shm_pci_addr > 0) {
-            /* map memory into BAR2 */
-            cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
-                                                            s->ivshmem_offset);
-        }
+        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
         /* only store the fd if it is successfully mapped */
         s->shm_fd = incoming_fd;
@@ -508,7 +471,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
 
     if (guest_max_eventfd == 0) {
         /* one eventfd per MSI vector */
-        s->peers[incoming_posn].eventfds = (int *) qemu_malloc(s->vectors *
+        s->peers[incoming_posn].eventfds = (int *) g_malloc(s->vectors *
                                                                 sizeof(int));
     }
 
@@ -549,20 +512,6 @@ static void ivshmem_reset(DeviceState *d)
     return;
 }
 
-static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
-
-    s->mmio_addr = addr;
-    cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
-                                                s->ivshmem_mmio_io_addr);
-
-    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
-        setup_ioeventfds(s);
-    }
-}
-
 static uint64_t ivshmem_get_size(IVShmemState * s) {
 
     uint64_t value;
@@ -596,11 +545,10 @@ static void ivshmem_setup_msi(IVShmemState * s) {
 
     /* allocate the MSI-X vectors */
 
-    if (!msix_init(&s->dev, s->vectors, 1, 0)) {
-        pci_register_bar(&s->dev, 1,
-                         msix_bar_size(&s->dev),
-                         PCI_BASE_ADDRESS_SPACE_MEMORY,
-                         msix_mmio_map);
+    memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
+    if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
+        pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         &s->msix_bar);
         IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
     } else {
         IVSHMEM_DPRINTF("msix initialization failed\n");
@@ -613,7 +561,7 @@ static void ivshmem_setup_msi(IVShmemState * s) {
     }
 
     /* allocate Qemu char devices for receiving interrupts */
-    s->eventfd_table = qemu_mallocz(s->vectors * sizeof(EventfdEntry));
+    s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
 }
 
 static void ivshmem_save(QEMUFile* f, void *opaque)
@@ -702,28 +650,29 @@ static int pci_ivshmem_init(PCIDevice *dev)
     }
 
     if (s->role_val == IVSHMEM_PEER) {
-        register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
+        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
+        migrate_add_blocker(s->migration_blocker);
     }
 
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET);
-    pci_conf[0x02] = 0x10;
-    pci_conf[0x03] = 0x11;
     pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-    pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM);
-    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
 
     pci_config_set_interrupt_pin(pci_conf, 1);
 
-    s->shm_pci_addr = 0;
-    s->ivshmem_offset = 0;
     s->shm_fd = 0;
 
-    s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
-                                    ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
+                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        setup_ioeventfds(s);
+    }
+
     /* region for registers*/
-    pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &s->ivshmem_mmio);
+
+    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
 
     if ((s->server_chr != NULL) &&
                         (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
@@ -747,12 +696,12 @@ static int pci_ivshmem_init(PCIDevice *dev)
         s->vm_id = -1;
 
         /* allocate/initialize space for interrupt handling */
-        s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
+        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
 
-        pci_register_bar(&s->dev, 2, s->ivshmem_size,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+        pci_register_bar(&s->dev, 2,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 
-        s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
+        s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
 
         qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
                      ivshmem_event, s);
@@ -797,7 +746,15 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
 {
     IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
 
-    cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+    if (s->migration_blocker) {
+        migrate_del_blocker(s->migration_blocker);
+        error_free(s->migration_blocker);
+    }
+
+    memory_region_destroy(&s->ivshmem_mmio);
+    memory_region_del_subregion(&s->bar, &s->ivshmem);
+    memory_region_destroy(&s->ivshmem);
+    memory_region_destroy(&s->bar);
     unregister_savevm(&dev->qdev, "ivshmem", s);
 
     return 0;
@@ -809,6 +766,9 @@ static PCIDeviceInfo ivshmem_info = {
     .qdev.reset = ivshmem_reset,
     .init       = pci_ivshmem_init,
     .exit       = pci_ivshmem_uninit,
+    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id  = 0x1110,
+    .class_id   = PCI_CLASS_MEMORY_RAM,
     .qdev.props = (Property[]) {
         DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
         DEFINE_PROP_STRING("size", IVShmemState, sizearg),
index 1dc22cf2e366ebca5b7bc40b30707cd7fc3f4d37..eb472a04c3e8a1b41db52424a7f4136cd39c9808 100644 (file)
@@ -312,7 +312,7 @@ void jazz_led_init(target_phys_addr_t base)
     LedState *s;
     int io;
 
-    s = qemu_mallocz(sizeof(LedState));
+    s = g_malloc0(sizeof(LedState));
 
     s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
 
diff --git a/hw/kvmclock.c b/hw/kvmclock.c
new file mode 100644 (file)
index 0000000..5388bc4
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "kvm.h"
+#include "kvmclock.h"
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+
+typedef struct KVMClockState {
+    SysBusDevice busdev;
+    uint64_t clock;
+    bool clock_valid;
+} KVMClockState;
+
+static void kvmclock_pre_save(void *opaque)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+    int ret;
+
+    if (s->clock_valid) {
+        return;
+    }
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+        data.clock = 0;
+    }
+    s->clock = data.clock;
+    /*
+     * If the VM is stopped, declare the clock state valid to avoid re-reading
+     * it on next vmsave (which would return a different value). Will be reset
+     * when the VM is continued.
+     */
+    s->clock_valid = !runstate_is_running();
+}
+
+static int kvmclock_post_load(void *opaque, int version_id)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+
+    data.clock = s->clock;
+    data.flags = 0;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
+}
+
+static void kvmclock_vm_state_change(void *opaque, int running,
+                                     RunState state)
+{
+    KVMClockState *s = opaque;
+
+    if (running) {
+        s->clock_valid = false;
+    }
+}
+
+static int kvmclock_init(SysBusDevice *dev)
+{
+    KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
+
+    qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
+    return 0;
+}
+
+static const VMStateDescription kvmclock_vmsd = {
+    .name = "kvmclock",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvmclock_pre_save,
+    .post_load = kvmclock_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(clock, KVMClockState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo kvmclock_info = {
+    .qdev.name = "kvmclock",
+    .qdev.size = sizeof(KVMClockState),
+    .qdev.vmsd = &kvmclock_vmsd,
+    .qdev.no_user = 1,
+    .init = kvmclock_init,
+};
+
+/* Note: Must be called after VCPU initialization. */
+void kvmclock_create(void)
+{
+    if (kvm_enabled() &&
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
+                                         (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
+        sysbus_create_simple("kvmclock", -1, NULL);
+    }
+}
+
+static void kvmclock_register_device(void)
+{
+    if (kvm_enabled()) {
+        sysbus_register_withprop(&kvmclock_info);
+    }
+}
+
+device_init(kvmclock_register_device);
diff --git a/hw/kvmclock.h b/hw/kvmclock.h
new file mode 100644 (file)
index 0000000..252ea13
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifdef CONFIG_KVM
+
+void kvmclock_create(void);
+
+#else /* CONFIG_KVM */
+
+static inline void kvmclock_create(void)
+{
+}
+
+#endif /* !CONFIG_KVM */
index 4ce9eb36948fdc53a2473069baba61bf0e68eda3..f8149e6983516f905eaafc7a2fcdd50ff9ea7683 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2009 CodeSourcery, LLC.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU GPL v2
+ * This code is licensed under the GNU GPL v2
  */
 
 #include "sysbus.h"
@@ -152,7 +152,7 @@ typedef struct {
     NICState *nic;
     NICConf conf;
     qemu_irq irq;
-    int mmio_index;
+    MemoryRegion mmio;
     ptimer_state *timer;
 
     uint32_t irq_cfg;
@@ -228,6 +228,12 @@ static void lan9118_update(lan9118_state *s)
     if ((s->irq_cfg & IRQ_EN) == 0) {
         level = 0;
     }
+    if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
+        /* Interrupt is active low unless we're configured as
+         * active-high polarity, push-pull type.
+         */
+        level = !level;
+    }
     qemu_set_irq(s->irq, level);
 }
 
@@ -294,8 +300,7 @@ static void phy_reset(lan9118_state *s)
 static void lan9118_reset(DeviceState *d)
 {
     lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d));
-
-    s->irq_cfg &= ~(IRQ_TYPE | IRQ_POL);
+    s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
     s->int_sts = 0;
     s->int_en = 0;
     s->fifo_int = 0x48000000;
@@ -327,7 +332,7 @@ static void lan9118_reset(DeviceState *d)
     s->afc_cfg = 0;
     s->e2p_cmd = 0;
     s->e2p_data = 0;
-    s->free_timer_start = qemu_get_clock(vm_clock) / 40;
+    s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40;
 
     ptimer_stop(s->timer);
     ptimer_set_count(s->timer, 0xffff);
@@ -721,7 +726,7 @@ static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
             break;
         }
         s->phy_control = val & 0x7980;
-        /* Complete autonegotiation imediately.  */
+        /* Complete autonegotiation immediately.  */
         if (val & 0x1000) {
             s->phy_status |= 0x0020;
         }
@@ -858,6 +863,7 @@ static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
         } else {
             DPRINTF("EEPROM Write All (ignored)\n");
         }
+        break;
     case 5: /* ERASE */
         if (s->eeprom_writable) {
             s->eeprom[addr] = 0xff;
@@ -890,7 +896,7 @@ static void lan9118_tick(void *opaque)
 }
 
 static void lan9118_writel(void *opaque, target_phys_addr_t offset,
-                           uint32_t val)
+                           uint64_t val, unsigned size)
 {
     lan9118_state *s = (lan9118_state *)opaque;
     offset &= 0xff;
@@ -904,7 +910,8 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
     switch (offset) {
     case CSR_IRQ_CFG:
         /* TODO: Implement interrupt deassertion intervals.  */
-        s->irq_cfg = (s->irq_cfg & IRQ_INT) | (val & IRQ_EN);
+        val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
+        s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
         break;
     case CSR_INT_STS:
         s->int_sts &= ~val;
@@ -1016,13 +1023,14 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
         break;
 
     default:
-        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, val);
+        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);
         break;
     }
     lan9118_update(s);
 }
 
-static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
+static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
+                              unsigned size)
 {
     lan9118_state *s = (lan9118_state *)opaque;
 
@@ -1076,7 +1084,7 @@ static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
     case CSR_WORD_SWAP:
         return s->word_swap;
     case CSR_FREE_RUN:
-        return (qemu_get_clock(vm_clock) / 40) - s->free_timer_start;
+        return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start;
     case CSR_RX_DROP:
         /* TODO: Implement dropped frames counter.  */
         return 0;
@@ -1095,16 +1103,10 @@ static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
     return 0;
 }
 
-static CPUReadMemoryFunc * const lan9118_readfn[] = {
-    lan9118_readl,
-    lan9118_readl,
-    lan9118_readl
-};
-
-static CPUWriteMemoryFunc * const lan9118_writefn[] = {
-    lan9118_writel,
-    lan9118_writel,
-    lan9118_writel
+static const MemoryRegionOps lan9118_mem_ops = {
+    .read = lan9118_readl,
+    .write = lan9118_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void lan9118_cleanup(VLANClientState *nc)
@@ -1129,10 +1131,8 @@ static int lan9118_init1(SysBusDevice *dev)
     QEMUBH *bh;
     int i;
 
-    s->mmio_index = cpu_register_io_memory(lan9118_readfn,
-                                           lan9118_writefn, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x100, s->mmio_index);
+    memory_region_init_io(&s->mmio, &lan9118_mem_ops, s, "lan9118-mmio", 0x100);
+    sysbus_init_mmio_region(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
index ddb1cbb7a42d6943ae5c5252ab076bea4eb6c9d3..93d5fda35b7231b41fec2e56ecfc41360430ca5a 100644 (file)
@@ -55,8 +55,8 @@ static void parent_lance_reset(void *opaque, int irq, int level)
         pcnet_h_reset(&d->state);
 }
 
-static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void lance_mem_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
 {
     SysBusPCNetState *d = opaque;
 
@@ -64,7 +64,8 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
     pcnet_ioport_writew(&d->state, addr, val & 0xffff);
 }
 
-static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
+static uint64_t lance_mem_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     SysBusPCNetState *d = opaque;
     uint32_t val;
@@ -74,16 +75,14 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
     return val & 0xffff;
 }
 
-static CPUReadMemoryFunc * const lance_mem_read[3] = {
-    NULL,
-    lance_mem_readw,
-    NULL,
-};
-
-static CPUWriteMemoryFunc * const lance_mem_write[3] = {
-    NULL,
-    lance_mem_writew,
-    NULL,
+static const MemoryRegionOps lance_mem_ops = {
+    .read = lance_mem_read,
+    .write = lance_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
 };
 
 static void lance_cleanup(VLANClientState *nc)
@@ -98,6 +97,7 @@ static NetClientInfo net_lance_info = {
     .size = sizeof(NICState),
     .can_receive = pcnet_can_receive,
     .receive = pcnet_receive,
+    .link_status_changed = pcnet_set_link_status,
     .cleanup = lance_cleanup,
 };
 
@@ -117,13 +117,11 @@ static int lance_init(SysBusDevice *dev)
     SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
     PCNetState *s = &d->state;
 
-    s->mmio_index =
-        cpu_register_io_memory(lance_mem_read, lance_mem_write, d,
-                               DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
 
     qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
-    sysbus_init_mmio(dev, 4, s->mmio_index);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     sysbus_init_irq(dev, &s->irq);
 
index 919f49fc1c1fbfce92fd16d1a00101b3300bcae3..607ec852fe65ebdbdceb448e72a84ceb12787131 100644 (file)
@@ -29,6 +29,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "trace.h"
+#include "exec-memory.h"
 
 #include "grlib.h"
 
@@ -100,7 +101,9 @@ static void leon3_generic_hw_init(ram_addr_t  ram_size,
                                   const char *cpu_model)
 {
     CPUState   *env;
-    ram_addr_t  ram_offset, prom_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *prom = g_new(MemoryRegion, 1);
     int         ret;
     char       *filename;
     qemu_irq   *cpu_irqs = NULL;
@@ -122,7 +125,7 @@ static void leon3_generic_hw_init(ram_addr_t  ram_size,
     cpu_sparc_set_id(env, 0);
 
     /* Reset data */
-    reset_info        = qemu_mallocz(sizeof(ResetData));
+    reset_info        = g_malloc0(sizeof(ResetData));
     reset_info->env   = env;
     qemu_register_reset(main_cpu_reset, reset_info);
 
@@ -139,14 +142,14 @@ static void leon3_generic_hw_init(ram_addr_t  ram_size,
         exit(1);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
-    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "leon3.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
 
     /* Allocate BIOS */
     prom_size = 8 * 1024 * 1024; /* 8Mb */
-    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
-    cpu_register_physical_memory(0x00000000, prom_size,
-                                 prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(prom, NULL, "Leon3.bios", prom_size);
+    memory_region_set_readonly(prom, true);
+    memory_region_add_subregion(address_space_mem, 0x00000000, prom);
 
     /* Load boot prom */
     if (bios_name == NULL) {
diff --git a/hw/lm32.h b/hw/lm32.h
new file mode 100644 (file)
index 0000000..0a67632
--- /dev/null
+++ b/hw/lm32.h
@@ -0,0 +1,25 @@
+
+#include "qemu-common.h"
+
+static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+
+    dev = qdev_create(NULL, "lm32-pic");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+    sysbus_connect_irq(d, 0, cpu_irq);
+
+    return dev;
+}
+
+static inline DeviceState *lm32_juart_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "lm32-juart");
+    qdev_init_nofail(dev);
+
+    return dev;
+}
diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c
new file mode 100644 (file)
index 0000000..97e1c00
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *  QEMU models for LatticeMico32 uclinux and evr32 boards.
+ *
+ *  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 "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "blockdev.h"
+#include "elf.h"
+#include "lm32_hwsetup.h"
+#include "lm32.h"
+#include "exec-memory.h"
+
+typedef struct {
+    CPUState *env;
+    target_phys_addr_t bootstrap_pc;
+    target_phys_addr_t flash_base;
+    target_phys_addr_t hwsetup_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 = (uint32_t)reset_info->bootstrap_pc;
+    env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
+    env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
+    env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
+    env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
+        reset_info->initrd_size);
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void lm32_evr_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;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_irq, irq[32];
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    target_phys_addr_t flash_base  = 0x04000000;
+    size_t flash_sector_size       = 256 * 1024;
+    size_t flash_size              = 32 * 1024 * 1024;
+    target_phys_addr_t ram_base    = 0x08000000;
+    size_t ram_size                = 64 * 1024 * 1024;
+    target_phys_addr_t timer0_base = 0x80002000;
+    target_phys_addr_t uart0_base  = 0x80006000;
+    target_phys_addr_t timer1_base = 0x8000a000;
+    int uart0_irq                  = 0;
+    int timer0_irq                 = 1;
+    int timer1_irq                 = 3;
+
+    reset_info = g_malloc0(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    memory_region_init_ram(phys_ram, NULL, "lm32_evr.sdram", ram_size);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 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);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        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, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static void lm32_uclinux_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;
+    DriveInfo *dinfo;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq *cpu_irq, irq[32];
+    HWSetup *hw;
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    target_phys_addr_t flash_base   = 0x04000000;
+    size_t flash_sector_size        = 256 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    target_phys_addr_t ram_base     = 0x08000000;
+    size_t ram_size                 = 64 * 1024 * 1024;
+    target_phys_addr_t uart0_base   = 0x80000000;
+    target_phys_addr_t timer0_base  = 0x80002000;
+    target_phys_addr_t timer1_base  = 0x80010000;
+    target_phys_addr_t timer2_base  = 0x80012000;
+    int uart0_irq                   = 0;
+    int timer0_irq                  = 1;
+    int timer1_irq                  = 20;
+    int timer2_irq                  = 21;
+    target_phys_addr_t hwsetup_base = 0x0bffe000;
+    target_phys_addr_t cmdline_base = 0x0bfff000;
+    target_phys_addr_t initrd_base  = 0x08400000;
+    size_t initrd_max               = 0x01000000;
+
+    reset_info = g_malloc0(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    memory_region_init_ram(phys_ram, NULL, "lm32_uclinux.sdram", ram_size);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 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);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+    sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        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, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* generate a rom with the hardware description */
+    hw = hwsetup_init();
+    hwsetup_add_cpu(hw, "LM32", 75000000);
+    hwsetup_add_flash(hw, "flash", flash_base, flash_size);
+    hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
+    hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
+    hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
+    hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
+    hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
+    hwsetup_add_trailer(hw);
+    hwsetup_create_rom(hw, hwsetup_base);
+    hwsetup_free(hw);
+
+    reset_info->hwsetup_base = hwsetup_base;
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = initrd_base;
+        reset_info->initrd_size = initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine lm32_evr_machine = {
+    .name = "lm32-evr",
+    .desc = "LatticeMico32 EVR32 eval system",
+    .init = lm32_evr_init,
+    .is_default = 1
+};
+
+static QEMUMachine lm32_uclinux_machine = {
+    .name = "lm32-uclinux",
+    .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems",
+    .init = lm32_uclinux_init,
+    .is_default = 0
+};
+
+static void lm32_machine_init(void)
+{
+    qemu_register_machine(&lm32_uclinux_machine);
+    qemu_register_machine(&lm32_evr_machine);
+}
+
+machine_init(lm32_machine_init);
diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h
new file mode 100644 (file)
index 0000000..8fc285e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  LatticeMico32 hwsetup helper functions.
+ *
+ *  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/>.
+ */
+
+/*
+ * These are helper functions for creating the hardware description blob used
+ * in the Theobroma's uClinux port.
+ */
+
+#ifndef QEMU_HW_LM32_HWSETUP_H
+#define QEMU_HW_LM32_HWSETUP_H
+
+#include "qemu-common.h"
+#include "loader.h"
+
+typedef struct {
+    void *data;
+    void *ptr;
+} HWSetup;
+
+enum hwsetup_tag {
+    HWSETUP_TAG_EOL         = 0,
+    HWSETUP_TAG_CPU         = 1,
+    HWSETUP_TAG_ASRAM       = 2,
+    HWSETUP_TAG_FLASH       = 3,
+    HWSETUP_TAG_SDRAM       = 4,
+    HWSETUP_TAG_OCM         = 5,
+    HWSETUP_TAG_DDR_SDRAM   = 6,
+    HWSETUP_TAG_DDR2_SDRAM  = 7,
+    HWSETUP_TAG_TIMER       = 8,
+    HWSETUP_TAG_UART        = 9,
+    HWSETUP_TAG_GPIO        = 10,
+    HWSETUP_TAG_TRISPEEDMAC = 11,
+    HWSETUP_TAG_I2CM        = 12,
+    HWSETUP_TAG_LEDS        = 13,
+    HWSETUP_TAG_7SEG        = 14,
+    HWSETUP_TAG_SPI_S       = 15,
+    HWSETUP_TAG_SPI_M       = 16,
+};
+
+static inline HWSetup *hwsetup_init(void)
+{
+    HWSetup *hw;
+
+    hw = g_malloc(sizeof(HWSetup));
+    hw->data = g_malloc0(TARGET_PAGE_SIZE);
+    hw->ptr = hw->data;
+
+    return hw;
+}
+
+static inline void hwsetup_free(HWSetup *hw)
+{
+    g_free(hw->data);
+    g_free(hw);
+}
+
+static inline void hwsetup_create_rom(HWSetup *hw,
+        target_phys_addr_t base)
+{
+    rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base);
+}
+
+static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
+{
+    stb_p(hw->ptr, u);
+    hw->ptr += 1;
+}
+
+static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
+{
+    stl_p(hw->ptr, u);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
+{
+    stl_p(hw->ptr, t);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_str(HWSetup *hw, const char *str)
+{
+    strncpy(hw->ptr, str, 31); /* make sure last byte is zero */
+    hw->ptr += 32;
+}
+
+static inline void hwsetup_add_trailer(HWSetup *hw)
+{
+    hwsetup_add_u32(hw, 8); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
+}
+
+static inline void hwsetup_add_cpu(HWSetup *hw,
+        const char *name, uint32_t frequency)
+{
+    hwsetup_add_u32(hw, 44); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, frequency);
+}
+
+static inline void hwsetup_add_flash(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 52); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+    hwsetup_add_u8(hw, 8); /* read latency */
+    hwsetup_add_u8(hw, 8); /* write latency */
+    hwsetup_add_u8(hw, 25); /* address width */
+    hwsetup_add_u8(hw, 32); /* data width */
+}
+
+static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 48); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+}
+
+static inline void hwsetup_add_timer(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u8(hw, 1); /* wr_tickcount */
+    hwsetup_add_u8(hw, 1); /* rd_tickcount */
+    hwsetup_add_u8(hw, 1); /* start_stop_control */
+    hwsetup_add_u8(hw, 32); /* counter_width */
+    hwsetup_add_u32(hw, 20); /* reload_ticks */
+    hwsetup_add_u8(hw, irq);
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+}
+
+static inline void hwsetup_add_uart(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_UART);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, 115200); /* baudrate */
+    hwsetup_add_u8(hw, 8); /* databits */
+    hwsetup_add_u8(hw, 1); /* stopbits */
+    hwsetup_add_u8(hw, 1); /* use_interrupt */
+    hwsetup_add_u8(hw, 1); /* block_on_transmit */
+    hwsetup_add_u8(hw, 1); /* block_on_receive */
+    hwsetup_add_u8(hw, 4); /* rx_buffer_size */
+    hwsetup_add_u8(hw, 4); /* tx_buffer_size */
+    hwsetup_add_u8(hw, irq);
+}
+
+#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
new file mode 100644 (file)
index 0000000..5454aa4
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  LatticeMico32 JTAG UART model.
+ *
+ *  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 "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+
+#include "lm32_juart.h"
+
+enum {
+    LM32_JUART_MIN_SAVE_VERSION = 0,
+    LM32_JUART_CURRENT_SAVE_VERSION = 0,
+    LM32_JUART_MAX_SAVE_VERSION = 0,
+};
+
+enum {
+    JTX_FULL = (1<<8),
+};
+
+enum {
+    JRX_FULL = (1<<8),
+};
+
+struct LM32JuartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+
+    uint32_t jtx;
+    uint32_t jrx;
+};
+typedef struct LM32JuartState LM32JuartState;
+
+uint32_t lm32_juart_get_jtx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jtx(s->jtx);
+    return s->jtx;
+}
+
+uint32_t lm32_juart_get_jrx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jrx(s->jrx);
+    return s->jrx;
+}
+
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+    unsigned char ch = jtx & 0xff;
+
+    trace_lm32_juart_set_jtx(s->jtx);
+
+    s->jtx = jtx;
+    if (s->chr) {
+        qemu_chr_fe_write(s->chr, &ch, 1);
+    }
+}
+
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_set_jrx(s->jrx);
+    s->jrx &= ~JRX_FULL;
+}
+
+static void juart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32JuartState *s = opaque;
+
+    s->jrx = *buf | JRX_FULL;
+}
+
+static int juart_can_rx(void *opaque)
+{
+    LM32JuartState *s = opaque;
+
+    return !(s->jrx & JRX_FULL);
+}
+
+static void juart_event(void *opaque, int event)
+{
+}
+
+static void juart_reset(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    s->jtx = 0;
+    s->jrx = 0;
+}
+
+static int lm32_juart_init(SysBusDevice *dev)
+{
+    LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_juart = {
+    .name = "lm32-juart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(jtx, LM32JuartState),
+        VMSTATE_UINT32(jrx, LM32JuartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_juart_info = {
+    .init = lm32_juart_init,
+    .qdev.name  = "lm32-juart",
+    .qdev.size  = sizeof(LM32JuartState),
+    .qdev.vmsd  = &vmstate_lm32_juart,
+    .qdev.reset = juart_reset,
+};
+
+static void lm32_juart_register(void)
+{
+    sysbus_register_withprop(&lm32_juart_info);
+}
+
+device_init(lm32_juart_register)
diff --git a/hw/lm32_juart.h b/hw/lm32_juart.h
new file mode 100644 (file)
index 0000000..67fc586
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef QEMU_HW_LM32_JUART_H
+#define QEMU_HW_LM32_JUART_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_juart_get_jtx(DeviceState *d);
+uint32_t lm32_juart_get_jrx(DeviceState *d);
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
+
+#endif /* QEMU_HW_LM32_JUART_H */
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
new file mode 100644 (file)
index 0000000..8dd0050
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  LatticeMico32 CPU interrupt controller logic.
+ *
+ *  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 <assert.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "lm32_pic.h"
+
+struct LM32PicState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+    uint32_t im;        /* interrupt mask */
+    uint32_t ip;        /* interrupt pending */
+    uint32_t irq_state;
+
+    /* statistics */
+    uint32_t stats_irq_count[32];
+};
+typedef struct LM32PicState LM32PicState;
+
+static LM32PicState *pic;
+void lm32_do_pic_info(Monitor *mon)
+{
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
+            pic->im, pic->ip, pic->irq_state);
+}
+
+void lm32_irq_info(Monitor *mon)
+{
+    int i;
+    uint32_t count;
+
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = pic->stats_irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %u\n", i, count);
+        }
+    }
+}
+
+static void update_irq(LM32PicState *s)
+{
+    s->ip |= s->irq_state;
+
+    if (s->ip & s->im) {
+        trace_lm32_pic_raise_irq();
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        trace_lm32_pic_lower_irq();
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    LM32PicState *s = opaque;
+
+    assert(irq < 32);
+    trace_lm32_pic_interrupt(irq, level);
+
+    if (level) {
+        s->irq_state |= (1 << irq);
+        s->stats_irq_count[irq]++;
+    } else {
+        s->irq_state &= ~(1 << irq);
+    }
+
+    update_irq(s);
+}
+
+void lm32_pic_set_im(DeviceState *d, uint32_t im)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_im(im);
+    s->im = im;
+
+    update_irq(s);
+}
+
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_ip(ip);
+
+    /* ack interrupt */
+    s->ip &= ~ip;
+
+    update_irq(s);
+}
+
+uint32_t lm32_pic_get_im(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_im(s->im);
+    return s->im;
+}
+
+uint32_t lm32_pic_get_ip(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_ip(s->ip);
+    return s->ip;
+}
+
+static void pic_reset(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+    int i;
+
+    s->im = 0;
+    s->ip = 0;
+    s->irq_state = 0;
+    for (i = 0; i < 32; i++) {
+        s->stats_irq_count[i] = 0;
+    }
+}
+
+static int lm32_pic_init(SysBusDevice *dev)
+{
+    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+
+    pic = s;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_pic = {
+    .name = "lm32-pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(im, LM32PicState),
+        VMSTATE_UINT32(ip, LM32PicState),
+        VMSTATE_UINT32(irq_state, LM32PicState),
+        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_pic_info = {
+    .init = lm32_pic_init,
+    .qdev.name  = "lm32-pic",
+    .qdev.size  = sizeof(LM32PicState),
+    .qdev.vmsd  = &vmstate_lm32_pic,
+    .qdev.reset = pic_reset,
+};
+
+static void lm32_pic_register(void)
+{
+    sysbus_register_withprop(&lm32_pic_info);
+}
+
+device_init(lm32_pic_register)
diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h
new file mode 100644 (file)
index 0000000..14456f3
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef QEMU_HW_LM32_PIC_H
+#define QEMU_HW_LM32_PIC_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_pic_get_ip(DeviceState *d);
+uint32_t lm32_pic_get_im(DeviceState *d);
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
+void lm32_pic_set_im(DeviceState *d, uint32_t im);
+
+void lm32_do_pic_info(Monitor *mon);
+void lm32_irq_info(Monitor *mon);
+
+#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
new file mode 100644 (file)
index 0000000..e5ff962
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  QEMU model of the LatticeMico32 system control 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/>.
+ */
+
+/*
+ * This model is mainly intended for testing purposes and doesn't fit to any
+ * real hardware. On the one hand it provides a control register (R_CTRL) on
+ * the other hand it supports the lm32 tests.
+ *
+ * A write to the control register causes a system shutdown.
+ * Tests first write the pointer to a test name to the test name register
+ * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
+ * the test is passed or any non-zero value to it if the test is failed.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "qemu-error.h"
+#include "sysemu.h"
+#include "qemu-log.h"
+
+enum {
+    R_CTRL = 0,
+    R_PASSFAIL,
+    R_TESTNAME,
+    R_MAX
+};
+
+#define MAX_TESTNAME_LEN 16
+
+struct LM32SysState {
+    SysBusDevice busdev;
+    uint32_t base;
+    uint32_t regs[R_MAX];
+    uint8_t testname[MAX_TESTNAME_LEN];
+};
+typedef struct LM32SysState LM32SysState;
+
+static void copy_testname(LM32SysState *s)
+{
+    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
+            MAX_TESTNAME_LEN);
+    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
+}
+
+static void sys_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32SysState *s = opaque;
+    char *testname;
+
+    trace_lm32_sys_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        qemu_system_shutdown_request();
+        break;
+    case R_PASSFAIL:
+        s->regs[addr] = value;
+        testname = (char *)s->testname;
+        qemu_log("TC  %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+        break;
+    case R_TESTNAME:
+        s->regs[addr] = value;
+        copy_testname(s);
+        break;
+
+    default:
+        error_report("lm32_sys: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sys_read_fn[] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const sys_write_fn[] = {
+    NULL,
+    NULL,
+    &sys_write,
+};
+
+static void sys_reset(DeviceState *d)
+{
+    LM32SysState *s = container_of(d, LM32SysState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->testname, 0, MAX_TESTNAME_LEN);
+}
+
+static int lm32_sys_init(SysBusDevice *dev)
+{
+    LM32SysState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sys_regs;
+
+    sys_regs = cpu_register_io_memory(sys_read_fn, sys_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sys_regs);
+
+    /* Note: This device is not created in the board initialization,
+     * instead it has to be added with the -device parameter. Therefore,
+     * the device maps itself. */
+    sysbus_mmio_map(dev, 0, s->base);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_sys = {
+    .name = "lm32-sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
+        VMSTATE_BUFFER(testname, LM32SysState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_sys_info = {
+    .init = lm32_sys_init,
+    .qdev.name  = "lm32-sys",
+    .qdev.size  = sizeof(LM32SysState),
+    .qdev.vmsd  = &vmstate_lm32_sys,
+    .qdev.reset = sys_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_sys_register(void)
+{
+    sysbus_register_withprop(&lm32_sys_info);
+}
+
+device_init(lm32_sys_register)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
new file mode 100644 (file)
index 0000000..49cbb22
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  QEMU model of the LatticeMico32 timer 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.latticesemi.com/documents/mico32timer.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-timer.h"
+#include "qemu-error.h"
+
+#define DEFAULT_FREQUENCY (50*1000000)
+
+enum {
+    R_SR = 0,
+    R_CR,
+    R_PERIOD,
+    R_SNAPSHOT,
+    R_MAX
+};
+
+enum {
+    SR_TO    = (1 << 0),
+    SR_RUN   = (1 << 1),
+};
+
+enum {
+    CR_ITO   = (1 << 0),
+    CR_CONT  = (1 << 1),
+    CR_START = (1 << 2),
+    CR_STOP  = (1 << 3),
+};
+
+struct LM32TimerState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    qemu_irq irq;
+    uint32_t freq_hz;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32TimerState LM32TimerState;
+
+static void timer_update_irq(LM32TimerState *s)
+{
+    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
+
+    trace_lm32_timer_irq_state(state);
+    qemu_set_irq(s->irq, state);
+}
+
+static uint32_t timer_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32TimerState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+    case R_CR:
+    case R_PERIOD:
+        r = s->regs[addr];
+        break;
+    case R_SNAPSHOT:
+        r = (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    default:
+        error_report("lm32_timer: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_timer_memory_read(addr << 2, r);
+    return r;
+}
+
+static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+        s->regs[R_SR] &= ~SR_TO;
+        break;
+    case R_CR:
+        s->regs[R_CR] = value;
+        if (s->regs[R_CR] & CR_START) {
+            ptimer_run(s->ptimer, 1);
+        }
+        if (s->regs[R_CR] & CR_STOP) {
+            ptimer_stop(s->ptimer);
+        }
+        break;
+    case R_PERIOD:
+        s->regs[R_PERIOD] = value;
+        ptimer_set_count(s->ptimer, value);
+        break;
+    case R_SNAPSHOT:
+        error_report("lm32_timer: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_timer: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    timer_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const timer_read_fn[] = {
+    NULL,
+    NULL,
+    &timer_read,
+};
+
+static CPUWriteMemoryFunc * const timer_write_fn[] = {
+    NULL,
+    NULL,
+    &timer_write,
+};
+
+static void timer_hit(void *opaque)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_hit();
+
+    s->regs[R_SR] |= SR_TO;
+
+    if (s->regs[R_CR] & CR_CONT) {
+        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
+        ptimer_run(s->ptimer, 1);
+    }
+    timer_update_irq(s);
+}
+
+static void timer_reset(DeviceState *d)
+{
+    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    ptimer_stop(s->ptimer);
+}
+
+static int lm32_timer_init(SysBusDevice *dev)
+{
+    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
+    int timer_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, s->freq_hz);
+
+    timer_regs = cpu_register_io_memory(timer_read_fn, timer_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, timer_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_timer = {
+    .name = "lm32-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, LM32TimerState),
+        VMSTATE_UINT32(freq_hz, LM32TimerState),
+        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_timer_info = {
+    .init = lm32_timer_init,
+    .qdev.name  = "lm32-timer",
+    .qdev.size  = sizeof(LM32TimerState),
+    .qdev.vmsd  = &vmstate_lm32_timer,
+    .qdev.reset = timer_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_timer_register(void)
+{
+    sysbus_register_withprop(&lm32_timer_info);
+}
+
+device_init(lm32_timer_register)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
new file mode 100644 (file)
index 0000000..3678545
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ *  QEMU model of the LatticeMico32 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.latticesemi.com/documents/mico32uart.pdf
+ */
+
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+#include "qemu-error.h"
+
+enum {
+    R_RXTX = 0,
+    R_IER,
+    R_IIR,
+    R_LCR,
+    R_MCR,
+    R_LSR,
+    R_MSR,
+    R_DIV,
+    R_MAX
+};
+
+enum {
+    IER_RBRI = (1<<0),
+    IER_THRI = (1<<1),
+    IER_RLSI = (1<<2),
+    IER_MSI  = (1<<3),
+};
+
+enum {
+    IIR_STAT = (1<<0),
+    IIR_ID0  = (1<<1),
+    IIR_ID1  = (1<<2),
+};
+
+enum {
+    LCR_WLS0 = (1<<0),
+    LCR_WLS1 = (1<<1),
+    LCR_STB  = (1<<2),
+    LCR_PEN  = (1<<3),
+    LCR_EPS  = (1<<4),
+    LCR_SP   = (1<<5),
+    LCR_SB   = (1<<6),
+};
+
+enum {
+    MCR_DTR  = (1<<0),
+    MCR_RTS  = (1<<1),
+};
+
+enum {
+    LSR_DR   = (1<<0),
+    LSR_OE   = (1<<1),
+    LSR_PE   = (1<<2),
+    LSR_FE   = (1<<3),
+    LSR_BI   = (1<<4),
+    LSR_THRE = (1<<5),
+    LSR_TEMT = (1<<6),
+};
+
+enum {
+    MSR_DCTS = (1<<0),
+    MSR_DDSR = (1<<1),
+    MSR_TERI = (1<<2),
+    MSR_DDCD = (1<<3),
+    MSR_CTS  = (1<<4),
+    MSR_DSR  = (1<<5),
+    MSR_RI   = (1<<6),
+    MSR_DCD  = (1<<7),
+};
+
+struct LM32UartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32UartState LM32UartState;
+
+static void uart_update_irq(LM32UartState *s)
+{
+    unsigned int irq;
+
+    if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
+            && (s->regs[R_IER] & IER_RLSI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
+    } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1;
+    } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID0;
+    } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
+        irq = 1;
+        s->regs[R_IIR] = 0;
+    } else {
+        irq = 0;
+        s->regs[R_IIR] = IIR_STAT;
+    }
+
+    trace_lm32_uart_irq_state(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32UartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[R_RXTX];
+        s->regs[R_LSR] &= ~LSR_DR;
+        uart_update_irq(s);
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        r = s->regs[addr];
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        error_report("lm32_uart: read access to write only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_uart_memory_read(addr << 2, r);
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32UartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_lm32_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_fe_write(s->chr, &ch, 1);
+        }
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        error_report("lm32_uart: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    uart_update_irq(s);
+}
+
+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)
+{
+    LM32UartState *s = opaque;
+
+    if (s->regs[R_LSR] & LSR_DR) {
+        s->regs[R_LSR] |= LSR_OE;
+    }
+
+    s->regs[R_LSR] |= LSR_DR;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    LM32UartState *s = opaque;
+
+    return !(s->regs[R_LSR] & LSR_DR);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void uart_reset(DeviceState *d)
+{
+    LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+}
+
+static int lm32_uart_init(SysBusDevice *dev)
+{
+    LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->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_lm32_uart = {
+    .name = "lm32-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_uart_info = {
+    .init = lm32_uart_init,
+    .qdev.name  = "lm32-uart",
+    .qdev.size  = sizeof(LM32UartState),
+    .qdev.vmsd  = &vmstate_lm32_uart,
+    .qdev.reset = uart_reset,
+};
+
+static void lm32_uart_register(void)
+{
+    sysbus_register_withprop(&lm32_uart_info);
+}
+
+device_init(lm32_uart_register)
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644 (file)
index 0000000..4d5b831
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include <stdio.h>
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+    LM4549_Reset                    = 0x00,
+    LM4549_Master_Volume            = 0x02,
+    LM4549_Line_Out_Volume          = 0x04,
+    LM4549_Master_Volume_Mono       = 0x06,
+    LM4549_PC_Beep_Volume           = 0x0A,
+    LM4549_Phone_Volume             = 0x0C,
+    LM4549_Mic_Volume               = 0x0E,
+    LM4549_Line_In_Volume           = 0x10,
+    LM4549_CD_Volume                = 0x12,
+    LM4549_Video_Volume             = 0x14,
+    LM4549_Aux_Volume               = 0x16,
+    LM4549_PCM_Out_Volume           = 0x18,
+    LM4549_Record_Select            = 0x1A,
+    LM4549_Record_Gain              = 0x1C,
+    LM4549_General_Purpose          = 0x20,
+    LM4549_3D_Control               = 0x22,
+    LM4549_Powerdown_Ctrl_Stat      = 0x26,
+    LM4549_Ext_Audio_ID             = 0x28,
+    LM4549_Ext_Audio_Stat_Ctrl      = 0x2A,
+    LM4549_PCM_Front_DAC_Rate       = 0x2C,
+    LM4549_PCM_ADC_Rate             = 0x32,
+    LM4549_Vendor_ID1               = 0x7C,
+    LM4549_Vendor_ID2               = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+    uint16_t *regfile = s->regfile;
+
+    regfile[LM4549_Reset]               = 0x0d50;
+    regfile[LM4549_Master_Volume]       = 0x8008;
+    regfile[LM4549_Line_Out_Volume]     = 0x8000;
+    regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+    regfile[LM4549_PC_Beep_Volume]      = 0x0000;
+    regfile[LM4549_Phone_Volume]        = 0x8008;
+    regfile[LM4549_Mic_Volume]          = 0x8008;
+    regfile[LM4549_Line_In_Volume]      = 0x8808;
+    regfile[LM4549_CD_Volume]           = 0x8808;
+    regfile[LM4549_Video_Volume]        = 0x8808;
+    regfile[LM4549_Aux_Volume]          = 0x8808;
+    regfile[LM4549_PCM_Out_Volume]      = 0x8808;
+    regfile[LM4549_Record_Select]       = 0x0000;
+    regfile[LM4549_Record_Gain]         = 0x8000;
+    regfile[LM4549_General_Purpose]     = 0x0000;
+    regfile[LM4549_3D_Control]          = 0x0101;
+    regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+    regfile[LM4549_Ext_Audio_ID]        = 0x0001;
+    regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
+    regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
+    regfile[LM4549_PCM_ADC_Rate]        = 0xbb80;
+    regfile[LM4549_Vendor_ID1]          = 0x4e53;
+    regfile[LM4549_Vendor_ID2]          = 0x4331;
+}
+
+static void lm4549_audio_transfer(lm4549_state *s)
+{
+    uint32_t written_bytes, written_samples;
+    uint32_t i;
+
+    /* Activate the voice */
+    AUD_set_active_out(s->voice, 1);
+    s->voice_is_active = 1;
+
+    /* Try to write the buffer content */
+    written_bytes = AUD_write(s->voice, s->buffer,
+                              s->buffer_level * sizeof(uint16_t));
+    written_samples = written_bytes >> 1;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
+#endif
+
+    s->buffer_level -= written_samples;
+
+    if (s->buffer_level > 0) {
+        /* Move the data back to the start of the buffer */
+        for (i = 0; i < s->buffer_level; i++) {
+            s->buffer[i] = s->buffer[i + written_samples];
+        }
+    }
+}
+
+static void lm4549_audio_out_callback(void *opaque, int free)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    static uint32_t prev_buffer_level;
+
+#ifdef LM4549_DEBUG
+    int size = AUD_get_buffer_size_out(s->voice);
+    DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
+#endif
+
+    /* Detect that no data are consumed
+       => disable the voice */
+    if (s->buffer_level == prev_buffer_level) {
+        AUD_set_active_out(s->voice, 0);
+        s->voice_is_active = 0;
+    }
+    prev_buffer_level = s->buffer_level;
+
+    /* Check if a buffer transfer is pending */
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        lm4549_audio_transfer(s);
+
+        /* Request more data */
+        if (s->data_req_cb != NULL) {
+            (s->data_req_cb)(s->opaque);
+        }
+    }
+}
+
+uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset)
+{
+    uint16_t *regfile = s->regfile;
+    uint32_t value = 0;
+
+    /* Read the stored value */
+    assert(offset < 128);
+    value = regfile[offset];
+
+    DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
+
+    return value;
+}
+
+void lm4549_write(lm4549_state *s,
+                  target_phys_addr_t offset, uint32_t value)
+{
+    uint16_t *regfile = s->regfile;
+
+    assert(offset < 128);
+    DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
+
+    switch (offset) {
+    case LM4549_Reset:
+        lm4549_reset(s);
+        break;
+
+    case LM4549_PCM_Front_DAC_Rate:
+        regfile[LM4549_PCM_Front_DAC_Rate] = value;
+        DPRINTF("DAC rate change = %i\n", value);
+
+        /* Re-open a voice with the new sample rate */
+        struct audsettings as;
+        as.freq = value;
+        as.nchannels = 2;
+        as.fmt = AUD_FMT_S16;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out(
+            &s->card,
+            s->voice,
+            "lm4549.out",
+            s,
+            lm4549_audio_out_callback,
+            &as
+        );
+        break;
+
+    case LM4549_Powerdown_Ctrl_Stat:
+        value &= ~0xf;
+        value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
+        regfile[LM4549_Powerdown_Ctrl_Stat] = value;
+        break;
+
+    case LM4549_Ext_Audio_ID:
+    case LM4549_Vendor_ID1:
+    case LM4549_Vendor_ID2:
+        DPRINTF("Write to read-only register 0x%x\n", (int)offset);
+        break;
+
+    default:
+        /* Store the new value */
+        regfile[offset] = value;
+        break;
+    }
+}
+
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
+{
+    /* The left and right samples are in 20-bit resolution.
+       The LM4549 has 18-bit resolution and only uses the bits [19:2].
+       This model supports 16-bit playback.
+    */
+
+    if (s->buffer_level >= LM4549_BUFFER_SIZE) {
+        DPRINTF("write_sample Buffer full\n");
+        return 0;
+    }
+
+    /* Store 16-bit samples in the buffer */
+    s->buffer[s->buffer_level++] = (left >> 4);
+    s->buffer[s->buffer_level++] = (right >> 4);
+
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        /* Trigger the transfer of the buffer to the audio host */
+        lm4549_audio_transfer(s);
+    }
+
+    return 1;
+}
+
+static int lm4549_post_load(void *opaque, int version_id)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    uint16_t *regfile = s->regfile;
+
+    /* Re-open a voice with the current sample rate */
+    uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate];
+
+    DPRINTF("post_load freq = %i\n", freq);
+    DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
+
+    struct audsettings as;
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    /* Request data */
+    if (s->voice_is_active == 1) {
+        lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice));
+    }
+
+    return 0;
+}
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
+{
+    struct audsettings as;
+
+    /* Store the callback and opaque pointer */
+    s->data_req_cb = data_req_cb;
+    s->opaque = opaque;
+
+    /* Init the registers */
+    lm4549_reset(s);
+
+    /* Register an audio card */
+    AUD_register_card("lm4549", &s->card);
+
+    /* Open a default voice */
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    AUD_set_volume_out(s->voice, 0, 255, 255);
+
+    s->voice_is_active = 0;
+
+    /* Reset the input buffer */
+    memset(s->buffer, 0x00, sizeof(s->buffer));
+    s->buffer_level = 0;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fp_dac_input = fopen("lm4549_dac_input.pcm", "wb");
+    if (!fp_dac_input) {
+        hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
+    }
+#endif
+}
+
+const VMStateDescription vmstate_lm4549_state = {
+    .name = "lm4549_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = &lm4549_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(voice_is_active, lm4549_state),
+        VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
+        VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
+        VMSTATE_UINT32(buffer_level, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/hw/lm4549.h b/hw/lm4549.h
new file mode 100644 (file)
index 0000000..70d0ac1
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_LM4549_H
+#define HW_LM4549_H
+
+#include "audio/audio.h"
+
+typedef void (*lm4549_callback)(void *opaque);
+
+#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */
+
+
+typedef struct {
+    QEMUSoundCard card;
+    SWVoiceOut *voice;
+    uint32_t voice_is_active;
+
+    uint16_t regfile[128];
+    lm4549_callback data_req_cb;
+    void *opaque;
+
+    uint16_t buffer[LM4549_BUFFER_SIZE];
+    uint32_t buffer_level;
+} lm4549_state;
+
+extern const VMStateDescription vmstate_lm4549_state;
+
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque);
+uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset);
+void lm4549_write(lm4549_state *s, target_phys_addr_t offset, uint32_t value);
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right);
+
+#endif /* #ifndef HW_LM4549_H */
index ce7dcac6885897eeed2692a737d9217ba751cf42..992ce49729d3d1f93510e2bf5a9ea134654a2cd3 100644 (file)
@@ -463,9 +463,9 @@ static int lm8323_init(i2c_slave *i2c)
     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 
     s->model = 0x8323;
-    s->pwm.tm[0] = qemu_new_timer(vm_clock, lm_kbd_pwm0_tick, s);
-    s->pwm.tm[1] = qemu_new_timer(vm_clock, lm_kbd_pwm1_tick, s);
-    s->pwm.tm[2] = qemu_new_timer(vm_clock, lm_kbd_pwm2_tick, s);
+    s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s);
+    s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s);
+    s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s);
     qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1);
 
     lm_kbd_reset(s);
@@ -474,9 +474,9 @@ static int lm8323_init(i2c_slave *i2c)
     return 0;
 }
 
-void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
+void lm832x_key_event(DeviceState *dev, int key, int state)
 {
-    LM823KbdState *s = (LM823KbdState *) i2c;
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE_FROM_QDEV(dev));
 
     if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
         return;
index 35d792e6477a1aa6ed3319208b35f7be8df34e19..9bbcddd424b9b21558864cc2e444af88c6ef815f 100644 (file)
@@ -85,17 +85,17 @@ int load_image(const char *filename, uint8_t *addr)
 }
 
 /* read()-like version */
-int read_targphys(const char *name,
-                  int fd, target_phys_addr_t dst_addr, size_t nbytes)
+ssize_t read_targphys(const char *name,
+                      int fd, target_phys_addr_t dst_addr, size_t nbytes)
 {
     uint8_t *buf;
-    size_t did;
+    ssize_t did;
 
-    buf = qemu_malloc(nbytes);
+    buf = g_malloc(nbytes);
     did = read(fd, buf, nbytes);
     if (did > 0)
         rom_add_blob_fixed("read", buf, did, dst_addr);
-    qemu_free(buf);
+    g_free(buf);
     return did;
 }
 
@@ -176,7 +176,8 @@ static void bswap_ahdr(struct exec *e)
 int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
               int bswap_needed, target_phys_addr_t target_page_size)
 {
-    int fd, size, ret;
+    int fd;
+    ssize_t size, ret;
     struct exec e;
     uint32_t magic;
 
@@ -234,9 +235,9 @@ static void *load_at(int fd, int offset, int size)
     void *ptr;
     if (lseek(fd, offset, SEEK_SET) < 0)
         return NULL;
-    ptr = qemu_malloc(size);
+    ptr = g_malloc(size);
     if (read(fd, ptr, size) != size) {
-        qemu_free(ptr);
+        g_free(ptr);
         return NULL;
     }
     return ptr;
@@ -351,14 +352,14 @@ static void *zalloc(void *x, unsigned items, unsigned size)
     size *= items;
     size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
 
-    p = qemu_malloc(size);
+    p = g_malloc(size);
 
     return (p);
 }
 
 static void zfree(void *x, void *addr)
 {
-    qemu_free(addr);
+    g_free(addr);
 }
 
 
@@ -476,7 +477,7 @@ int load_uimage(const char *filename, target_phys_addr_t *ep,
     }
 
     *ep = hdr->ih_ep;
-    data = qemu_malloc(hdr->ih_size);
+    data = g_malloc(hdr->ih_size);
 
     if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
         fprintf(stderr, "Error reading file\n");
@@ -490,10 +491,10 @@ int load_uimage(const char *filename, target_phys_addr_t *ep,
 
         compressed_data = data;
         max_bytes = UBOOT_MAX_GUNZIP_BYTES;
-        data = qemu_malloc(max_bytes);
+        data = g_malloc(max_bytes);
 
         bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
-        qemu_free(compressed_data);
+        g_free(compressed_data);
         if (bytes < 0) {
             fprintf(stderr, "Unable to decompress gzipped image!\n");
             goto out;
@@ -510,7 +511,7 @@ int load_uimage(const char *filename, target_phys_addr_t *ep,
 
 out:
     if (data)
-        qemu_free(data);
+        g_free(data);
     close(fd);
     return ret;
 }
@@ -564,11 +565,11 @@ int rom_add_file(const char *file, const char *fw_dir,
     int rc, fd = -1;
     char devpath[100];
 
-    rom = qemu_mallocz(sizeof(*rom));
-    rom->name = qemu_strdup(file);
+    rom = g_malloc0(sizeof(*rom));
+    rom->name = g_strdup(file);
     rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
     if (rom->path == NULL) {
-        rom->path = qemu_strdup(file);
+        rom->path = g_strdup(file);
     }
 
     fd = open(rom->path, O_RDONLY | O_BINARY);
@@ -579,12 +580,12 @@ int rom_add_file(const char *file, const char *fw_dir,
     }
 
     if (fw_dir) {
-        rom->fw_dir  = qemu_strdup(fw_dir);
-        rom->fw_file = qemu_strdup(file);
+        rom->fw_dir  = g_strdup(fw_dir);
+        rom->fw_file = g_strdup(file);
     }
     rom->addr    = addr;
     rom->romsize = lseek(fd, 0, SEEK_END);
-    rom->data    = qemu_mallocz(rom->romsize);
+    rom->data    = g_malloc0(rom->romsize);
     lseek(fd, 0, SEEK_SET);
     rc = read(fd, rom->data, rom->romsize);
     if (rc != rom->romsize) {
@@ -618,10 +619,10 @@ int rom_add_file(const char *file, const char *fw_dir,
 err:
     if (fd != -1)
         close(fd);
-    qemu_free(rom->data);
-    qemu_free(rom->path);
-    qemu_free(rom->name);
-    qemu_free(rom);
+    g_free(rom->data);
+    g_free(rom->path);
+    g_free(rom->name);
+    g_free(rom);
     return -1;
 }
 
@@ -630,11 +631,11 @@ int rom_add_blob(const char *name, const void *blob, size_t len,
 {
     Rom *rom;
 
-    rom = qemu_mallocz(sizeof(*rom));
-    rom->name    = qemu_strdup(name);
+    rom = g_malloc0(sizeof(*rom));
+    rom->name    = g_strdup(name);
     rom->addr    = addr;
     rom->romsize = len;
-    rom->data    = qemu_mallocz(rom->romsize);
+    rom->data    = g_malloc0(rom->romsize);
     memcpy(rom->data, blob, len);
     rom_insert(rom);
     return 0;
@@ -664,7 +665,7 @@ static void rom_reset(void *unused)
         cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
         if (rom->isrom) {
             /* rom needs to be written only once */
-            qemu_free(rom->data);
+            g_free(rom->data);
             rom->data = NULL;
         }
     }
@@ -779,13 +780,13 @@ void do_info_roms(Monitor *mon)
     QTAILQ_FOREACH(rom, &roms, next) {
         if (!rom->fw_file) {
             monitor_printf(mon, "addr=" TARGET_FMT_plx
-                           " size=0x%06zx mem=%s name=\"%s\" \n",
+                           " size=0x%06zx mem=%s name=\"%s\"\n",
                            rom->addr, rom->romsize,
                            rom->isrom ? "rom" : "ram",
                            rom->name);
         } else {
             monitor_printf(mon, "fw=%s/%s"
-                           " size=0x%06zx name=\"%s\" \n",
+                           " size=0x%06zx name=\"%s\"\n",
                            rom->fw_dir,
                            rom->fw_file,
                            rom->romsize,
index fc6bdff6bb303f44e0a441bbd0c645281cfacce5..fbcaba9f0c05417817538fcc5a60de011ae5d37b 100644 (file)
@@ -14,8 +14,8 @@ int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
 int load_uimage(const char *filename, target_phys_addr_t *ep,
                 target_phys_addr_t *loadaddr, int *is_linux);
 
-int read_targphys(const char *name,
-                  int fd, target_phys_addr_t dst_addr, size_t nbytes);
+ssize_t read_targphys(const char *name,
+                      int fd, target_phys_addr_t dst_addr, size_t nbytes);
 void pstrcpy_targphys(const char *name,
                       target_phys_addr_t dest, int buf_size,
                       const char *source);
index e4b51a8eaf25291492974a0160d49da97de8c5e0..fcc27d726f26dfdc2a63a4f863b279d3f75d96ba 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 /* ??? Need to check if the {read,write}[wl] routines work properly on
@@ -16,6 +16,7 @@
 #include "pci.h"
 #include "scsi.h"
 #include "block_int.h"
+#include "dma.h"
 
 //#define DEBUG_LSI
 //#define DEBUG_LSI_REG
@@ -174,6 +175,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
 #define LSI_TAG_VALID     (1 << 16)
 
 typedef struct lsi_request {
+    SCSIRequest *req;
     uint32_t tag;
     uint32_t dma_len;
     uint8_t *dma_buf;
@@ -184,12 +186,12 @@ typedef struct lsi_request {
 
 typedef struct {
     PCIDevice dev;
-    int mmio_io_addr;
-    int ram_io_addr;
-    uint32_t script_ram_base;
+    MemoryRegion mmio_io;
+    MemoryRegion ram_io;
+    MemoryRegion io_io;
 
     int carry; /* ??? Should this be an a visible register somewhere?  */
-    int sense;
+    int status;
     /* Action to take at the end of a MSG IN phase.
        0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN.  */
     int msg_action;
@@ -352,10 +354,10 @@ static void lsi_soft_reset(LSIState *s)
     while (!QTAILQ_EMPTY(&s->queue)) {
         p = QTAILQ_FIRST(&s->queue);
         QTAILQ_REMOVE(&s->queue, p, next);
-        qemu_free(p);
+        g_free(p);
     }
     if (s->current) {
-        qemu_free(s->current);
+        g_free(s->current);
         s->current = NULL;
     }
 }
@@ -390,11 +392,7 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr)
 {
     uint32_t buf;
 
-    /* Optimize reading from SCRIPTS RAM.  */
-    if ((addr & 0xffffe000) == s->script_ram_base) {
-        return s->script_ram[(addr & 0x1fff) >> 2];
-    }
-    cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
+    pci_dma_read(&s->dev, addr, (uint8_t *)&buf, 4);
     return cpu_to_le32(buf);
 }
 
@@ -532,8 +530,8 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
 /* Initiate a SCSI layer data transfer.  */
 static void lsi_do_dma(LSIState *s, int out)
 {
-    uint32_t count, id;
-    target_phys_addr_t addr;
+    uint32_t count;
+    dma_addr_t addr;
     SCSIDevice *dev;
 
     assert(s->current);
@@ -543,12 +541,8 @@ static void lsi_do_dma(LSIState *s, int out)
         return;
     }
 
-    id = (s->current->tag >> 8) & 0xf;
-    dev = s->bus.devs[id];
-    if (!dev) {
-        lsi_bad_selection(s, id);
-        return;
-    }
+    dev = s->current->req->dev;
+    assert(dev);
 
     count = s->dbc;
     if (count > s->current->dma_len)
@@ -563,31 +557,23 @@ static void lsi_do_dma(LSIState *s, int out)
     else if (s->sbms)
         addr |= ((uint64_t)s->sbms << 32);
 
-    DPRINTF("DMA addr=0x" TARGET_FMT_plx " len=%d\n", addr, count);
+    DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
     s->csbc += count;
     s->dnad += count;
     s->dbc -= count;
-
-    if (s->current->dma_buf == NULL) {
-        s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
+     if (s->current->dma_buf == NULL) {
+        s->current->dma_buf = scsi_req_get_buf(s->current->req);
     }
-
     /* ??? Set SFBR to first data byte.  */
     if (out) {
-        cpu_physical_memory_read(addr, s->current->dma_buf, count);
+        pci_dma_read(&s->dev, addr, s->current->dma_buf, count);
     } else {
-        cpu_physical_memory_write(addr, s->current->dma_buf, count);
+        pci_dma_write(&s->dev, addr, s->current->dma_buf, count);
     }
     s->current->dma_len -= count;
     if (s->current->dma_len == 0) {
         s->current->dma_buf = NULL;
-        if (out) {
-            /* Write the data.  */
-            dev->info->write_data(dev, s->current->tag);
-        } else {
-            /* Request any remaining data.  */
-            dev->info->read_data(dev, s->current->tag);
-        }
+        scsi_req_continue(s->current->req);
     } else {
         s->current->dma_buf += count;
         lsi_resume_script(s);
@@ -652,82 +638,116 @@ static void lsi_reselect(LSIState *s, lsi_request *p)
     }
 }
 
-/* Record that data is available for a queued command.  Returns zero if
-   the device was reselected, nonzero if the IO is deferred.  */
-static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
+static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
 {
     lsi_request *p;
 
     QTAILQ_FOREACH(p, &s->queue, next) {
         if (p->tag == tag) {
-            if (p->pending) {
-                BADF("Multiple IO pending for tag %d\n", tag);
-            }
-            p->pending = arg;
-            /* Reselect if waiting for it, or if reselection triggers an IRQ
-               and the bus is free.
-               Since no interrupt stacking is implemented in the emulation, it
-               is also required that there are no pending interrupts waiting
-               for service from the device driver. */
-            if (s->waiting == 1 ||
-                (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
-                 !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
-                /* Reselect device.  */
-                lsi_reselect(s, p);
-                return 0;
-            } else {
-                DPRINTF("Queueing IO tag=0x%x\n", tag);
-                p->pending = arg;
-                return 1;
-            }
+            return p;
         }
     }
-    BADF("IO with unknown tag %d\n", tag);
-    return 1;
+
+    return NULL;
 }
 
-/* Callback to indicate that the SCSI layer has completed a transfer.  */
-static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
-                                 uint32_t arg)
+static void lsi_request_cancelled(SCSIRequest *req)
 {
-    LSIState *s = DO_UPCAST(LSIState, dev.qdev, bus->qbus.parent);
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    lsi_request *p = req->hba_private;
+
+    if (s->current && req == s->current->req) {
+        scsi_req_unref(req);
+        g_free(s->current);
+        s->current = NULL;
+        return;
+    }
+
+    if (p) {
+        QTAILQ_REMOVE(&s->queue, p, next);
+        scsi_req_unref(req);
+        g_free(p);
+    }
+}
+
+/* Record that data is available for a queued command.  Returns zero if
+   the device was reselected, nonzero if the IO is deferred.  */
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
+{
+    lsi_request *p = req->hba_private;
+
+    if (p->pending) {
+        BADF("Multiple IO pending for request %p\n", p);
+    }
+    p->pending = len;
+    /* Reselect if waiting for it, or if reselection triggers an IRQ
+       and the bus is free.
+       Since no interrupt stacking is implemented in the emulation, it
+       is also required that there are no pending interrupts waiting
+       for service from the device driver. */
+    if (s->waiting == 1 ||
+        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
+         !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
+        /* Reselect device.  */
+        lsi_reselect(s, p);
+        return 0;
+    } else {
+        DPRINTF("Queueing IO tag=0x%x\n", p->tag);
+        p->pending = len;
+        return 1;
+    }
+}
+
+ /* Callback to indicate that the SCSI layer has completed a command.  */
+static void lsi_command_complete(SCSIRequest *req, uint32_t status)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
     int out;
 
     out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-    if (reason == SCSI_REASON_DONE) {
-        DPRINTF("Command complete sense=%d\n", (int)arg);
-        s->sense = arg;
-        s->command_complete = 2;
-        if (s->waiting && s->dbc != 0) {
-            /* Raise phase mismatch for short transfers.  */
-            lsi_bad_phase(s, out, PHASE_ST);
-        } else {
-            lsi_set_phase(s, PHASE_ST);
-        }
+    DPRINTF("Command complete status=%d\n", (int)status);
+    s->status = status;
+    s->command_complete = 2;
+    if (s->waiting && s->dbc != 0) {
+        /* Raise phase mismatch for short transfers.  */
+        lsi_bad_phase(s, out, PHASE_ST);
+    } else {
+        lsi_set_phase(s, PHASE_ST);
+    }
 
-        qemu_free(s->current);
+    if (s->current && req == s->current->req) {
+        scsi_req_unref(s->current->req);
+        g_free(s->current);
         s->current = NULL;
-
-        lsi_resume_script(s);
-        return;
     }
+    lsi_resume_script(s);
+}
+
+ /* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    int out;
 
-    if (s->waiting == 1 || !s->current || tag != s->current->tag ||
+    if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
         (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
-        if (lsi_queue_tag(s, tag, arg))
+        if (lsi_queue_req(s, req, len)) {
             return;
+        }
     }
 
+    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+
     /* host adapter (re)connected */
-    DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
-    s->current->dma_len = arg;
+    DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
+    s->current->dma_len = len;
     s->command_complete = 1;
-    if (!s->waiting)
-        return;
-    if (s->waiting == 1 || s->dbc == 0) {
-        lsi_resume_script(s);
-    } else {
-        lsi_do_dma(s, out);
+    if (s->waiting) {
+        if (s->waiting == 1 || s->dbc == 0) {
+            lsi_resume_script(s);
+        } else {
+            lsi_do_dma(s, out);
+        }
     }
 }
 
@@ -741,30 +761,32 @@ static void lsi_do_command(LSIState *s)
     DPRINTF("Send command len=%d\n", s->dbc);
     if (s->dbc > 16)
         s->dbc = 16;
-    cpu_physical_memory_read(s->dnad, buf, s->dbc);
+    pci_dma_read(&s->dev, s->dnad, buf, s->dbc);
     s->sfbr = buf[0];
     s->command_complete = 0;
 
     id = (s->select_tag >> 8) & 0xf;
-    dev = s->bus.devs[id];
+    dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
     if (!dev) {
         lsi_bad_selection(s, id);
         return;
     }
 
     assert(s->current == NULL);
-    s->current = qemu_mallocz(sizeof(lsi_request));
+    s->current = g_malloc0(sizeof(lsi_request));
     s->current->tag = s->select_tag;
+    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
+                                   s->current);
 
-    n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun);
-    if (n > 0) {
-        lsi_set_phase(s, PHASE_DI);
-        dev->info->read_data(dev, s->current->tag);
-    } else if (n < 0) {
-        lsi_set_phase(s, PHASE_DO);
-        dev->info->write_data(dev, s->current->tag);
+    n = scsi_req_enqueue(s->current->req);
+    if (n) {
+        if (n > 0) {
+            lsi_set_phase(s, PHASE_DI);
+        } else if (n < 0) {
+            lsi_set_phase(s, PHASE_DO);
+        }
+        scsi_req_continue(s->current->req);
     }
-
     if (!s->command_complete) {
         if (n) {
             /* Command did not complete immediately so disconnect.  */
@@ -783,14 +805,14 @@ static void lsi_do_command(LSIState *s)
 
 static void lsi_do_status(LSIState *s)
 {
-    uint8_t sense;
-    DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense);
+    uint8_t status;
+    DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
     if (s->dbc != 1)
         BADF("Bad Status move\n");
     s->dbc = 1;
-    sense = s->sense;
-    s->sfbr = sense;
-    cpu_physical_memory_write(s->dnad, &sense, 1);
+    status = s->status;
+    s->sfbr = status;
+    pci_dma_write(&s->dev, s->dnad, &status, 1);
     lsi_set_phase(s, PHASE_MI);
     s->msg_action = 1;
     lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
@@ -804,7 +826,7 @@ static void lsi_do_msgin(LSIState *s)
     len = s->msg_len;
     if (len > s->dbc)
         len = s->dbc;
-    cpu_physical_memory_write(s->dnad, s->msg, len);
+    pci_dma_write(&s->dev, s->dnad, s->msg, len);
     /* Linux drivers rely on the last byte being in the SIDL.  */
     s->sidl = s->msg[len - 1];
     s->msg_len -= len;
@@ -836,7 +858,7 @@ static void lsi_do_msgin(LSIState *s)
 static uint8_t lsi_get_msgbyte(LSIState *s)
 {
     uint8_t data;
-    cpu_physical_memory_read(s->dnad, &data, 1);
+    pci_dma_read(&s->dev, s->dnad, &data, 1);
     s->dnad++;
     s->dbc--;
     return data;
@@ -854,17 +876,15 @@ 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;
+    lsi_request *current_req, *p, *p_next;
 
     if (s->current) {
         current_tag = s->current->tag;
+        current_req = s->current;
     } else {
         current_tag = s->select_tag;
+        current_req = lsi_find_by_tag(s, current_tag);
     }
-    id = (current_tag >> 8) & 0xf;
-    current_dev = s->bus.devs[id];
 
     DPRINTF("MSG out len=%d\n", s->dbc);
     while (s->dbc) {
@@ -913,7 +933,9 @@ static void lsi_do_msgout(LSIState *s)
         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);
+            if (current_req) {
+                scsi_req_cancel(current_req->req);
+            }
             lsi_disconnect(s);
             break;
         case 0x06:
@@ -936,7 +958,9 @@ static void lsi_do_msgout(LSIState *s)
             }
 
             /* clear the current I/O process */
-            current_dev->info->cancel_io(current_dev, current_tag);
+            if (s->current) {
+                scsi_req_cancel(s->current->req);
+            }
 
             /* As the current implemented devices scsi_disk and scsi_generic
                only support one LUN, we don't need to keep track of LUNs.
@@ -945,11 +969,9 @@ static void lsi_do_msgout(LSIState *s)
                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);
+                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
+                    scsi_req_cancel(p->req);
                 }
             }
 
@@ -988,8 +1010,8 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
     DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
     while (count) {
         n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
-        cpu_physical_memory_read(src, buf, n);
-        cpu_physical_memory_write(dest, buf, n);
+        pci_dma_read(&s->dev, src, buf, n);
+        pci_dma_write(&s->dev, dest, buf, n);
         src += n;
         dest += n;
         count -= n;
@@ -1057,7 +1079,7 @@ again:
 
             /* 32-bit Table indirect */
             offset = sxt24(addr);
-            cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
+            pci_dma_read(&s->dev, s->dsa + offset, (uint8_t *)buf, 8);
             /* byte count is stored in bits 0:23 only */
             s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
             s->rbc = s->dbc;
@@ -1175,7 +1197,7 @@ again:
                 }
                 s->sstat0 |= LSI_SSTAT0_WOA;
                 s->scntl1 &= ~LSI_SCNTL1_IARB;
-                if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
+                if (!scsi_device_find(&s->bus, 0, id, 0)) {
                     lsi_bad_selection(s, id);
                     break;
                 }
@@ -1416,7 +1438,7 @@ again:
             n = (insn & 7);
             reg = (insn >> 16) & 0xff;
             if (insn & (1 << 24)) {
-                cpu_physical_memory_read(addr, data, n);
+                pci_dma_read(&s->dev, addr, data, n);
                 DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
                         addr, *(int *)data);
                 for (i = 0; i < n; i++) {
@@ -1427,7 +1449,7 @@ again:
                 for (i = 0; i < n; i++) {
                     data[i] = lsi_reg_readb(s, reg + i);
                 }
-                cpu_physical_memory_write(addr, data, n);
+                pci_dma_write(&s->dev, addr, data, n);
             }
         }
     }
@@ -1657,13 +1679,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
         if (val & LSI_SCNTL1_RST) {
             if (!(s->sstat0 & LSI_SSTAT0_RST)) {
                 DeviceState *dev;
-                int id;
 
-                for (id = 0; id < s->bus.ndev; id++) {
-                    if (s->bus.devs[id]) {
-                        dev = &s->bus.devs[id]->qdev;
-                        dev->info->reset(dev);
-                    }
+                QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
+                    dev->info->reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
@@ -1867,241 +1885,90 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
 #undef CASE_SET_REG32
 }
 
-static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void lsi_mmio_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
 
     lsi_reg_writeb(s, addr & 0xff, val);
 }
 
-static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
-    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
-}
-
-static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t lsi_mmio_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     LSIState *s = opaque;
 
     return lsi_reg_readb(s, addr & 0xff);
 }
 
-static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    return val;
-}
-
-static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    val |= lsi_reg_readb(s, addr + 2) << 16;
-    val |= lsi_reg_readb(s, addr + 3) << 24;
-    return val;
-}
-
-static CPUReadMemoryFunc * const lsi_mmio_readfn[3] = {
-    lsi_mmio_readb,
-    lsi_mmio_readw,
-    lsi_mmio_readl,
+static const MemoryRegionOps lsi_mmio_ops = {
+    .read = lsi_mmio_read,
+    .write = lsi_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
-static CPUWriteMemoryFunc * const lsi_mmio_writefn[3] = {
-    lsi_mmio_writeb,
-    lsi_mmio_writew,
-    lsi_mmio_writel,
-};
-
-static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void lsi_ram_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
     uint32_t newval;
+    uint32_t mask;
     int shift;
 
-    addr &= 0x1fff;
     newval = s->script_ram[addr >> 2];
     shift = (addr & 3) * 8;
-    newval &= ~(0xff << shift);
+    mask = ((uint64_t)1 << (size * 8)) - 1;
+    newval &= ~(mask << shift);
     newval |= val << shift;
     s->script_ram[addr >> 2] = newval;
 }
 
-static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    uint32_t newval;
-
-    addr &= 0x1fff;
-    newval = s->script_ram[addr >> 2];
-    if (addr & 2) {
-        newval = (newval & 0xffff) | (val << 16);
-    } else {
-        newval = (newval & 0xffff0000) | val;
-    }
-    s->script_ram[addr >> 2] = newval;
-}
-
-
-static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0x1fff;
-    s->script_ram[addr >> 2] = val;
-}
-
-static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t lsi_ram_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     LSIState *s = opaque;
     uint32_t val;
+    uint32_t mask;
 
-    addr &= 0x1fff;
     val = s->script_ram[addr >> 2];
+    mask = ((uint64_t)1 << (size * 8)) - 1;
     val >>= (addr & 3) * 8;
-    return val & 0xff;
-}
-
-static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-
-    addr &= 0x1fff;
-    val = s->script_ram[addr >> 2];
-    if (addr & 2)
-        val >>= 16;
-    return val;
-}
-
-static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-
-    addr &= 0x1fff;
-    return s->script_ram[addr >> 2];
+    return val & mask;
 }
 
-static CPUReadMemoryFunc * const lsi_ram_readfn[3] = {
-    lsi_ram_readb,
-    lsi_ram_readw,
-    lsi_ram_readl,
-};
-
-static CPUWriteMemoryFunc * const lsi_ram_writefn[3] = {
-    lsi_ram_writeb,
-    lsi_ram_writew,
-    lsi_ram_writel,
+static const MemoryRegionOps lsi_ram_ops = {
+    .read = lsi_ram_read,
+    .write = lsi_ram_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
+static uint64_t lsi_io_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     LSIState *s = opaque;
     return lsi_reg_readb(s, addr & 0xff);
 }
 
-static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    return val;
-}
-
-static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    val |= lsi_reg_readb(s, addr + 2) << 16;
-    val |= lsi_reg_readb(s, addr + 3) << 24;
-    return val;
-}
-
-static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void lsi_io_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
     lsi_reg_writeb(s, addr & 0xff, val);
 }
 
-static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
-    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
-}
-
-static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
-                           pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
-
-    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
-    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
-    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
-    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
-    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
-    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
-}
-
-static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
-    s->script_ram_base = addr;
-    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
-}
-
-static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping registers at %08"FMT_PCIBUS"\n", addr);
-    cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
-}
+static const MemoryRegionOps lsi_io_ops = {
+    .read = lsi_io_read,
+    .write = lsi_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
 
 static void lsi_scsi_reset(DeviceState *dev)
 {
@@ -2131,7 +1998,7 @@ static const VMStateDescription vmstate_lsi_scsi = {
         VMSTATE_PCI_DEVICE(dev, LSIState),
 
         VMSTATE_INT32(carry, LSIState),
-        VMSTATE_INT32(sense, LSIState),
+        VMSTATE_INT32(status, LSIState),
         VMSTATE_INT32(msg_action, LSIState),
         VMSTATE_INT32(msg_len, LSIState),
         VMSTATE_BUFFER(msg, LSIState),
@@ -2208,12 +2075,23 @@ static int lsi_scsi_uninit(PCIDevice *d)
 {
     LSIState *s = DO_UPCAST(LSIState, dev, d);
 
-    cpu_unregister_io_memory(s->mmio_io_addr);
-    cpu_unregister_io_memory(s->ram_io_addr);
+    memory_region_destroy(&s->mmio_io);
+    memory_region_destroy(&s->ram_io);
+    memory_region_destroy(&s->io_io);
 
     return 0;
 }
 
+static const struct SCSIBusInfo lsi_scsi_info = {
+    .tcq = true,
+    .max_target = LSI_MAX_DEVS,
+    .max_lun = 0,  /* LUN support is buggy */
+
+    .transfer_data = lsi_transfer_data,
+    .complete = lsi_command_complete,
+    .cancel = lsi_request_cancelled
+};
+
 static int lsi_scsi_init(PCIDevice *dev)
 {
     LSIState *s = DO_UPCAST(LSIState, dev, dev);
@@ -2221,37 +2099,21 @@ static int lsi_scsi_init(PCIDevice *dev)
 
     pci_conf = s->dev.config;
 
-    /* PCI Vendor ID (word) */
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_LSI_LOGIC);
-    /* PCI device ID (word) */
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_LSI_53C895A);
-    /* PCI base class code */
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_SCSI);
-    /* PCI subsystem ID */
-    pci_conf[PCI_SUBSYSTEM_ID] = 0x00;
-    pci_conf[PCI_SUBSYSTEM_ID + 1] = 0x10;
     /* PCI latency timer = 255 */
     pci_conf[PCI_LATENCY_TIMER] = 0xff;
-    /* TODO: RST# value should be 0 */
-    /* Interrupt pin 1 */
+    /* Interrupt pin A */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01;
 
-    s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn,
-                                             lsi_mmio_writefn, s,
-                                             DEVICE_NATIVE_ENDIAN);
-    s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn,
-                                            lsi_ram_writefn, s,
-                                            DEVICE_NATIVE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, 256,
-                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
-    pci_register_bar(&s->dev, 1, 0x400,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
-    pci_register_bar(&s->dev, 2, 0x2000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
+    memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400);
+    memory_region_init_io(&s->ram_io, &lsi_ram_ops, s, "lsi-ram", 0x2000);
+    memory_region_init_io(&s->io_io, &lsi_io_ops, s, "lsi-io", 256);
+
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+    pci_register_bar(&s->dev, 1, 0, &s->mmio_io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
     QTAILQ_INIT(&s->queue);
 
-    scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
+    scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info);
     if (!dev->qdev.hotplugged) {
         return scsi_bus_legacy_handle_cmdline(&s->bus);
     }
@@ -2266,6 +2128,10 @@ static PCIDeviceInfo lsi_info = {
     .qdev.vmsd  = &vmstate_lsi_scsi,
     .init       = lsi_scsi_init,
     .exit       = lsi_scsi_uninit,
+    .vendor_id  = PCI_VENDOR_ID_LSI_LOGIC,
+    .device_id  = PCI_DEVICE_ID_LSI_53C895A,
+    .class_id   = PCI_CLASS_STORAGE_SCSI,
+    .subsystem_id = 0x1000,
 };
 
 static void lsi53c895a_register_devices(void)
index 2020487bbec8a9270686900a2764838e205adf3c..a77937ef68501392073076e5831eff294862609b 100644 (file)
@@ -50,8 +50,6 @@
  */
 
 struct M48t59State {
-    /* Model parameters */
-    uint32_t type; // 2 = m48t02, 8 = m48t08, 59 = m48t59
     /* Hardware parameters */
     qemu_irq IRQ;
     uint32_t io_base;
@@ -64,14 +62,18 @@ struct M48t59State {
     struct QEMUTimer *alrm_timer;
     struct QEMUTimer *wd_timer;
     /* NVRAM storage */
-    uint8_t  lock;
-    uint16_t addr;
     uint8_t *buffer;
+    /* Model parameters */
+    uint32_t type; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
+    /* NVRAM storage */
+    uint16_t addr;
+    uint8_t  lock;
 };
 
 typedef struct M48t59ISAState {
     ISADevice busdev;
     M48t59State state;
+    MemoryRegion io;
 } M48t59ISAState;
 
 typedef struct M48t59SysBusState {
@@ -123,7 +125,7 @@ static void alarm_cb (void *opaque)
         /* Repeat once a second */
         next_time = 1;
     }
-    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
                     next_time * 1000);
     qemu_set_irq(NVRAM->IRQ, 0);
 }
@@ -478,7 +480,6 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
 {
     M48t59State *NVRAM = opaque;
 
-    addr -= NVRAM->io_base;
     NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
     switch (addr) {
     case 0:
@@ -490,7 +491,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
         NVRAM->addr |= val << 8;
         break;
     case 3:
-        m48t59_write(NVRAM, val, NVRAM->addr);
+        m48t59_write(NVRAM, NVRAM->addr, val);
         NVRAM->addr = 0x0000;
         break;
     default:
@@ -503,7 +504,6 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
     M48t59State *NVRAM = opaque;
     uint32_t retval;
 
-    addr -= NVRAM->io_base;
     switch (addr) {
     case 3:
         retval = m48t59_read(NVRAM, NVRAM->addr);
@@ -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)
 {
@@ -635,6 +625,15 @@ static void m48t59_reset_sysbus(DeviceState *d)
     m48t59_reset_common(NVRAM);
 }
 
+static const MemoryRegionPortio m48t59_portio[] = {
+    {0, 4, 1, .read = NVRAM_readb, .write = NVRAM_writeb },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps m48t59_io_ops = {
+    .old_portio = m48t59_portio,
+};
+
 /* Initialisation routine */
 M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
                          uint32_t io_base, uint16_t size, int type)
@@ -678,10 +677,9 @@ M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
     d = DO_UPCAST(M48t59ISAState, busdev, dev);
     s = &d->state;
 
+    memory_region_init_io(&d->io, &m48t59_io_ops, s, "m48t59", 4);
     if (io_base != 0) {
-        register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
-        register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
-        isa_init_ioport_range(dev, io_base, 4);
+        isa_register_ioport(dev, &d->io, io_base);
     }
 
     return s;
@@ -689,14 +687,14 @@ M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
 
 static void m48t59_init_common(M48t59State *s)
 {
-    s->buffer = qemu_mallocz(s->size);
+    s->buffer = g_malloc0(s->size);
     if (s->type == 59) {
-        s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
-        s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
+        s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
+        s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, 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..1791ec12e1664b1dc92c180095a6abbc8ee1a6ad 100644 (file)
@@ -165,6 +165,11 @@ typedef struct DBDMA_channel {
     int processing;
 } DBDMA_channel;
 
+typedef struct {
+    MemoryRegion mem;
+    DBDMA_channel channels[DBDMA_CHANNELS];
+} DBDMAState;
+
 #ifdef DEBUG_DBDMA
 static void dump_dbdma_cmd(dbdma_cmd *cmd)
 {
@@ -617,31 +622,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);
 
@@ -653,11 +661,6 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
     ch->io.channel = ch;
 }
 
-void DBDMA_schedule(void)
-{
-    qemu_notify_event();
-}
-
 static void
 dbdma_control_write(DBDMA_channel *ch)
 {
@@ -696,11 +699,12 @@ dbdma_control_write(DBDMA_channel *ch)
         ch->flush(&ch->io);
 }
 
-static void dbdma_writel (void *opaque,
-                          target_phys_addr_t addr, uint32_t value)
+static void dbdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t value, unsigned size)
 {
     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);
@@ -745,11 +749,13 @@ static void dbdma_writel (void *opaque,
     }
 }
 
-static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t dbdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     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];
@@ -789,61 +795,57 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const dbdma_write[] = {
-    NULL,
-    NULL,
-    dbdma_writel,
+static const MemoryRegionOps dbdma_ops = {
+    .read = dbdma_read,
+    .write = dbdma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-static CPUReadMemoryFunc * const dbdma_read[] = {
-    NULL,
-    NULL,
-    dbdma_readl,
+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()
+    }
 };
 
-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]);
-
-    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)
+void* DBDMA_init (MemoryRegion **dbdma_mem)
 {
-    DBDMA_channel *s;
+    DBDMAState *s;
 
-    s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
+    s = g_malloc0(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);
+    memory_region_init_io(&s->mem, &dbdma_ops, s, "dbdma", 0x1000);
+    *dbdma_mem = &s->mem;
+    vmstate_register(NULL, -1, &vmstate_dbdma, s);
     qemu_register_reset(dbdma_reset, s);
 
     dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
index d236c5b3f29eead8b849e85ba23d4f332d2482f9..6d1abe6aae969bf749d4c4ef4c9bcec2af5e07b8 100644 (file)
@@ -20,6 +20,8 @@
  * THE SOFTWARE.
  */
 
+#include "memory.h"
+
 typedef struct DBDMA_io DBDMA_io;
 
 typedef void (*DBDMA_flush)(DBDMA_io *io);
@@ -39,5 +41,4 @@ struct DBDMA_io {
 void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                             DBDMA_rw rw, DBDMA_flush flush,
                             void *opaque);
-void DBDMA_schedule(void);
-void* DBDMA_init (int *dbdma_mem_index);
+void* DBDMA_init (MemoryRegion **dbdma_mem);
index c2a2fc21e49ba137c256b0e57ebff82561fc51e2..ed0a2b7ef2597b99a0353b2df368815ddac01362 100644 (file)
@@ -38,8 +38,8 @@
 #endif
 
 struct MacIONVRAMState {
-    target_phys_addr_t size;
-    int mem_index;
+    uint32_t size;
+    MemoryRegion mem;
     unsigned int it_shift;
     uint8_t *data;
 };
@@ -71,8 +71,8 @@ void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val)
 }
 
 /* macio style NVRAM device */
-static void macio_nvram_writeb (void *opaque,
-                                target_phys_addr_t addr, uint32_t value)
+static void macio_nvram_writeb(void *opaque, target_phys_addr_t addr,
+                               uint64_t value, unsigned size)
 {
     MacIONVRAMState *s = opaque;
 
@@ -81,7 +81,8 @@ static void macio_nvram_writeb (void *opaque,
     NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value);
 }
 
-static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
+static uint64_t macio_nvram_readb(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     MacIONVRAMState *s = opaque;
     uint32_t value;
@@ -93,68 +94,50 @@ static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const nvram_write[] = {
-    &macio_nvram_writeb,
-    &macio_nvram_writeb,
-    &macio_nvram_writeb,
+static const MemoryRegionOps macio_nvram_ops = {
+    .read = macio_nvram_readb,
+    .write = macio_nvram_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const nvram_read[] = {
-    &macio_nvram_readb,
-    &macio_nvram_readb,
-    &macio_nvram_readb,
+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()
+    }
 };
 
-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);
-
-    return 0;
-}
 
 static void macio_nvram_reset(void *opaque)
 {
 }
 
-MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+MacIONVRAMState *macio_nvram_init (target_phys_addr_t size,
                                    unsigned int it_shift)
 {
     MacIONVRAMState *s;
 
-    s = qemu_mallocz(sizeof(MacIONVRAMState));
-    s->data = qemu_mallocz(size);
+    s = g_malloc0(sizeof(MacIONVRAMState));
+    s->data = g_malloc0(size);
     s->size = size;
     s->it_shift = it_shift;
 
-    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);
+    memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram",
+                          size << it_shift);
+    vmstate_register(NULL, -1, &vmstate_macio_nvram, s);
     qemu_register_reset(macio_nvram_reset, s);
 
     return s;
 }
 
-void macio_nvram_map (void *opaque, target_phys_addr_t mem_base)
+void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
+                           target_phys_addr_t mem_base)
 {
-    MacIONVRAMState *s;
-
-    s = opaque;
-    cpu_register_physical_memory(mem_base, s->size << s->it_shift,
-                                 s->mem_index);
+    memory_region_add_subregion(bar, mem_base, &s->mem);
 }
 
 /* Set up a system OpenBIOS NVRAM partition */
index 789ca5529d2125a5224976da72a09c0a0fe8326e..cc6ae400505e84ee9b3f8030c07ce0cf78aa084f 100644 (file)
 typedef struct macio_state_t macio_state_t;
 struct macio_state_t {
     int is_oldworld;
-    int pic_mem_index;
-    int dbdma_mem_index;
-    int cuda_mem_index;
-    int escc_mem_index;
+    MemoryRegion bar;
+    MemoryRegion *pic_mem;
+    MemoryRegion *dbdma_mem;
+    MemoryRegion *cuda_mem;
+    MemoryRegion *escc_mem;
     void *nvram;
     int nb_ide;
-    int ide_mem_index[4];
+    MemoryRegion *ide_mem[4];
 };
 
-static void macio_map (PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
+static void macio_bar_setup(macio_state_t *macio_state)
 {
-    macio_state_t *macio_state;
     int i;
+    MemoryRegion *bar = &macio_state->bar;
 
-    macio_state = (macio_state_t *)(pci_dev + 1);
-    if (macio_state->pic_mem_index >= 0) {
+    memory_region_init(bar, "macio", 0x80000);
+    if (macio_state->pic_mem) {
         if (macio_state->is_oldworld) {
             /* Heathrow PIC */
-            cpu_register_physical_memory(addr + 0x00000, 0x1000,
-                                         macio_state->pic_mem_index);
+            memory_region_add_subregion(bar, 0x00000, macio_state->pic_mem);
         } else {
             /* OpenPIC */
-            cpu_register_physical_memory(addr + 0x40000, 0x40000,
-                                         macio_state->pic_mem_index);
+            memory_region_add_subregion(bar, 0x40000, macio_state->pic_mem);
         }
     }
-    if (macio_state->dbdma_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x08000, 0x1000,
-                                     macio_state->dbdma_mem_index);
+    if (macio_state->dbdma_mem) {
+        memory_region_add_subregion(bar, 0x08000, macio_state->dbdma_mem);
     }
-    if (macio_state->escc_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE << 4,
-                                     macio_state->escc_mem_index);
+    if (macio_state->escc_mem) {
+        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
     }
-    if (macio_state->cuda_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x16000, 0x2000,
-                                     macio_state->cuda_mem_index);
+    if (macio_state->cuda_mem) {
+        memory_region_add_subregion(bar, 0x16000, macio_state->cuda_mem);
     }
     for (i = 0; i < macio_state->nb_ide; i++) {
-        if (macio_state->ide_mem_index[i] >= 0) {
-            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
-                                         macio_state->ide_mem_index[i]);
+        if (macio_state->ide_mem[i]) {
+            memory_region_add_subregion(bar, 0x1f000 + (i * 0x1000),
+                                        macio_state->ide_mem[i]);
         }
     }
     if (macio_state->nvram != NULL)
-        macio_nvram_map(macio_state->nvram, addr + 0x60000);
+        macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000);
 }
 
-void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index)
+void macio_init (PCIBus *bus, int device_id, int is_oldworld,
+                 MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
+                 MemoryRegion *cuda_mem, void *nvram,
+                 int nb_ide, MemoryRegion **ide_mem,
+                 MemoryRegion *escc_mem)
 {
     PCIDevice *d;
     macio_state_t *macio_state;
@@ -92,18 +89,18 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
                             -1, NULL, NULL);
     macio_state = (macio_state_t *)(d + 1);
     macio_state->is_oldworld = is_oldworld;
-    macio_state->pic_mem_index = pic_mem_index;
-    macio_state->dbdma_mem_index = dbdma_mem_index;
-    macio_state->cuda_mem_index = cuda_mem_index;
-    macio_state->escc_mem_index = escc_mem_index;
+    macio_state->pic_mem = pic_mem;
+    macio_state->dbdma_mem = dbdma_mem;
+    macio_state->cuda_mem = cuda_mem;
+    macio_state->escc_mem = escc_mem;
     macio_state->nvram = nvram;
     if (nb_ide > 4)
         nb_ide = 4;
     macio_state->nb_ide = nb_ide;
     for (i = 0; i < nb_ide; i++)
-        macio_state->ide_mem_index[i] = ide_mem_index[i];
+        macio_state->ide_mem[i] = ide_mem[i];
     for (; i < 4; i++)
-        macio_state->ide_mem_index[i] = -1;
+        macio_state->ide_mem[i] = NULL;
     /* Note: this code is strongly inspirated from the corresponding code
        in PearPC */
 
@@ -113,6 +110,6 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
 
     d->config[0x3d] = 0x01; // interrupt on pin 1
 
-    pci_register_bar(d, 0, 0x80000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
+    macio_bar_setup(macio_state);
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar);
 }
index 58e3f8670d5fad234cacfa5b682226032b06400a..3ed6649204ceca51b94f6f6fce5c888acefe00ab 100644 (file)
 #include "net.h"
 #include "devices.h"
 #include "boards.h"
-#include "mainstone.h"
-#include "sysemu.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "sysbus.h"
+#include "exec-memory.h"
+
+/* Device addresses */
+#define MST_FPGA_PHYS  0x08000000
+#define MST_ETH_PHYS   0x10000300
+#define MST_FLASH_0            0x00000000
+#define MST_FLASH_1            0x04000000
+
+/* IRQ definitions */
+#define MMC_IRQ       0
+#define USIM_IRQ      1
+#define USBC_IRQ      2
+#define ETHERNET_IRQ  3
+#define AC97_IRQ      4
+#define PEN_IRQ       5
+#define MSINS_IRQ     6
+#define EXBRD_IRQ     7
+#define S0_CD_IRQ     9
+#define S0_STSCHG_IRQ 10
+#define S0_IRQ        11
+#define S1_CD_IRQ     13
+#define S1_STSCHG_IRQ 14
+#define S1_IRQ        15
 
 static struct keymap map[0xE0] = {
     [0 ... 0xDF] = { -1, -1 },
@@ -69,7 +91,8 @@ static struct arm_boot_info mainstone_binfo = {
     .ram_size = 0x04000000,
 };
 
-static void mainstone_common_init(ram_addr_t ram_size,
+static void mainstone_common_init(MemoryRegion *address_space_mem,
+                ram_addr_t ram_size,
                 const char *kernel_filename,
                 const char *kernel_cmdline, const char *initrd_filename,
                 const char *cpu_model, enum mainstone_model_e model, int arm_id)
@@ -77,19 +100,20 @@ static void mainstone_common_init(ram_addr_t ram_size,
     uint32_t sector_len = 256 * 1024;
     target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
     PXA2xxState *cpu;
-    qemu_irq *mst_irq;
+    DeviceState *mst_irq;
     DriveInfo *dinfo;
     int i;
     int be;
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "pxa270-c5";
 
     /* Setup CPU & memory */
-    cpu = pxa270_init(mainstone_binfo.ram_size, cpu_model);
-    cpu_register_physical_memory(0, MAINSTONE_ROM,
-                    qemu_ram_alloc(NULL, "mainstone.rom",
-                                   MAINSTONE_ROM) | IO_MEM_ROM);
+    cpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
+    memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
@@ -105,10 +129,9 @@ static void mainstone_common_init(ram_addr_t ram_size,
             exit(1);
         }
 
-        if (!pflash_cfi01_register(mainstone_flash_base[i],
-                                   qemu_ram_alloc(NULL, i ? "mainstone.flash1" :
-                                                  "mainstone.flash0",
-                                                  MAINSTONE_FLASH),
+        if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
+                                   i ? "mainstone.flash1" : "mainstone.flash0",
+                                   MAINSTONE_FLASH,
                                    dinfo->bdrv, sector_len,
                                    MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
                                    be)) {
@@ -117,16 +140,25 @@ static void mainstone_common_init(ram_addr_t ram_size,
         }
     }
 
-    mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0);
+    mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
+                    qdev_get_gpio_in(cpu->gpio, 0));
 
     /* setup keypad */
     printf("map addr %p\n", &map);
     pxa27x_register_keypad(cpu->kp, map, 0xe0);
 
     /* MMC/SD host */
-    pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]);
+    pxa2xx_mmci_handlers(cpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
 
-    smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]);
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+            qdev_get_gpio_in(mst_irq, S0_IRQ),
+            qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+            qdev_get_gpio_in(mst_irq, S1_IRQ),
+            qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
+
+    smc91c111_init(&nd_table[0], MST_ETH_PHYS,
+                    qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
 
     mainstone_binfo.kernel_filename = kernel_filename;
     mainstone_binfo.kernel_cmdline = kernel_cmdline;
@@ -140,7 +172,7 @@ static void mainstone_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
-    mainstone_common_init(ram_size, kernel_filename,
+    mainstone_common_init(get_system_memory(), ram_size, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196);
 }
 
index 3eff925b0eaf1b090382180642c0a7005d15acdc..f8c524286756ba6160280234d1bb7ecb198b66ae 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2008 Jan Kiszka
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 #include "sysbus.h"
 #include "hw.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;
 }
 
index c302eb6aa4561bd536c6f191f399b3a86740b791..c1bdb2ee0c5e98d4aa26dd87bca15149eba37998 100644 (file)
@@ -23,9 +23,9 @@ typedef struct {
     qemu_irq *gpio_in;
 } MAX7310State;
 
-void max7310_reset(i2c_slave *i2c)
+static void max7310_reset(DeviceState *dev)
 {
-    MAX7310State *s = (MAX7310State *) i2c;
+    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE_FROM_QDEV(dev));
     s->level &= s->direction;
     s->direction = 0xff;
     s->polarity = 0xf0;
@@ -179,33 +179,17 @@ static int max7310_init(i2c_slave *i2c)
 {
     MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
 
-    s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s,
-                    ARRAY_SIZE(s->handler));
-
-    max7310_reset(&s->i2c);
+    qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
+    qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
 
     return 0;
 }
 
-qemu_irq *max7310_gpio_in_get(i2c_slave *i2c)
-{
-    MAX7310State *s = (MAX7310State *) i2c;
-    return s->gpio_in;
-}
-
-void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
-{
-    MAX7310State *s = (MAX7310State *) i2c;
-    if (line >= ARRAY_SIZE(s->handler) || line  < 0)
-        hw_error("bad GPIO line");
-
-    s->handler[line] = handler;
-}
-
 static I2CSlaveInfo max7310_info = {
     .qdev.name = "max7310",
     .qdev.size = sizeof(MAX7310State),
     .qdev.vmsd = &vmstate_max7310,
+    .qdev.reset = max7310_reset,
     .init = max7310_init,
     .event = max7310_event,
     .recv = max7310_rx,
index a1b0e31ee547c18922d7483d2fb79d38a2103e13..2aaca2ff416fa76d5fa5a92635f5041317f619da 100644 (file)
@@ -81,6 +81,7 @@
 
 typedef struct RTCState {
     ISADevice dev;
+    MemoryRegion io;
     uint8_t cmos_data[128];
     uint8_t cmos_index;
     struct tm current_tm;
@@ -99,6 +100,7 @@ typedef struct RTCState {
     QEMUTimer *coalesced_timer;
     QEMUTimer *second_timer;
     QEMUTimer *second_timer2;
+    Notifier clock_reset_notifier;
 } RTCState;
 
 static void rtc_set_time(RTCState *s);
@@ -112,7 +114,7 @@ static void rtc_coalesced_timer_update(RTCState *s)
     } else {
         /* divide each RTC interval to 2 - 8 smaller intervals */
         int c = MIN(s->irq_coalesced, 7) + 1; 
-        int64_t next_clock = qemu_get_clock(rtc_clock) +
+        int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
             muldiv64(s->period / c, get_ticks_per_sec(), 32768);
         qemu_mod_timer(s->coalesced_timer, next_clock);
     }
@@ -234,7 +236,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
             /* UIP bit is read only */
             s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
                 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
-            rtc_timer_update(s, qemu_get_clock(rtc_clock));
+            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
             break;
         case RTC_REG_B:
             if (data & REG_B_SET) {
@@ -256,7 +258,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
             } else {
                 s->cmos_data[RTC_REG_B] = data;
             }
-            rtc_timer_update(s, qemu_get_clock(rtc_clock));
+            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
             break;
         case RTC_REG_C:
         case RTC_REG_D:
@@ -572,6 +574,22 @@ static const VMStateDescription vmstate_rtc = {
     }
 };
 
+static void rtc_notify_clock_reset(Notifier *notifier, void *data)
+{
+    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
+    int64_t now = *(int64_t *)data;
+
+    rtc_set_date_from_host(&s->dev);
+    s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+    rtc_timer_update(s, now);
+#ifdef TARGET_I386
+    if (rtc_td_hack) {
+        rtc_coalesced_timer_update(s);
+    }
+#endif
+}
+
 static void rtc_reset(void *opaque)
 {
     RTCState *s = opaque;
@@ -587,6 +605,15 @@ static void rtc_reset(void *opaque)
 #endif
 }
 
+static const MemoryRegionPortio cmos_portio[] = {
+    {0, 2, 1, .read = cmos_ioport_read, .write = cmos_ioport_write },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps cmos_ops = {
+    .old_portio = cmos_portio
+};
+
 static int rtc_initfn(ISADevice *dev)
 {
     RTCState *s = DO_UPCAST(RTCState, dev, dev);
@@ -599,22 +626,24 @@ static int rtc_initfn(ISADevice *dev)
 
     rtc_set_date_from_host(dev);
 
-    s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s);
+    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
 #ifdef TARGET_I386
     if (rtc_td_hack)
         s->coalesced_timer =
-            qemu_new_timer(rtc_clock, rtc_coalesced_timer, s);
+            qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
 #endif
-    s->second_timer = qemu_new_timer(rtc_clock, rtc_update_second, s);
-    s->second_timer2 = qemu_new_timer(rtc_clock, rtc_update_second2, s);
+    s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
+    s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
+
+    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
+    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
 
     s->next_second_time =
-        qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
+        qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
     qemu_mod_timer(s->second_timer2, s->next_second_time);
 
-    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
-    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
-    isa_init_ioport_range(dev, base, 2);
+    memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
+    isa_register_ioport(dev, &s->io, base);
 
     qdev_set_legacy_instance_id(&dev->qdev, base, 2);
     qemu_register_reset(rtc_reset, s);
index 2a618d44463d554a82290a5a9e42561847d27aba..15d6f22f13ea85247095731e7f7636c570ceb0bd 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 #include "hw.h"
 #include "mcf.h"
@@ -132,7 +132,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq)
     m5206_timer_state *s;
     QEMUBH *bh;
 
-    s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
+    s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state));
     bh = qemu_bh_new(m5206_timer_trigger, s);
     s->timer = ptimer_init(bh);
     s->irq = irq;
@@ -523,7 +523,7 @@ qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
     qemu_irq *pic;
     int iomemtype;
 
-    s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
+    s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state));
     iomemtype = cpu_register_io_memory(m5206_mbar_readfn,
                                        m5206_mbar_writefn, s,
                                        DEVICE_NATIVE_ENDIAN);
index 17a692d4a33e8911a3cdc73f30841dcfec84b7a8..1c2c0c48aa9dc9ef6d49208dc4ee1491d4383280 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 #include "hw.h"
 #include "mcf.h"
@@ -13,6 +13,7 @@
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define SYS_FREQ 66000000
 
@@ -27,6 +28,7 @@
 #define PCSR_PRE_MASK   0x0f00
 
 typedef struct {
+    MemoryRegion iomem;
     qemu_irq irq;
     ptimer_state *timer;
     uint16_t pcsr;
@@ -43,7 +45,7 @@ static void m5208_timer_update(m5208_timer_state *s)
 }
 
 static void m5208_timer_write(void *opaque, target_phys_addr_t offset,
-                              uint32_t value)
+                              uint64_t value, unsigned size)
 {
     m5208_timer_state *s = (m5208_timer_state *)opaque;
     int prescale;
@@ -104,7 +106,8 @@ static void m5208_timer_trigger(void *opaque)
     m5208_timer_update(s);
 }
 
-static uint32_t m5208_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t m5208_timer_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     m5208_timer_state *s = (m5208_timer_state *)opaque;
     switch (addr) {
@@ -120,19 +123,14 @@ static uint32_t m5208_timer_read(void *opaque, target_phys_addr_t addr)
     }
 }
 
-static CPUReadMemoryFunc * const m5208_timer_readfn[] = {
-   m5208_timer_read,
-   m5208_timer_read,
-   m5208_timer_read
+static const MemoryRegionOps m5208_timer_ops = {
+    .read = m5208_timer_read,
+    .write = m5208_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const m5208_timer_writefn[] = {
-   m5208_timer_write,
-   m5208_timer_write,
-   m5208_timer_write
-};
-
-static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
+static uint64_t m5208_sys_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     switch (addr) {
     case 0x110: /* SDCS0 */
@@ -154,45 +152,36 @@ static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void m5208_sys_write(void *opaque, target_phys_addr_t addr,
-                            uint32_t value)
+                            uint64_t value, unsigned size)
 {
     hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
 }
 
-static CPUReadMemoryFunc * const m5208_sys_readfn[] = {
-   m5208_sys_read,
-   m5208_sys_read,
-   m5208_sys_read
-};
-
-static CPUWriteMemoryFunc * const m5208_sys_writefn[] = {
-   m5208_sys_write,
-   m5208_sys_write,
-   m5208_sys_write
+static const MemoryRegionOps m5208_sys_ops = {
+    .read = m5208_sys_read,
+    .write = m5208_sys_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void mcf5208_sys_init(qemu_irq *pic)
+static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
     m5208_timer_state *s;
     QEMUBH *bh;
     int i;
 
-    iomemtype = cpu_register_io_memory(m5208_sys_readfn,
-                                       m5208_sys_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
     /* SDRAMC.  */
-    cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
+    memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
+    memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
     /* Timers.  */
     for (i = 0; i < 2; i++) {
-        s = (m5208_timer_state *)qemu_mallocz(sizeof(m5208_timer_state));
+        s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state));
         bh = qemu_bh_new(m5208_timer_trigger, s);
         s->timer = ptimer_init(bh);
-        iomemtype = cpu_register_io_memory(m5208_timer_readfn,
-                                           m5208_timer_writefn, s,
-                                           DEVICE_NATIVE_ENDIAN);
-        cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
-                                     iomemtype);
+        memory_region_init_io(&s->iomem, &m5208_timer_ops, s,
+                              "m5208-timer", 0x00004000);
+        memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
+                                    &s->iomem);
         s->irq = pic[4 + i];
     }
 }
@@ -207,6 +196,9 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     uint64_t elf_entry;
     target_phys_addr_t entry;
     qemu_irq *pic;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "m5208";
@@ -221,12 +213,12 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     /* TODO: Configure BARs.  */
 
     /* DRAM at 0x40000000 */
-    cpu_register_physical_memory(0x40000000, ram_size,
-        qemu_ram_alloc(NULL, "mcf5208.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "mcf5208.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
 
     /* Internal SRAM.  */
-    cpu_register_physical_memory(0x80000000, 16384,
-        qemu_ram_alloc(NULL, "mcf5208.sram", 16384) | IO_MEM_RAM);
+    memory_region_init_ram(sram, NULL, "mcf5208.sram", 16384);
+    memory_region_add_subregion(address_space_mem, 0x80000000, sram);
 
     /* Internal peripherals.  */
     pic = mcf_intc_init(0xfc048000, env);
@@ -235,7 +227,7 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
     mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
 
-    mcf5208_sys_init(pic);
+    mcf5208_sys_init(address_space_mem, pic);
 
     if (nb_nics > 1) {
         fprintf(stderr, "Too many NICs\n");
index 21035da3451eb485692a5d19ad74cf66a526b11e..42a5d779521188cf4eb96bf565edd209146aec13 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 #include "hw.h"
 #include "net.h"
@@ -447,7 +447,7 @@ static void mcf_fec_cleanup(VLANClientState *nc)
 
     cpu_unregister_io_memory(s->mmio_index);
 
-    qemu_free(s);
+    g_free(s);
 }
 
 static NetClientInfo net_mcf_fec_info = {
@@ -464,14 +464,14 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
 
     qemu_check_nic_model(nd, "mcf_fec");
 
-    s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
+    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
     s->irq = irq;
     s->mmio_index = cpu_register_io_memory(mcf_fec_readfn,
                                            mcf_fec_writefn, s,
                                            DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x400, s->mmio_index);
 
-    memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
+    s->conf.macaddr = nd->macaddr;
     s->conf.vlan = nd->vlan;
     s->conf.peer = nd->netdev;
 
index ac04295198f05ae9034f877794a2518ab07c47a0..99092e72d1ce1eb6d5cba59c5f733a28e6982f33 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 #include "hw.h"
 #include "mcf.h"
@@ -144,7 +144,7 @@ qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
     mcf_intc_state *s;
     int iomemtype;
 
-    s = qemu_mallocz(sizeof(mcf_intc_state));
+    s = g_malloc0(sizeof(mcf_intc_state));
     s->env = env;
     mcf_intc_reset(s);
 
index db57096af22d103cf4cc64058336e446b1641844..e6b2ab067abff272c7b6fb6a22100f86e5514123 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 #include "hw.h"
 #include "mcf.h"
@@ -110,7 +110,7 @@ static void mcf_uart_do_tx(mcf_uart_state *s)
 {
     if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
         if (s->chr)
-            qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
+            qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
         s->sr |= MCF_UART_TxEMP;
     }
     if (s->tx_enabled) {
@@ -272,7 +272,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
 {
     mcf_uart_state *s;
 
-    s = qemu_mallocz(sizeof(mcf_uart_state));
+    s = g_malloc0(sizeof(mcf_uart_state));
     s->chr = chr;
     s->irq = irq;
     if (chr) {
index 7c59382fbea4271241e2536fb911e3db02a5f979..8b5623ce282802cb4b02c19b6a40a915c7f13ab7 100644 (file)
  */
 
 #include "hw.h"
-#include "pc.h"
+#include "microblaze_pic_cpu.h"
 
 #define D(x)
 
-void pic_info(Monitor *mon)
-{}
-void irq_info(Monitor *mon)
-{}
-
 static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
 {
     CPUState *env = (CPUState *)opaque;
@@ -43,7 +38,6 @@ static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
         cpu_reset_interrupt(env, type);
 }
 
-qemu_irq *microblaze_pic_init_cpu(CPUState *env);
 qemu_irq *microblaze_pic_init_cpu(CPUState *env)
 {
     return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
diff --git a/hw/microblaze_pic_cpu.h b/hw/microblaze_pic_cpu.h
new file mode 100644 (file)
index 0000000..4c76275
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef MICROBLAZE_PIC_CPU_H
+#define MICROBLAZE_PIC_CPU_H
+
+#include "qemu-common.h"
+
+qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+
+#endif /*  MICROBLAZE_PIC_CPU_H */
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
new file mode 100644 (file)
index 0000000..5c5ed27
--- /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;
+    MemoryRegion regs_region;
+
+    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 uint64_t ac97_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
+{
+    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 unknown 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, uint64_t value,
+                       unsigned size)
+{
+    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 unknown register 0x"
+                TARGET_FMT_plx, addr);
+        break;
+    }
+
+}
+
+static const MemoryRegionOps ac97_mmio_ops = {
+    .read = ac97_read,
+    .write = ac97_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    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);
+
+    memory_region_init_io(&s->regs_region, &ac97_mmio_ops, s,
+            "milkymist-ac97", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..17c840f
--- /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;
+    MemoryRegion regs_region;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistHpdmcState MilkymistHpdmcState;
+
+static uint64_t hpdmc_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
+{
+    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, uint64_t value,
+                        unsigned size)
+{
+    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 const MemoryRegionOps hpdmc_mmio_ops = {
+    .read = hpdmc_read,
+    .write = hpdmc_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s,
+            "milkymist-hpdmc", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..9f358a7
--- /dev/null
@@ -0,0 +1,223 @@
+#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 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, 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..fb6e558
--- /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;
+    MemoryRegion regs_region;
+    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 uint64_t memcard_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    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 unknown 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, uint64_t value,
+                          unsigned size)
+{
+    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 unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps memcard_mmio_ops = {
+    .read = memcard_read,
+    .write = memcard_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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;
+
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
+
+    memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
+            "milkymist-memcard", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..85d9400
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ *  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;
+    MemoryRegion buffers;
+    MemoryRegion regs_region;
+
+    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)",
+                txcount, 64);
+        goto err;
+    }
+
+    if (txcount > MINIMAC2_MTU) {
+        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
+                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)",
+                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 uint64_t
+minimac2_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    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, uint64_t value,
+               unsigned size)
+{
+    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 const MemoryRegionOps minimac2_ops = {
+    .read = minimac2_read,
+    .write = minimac2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+    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);
+
+    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
+                          "milkymist-minimac2", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    /* register buffers memory */
+    memory_region_init_ram(&s->buffers, NULL, "milkymist-minimac2.buffers",
+                           buffers_size);
+    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
+    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
+    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
+
+    sysbus_add_memory(dev, s->buffers_base, &s->buffers);
+
+    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..672f6e4
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ *  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;
+    MemoryRegion regs_region;
+    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", 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?");
+                    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 uint64_t pfpu_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
+{
+    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, uint64_t value,
+                       unsigned size)
+{
+    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 const MemoryRegionOps pfpu_mmio_ops = {
+    .read = pfpu_read,
+    .write = pfpu_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s,
+            "milkymist-pfpu", MICROCODE_END * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..ec5f334
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  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 "hid.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;
+    HIDState hid_kbd;
+    HIDState hid_mouse;
+
+    MemoryRegion regs_region;
+    MemoryRegion pmem;
+    MemoryRegion dmem;
+    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 */
+    uint8_t mouse_hid_buffer[4];
+
+    /* keyboard state */
+    uint8_t kbd_hid_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint64_t softusb_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    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, uint64_t value,
+              unsigned size)
+{
+    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 const MemoryRegionOps softusb_mmio_ops = {
+    .read = softusb_read,
+    .write = softusb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+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", 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", 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", 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", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 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_hid_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_kbd_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
+
+    if (len == 8) {
+        softusb_kbd_changed(s);
+    }
+}
+
+static void softusb_mouse_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s =
+            container_of(hs, MilkymistSoftUsbState, hid_mouse);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
+            sizeof(s->mouse_hid_buffer));
+
+    if (len == 4) {
+        softusb_mouse_changed(s);
+    }
+}
+
+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;
+    }
+    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
+    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
+
+    hid_reset(&s->hid_kbd);
+    hid_reset(&s->hid_mouse);
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
+                          "milkymist-softusb", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    /* register pmem and dmem */
+    memory_region_init_ram(&s->pmem, NULL, "milkymist-softusb.pmem",
+                           s->pmem_size);
+    sysbus_add_memory(dev, s->pmem_base, &s->pmem);
+    memory_region_init_ram(&s->dmem, NULL, "milkymist-softusb.dmem",
+                           s->dmem_size);
+    sysbus_add_memory(dev, s->dmem_base, &s->dmem);
+
+    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
+    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
+
+    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_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
+        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(mouse_hid_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..5783f08
--- /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;
+    MemoryRegion regs_region;
+
+    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 uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
+{
+    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 unknown 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, uint64_t value,
+                         unsigned size)
+{
+    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 unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps sysctl_mmio_ops = {
+    .read = sysctl_read,
+    .write = sysctl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    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);
+
+    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
+            "milkymist-sysctl", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..aad0ed0
--- /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;
+} QEMU_PACKED;
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    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 uint64_t tmu2_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
+{
+    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", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned");
+    }
+}
+
+static void tmu2_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
+{
+    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 const MemoryRegionOps tmu2_mmio_ops = {
+    .read = tmu2_read,
+    .write = tmu2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
+            "milkymist-tmu2", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..5404ca9
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *  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_STAT,
+    R_CTRL,
+    R_DBG,
+    R_MAX
+};
+
+enum {
+    STAT_THRE   = (1<<0),
+    STAT_RX_EVT = (1<<1),
+    STAT_TX_EVT = (1<<2),
+};
+
+enum {
+    CTRL_RX_IRQ_EN = (1<<0),
+    CTRL_TX_IRQ_EN = (1<<1),
+    CTRL_THRU_EN   = (1<<2),
+};
+
+enum {
+    DBG_BREAK_EN = (1<<0),
+};
+
+struct MilkymistUartState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static void uart_update_irq(MilkymistUartState *s)
+{
+    int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
+    int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
+    int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
+    int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
+
+    if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
+        trace_milkymist_uart_raise_irq();
+        qemu_irq_raise(s->irq);
+    } else {
+        trace_milkymist_uart_lower_irq();
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint64_t uart_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
+{
+    MilkymistUartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[addr];
+        break;
+    case R_DIV:
+    case R_STAT:
+    case R_CTRL:
+    case R_DBG:
+        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, uint64_t value,
+                       unsigned size)
+{
+    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_fe_write(s->chr, &ch, 1);
+        }
+        s->regs[R_STAT] |= STAT_TX_EVT;
+        break;
+    case R_DIV:
+    case R_CTRL:
+    case R_DBG:
+        s->regs[addr] = value;
+        break;
+
+    case R_STAT:
+        /* write one to clear bits */
+        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
+        break;
+
+    default:
+        error_report("milkymist_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_mmio_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    MilkymistUartState *s = opaque;
+
+    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
+
+    s->regs[R_STAT] |= STAT_RX_EVT;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    MilkymistUartState *s = opaque;
+
+    return !(s->regs[R_STAT] & STAT_RX_EVT);
+}
+
+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;
+    }
+
+    /* THRE is always set */
+    s->regs[R_STAT] = STAT_THRE;
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
+            "milkymist-uart", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..be81abd
--- /dev/null
@@ -0,0 +1,320 @@
+
+/*
+ *  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;
+    MemoryRegion regs_region;
+    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 uint64_t vgafb_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
+{
+    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, uint64_t value,
+                        unsigned size)
+{
+    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 const MemoryRegionOps vgafb_mmio_ops = {
+    .read = vgafb_read,
+    .write = vgafb_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
+            "milkymist-vgafb", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
+
+    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..b7a8c1c
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  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"
+#include "exec-memory.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;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
+    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 = g_malloc0(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);
+
+    memory_region_init_ram(phys_sdram, NULL, "milkymist.sdram", sdram_size);
+    memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Numonyx JS28F256J3F105 */
+    pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
+                          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]);
+    milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
+            80000000, 0x10014d31, 0x0000041f, 0x00000001);
+    milkymist_hpdmc_create(0x60002000);
+    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
+    milkymist_memcard_create(0x60004000);
+    milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
+    milkymist_pfpu_create(0x60006000, irq[8]);
+    milkymist_tmu2_create(0x60007000, irq[9]);
+    milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
+    milkymist_softusb_create(0x6000f000, irq[15],
+            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 73aa8f8b0e95db6cc4c079dc5deb7a3c00ba2ca7..6fa9a3ae7571636d22b4591b42c16b4c944ca3d7 100644 (file)
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,18 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
 /* bonito.c */
 PCIBus *bonito_init(qemu_irq *pic);
 
-/* ds1225y.c */
-void *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
-void ds1225y_set_protection(void *opaque, int protection);
-
-/* g364fb.c */
-int g364fb_mm_init(target_phys_addr_t vram_base,
-                   target_phys_addr_t ctrl_base, int it_shift,
-                   qemu_irq irq);
-
-/* mipsnet.c */
-void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
-
 /* jazz_led.c */
 void jazz_led_init(target_phys_addr_t base);
 
index 3b0abdba8a4571a065ff1edcc381f57fd0a3acff..04921c147e7689980756bbfaf2cf6ffd0923c67d 100644 (file)
@@ -38,6 +38,7 @@
 #include "vt82c686.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define DEBUG_FULONG2E_INIT
 
@@ -67,7 +68,7 @@
 #define FULONG2E_ATI_SLOT        6
 #define FULONG2E_RTL8139_SLOT    7
 
-static PITState *pit;
+static ISADevice *pit;
 
 static struct _loaderparams {
     int ram_size;
@@ -140,7 +141,7 @@ static int64_t load_kernel (CPUState *env)
 
     /* Setup prom parameters. */
     prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
-    prom_buf = qemu_malloc(prom_size);
+    prom_buf = g_malloc(prom_size);
 
     prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
     if (initrd_size > 0) {
@@ -256,18 +257,18 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
                         const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    unsigned long ram_offset, bios_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     long bios_size;
     int64_t kernel_entry;
     qemu_irq *i8259;
     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 */
@@ -290,12 +291,12 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     bios_size = 1024 * 1024;
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
+    memory_region_init_ram(ram, NULL, "fulong2e.ram", ram_size);
+    memory_region_init_ram(bios, NULL, "fulong2e.bios", bios_size);
+    memory_region_set_readonly(bios, true);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset);
-    cpu_register_physical_memory(0x1fc00000LL,
-                                          bios_size, bios_offset | IO_MEM_ROM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
 
     /* We do not support flash operation, just loading pmon.bin as raw BIOS.
      * Please use -L to set the BIOS path and -bios to set bios name. */
@@ -306,7 +307,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
         loaderparams.kernel_cmdline = kernel_cmdline;
         loaderparams.initrd_filename = initrd_filename;
         kernel_entry = load_kernel (env);
-        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
     } else {
         if (bios_name == NULL) {
                 bios_name = FULONG_BIOSNAME;
@@ -315,7 +316,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
         if (filename) {
             bios_size = load_image_targphys(filename, 0x1fc00000LL,
                                             BIOS_SIZE);
-            qemu_free(filename);
+            g_free(filename);
         } else {
             bios_size = -1;
         }
@@ -330,46 +331,34 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
 
-    /* Interrupt controller */
-    /* The 8259 -> IP5  */
-    i8259 = i8259_init(env->irq[5]);
-
     /* North bridge, Bonito --> IP2 */
     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) {
-        fprintf(stderr, "vt82c686b_init error \n");
+        fprintf(stderr, "vt82c686b_init error\n");
         exit(1);
     }
 
+    /* Interrupt controller */
+    /* The 8259 -> IP5  */
+    i8259 = i8259_init(env->irq[5]);
     isa_bus_irqs(i8259);
+
     vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
     usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));
     usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));
 
     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, isa_get_irq(0));
+    pit = pit_init(0x40, 0);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
 
index 85eba5a69a8a18d1dd1956ca0bcf874d09e6f827..14beea2d64b5b760b0797f45baeeb6e27af8bd5c 100644 (file)
@@ -37,6 +37,8 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "sysbus.h"
+#include "exec-memory.h"
 
 enum jazz_model_e
 {
@@ -50,44 +52,42 @@ static void main_cpu_reset(void *opaque)
     cpu_reset(env);
 }
 
-static uint32_t rtc_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t rtc_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     return cpu_inw(0x71);
 }
 
-static void rtc_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void rtc_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t val, unsigned size)
 {
     cpu_outw(0x71, val & 0xff);
 }
 
-static CPUReadMemoryFunc * const rtc_read[3] = {
-    rtc_readb,
-    rtc_readb,
-    rtc_readb,
+static const MemoryRegionOps rtc_ops = {
+    .read = rtc_read,
+    .write = rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const rtc_write[3] = {
-    rtc_writeb,
-    rtc_writeb,
-    rtc_writeb,
-};
-
-static void dma_dummy_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t dma_dummy_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     /* Nothing to do. That is only to ensure that
      * the current DMA acknowledge cycle is completed. */
+    return 0xff;
 }
 
-static CPUReadMemoryFunc * const dma_dummy_read[3] = {
-    NULL,
-    NULL,
-    NULL,
-};
+static void dma_dummy_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+}
 
-static CPUWriteMemoryFunc * const dma_dummy_write[3] = {
-    dma_dummy_writeb,
-    dma_dummy_writeb,
-    dma_dummy_writeb,
+static const MemoryRegionOps dma_dummy_ops = {
+    .read = dma_dummy_read,
+    .write = dma_dummy_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 #define MAGNUM_BIOS_SIZE_MAX 0x7e000
@@ -102,10 +102,11 @@ static void cpu_request_exit(void *opaque, int irq, int level)
     }
 }
 
-static
-void mips_jazz_init (ram_addr_t ram_size,
-                     const char *cpu_model,
-                     enum jazz_model_e jazz_model)
+static void mips_jazz_init(MemoryRegion *address_space,
+                           MemoryRegion *address_space_io,
+                           ram_addr_t ram_size,
+                           const char *cpu_model,
+                           enum jazz_model_e jazz_model)
 {
     char *filename;
     int bios_size, n;
@@ -113,14 +114,19 @@ void mips_jazz_init (ram_addr_t ram_size,
     qemu_irq *rc4030, *i8259;
     rc4030_dma *dmas;
     void* rc4030_opaque;
-    int s_rtc, s_dma_dummy;
+    MemoryRegion *rtc = g_new(MemoryRegion, 1);
+    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+    MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
     NICInfo *nd;
-    PITState *pit;
+    DeviceState *dev;
+    SysBusDevice *sysbus;
+    ISADevice *pit;
     DriveInfo *fds[MAX_FD];
     qemu_irq esp_reset, dma_enable;
     qemu_irq *cpu_exit_irq;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    MemoryRegion *bios2 = g_new(MemoryRegion, 1);
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -139,14 +145,15 @@ void mips_jazz_init (ram_addr_t ram_size,
     qemu_register_reset(main_cpu_reset, env);
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "mips_jazz.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "mips_jazz.ram", ram_size);
+    memory_region_add_subregion(address_space, 0, ram);
 
-    bios_offset = qemu_ram_alloc(NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
-    cpu_register_physical_memory(0xfff00000LL,
-                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_init_ram(bios, NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
+    memory_region_set_readonly(bios, true);
+    memory_region_init_alias(bios2, "mips_jazz.bios", bios,
+                             0, MAGNUM_BIOS_SIZE);
+    memory_region_add_subregion(address_space, 0x1fc00000LL, bios);
+    memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
 
     /* load the BIOS image. */
     if (bios_name == NULL)
@@ -155,7 +162,7 @@ void mips_jazz_init (ram_addr_t ram_size,
     if (filename) {
         bios_size = load_image_targphys(filename, 0xfff00000LL,
                                         MAGNUM_BIOS_SIZE);
-        qemu_free(filename);
+        g_free(filename);
     } else {
         bios_size = -1;
     }
@@ -171,17 +178,16 @@ void mips_jazz_init (ram_addr_t ram_size,
 
     /* Chipset */
     rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas);
-    s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
+    memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
+    memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
 
     /* ISA devices */
+    isa_bus_new(NULL, address_space_io);
     i8259 = i8259_init(env->irq[4]);
-    isa_bus_new(NULL);
     isa_bus_irqs(i8259);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
-    pit = pit_init(0x40, i8259[0]);
+    pit = pit_init(0x40, 0);
     pcspk_init(pit);
 
     /* ISA IO space at 0x90000000 */
@@ -191,10 +197,24 @@ void mips_jazz_init (ram_addr_t ram_size,
     /* Video card */
     switch (jazz_model) {
     case JAZZ_MAGNUM:
-        g364fb_mm_init(0x40000000, 0x60000000, 0, rc4030[3]);
+        dev = qdev_create(NULL, "sysbus-g364");
+        qdev_init_nofail(dev);
+        sysbus = sysbus_from_qdev(dev);
+        sysbus_mmio_map(sysbus, 0, 0x60080000);
+        sysbus_mmio_map(sysbus, 1, 0x40000000);
+        sysbus_connect_irq(sysbus, 0, rc4030[3]);
+        {
+            /* Simple ROM, so user doesn't have to provide one */
+            MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
+            memory_region_init_ram(rom_mr, NULL, "g364fb.rom", 0x80000);
+            memory_region_set_readonly(rom_mr, true);
+            uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
+            memory_region_add_subregion(address_space, 0x60000000, rom_mr);
+            rom[0] = 0x10; /* Mips G364 */
+        }
         break;
     case JAZZ_PICA61:
-        isa_vga_mm_init(0x40000000, 0x60000000, 0);
+        isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory());
         break;
     default:
         break;
@@ -204,7 +224,7 @@ void mips_jazz_init (ram_addr_t ram_size,
     for (n = 0; n < nb_nics; n++) {
         nd = &nd_table[n];
         if (!nd->model)
-            nd->model = qemu_strdup("dp83932");
+            nd->model = g_strdup("dp83932");
         if (strcmp(nd->model, "dp83932") == 0) {
             dp83932_init(nd, 0x80001000, 2, rc4030[4],
                          rc4030_opaque, rc4030_dma_memory_rw);
@@ -235,27 +255,21 @@ void mips_jazz_init (ram_addr_t ram_size,
 
     /* Real time clock */
     rtc_init(1980, NULL);
-    s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL,
-                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
+    memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000);
+    memory_region_add_subregion(address_space, 0x80004000, rtc);
 
     /* Keyboard (i8042) */
-    i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0x1000, 0x1);
+    i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
+    memory_region_add_subregion(address_space, 0x80005000, i8042);
 
     /* Serial ports */
     if (serial_hds[0]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 1);
-#else
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 0);
-#endif
+        serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
+                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 1);
-#else
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 0);
-#endif
+        serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
+                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
     }
 
     /* Parallel port */
@@ -266,8 +280,11 @@ void mips_jazz_init (ram_addr_t ram_size,
     /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
     audio_init(i8259, NULL);
 
-    /* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
-    ds1225y_init(0x80009000, "nvram");
+    /* NVRAM */
+    dev = qdev_create(NULL, "ds1225y");
+    qdev_init_nofail(dev);
+    sysbus = sysbus_from_qdev(dev);
+    sysbus_mmio_map(sysbus, 0, 0x80009000);
 
     /* LED indicator */
     jazz_led_init(0x8000f000);
@@ -279,7 +296,8 @@ void mips_magnum_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(ram_size, cpu_model, JAZZ_MAGNUM);
+        mips_jazz_init(get_system_memory(), get_system_io(),
+                       ram_size, cpu_model, JAZZ_MAGNUM);
 }
 
 static
@@ -288,7 +306,8 @@ void mips_pica61_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(ram_size, cpu_model, JAZZ_PICA61);
+    mips_jazz_init(get_system_memory(), get_system_io(),
+                   ram_size, cpu_model, JAZZ_PICA61);
 }
 
 static QEMUMachine mips_magnum_machine = {
index 7211d98a196fa9f9ba58c4b0ca156199774943dc..941b9bdd8e89d4d35e3cc2b3286fd8274f71f2c3 100644 (file)
@@ -46,6 +46,8 @@
 #include "elf.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
+#include "sysbus.h"             /* SysBusDevice */
 
 //#define DEBUG_BOARD_INIT
 
@@ -56,6 +58,9 @@
 #define MAX_IDE_BUS 2
 
 typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_lo; /* 0 - 0x900 */
+    MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
     uint32_t leds;
     uint32_t brk;
     uint32_t gpout;
@@ -68,7 +73,12 @@ typedef struct {
     SerialState *uart;
 } MaltaFPGAState;
 
-static PITState *pit;
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq *i8259;
+} MaltaState;
+
+static ISADevice *pit;
 
 static struct _loaderparams {
     int ram_size;
@@ -92,8 +102,8 @@ static void malta_fpga_update_display(void *opaque)
     }
     leds_text[8] = '\0';
 
-    qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
-    qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+    qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
+    qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
 }
 
 /*
@@ -214,7 +224,8 @@ static void eeprom24c0x_write(int scl, int sda)
     eeprom.sda = sda;
 }
 
-static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t malta_fpga_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     MaltaFPGAState *s = opaque;
     uint32_t val = 0;
@@ -301,8 +312,8 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
+static void malta_fpga_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     MaltaFPGAState *s = opaque;
     uint32_t saddr;
@@ -327,7 +338,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
 
     /* ASCIIWORD Register */
     case 0x00410:
-        snprintf(s->display_text, 9, "%08X", val);
+        snprintf(s->display_text, 9, "%08X", (uint32_t)val);
         malta_fpga_update_display(s);
         break;
 
@@ -387,16 +398,10 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const malta_fpga_read[] = {
-   malta_fpga_readl,
-   malta_fpga_readl,
-   malta_fpga_readl
-};
-
-static CPUWriteMemoryFunc * const malta_fpga_write[] = {
-   malta_fpga_writel,
-   malta_fpga_writel,
-   malta_fpga_writel
+static const MemoryRegionOps malta_fpga_ops = {
+    .read = malta_fpga_read,
+    .write = malta_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void malta_fpga_reset(void *opaque)
@@ -417,39 +422,38 @@ static void malta_fpga_reset(void *opaque)
 
 static void malta_fpga_led_init(CharDriverState *chr)
 {
-    qemu_chr_printf(chr, "\e[HMalta LEDBAR\r\n");
-    qemu_chr_printf(chr, "+--------+\r\n");
-    qemu_chr_printf(chr, "+        +\r\n");
-    qemu_chr_printf(chr, "+--------+\r\n");
-    qemu_chr_printf(chr, "\n");
-    qemu_chr_printf(chr, "Malta ASCII\r\n");
-    qemu_chr_printf(chr, "+--------+\r\n");
-    qemu_chr_printf(chr, "+        +\r\n");
-    qemu_chr_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "+        +\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "\n");
+    qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    qemu_chr_fe_printf(chr, "+        +\r\n");
+    qemu_chr_fe_printf(chr, "+--------+\r\n");
 }
 
-static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
+static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
+         target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
 {
     MaltaFPGAState *s;
-    int malta;
 
-    s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
+    s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
 
-    malta = cpu_register_io_memory(malta_fpga_read,
-                                   malta_fpga_write, s,
-                                   DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &malta_fpga_ops, s,
+                          "malta-fpga", 0x100000);
+    memory_region_init_alias(&s->iomem_lo, "malta-fpga",
+                             &s->iomem, 0, 0x900);
+    memory_region_init_alias(&s->iomem_hi, "malta-fpga",
+                             &s->iomem, 0xa00, 0x10000-0xa00);
 
-    cpu_register_physical_memory(base, 0x900, malta);
-    /* 0xa00 is less than a page, so will still get the right offsets.  */
-    cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
+    memory_region_add_subregion(address_space, base, &s->iomem_lo);
+    memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
-    s->display = qemu_chr_open("fpga", "vc:320x200", malta_fpga_led_init);
+    s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 1);
-#else
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 0);
-#endif
+    s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
+                             230400, uart_chr, DEVICE_NATIVE_ENDIAN);
 
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
@@ -709,7 +713,7 @@ static int64_t load_kernel (void)
 
     /* Setup prom parameters. */
     prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
-    prom_buf = qemu_malloc(prom_size);
+    prom_buf = g_malloc(prom_size);
 
     prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
     if (initrd_size > 0) {
@@ -732,6 +736,12 @@ static int64_t load_kernel (void)
     return kernel_entry;
 }
 
+static void malta_mips_config(CPUState *env)
+{
+    env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
+                         ((smp_cpus * env->nr_threads - 1) << CP0MVPC0_PTC);
+}
+
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
@@ -743,6 +753,8 @@ static void main_cpu_reset(void *opaque)
     if (loaderparams.kernel_filename) {
         env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
     }
+
+    malta_mips_config(env);
 }
 
 static void cpu_request_exit(void *opaque, int irq, int level)
@@ -761,16 +773,17 @@ void mips_malta_init (ram_addr_t ram_size,
                       const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    pflash_t *fl;
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
     target_long bios_size;
     int64_t kernel_entry;
     PCIBus *pci_bus;
     CPUState *env;
-    qemu_irq *i8259;
+    qemu_irq *isa_irq;
     qemu_irq *cpu_exit_irq;
     int piix4_devfn;
-    uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
     DriveInfo *dinfo;
@@ -780,12 +793,17 @@ void mips_malta_init (ram_addr_t ram_size,
     int fl_sectors = 0;
     int be;
 
+    DeviceState *dev = qdev_create(NULL, "mips-malta");
+    MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
+
+    qdev_init_nofail(dev);
+
     /* Make sure the first 3 serial ports are associated with a device. */
     for(i = 0; i < 3; i++) {
         if (!serial_hds[i]) {
             char label[32];
             snprintf(label, sizeof(label), "serial%d", i);
-            serial_hds[i] = qemu_chr_open(label, "null", NULL);
+            serial_hds[i] = qemu_chr_new(label, "null", NULL);
         }
     }
 
@@ -797,12 +815,19 @@ void mips_malta_init (ram_addr_t ram_size,
         cpu_model = "24Kf";
 #endif
     }
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
+
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        /* Init internal devices */
+        cpu_mips_irq_init_cpu(env);
+        cpu_mips_clock_init(env);
+        qemu_register_reset(main_cpu_reset, env);
     }
-    qemu_register_reset(main_cpu_reset, env);
+    env = first_cpu;
 
     /* allocate RAM */
     if (ram_size > (256 << 20)) {
@@ -811,17 +836,8 @@ void mips_malta_init (ram_addr_t ram_size,
                 ((unsigned int)ram_size / (1 << 20)));
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "mips_malta.bios", BIOS_SIZE);
-
-
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
-
-    /* Map the bios at two physical locations, as on the real board. */
-    cpu_register_physical_memory(0x1e000000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_init_ram(ram, NULL, "mips_malta.ram", ram_size);
+    memory_region_add_subregion(system_memory, 0, ram);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
@@ -829,17 +845,24 @@ void mips_malta_init (ram_addr_t ram_size,
     be = 0;
 #endif
     /* FPGA */
-    malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+    malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]);
 
     /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
     if (kernel_filename) {
         /* Write a small bootloader to the flash location. */
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "mips_malta.bios", BIOS_SIZE);
+        memory_region_set_readonly(bios, true);
+        memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
+        /* Map the bios at two physical locations, as on the real board. */
+        memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
+        memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias);
         loaderparams.ram_size = ram_size;
         loaderparams.kernel_filename = kernel_filename;
         loaderparams.kernel_cmdline = kernel_cmdline;
         loaderparams.initrd_filename = initrd_filename;
         kernel_entry = load_kernel();
-        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
     } else {
         dinfo = drive_get(IF_PFLASH, 0, fl_idx);
         if (dinfo) {
@@ -848,15 +871,31 @@ void mips_malta_init (ram_addr_t ram_size,
             fl_sectors = bios_size >> 16;
 #ifdef DEBUG_BOARD_INIT
             printf("Register parallel flash %d size " TARGET_FMT_lx " at "
-                   "offset %08lx addr %08llx '%s' %x\n",
-                   fl_idx, bios_size, bios_offset, 0x1e000000LL,
+                   "addr %08llx '%s' %x\n",
+                   fl_idx, bios_size, 0x1e000000LL,
                    bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-            pflash_cfi01_register(0x1e000000LL, bios_offset,
-                                  dinfo->bdrv, 65536, fl_sectors,
-                                  4, 0x0000, 0x0000, 0x0000, 0x0000, be);
-            fl_idx++;
+            fl = pflash_cfi01_register(0x1e000000LL,
+                                       NULL, "mips_malta.bios", BIOS_SIZE,
+                                       dinfo->bdrv, 65536, fl_sectors,
+                                       4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+            bios = pflash_cfi01_get_memory(fl);
+            /* Map the bios at two physical locations, as on the real board. */
+            memory_region_init_alias(bios_alias, "bios.1fc",
+                                     bios, 0, BIOS_SIZE);
+            memory_region_add_subregion(system_memory, 0x1fc00000LL,
+                                        bios_alias);
+           fl_idx++;
         } else {
+            bios = g_new(MemoryRegion, 1);
+            memory_region_init_ram(bios, NULL, "mips_malta.bios", BIOS_SIZE);
+            memory_region_set_readonly(bios, true);
+            memory_region_init_alias(bios_alias, "bios.1fc",
+                                     bios, 0, BIOS_SIZE);
+            /* Map the bios at two physical locations, as on the real board. */
+            memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
+            memory_region_add_subregion(system_memory, 0x1fc00000LL,
+                                        bios_alias);
             /* Load a BIOS image. */
             if (bios_name == NULL)
                 bios_name = BIOS_FILENAME;
@@ -864,7 +903,7 @@ void mips_malta_init (ram_addr_t ram_size,
             if (filename) {
                 bios_size = load_image_targphys(filename, 0x1fc00000LL,
                                                 BIOS_SIZE);
-                qemu_free(filename);
+                g_free(filename);
             } else {
                 bios_size = -1;
             }
@@ -879,7 +918,7 @@ void mips_malta_init (ram_addr_t ram_size,
            a neat trick which allows bi-endian firmware. */
 #ifndef TARGET_WORDS_BIGENDIAN
         {
-            uint32_t *addr = qemu_get_ram_ptr(bios_offset);;
+            uint32_t *addr = memory_region_get_ram_ptr(bios);
             uint32_t *end = addr + bios_size;
             while (addr < end) {
                 bswap32s(addr);
@@ -891,46 +930,41 @@ void mips_malta_init (ram_addr_t ram_size,
     /* Board ID = 0x420 (Malta Board with CoreLV)
        XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
        map to the board ID. */
-    stl_p(qemu_get_ram_ptr(bios_offset) + 0x10, 0x00000420);
+    stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420);
 
     /* Init internal devices */
     cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
 
-    /* Interrupt controller */
-    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
-    i8259 = i8259_init(env->irq[2]);
+    /*
+     * We have a circular dependency problem: pci_bus depends on isa_irq,
+     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
+     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
+     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
+     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
+     */
+    isa_irq = qemu_irq_proxy(&s->i8259, 16);
 
     /* Northbridge */
-    pci_bus = gt64120_register(i8259);
+    pci_bus = gt64120_register(isa_irq);
 
     /* Southbridge */
+    ide_drive_get(hd, MAX_IDE_BUS);
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
+    piix4_devfn = piix4_init(pci_bus, 80);
 
-    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);
-    }
+    /* Interrupt controller */
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    s->i8259 = i8259_init(env->irq[2]);
 
-    piix4_devfn = piix4_init(pci_bus, 80);
-    isa_bus_irqs(i8259);
+    isa_bus_irqs(s->i8259);
     pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
     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);
-    }
-    pit = pit_init(0x40, isa_get_irq(0));
+    /* 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);
 
@@ -957,22 +991,47 @@ void mips_malta_init (ram_addr_t ram_size,
     if (cirrus_vga_enabled) {
         pci_cirrus_vga_init(pci_bus);
     } else if (vmsvga_enabled) {
-        pci_vmsvga_init(pci_bus);
+        if (!pci_vmsvga_init(pci_bus)) {
+            fprintf(stderr, "Warning: vmware_vga not available,"
+                    " using standard VGA instead\n");
+            pci_vga_init(pci_bus);
+        }
     } else if (std_vga_enabled) {
         pci_vga_init(pci_bus);
     }
 }
 
+static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo mips_malta_device = {
+    .init = mips_malta_sysbus_device_init,
+    .qdev.name  = "mips-malta",
+    .qdev.size  = sizeof(MaltaState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
 static QEMUMachine mips_malta_machine = {
     .name = "malta",
     .desc = "MIPS Malta Core LV",
     .init = mips_malta_init,
+    .max_cpus = 16,
     .is_default = 1,
 };
 
+static void mips_malta_device_init(void)
+{
+    sysbus_register_withprop(&mips_malta_device);
+}
+
 static void mips_malta_machine_init(void)
 {
     qemu_register_machine(&mips_malta_machine);
 }
 
+device_init(mips_malta_device_init);
 machine_init(mips_malta_machine_init);
index 380a7eb78c4f7e21a467b0099418c56f77d6fe06..b56cba619e08c1081181933a306b9359c70c1095 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU/mipssim emulation
  *
- * Emulates a very simple machine model similiar to the one use by the
+ * Emulates a very simple machine model similar to the one used by the
  * proprietary MIPS emulator.
  * 
  * Copyright (c) 2007 Thiemo Seufer
@@ -35,6 +35,8 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "elf.h"
+#include "sysbus.h"
+#include "exec-memory.h"
 
 static struct _loaderparams {
     int ram_size;
@@ -112,6 +114,22 @@ static void main_cpu_reset(void *opaque)
     }
 }
 
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "mipsnet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(get_system_io(),
+                                base,
+                                sysbus_mmio_get_region(s, 0));
+}
+
 static void
 mips_mipssim_init (ram_addr_t ram_size,
                    const char *boot_device,
@@ -119,8 +137,9 @@ mips_mipssim_init (ram_addr_t ram_size,
                    const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     CPUState *env;
     ResetData *reset_info;
     int bios_size;
@@ -138,27 +157,27 @@ mips_mipssim_init (ram_addr_t ram_size,
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info = g_malloc0(sizeof(ResetData));
     reset_info->env = env;
     reset_info->vector = env->active_tc.PC;
     qemu_register_reset(main_cpu_reset, reset_info);
 
     /* Allocate RAM. */
-    ram_offset = qemu_ram_alloc(NULL, "mips_mipssim.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "mips_mipssim.bios", BIOS_SIZE);
+    memory_region_init_ram(ram, NULL, "mips_mipssim.ram", ram_size);
+    memory_region_init_ram(bios, NULL, "mips_mipssim.bios", BIOS_SIZE);
+    memory_region_set_readonly(bios, true);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Map the BIOS / boot exception handler. */
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
     /* Load a BIOS / boot exception handler image. */
     if (bios_name == NULL)
         bios_name = BIOS_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
     if (filename) {
         bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
-        qemu_free(filename);
+        g_free(filename);
     } else {
         bios_size = -1;
     }
index fb34dcfcdc49c6e3c03cc5e21c6f5b065131d0bb..d0564d4449d3d49fff0f6f99a5d111540f618ae8 100644 (file)
@@ -23,6 +23,7 @@
 #include "elf.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MAX_IDE_BUS 2
 
@@ -30,7 +31,7 @@ static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
 
-static PITState *pit; /* PIT i8254 */
+static ISADevice *pit; /* PIT i8254 */
 
 /* i8254 PIT is attached to the IRQ0 at PIC i8259 */
 
@@ -41,8 +42,8 @@ static struct _loaderparams {
     const char *initrd_filename;
 } loaderparams;
 
-static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void mips_qemu_write (void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     if ((addr & 0xffff) == 0 && val == 42)
         qemu_system_reset_request ();
@@ -50,25 +51,18 @@ static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
         qemu_system_shutdown_request ();
 }
 
-static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t mips_qemu_read (void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     return 0;
 }
 
-static CPUWriteMemoryFunc * const mips_qemu_write[] = {
-    &mips_qemu_writel,
-    &mips_qemu_writel,
-    &mips_qemu_writel,
+static const MemoryRegionOps mips_qemu_ops = {
+    .read = mips_qemu_read,
+    .write = mips_qemu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mips_qemu_read[] = {
-    &mips_qemu_readl,
-    &mips_qemu_readl,
-    &mips_qemu_readl,
-};
-
-static int mips_qemu_iomemtype = 0;
-
 typedef struct ResetData {
     CPUState *env;
     uint64_t vector;
@@ -126,7 +120,7 @@ static int64_t load_kernel(void)
 
     /* Store command line.  */
     params_size = 264;
-    params_buf = qemu_malloc(params_size);
+    params_buf = g_malloc(params_size);
 
     params_buf[0] = tswap32(ram_size);
     params_buf[1] = tswap32(0x12345678);
@@ -162,8 +156,10 @@ void mips_r4k_init (ram_addr_t ram_size,
                     const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
     int bios_size;
     CPUState *env;
     ResetData *reset_info;
@@ -186,7 +182,7 @@ void mips_r4k_init (ram_addr_t ram_size,
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info = g_malloc0(sizeof(ResetData));
     reset_info->env = env;
     reset_info->vector = env->active_tc.PC;
     qemu_register_reset(main_cpu_reset, reset_info);
@@ -198,16 +194,12 @@ void mips_r4k_init (ram_addr_t ram_size,
                 ((unsigned int)ram_size / (1 << 20)));
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "mips_r4k.ram", ram_size);
+    memory_region_init_ram(ram, NULL, "mips_r4k.ram", ram_size);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
-    if (!mips_qemu_iomemtype) {
-        mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read,
-                                                     mips_qemu_write, NULL,
-                                                     DEVICE_NATIVE_ENDIAN);
-    }
-    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
+    memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000);
+    memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem);
 
     /* Try to load a BIOS image. If this fails, we continue regardless,
        but initialize the hardware ourselves. When a kernel gets
@@ -227,15 +219,15 @@ void mips_r4k_init (ram_addr_t ram_size,
     be = 0;
 #endif
     if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
-        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", BIOS_SIZE);
-       cpu_register_physical_memory(0x1fc00000, BIOS_SIZE,
-                                     bios_offset | IO_MEM_ROM);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "mips_r4k.bios", BIOS_SIZE);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
 
         load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
     } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
         uint32_t mips_rom = 0x00400000;
-        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", mips_rom);
-        if (!pflash_cfi01_register(0x1fc00000, bios_offset,
+        if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
                                    dinfo->bdrv, sector_len,
                                    mips_rom / sector_len,
                                    4, 0, 0, 0, 0, be)) {
@@ -248,7 +240,7 @@ void mips_r4k_init (ram_addr_t ram_size,
                bios_name);
     }
     if (filename) {
-        qemu_free(filename);
+        g_free(filename);
     }
 
     if (kernel_filename) {
@@ -264,8 +256,8 @@ void mips_r4k_init (ram_addr_t ram_size,
     cpu_mips_clock_init(env);
 
     /* The PIC is attached to the MIPS CPU INT0 pin */
+    isa_bus_new(NULL, get_system_io());
     i8259 = i8259_init(env->irq[2]);
-    isa_bus_new(NULL);
     isa_bus_irqs(i8259);
 
     rtc_init(2000, NULL);
@@ -274,7 +266,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
-    pit = pit_init(0x40, i8259[0]);
+    pit = pit_init(0x40, 0);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
@@ -287,15 +279,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 9c95f282a2745ceb59ecc65a36b4be523a8e5423..cf6ac694e365c6097c5435681e1d543ab6e52b69 100644 (file)
@@ -47,7 +47,7 @@ static void cpu_mips_timer_update(CPUState *env)
     uint64_t now, next;
     uint32_t wait;
 
-    now = qemu_get_clock(vm_clock);
+    now = qemu_get_clock_ns(vm_clock);
     wait = env->CP0_Compare - env->CP0_Count -
            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
     next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
@@ -71,7 +71,7 @@ uint32_t cpu_mips_get_count (CPUState *env)
     } else {
         uint64_t now;
 
-        now = qemu_get_clock(vm_clock);
+        now = qemu_get_clock_ns(vm_clock);
         if (qemu_timer_pending(env->timer)
             && qemu_timer_expired(env->timer, now)) {
             /* The timer has already expired.  */
@@ -90,7 +90,7 @@ void cpu_mips_store_count (CPUState *env, uint32_t count)
     else {
         /* Store new count register */
         env->CP0_Count =
-            count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+            count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
                                        TIMER_FREQ, get_ticks_per_sec());
         /* Update timer timer */
         cpu_mips_timer_update(env);
@@ -115,7 +115,7 @@ void cpu_mips_start_count(CPUState *env)
 void cpu_mips_stop_count(CPUState *env)
 {
     /* Store the current value */
-    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
                                          TIMER_FREQ, get_ticks_per_sec());
 }
 
@@ -141,7 +141,7 @@ static void mips_timer_cb (void *opaque)
 
 void cpu_mips_clock_init (CPUState *env)
 {
-    env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
+    env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env);
     env->CP0_Compare = 0;
     cpu_mips_store_count(env, 1);
 }
index c5e54ffc359208c5eae19c242a4556262010f59e..605367bc5ffc87d5cf5baeb705463d6aa8923e00 100644 (file)
@@ -1,12 +1,7 @@
 #include "hw.h"
-#include "mips.h"
 #include "net.h"
-#include "isa.h"
-
-//#define DEBUG_MIPSNET_SEND
-//#define DEBUG_MIPSNET_RECEIVE
-//#define DEBUG_MIPSNET_DATA
-//#define DEBUG_MIPSNET_IRQ
+#include "trace.h"
+#include "sysbus.h"
 
 /* MIPSnet register offsets */
 
@@ -25,6 +20,8 @@
 #define MAX_ETH_FRAME_SIZE     1514
 
 typedef struct MIPSnetState {
+    SysBusDevice busdev;
+
     uint32_t busy;
     uint32_t rx_count;
     uint32_t rx_read;
@@ -33,7 +30,7 @@ typedef struct MIPSnetState {
     uint32_t intctl;
     uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
     uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
-    int io_base;
+    MemoryRegion io;
     qemu_irq irq;
     NICState *nic;
     NICConf conf;
@@ -54,9 +51,7 @@ static void mipsnet_reset(MIPSnetState *s)
 static void mipsnet_update_irq(MIPSnetState *s)
 {
     int isr = !!s->intctl;
-#ifdef DEBUG_MIPSNET_IRQ
-    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
-#endif
+    trace_mipsnet_irq(isr, s->intctl);
     qemu_set_irq(s->irq, isr);
 }
 
@@ -80,9 +75,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-#ifdef DEBUG_MIPSNET_RECEIVE
-    printf("mipsnet: receiving len=%zu\n", size);
-#endif
+    trace_mipsnet_receive(size);
     if (!mipsnet_can_receive(nc))
         return -1;
 
@@ -103,7 +96,8 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
     return size;
 }
 
-static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
+static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned int size)
 {
     MIPSnetState *s = opaque;
     int ret = 0;
@@ -144,20 +138,17 @@ static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
     default:
         break;
     }
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+    trace_mipsnet_read(addr, ret);
     return ret;
 }
 
-static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t val, unsigned int size)
 {
     MIPSnetState *s = opaque;
 
     addr &= 0x3f;
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+    trace_mipsnet_write(addr, val);
     switch (addr) {
     case MIPSNET_TX_DATA_COUNT:
        s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
@@ -181,9 +172,7 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         s->tx_buffer[s->tx_written++] = val;
         if (s->tx_written == s->tx_count) {
             /* Send buffer. */
-#ifdef DEBUG_MIPSNET_SEND
-            printf("mipsnet: sending len=%d\n", s->tx_count);
-#endif
+            trace_mipsnet_send(s->tx_count);
             qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
             s->tx_count = s->tx_written = 0;
             s->intctl |= MIPSNET_INTCTL_TXDONE;
@@ -202,48 +191,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);
-
-    isa_unassign_ioport(s->io_base, 36);
-
-    qemu_free(s);
+    s->nic = NULL;
 }
 
 static NetClientInfo net_mipsnet_info = {
@@ -254,35 +224,50 @@ static NetClientInfo net_mipsnet_info = {
     .cleanup = mipsnet_cleanup,
 };
 
-void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
-{
-    MIPSnetState *s;
-
-    qemu_check_nic_model(nd, "mipsnet");
+static MemoryRegionOps mipsnet_ioport_ops = {
+    .read = mipsnet_ioport_read,
+    .write = mipsnet_ioport_write,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 4,
+};
 
-    s = qemu_mallocz(sizeof(MIPSnetState));
+static int mipsnet_sysbus_init(SysBusDevice *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
 
-    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
+    sysbus_init_mmio_region(dev, &s->io);
+    sysbus_init_irq(dev, &s->irq);
 
-    s->io_base = base;
-    s->irq = irq;
+    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
-    if (nd) {
-        memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
-        s->conf.vlan = nd->vlan;
-        s->conf.peer = nd->netdev;
+    return 0;
+}
 
-        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
-                              nd->model, nd->name, s);
+static void mipsnet_sysbus_reset(DeviceState *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
+    mipsnet_reset(s);
+}
 
-        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+static SysBusDeviceInfo mipsnet_info = {
+    .init = mipsnet_sysbus_init,
+    .qdev.name = "mipsnet",
+    .qdev.desc = "MIPS Simulator network device",
+    .qdev.size = sizeof(MIPSnetState),
+    .qdev.vmsd = &vmstate_mipsnet,
+    .qdev.reset = mipsnet_sysbus_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+        DEFINE_PROP_END_OF_LIST(),
     }
+};
 
-    mipsnet_reset(s);
-    register_savevm(NULL, "mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
+static void mipsnet_register_devices(void)
+{
+    sysbus_register_withprop(&mipsnet_info);
 }
+
+device_init(mipsnet_register_devices)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
new file mode 100644 (file)
index 0000000..c685f3e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * QEMU PowerPC MPC8544 global util pseudo-device
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <alex@csgraf.de>
+ *
+ * This 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.
+ *
+ * *****************************************************************
+ *
+ * The documentation for this device is noted in the MPC8544 documentation,
+ * file name "MPC8544ERM.pdf". You can easily find it on the web.
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+
+#define MPC8544_GUTS_MMIO_SIZE        0x1000
+#define MPC8544_GUTS_RSTCR_RESET      0x02
+
+#define MPC8544_GUTS_ADDR_PORPLLSR    0x00
+#define MPC8544_GUTS_ADDR_PORBMSR     0x04
+#define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
+#define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
+#define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
+#define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
+#define MPC8544_GUTS_ADDR_GPPORCR     0x20
+#define MPC8544_GUTS_ADDR_GPIOCR      0x30
+#define MPC8544_GUTS_ADDR_GPOUTDR     0x40
+#define MPC8544_GUTS_ADDR_GPINDR      0x50
+#define MPC8544_GUTS_ADDR_PMUXCR      0x60
+#define MPC8544_GUTS_ADDR_DEVDISR     0x70
+#define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
+#define MPC8544_GUTS_ADDR_MCPSUMR     0x90
+#define MPC8544_GUTS_ADDR_RSTRSCR     0x94
+#define MPC8544_GUTS_ADDR_PVR         0xA0
+#define MPC8544_GUTS_ADDR_SVR         0xA4
+#define MPC8544_GUTS_ADDR_RSTCR       0xB0
+#define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
+#define MPC8544_GUTS_ADDR_DDRCSR      0xB20
+#define MPC8544_GUTS_ADDR_DDRCDR      0xB24
+#define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
+#define MPC8544_GUTS_ADDR_CLKOCR      0xE00
+#define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
+#define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
+#define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
+
+struct GutsState {
+    SysBusDevice busdev;
+};
+
+typedef struct GutsState GutsState;
+
+static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t value = 0;
+    CPUState *env = cpu_single_env;
+
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_PVR:
+        value = env->spr[SPR_PVR];
+        break;
+    case MPC8544_GUTS_ADDR_SVR:
+        value = env->spr[SPR_E500_SVR];
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
+        break;
+    }
+
+    return value;
+}
+
+static CPUReadMemoryFunc * const mpc8544_guts_read[] = {
+    NULL,
+    NULL,
+    &mpc8544_guts_read32,
+};
+
+static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_RSTCR:
+        if (value & MPC8544_GUTS_RSTCR_RESET) {
+            qemu_system_reset_request();
+        }
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register write: %x = %x\n",
+                (int)addr, value);
+        break;
+    }
+}
+
+static CPUWriteMemoryFunc * const mpc8544_guts_write[] = {
+    NULL,
+    NULL,
+    &mpc8544_guts_write32,
+};
+
+static int mpc8544_guts_initfn(SysBusDevice *dev)
+{
+    GutsState *s;
+    int iomem;
+
+    s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev));
+
+    iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s,
+                                   DEVICE_BIG_ENDIAN);
+    sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem);
+
+    return 0;
+}
+
+static SysBusDeviceInfo mpc8544_guts_info = {
+    .init         = mpc8544_guts_initfn,
+    .qdev.name    = "mpc8544-guts",
+    .qdev.size    = sizeof(GutsState),
+};
+
+static void mpc8544_guts_register(void)
+{
+    sysbus_register_withprop(&mpc8544_guts_info);
+}
+device_init(mpc8544_guts_register);
index fc0521549ac65932c73d4e4ea505a0c521c62d11..d6175cfc2d3bc16baa8f3ea06a80fe943004421f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -40,6 +40,8 @@ typedef struct mpcore_priv_state {
     int iomemtype;
     mpcore_timer_state timer[8];
     uint32_t num_cpu;
+    MemoryRegion iomem;
+    MemoryRegion container;
 } mpcore_priv_state;
 
 /* Per-CPU Timers.  */
@@ -63,7 +65,7 @@ static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
     if (s->count == 0)
         return;
     if (restart)
-        s->tick = qemu_get_clock(vm_clock);
+        s->tick = qemu_get_clock_ns(vm_clock);
     s->tick += (int64_t)s->count * mpcore_timer_scale(s);
     qemu_mod_timer(s->timer, s->tick);
 }
@@ -92,7 +94,7 @@ static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
         if (((s->control & 1) == 0) || (s->count == 0))
             return 0;
         /* Slow and ugly, but hopefully won't happen too often.  */
-        val = s->tick - qemu_get_clock(vm_clock);
+        val = s->tick - qemu_get_clock_ns(vm_clock);
         val /= mpcore_timer_scale(s);
         if (val < 0)
             val = 0;
@@ -145,13 +147,14 @@ static void mpcore_timer_init(mpcore_priv_state *mpcore,
 {
     s->id = id;
     s->mpcore = mpcore;
-    s->timer = qemu_new_timer(vm_clock, mpcore_timer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, mpcore_timer_tick, s);
 }
 
 
 /* Per-CPU private memory mapped IO.  */
 
-static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
+                                 unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     int id;
@@ -203,7 +206,7 @@ bad_reg:
 }
 
 static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
-                          uint32_t value)
+                              uint64_t value, unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     int id;
@@ -250,23 +253,19 @@ bad_reg:
     hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
 }
 
-static CPUReadMemoryFunc * const mpcore_priv_readfn[] = {
-   mpcore_priv_read,
-   mpcore_priv_read,
-   mpcore_priv_read
+static const MemoryRegionOps mpcore_priv_ops = {
+    .read = mpcore_priv_read,
+    .write = mpcore_priv_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpcore_priv_writefn[] = {
-   mpcore_priv_write,
-   mpcore_priv_write,
-   mpcore_priv_write
-};
-
-static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base)
+static void mpcore_priv_map_setup(mpcore_priv_state *s)
 {
-    mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
-    cpu_register_physical_memory(base, 0x1000, s->iomemtype);
-    cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+    memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
+    memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
+                          0x1000);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
 }
 
 static int mpcore_priv_init(SysBusDevice *dev)
@@ -275,10 +274,8 @@ static int mpcore_priv_init(SysBusDevice *dev)
     int i;
 
     gic_init(&s->gic, s->num_cpu);
-    s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn,
-                                          mpcore_priv_writefn, s,
-                                          DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
+    mpcore_priv_map_setup(s);
+    sysbus_init_mmio_region(dev, &s->container);
     for (i = 0; i < s->num_cpu * 2; i++) {
         mpcore_timer_init(s, &s->timer[i], i);
     }
index 3dc3a24b779002b848301776220670f8b8b035f2..f214fcf5793b649ff0b3165ef76a07846753a142 100644 (file)
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -155,7 +155,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
 
     if (msi_per_vector_mask) {
-        /* Make mask bits 0 to nr_vectors - 1 writeable. */
+        /* Make mask bits 0 to nr_vectors - 1 writable. */
         pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
                      0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
     }
@@ -164,9 +164,17 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
 
 void msi_uninit(struct PCIDevice *dev)
 {
-    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
-    uint8_t cap_size = msi_cap_sizeof(flags);
-    pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
+    uint16_t flags;
+    uint8_t cap_size;
+
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSI)) {
+        return;
+    }
+    flags = pci_get_word(dev->config + msi_flags_off(dev));
+    cap_size = msi_cap_sizeof(flags);
+    pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
+    dev->cap_present &= ~QEMU_PCI_CAP_MSI;
+
     MSI_DEV_PRINTF(dev, "uninit\n");
 }
 
@@ -241,7 +249,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
                    "notify vector 0x%x"
                    " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
                    vector, address, data);
-    stl_phys(address, data);
+    stl_le_phys(address, data);
 }
 
 /* call this function after updating configs by pci_default_write_config(). */
index daaf9b7878a52a89713fa8d1cad8f042e6d035ea..149eed22fb271a8b9bd87dd880b14ed6b12aeb9c 100644 (file)
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -16,9 +16,6 @@
 #include "pci.h"
 #include "range.h"
 
-/* MSI-X capability structure */
-#define MSIX_TABLE_OFFSET 4
-#define MSIX_PBA_OFFSET 8
 #define MSIX_CAP_LENGTH 12
 
 /* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
 #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
 #define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
 
-/* MSI-X table format */
-#define MSIX_MSG_ADDR 0
-#define MSIX_MSG_UPPER_ADDR 4
-#define MSIX_MSG_DATA 8
-#define MSIX_VECTOR_CTRL 12
-#define MSIX_ENTRY_SIZE 16
-#define MSIX_VECTOR_MASK 0x1
-
 /* How much space does an MSIX table need. */
 /* The spec requires giving the table structure
  * a 4K aligned region all by itself. */
@@ -82,18 +71,20 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
 
     pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
     /* Table on top of BAR */
-    pci_set_long(config + MSIX_TABLE_OFFSET, bar_size | bar_nr);
+    pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
     /* Pending bits on top of that */
-    pci_set_long(config + MSIX_PBA_OFFSET, (bar_size + MSIX_PAGE_PENDING) |
+    pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
                  bar_nr);
     pdev->msix_cap = config_offset;
-    /* Make flags bit writeable. */
+    /* Make flags bit writable. */
     pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
            MSIX_MASKALL_MASK;
+    pdev->msix_function_masked = true;
     return 0;
 }
 
-static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
@@ -102,12 +93,6 @@ static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
     return pci_get_long(page + offset);
 }
 
-static uint32_t msix_mmio_read_unallowed(void *opaque, target_phys_addr_t addr)
-{
-    fprintf(stderr, "MSI-X: only dword read is allowed!\n");
-    return 0;
-}
-
 static uint8_t msix_pending_mask(int vector)
 {
     return 1 << (vector % 8);
@@ -133,107 +118,120 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
     *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
 }
 
-static int msix_function_masked(PCIDevice *dev)
+static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
 {
-    return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
+    unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
+    return fmask || dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
 }
 
-static int msix_is_masked(PCIDevice *dev, int vector)
+static bool msix_is_masked(PCIDevice *dev, int vector)
 {
-    unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
-    return msix_function_masked(dev) ||
-          dev->msix_table_page[offset] & MSIX_VECTOR_MASK;
+    return msix_vector_masked(dev, vector, dev->msix_function_masked);
 }
 
-static void msix_handle_mask_update(PCIDevice *dev, int vector)
+static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
 {
-    if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
+    bool is_masked = msix_is_masked(dev, vector);
+    if (is_masked == was_masked) {
+        return;
+    }
+
+    if (!is_masked && msix_is_pending(dev, vector)) {
         msix_clr_pending(dev, vector);
         msix_notify(dev, vector);
     }
 }
 
+static void msix_update_function_masked(PCIDevice *dev)
+{
+    dev->msix_function_masked = !msix_enabled(dev) ||
+        (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK);
+}
+
 /* Handle MSI-X capability config write. */
 void msix_write_config(PCIDevice *dev, uint32_t addr,
                        uint32_t val, int len)
 {
     unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
     int vector;
+    bool was_masked;
 
     if (!range_covers_byte(addr, len, enable_pos)) {
         return;
     }
 
+    was_masked = dev->msix_function_masked;
+    msix_update_function_masked(dev);
+
     if (!msix_enabled(dev)) {
         return;
     }
 
     pci_device_deassert_intx(dev);
 
-    if (msix_function_masked(dev)) {
+    if (dev->msix_function_masked == was_masked) {
         return;
     }
 
     for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
-        msix_handle_mask_update(dev, vector);
+        msix_handle_mask_update(dev, vector,
+                                msix_vector_masked(dev, vector, was_masked));
     }
 }
 
-static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
 {
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
-    int vector = offset / MSIX_ENTRY_SIZE;
-    pci_set_long(dev->msix_table_page + offset, val);
-    msix_handle_mask_update(dev, vector);
-}
+    int vector = offset / PCI_MSIX_ENTRY_SIZE;
+    bool was_masked;
 
-static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr,
-                                      uint32_t val)
-{
-    fprintf(stderr, "MSI-X: only dword write is allowed!\n");
-}
+    /* MSI-X page includes a read-only PBA and a writeable Vector Control. */
+    if (vector >= dev->msix_entries_nr) {
+        return;
+    }
 
-static CPUWriteMemoryFunc * const msix_mmio_write[] = {
-    msix_mmio_write_unallowed, msix_mmio_write_unallowed, msix_mmio_writel
-};
+    was_masked = msix_is_masked(dev, vector);
+    pci_set_long(dev->msix_table_page + offset, val);
+    msix_handle_mask_update(dev, vector, was_masked);
+}
 
-static CPUReadMemoryFunc * const msix_mmio_read[] = {
-    msix_mmio_read_unallowed, msix_mmio_read_unallowed, msix_mmio_readl
+static const MemoryRegionOps msix_mmio_ops = {
+    .read = msix_mmio_read,
+    .write = msix_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-/* Should be called from device's map method. */
-void msix_mmio_map(PCIDevice *d, int region_num,
-                   pcibus_t addr, pcibus_t size, int type)
+static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
 {
     uint8_t *config = d->config + d->msix_cap;
-    uint32_t table = pci_get_long(config + MSIX_TABLE_OFFSET);
+    uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
     uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
     /* TODO: for assigned devices, we'll want to make it possible to map
      * pending bits separately in case they are in a separate bar. */
-    int table_bir = table & PCI_MSIX_FLAGS_BIRMASK;
 
-    if (table_bir != region_num)
-        return;
-    if (size <= offset)
-        return;
-    cpu_register_physical_memory(addr + offset, size - offset,
-                                 d->msix_mmio_index);
+    memory_region_add_subregion(bar, offset, &d->msix_mmio);
 }
 
 static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
 {
     int vector;
     for (vector = 0; vector < nentries; ++vector) {
-        unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
-        dev->msix_table_page[offset] |= MSIX_VECTOR_MASK;
+        unsigned offset =
+            vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
+        dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
     }
 }
 
 /* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
  * modified, it should be retrieved with msix_bar_size. */
 int msix_init(struct PCIDevice *dev, unsigned short nentries,
+              MemoryRegion *bar,
               unsigned bar_nr, unsigned bar_size)
 {
     int ret;
@@ -244,19 +242,14 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
-    dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
+    dev->msix_entry_used = g_malloc0(MSIX_MAX_ENTRIES *
                                         sizeof *dev->msix_entry_used);
 
-    dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
+    dev->msix_table_page = g_malloc0(MSIX_PAGE_SIZE);
     msix_mask_all(dev, nentries);
 
-    dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read,
-                                                  msix_mmio_write, dev,
-                                                  DEVICE_NATIVE_ENDIAN);
-    if (dev->msix_mmio_index == -1) {
-        ret = -EBUSY;
-        goto err_index;
-    }
+    memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
+                          "msix", MSIX_PAGE_SIZE);
 
     dev->msix_entries_nr = nentries;
     ret = msix_add_config(dev, nentries, bar_nr, bar_size);
@@ -264,15 +257,15 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
         goto err_config;
 
     dev->cap_present |= QEMU_PCI_CAP_MSIX;
+    msix_mmio_setup(dev, bar);
     return 0;
 
 err_config:
     dev->msix_entries_nr = 0;
-    cpu_unregister_io_memory(dev->msix_mmio_index);
-err_index:
-    qemu_free(dev->msix_table_page);
+    memory_region_destroy(&dev->msix_mmio);
+    g_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
-    qemu_free(dev->msix_entry_used);
+    g_free(dev->msix_entry_used);
     dev->msix_entry_used = NULL;
     return ret;
 }
@@ -288,7 +281,7 @@ static void msix_free_irq_entries(PCIDevice *dev)
 }
 
 /* Clean up resources for the device. */
-int msix_uninit(PCIDevice *dev)
+int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
 {
     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
         return 0;
@@ -296,10 +289,11 @@ int msix_uninit(PCIDevice *dev)
     dev->msix_cap = 0;
     msix_free_irq_entries(dev);
     dev->msix_entries_nr = 0;
-    cpu_unregister_io_memory(dev->msix_mmio_index);
-    qemu_free(dev->msix_table_page);
+    memory_region_del_subregion(bar, &dev->msix_mmio);
+    memory_region_destroy(&dev->msix_mmio);
+    g_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
-    qemu_free(dev->msix_entry_used);
+    g_free(dev->msix_entry_used);
     dev->msix_entry_used = NULL;
     dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
     return 0;
@@ -313,7 +307,7 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
         return;
     }
 
-    qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
+    qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
 }
 
@@ -327,8 +321,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
     }
 
     msix_free_irq_entries(dev);
-    qemu_get_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
+    qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
     qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
+    msix_update_function_masked(dev);
 }
 
 /* Does device support MSI-X? */
@@ -355,7 +350,7 @@ uint32_t msix_bar_size(PCIDevice *dev)
 /* Send an MSI-X message */
 void msix_notify(PCIDevice *dev, unsigned vector)
 {
-    uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
+    uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
     uint64_t address;
     uint32_t data;
 
@@ -366,10 +361,9 @@ void msix_notify(PCIDevice *dev, unsigned vector)
         return;
     }
 
-    address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
-    address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
-    data = pci_get_long(table_entry + MSIX_MSG_DATA);
-    stl_phys(address, data);
+    address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
+    data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
+    stl_le_phys(address, data);
 }
 
 void msix_reset(PCIDevice *dev)
index a9f7993c396a5923b147526793e8ba7613c77747..7e04336618a44b1ec17cdda89d63bb783b60544b 100644 (file)
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -5,15 +5,13 @@
 #include "pci.h"
 
 int msix_init(PCIDevice *pdev, unsigned short nentries,
+              MemoryRegion *bar,
               unsigned bar_nr, unsigned bar_size);
 
 void msix_write_config(PCIDevice *pci_dev, uint32_t address,
                        uint32_t val, int len);
 
-void msix_mmio_map(PCIDevice *pci_dev, int region_num,
-                   pcibus_t addr, pcibus_t size, int type);
-
-int msix_uninit(PCIDevice *d);
+int msix_uninit(PCIDevice *d, MemoryRegion *bar);
 
 void msix_save(PCIDevice *dev, QEMUFile *f);
 void msix_load(PCIDevice *dev, QEMUFile *f);
index 05f893ca9393c9b1aa7b0f2e37714c14e7cc0467..c3b57ea31c73d1fd8d9bc1b5196422fd1fcce82b 100644 (file)
@@ -50,7 +50,7 @@ static void msmouse_event(void *opaque,
     /* We always send the packet of, so that we do not have to keep track
        of previous state of the middle button. This can potentially confuse
        some very old drivers for two button mice though. */
-    qemu_chr_read(chr, bytes, 4);
+    qemu_chr_be_write(chr, bytes, 4);
 }
 
 static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
@@ -61,18 +61,19 @@ static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int
 
 static void msmouse_chr_close (struct CharDriverState *chr)
 {
-    qemu_free (chr);
+    g_free (chr);
 }
 
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = msmouse_chr_write;
     chr->chr_close = msmouse_chr_close;
 
     qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
index 456cb214241cddac2d1640bc574c190937478f14..8b853b35bf35d254a5ff711815be342a49a48b9e 100644 (file)
@@ -1,2 +1,2 @@
 /* msmouse.c */
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr);
index 5252fc5e1c41af014e04663d8eda81aeec977ef7..7bcd5d75e819cf75d0e82c00d909cb85c15fcd84 100644 (file)
@@ -8,8 +8,7 @@
  * This code is licensed under the GNU GPL v2.
  */
 #include "hw.h"
-#include "pxa.h"
-#include "mainstone.h"
+#include "sysbus.h"
 
 /* Mainstone FPGA for extern irqs */
 #define FPGA_GPIO_PIN  0
 #define MST_PCMCIA0            0xe0
 #define MST_PCMCIA1            0xe4
 
+#define MST_PCMCIAx_READY      (1 << 10)
+#define MST_PCMCIAx_nCD                (1 << 5)
+
+#define MST_PCMCIA_CD0_IRQ     9
+#define MST_PCMCIA_CD1_IRQ     13
+
 typedef struct mst_irq_state{
-       qemu_irq *parent;
-       qemu_irq *pins;
+       SysBusDevice busdev;
+
+       qemu_irq parent;
 
        uint32_t prev_level;
        uint32_t leddat1;
@@ -46,34 +52,37 @@ typedef struct mst_irq_state{
        uint32_t pcmcia1;
 }mst_irq_state;
 
-static void
-mst_fpga_update_gpio(mst_irq_state *s)
-{
-       uint32_t level, diff;
-       int bit;
-       level = s->prev_level ^ s->intsetclr;
-
-       for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-               bit = ffs(diff) - 1;
-               qemu_set_irq(s->pins[bit], (level >> bit) & 1 );
-       }
-       s->prev_level = level;
-}
-
 static void
 mst_fpga_set_irq(void *opaque, int irq, int level)
 {
        mst_irq_state *s = (mst_irq_state *)opaque;
+       uint32_t oldint = s->intsetclr & s->intmskena;
 
        if (level)
                s->prev_level |= 1u << irq;
        else
                s->prev_level &= ~(1u << irq);
 
-       if(s->intmskena & (1u << irq)) {
-               s->intsetclr = 1u << irq;
-               qemu_set_irq(s->parent[0], level);
+       switch(irq) {
+       case MST_PCMCIA_CD0_IRQ:
+               if (level)
+                       s->pcmcia0 &= ~MST_PCMCIAx_nCD;
+               else
+                       s->pcmcia0 |=  MST_PCMCIAx_nCD;
+               break;
+       case MST_PCMCIA_CD1_IRQ:
+               if (level)
+                       s->pcmcia1 &= ~MST_PCMCIAx_nCD;
+               else
+                       s->pcmcia1 |=  MST_PCMCIAx_nCD;
+               break;
        }
+
+       if ((s->intmskena & (1u << irq)) && level)
+               s->intsetclr |= 1u << irq;
+
+       if (oldint != (s->intsetclr & s->intmskena))
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
 }
 
 
@@ -109,7 +118,7 @@ mst_fpga_readb(void *opaque, target_phys_addr_t addr)
                return s->pcmcia1;
        default:
                printf("Mainstone - mst_fpga_readb: Bad register offset "
-                       REG_FMT " \n", addr);
+                       "0x" TARGET_FMT_plx "\n", addr);
        }
        return 0;
 }
@@ -145,22 +154,24 @@ mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
        case MST_MSCRD:
                s->mscrd =  value;
                break;
-       case MST_INTMSKENA:     /* Mask interupt */
+       case MST_INTMSKENA:     /* Mask interrupt */
                s->intmskena = (value & 0xFEEFF);
-               mst_fpga_update_gpio(s);
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
                break;
        case MST_INTSETCLR:     /* clear or set interrupt */
                s->intsetclr = (value & 0xFEEFF);
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
                break;
+               /* For PCMCIAx allow the to change only power and reset */
        case MST_PCMCIA0:
-               s->pcmcia0 = value;
+               s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
                break;
        case MST_PCMCIA1:
-               s->pcmcia1 = value;
+               s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
                break;
        default:
                printf("Mainstone - mst_fpga_writeb: Bad register offset "
-                       REG_FMT " \n", addr);
+                       "0x" TARGET_FMT_plx "\n", addr);
        }
 }
 
@@ -175,66 +186,70 @@ static CPUWriteMemoryFunc * const mst_fpga_writefn[] = {
        mst_fpga_writeb,
 };
 
-static void
-mst_fpga_save(QEMUFile *f, void *opaque)
-{
-       struct mst_irq_state *s = (mst_irq_state *) opaque;
-
-       qemu_put_be32s(f, &s->prev_level);
-       qemu_put_be32s(f, &s->leddat1);
-       qemu_put_be32s(f, &s->leddat2);
-       qemu_put_be32s(f, &s->ledctrl);
-       qemu_put_be32s(f, &s->gpswr);
-       qemu_put_be32s(f, &s->mscwr1);
-       qemu_put_be32s(f, &s->mscwr2);
-       qemu_put_be32s(f, &s->mscwr3);
-       qemu_put_be32s(f, &s->mscrd);
-       qemu_put_be32s(f, &s->intmskena);
-       qemu_put_be32s(f, &s->intsetclr);
-       qemu_put_be32s(f, &s->pcmcia0);
-       qemu_put_be32s(f, &s->pcmcia1);
-}
 
-static int
-mst_fpga_load(QEMUFile *f, void *opaque, int version_id)
+static int mst_fpga_post_load(void *opaque, int version_id)
 {
        mst_irq_state *s = (mst_irq_state *) opaque;
 
-       qemu_get_be32s(f, &s->prev_level);
-       qemu_get_be32s(f, &s->leddat1);
-       qemu_get_be32s(f, &s->leddat2);
-       qemu_get_be32s(f, &s->ledctrl);
-       qemu_get_be32s(f, &s->gpswr);
-       qemu_get_be32s(f, &s->mscwr1);
-       qemu_get_be32s(f, &s->mscwr2);
-       qemu_get_be32s(f, &s->mscwr3);
-       qemu_get_be32s(f, &s->mscrd);
-       qemu_get_be32s(f, &s->intmskena);
-       qemu_get_be32s(f, &s->intsetclr);
-       qemu_get_be32s(f, &s->pcmcia0);
-       qemu_get_be32s(f, &s->pcmcia1);
+       qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
        return 0;
 }
 
-qemu_irq *mst_irq_init(PXA2xxState *cpu, uint32_t base, int irq)
+static int mst_fpga_init(SysBusDevice *dev)
 {
        mst_irq_state *s;
        int iomemtype;
-       qemu_irq *qi;
 
-       s = (mst_irq_state  *)
-               qemu_mallocz(sizeof(mst_irq_state));
+       s = FROM_SYSBUS(mst_irq_state, dev);
 
-       s->parent = &cpu->pic[irq];
+       s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+       s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+
+       sysbus_init_irq(dev, &s->parent);
 
        /* alloc the external 16 irqs */
-       qi  = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS);
-       s->pins = qi;
+       qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS);
 
        iomemtype = cpu_register_io_memory(mst_fpga_readfn,
                mst_fpga_writefn, s, DEVICE_NATIVE_ENDIAN);
-       cpu_register_physical_memory(base, 0x00100000, iomemtype);
-       register_savevm(NULL, "mainstone_fpga", 0, 0, mst_fpga_save,
-                        mst_fpga_load, s);
-       return qi;
+       sysbus_init_mmio(dev, 0x00100000, iomemtype);
+       return 0;
+}
+
+static VMStateDescription vmstate_mst_fpga_regs = {
+       .name = "mainstone_fpga",
+       .version_id = 0,
+       .minimum_version_id = 0,
+       .minimum_version_id_old = 0,
+       .post_load = mst_fpga_post_load,
+       .fields = (VMStateField []) {
+               VMSTATE_UINT32(prev_level, mst_irq_state),
+               VMSTATE_UINT32(leddat1, mst_irq_state),
+               VMSTATE_UINT32(leddat2, mst_irq_state),
+               VMSTATE_UINT32(ledctrl, mst_irq_state),
+               VMSTATE_UINT32(gpswr, mst_irq_state),
+               VMSTATE_UINT32(mscwr1, mst_irq_state),
+               VMSTATE_UINT32(mscwr2, mst_irq_state),
+               VMSTATE_UINT32(mscwr3, mst_irq_state),
+               VMSTATE_UINT32(mscrd, mst_irq_state),
+               VMSTATE_UINT32(intmskena, mst_irq_state),
+               VMSTATE_UINT32(intsetclr, mst_irq_state),
+               VMSTATE_UINT32(pcmcia0, mst_irq_state),
+               VMSTATE_UINT32(pcmcia1, mst_irq_state),
+               VMSTATE_END_OF_LIST(),
+       },
+};
+
+static SysBusDeviceInfo mst_fpga_info = {
+       .init = mst_fpga_init,
+       .qdev.name = "mainstone-fpga",
+       .qdev.desc = "Mainstone II FPGA",
+       .qdev.size = sizeof(mst_irq_state),
+       .qdev.vmsd = &vmstate_mst_fpga_regs,
+};
+
+static void mst_fpga_register(void)
+{
+       sysbus_register_withprop(&mst_fpga_info);
 }
+device_init(mst_fpga_register);
index 0d2bfb4973b4b5fcd05324188c42a16958b02703..b4484a3262f6f73233b37b4003d1a9bb2794b6cf 100644 (file)
@@ -97,11 +97,11 @@ typedef struct {
 
 static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
 {
-    int len = strlen(cmdline) + 1;
     target_phys_addr_t p = s->offset_cmdlines;
+    char *b = (char *)s->mb_buf + p;
 
-    pstrcpy((char *)s->mb_buf + p, len, cmdline);
-    s->offset_cmdlines += len;
+    get_opt_value(b, strlen(cmdline) + 1, cmdline);
+    s->offset_cmdlines += strlen(b) + 1;
     return s->mb_buf_phys + p;
 }
 
@@ -187,7 +187,7 @@ int load_multiboot(void *fw_cfg,
         mb_kernel_size = elf_high - elf_low;
         mh_entry_addr = elf_entry;
 
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        mbs.mb_buf = g_malloc(mb_kernel_size);
         if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
             fprintf(stderr, "Error while fetching elf kernel from rom\n");
             exit(1);
@@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
     } else {
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
         uint32_t mh_header_addr = ldl_p(header+i+12);
+        uint32_t mh_load_end_addr = ldl_p(header+i+20);
+        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
         mh_load_addr = ldl_p(header+i+16);
         uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
 
         mh_entry_addr = ldl_p(header+i+28);
-        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
 
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
         uint32_t mh_mode_type = ldl_p(header+i+32);
@@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
 
         mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
         mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
-        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
         mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                 mb_kernel_size, mh_load_addr);
+                 mb_load_size, mh_load_addr);
 
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        mbs.mb_buf = g_malloc(mb_kernel_size);
         fseek(f, mb_kernel_text_offset, SEEK_SET);
-        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
+        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
             fprintf(stderr, "fread() failed\n");
             exit(1);
         }
+        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
         fclose(f);
     }
 
@@ -238,7 +242,7 @@ int load_multiboot(void *fw_cfg,
         const char *r = initrd_filename;
         mbs.mb_buf_size += strlen(r) + 1;
         mbs.mb_mods_avail = 1;
-        while ((r = strchr(r, ','))) {
+        while (*(r = get_opt_value(NULL, 0, r))) {
            mbs.mb_mods_avail++;
            r++;
         }
@@ -248,11 +252,11 @@ int load_multiboot(void *fw_cfg,
     mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
 
     /* enlarge mb_buf to hold cmdlines and mb-info structs */
-    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.mb_buf          = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
     mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
 
     if (initrd_filename) {
-        char *next_initrd;
+        char *next_initrd, not_last;
 
         mbs.offset_mods = mbs.mb_buf_size;
 
@@ -261,9 +265,9 @@ int load_multiboot(void *fw_cfg,
             int mb_mod_length;
             uint32_t offs = mbs.mb_buf_size;
 
-            next_initrd = strchr(initrd_filename, ',');
-            if (next_initrd)
-                *next_initrd = '\0';
+            next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
+            not_last = *next_initrd;
+            *next_initrd = '\0';
             /* if a space comes after the module filename, treat everything
                after that as parameters */
             target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
@@ -272,12 +276,12 @@ 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);
             }
 
             mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
-            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+            mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
 
             load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
             mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
@@ -287,7 +291,7 @@ int load_multiboot(void *fw_cfg,
                      (char *)mbs.mb_buf + offs,
                      (char *)mbs.mb_buf + offs + mb_mod_length, c);
             initrd_filename = next_initrd+1;
-        } while (next_initrd);
+        } while (not_last);
     }
 
     /* Commandline support */
@@ -307,7 +311,7 @@ int load_multiboot(void *fw_cfg,
                                 | MULTIBOOT_FLAGS_MMAP);
     stl_p(bootinfo + MBI_MEM_LOWER,   640);
     stl_p(bootinfo + MBI_MEM_UPPER,   (ram_size / 1024) - 1024);
-    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
     stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
 
     mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
@@ -316,7 +320,7 @@ int load_multiboot(void *fw_cfg,
     mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
 
     /* save bootinfo off the stack */
-    mb_bootinfo_data = qemu_malloc(sizeof(bootinfo));
+    mb_bootinfo_data = g_malloc(sizeof(bootinfo));
     memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
 
     /* Pass variables to option rom */
index d98aa8d03c4e60e615a0c7faed230e7f77593f27..20553b525bd3435379f061e798b8e3deb1032d7a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2008 Jan Kiszka
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 
 #include "sysbus.h"
@@ -19,6 +19,7 @@
 #include "console.h"
 #include "i2c.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MP_MISC_BASE            0x80002000
 #define MP_MISC_SIZE            0x00001000
@@ -142,6 +143,7 @@ typedef struct mv88w8618_rx_desc {
 
 typedef struct mv88w8618_eth_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq irq;
     uint32_t smir;
     uint32_t icr;
@@ -260,7 +262,8 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
     } while (desc_addr != s->tx_queue[queue_index]);
 }
 
-static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_eth_state *s = opaque;
 
@@ -302,7 +305,7 @@ static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_eth_state *s = opaque;
 
@@ -353,16 +356,10 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_eth_readfn[] = {
-    mv88w8618_eth_read,
-    mv88w8618_eth_read,
-    mv88w8618_eth_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = {
-    mv88w8618_eth_write,
-    mv88w8618_eth_write,
-    mv88w8618_eth_write
+static const MemoryRegionOps mv88w8618_eth_ops = {
+    .read = mv88w8618_eth_read,
+    .write = mv88w8618_eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void eth_cleanup(VLANClientState *nc)
@@ -387,10 +384,9 @@ static int mv88w8618_eth_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
                           dev->qdev.info->name, dev->qdev.id, s);
-    s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn,
-                                           mv88w8618_eth_writefn, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index);
+    memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
+                          MP_ETH_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -444,6 +440,7 @@ static SysBusDeviceInfo mv88w8618_eth_info = {
 
 typedef struct musicpal_lcd_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t brightness;
     uint32_t mode;
     uint32_t irqctrl;
@@ -528,7 +525,8 @@ static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
     s->brightness |= level << irq;
 }
 
-static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
 {
     musicpal_lcd_state *s = opaque;
 
@@ -542,7 +540,7 @@ static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
-                               uint32_t value)
+                               uint64_t value, unsigned size)
 {
     musicpal_lcd_state *s = opaque;
 
@@ -581,29 +579,21 @@ static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const musicpal_lcd_readfn[] = {
-    musicpal_lcd_read,
-    musicpal_lcd_read,
-    musicpal_lcd_read
-};
-
-static CPUWriteMemoryFunc * const musicpal_lcd_writefn[] = {
-    musicpal_lcd_write,
-    musicpal_lcd_write,
-    musicpal_lcd_write
+static const MemoryRegionOps musicpal_lcd_ops = {
+    .read = musicpal_lcd_read,
+    .write = musicpal_lcd_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int musicpal_lcd_init(SysBusDevice *dev)
 {
     musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
-    int iomemtype;
 
     s->brightness = 7;
 
-    iomemtype = cpu_register_io_memory(musicpal_lcd_readfn,
-                                       musicpal_lcd_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s,
+                          "musicpal-lcd", MP_LCD_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
                                  NULL, NULL, s);
@@ -645,6 +635,7 @@ static SysBusDeviceInfo musicpal_lcd_info = {
 typedef struct mv88w8618_pic_state
 {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t level;
     uint32_t enabled;
     qemu_irq parent_irq;
@@ -667,7 +658,8 @@ static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
     mv88w8618_pic_update(s);
 }
 
-static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_pic_state *s = opaque;
 
@@ -681,7 +673,7 @@ static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_pic_state *s = opaque;
 
@@ -707,29 +699,21 @@ static void mv88w8618_pic_reset(DeviceState *d)
     s->enabled = 0;
 }
 
-static CPUReadMemoryFunc * const mv88w8618_pic_readfn[] = {
-    mv88w8618_pic_read,
-    mv88w8618_pic_read,
-    mv88w8618_pic_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_pic_writefn[] = {
-    mv88w8618_pic_write,
-    mv88w8618_pic_write,
-    mv88w8618_pic_write
+static const MemoryRegionOps mv88w8618_pic_ops = {
+    .read = mv88w8618_pic_read,
+    .write = mv88w8618_pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_pic_init(SysBusDevice *dev)
 {
     mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
-    int iomemtype;
 
     qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
     sysbus_init_irq(dev, &s->parent_irq);
-    iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn,
-                                       mv88w8618_pic_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s,
+                          "musicpal-pic", MP_PIC_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -775,6 +759,7 @@ typedef struct mv88w8618_timer_state {
 
 typedef struct mv88w8618_pit_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     mv88w8618_timer_state timer[4];
 } mv88w8618_pit_state;
 
@@ -797,7 +782,8 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
     s->ptimer = ptimer_init(bh);
 }
 
-static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_pit_state *s = opaque;
     mv88w8618_timer_state *t;
@@ -813,7 +799,7 @@ static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_pit_state *s = opaque;
     mv88w8618_timer_state *t;
@@ -864,21 +850,14 @@ static void mv88w8618_pit_reset(DeviceState *d)
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = {
-    mv88w8618_pit_read,
-    mv88w8618_pit_read,
-    mv88w8618_pit_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_pit_writefn[] = {
-    mv88w8618_pit_write,
-    mv88w8618_pit_write,
-    mv88w8618_pit_write
+static const MemoryRegionOps mv88w8618_pit_ops = {
+    .read = mv88w8618_pit_read,
+    .write = mv88w8618_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_pit_init(SysBusDevice *dev)
 {
-    int iomemtype;
     mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
     int i;
 
@@ -888,10 +867,9 @@ static int mv88w8618_pit_init(SysBusDevice *dev)
         mv88w8618_timer_init(dev, &s->timer[i], 1000000);
     }
 
-    iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn,
-                                       mv88w8618_pit_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s,
+                          "musicpal-pit", MP_PIT_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -932,11 +910,13 @@ static SysBusDeviceInfo mv88w8618_pit_info = {
 
 typedef struct mv88w8618_flashcfg_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t cfgr0;
 } mv88w8618_flashcfg_state;
 
-static uint32_t mv88w8618_flashcfg_read(void *opaque,
-                                        target_phys_addr_t offset)
+static uint64_t mv88w8618_flashcfg_read(void *opaque,
+                                        target_phys_addr_t offset,
+                                        unsigned size)
 {
     mv88w8618_flashcfg_state *s = opaque;
 
@@ -950,7 +930,7 @@ static uint32_t mv88w8618_flashcfg_read(void *opaque,
 }
 
 static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
-                                     uint32_t value)
+                                     uint64_t value, unsigned size)
 {
     mv88w8618_flashcfg_state *s = opaque;
 
@@ -961,28 +941,20 @@ static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_flashcfg_readfn[] = {
-    mv88w8618_flashcfg_read,
-    mv88w8618_flashcfg_read,
-    mv88w8618_flashcfg_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_flashcfg_writefn[] = {
-    mv88w8618_flashcfg_write,
-    mv88w8618_flashcfg_write,
-    mv88w8618_flashcfg_write
+static const MemoryRegionOps mv88w8618_flashcfg_ops = {
+    .read = mv88w8618_flashcfg_read,
+    .write = mv88w8618_flashcfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_flashcfg_init(SysBusDevice *dev)
 {
-    int iomemtype;
     mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev);
 
     s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
-    iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn,
-                                       mv88w8618_flashcfg_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s,
+                          "musicpal-flashcfg", MP_FLASHCFG_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -1009,7 +981,8 @@ static SysBusDeviceInfo mv88w8618_flashcfg_info = {
 
 #define MP_BOARD_REVISION       0x31
 
-static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_misc_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     switch (offset) {
     case MP_MISC_BOARD_REVISION:
@@ -1021,37 +994,31 @@ static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_misc_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const musicpal_misc_readfn[] = {
-    musicpal_misc_read,
-    musicpal_misc_read,
-    musicpal_misc_read,
-};
-
-static CPUWriteMemoryFunc * const musicpal_misc_writefn[] = {
-    musicpal_misc_write,
-    musicpal_misc_write,
-    musicpal_misc_write,
+static const MemoryRegionOps musicpal_misc_ops = {
+    .read = musicpal_misc_read,
+    .write = musicpal_misc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void musicpal_misc_init(void)
+static void musicpal_misc_init(SysBusDevice *dev)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
 
-    iomemtype = cpu_register_io_memory(musicpal_misc_readfn,
-                                       musicpal_misc_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype);
+    memory_region_init_io(iomem, &musicpal_misc_ops, NULL,
+                          "musicpal-misc", MP_MISC_SIZE);
+    sysbus_add_memory(dev, MP_MISC_BASE, iomem);
 }
 
 /* WLAN register offsets */
 #define MP_WLAN_MAGIC1          0x11c
 #define MP_WLAN_MAGIC2          0x124
 
-static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
 {
     switch (offset) {
     /* Workaround to allow loading the binary-only wlandrv.ko crap
@@ -1067,30 +1034,23 @@ static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset,
-                                 uint32_t value)
+                                 uint64_t value, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const mv88w8618_wlan_readfn[] = {
-    mv88w8618_wlan_read,
-    mv88w8618_wlan_read,
-    mv88w8618_wlan_read,
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_wlan_writefn[] = {
-    mv88w8618_wlan_write,
-    mv88w8618_wlan_write,
-    mv88w8618_wlan_write,
+static const MemoryRegionOps mv88w8618_wlan_ops = {
+    .read = mv88w8618_wlan_read,
+    .write =mv88w8618_wlan_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_wlan_init(SysBusDevice *dev)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
 
-    iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn,
-                                       mv88w8618_wlan_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype);
+    memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL,
+                          "musicpal-wlan", MP_WLAN_SIZE);
+    sysbus_init_mmio_region(dev, iomem);
     return 0;
 }
 
@@ -1118,6 +1078,7 @@ static int mv88w8618_wlan_init(SysBusDevice *dev)
 
 typedef struct musicpal_gpio_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t lcd_brightness;
     uint32_t out_state;
     uint32_t in_state;
@@ -1190,7 +1151,8 @@ static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
     }
 }
 
-static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     musicpal_gpio_state *s = opaque;
 
@@ -1229,7 +1191,7 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     musicpal_gpio_state *s = opaque;
     switch (offset) {
@@ -1267,16 +1229,10 @@ static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const musicpal_gpio_readfn[] = {
-    musicpal_gpio_read,
-    musicpal_gpio_read,
-    musicpal_gpio_read,
-};
-
-static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = {
-    musicpal_gpio_write,
-    musicpal_gpio_write,
-    musicpal_gpio_write,
+static const MemoryRegionOps musicpal_gpio_ops = {
+    .read = musicpal_gpio_read,
+    .write = musicpal_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void musicpal_gpio_reset(DeviceState *d)
@@ -1295,14 +1251,12 @@ static void musicpal_gpio_reset(DeviceState *d)
 static int musicpal_gpio_init(SysBusDevice *dev)
 {
     musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
-    int iomemtype;
 
     sysbus_init_irq(dev, &s->irq);
 
-    iomemtype = cpu_register_io_memory(musicpal_gpio_readfn,
-                                       musicpal_gpio_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s,
+                          "musicpal-gpio", MP_GPIO_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
 
@@ -1501,7 +1455,9 @@ static void musicpal_init(ram_addr_t ram_size,
     int i;
     unsigned long flash_size;
     DriveInfo *dinfo;
-    ram_addr_t sram_off;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model) {
         cpu_model = "arm926";
@@ -1514,12 +1470,11 @@ static void musicpal_init(ram_addr_t ram_size,
     cpu_pic = arm_pic_init_cpu(env);
 
     /* For now we use a fixed - the original - RAM size */
-    cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,
-                                 qemu_ram_alloc(NULL, "musicpal.ram",
-                                                MP_RAM_DEFAULT_SIZE));
+    memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
-    sram_off = qemu_ram_alloc(NULL, "musicpal.sram", MP_SRAM_SIZE);
-    cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);
+    memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE);
+    memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
 
     dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
                                cpu_pic[ARM_PIC_CPU_IRQ]);
@@ -1531,22 +1486,12 @@ static void musicpal_init(ram_addr_t ram_size,
                           pic[MP_TIMER4_IRQ], NULL);
 
     if (serial_hds[0]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 1);
-#else
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 0);
-#endif
+        serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
+                       1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 1);
-#else
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 0);
-#endif
+        serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
+                       1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
     }
 
     /* Register flash */
@@ -1565,16 +1510,16 @@ static void musicpal_init(ram_addr_t ram_size,
          * image is smaller than 32 MB.
          */
 #ifdef TARGET_WORDS_BIGENDIAN
-        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
-                              "musicpal.flash", flash_size),
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
                               dinfo->bdrv, 0x10000,
                               (flash_size + 0xffff) >> 16,
                               MP_FLASH_SIZE_MAX / flash_size,
                               2, 0x00BF, 0x236D, 0x0000, 0x0000,
                               0x5555, 0x2AAA, 1);
 #else
-        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
-                              "musicpal.flash", flash_size),
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
                               dinfo->bdrv, 0x10000,
                               (flash_size + 0xffff) >> 16,
                               MP_FLASH_SIZE_MAX / flash_size,
@@ -1594,14 +1539,14 @@ static void musicpal_init(ram_addr_t ram_size,
 
     sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
 
-    musicpal_misc_init();
+    musicpal_misc_init(sysbus_from_qdev(dev));
 
     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..7f25814dddf428a2d9be67861317bbb3b1ed9284 100644 (file)
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
  * This code is licensed under the GNU GPL v2.
  */
 
@@ -14,7 +18,8 @@
 # include "hw.h"
 # include "flash.h"
 # include "blockdev.h"
-/* FIXME: Pass block device as an argument.  */
+# include "sysbus.h"
+#include "qemu-error.h"
 
 # define NAND_CMD_READ0                0x00
 # define NAND_CMD_READ1                0x01
 # define MAX_PAGE              0x800
 # define MAX_OOB               0x40
 
+typedef struct NANDFlashState NANDFlashState;
 struct NANDFlashState {
+    SysBusDevice busdev;
     uint8_t manf_id, chip_id;
+    uint8_t buswidth; /* in BYTES */
     int size, pages;
     int page_shift, oob_shift, erase_shift, addr_shift;
     uint8_t *storage;
     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;
     int iolen;
 
-    uint32_t cmd, addr;
+    uint32_t cmd;
+    uint64_t addr;
     int addrlen;
     int status;
     int offset;
 
     void (*blk_write)(NANDFlashState *s);
     void (*blk_erase)(NANDFlashState *s);
-    void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+    void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
+
+    uint32_t ioaddr_vmstate;
 };
 
+static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
+{
+    /* Like memcpy() but we logical-AND the data into the destination */
+    int i;
+    for (i = 0; i < n; i++) {
+        dest[i] &= src[i];
+    }
+}
+
 # define NAND_NO_AUTOINCR      0x00000001
 # define NAND_BUSWIDTH_16      0x00000002
 # define NAND_NO_PADDING       0x00000004
@@ -199,8 +219,9 @@ static const struct {
     [0xc5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
 };
 
-static void nand_reset(NANDFlashState *s)
+static void nand_reset(DeviceState *dev)
 {
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, sysbus_from_qdev(dev));
     s->cmd = NAND_CMD_READ0;
     s->addr = 0;
     s->addrlen = 0;
@@ -209,6 +230,14 @@ static void nand_reset(NANDFlashState *s)
     s->status &= NAND_IOSTATUS_UNPROTCT;
 }
 
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+    s->ioaddr[s->iolen++] = value;
+    for (value = s->buswidth; --value;) {
+        s->ioaddr[s->iolen++] = 0;
+    }
+}
+
 static void nand_command(NANDFlashState *s)
 {
     unsigned int offset;
@@ -218,15 +247,19 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_READID:
-        s->io[0] = s->manf_id;
-        s->io[1] = s->chip_id;
-        s->io[2] = 'Q';                /* Don't-care byte (often 0xa5) */
-        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
-            s->io[3] = 0x15;   /* Page Size, Block Size, Spare Size.. */
-        else
-            s->io[3] = 0xc0;   /* Multi-plane */
         s->ioaddr = s->io;
-        s->iolen = 4;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->manf_id);
+        nand_pushio_byte(s, s->chip_id);
+        nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            /* Page Size, Block Size, Spare Size; bit 6 indicates
+             * 8 vs 16 bit width NAND.
+             */
+            nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
+        } else {
+            nand_pushio_byte(s, 0xc0); /* Multi-plane */
+        }
         break;
 
     case NAND_CMD_RANDOMREAD2:
@@ -242,7 +275,7 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_RESET:
-        nand_reset(s);
+        nand_reset(&s->busdev.qdev);
         break;
 
     case NAND_CMD_PAGEPROGRAM1:
@@ -271,9 +304,9 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_READSTATUS:
-        s->io[0] = s->status;
         s->ioaddr = s->io;
-        s->iolen = 1;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->status);
         break;
 
     default:
@@ -281,57 +314,135 @@ 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 = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .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_UINT64(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()
+    }
+};
+
+static int nand_device_init(SysBusDevice *dev)
+{
+    int pagesize;
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
+
+    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
+    s->size = nand_flash_ids[s->chip_id].size << 20;
+    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+        s->page_shift = 11;
+        s->erase_shift = 6;
+    } else {
+        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    }
+
+    switch (1 << s->page_shift) {
+    case 256:
+        nand_init_256(s);
+        break;
+    case 512:
+        nand_init_512(s);
+        break;
+    case 2048:
+        nand_init_2048(s);
+        break;
+    default:
+        error_report("Unsupported NAND block size");
+        return -1;
+    }
+
+    pagesize = 1 << s->oob_shift;
+    s->mem_oob = 1;
+    if (s->bdrv) {
+        if (bdrv_is_read_only(s->bdrv)) {
+            error_report("Can't use a read-only drive");
+            return -1;
+        }
+        if (bdrv_getlength(s->bdrv) >=
+                (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+            pagesize = 0;
+            s->mem_oob = 0;
+        }
+    } else {
+        pagesize += 1 << s->page_shift;
+    }
+    if (pagesize) {
+        s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
+                        0xff, s->pages * pagesize);
+    }
+    /* Give s->ioaddr a sane value in case we save state before it is used. */
+    s->ioaddr = s->io;
+
+    return 0;
+}
+
+static SysBusDeviceInfo nand_info = {
+    .init = nand_device_init,
+    .qdev.name = "nand",
+    .qdev.size = sizeof(NANDFlashState),
+    .qdev.reset = nand_reset,
+    .qdev.vmsd = &vmstate_nand,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+        DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+        DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void nand_create_device(void)
+{
+    sysbus_register_withprop(&nand_info);
+}
+
 /*
  * 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(DeviceState *dev, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd)
 {
+    NANDFlashState *s = (NANDFlashState *) dev;
     s->cle = cle;
     s->ale = ale;
     s->ce = ce;
@@ -343,13 +454,15 @@ void nand_setpins(NANDFlashState *s,
         s->status &= ~NAND_IOSTATUS_UNPROTCT;
 }
 
-void nand_getpins(NANDFlashState *s, int *rb)
+void nand_getpins(DeviceState *dev, int *rb)
 {
     *rb = 1;
 }
 
-void nand_setio(NANDFlashState *s, uint8_t value)
+void nand_setio(DeviceState *dev, uint32_t value)
 {
+    int i;
+    NANDFlashState *s = (NANDFlashState *) dev;
     if (!s->ce && s->cle) {
         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -395,40 +508,69 @@ void nand_setio(NANDFlashState *s, uint8_t value)
         s->addr = (s->addr & mask) | v;
         s->addrlen ++;
 
-        if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
-            nand_command(s);
-
-        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                s->addrlen == 3 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
-        if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-               s->addrlen == 4 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
+        switch (s->addrlen) {
+        case 1:
+            if (s->cmd == NAND_CMD_READID) {
+                nand_command(s);
+            }
+            break;
+        case 2: /* fix cache address as a byte address */
+            s->addr <<= (s->buswidth - 1);
+            break;
+        case 3:
+            if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 4:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 5:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        default:
+            break;
+        }
     }
 
     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
-        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
-            s->io[s->iolen ++] = value;
+        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
+            for (i = s->buswidth; i--; value >>= 8) {
+                s->io[s->iolen ++] = (uint8_t) (value & 0xff);
+            }
+        }
     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
         if ((s->addr & ((1 << s->addr_shift) - 1)) <
                 (1 << s->page_shift) + (1 << s->oob_shift)) {
-            s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
-            s->addr ++;
+            for (i = s->buswidth; i--; s->addr++, value >>= 8) {
+                s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+                    (uint8_t) (value & 0xff);
+            }
         }
     }
 }
 
-uint8_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(DeviceState *dev)
 {
     int offset;
+    uint32_t x = 0;
+    NANDFlashState *s = (NANDFlashState *) dev;
 
     /* Allow sequential reading */
     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
-        offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
         s->offset = 0;
 
         s->blk_load(s, s->addr, offset);
@@ -441,129 +583,90 @@ uint8_t nand_getio(NANDFlashState *s)
     if (s->ce || s->iolen <= 0)
         return 0;
 
-    s->iolen --;
-    s->addr++;
-    return *(s->ioaddr ++);
+    for (offset = s->buswidth; offset--;) {
+        x |= s->ioaddr[offset] << (offset << 3);
+    }
+    /* after receiving READ STATUS command all subsequent reads will
+     * return the status register value until another command is issued
+     */
+    if (s->cmd != NAND_CMD_READSTATUS) {
+        s->addr   += s->buswidth;
+        s->ioaddr += s->buswidth;
+        s->iolen  -= s->buswidth;
+    }
+    return x;
+}
+
+uint32_t nand_getbuswidth(DeviceState *dev)
+{
+    NANDFlashState *s = (NANDFlashState *) dev;
+    return s->buswidth << 3;
 }
 
-NANDFlashState *nand_init(int manf_id, int chip_id)
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
 {
-    int pagesize;
-    NANDFlashState *s;
-    DriveInfo *dinfo;
+    DeviceState *dev;
 
     if (nand_flash_ids[chip_id].size == 0) {
         hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
     }
-
-    s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
-    dinfo = drive_get(IF_MTD, 0, 0);
-    if (dinfo)
-        s->bdrv = dinfo->bdrv;
-    s->manf_id = manf_id;
-    s->chip_id = chip_id;
-    s->size = nand_flash_ids[s->chip_id].size << 20;
-    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-        s->page_shift = 11;
-        s->erase_shift = 6;
-    } else {
-        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
-        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
-    }
-
-    switch (1 << s->page_shift) {
-    case 256:
-        nand_init_256(s);
-        break;
-    case 512:
-        nand_init_512(s);
-        break;
-    case 2048:
-        nand_init_2048(s);
-        break;
-    default:
-        hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
-    }
-
-    pagesize = 1 << s->oob_shift;
-    s->mem_oob = 1;
-    if (s->bdrv && bdrv_getlength(s->bdrv) >=
-                    (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
-        pagesize = 0;
-        s->mem_oob = 0;
+    dev = qdev_create(NULL, "nand");
+    qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
+    qdev_prop_set_uint8(dev, "chip_id", chip_id);
+    if (bdrv) {
+        qdev_prop_set_drive_nofail(dev, "drive", bdrv);
     }
 
-    if (!s->bdrv)
-        pagesize += 1 << s->page_shift;
-    if (pagesize)
-        s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
-                        0xff, s->pages * pagesize);
-    /* Give s->ioaddr a sane value in case we save state before it
-       is used.  */
-    s->ioaddr = s->io;
-
-    register_savevm(NULL, "nand", -1, 0, nand_save, nand_load, s);
-
-    return s;
+    qdev_init_nofail(dev);
+    return dev;
 }
 
-void nand_done(NANDFlashState *s)
-{
-    if (s->bdrv) {
-        bdrv_close(s->bdrv);
-        bdrv_delete(s->bdrv);
-    }
-
-    if (!s->bdrv || s->mem_oob)
-        qemu_free(s->storage);
-
-    qemu_free(s);
-}
+device_init(nand_create_device)
 
 #else
 
 /* Program a single page */
 static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
 {
-    uint32_t off, page, sector, soff;
+    uint64_t off, page, sector, soff;
     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
     if (PAGE(s->addr) >= s->pages)
         return;
 
     if (!s->bdrv) {
-        memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+        mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
                         s->offset, s->io, s->iolen);
     } else if (s->mem_oob) {
         sector = SECTOR(s->addr);
         off = (s->addr & PAGE_MASK) + s->offset;
         soff = SECTOR_OFFSET(s->addr);
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
             return;
         }
 
-        memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+        mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
         if (off + s->iolen > PAGE_SIZE) {
             page = PAGE(s->addr);
-            memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+            mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
                             MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
         }
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
     } else {
         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
         sector = off >> 9;
         soff = off & 0x1ff;
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
             return;
         }
 
-        memcpy(iobuf + soff, s->io, s->iolen);
+        mem_and(iobuf + soff, s->io, s->iolen);
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
     }
     s->offset = 0;
 }
@@ -571,7 +674,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
 /* Erase a single block */
 static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
 {
-    uint32_t i, page, addr;
+    uint64_t i, page, addr;
     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
 
@@ -588,34 +691,35 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
         for (; i < page; i ++)
             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i);
+                printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
     } else {
         addr = PAGE_START(addr);
         page = addr >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
 
         memset(iobuf, 0xff, 0x200);
         i = (addr & ~0x1ff) + 0x200;
         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
                         i < addr; i += 0x200)
             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+                printf("%s: write error in sector %" PRIu64 "\n",
+                       __func__, i >> 9);
 
         page = i >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
     }
 }
 
 static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
-                uint32_t addr, int offset)
+                uint64_t addr, int offset)
 {
     if (PAGE(addr) >= s->pages)
         return;
@@ -623,8 +727,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
     if (s->bdrv) {
         if (s->mem_oob) {
             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
-                printf("%s: read error in sector %i\n",
-                                __FUNCTION__, SECTOR(addr));
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, SECTOR(addr));
             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
                             OOB_SIZE);
@@ -632,8 +736,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
         } else {
             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
                                     s->io, (PAGE_SECTORS + 2)) == -1)
-                printf("%s: read error in sector %i\n",
-                                __FUNCTION__, PAGE_START(addr) >> 9);
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, PAGE_START(addr) >> 9);
             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
         }
     } else {
index 3ff0d89a74a95eb13698d3869649dd2cb6940019..11ffee7d7c21a7768859537c4dee25bdcd3062f9 100644 (file)
@@ -27,6 +27,7 @@
 #include "qdev.h"
 #include "net.h"
 #include "ne2000.h"
+#include "exec-memory.h"
 
 typedef struct ISANE2000State {
     ISADevice dev;
@@ -66,19 +67,8 @@ static int isa_ne2000_initfn(ISADevice *dev)
     ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev);
     NE2000State *s = &isa->ne2000;
 
-    register_ioport_write(isa->iobase, 16, 1, ne2000_ioport_write, s);
-    register_ioport_read(isa->iobase, 16, 1, ne2000_ioport_read, s);
-    isa_init_ioport_range(dev, isa->iobase, 16);
-
-    register_ioport_write(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_read, s);
-    register_ioport_write(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_read, s);
-    isa_init_ioport_range(dev, isa->iobase + 0x10, 2);
-
-    register_ioport_write(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
-    isa_init_ioport(dev, isa->iobase + 0x1f);
+    ne2000_setup_io(s, 0x20);
+    isa_register_ioport(dev, &s->io, isa->iobase);
 
     isa_init_irq(dev, &s->irq, isa->isairq);
 
@@ -92,19 +82,6 @@ static int isa_ne2000_initfn(ISADevice *dev)
     return 0;
 }
 
-void isa_ne2000_init(int base, int irq, NICInfo *nd)
-{
-    ISADevice *dev;
-
-    qemu_check_nic_model(nd, "ne2k_isa");
-
-    dev = isa_create("ne2k_isa");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq",    irq);
-    qdev_set_nic_properties(&dev->qdev, nd);
-    qdev_init_nofail(&dev->qdev);
-}
-
 static ISADeviceInfo ne2000_isa_info = {
     .qdev.name  = "ne2k_isa",
     .qdev.size  = sizeof(ISANE2000State),
index 5966359852f101f1aa32233e193c846b552a1775..62e082f8a93df7dcb6004deca269c53ea00367dc 100644 (file)
@@ -297,7 +297,7 @@ ssize_t ne2000_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
     return size_;
 }
 
-void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     NE2000State *s = opaque;
     int offset, page, index;
@@ -394,7 +394,7 @@ void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     int offset, page, ret;
@@ -544,7 +544,7 @@ static inline void ne2000_dma_update(NE2000State *s, int len)
     }
 }
 
-void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     NE2000State *s = opaque;
 
@@ -564,7 +564,7 @@ void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     int ret;
@@ -612,12 +612,12 @@ static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
     return ret;
 }
 
-void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     /* nothing to do (end of reset pulse) */
 }
 
-uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     ne2000_reset(s);
@@ -676,27 +676,55 @@ static const VMStateDescription vmstate_pci_ne2000 = {
     }
 };
 
-/***********************************************************/
-/* PCI NE2000 definitions */
+static uint64_t ne2000_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
+{
+    NE2000State *s = opaque;
 
-static void ne2000_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
+    if (addr < 0x10 && size == 1) {
+        return ne2000_ioport_read(s, addr);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            return ne2000_asic_ioport_read(s, addr);
+        } else {
+            return ne2000_asic_ioport_readl(s, addr);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        return ne2000_reset_ioport_read(s, addr);
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void ne2000_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t data, unsigned size)
 {
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
+    NE2000State *s = opaque;
 
-    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
-    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
+    if (addr < 0x10 && size == 1) {
+        return ne2000_ioport_write(s, addr, data);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            return ne2000_asic_ioport_write(s, addr, data);
+        } else {
+            return ne2000_asic_ioport_writel(s, addr, data);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        return ne2000_reset_ioport_write(s, addr, data);
+    }
+}
 
-    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
-    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
+static const MemoryRegionOps ne2000_ops = {
+    .read = ne2000_read,
+    .write = ne2000_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
 
-    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
-    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+/***********************************************************/
+/* PCI NE2000 definitions */
+
+void ne2000_setup_io(NE2000State *s, unsigned size)
+{
+    memory_region_init_io(&s->io, &ne2000_ops, s, "ne2000", size);
 }
 
 static void ne2000_cleanup(VLANClientState *nc)
@@ -721,15 +749,11 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     uint8_t *pci_conf;
 
     pci_conf = d->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8029);
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
-    /* TODO: RST# value should be 0. PCI spec 6.2.4 */
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
-
-    pci_register_bar(&d->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+
     s = &d->ne2000;
+    ne2000_setup_io(s, 0x100);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     s->irq = d->dev.irq[0];
 
     qemu_macaddr_default_if_unset(&s->c.macaddr);
@@ -742,7 +766,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;
         }
     }
@@ -757,6 +781,7 @@ static int pci_ne2000_exit(PCIDevice *pci_dev)
     PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
     NE2000State *s = &d->ne2000;
 
+    memory_region_destroy(&s->io);
     qemu_del_vlan_client(&s->nic->nc);
     return 0;
 }
@@ -767,6 +792,9 @@ static PCIDeviceInfo ne2000_info = {
     .qdev.vmsd  = &vmstate_pci_ne2000,
     .init       = pci_ne2000_init,
     .exit       = pci_ne2000_exit,
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8029,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
         DEFINE_PROP_END_OF_LIST(),
index 54fdfca1339371eb59cc5dc227a8b90ee13cf4f5..5fee052194c21894983d7ca239b6a43a64cf2fbc 100644 (file)
@@ -4,6 +4,7 @@
 #define NE2000_MEM_SIZE     NE2000_PMEM_END
 
 typedef struct NE2000State {
+    MemoryRegion io;
     uint8_t cmd;
     uint32_t start;
     uint32_t stop;
@@ -27,12 +28,7 @@ typedef struct NE2000State {
     uint8_t mem[NE2000_MEM_SIZE];
 } NE2000State;
 
-void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_ioport_read(void *opaque, uint32_t addr);
-void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr);
-void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr);
+void ne2000_setup_io(NE2000State *s, unsigned size);
 extern const VMStateDescription vmstate_ne2000;
 void ne2000_reset(NE2000State *s);
 int ne2000_can_receive(VLANClientState *vc);
index 2f6f473d64dbc3e614b2a205c929364dacc89f7d..eb991431a42540f04640bb9390a1ad11e59ae7f2 100644 (file)
@@ -31,6 +31,8 @@
 #include "hw.h"
 #include "bt.h"
 #include "loader.h"
+#include "blockdev.h"
+#include "sysbus.h"
 
 /* Nokia N8x0 support */
 struct n800_s {
@@ -45,12 +47,12 @@ struct n800_s {
     i2c_bus *i2c;
 
     int keymap[0x80];
-    i2c_slave *kbd;
+    DeviceState *kbd;
 
-    TUSBState *usb;
+    DeviceState *usb;
     void *retu;
     void *tahvo;
-    void *nand;
+    DeviceState *nand;
 };
 
 /* GPIO pins */
@@ -134,9 +136,9 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
 static void n8x0_gpio_setup(struct n800_s *s)
 {
     qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1);
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]);
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
 
-    qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]);
+    qemu_irq_lower(qdev_get_gpio_in(s->cpu->gpio, N800_BAT_COVER_GPIO));
 }
 
 #define MAEMO_CAL_HEADER(...)                          \
@@ -163,13 +165,23 @@ static const uint8_t n8x0_cal_bt_id[] = {
 static void n8x0_nand_setup(struct n800_s *s)
 {
     char *otp_region;
-
-    /* Either ec40xx or ec48xx are OK for the ID */
-    omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
-                    onenand_base_unmap,
-                    (s->nand = onenand_init(0xec4800, 1,
-                                            omap2_gpio_in_get(s->cpu->gpif,
-                                                    N8X0_ONENAND_GPIO)[0])));
+    DriveInfo *dinfo;
+
+    s->nand = qdev_create(NULL, "onenand");
+    qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
+    /* Either 0x40 or 0x48 are OK for the device ID */
+    qdev_prop_set_uint16(s->nand, "device_id", 0x48);
+    qdev_prop_set_uint16(s->nand, "version_id", 0);
+    qdev_prop_set_int32(s->nand, "shift", 1);
+    dinfo = drive_get(IF_MTD, 0, 0);
+    if (dinfo && dinfo->bdrv) {
+        qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv);
+    }
+    qdev_init_nofail(s->nand);
+    sysbus_connect_irq(sysbus_from_qdev(s->nand), 0,
+                       qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
+    omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS,
+                     sysbus_mmio_get_region(sysbus_from_qdev(s->nand), 0));
     otp_region = onenand_raw_otp(s->nand);
 
     memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
@@ -180,14 +192,16 @@ static void n8x0_nand_setup(struct n800_s *s)
 static void n8x0_i2c_setup(struct n800_s *s)
 {
     DeviceState *dev;
-    qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0];
+    qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO);
 
     /* Attach the CPU on one end of our I2C bus.  */
     s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
 
     /* Attach a menelaus PM chip */
     dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR);
-    qdev_connect_gpio_out(dev, 3, s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]);
+    qdev_connect_gpio_out(dev, 3,
+                          qdev_get_gpio_in(s->cpu->ih[0],
+                                           OMAP_INT_24XX_SYS_NIRQ));
 
     /* Attach a TMP105 PM chip (A0 wired to ground) */
     dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
@@ -249,8 +263,8 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
     /* XXX: are the three pins inverted inside the chip between the
      * tsc and the cpu (N4111)?  */
     qemu_irq penirq = NULL;    /* NC */
-    qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0];
-    qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0];
+    qemu_irq kbirq = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_KP_IRQ_GPIO);
+    qemu_irq dav = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_TS_GPIO);
 
     s->ts.chip = tsc2301_init(penirq, kbirq, dav);
     s->ts.opaque = s->ts.chip->opaque;
@@ -269,7 +283,7 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
 
 static void n810_tsc_setup(struct n800_s *s)
 {
-    qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0];
+    qemu_irq pintdav = qdev_get_gpio_in(s->cpu->gpio, N810_TSC_TS_GPIO);
 
     s->ts.opaque = tsc2005_init(pintdav);
     s->ts.txrx = tsc2005_txrx;
@@ -361,8 +375,7 @@ static int n810_keys[0x80] = {
 
 static void n810_kbd_setup(struct n800_s *s)
 {
-    qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0];
-    DeviceState *dev;
+    qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO);
     int i;
 
     for (i = 0; i < 0x80; i ++)
@@ -375,8 +388,8 @@ static void n810_kbd_setup(struct n800_s *s)
 
     /* Attach the LM8322 keyboard to the I2C bus,
      * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
-    dev = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
-    qdev_connect_gpio_out(dev, 0, kbd_irq);
+    s->kbd = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
+    qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
 }
 
 /* LCD MIPI DBI-C controller (URAL) */
@@ -652,7 +665,7 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
 
 static void *mipid_init(void)
 {
-    struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s));
+    struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s));
 
     s->id = 0x838f03;
     mipid_reset(s);
@@ -708,10 +721,10 @@ static void n800_dss_init(struct rfbi_chip_s *chip)
     chip->write(chip->opaque, 1, 0x01);                /* Input Data Format */
     chip->write(chip->opaque, 1, 0x01);                /* Data Source Select */
 
-    fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
+    fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
     /* Display Memory Data Port */
     chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
-    qemu_free(fb_blank);
+    g_free(fb_blank);
 }
 
 static void n8x0_dss_setup(struct n800_s *s)
@@ -726,15 +739,15 @@ static void n8x0_dss_setup(struct n800_s *s)
 
 static void n8x0_cbus_setup(struct n800_s *s)
 {
-    qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0];
-    qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0];
-    qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0];
+    qemu_irq dat_out = qdev_get_gpio_in(s->cpu->gpio, N8X0_CBUS_DAT_GPIO);
+    qemu_irq retu_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_RETU_GPIO);
+    qemu_irq tahvo_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TAHVO_GPIO);
 
     CBus *cbus = cbus_init(dat_out);
 
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk);
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat);
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel);
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
 
     cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
     cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
@@ -743,38 +756,31 @@ static void n8x0_cbus_setup(struct n800_s *s)
 static void n8x0_uart_setup(struct n800_s *s)
 {
     CharDriverState *radio = uart_hci_init(
-                    omap2_gpio_in_get(s->cpu->gpif,
-                            N8X0_BT_HOST_WKUP_GPIO)[0]);
+                    qdev_get_gpio_in(s->cpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
 
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO,
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_RESET_GPIO,
                     csrhci_pins_get(radio)[csrhci_pin_reset]);
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO,
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_WKUP_GPIO,
                     csrhci_pins_get(radio)[csrhci_pin_wakeup]);
 
     omap_uart_attach(s->cpu->uart[BT_UART], radio);
 }
 
-static void n8x0_usb_power_cb(void *opaque, int line, int level)
-{
-    struct n800_s *s = opaque;
-
-    tusb6010_power(s->usb, level);
-}
-
 static void n8x0_usb_setup(struct n800_s *s)
 {
-    qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0];
-    qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0];
-    TUSBState *tusb = tusb6010_init(tusb_irq);
-
+    SysBusDevice *dev;
+    s->usb = qdev_create(NULL, "tusb6010");
+    dev = sysbus_from_qdev(s->usb);
+    qdev_init_nofail(s->usb);
+    sysbus_connect_irq(dev, 0,
+                       qdev_get_gpio_in(s->cpu->gpio, N8X0_TUSB_INT_GPIO));
     /* Using the NOR interface */
     omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS,
-                    tusb6010_async_io(tusb), NULL, NULL, tusb);
+                     sysbus_mmio_get_region(dev, 0));
     omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS,
-                    tusb6010_sync_io(tusb), NULL, NULL, tusb);
-
-    s->usb = tusb;
-    omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
+                     sysbus_mmio_get_region(dev, 1));
+    qdev_connect_gpio_out(s->cpu->gpio, N8X0_TUSB_ENABLE_GPIO,
+                          qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
 }
 
 /* Setup done before the main bootloader starts by some early setup code
@@ -1020,7 +1026,7 @@ static void n8x0_boot_init(void *opaque)
 
     /* If the machine has a slided keyboard, open it */
     if (s->kbd)
-        qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]);
+        qemu_irq_raise(qdev_get_gpio_in(s->cpu->gpio, N810_SLIDE_GPIO));
 }
 
 #define OMAP_TAG_NOKIA_BT      0x4e01
@@ -1254,12 +1260,12 @@ static int n8x0_atag_setup(void *p, int model)
     return (void *) w - p;
 }
 
-static int n800_atag_setup(struct arm_boot_info *info, void *p)
+static int n800_atag_setup(const struct arm_boot_info *info, void *p)
 {
     return n8x0_atag_setup(p, 800);
 }
 
-static int n810_atag_setup(struct arm_boot_info *info, void *p)
+static int n810_atag_setup(const struct arm_boot_info *info, void *p)
 {
     return n8x0_atag_setup(p, 810);
 }
@@ -1269,7 +1275,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
                 const char *kernel_cmdline, const char *initrd_filename,
                 const char *cpu_model, struct arm_boot_info *binfo, int model)
 {
-    struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s));
+    struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
     int sdram_size = binfo->ram_size;
     DisplayState *ds;
 
index c227a82b2c12dac21854f01c1cdf78997ef0d1e9..cc09a3c0ee133307b8395e676ec7173f4436c4cd 100644 (file)
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -17,6 +17,7 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #ifndef hw_omap_h
+#include "memory.h"
 # define hw_omap_h             "omap.h"
 
 # define OMAP_EMIFS_BASE       0x00000000
@@ -93,21 +94,11 @@ struct omap_target_agent_s *omap_l4ta_get(
     int cs);
 target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
                 int iotype);
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+                                       int region);
 int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                 CPUWriteMemoryFunc * const *mem_write, void *opaque);
 
-/* OMAP interrupt controller */
-struct omap_intr_handler_s;
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk);
-void omap_inth_reset(struct omap_intr_handler_s *s);
-qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n);
-
 /* OMAP2 SDRAM controller */
 struct omap_sdrc_s;
 struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
@@ -115,11 +106,12 @@ void omap_sdrc_reset(struct omap_sdrc_s *s);
 
 /* OMAP2 general purpose memory controller */
 struct omap_gpmc_s;
-struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq);
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   target_phys_addr_t base,
+                                   qemu_irq irq, qemu_irq drq);
 void omap_gpmc_reset(struct omap_gpmc_s *s);
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
-                void (*base_upd)(void *opaque, target_phys_addr_t new),
-                void (*unmap)(void *opaque), void *opaque);
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem);
+void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
 
 /*
  * Common IRQ numbers for level 1 interrupt handler
@@ -674,37 +666,20 @@ void omap_uart_reset(struct omap_uart_s *s);
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
 
 struct omap_mpuio_s;
-struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
                 omap_clk clk);
 qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
 void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
 void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
 
-/* omap1 gpio module interface */
-struct omap_gpio_s;
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
-                qemu_irq irq, omap_clk clk);
-void omap_gpio_reset(struct omap_gpio_s *s);
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
-
-/* omap2 gpio interface */
-struct omap_gpif_s;
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
-                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
-void omap_gpif_reset(struct omap_gpif_s *s);
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
-
 struct uWireSlave {
     uint16_t (*receive)(void *opaque);
     void (*send)(void *opaque, uint16_t data);
     void *opaque;
 };
 struct omap_uwire_s;
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk);
 void omap_uwire_attach(struct omap_uwire_s *s,
                 uWireSlave *slave, int chipselect);
 
@@ -742,8 +717,6 @@ struct I2SCodec {
     } in, out;
 };
 struct omap_mcbsp_s;
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk);
 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
 
 void omap_tap_init(struct omap_target_agent_s *ta,
@@ -753,8 +726,7 @@ void omap_tap_init(struct omap_target_agent_s *ta,
 struct omap_lcd_panel_s;
 void omap_lcdc_reset(struct omap_lcd_panel_s *s);
 struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
-                struct omap_dma_lcd_channel_s *dma,
-                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
+                struct omap_dma_lcd_channel_s *dma, omap_clk clk);
 
 /* omap_dss.c */
 struct rfbi_chip_s {
@@ -801,6 +773,7 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
 # define cpu_is_omap2420(cpu)          (cpu->mpu_model == omap2420)
 # define cpu_is_omap2430(cpu)          (cpu->mpu_model == omap2430)
 # define cpu_is_omap3430(cpu)          (cpu->mpu_model == omap3430)
+# define cpu_is_omap3630(cpu)           (cpu->mpu_model == omap3630)
 
 # define cpu_is_omap15xx(cpu)          \
         (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
@@ -812,7 +785,8 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
 # define cpu_class_omap1(cpu)          \
         (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
 # define cpu_class_omap2(cpu)          cpu_is_omap24xx(cpu)
-# define cpu_class_omap3(cpu)          cpu_is_omap3430(cpu)
+# define cpu_class_omap3(cpu) \
+        (cpu_is_omap3430(cpu) || cpu_is_omap3630(cpu))
 
 struct omap_mpu_state_s {
     enum omap_mpu_model {
@@ -826,15 +800,31 @@ struct omap_mpu_state_s {
         omap2423,
         omap2430,
         omap3430,
+        omap3630,
     } mpu_model;
 
     CPUState *env;
 
-    qemu_irq *irq[2];
     qemu_irq *drq;
 
     qemu_irq wakeup;
 
+    MemoryRegion ulpd_pm_iomem;
+    MemoryRegion pin_cfg_iomem;
+    MemoryRegion id_iomem;
+    MemoryRegion id_iomem_e18;
+    MemoryRegion id_iomem_ed4;
+    MemoryRegion id_iomem_e20;
+    MemoryRegion mpui_iomem;
+    MemoryRegion tcmi_iomem;
+    MemoryRegion clkm_iomem;
+    MemoryRegion clkdsp_iomem;
+    MemoryRegion pwl_iomem;
+    MemoryRegion pwt_iomem;
+    MemoryRegion mpui_io_iomem;
+    MemoryRegion imif_ram;
+    MemoryRegion emiff_ram;
+
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
                         target_phys_addr_t offset);
@@ -850,7 +840,7 @@ struct omap_mpu_state_s {
     /* MPUI-TIPB peripherals */
     struct omap_uart_s *uart[3];
 
-    struct omap_gpio_s *gpio;
+    DeviceState *gpio;
 
     struct omap_mcbsp_s *mcbsp1;
     struct omap_mcbsp_s *mcbsp3;
@@ -887,7 +877,7 @@ struct omap_mpu_state_s {
     struct omap_lpg_s *led[2];
 
     /* MPU private TIPB peripherals */
-    struct omap_intr_handler_s *ih[2];
+    DeviceState *ih[2];
 
     struct soc_dma_s *dma;
 
@@ -916,6 +906,7 @@ struct omap_mpu_state_s {
     uint32_t tcmi_regs[17];
 
     struct dpll_ctl_s {
+        MemoryRegion iomem;
         uint16_t mode;
         omap_clk dpll;
     } dpll[3];
@@ -948,8 +939,6 @@ struct omap_mpu_state_s {
     struct omap_gpmc_s *gpmc;
     struct omap_sysctl_s *sysc;
 
-    struct omap_gpif_s *gpif;
-
     struct omap_mcspi_s *mcspi[2];
 
     struct omap_dss_s *dss;
@@ -958,7 +947,8 @@ struct omap_mpu_state_s {
 };
 
 /* omap1.c */
-struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
+                unsigned long sdram_size,
                 const char *core);
 
 /* omap2.c */
@@ -1123,7 +1113,7 @@ inline static int debug_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                                            CPUWriteMemoryFunc * const *mem_write,
                                            void *opaque)
 {
-    struct io_fn *s = qemu_malloc(sizeof(struct io_fn));
+    struct io_fn *s = g_malloc(sizeof(struct io_fn));
 
     s->mem_read = mem_read;
     s->mem_write = mem_write;
index d5e4dabc876dcaf53a48162d62a55c26ef0d7fe5..619812c1764d6a0160f8c22b3fdf32f82639d358 100644 (file)
@@ -27,6 +27,7 @@
 #include "pc.h"
 #include "blockdev.h"
 #include "range.h"
+#include "sysbus.h"
 
 /* Should signal the TCMI/GPMC */
 uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
@@ -83,6 +84,7 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
 
 /* MPU OS timers */
 struct omap_mpu_timer_s {
+    MemoryRegion iomem;
     qemu_irq irq;
     omap_clk clk;
     uint32_t val;
@@ -101,7 +103,7 @@ struct omap_mpu_timer_s {
 
 static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
 {
-    uint64_t distance = qemu_get_clock(vm_clock) - timer->time;
+    uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time;
 
     if (timer->st && timer->enable && timer->rate)
         return timer->val - muldiv64(distance >> (timer->ptv + 1),
@@ -113,7 +115,7 @@ static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
 static inline void omap_timer_sync(struct omap_mpu_timer_s *timer)
 {
     timer->val = omap_timer_read(timer);
-    timer->time = qemu_get_clock(vm_clock);
+    timer->time = qemu_get_clock_ns(vm_clock);
 }
 
 static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
@@ -178,10 +180,15 @@ static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
     timer->rate = omap_clk_getrate(timer->clk);
 }
 
-static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
 {
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* CNTL_TIMER */
         return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
@@ -198,10 +205,14 @@ static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                 uint64_t value, unsigned size)
 {
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* CNTL_TIMER */
         omap_timer_sync(s);
@@ -225,16 +236,10 @@ static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpu_timer_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_mpu_timer_read,
-};
-
-static CPUWriteMemoryFunc * const omap_mpu_timer_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_mpu_timer_write,
+static const MemoryRegionOps omap_mpu_timer_ops = {
+    .read = omap_mpu_timer_read,
+    .write = omap_mpu_timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
@@ -249,23 +254,24 @@ static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
     s->it_ena = 1;
 }
 
-static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
+static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
-            qemu_mallocz(sizeof(struct omap_mpu_timer_s));
+            g_malloc0(sizeof(struct omap_mpu_timer_s));
 
     s->irq = irq;
     s->clk = clk;
-    s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s);
     s->tick = qemu_bh_new(omap_timer_fire, s);
     omap_mpu_timer_reset(s);
     omap_timer_clk_setup(s);
 
-    iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn,
-                    omap_mpu_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s,
+                          "omap-mpu-timer", 0x100);
+
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -273,16 +279,22 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
 /* Watchdog timer */
 struct omap_watchdog_timer_s {
     struct omap_mpu_timer_s timer;
+    MemoryRegion iomem;
     uint8_t last_wr;
     int mode;
     int free;
     int reset;
 };
 
-static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* CNTL_TIMER */
         return (s->timer.ptv << 9) | (s->timer.ar << 8) |
@@ -300,10 +312,14 @@ static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* CNTL_TIMER */
         omap_timer_sync(&s->timer);
@@ -343,16 +359,10 @@ static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_wd_timer_readfn[] = {
-    omap_badwidth_read16,
-    omap_wd_timer_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_wd_timer_writefn[] = {
-    omap_badwidth_write16,
-    omap_wd_timer_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_wd_timer_ops = {
+    .read = omap_wd_timer_read,
+    .write = omap_wd_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
@@ -373,22 +383,22 @@ static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
     omap_timer_update(&s->timer);
 }
 
-static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
+static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
-            qemu_mallocz(sizeof(struct omap_watchdog_timer_s));
+            g_malloc0(sizeof(struct omap_watchdog_timer_s));
 
     s->timer.irq = irq;
     s->timer.clk = clk;
-    s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer);
+    s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
     omap_wd_timer_reset(s);
     omap_timer_clk_setup(&s->timer);
 
-    iomemtype = cpu_register_io_memory(omap_wd_timer_readfn,
-                    omap_wd_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s,
+                          "omap-wd-timer", 0x100);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
@@ -396,13 +406,19 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
 /* 32-kHz timer */
 struct omap_32khz_timer_s {
     struct omap_mpu_timer_s timer;
+    MemoryRegion iomem;
 };
 
-static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_os_timer_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* TVR */
         return s->timer.reset_val;
@@ -421,11 +437,15 @@ static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* TVR */
         s->timer.reset_val = value & 0x00ffffff;
@@ -451,16 +471,10 @@ static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_os_timer_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_os_timer_read,
-};
-
-static CPUWriteMemoryFunc * const omap_os_timer_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_os_timer_write,
+static const MemoryRegionOps omap_os_timer_ops = {
+    .read = omap_os_timer_read,
+    .write = omap_os_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
@@ -475,37 +489,42 @@ static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
     s->timer.ar = 1;
 }
 
-static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
+static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
-            qemu_mallocz(sizeof(struct omap_32khz_timer_s));
+            g_malloc0(sizeof(struct omap_32khz_timer_s));
 
     s->timer.irq = irq;
     s->timer.clk = clk;
-    s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer);
+    s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
     omap_os_timer_reset(s);
     omap_timer_clk_setup(&s->timer);
 
-    iomemtype = cpu_register_io_memory(omap_os_timer_readfn,
-                    omap_os_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_os_timer_ops, s,
+                          "omap-os-timer", 0x800);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
 
 /* Ultra Low-Power Device Module */
-static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x14: /* IT_STATUS */
         ret = s->ulpd_pm_regs[addr >> 2];
         s->ulpd_pm_regs[addr >> 2] = 0;
-        qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]);
+        qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
         return ret;
 
     case 0x18: /* Reserved */
@@ -559,7 +578,7 @@ static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                               uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int64_t now, ticks;
@@ -567,6 +586,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
     static const int bypass_div[4] = { 1, 2, 4, 4 };
     uint16_t diff;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* COUNTER_32_LSB */
     case 0x04: /* COUNTER_32_MSB */
@@ -580,7 +603,7 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
     case 0x10: /* GAUGING_CTRL */
         /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
         if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) {
-            now = qemu_get_clock(vm_clock);
+            now = qemu_get_clock_ns(vm_clock);
 
             if (value & 1)
                 s->ulpd_gauge_start = now;
@@ -602,7 +625,7 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
                     s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
 
                 s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;  /* IT_GAUGING */
-                qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]);
+                qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
             }
         }
         s->ulpd_pm_regs[addr >> 2] = value;
@@ -673,16 +696,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_ulpd_pm_readfn[] = {
-    omap_badwidth_read16,
-    omap_ulpd_pm_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_ulpd_pm_writefn[] = {
-    omap_badwidth_write16,
-    omap_ulpd_pm_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_ulpd_pm_ops = {
+    .read = omap_ulpd_pm_read,
+    .write = omap_ulpd_pm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
@@ -712,21 +729,26 @@ static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
     omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
 }
 
-static void omap_ulpd_pm_init(target_phys_addr_t base,
+static void omap_ulpd_pm_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_ulpd_pm_readfn,
-                    omap_ulpd_pm_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu,
+                          "omap-ulpd-pm", 0x800);
+    memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem);
     omap_ulpd_pm_reset(mpu);
 }
 
 /* OMAP Pin Configuration */
-static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* FUNC_MUX_CTRL_0 */
     case 0x04: /* FUNC_MUX_CTRL_1 */
@@ -826,11 +848,15 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                               uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint32_t diff;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* FUNC_MUX_CTRL_0 */
         diff = s->func_mux_ctrl[addr >> 2] ^ value;
@@ -899,16 +925,10 @@ static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pin_cfg_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_pin_cfg_read,
-};
-
-static CPUWriteMemoryFunc * const omap_pin_cfg_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_pin_cfg_write,
+static const MemoryRegionOps omap_pin_cfg_ops = {
+    .read = omap_pin_cfg_read,
+    .write = omap_pin_cfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
@@ -927,21 +947,26 @@ static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
     memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
 }
 
-static void omap_pin_cfg_init(target_phys_addr_t base,
+static void omap_pin_cfg_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_pin_cfg_readfn,
-                    omap_pin_cfg_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu,
+                          "omap-pin-cfg", 0x800);
+    memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem);
     omap_pin_cfg_reset(mpu);
 }
 
 /* Device Identification, Die Identification */
-static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_id_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0xfffe1800:   /* DIE_ID_LSB */
         return 0xc9581f0e;
@@ -981,38 +1006,48 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_id_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                          uint64_t value, unsigned size)
 {
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap_id_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_id_read,
+static const MemoryRegionOps omap_id_ops = {
+    .read = omap_id_read,
+    .write = omap_id_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const omap_id_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_id_write,
-};
-
-static void omap_id_init(struct omap_mpu_state_s *mpu)
+static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_id_readfn,
-                    omap_id_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory_offset(0xfffe1800, 0x800, iomemtype, 0xfffe1800);
-    cpu_register_physical_memory_offset(0xfffed400, 0x100, iomemtype, 0xfffed400);
-    if (!cpu_is_omap15xx(mpu))
-        cpu_register_physical_memory_offset(0xfffe2000, 0x800, iomemtype, 0xfffe2000);
+    memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu,
+                          "omap-id", 0x100000000ULL);
+    memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem,
+                             0xfffe1800, 0x800);
+    memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18);
+    memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem,
+                             0xfffed400, 0x100);
+    memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4);
+    if (!cpu_is_omap15xx(mpu)) {
+        memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20",
+                                 &mpu->id_iomem, 0xfffe2000, 0x800);
+        memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20);
+    }
 }
 
 /* MPUI Control (Dummy) */
-static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpui_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* CTRL */
         return s->mpui_ctrl;
@@ -1038,10 +1073,14 @@ static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* CTRL */
         s->mpui_ctrl = value & 0x007fffff;
@@ -1063,16 +1102,10 @@ static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpui_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_mpui_read,
-};
-
-static CPUWriteMemoryFunc * const omap_mpui_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_mpui_write,
+static const MemoryRegionOps omap_mpui_ops = {
+    .read = omap_mpui_read,
+    .write = omap_mpui_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mpui_reset(struct omap_mpu_state_s *s)
@@ -1080,13 +1113,12 @@ static void omap_mpui_reset(struct omap_mpu_state_s *s)
     s->mpui_ctrl = 0x0003ff1b;
 }
 
-static void omap_mpui_init(target_phys_addr_t base,
+static void omap_mpui_init(MemoryRegion *memory, target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_mpui_readfn,
-                    omap_mpui_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu,
+                          "omap-mpui", 0x100);
+    memory_region_add_subregion(memory, base, &mpu->mpui_iomem);
 
     omap_mpui_reset(mpu);
 }
@@ -1094,6 +1126,7 @@ static void omap_mpui_init(target_phys_addr_t base,
 /* TIPB Bridges */
 struct omap_tipb_bridge_s {
     qemu_irq abort;
+    MemoryRegion iomem;
 
     int width_intr;
     uint16_t control;
@@ -1102,10 +1135,15 @@ struct omap_tipb_bridge_s {
     uint16_t enh_control;
 };
 
-static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr,
+                                      unsigned size)
 {
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
 
+    if (size < 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* TIPB_CNTL */
         return s->control;
@@ -1128,10 +1166,14 @@ static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                   uint64_t value, unsigned size)
 {
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
 
+    if (size < 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* TIPB_CNTL */
         s->control = value & 0xffff;
@@ -1162,16 +1204,10 @@ static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_tipb_bridge_readfn[] = {
-    omap_badwidth_read16,
-    omap_tipb_bridge_read,
-    omap_tipb_bridge_read,
-};
-
-static CPUWriteMemoryFunc * const omap_tipb_bridge_writefn[] = {
-    omap_badwidth_write16,
-    omap_tipb_bridge_write,
-    omap_tipb_bridge_write,
+static const MemoryRegionOps omap_tipb_bridge_ops = {
+    .read = omap_tipb_bridge_read,
+    .write = omap_tipb_bridge_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
@@ -1182,29 +1218,34 @@ static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
     s->enh_control = 0x000f;
 }
 
-static struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
-                qemu_irq abort_irq, omap_clk clk)
+static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
+    MemoryRegion *memory, target_phys_addr_t base,
+    qemu_irq abort_irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
-            qemu_mallocz(sizeof(struct omap_tipb_bridge_s));
+            g_malloc0(sizeof(struct omap_tipb_bridge_s));
 
     s->abort = abort_irq;
     omap_tipb_bridge_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn,
-                    omap_tipb_bridge_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s,
+                          "omap-tipb-bridge", 0x100);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
 
 /* Dummy Traffic Controller's Memory Interface */
-static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_tcmi_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint32_t ret;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* IMIF_PRIO */
     case 0x04: /* EMIFS_PRIO */
@@ -1234,10 +1275,14 @@ static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* IMIF_PRIO */
     case 0x04: /* EMIFS_PRIO */
@@ -1264,16 +1309,10 @@ static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_tcmi_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_tcmi_read,
-};
-
-static CPUWriteMemoryFunc * const omap_tcmi_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_tcmi_write,
+static const MemoryRegionOps omap_tcmi_ops = {
+    .read = omap_tcmi_read,
+    .write = omap_tcmi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
@@ -1295,21 +1334,25 @@ static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
     mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
 }
 
-static void omap_tcmi_init(target_phys_addr_t base,
+static void omap_tcmi_init(MemoryRegion *memory, target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_tcmi_readfn,
-                    omap_tcmi_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu,
+                          "omap-tcmi", 0x100);
+    memory_region_add_subregion(memory, base, &mpu->tcmi_iomem);
     omap_tcmi_reset(mpu);
 }
 
 /* Digital phase-locked loops control */
-static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     if (addr == 0x00)  /* CTL_REG */
         return s->mode;
 
@@ -1318,13 +1361,17 @@ static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
     uint16_t diff;
     static const int bypass_div[4] = { 1, 2, 4, 4 };
     int div, mult;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     if (addr == 0x00) {        /* CTL_REG */
         /* See omap_ulpd_pm_write() too */
         diff = s->mode & value;
@@ -1350,16 +1397,10 @@ static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_dpll_readfn[] = {
-    omap_badwidth_read16,
-    omap_dpll_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_dpll_writefn[] = {
-    omap_badwidth_write16,
-    omap_dpll_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_dpll_ops = {
+    .read = omap_dpll_read,
+    .write = omap_dpll_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_dpll_reset(struct dpll_ctl_s *s)
@@ -1368,23 +1409,27 @@ static void omap_dpll_reset(struct dpll_ctl_s *s)
     omap_clk_setrate(s->dpll, 1, 1);
 }
 
-static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
-                omap_clk clk)
+static void omap_dpll_init(MemoryRegion *memory, struct dpll_ctl_s *s,
+                           target_phys_addr_t base, omap_clk clk)
 {
-    int iomemtype = cpu_register_io_memory(omap_dpll_readfn,
-                    omap_dpll_writefn, s, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
 
     s->dpll = clk;
     omap_dpll_reset(s);
 
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_add_subregion(memory, base, &s->iomem);
 }
 
 /* MPU Clock/Reset/Power Mode Control */
-static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_clkm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00: /* ARM_CKCTL */
         return s->clkm.arm_ckctl;
@@ -1578,7 +1623,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t diff;
@@ -1588,6 +1633,10 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
         "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
     };
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00: /* ARM_CKCTL */
         diff = s->clkm.arm_ckctl ^ value;
@@ -1654,22 +1703,21 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_clkm_readfn[] = {
-    omap_badwidth_read16,
-    omap_clkm_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_clkm_writefn[] = {
-    omap_badwidth_write16,
-    omap_clkm_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_clkm_ops = {
+    .read = omap_clkm_read,
+    .write = omap_clkm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x04: /* DSP_IDLECT1 */
         return s->clkm.dsp_idlect1;
@@ -1706,11 +1754,15 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                              uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t diff;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x04: /* DSP_IDLECT1 */
         diff = s->clkm.dsp_idlect1 ^ value;
@@ -1737,16 +1789,10 @@ static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_clkdsp_readfn[] = {
-    omap_badwidth_read16,
-    omap_clkdsp_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_clkdsp_writefn[] = {
-    omap_badwidth_write16,
-    omap_clkdsp_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_clkdsp_ops = {
+    .read = omap_clkdsp_read,
+    .write = omap_clkdsp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_clkm_reset(struct omap_mpu_state_s *s)
@@ -1772,15 +1818,13 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s)
     s->clkm.dsp_rstct2 = 0x0000;
 }
 
-static void omap_clkm_init(target_phys_addr_t mpu_base,
+static void omap_clkm_init(MemoryRegion *memory, target_phys_addr_t mpu_base,
                 target_phys_addr_t dsp_base, struct omap_mpu_state_s *s)
 {
-    int iomemtype[2] = {
-        cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s,
-                               DEVICE_NATIVE_ENDIAN),
-        cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s,
-                               DEVICE_NATIVE_ENDIAN),
-    };
+    memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s,
+                          "omap-clkm", 0x100);
+    memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s,
+                          "omap-clkdsp", 0x1000);
 
     s->clkm.arm_idlect1 = 0x03ff;
     s->clkm.arm_idlect2 = 0x0100;
@@ -1788,8 +1832,8 @@ static void omap_clkm_init(target_phys_addr_t mpu_base,
     omap_clkm_reset(s);
     s->clkm.cold_start = 0x3a;
 
-    cpu_register_physical_memory(mpu_base, 0x100, iomemtype[0]);
-    cpu_register_physical_memory(dsp_base, 0x1000, iomemtype[1]);
+    memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem);
+    memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem);
 }
 
 /* MPU I/O */
@@ -1799,6 +1843,7 @@ struct omap_mpuio_s {
     qemu_irq *in;
     qemu_irq handler[16];
     qemu_irq wakeup;
+    MemoryRegion iomem;
 
     uint16_t inputs;
     uint16_t outputs;
@@ -1853,12 +1898,17 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s)
     s->row_latch = ~rows;
 }
 
-static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpuio_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* INPUT_LATCH */
         return s->inputs;
@@ -1909,13 +1959,17 @@ static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpuio_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t diff;
     int ln;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x04: /* OUTPUT_REG */
         diff = (s->outputs ^ value) & ~s->dir;
@@ -1981,16 +2035,10 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpuio_readfn[] = {
-    omap_badwidth_read16,
-    omap_mpuio_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_mpuio_writefn[] = {
-    omap_badwidth_write16,
-    omap_mpuio_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_mpuio_ops  = {
+    .read = omap_mpuio_read,
+    .write = omap_mpuio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mpuio_reset(struct omap_mpuio_s *s)
@@ -2018,13 +2066,13 @@ static void omap_mpuio_onoff(void *opaque, int line, int on)
         omap_mpuio_kbd_update(s);
 }
 
-struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
                 omap_clk clk)
 {
-    int iomemtype;
     struct omap_mpuio_s *s = (struct omap_mpuio_s *)
-            qemu_mallocz(sizeof(struct omap_mpuio_s));
+            g_malloc0(sizeof(struct omap_mpuio_s));
 
     s->irq = gpio_int;
     s->kbd_irq = kbd_int;
@@ -2032,9 +2080,9 @@ struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
     s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16);
     omap_mpuio_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_mpuio_readfn,
-                    omap_mpuio_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mpuio_ops, s,
+                          "omap-mpuio", 0x800);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]);
 
@@ -2068,6 +2116,7 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down)
 
 /* MicroWire Interface */
 struct omap_uwire_s {
+    MemoryRegion iomem;
     qemu_irq txirq;
     qemu_irq rxirq;
     qemu_irq txdrq;
@@ -2105,11 +2154,16 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s)
     }
 }
 
-static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_uwire_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* RDR */
         s->control &= ~(1 << 15);                      /* RDRB */
@@ -2135,11 +2189,15 @@ static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_uwire_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* TDR */
         s->txbuf = value;                              /* TD */
@@ -2183,16 +2241,10 @@ static void omap_uwire_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_uwire_readfn[] = {
-    omap_badwidth_read16,
-    omap_uwire_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_uwire_writefn[] = {
-    omap_badwidth_write16,
-    omap_uwire_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_uwire_ops = {
+    .read = omap_uwire_read,
+    .write = omap_uwire_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_uwire_reset(struct omap_uwire_s *s)
@@ -2205,21 +2257,22 @@ static void omap_uwire_reset(struct omap_uwire_s *s)
     s->setup[4] = 0;
 }
 
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk)
+static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
+                                            target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq dma,
+                                            omap_clk clk)
 {
-    int iomemtype;
     struct omap_uwire_s *s = (struct omap_uwire_s *)
-            qemu_mallocz(sizeof(struct omap_uwire_s));
+            g_malloc0(sizeof(struct omap_uwire_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma;
     omap_uwire_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_uwire_readfn,
-                    omap_uwire_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -2246,11 +2299,16 @@ static void omap_pwl_update(struct omap_mpu_state_s *s)
     }
 }
 
-static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* PWL_LEVEL */
         return s->pwl.level;
@@ -2262,11 +2320,15 @@ static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* PWL_LEVEL */
         s->pwl.level = value;
@@ -2282,16 +2344,10 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pwl_readfn[] = {
-    omap_pwl_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_pwl_writefn[] = {
-    omap_pwl_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_pwl_ops = {
+    .read = omap_pwl_read,
+    .write = omap_pwl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pwl_reset(struct omap_mpu_state_s *s)
@@ -2311,26 +2367,30 @@ static void omap_pwl_clk_update(void *opaque, int line, int on)
     omap_pwl_update(s);
 }
 
-static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+static void omap_pwl_init(MemoryRegion *system_memory,
+                target_phys_addr_t base, struct omap_mpu_state_s *s,
                 omap_clk clk)
 {
-    int iomemtype;
-
     omap_pwl_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_pwl_readfn,
-                    omap_pwl_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->pwl_iomem, &omap_pwl_ops, s,
+                          "omap-pwl", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->pwl_iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
 }
 
 /* Pulse-Width Tone module */
-static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* FRC */
         return s->pwt.frc;
@@ -2344,11 +2404,15 @@ static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* FRC */
         s->pwt.frc = value & 0x3f;
@@ -2386,16 +2450,10 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pwt_readfn[] = {
-    omap_pwt_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_pwt_writefn[] = {
-    omap_pwt_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_pwt_ops = {
+    .read =omap_pwt_read,
+    .write = omap_pwt_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pwt_reset(struct omap_mpu_state_s *s)
@@ -2405,21 +2463,21 @@ static void omap_pwt_reset(struct omap_mpu_state_s *s)
     s->pwt.gcr = 0;
 }
 
-static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+static void omap_pwt_init(MemoryRegion *system_memory,
+                target_phys_addr_t base, struct omap_mpu_state_s *s,
                 omap_clk clk)
 {
-    int iomemtype;
-
     s->pwt.clk = clk;
     omap_pwt_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_pwt_readfn,
-                    omap_pwt_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->pwt_iomem, &omap_pwt_ops, s,
+                          "omap-pwt", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->pwt_iomem);
 }
 
 /* Real-time Clock module */
 struct omap_rtc_s {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq alarm;
     QEMUTimer *clk;
@@ -2452,12 +2510,17 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s)
         printf("%s: conversion failed\n", __FUNCTION__);
 }
 
-static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_rtc_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint8_t i;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* SECONDS_REG */
         return to_bcd(s->current_tm.tm_sec);
@@ -2530,13 +2593,17 @@ static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_rtc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     struct tm new_tm;
     time_t ti[2];
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* SECONDS_REG */
 #ifdef ALMDEBUG
@@ -2717,16 +2784,10 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_rtc_readfn[] = {
-    omap_rtc_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_rtc_writefn[] = {
-    omap_rtc_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_rtc_ops = {
+    .read = omap_rtc_read,
+    .write = omap_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_rtc_tick(void *opaque)
@@ -2802,7 +2863,7 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
     s->pm_am = 0;
     s->auto_comp = 0;
     s->round = 0;
-    s->tick = qemu_get_clock(rt_clock);
+    s->tick = qemu_get_clock_ms(rt_clock);
     memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
     s->alarm_tm.tm_mday = 0x01;
     s->status = 1 << 7;
@@ -2813,28 +2874,30 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
     omap_rtc_tick(s);
 }
 
-static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
-                qemu_irq *irq, omap_clk clk)
+static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
+                                        target_phys_addr_t base,
+                                        qemu_irq timerirq, qemu_irq alarmirq,
+                                        omap_clk clk)
 {
-    int iomemtype;
     struct omap_rtc_s *s = (struct omap_rtc_s *)
-            qemu_mallocz(sizeof(struct omap_rtc_s));
+            g_malloc0(sizeof(struct omap_rtc_s));
 
-    s->irq = irq[0];
-    s->alarm = irq[1];
-    s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s);
+    s->irq = timerirq;
+    s->alarm = alarmirq;
+    s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s);
 
     omap_rtc_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_rtc_readfn,
-                    omap_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_rtc_ops, s,
+                          "omap-rtc", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
 
 /* Multi-channel Buffered Serial Port interfaces */
 struct omap_mcbsp_s {
+    MemoryRegion iomem;
     qemu_irq txirq;
     qemu_irq rxirq;
     qemu_irq txdrq;
@@ -2915,7 +2978,7 @@ static void omap_mcbsp_source_tick(void *opaque)
     s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
 
     omap_mcbsp_rx_newdata(s);
-    qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) +
                    get_ticks_per_sec());
 }
 
@@ -2961,7 +3024,7 @@ static void omap_mcbsp_sink_tick(void *opaque)
     s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
 
     omap_mcbsp_tx_newdata(s);
-    qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) +
                    get_ticks_per_sec());
 }
 
@@ -3040,12 +3103,17 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
         omap_mcbsp_rx_stop(s);
 }
 
-static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* DRR2 */
         if (((s->rcr[0] >> 5) & 7) < 3)                        /* RWDLEN1 */
@@ -3302,16 +3370,20 @@ static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr,
     omap_badwidth_write16(opaque, addr, value);
 }
 
-static CPUReadMemoryFunc * const omap_mcbsp_readfn[] = {
-    omap_badwidth_read16,
-    omap_mcbsp_read,
-    omap_badwidth_read16,
-};
+static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t value, unsigned size)
+{
+    switch (size) {
+    case 2: return omap_mcbsp_writeh(opaque, addr, value);
+    case 4: return omap_mcbsp_writew(opaque, addr, value);
+    default: return omap_badwidth_write16(opaque, addr, value);
+    }
+}
 
-static CPUWriteMemoryFunc * const omap_mcbsp_writefn[] = {
-    omap_badwidth_write16,
-    omap_mcbsp_writeh,
-    omap_mcbsp_writew,
+static const MemoryRegionOps omap_mcbsp_ops = {
+    .read = omap_mcbsp_read,
+    .write = omap_mcbsp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
@@ -3333,24 +3405,24 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
     qemu_del_timer(s->sink_timer);
 }
 
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk)
+static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
+                                            target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq *dma, omap_clk clk)
 {
-    int iomemtype;
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
-            qemu_mallocz(sizeof(struct omap_mcbsp_s));
+            g_malloc0(sizeof(struct omap_mcbsp_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma[0];
     s->rxdrq = dma[1];
-    s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s);
-    s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s);
+    s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s);
+    s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s);
     omap_mcbsp_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_mcbsp_readfn,
-                    omap_mcbsp_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -3384,6 +3456,7 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave)
 
 /* LED Pulse Generators */
 struct omap_lpg_s {
+    MemoryRegion iomem;
     QEMUTimer *tm;
 
     uint8_t control;
@@ -3399,9 +3472,9 @@ static void omap_lpg_tick(void *opaque)
     struct omap_lpg_s *s = opaque;
 
     if (s->cycle)
-        qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->period - s->on);
+        qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->period - s->on);
     else
-        qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->on);
+        qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->on);
 
     s->cycle = !s->cycle;
     printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
@@ -3448,11 +3521,16 @@ static void omap_lpg_reset(struct omap_lpg_s *s)
     omap_lpg_update(s);
 }
 
-static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_lpg_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00: /* LCR */
         return s->control;
@@ -3466,11 +3544,15 @@ static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00: /* LCR */
         if (~value & (1 << 6))                                 /* LPGRES */
@@ -3490,16 +3572,10 @@ static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_lpg_readfn[] = {
-    omap_lpg_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_lpg_writefn[] = {
-    omap_lpg_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_lpg_ops = {
+    .read = omap_lpg_read,
+    .write = omap_lpg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_lpg_clk_update(void *opaque, int line, int on)
@@ -3510,19 +3586,18 @@ static void omap_lpg_clk_update(void *opaque, int line, int on)
     omap_lpg_update(s);
 }
 
-static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
+static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
+                                        target_phys_addr_t base, omap_clk clk)
 {
-    int iomemtype;
     struct omap_lpg_s *s = (struct omap_lpg_s *)
-            qemu_mallocz(sizeof(struct omap_lpg_s));
+            g_malloc0(sizeof(struct omap_lpg_s));
 
-    s->tm = qemu_new_timer(rt_clock, omap_lpg_tick, s);
+    s->tm = qemu_new_timer_ms(rt_clock, omap_lpg_tick, s);
 
     omap_lpg_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_lpg_readfn,
-                    omap_lpg_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
 
@@ -3530,8 +3605,13 @@ static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
 }
 
 /* MPUI Peripheral Bridge configuration */
-static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     if (addr == OMAP_MPUI_BASE)        /* CMR */
         return 0xfe4d;
 
@@ -3539,23 +3619,26 @@ static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static CPUReadMemoryFunc * const omap_mpui_io_readfn[] = {
-    omap_badwidth_read16,
-    omap_mpui_io_read,
-    omap_badwidth_read16,
-};
+static void omap_mpui_io_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t value, unsigned size)
+{
+    /* FIXME: infinite loop */
+    omap_badwidth_write16(opaque, addr, value);
+}
 
-static CPUWriteMemoryFunc * const omap_mpui_io_writefn[] = {
-    omap_badwidth_write16,
-    omap_badwidth_write16,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_mpui_io_ops = {
+    .read = omap_mpui_io_read,
+    .write = omap_mpui_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
+static void omap_setup_mpui_io(MemoryRegion *system_memory,
+                               struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn,
-                    omap_mpui_io_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype);
+    memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu,
+                          "omap-mpui-io", 0x7fff);
+    memory_region_add_subregion(system_memory, OMAP_MPUI_BASE,
+                                &mpu->mpui_io_iomem);
 }
 
 /* General chip reset */
@@ -3563,8 +3646,6 @@ static void omap1_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
-    omap_inth_reset(mpu->ih[1]);
     omap_dma_reset(mpu->dma);
     omap_mpu_timer_reset(mpu->timer[0]);
     omap_mpu_timer_reset(mpu->timer[1]);
@@ -3585,7 +3666,6 @@ static void omap1_mpu_reset(void *opaque)
     omap_uart_reset(mpu->uart[2]);
     omap_mmc_reset(mpu->mmc);
     omap_mpuio_reset(mpu->mpuio);
-    omap_gpio_reset(mpu->gpio);
     omap_uwire_reset(mpu->microwire);
     omap_pwl_reset(mpu);
     omap_pwt_reset(mpu);
@@ -3630,14 +3710,16 @@ static const struct omap_map_s {
     { 0 }
 };
 
-static void omap_setup_dsp_mapping(const struct omap_map_s *map)
+static void omap_setup_dsp_mapping(MemoryRegion *system_memory,
+                                   const struct omap_map_s *map)
 {
-    int io;
+    MemoryRegion *io;
 
     for (; map->phys_dsp; map ++) {
-        io = cpu_get_physical_page_desc(map->phys_mpu);
-
-        cpu_register_physical_memory(map->phys_dsp, map->size, io);
+        io = g_new(MemoryRegion, 1);
+        memory_region_init_alias(io, map->name,
+                                 system_memory, map->phys_mpu, map->size);
+        memory_region_add_subregion(system_memory, map->phys_dsp, io);
     }
 }
 
@@ -3706,16 +3788,17 @@ static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
     return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
 }
 
-struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
+                unsigned long sdram_size,
                 const char *core)
 {
     int i;
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
-            qemu_mallocz(sizeof(struct omap_mpu_state_s));
-    ram_addr_t imif_base, emiff_base;
+            g_malloc0(sizeof(struct omap_mpu_state_s));
     qemu_irq *cpu_irq;
     qemu_irq dma_irqs[6];
     DriveInfo *dinfo;
+    SysBusDevice *busdev;
 
     if (!core)
         core = "ti925t";
@@ -3736,27 +3819,38 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     omap_clk_init(s);
 
     /* Memory-mapped stuff */
-    cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size,
-                    (emiff_base = qemu_ram_alloc(NULL, "omap1.dram",
-                                                 s->sdram_size)) | IO_MEM_RAM);
-    cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size,
-                    (imif_base = qemu_ram_alloc(NULL, "omap1.sram",
-                                                s->sram_size)) | IO_MEM_RAM);
+    memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size);
+    memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
+    memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size);
+    memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
 
-    omap_clkm_init(0xfffece00, 0xe1008000, s);
+    omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
 
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "arminth_ck"));
-    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1],
-                    omap_inth_get_pin(s->ih[0], OMAP_INT_15XX_IH2_IRQ),
-                   NULL, omap_findclk(s, "arminth_ck"));
-
-    for (i = 0; i < 6; i ++)
-        dma_irqs[i] =
-                s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr];
-    s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
+    s->ih[0] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[0], "size", 0x100);
+    qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0xfffecb00);
+    s->ih[1] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[1], "size", 0x800);
+    qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[1]);
+    busdev = sysbus_from_qdev(s->ih[1]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ));
+    /* The second interrupt controller's FIQ output is not wired up */
+    sysbus_mmio_map(busdev, 0, 0xfffe0000);
+
+    for (i = 0; i < 6; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih],
+                                       omap1_dma_irq_map[i].intr);
+    }
+    s->dma = omap_dma_init(0xfffed800, dma_irqs,
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD),
                            s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
 
     s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
@@ -3767,70 +3861,77 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
 
     /* Register SDRAM and SRAM DMA ports for fast transfers.  */
-    soc_dma_port_add_mem_ram(s->dma,
-                    emiff_base, OMAP_EMIFF_BASE, s->sdram_size);
-    soc_dma_port_add_mem_ram(s->dma,
-                    imif_base, OMAP_IMIF_BASE, s->sram_size);
+    soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram),
+                         OMAP_EMIFF_BASE, s->sdram_size);
+    soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram),
+                         OMAP_IMIF_BASE, s->sram_size);
 
-    s->timer[0] = omap_mpu_timer_init(0xfffec500,
-                    s->irq[0][OMAP_INT_TIMER1],
+    s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1),
                     omap_findclk(s, "mputim_ck"));
-    s->timer[1] = omap_mpu_timer_init(0xfffec600,
-                    s->irq[0][OMAP_INT_TIMER2],
+    s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2),
                     omap_findclk(s, "mputim_ck"));
-    s->timer[2] = omap_mpu_timer_init(0xfffec700,
-                    s->irq[0][OMAP_INT_TIMER3],
+    s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3),
                     omap_findclk(s, "mputim_ck"));
 
-    s->wdt = omap_wd_timer_init(0xfffec800,
-                    s->irq[0][OMAP_INT_WD_TIMER],
+    s->wdt = omap_wd_timer_init(system_memory, 0xfffec800,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER),
                     omap_findclk(s, "armwdt_ck"));
 
-    s->os_timer = omap_os_timer_init(0xfffb9000,
-                    s->irq[1][OMAP_INT_OS_TIMER],
+    s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000,
+                    qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
-                    omap_dma_get_lcdch(s->dma), imif_base, emiff_base,
-                    omap_findclk(s, "lcd_ck"));
+    s->lcd = omap_lcdc_init(0xfffec000,
+                            qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL),
+                            omap_dma_get_lcdch(s->dma),
+                            omap_findclk(s, "lcd_ck"));
 
-    omap_ulpd_pm_init(0xfffe0800, s);
-    omap_pin_cfg_init(0xfffe1000, s);
-    omap_id_init(s);
+    omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
+    omap_pin_cfg_init(system_memory, 0xfffe1000, s);
+    omap_id_init(system_memory, s);
 
-    omap_mpui_init(0xfffec900, s);
+    omap_mpui_init(system_memory, 0xfffec900, s);
 
-    s->private_tipb = omap_tipb_bridge_init(0xfffeca00,
-                    s->irq[0][OMAP_INT_BRIDGE_PRIV],
+    s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV),
                     omap_findclk(s, "tipb_ck"));
-    s->public_tipb = omap_tipb_bridge_init(0xfffed300,
-                    s->irq[0][OMAP_INT_BRIDGE_PUB],
+    s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300,
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB),
                     omap_findclk(s, "tipb_ck"));
 
-    omap_tcmi_init(0xfffecc00, s);
+    omap_tcmi_init(system_memory, 0xfffecc00, s);
 
-    s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
+    s->uart[0] = omap_uart_init(0xfffb0000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
                     omap_findclk(s, "uart1_ck"),
                     omap_findclk(s, "uart1_ck"),
                     s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
                     "uart1",
                     serial_hds[0]);
-    s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
+    s->uart[1] = omap_uart_init(0xfffb0800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
                     omap_findclk(s, "uart2_ck"),
                     omap_findclk(s, "uart2_ck"),
                     s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
-    s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
+    s->uart[2] = omap_uart_init(0xfffb9800,
+                                qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
                     omap_findclk(s, "uart3_ck"),
                     omap_findclk(s, "uart3_ck"),
                     s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
                     "uart3",
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
-    omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
-    omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
-    omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
 
     dinfo = drive_get(IF_SD, 0, 0);
     if (!dinfo) {
@@ -3838,37 +3939,59 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->mmc = omap_mmc_init(0xfffb7800, dinfo->bdrv,
-                    s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX],
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
+                           &s->drq[OMAP_DMA_MMC_TX],
                     omap_findclk(s, "mmc_ck"));
 
-    s->mpuio = omap_mpuio_init(0xfffb5000,
-                    s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
-                    s->wakeup, omap_findclk(s, "clk32-kHz"));
-
-    s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1],
-                    omap_findclk(s, "arm_gpio_ck"));
-
-    s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
+    s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO),
+                               s->wakeup, omap_findclk(s, "clk32-kHz"));
+
+    s->gpio = qdev_create(NULL, "omap-gpio");
+    qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+    qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck"));
+    qdev_init_nofail(s->gpio);
+    sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
+    sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
+
+    s->microwire = omap_uwire_init(system_memory, 0xfffb3000,
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX),
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
                     s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
 
-    omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck"));
-    omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck"));
+    omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck"));
+    omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck"));
 
-    s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
+    s->i2c[0] = omap_i2c_init(0xfffb3800,
+                              qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
                     &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
 
-    s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
+    s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
+    s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX),
                     &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
-    s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
+    s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000,
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_TX),
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_RX),
                     &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
-    s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
+    s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX),
                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
 
-    s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
-    s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz"));
+    s->led[0] = omap_lpg_init(system_memory,
+                              0xfffbd000, omap_findclk(s, "clk32-kHz"));
+    s->led[1] = omap_lpg_init(system_memory,
+                              0xfffbd800, omap_findclk(s, "clk32-kHz"));
 
     /* Register mappings not currenlty implemented:
      * MCSI2 Comm      fffb2000 - fffb27ff (not mapped on OMAP310)
@@ -3885,8 +4008,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
      * DSP MMU         fffed200 - fffed2ff
      */
 
-    omap_setup_dsp_mapping(omap15xx_dsp_mm);
-    omap_setup_mpui_io(s);
+    omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm);
+    omap_setup_mpui_io(system_memory, s);
 
     qemu_register_reset(omap1_mpu_reset, s);
 
index 0f13272c7b43536ba693402cab8734c83024b6f1..5197fef2d88475a27d1ff39d2310e608551cbfd7 100644 (file)
@@ -27,6 +27,7 @@
 #include "qemu-char.h"
 #include "flash.h"
 #include "soc_dma.h"
+#include "sysbus.h"
 #include "audio/audio.h"
 
 /* Enhanced Audio Controller (CODEC only) */
@@ -590,7 +591,7 @@ static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_eac_s *s = (struct omap_eac_s *)
-            qemu_mallocz(sizeof(struct omap_eac_s));
+            g_malloc0(sizeof(struct omap_eac_s));
 
     s->irq = irq;
     s->codec.rxdrq = *drq ++;
@@ -747,14 +748,14 @@ static void omap_sti_fifo_write(void *opaque, target_phys_addr_t addr,
 
     if (ch == STI_TRACE_CONTROL_CHANNEL) {
         /* Flush channel <i>value</i>.  */
-        qemu_chr_write(s->chr, (const uint8_t *) "\r", 1);
+        qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1);
     } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
         if (value == 0xc0 || value == 0xc3) {
             /* Open channel <i>ch</i>.  */
         } else if (value == 0x00)
-            qemu_chr_write(s->chr, (const uint8_t *) "\n", 1);
+            qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1);
         else
-            qemu_chr_write(s->chr, &byte, 1);
+            qemu_chr_fe_write(s->chr, &byte, 1);
     }
 }
 
@@ -776,12 +777,12 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_sti_s *s = (struct omap_sti_s *)
-            qemu_mallocz(sizeof(struct omap_sti_s));
+            g_malloc0(sizeof(struct omap_sti_s));
 
     s->irq = irq;
     omap_sti_reset(s);
 
-    s->chr = chr ?: qemu_chr_open("null", "null", NULL);
+    s->chr = chr ?: qemu_chr_new("null", "null", NULL);
 
     iomemtype = l4_register_io_memory(omap_sti_readfn,
                     omap_sti_writefn, s);
@@ -1789,7 +1790,7 @@ static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_prcm_s *s = (struct omap_prcm_s *)
-            qemu_mallocz(sizeof(struct omap_prcm_s));
+            g_malloc0(sizeof(struct omap_prcm_s));
 
     s->irq[0] = mpu_int;
     s->irq[1] = dsp_int;
@@ -2162,7 +2163,7 @@ static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_sysctl_s *s = (struct omap_sysctl_s *)
-            qemu_mallocz(sizeof(struct omap_sysctl_s));
+            g_malloc0(sizeof(struct omap_sysctl_s));
 
     s->mpu = mpu;
     omap_sysctl_reset(s);
@@ -2179,7 +2180,6 @@ static void omap2_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
     omap_dma_reset(mpu->dma);
     omap_prcm_reset(mpu->prcm);
     omap_sysctl_reset(mpu->sysc);
@@ -2203,7 +2203,6 @@ static void omap2_mpu_reset(void *opaque)
     omap_uart_reset(mpu->uart[1]);
     omap_uart_reset(mpu->uart[2]);
     omap_mmc_reset(mpu->mmc);
-    omap_gpif_reset(mpu->gpif);
     omap_mcspi_reset(mpu->mcspi[0]);
     omap_mcspi_reset(mpu->mcspi[1]);
     omap_i2c_reset(mpu->i2c[0]);
@@ -2228,13 +2227,14 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                 const char *core)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
-            qemu_mallocz(sizeof(struct omap_mpu_state_s));
+            g_malloc0(sizeof(struct omap_mpu_state_s));
     ram_addr_t sram_base, q2_base;
     qemu_irq *cpu_irq;
     qemu_irq dma_irqs[4];
-    omap_clk gpio_clks[4];
     DriveInfo *dinfo;
     int i;
+    SysBusDevice *busdev;
+    struct omap_target_agent_s *ta;
 
     /* Core */
     s->mpu_model = omap2420;
@@ -2263,31 +2263,41 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
 
     /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "mpu_intc_fclk"),
-                    omap_findclk(s, "mpu_intc_iclk"));
-
+    s->ih[0] = qdev_create(NULL, "omap2-intc");
+    qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
+    qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
+    qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0x480fe000);
     s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
-                    s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s);
+                             qdev_get_gpio_in(s->ih[0],
+                                              OMAP_INT_24XX_PRCM_MPU_IRQ),
+                             NULL, NULL, s);
 
     s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
                     omap_findclk(s, "omapctrl_iclk"), s);
 
-    for (i = 0; i < 4; i ++)
-        dma_irqs[i] =
-                s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr];
+    for (i = 0; i < 4; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
+                                       omap2_dma_irq_map[i].intr);
+    }
     s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
                     omap_findclk(s, "sdma_iclk"),
                     omap_findclk(s, "sdma_fclk"));
     s->port->addr_valid = omap2_validate_addr;
 
     /* Register SDRAM and SRAM ports for fast DMA transfers.  */
-    soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size);
-    soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(q2_base),
+                         OMAP2_Q2_BASE, s->sdram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(sram_base),
+                         OMAP2_SRAM_BASE, s->sram_size);
 
     s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
-                    s->irq[0][OMAP_INT_24XX_UART1_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART1_IRQ),
                     omap_findclk(s, "uart1_fclk"),
                     omap_findclk(s, "uart1_iclk"),
                     s->drq[OMAP24XX_DMA_UART1_TX],
@@ -2295,7 +2305,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart1",
                     serial_hds[0]);
     s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
-                    s->irq[0][OMAP_INT_24XX_UART2_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART2_IRQ),
                     omap_findclk(s, "uart2_fclk"),
                     omap_findclk(s, "uart2_iclk"),
                     s->drq[OMAP24XX_DMA_UART2_TX],
@@ -2303,7 +2314,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
     s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
-                    s->irq[0][OMAP_INT_24XX_UART3_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART3_IRQ),
                     omap_findclk(s, "uart3_fclk"),
                     omap_findclk(s, "uart3_iclk"),
                     s->drq[OMAP24XX_DMA_UART3_TX],
@@ -2312,51 +2324,51 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
     s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER1],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
                     omap_findclk(s, "wu_gpt1_clk"),
                     omap_findclk(s, "wu_l4_iclk"));
     s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER2],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
                     omap_findclk(s, "core_gpt2_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER3],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
                     omap_findclk(s, "core_gpt3_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER4],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
                     omap_findclk(s, "core_gpt4_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER5],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
                     omap_findclk(s, "core_gpt5_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER6],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
                     omap_findclk(s, "core_gpt6_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER7],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
                     omap_findclk(s, "core_gpt7_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER8],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
                     omap_findclk(s, "core_gpt8_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER9],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
                     omap_findclk(s, "core_gpt9_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER10],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
                     omap_findclk(s, "core_gpt10_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER11],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
                     omap_findclk(s, "core_gpt11_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER12],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
                     omap_findclk(s, "core_gpt12_clk"),
                     omap_findclk(s, "core_l4_iclk"));
 
@@ -2367,26 +2379,52 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "core_l4_iclk"));
 
     s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
-                    s->irq[0][OMAP_INT_24XX_I2C1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C1_TX],
                     omap_findclk(s, "i2c1.fclk"),
                     omap_findclk(s, "i2c1.iclk"));
     s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
-                    s->irq[0][OMAP_INT_24XX_I2C2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C2_TX],
                     omap_findclk(s, "i2c2.fclk"),
                     omap_findclk(s, "i2c2.iclk"));
 
-    gpio_clks[0] = omap_findclk(s, "gpio1_dbclk");
-    gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
-    gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
-    gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
-    s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
-                    &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
-                    gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
+    s->gpio = qdev_create(NULL, "omap2-gpio");
+    qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+    qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk"));
+    qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk"));
+    qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk"));
+    qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk"));
+    qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk"));
+    if (s->mpu_model == omap2430) {
+        qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk"));
+    }
+    qdev_init_nofail(s->gpio);
+    busdev = sysbus_from_qdev(s->gpio);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
+    sysbus_connect_irq(busdev, 3,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
+    sysbus_connect_irq(busdev, 6,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
+    sysbus_connect_irq(busdev, 9,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
+    if (s->mpu_model == omap2430) {
+        sysbus_connect_irq(busdev, 12,
+                           qdev_get_gpio_in(s->ih[0],
+                                            OMAP_INT_243X_GPIO_BANK5));
+    }
+    ta = omap_l4ta(s->l4, 3);
+    sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
+    sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
+    sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
+    sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
+    sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
 
     s->sdrc = omap_sdrc_init(0x68009000);
-    s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
+    s->gpmc = omap_gpmc_init(s, 0x6800a000,
+                             qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
+                             s->drq[OMAP24XX_DMA_GPMC]);
 
     dinfo = drive_get(IF_SD, 0, 0);
     if (!dinfo) {
@@ -2394,36 +2432,38 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
-                    s->irq[0][OMAP_INT_24XX_MMC_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
                     &s->drq[OMAP24XX_DMA_MMC1_TX],
                     omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
 
     s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
-                    s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI1_TX0],
                     omap_findclk(s, "spi1_fclk"),
                     omap_findclk(s, "spi1_iclk"));
     s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
-                    s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI2_TX0],
                     omap_findclk(s, "spi2_fclk"),
                     omap_findclk(s, "spi2_iclk"));
 
     s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800,
                     /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
-                    s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
+                           s->drq[OMAP24XX_DMA_DSS],
                     omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
                     omap_findclk(s, "dss_54m_clk"),
                     omap_findclk(s, "dss_l3_iclk"),
                     omap_findclk(s, "dss_l4_iclk"));
 
     omap_sti_init(omap_l4ta(s->l4, 18), 0x54000000,
-                    s->irq[0][OMAP_INT_24XX_STI], omap_findclk(s, "emul_ck"),
+                  qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
+                  omap_findclk(s, "emul_ck"),
                     serial_hds[0] && serial_hds[1] && serial_hds[2] ?
                     serial_hds[3] : NULL);
 
     s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
-                    s->irq[0][OMAP_INT_24XX_EAC_IRQ],
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
                     /* Ten consecutive lines */
                     &s->drq[OMAP24XX_DMA_EAC_AC_RD],
                     omap_findclk(s, "func_96m_clk"),
index 6bcabef8acb7112f6f44443820337a235e766ce4..844800606766664ae5e2422c2f79f476bc9f684b 100644 (file)
@@ -836,7 +836,7 @@ static struct clk i2c2_iclk = {
     .parent    = &core_l4_iclk,
 };
 
-static struct clk gpio_dbclk[4] = {
+static struct clk gpio_dbclk[5] = {
     {
         .name  = "gpio1_dbclk",
         .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
@@ -853,6 +853,10 @@ static struct clk gpio_dbclk[4] = {
         .name  = "gpio4_dbclk",
         .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
         .parent        = &wu_32k_clk,
+    }, {
+        .name   = "gpio5_dbclk",
+        .flags  = CLOCK_IN_OMAP243X,
+        .parent = &wu_32k_clk,
     },
 };
 
@@ -1235,7 +1239,7 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
     for (i = onchip_clks, count = 0; *i; i ++)
         if ((*i)->flags & flag)
             count ++;
-    mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1));
+    mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1));
     for (i = onchip_clks, j = mpu->clks; *i; i ++)
         if ((*i)->flags & flag) {
             memcpy(j, *i, sizeof(struct clk));
index 8e2dcc90c83b25959cf1bb8b386fd345d97f32c7..f943d4e147e882952257901eca0e9f9ef8fac254 100644 (file)
@@ -1620,7 +1620,7 @@ struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
 {
     int iomemtype, num_irqs, memsize, i;
     struct omap_dma_s *s = (struct omap_dma_s *)
-            qemu_mallocz(sizeof(struct omap_dma_s));
+            g_malloc0(sizeof(struct omap_dma_s));
 
     if (model <= omap_dma_3_1) {
         num_irqs = 6;
@@ -2039,7 +2039,7 @@ struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
 {
     int iomemtype, i;
     struct omap_dma_s *s = (struct omap_dma_s *)
-            qemu_mallocz(sizeof(struct omap_dma_s));
+            g_malloc0(sizeof(struct omap_dma_s));
 
     s->model = omap_dma_4;
     s->chans = chans;
index afe287a43ed6a8bcbe9c2280657e26ec9d0a8777..b4a8b4c45d4c207c23d4b5da105bac45cda2549e 100644 (file)
@@ -389,10 +389,11 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
         s->dig.enable = (value >> 1) & 1;
         s->lcd.enable = (value >> 0) & 1;
         if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
-            if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
-                 fprintf(stderr, "%s: Overlay Optimization when no overlay "
-                                 "region effectively exists leads to "
-                                 "unpredictable behaviour!\n", __FUNCTION__);
+            if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
+                fprintf(stderr, "%s: Overlay Optimization when no overlay "
+                        "region effectively exists leads to "
+                        "unpredictable behaviour!\n", __func__);
+            }
         if (value & (1 << 6)) {                                /* GODIGITAL */
             /* XXX: Shadowed fields are:
              * s->dispc.config
@@ -627,7 +628,7 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s)
     }
     if (!data) {
         if (len > bounce_len) {
-            bounce_buffer = qemu_realloc(bounce_buffer, len);
+            bounce_buffer = g_realloc(bounce_buffer, len);
         }
         data = bounce_buffer;
         cpu_physical_memory_read(data_addr, data, len);
@@ -1030,7 +1031,7 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
 {
     int iomemtype[5];
     struct omap_dss_s *s = (struct omap_dss_s *)
-            qemu_mallocz(sizeof(struct omap_dss_s));
+            g_malloc0(sizeof(struct omap_dss_s));
 
     s->irq = irq;
     s->drq = drq;
index 478f7d9825318db66336f25e662e281cd499fe0d..30630a8aa9c37b913c30b949922eb8ebf4ae84f0 100644 (file)
 
 #include "hw.h"
 #include "omap.h"
-/* General-Purpose I/O */
+#include "sysbus.h"
+
 struct omap_gpio_s {
     qemu_irq irq;
-    qemu_irq *in;
     qemu_irq handler[16];
 
     uint16_t inputs;
@@ -35,9 +35,17 @@ struct omap_gpio_s {
     uint16_t pins;
 };
 
+struct omap_gpif_s {
+    SysBusDevice busdev;
+    int mpu_model;
+    void *clk;
+    struct omap_gpio_s omap1;
+};
+
+/* General-Purpose I/O of OMAP1 */
 static void omap_gpio_set(void *opaque, int line, int level)
 {
-    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
     uint16_t prev = s->inputs;
 
     if (level)
@@ -160,7 +168,7 @@ static CPUWriteMemoryFunc * const omap_gpio_writefn[] = {
     omap_badwidth_write16,
 };
 
-void omap_gpio_reset(struct omap_gpio_s *s)
+static void omap_gpio_reset(struct omap_gpio_s *s)
 {
     s->inputs = 0;
     s->outputs = ~0;
@@ -171,43 +179,12 @@ void omap_gpio_reset(struct omap_gpio_s *s)
     s->pins = ~0;
 }
 
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
-                qemu_irq irq, omap_clk clk)
-{
-    int iomemtype;
-    struct omap_gpio_s *s = (struct omap_gpio_s *)
-            qemu_mallocz(sizeof(struct omap_gpio_s));
-
-    s->irq = irq;
-    s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
-    omap_gpio_reset(s);
-
-    iomemtype = cpu_register_io_memory(omap_gpio_readfn,
-                    omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x1000, iomemtype);
-
-    return s;
-}
-
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
-{
-    return s->in;
-}
-
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler)
-{
-    if (line >= 16 || line < 0)
-        hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
-    s->handler[line] = handler;
-}
-
-/* General-Purpose Interface of OMAP2 */
 struct omap2_gpio_s {
     qemu_irq irq[2];
     qemu_irq wkup;
-    qemu_irq *in;
-    qemu_irq handler[32];
+    qemu_irq *handler;
 
+    uint8_t revision;
     uint8_t config[2];
     uint32_t inputs;
     uint32_t outputs;
@@ -221,8 +198,21 @@ struct omap2_gpio_s {
     uint8_t delay;
 };
 
+struct omap2_gpif_s {
+    SysBusDevice busdev;
+    int mpu_model;
+    void *iclk;
+    void *fclk[6];
+    int modulecount;
+    struct omap2_gpio_s *modules;
+    qemu_irq *handler;
+    int autoidle;
+    int gpo;
+};
+
+/* General-Purpose Interface of OMAP2/3 */
 static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
-                int line)
+                                                int line)
 {
     qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
 }
@@ -269,10 +259,12 @@ static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
     omap2_gpio_module_wake(s, line);
 }
 
-static void omap2_gpio_module_set(void *opaque, int line, int level)
+static void omap2_gpio_set(void *opaque, int line, int level)
 {
-    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    struct omap2_gpif_s *p = opaque;
+    struct omap2_gpio_s *s = &p->modules[line >> 5];
 
+    line &= 31;
     if (level) {
         if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
             omap2_gpio_module_int(s, line);
@@ -308,7 +300,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr)
 
     switch (addr) {
     case 0x00: /* GPIO_REVISION */
-        return 0x18;
+        return s->revision;
 
     case 0x10: /* GPIO_SYSCONFIG */
         return s->config[0];
@@ -518,7 +510,7 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
 
 static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr)
 {
-    return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3);
+    return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
 }
 
 static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
@@ -583,45 +575,28 @@ static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = {
     omap2_gpio_module_write,
 };
 
-static void omap2_gpio_module_init(struct omap2_gpio_s *s,
-                struct omap_target_agent_s *ta, int region,
-                qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
-                omap_clk fclk, omap_clk iclk)
+static void omap_gpif_reset(DeviceState *dev)
 {
-    int iomemtype;
-
-    s->irq[0] = mpu;
-    s->irq[1] = dsp;
-    s->wkup = wkup;
-    s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
-
-    iomemtype = l4_register_io_memory(omap2_gpio_module_readfn,
-                    omap2_gpio_module_writefn, s);
-    omap_l4_attach(ta, region, iomemtype);
+    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
+                    sysbus_from_qdev(dev));
+    omap_gpio_reset(&s->omap1);
 }
 
-struct omap_gpif_s {
-    struct omap2_gpio_s module[5];
-    int modules;
-
-    int autoidle;
-    int gpo;
-};
-
-void omap_gpif_reset(struct omap_gpif_s *s)
+static void omap2_gpif_reset(DeviceState *dev)
 {
     int i;
-
-    for (i = 0; i < s->modules; i ++)
-        omap2_gpio_module_reset(s->module + i);
-
+    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
+                    sysbus_from_qdev(dev));
+    for (i = 0; i < s->modulecount; i++) {
+        omap2_gpio_module_reset(&s->modules[i]);
+    }
     s->autoidle = 0;
     s->gpo = 0;
 }
 
-static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+static uint32_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr)
 {
-    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
 
     switch (addr) {
     case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -647,10 +622,10 @@ static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
+static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
-    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
 
     switch (addr) {
     case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -662,7 +637,7 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
 
     case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
         if (value & (1 << 1))                                  /* SOFTRESET */
-            omap_gpif_reset(s);
+            omap2_gpif_reset(&s->busdev.qdev);
         s->autoidle = value & 1;
         break;
 
@@ -676,50 +651,119 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = {
-    omap_gpif_top_read,
-    omap_gpif_top_read,
-    omap_gpif_top_read,
+static CPUReadMemoryFunc * const omap2_gpif_top_readfn[] = {
+    omap2_gpif_top_read,
+    omap2_gpif_top_read,
+    omap2_gpif_top_read,
 };
 
-static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = {
-    omap_gpif_top_write,
-    omap_gpif_top_write,
-    omap_gpif_top_write,
+static CPUWriteMemoryFunc * const omap2_gpif_top_writefn[] = {
+    omap2_gpif_top_write,
+    omap2_gpif_top_write,
+    omap2_gpif_top_write,
 };
 
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
-                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+static int omap_gpio_init(SysBusDevice *dev)
 {
-    int iomemtype, i;
-    struct omap_gpif_s *s = (struct omap_gpif_s *)
-            qemu_mallocz(sizeof(struct omap_gpif_s));
-    int region[4] = { 0, 2, 4, 5 };
+    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
+    if (!s->clk) {
+        hw_error("omap-gpio: clk not connected\n");
+    }
+    qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
+    qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
+    sysbus_init_irq(dev, &s->omap1.irq);
+    sysbus_init_mmio(dev, 0x1000,
+                    cpu_register_io_memory(omap_gpio_readfn,
+                                    omap_gpio_writefn,
+                                    &s->omap1,
+                                    DEVICE_NATIVE_ENDIAN));
+    return 0;
+}
 
-    s->modules = modules;
-    for (i = 0; i < modules; i ++)
-        omap2_gpio_module_init(s->module + i, ta, region[i],
-                              irq[i], NULL, NULL, fclk[i], iclk);
+static int omap2_gpio_init(SysBusDevice *dev)
+{
+    int i;
+    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-gpio: iclk not connected\n");
+    }
+    if (s->mpu_model < omap3430) {
+        s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
+        sysbus_init_mmio(dev, 0x1000,
+                        cpu_register_io_memory(omap2_gpif_top_readfn,
+                                        omap2_gpif_top_writefn, s,
+                                        DEVICE_NATIVE_ENDIAN));
+    } else {
+        s->modulecount = 6;
+    }
+    s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s));
+    s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq));
+    qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
+    qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
+    for (i = 0; i < s->modulecount; i++) {
+        struct omap2_gpio_s *m = &s->modules[i];
+        if (!s->fclk[i]) {
+            hw_error("omap2-gpio: fclk%d not connected\n", i);
+        }
+        m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
+        m->handler = &s->handler[i * 32];
+        sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
+        sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
+        sysbus_init_irq(dev, &m->wkup);
+        sysbus_init_mmio(dev, 0x1000,
+                        cpu_register_io_memory(omap2_gpio_module_readfn,
+                                        omap2_gpio_module_writefn,
+                                        m, DEVICE_NATIVE_ENDIAN));
+    }
+    return 0;
+}
 
-    omap_gpif_reset(s);
+/* Using qdev pointer properties for the clocks is not ideal.
+ * qdev should support a generic means of defining a 'port' with
+ * an arbitrary interface for connecting two devices. Then we
+ * could reframe the omap clock API in terms of clock ports,
+ * and get some type safety. For now the best qdev provides is
+ * passing an arbitrary pointer.
+ * (It's not possible to pass in the string which is the clock
+ * name, because this device does not have the necessary information
+ * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
+ * translation.)
+ */
 
-    iomemtype = l4_register_io_memory(omap_gpif_top_readfn,
-                    omap_gpif_top_writefn, s);
-    omap_l4_attach(ta, 1, iomemtype);
+static SysBusDeviceInfo omap_gpio_info = {
+    .init = omap_gpio_init,
+    .qdev.name = "omap-gpio",
+    .qdev.size = sizeof(struct omap_gpif_s),
+    .qdev.reset = omap_gpif_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+        DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
-}
+static SysBusDeviceInfo omap2_gpio_info = {
+    .init = omap2_gpio_init,
+    .qdev.name = "omap2-gpio",
+    .qdev.size = sizeof(struct omap2_gpif_s),
+    .qdev.reset = omap2_gpif_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+        DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+        DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+        DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+        DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+        DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+        DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+        DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+static void omap_gpio_register_device(void)
 {
-    if (start >= s->modules * 32 || start < 0)
-        hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
-    return s->module[start >> 5].in + (start & 31);
+    sysbus_register_withprop(&omap_gpio_info);
+    sysbus_register_withprop(&omap2_gpio_info);
 }
 
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
-{
-    if (line >= s->modules * 32 || line < 0)
-        hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
-    s->module[line >> 5].handler[line & 31] = handler;
-}
+device_init(omap_gpio_register_device)
index 8bf3343a61221864ecffc2f303258c47547ce0d4..414f9f5c375594064913872e2dd37e64f0136f32 100644 (file)
 #include "hw.h"
 #include "flash.h"
 #include "omap.h"
+#include "memory.h"
+#include "exec-memory.h"
 
 /* General-Purpose Memory Controller */
 struct omap_gpmc_s {
     qemu_irq irq;
+    qemu_irq drq;
+    MemoryRegion iomem;
+    int accept_256;
 
+    uint8_t revision;
     uint8_t sysconfig;
     uint16_t irqst;
     uint16_t irqen;
+    uint16_t lastirq;
     uint16_t timeout;
     uint16_t config;
-    uint32_t prefconfig[2];
-    int prefcontrol;
-    int preffifo;
-    int prefcount;
     struct omap_gpmc_cs_file_s {
         uint32_t config[7];
-        target_phys_addr_t base;
-        size_t size;
-        int iomemtype;
-        void (*base_update)(void *opaque, target_phys_addr_t new);
-        void (*unmap)(void *opaque);
-        void *opaque;
+        MemoryRegion *iomem;
+        MemoryRegion container;
+        MemoryRegion nandiomem;
+        DeviceState *dev;
     } cs_file[8];
     int ecc_cs;
     int ecc_ptr;
     uint32_t ecc_cfg;
     ECCState ecc[9];
+    struct prefetch {
+        uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
+        uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
+        int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
+        int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
+        int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
+        MemoryRegion iomem;
+        uint8_t fifo[64];
+    } prefetch;
 };
 
+#define OMAP_GPMC_8BIT 0
+#define OMAP_GPMC_16BIT 1
+#define OMAP_GPMC_NOR 0
+#define OMAP_GPMC_NAND 2
+
+static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
+{
+    return (f->config[0] >> 10) & 3;
+}
+
+static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
+{
+    /* devsize field is really 2 bits but we ignore the high
+     * bit to ensure consistent behaviour if the guest sets
+     * it (values 2 and 3 are reserved in the TRM)
+     */
+    return (f->config[0] >> 12) & 1;
+}
+
+/* Extract the chip-select value from the prefetch config1 register */
+static int prefetch_cs(uint32_t config1)
+{
+    return (config1 >> 24) & 7;
+}
+
+static int prefetch_threshold(uint32_t config1)
+{
+    return (config1 >> 8) & 0x7f;
+}
+
 static void omap_gpmc_int_update(struct omap_gpmc_s *s)
 {
-    qemu_set_irq(s->irq, s->irqen & s->irqst);
+    /* The TRM is a bit unclear, but it seems to say that
+     * the TERMINALCOUNTSTATUS bit is set only on the
+     * transition when the prefetch engine goes from
+     * active to inactive, whereas the FIFOEVENTSTATUS
+     * bit is held high as long as the fifo has at
+     * least THRESHOLD bytes available.
+     * So we do the latter here, but TERMINALCOUNTSTATUS
+     * is set elsewhere.
+     */
+    if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
+        s->irqst |= 1;
+    }
+    if ((s->irqen & s->irqst) != s->lastirq) {
+        s->lastirq = s->irqen & s->irqst;
+        qemu_set_irq(s->irq, s->lastirq);
+    }
 }
 
-static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask)
+static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
 {
-    /* TODO: check for overlapping regions and report access errors */
-    if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) ||
-                    (base < 0 || base >= 0x40) ||
-                    (base & 0x0f & ~mask)) {
-        fprintf(stderr, "%s: wrong cs address mapping/decoding!\n",
-                        __FUNCTION__);
+    if (s->prefetch.config1 & 4) {
+        qemu_set_irq(s->drq, value);
+    }
+}
+
+/* Access functions for when a NAND-like device is mapped into memory:
+ * all addresses in the region behave like accesses to the relevant
+ * GPMC_NAND_DATA_i register (which is actually implemented to call these)
+ */
+static uint64_t omap_nand_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
+{
+    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
+    uint64_t v;
+    nand_setpins(f->dev, 0, 0, 0, 1, 0);
+    switch (omap_gpmc_devsize(f)) {
+    case OMAP_GPMC_8BIT:
+        v = nand_getio(f->dev);
+        if (size == 1) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 8);
+        if (size == 2) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 16);
+        v |= (nand_getio(f->dev) << 24);
+        return v;
+    case OMAP_GPMC_16BIT:
+        v = nand_getio(f->dev);
+        if (size == 1) {
+            /* 8 bit read from 16 bit device : probably a guest bug */
+            return v & 0xff;
+        }
+        if (size == 2) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 16);
+        return v;
+    default:
+        abort();
+    }
+}
+
+static void omap_nand_setio(DeviceState *dev, uint64_t value,
+                            int nandsize, int size)
+{
+    /* Write the specified value to the NAND device, respecting
+     * both size of the NAND device and size of the write access.
+     */
+    switch (nandsize) {
+    case OMAP_GPMC_8BIT:
+        switch (size) {
+        case 1:
+            nand_setio(dev, value & 0xff);
+            break;
+        case 2:
+            nand_setio(dev, value & 0xff);
+            nand_setio(dev, (value >> 8) & 0xff);
+            break;
+        case 4:
+        default:
+            nand_setio(dev, value & 0xff);
+            nand_setio(dev, (value >> 8) & 0xff);
+            nand_setio(dev, (value >> 16) & 0xff);
+            nand_setio(dev, (value >> 24) & 0xff);
+            break;
+        }
+        break;
+    case OMAP_GPMC_16BIT:
+        switch (size) {
+        case 1:
+            /* writing to a 16bit device with 8bit access is probably a guest
+             * bug; pass the value through anyway.
+             */
+        case 2:
+            nand_setio(dev, value & 0xffff);
+            break;
+        case 4:
+        default:
+            nand_setio(dev, value & 0xffff);
+            nand_setio(dev, (value >> 16) & 0xffff);
+            break;
+        }
+        break;
+    }
+}
+
+static void omap_nand_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
+    nand_setpins(f->dev, 0, 0, 0, 1, 0);
+    omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+}
+
+static const MemoryRegionOps omap_nand_ops = {
+    .read = omap_nand_read,
+    .write = omap_nand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void fill_prefetch_fifo(struct omap_gpmc_s *s)
+{
+    /* Fill the prefetch FIFO by reading data from NAND.
+     * We do this synchronously, unlike the hardware which
+     * will do this asynchronously. We refill when the
+     * FIFO has THRESHOLD bytes free, and we always refill
+     * as much data as possible starting at the top end
+     * of the FIFO.
+     * (We have to refill at THRESHOLD rather than waiting
+     * for the FIFO to empty to allow for the case where
+     * the FIFO size isn't an exact multiple of THRESHOLD
+     * and we're doing DMA transfers.)
+     * This means we never need to handle wrap-around in
+     * the fifo-reading code, and the next byte of data
+     * to read is always fifo[63 - fifopointer].
+     */
+    int fptr;
+    int cs = prefetch_cs(s->prefetch.config1);
+    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
+    int bytes;
+    /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
+     * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
+     * Instead believe the bit that says it is always a byte count.
+     */
+    bytes = 64 - s->prefetch.fifopointer;
+    if (bytes > s->prefetch.count) {
+        bytes = s->prefetch.count;
+    }
+    s->prefetch.count -= bytes;
+    s->prefetch.fifopointer += bytes;
+    fptr = 64 - s->prefetch.fifopointer;
+    /* Move the existing data in the FIFO so it sits just
+     * before what we're about to read in
+     */
+    while (fptr < (64 - bytes)) {
+        s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
+        fptr++;
+    }
+    while (fptr < 64) {
+        if (is16bit) {
+            uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
+            s->prefetch.fifo[fptr++] = v & 0xff;
+            s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
+        } else {
+            s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
+        }
+    }
+    if (s->prefetch.startengine && (s->prefetch.count == 0)) {
+        /* This was the final transfer: raise TERMINALCOUNTSTATUS */
+        s->irqst |= 2;
+        s->prefetch.startengine = 0;
+    }
+    /* If there are any bytes in the FIFO at this point then
+     * we must raise a DMA request (either this is a final part
+     * transfer, or we filled the FIFO in which case we certainly
+     * have THRESHOLD bytes available)
+     */
+    if (s->prefetch.fifopointer != 0) {
+        omap_gpmc_dma_update(s, 1);
+    }
+    omap_gpmc_int_update(s);
+}
+
+/* Access functions for a NAND-like device when the prefetch/postwrite
+ * engine is enabled -- all addresses in the region behave alike:
+ * data is read or written to the FIFO.
+ */
+static uint64_t omap_gpmc_prefetch_read(void *opaque, target_phys_addr_t addr,
+                                        unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    uint32_t data;
+    if (s->prefetch.config1 & 1) {
+        /* The TRM doesn't define the behaviour if you read from the
+         * FIFO when the prefetch engine is in write mode. We choose
+         * to always return zero.
+         */
+        return 0;
+    }
+    /* Note that trying to read an empty fifo repeats the last byte */
+    if (s->prefetch.fifopointer) {
+        s->prefetch.fifopointer--;
+    }
+    data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
+    if (s->prefetch.fifopointer ==
+        (64 - prefetch_threshold(s->prefetch.config1))) {
+        /* We've drained THRESHOLD bytes now. So deassert the
+         * DMA request, then refill the FIFO (which will probably
+         * assert it again.)
+         */
+        omap_gpmc_dma_update(s, 0);
+        fill_prefetch_fifo(s);
+    }
+    omap_gpmc_int_update(s);
+    return data;
+}
+
+static void omap_gpmc_prefetch_write(void *opaque, target_phys_addr_t addr,
+                                     uint64_t value, unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs = prefetch_cs(s->prefetch.config1);
+    if ((s->prefetch.config1 & 1) == 0) {
+        /* The TRM doesn't define the behaviour of writing to the
+         * FIFO when the prefetch engine is in read mode. We
+         * choose to ignore the write.
+         */
+        return;
+    }
+    if (s->prefetch.count == 0) {
+        /* The TRM doesn't define the behaviour of writing to the
+         * FIFO if the transfer is complete. We choose to ignore.
+         */
         return;
     }
+    /* The only reason we do any data buffering in postwrite
+     * mode is if we are talking to a 16 bit NAND device, in
+     * which case we need to buffer the first byte of the
+     * 16 bit word until the other byte arrives.
+     */
+    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
+    if (is16bit) {
+        /* fifopointer alternates between 64 (waiting for first
+         * byte of word) and 63 (waiting for second byte)
+         */
+        if (s->prefetch.fifopointer == 64) {
+            s->prefetch.fifo[0] = value;
+            s->prefetch.fifopointer--;
+        } else {
+            value = (value << 8) | s->prefetch.fifo[0];
+            omap_nand_write(&s->cs_file[cs], 0, value, 2);
+            s->prefetch.count--;
+            s->prefetch.fifopointer = 64;
+        }
+    } else {
+        /* Just write the byte : fifopointer remains 64 at all times */
+        omap_nand_write(&s->cs_file[cs], 0, value, 1);
+        s->prefetch.count--;
+    }
+    if (s->prefetch.count == 0) {
+        /* Final transfer: raise TERMINALCOUNTSTATUS */
+        s->irqst |= 2;
+        s->prefetch.startengine = 0;
+    }
+    omap_gpmc_int_update(s);
+}
+
+static const MemoryRegionOps omap_prefetch_ops = {
+    .read = omap_gpmc_prefetch_read,
+    .write = omap_gpmc_prefetch_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+};
+
+static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
+{
+    /* Return the MemoryRegion* to map/unmap for this chipselect */
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
+        return f->iomem;
+    }
+    if ((s->prefetch.config1 & 0x80) &&
+        (prefetch_cs(s->prefetch.config1) == cs)) {
+        /* The prefetch engine is enabled for this CS: map the FIFO */
+        return &s->prefetch.iomem;
+    }
+    return &f->nandiomem;
+}
 
-    if (!f->opaque)
+static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
+{
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    uint32_t mask = (f->config[6] >> 8) & 0xf;
+    uint32_t base = f->config[6] & 0x3f;
+    uint32_t size;
+
+    if (!f->iomem && !f->dev) {
+        return;
+    }
+
+    if (!(f->config[6] & (1 << 6))) {
+        /* Do nothing unless CSVALID */
         return;
+    }
 
-    f->base = base << 24;
-    f->size = (0x0fffffff & ~(mask << 24)) + 1;
+    /* TODO: check for overlapping regions and report access errors */
+    if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
+         && !(s->accept_256 && !mask)) {
+        fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
+                 __func__, mask);
+    }
+
+    base <<= 24;
+    size = (0x0fffffff & ~(mask << 24)) + 1;
     /* TODO: rather than setting the size of the mapping (which should be
      * constant), the mask should cause wrapping of the address space, so
      * that the same memory becomes accessible at every <i>size</i> bytes
      * starting from <i>base</i>.  */
-    if (f->iomemtype)
-        cpu_register_physical_memory(f->base, f->size, f->iomemtype);
-
-    if (f->base_update)
-        f->base_update(f->opaque, f->base);
+    memory_region_init(&f->container, "omap-gpmc-file", size);
+    memory_region_add_subregion(&f->container, 0,
+                                omap_gpmc_cs_memregion(s, cs));
+    memory_region_add_subregion(get_system_memory(), base,
+                                &f->container);
 }
 
-static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f)
+static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
 {
-    if (f->size) {
-        if (f->unmap)
-            f->unmap(f->opaque);
-        if (f->iomemtype)
-            cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED);
-        f->base = 0;
-        f->size = 0;
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    if (!(f->config[6] & (1 << 6))) {
+        /* Do nothing unless CSVALID */
+        return;
     }
+    if (!f->iomem && !f->dev) {
+        return;
+    }
+    memory_region_del_subregion(get_system_memory(), &f->container);
+    memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
+    memory_region_destroy(&f->container);
 }
 
 void omap_gpmc_reset(struct omap_gpmc_s *s)
@@ -104,27 +445,33 @@ void omap_gpmc_reset(struct omap_gpmc_s *s)
     omap_gpmc_int_update(s);
     s->timeout = 0;
     s->config = 0xa00;
-    s->prefconfig[0] = 0x00004000;
-    s->prefconfig[1] = 0x00000000;
-    s->prefcontrol = 0;
-    s->preffifo = 0;
-    s->prefcount = 0;
+    s->prefetch.config1 = 0x00004000;
+    s->prefetch.transfercount = 0x00000000;
+    s->prefetch.startengine = 0;
+    s->prefetch.fifopointer = 0;
+    s->prefetch.count = 0;
     for (i = 0; i < 8; i ++) {
-        if (s->cs_file[i].config[6] & (1 << 6))                        /* CSVALID */
-            omap_gpmc_cs_unmap(s->cs_file + i);
-        s->cs_file[i].config[0] = i ? 1 << 12 : 0;
+        omap_gpmc_cs_unmap(s, i);
         s->cs_file[i].config[1] = 0x101001;
         s->cs_file[i].config[2] = 0x020201;
         s->cs_file[i].config[3] = 0x10031003;
         s->cs_file[i].config[4] = 0x10f1111;
         s->cs_file[i].config[5] = 0;
         s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
-        if (s->cs_file[i].config[6] & (1 << 6))                        /* CSVALID */
-            omap_gpmc_cs_map(&s->cs_file[i],
-                            s->cs_file[i].config[6] & 0x1f,    /* MASKADDR */
-                        (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */
+
+        s->cs_file[i].config[6] = 0xf00;
+        /* In theory we could probe attached devices for some CFG1
+         * bits here, but we just retain them across resets as they
+         * were set initially by omap_gpmc_attach().
+         */
+        if (i == 0) {
+            s->cs_file[i].config[0] &= 0x00433e00;
+            s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
+            omap_gpmc_cs_map(s, i);
+        } else {
+            s->cs_file[i].config[0] &= 0x00403c00;
+        }
     }
-    omap_gpmc_cs_map(s->cs_file, 0, 0xf);
     s->ecc_cs = 0;
     s->ecc_ptr = 0;
     s->ecc_cfg = 0x3fcff000;
@@ -132,15 +479,38 @@ void omap_gpmc_reset(struct omap_gpmc_s *s)
         ecc_reset(&s->ecc[i]);
 }
 
-static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
+static int gpmc_wordaccess_only(target_phys_addr_t addr)
+{
+    /* Return true if the register offset is to a register that
+     * only permits word width accesses.
+     * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
+     * for any chipselect.
+     */
+    if (addr >= 0x60 && addr <= 0x1d4) {
+        int cs = (addr - 0x60) / 0x30;
+        addr -= cs * 0x30;
+        if (addr >= 0x7c && addr < 0x88) {
+            /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
     int cs;
     struct omap_gpmc_cs_file_s *f;
 
+    if (size != 4 && gpmc_wordaccess_only(addr)) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x000:        /* GPMC_REVISION */
-        return 0x20;
+        return s->revision;
 
     case 0x010:        /* GPMC_SYSCONFIG */
         return s->sysconfig;
@@ -172,36 +542,46 @@ static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
         addr -= cs * 0x30;
         f = s->cs_file + cs;
         switch (addr) {
-            case 0x60: /* GPMC_CONFIG1 */
-                return f->config[0];
-            case 0x64: /* GPMC_CONFIG2 */
-                return f->config[1];
-            case 0x68: /* GPMC_CONFIG3 */
-                return f->config[2];
-            case 0x6c: /* GPMC_CONFIG4 */
-                return f->config[3];
-            case 0x70: /* GPMC_CONFIG5 */
-                return f->config[4];
-            case 0x74: /* GPMC_CONFIG6 */
-                return f->config[5];
-            case 0x78: /* GPMC_CONFIG7 */
-                return f->config[6];
-            case 0x84: /* GPMC_NAND_DATA */
-                return 0;
+        case 0x60:      /* GPMC_CONFIG1 */
+            return f->config[0];
+        case 0x64:      /* GPMC_CONFIG2 */
+            return f->config[1];
+        case 0x68:      /* GPMC_CONFIG3 */
+            return f->config[2];
+        case 0x6c:      /* GPMC_CONFIG4 */
+            return f->config[3];
+        case 0x70:      /* GPMC_CONFIG5 */
+            return f->config[4];
+        case 0x74:      /* GPMC_CONFIG6 */
+            return f->config[5];
+        case 0x78:      /* GPMC_CONFIG7 */
+            return f->config[6];
+        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                return omap_nand_read(f, 0, size);
+            }
+            return 0;
         }
         break;
 
     case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
-        return s->prefconfig[0];
+        return s->prefetch.config1;
     case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
-        return s->prefconfig[1];
+        return s->prefetch.transfercount;
     case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
-        return s->prefcontrol;
+        return s->prefetch.startengine;
     case 0x1f0:        /* GPMC_PREFETCH_STATUS */
-        return (s->preffifo << 24) |
-                ((s->preffifo >
-                  ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) |
-                s->prefcount;
+        /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
+         * FIFOTHRESHOLDSTATUS bit should be set when
+         * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
+         * Apparently the underlying functional spec from which the TRM was
+         * created states that the behaviour is ">=", and this also
+         * makes more conceptual sense.
+         */
+        return (s->prefetch.fifopointer << 24) |
+                ((s->prefetch.fifopointer >=
+                  ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
+                s->prefetch.count;
 
     case 0x1f4:        /* GPMC_ECC_CONFIG */
         return s->ecc_cs;
@@ -230,12 +610,16 @@ static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
     int cs;
     struct omap_gpmc_cs_file_s *f;
 
+    if (size != 4 && gpmc_wordaccess_only(addr)) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x000:        /* GPMC_REVISION */
     case 0x014:        /* GPMC_SYSSTATUS */
@@ -249,7 +633,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
 
     case 0x010:        /* GPMC_SYSCONFIG */
         if ((value >> 3) == 0x3)
-            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+            fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
                             __FUNCTION__, value >> 3);
         if (value & 2)
             omap_gpmc_reset(s);
@@ -257,7 +641,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x018:        /* GPMC_IRQSTATUS */
-        s->irqen = ~value;
+        s->irqst &= ~value;
         omap_gpmc_int_update(s);
         break;
 
@@ -283,62 +667,109 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
         addr -= cs * 0x30;
         f = s->cs_file + cs;
         switch (addr) {
-            case 0x60: /* GPMC_CONFIG1 */
-                f->config[0] = value & 0xffef3e13;
-                break;
-            case 0x64: /* GPMC_CONFIG2 */
-                f->config[1] = value & 0x001f1f8f;
-                break;
-            case 0x68: /* GPMC_CONFIG3 */
-                f->config[2] = value & 0x001f1f8f;
-                break;
-            case 0x6c: /* GPMC_CONFIG4 */
-                f->config[3] = value & 0x1f8f1f8f;
-                break;
-            case 0x70: /* GPMC_CONFIG5 */
-                f->config[4] = value & 0x0f1f1f1f;
-                break;
-            case 0x74: /* GPMC_CONFIG6 */
-                f->config[5] = value & 0x00000fcf;
-                break;
-            case 0x78: /* GPMC_CONFIG7 */
-                if ((f->config[6] ^ value) & 0xf7f) {
-                    if (f->config[6] & (1 << 6))               /* CSVALID */
-                        omap_gpmc_cs_unmap(f);
-                    if (value & (1 << 6))                      /* CSVALID */
-                        omap_gpmc_cs_map(f, value & 0x1f,      /* MASKADDR */
-                                        (value >> 8 & 0xf));   /* BASEADDR */
-                }
+        case 0x60:      /* GPMC_CONFIG1 */
+            f->config[0] = value & 0xffef3e13;
+            break;
+        case 0x64:      /* GPMC_CONFIG2 */
+            f->config[1] = value & 0x001f1f8f;
+            break;
+        case 0x68:      /* GPMC_CONFIG3 */
+            f->config[2] = value & 0x001f1f8f;
+            break;
+        case 0x6c:      /* GPMC_CONFIG4 */
+            f->config[3] = value & 0x1f8f1f8f;
+            break;
+        case 0x70:      /* GPMC_CONFIG5 */
+            f->config[4] = value & 0x0f1f1f1f;
+            break;
+        case 0x74:      /* GPMC_CONFIG6 */
+            f->config[5] = value & 0x00000fcf;
+            break;
+        case 0x78:      /* GPMC_CONFIG7 */
+            if ((f->config[6] ^ value) & 0xf7f) {
+                omap_gpmc_cs_unmap(s, cs);
                 f->config[6] = value & 0x00000f7f;
-                break;
-            case 0x7c: /* GPMC_NAND_COMMAND */
-            case 0x80: /* GPMC_NAND_ADDRESS */
-            case 0x84: /* GPMC_NAND_DATA */
-                break;
-
-            default:
-                goto bad_reg;
+                omap_gpmc_cs_map(s, cs);
+            }
+            break;
+        case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
+                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+            }
+            break;
+        case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
+                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+            }
+            break;
+        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                omap_nand_write(f, 0, value, size);
+            }
+            break;
+        default:
+            goto bad_reg;
         }
         break;
 
     case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
-        s->prefconfig[0] = value & 0x7f8f7fbf;
-        /* TODO: update interrupts, fifos, dmas */
+        if (!s->prefetch.startengine) {
+            uint32_t oldconfig1 = s->prefetch.config1;
+            uint32_t changed;
+            s->prefetch.config1 = value & 0x7f8f7fbf;
+            changed = oldconfig1 ^ s->prefetch.config1;
+            if (changed & (0x80 | 0x7000000)) {
+                /* Turning the engine on or off, or mapping it somewhere else.
+                 * cs_map() and cs_unmap() check the prefetch config and
+                 * overall CSVALID bits, so it is sufficient to unmap-and-map
+                 * both the old cs and the new one.
+                 */
+                int oldcs = prefetch_cs(oldconfig1);
+                int newcs = prefetch_cs(s->prefetch.config1);
+                omap_gpmc_cs_unmap(s, oldcs);
+                omap_gpmc_cs_map(s, oldcs);
+                if (newcs != oldcs) {
+                    omap_gpmc_cs_unmap(s, newcs);
+                    omap_gpmc_cs_map(s, newcs);
+                }
+            }
+        }
         break;
 
     case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
-        s->prefconfig[1] = value & 0x3fff;
+        if (!s->prefetch.startengine) {
+            s->prefetch.transfercount = value & 0x3fff;
+        }
         break;
 
     case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
-        s->prefcontrol = value & 1;
-        if (s->prefcontrol) {
-            if (s->prefconfig[0] & 1)
-                s->preffifo = 0x40;
-            else
-                s->preffifo = 0x00;
+        if (s->prefetch.startengine != (value & 1)) {
+            s->prefetch.startengine = value & 1;
+            if (s->prefetch.startengine) {
+                /* Prefetch engine start */
+                s->prefetch.count = s->prefetch.transfercount;
+                if (s->prefetch.config1 & 1) {
+                    /* Write */
+                    s->prefetch.fifopointer = 64;
+                } else {
+                    /* Read */
+                    s->prefetch.fifopointer = 0;
+                    fill_prefetch_fifo(s);
+                }
+            } else {
+                /* Prefetch engine forcibly stopped. The TRM
+                 * doesn't define the behaviour if you do this.
+                 * We clear the prefetch count, which means that
+                 * we permit no more writes, and don't read any
+                 * more data from NAND. The CPU can still drain
+                 * the FIFO of unread data.
+                 */
+                s->prefetch.count = 0;
+            }
+            omap_gpmc_int_update(s);
         }
-        /* TODO: start */
         break;
 
     case 0x1f4:        /* GPMC_ECC_CONFIG */
@@ -369,38 +800,53 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_gpmc_readfn[] = {
-    omap_badwidth_read32,      /* TODO */
-    omap_badwidth_read32,      /* TODO */
-    omap_gpmc_read,
+static const MemoryRegionOps omap_gpmc_ops = {
+    .read = omap_gpmc_read,
+    .write = omap_gpmc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const omap_gpmc_writefn[] = {
-    omap_badwidth_write32,     /* TODO */
-    omap_badwidth_write32,     /* TODO */
-    omap_gpmc_write,
-};
-
-struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   target_phys_addr_t base,
+                                   qemu_irq irq, qemu_irq drq)
 {
-    int iomemtype;
+    int cs;
     struct omap_gpmc_s *s = (struct omap_gpmc_s *)
-            qemu_mallocz(sizeof(struct omap_gpmc_s));
+            g_malloc0(sizeof(struct omap_gpmc_s));
+
+    memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
+    memory_region_add_subregion(get_system_memory(), base, &s->iomem);
 
+    s->irq = irq;
+    s->drq = drq;
+    s->accept_256 = cpu_is_omap3630(mpu);
+    s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
+    s->lastirq = 0;
     omap_gpmc_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_gpmc_readfn,
-                    omap_gpmc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x1000, iomemtype);
+    /* We have to register a different IO memory handler for each
+     * chip select region in case a NAND device is mapped there. We
+     * make the region the worst-case size of 256MB and rely on the
+     * container memory region in cs_map to chop it down to the actual
+     * guest-requested size.
+     */
+    for (cs = 0; cs < 8; cs++) {
+        memory_region_init_io(&s->cs_file[cs].nandiomem,
+                              &omap_nand_ops,
+                              &s->cs_file[cs],
+                              "omap-nand",
+                              256 * 1024 * 1024);
+    }
 
+    memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s,
+                          "omap-gpmc-prefetch", 256 * 1024 * 1024);
     return s;
 }
 
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
-                void (*base_upd)(void *opaque, target_phys_addr_t new),
-                void (*unmap)(void *opaque), void *opaque)
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
 {
     struct omap_gpmc_cs_file_s *f;
+    assert(iomem);
 
     if (cs < 0 || cs >= 8) {
         fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
@@ -408,12 +854,29 @@ void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
     }
     f = &s->cs_file[cs];
 
-    f->iomemtype = iomemtype;
-    f->base_update = base_upd;
-    f->unmap = unmap;
-    f->opaque = opaque;
+    omap_gpmc_cs_unmap(s, cs);
+    f->config[0] &= ~(0xf << 10);
+    f->iomem = iomem;
+    omap_gpmc_cs_map(s, cs);
+}
 
-    if (f->config[6] & (1 << 6))                               /* CSVALID */
-        omap_gpmc_cs_map(f, f->config[6] & 0x1f,               /* MASKADDR */
-                        (f->config[6] >> 8 & 0xf));            /* BASEADDR */
+void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
+{
+    struct omap_gpmc_cs_file_s *f;
+    assert(nand);
+
+    if (cs < 0 || cs >= 8) {
+        fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
+        exit(-1);
+    }
+    f = &s->cs_file[cs];
+
+    omap_gpmc_cs_unmap(s, cs);
+    f->config[0] &= ~(0xf << 10);
+    f->config[0] |= (OMAP_GPMC_NAND << 10);
+    f->dev = nand;
+    if (nand_getbuswidth(f->dev) == 16) {
+        f->config[0] |= OMAP_GPMC_16BIT << 12;
+    }
+    omap_gpmc_cs_map(s, cs);
 }
index 9c0f9f2b33843c0ae82e4fcf88c90072a295a586..704b000636db79d014c8124d2b94fefc7d35d665 100644 (file)
@@ -102,7 +102,7 @@ static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
     uint64_t distance;
 
     if (timer->st && timer->rate) {
-        distance = qemu_get_clock(vm_clock) - timer->time;
+        distance = qemu_get_clock_ns(vm_clock) - timer->time;
         distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
 
         if (distance >= 0xffffffff - timer->val)
@@ -117,7 +117,7 @@ static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
 {
     if (timer->st) {
         timer->val = omap_gp_timer_read(timer);
-        timer->time = qemu_get_clock(vm_clock);
+        timer->time = qemu_get_clock_ns(vm_clock);
     }
 }
 
@@ -163,7 +163,7 @@ static void omap_gp_timer_tick(void *opaque)
         timer->val = 0;
     } else {
         timer->val = timer->load_val;
-        timer->time = qemu_get_clock(vm_clock);
+        timer->time = qemu_get_clock_ns(vm_clock);
     }
 
     if (timer->trigger == gpt_trigger_overflow ||
@@ -411,7 +411,7 @@ static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x28: /* TCRR */
-        s->time = qemu_get_clock(vm_clock);
+        s->time = qemu_get_clock_ns(vm_clock);
         s->val = value;
         omap_gp_timer_update(s);
         break;
@@ -421,7 +421,7 @@ static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x30: /* TTGR */
-        s->time = qemu_get_clock(vm_clock);
+        s->time = qemu_get_clock_ns(vm_clock);
         s->val = s->load_val;
         omap_gp_timer_update(s);
         break;
@@ -465,13 +465,13 @@ struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
-            qemu_mallocz(sizeof(struct omap_gp_timer_s));
+            g_malloc0(sizeof(struct omap_gp_timer_s));
 
     s->ta = ta;
     s->irq = irq;
     s->clk = fclk;
-    s->timer = qemu_new_timer(vm_clock, omap_gp_timer_tick, s);
-    s->match = qemu_new_timer(vm_clock, omap_gp_timer_match, s);
+    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
+    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
     s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
     omap_gp_timer_reset(s);
     omap_gp_timer_clk_setup(s);
index 5cabb5a7b367258ceef7b78b56f4a626860d046d..11577b1eecaecf12fe71253f705c579d8a61a247 100644 (file)
@@ -426,7 +426,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
 {
     int iomemtype;
     struct omap_i2c_s *s = (struct omap_i2c_s *)
-            qemu_mallocz(sizeof(struct omap_i2c_s));
+            g_malloc0(sizeof(struct omap_i2c_s));
 
     /* TODO: set a value greater or equal to real hardware */
     s->revision = 0x11;
@@ -448,7 +448,7 @@ struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_i2c_s *s = (struct omap_i2c_s *)
-            qemu_mallocz(sizeof(struct omap_i2c_s));
+            g_malloc0(sizeof(struct omap_i2c_s));
 
     s->revision = 0x34;
     s->irq = irq;
index 001e20b9d330bdbefd9feb687b382f1e2729f180..45efa25109941bbef180def3a5cd9937b35ff998 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include "hw.h"
 #include "omap.h"
+#include "sysbus.h"
 
 /* Interrupt Handlers */
 struct omap_intr_handler_bank_s {
@@ -32,24 +33,26 @@ struct omap_intr_handler_bank_s {
 };
 
 struct omap_intr_handler_s {
+    SysBusDevice busdev;
     qemu_irq *pins;
     qemu_irq parent_intr[2];
+    MemoryRegion mmio;
+    void *iclk;
+    void *fclk;
     unsigned char nbanks;
     int level_only;
+    uint32_t size;
+
+    uint8_t revision;
 
     /* state */
     uint32_t new_agr[2];
     int sir_intr[2];
     int autoidle;
     uint32_t mask;
-    struct omap_intr_handler_bank_s bank[];
+    struct omap_intr_handler_bank_s bank[3];
 };
 
-inline qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n)
-{
-    return s->pins[n];
-}
-
 static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
 {
     int i, j, sir_intr, p_intr, p, f;
@@ -142,7 +145,8 @@ static void omap_set_intr_noedge(void *opaque, int irq, int req)
         bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
 }
 
-static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_inth_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr;
@@ -220,7 +224,7 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_inth_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr;
@@ -312,20 +316,20 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr,
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap_inth_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_inth_read,
+static const MemoryRegionOps omap_inth_mem_ops = {
+    .read = omap_inth_read,
+    .write = omap_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-static CPUWriteMemoryFunc * const omap_inth_writefn[] = {
-    omap_inth_write,
-    omap_inth_write,
-    omap_inth_write,
-};
-
-void omap_inth_reset(struct omap_intr_handler_s *s)
+static void omap_inth_reset(DeviceState *dev)
 {
+    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
+                                                sysbus_from_qdev(dev));
     int i;
 
     for (i = 0; i < s->nbanks; ++i){
@@ -352,32 +356,37 @@ void omap_inth_reset(struct omap_intr_handler_s *s)
     qemu_set_irq(s->parent_intr[1], 0);
 }
 
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
+static int omap_intc_init(SysBusDevice *dev)
 {
-    int iomemtype;
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            qemu_mallocz(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
-    s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    omap_inth_reset(s);
-
-    iomemtype = cpu_register_io_memory(omap_inth_readfn,
-                    omap_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, iomemtype);
-
-    return s;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap-intc: clk not connected\n");
+    }
+    s->nbanks = 1;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
+                          "omap-intc", s->size);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
 }
 
-static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
+static SysBusDeviceInfo omap_intc_info = {
+    .init = omap_intc_init,
+    .qdev.name = "omap-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+        DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int offset = addr;
@@ -389,12 +398,15 @@ static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
         if (bank_no < s->nbanks) {
             offset &= ~0x60;
             bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return 0;
         }
     }
 
     switch (offset) {
     case 0x00: /* INTC_REVISION */
-        return 0x21;
+        return s->revision;
 
     case 0x10: /* INTC_SYSCONFIG */
         return (s->autoidle >> 2) & 1;
@@ -455,7 +467,7 @@ static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int offset = addr;
@@ -467,6 +479,9 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
         if (bank_no < s->nbanks) {
             offset &= ~0x60;
             bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return;
         }
     }
 
@@ -475,7 +490,7 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
         s->autoidle &= 4;
         s->autoidle |= (value & 1) << 2;
         if (value & 2)                                         /* SOFTRESET */
-            omap_inth_reset(s);
+            omap_inth_reset(&s->busdev.qdev);
         return;
 
     case 0x48: /* INTC_CONTROL */
@@ -558,41 +573,55 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap2_inth_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap2_inth_read,
-};
-
-static CPUWriteMemoryFunc * const omap2_inth_writefn[] = {
-    omap2_inth_write,
-    omap2_inth_write,
-    omap2_inth_write,
+static const MemoryRegionOps omap2_inth_mem_ops = {
+    .read = omap2_inth_read,
+    .write = omap2_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk)
+static int omap2_intc_init(SysBusDevice *dev)
 {
-    int iomemtype;
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            qemu_mallocz(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-intc: iclk not connected\n");
+    }
+    if (!s->fclk) {
+        hw_error("omap2-intc: fclk not connected\n");
+    }
     s->level_only = 1;
-    s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    omap_inth_reset(s);
+    s->nbanks = 3;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
+                          "omap2-intc", 0x1000);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
+}
 
-    iomemtype = cpu_register_io_memory(omap2_inth_readfn,
-                    omap2_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, iomemtype);
+static SysBusDeviceInfo omap2_intc_info = {
+    .init = omap2_intc_init,
+    .qdev.name = "omap2-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+                          revision, 0x21),
+        DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
+static void omap_intc_register_device(void)
+{
+    sysbus_register_withprop(&omap_intc_info);
+    sysbus_register_withprop(&omap2_intc_info);
 }
+
+device_init(omap_intc_register_device)
index 4af0ca8ea611549151f61dfd686ec680d820f47e..a4a8883d2a8f75054be9c2653054ec746b672b20 100644 (file)
@@ -120,7 +120,7 @@ struct omap_l4_s {
 
 struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
 {
-    struct omap_l4_s *bus = qemu_mallocz(
+    struct omap_l4_s *bus = g_malloc0(
                     sizeof(*bus) + ta_num * sizeof(*bus->ta));
 
     bus->ta_num = ta_num;
@@ -128,24 +128,30 @@ struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
 
 #ifdef L4_MUX_HACK
     omap_l4_io_entries = 1;
-    omap_l4_io_entry = qemu_mallocz(125 * sizeof(*omap_l4_io_entry));
+    omap_l4_io_entry = g_malloc0(125 * sizeof(*omap_l4_io_entry));
 
     omap_cpu_io_entry =
             cpu_register_io_memory(omap_l4_io_readfn,
                             omap_l4_io_writefn, bus, DEVICE_NATIVE_ENDIAN);
 # define L4_PAGES      (0xb4000 / TARGET_PAGE_SIZE)
-    omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_readh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_readw_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_writeb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_writeh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_writew_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
-    omap_l4_io_opaque = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_readb_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_readh_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_readw_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writeb_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writeh_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writew_fn = g_malloc0(sizeof(void *) * L4_PAGES);
+    omap_l4_io_opaque = g_malloc0(sizeof(void *) * L4_PAGES);
 #endif
 
     return bus;
 }
 
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+                                       int region)
+{
+    return ta->bus->base + ta->start[region].offset;
+}
+
 static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
index 0c2c55012b58ad4c1d893b22bc833f8f83110b52..29e604863df7e873e0d30b634fb505dbd1e387dc 100644 (file)
@@ -24,8 +24,6 @@
 struct omap_lcd_panel_s {
     qemu_irq irq;
     DisplayState *state;
-    ram_addr_t imif_base;
-    ram_addr_t emiff_base;
 
     int plm;
     int tft;
@@ -436,17 +434,14 @@ void omap_lcdc_reset(struct omap_lcd_panel_s *s)
 }
 
 struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
-                struct omap_dma_lcd_channel_s *dma,
-                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk)
+                struct omap_dma_lcd_channel_s *dma, omap_clk clk)
 {
     int iomemtype;
     struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
-            qemu_mallocz(sizeof(struct omap_lcd_panel_s));
+            g_malloc0(sizeof(struct omap_lcd_panel_s));
 
     s->irq = irq;
     s->dma = dma;
-    s->imif_base = imif_base;
-    s->emiff_base = emiff_base;
     omap_lcdc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_lcdc_readfn,
index e9ec2f398bb99a873ebcc53f2eab6f4f55f46b12..a1afeb5c91975de1017e22a258dd88858d7523b0 100644 (file)
@@ -576,7 +576,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
 {
     int iomemtype;
     struct omap_mmc_s *s = (struct omap_mmc_s *)
-            qemu_mallocz(sizeof(struct omap_mmc_s));
+            g_malloc0(sizeof(struct omap_mmc_s));
 
     s->irq = irq;
     s->dma = dma;
@@ -602,7 +602,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
 {
     int iomemtype;
     struct omap_mmc_s *s = (struct omap_mmc_s *)
-            qemu_mallocz(sizeof(struct omap_mmc_s));
+            g_malloc0(sizeof(struct omap_mmc_s));
 
     s->irq = irq;
     s->dma = dma;
index e18376260edff4c910cf33f1ac03dc9e67d35079..1df2fd82bd995d4f675b85deeca2634f60be462e 100644 (file)
@@ -153,7 +153,7 @@ struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
 {
     int iomemtype;
     struct omap_sdrc_s *s = (struct omap_sdrc_s *)
-            qemu_mallocz(sizeof(struct omap_sdrc_s));
+            g_malloc0(sizeof(struct omap_sdrc_s));
 
     omap_sdrc_reset(s);
 
index a6b03496c44ea8722950facaeb528fc03553d1c0..6030ad9551a4af8b5658367049abff7b3c894b2a 100644 (file)
@@ -315,7 +315,7 @@ struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
 {
     int iomemtype;
     struct omap_mcspi_s *s = (struct omap_mcspi_s *)
-            qemu_mallocz(sizeof(struct omap_mcspi_s));
+            g_malloc0(sizeof(struct omap_mcspi_s));
     struct omap_mcspi_ch_s *ch = s->ch;
 
     s->irq = irq;
index 06bccbdc4e63cd26b683a789c0e7cd3ab618f276..fe535459df66188b710faaec81c4e422dc59b95a 100644 (file)
  * 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"
 #include "arm-misc.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 /*****************************************************************************/
 /* Siemens SX1 Cellphone V1 */
@@ -122,6 +122,7 @@ static void sx1_init(ram_addr_t ram_size,
                 const int version)
 {
     struct omap_mpu_state_s *cpu;
+    MemoryRegion *address_space = get_system_memory();
     int io;
     static uint32_t cs0val = 0x00213090;
     static uint32_t cs1val = 0x00215070;
@@ -136,7 +137,7 @@ static void sx1_init(ram_addr_t ram_size,
         flash_size = flash2_size;
     }
 
-    cpu = omap310_mpu_init(sx1_binfo.ram_size, cpu_model);
+    cpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model);
 
     /* External Flash (EMIFS) */
     cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
@@ -162,8 +163,8 @@ static void sx1_init(ram_addr_t ram_size,
 #endif
 
     if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
-        if (!pflash_cfi01_register(OMAP_CS0_BASE, qemu_ram_alloc(NULL,
-                                   "omap_sx1.flash0-1", flash_size),
+        if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
+                                   "omap_sx1.flash0-1", flash_size,
                                    dinfo->bdrv, sector_size,
                                    flash_size / sector_size,
                                    4, 0, 0, 0, 0, be)) {
@@ -183,8 +184,8 @@ static void sx1_init(ram_addr_t ram_size,
         cpu_register_physical_memory(OMAP_CS1_BASE + flash1_size,
                         OMAP_CS1_SIZE - flash1_size, io);
 
-        if (!pflash_cfi01_register(OMAP_CS1_BASE, qemu_ram_alloc(NULL,
-                                   "omap_sx1.flash1-1", flash1_size),
+        if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
+                                   "omap_sx1.flash1-1", flash1_size,
                                    dinfo->bdrv, sector_size,
                                    flash1_size / sector_size,
                                    4, 0, 0, 0, 0, be)) {
index 118668aead0078e11d67158d7539505bf9b17d83..b47ca881959c4f2b6395d548c7a3282973e4401c 100644 (file)
@@ -27,7 +27,7 @@ struct omap_synctimer_s {
 
 /* 32-kHz Sync Timer of the OMAP2 */
 static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
-    return muldiv64(qemu_get_clock(vm_clock), 0x8000, get_ticks_per_sec());
+    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
 }
 
 void omap_synctimer_reset(struct omap_synctimer_s *s)
@@ -86,7 +86,7 @@ static CPUWriteMemoryFunc * const omap_synctimer_writefn[] = {
 struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
                 struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
 {
-    struct omap_synctimer_s *s = qemu_mallocz(sizeof(*s));
+    struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
 
     omap_synctimer_reset(s);
     omap_l4_attach(ta, 0, l4_register_io_memory(
index 9cee81d7c9a9a0ffd7d060d766d3ea60fadf460f..19f8e6eec9be07bdefd5c948a5d3571ee3a96664 100644 (file)
@@ -22,6 +22,7 @@
 #include "omap.h"
 /* We use pc-style serial ports.  */
 #include "pc.h"
+#include "exec-memory.h"
 
 /* UARTs */
 struct omap_uart_s {
@@ -55,20 +56,15 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
                 const char *label, CharDriverState *chr)
 {
     struct omap_uart_s *s = (struct omap_uart_s *)
-            qemu_mallocz(sizeof(struct omap_uart_s));
+            g_malloc0(sizeof(struct omap_uart_s));
 
     s->base = base;
     s->fclk = fclk;
     s->irq = irq;
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_open(label, "null", NULL), 1,
-                               1);
-#else
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_open(label, "null", NULL), 1,
-                               0);
-#endif
+    s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
+                               omap_clk_getrate(fclk)/16,
+                               chr ?: qemu_chr_new(label, "null", NULL),
+                               DEVICE_NATIVE_ENDIAN);
     return s;
 }
 
@@ -182,15 +178,8 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->serial = serial_mm_init(s->base, 2, s->irq,
+    s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_open("null", "null", NULL), 1,
-                               1);
-#else
-    s->serial = serial_mm_init(s->base, 2, s->irq,
-                               omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_open("null", "null", NULL), 1,
-                               0);
-#endif
+                               chr ?: qemu_chr_new("null", "null", NULL),
+                               DEVICE_NATIVE_ENDIAN);
 }
index 71c1ab40b49ff5464174deb457f899a2c84a3601..7898da9321b80ca59f8ca266347a89777b87c817 100644 (file)
 #include "flash.h"
 #include "irq.h"
 #include "blockdev.h"
+#include "memory.h"
+#include "exec-memory.h"
+#include "sysbus.h"
+#include "qemu-error.h"
 
 /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
 #define PAGE_SHIFT     11
 #define BLOCK_SHIFT    (PAGE_SHIFT + 6)
 
 typedef struct {
-    uint32_t id;
+    SysBusDevice busdev;
+    struct {
+        uint16_t man;
+        uint16_t dev;
+        uint16_t ver;
+    } id;
     int shift;
     target_phys_addr_t base;
     qemu_irq intr;
@@ -41,10 +50,13 @@ typedef struct {
     uint8_t *image;
     uint8_t *otp;
     uint8_t *current;
-    ram_addr_t ram;
+    MemoryRegion ram;
+    MemoryRegion mapped_ram;
+    uint8_t current_direction;
     uint8_t *boot[2];
     uint8_t *data[2][2];
-    int iomemtype;
+    MemoryRegion iomem;
+    MemoryRegion container;
     int cycle;
     int otpmode;
 
@@ -96,38 +108,88 @@ enum {
     ONEN_LOCK_UNLOCKED = 1 << 2,
 };
 
-void onenand_base_update(void *opaque, target_phys_addr_t new)
+static void onenand_mem_setup(OneNANDState *s)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
-
-    s->base = new;
-
     /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
      * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
      * write boot commands.  Also take note of the BWPS bit.  */
-    cpu_register_physical_memory(s->base + (0x0000 << s->shift),
-                    0x0200 << s->shift, s->iomemtype);
-    cpu_register_physical_memory(s->base + (0x0200 << s->shift),
-                    0xbe00 << s->shift,
-                    (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM);
-    if (s->iomemtype)
-        cpu_register_physical_memory_offset(s->base + (0xc000 << s->shift),
-                    0x4000 << s->shift, s->iomemtype, (0xc000 << s->shift));
+    memory_region_init(&s->container, "onenand", 0x10000 << s->shift);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    memory_region_init_alias(&s->mapped_ram, "onenand-mapped-ram",
+                             &s->ram, 0x0200 << s->shift,
+                             0xbe00 << s->shift);
+    memory_region_add_subregion_overlap(&s->container,
+                                        0x0200 << s->shift,
+                                        &s->mapped_ram,
+                                        1);
 }
 
-void onenand_base_unmap(void *opaque)
+static void onenand_intr_update(OneNANDState *s)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
+    qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
+}
 
-    cpu_register_physical_memory(s->base,
-                    0x10000 << s->shift, IO_MEM_UNASSIGNED);
+static void onenand_pre_save(void *opaque)
+{
+    OneNANDState *s = opaque;
+    if (s->current == s->otp) {
+        s->current_direction = 1;
+    } else if (s->current == s->image) {
+        s->current_direction = 2;
+    } else {
+        s->current_direction = 0;
+    }
 }
 
-static void onenand_intr_update(OneNANDState *s)
+static int onenand_post_load(void *opaque, int version_id)
 {
-    qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
+    OneNANDState *s = opaque;
+    switch (s->current_direction) {
+    case 0:
+        break;
+    case 1:
+        s->current = s->otp;
+        break;
+    case 2:
+        s->current = s->image;
+        break;
+    default:
+        return -1;
+    }
+    onenand_intr_update(s);
+    return 0;
 }
 
+static const VMStateDescription vmstate_onenand = {
+    .name = "onenand",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = onenand_pre_save,
+    .post_load = onenand_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(current_direction, OneNANDState),
+        VMSTATE_INT32(cycle, OneNANDState),
+        VMSTATE_INT32(otpmode, OneNANDState),
+        VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
+        VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
+        VMSTATE_INT32(bufaddr, OneNANDState),
+        VMSTATE_INT32(count, OneNANDState),
+        VMSTATE_UINT16(command, OneNANDState),
+        VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
+        VMSTATE_UINT16(status, OneNANDState),
+        VMSTATE_UINT16(intstatus, OneNANDState),
+        VMSTATE_UINT16(wpstatus, OneNANDState),
+        VMSTATE_INT32(secs_cur, OneNANDState),
+        VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
+        VMSTATE_UINT8(ecc.cp, OneNANDState),
+        VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
+        VMSTATE_UINT16(ecc.count, OneNANDState),
+        VMSTATE_BUFFER_UNSAFE(otp, OneNANDState, 0, ((64 + 2) << PAGE_SHIFT)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 /* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
 static void onenand_reset(OneNANDState *s, int cold)
 {
@@ -154,11 +216,17 @@ static void onenand_reset(OneNANDState *s, int cold)
         /* Lock the whole flash */
         memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
 
-        if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0)
-            hw_error("%s: Loading the BootRAM failed.\n", __FUNCTION__);
+        if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
+            hw_error("%s: Loading the BootRAM failed.\n", __func__);
+        }
     }
 }
 
+static void onenand_system_reset(DeviceState *dev)
+{
+    onenand_reset(FROM_SYSBUS(OneNANDState, sysbus_from_qdev(dev)), 1);
+}
+
 static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
                 void *dest)
 {
@@ -175,14 +243,39 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
 static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
                 void *src)
 {
-    if (s->bdrv_cur)
-        return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
-    else if (sec + secn > s->secs_cur)
-        return 1;
-
-    memcpy(s->current + (sec << 9), src, secn << 9);
+    int result = 0;
+
+    if (secn > 0) {
+        uint32_t size = (uint32_t)secn * 512;
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0;
+        if (s->bdrv_cur) {
+            dp = g_malloc(size);
+            if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+                result = 1;
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dp = (uint8_t *)s->current + (sec << 9);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < size; i++) {
+                dp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+            }
+        }
+        if (dp && s->bdrv_cur) {
+            g_free(dp);
+        }
+    }
 
-    return 0;
+    return result;
 }
 
 static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
@@ -205,38 +298,90 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
 static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
                 void *src)
 {
-    uint8_t buf[512];
-
-    if (s->bdrv_cur) {
-        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
-            return 1;
-        memcpy(buf + ((sec & 31) << 4), src, secn << 4);
-        return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
-    } else if (sec + secn > s->secs_cur)
-        return 1;
-
-    memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
-    return 0;
+    int result = 0;
+    if (secn > 0) {
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0, *dpp = 0;
+        if (s->bdrv_cur) {
+            dp = g_malloc(512);
+            if (!dp || bdrv_read(s->bdrv_cur,
+                                 s->secs_cur + (sec >> 5),
+                                 dp, 1) < 0) {
+                result = 1;
+            } else {
+                dpp = dp + ((sec & 31) << 4);
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < (secn << 4); i++) {
+                dpp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+                                    dp, 1) < 0;
+            }
+        }
+        if (dp) {
+            g_free(dp);
+        }
+    }
+    return result;
 }
 
 static inline int onenand_erase(OneNANDState *s, int sec, int num)
 {
-    /* TODO: optimise */
-    uint8_t buf[512];
-
-    memset(buf, 0xff, sizeof(buf));
-    for (; num > 0; num --, sec ++) {
-        if (onenand_prog_main(s, sec, 1, buf))
-            return 1;
-        if (onenand_prog_spare(s, sec, 1, buf))
-            return 1;
+    uint8_t *blankbuf, *tmpbuf;
+    blankbuf = g_malloc(512);
+    if (!blankbuf) {
+        return 1;
+    }
+    tmpbuf = g_malloc(512);
+    if (!tmpbuf) {
+        g_free(blankbuf);
+        return 1;
+    }
+    memset(blankbuf, 0xff, 512);
+    for (; num > 0; num--, sec++) {
+        if (s->bdrv_cur) {
+            int erasesec = s->secs_cur + (sec >> 5);
+            if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
+                goto fail;
+            }
+            if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+            memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
+            if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+        } else {
+            if (sec + 1 > s->secs_cur) {
+                goto fail;
+            }
+            memcpy(s->current + (sec << 9), blankbuf, 512);
+            memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+                   blankbuf, 1 << 4);
+        }
     }
 
+    g_free(tmpbuf);
+    g_free(blankbuf);
     return 0;
+
+fail:
+    g_free(tmpbuf);
+    g_free(blankbuf);
+    return 1;
 }
 
-static void onenand_command(OneNANDState *s, int cmd)
+static void onenand_command(OneNANDState *s)
 {
     int b;
     int sec;
@@ -256,7 +401,7 @@ static void onenand_command(OneNANDState *s, int cmd)
             s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];    \
     buf += (s->bufaddr & 3) << 4;
 
-    switch (cmd) {
+    switch (s->command) {
     case 0x00: /* Load single/multiple sector data unit into buffer */
         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
 
@@ -437,13 +582,14 @@ static void onenand_command(OneNANDState *s, int cmd)
         s->status |= ONEN_ERR_CMD;
         s->intstatus |= ONEN_INT;
         fprintf(stderr, "%s: unknown OneNAND command %x\n",
-                        __FUNCTION__, cmd);
+                        __func__, s->command);
     }
 
     onenand_intr_update(s);
 }
 
-static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
+static uint64_t onenand_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     OneNANDState *s = (OneNANDState *) opaque;
     int offset = addr >> s->shift;
@@ -453,12 +599,12 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
         return lduw_le_p(s->boot[0] + addr);
 
     case 0xf000:       /* Manufacturer ID */
-        return (s->id >> 16) & 0xff;
+        return s->id.man;
     case 0xf001:       /* Device ID */
-        return (s->id >>  8) & 0xff;
-    /* TODO: get the following values from a real chip!  */
+        return s->id.dev;
     case 0xf002:       /* Version ID */
-        return (s->id >>  0) & 0xff;
+        return s->id.ver;
+    /* TODO: get the following values from a real chip!  */
     case 0xf003:       /* Data Buffer size */
         return 1 << PAGE_SHIFT;
     case 0xf004:       /* Boot Buffer size */
@@ -508,7 +654,7 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void onenand_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                          uint64_t value, unsigned size)
 {
     OneNANDState *s = (OneNANDState *) opaque;
     int offset = addr >> s->shift;
@@ -541,13 +687,13 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
 
         case 0x0090:   /* Read Identification Data */
             memset(s->boot[0], 0, 3 << s->shift);
-            s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
-            s->boot[0][1 << s->shift] = (s->id >>  8) & 0xff;
+            s->boot[0][0 << s->shift] = s->id.man & 0xff;
+            s->boot[0][1 << s->shift] = s->id.dev & 0xff;
             s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
             break;
 
         default:
-            fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
+            fprintf(stderr, "%s: unknown OneNAND boot command %"PRIx64"\n",
                             __FUNCTION__, value);
         }
         break;
@@ -568,7 +714,7 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
         if (s->intstatus & (1 << 15))
             break;
         s->command = value;
-        onenand_command(s, s->command);
+        onenand_command(s);
         break;
     case 0xf221:       /* System Configuration 1 */
         s->config[0] = value;
@@ -603,59 +749,81 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const onenand_readfn[] = {
-    onenand_read,      /* TODO */
-    onenand_read,
-    onenand_read,
-};
-
-static CPUWriteMemoryFunc * const onenand_writefn[] = {
-    onenand_write,     /* TODO */
-    onenand_write,
-    onenand_write,
+static const MemoryRegionOps onenand_ops = {
+    .read = onenand_read,
+    .write = onenand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+static int onenand_initfn(SysBusDevice *dev)
 {
-    OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
-    DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
-    uint32_t size = 1 << (24 + ((id >> 12) & 7));
+    OneNANDState *s = (OneNANDState *)dev;
+    uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
     void *ram;
-
-    s->shift = regshift;
-    s->intr = irq;
+    s->base = (target_phys_addr_t)-1;
     s->rdy = NULL;
-    s->id = id;
     s->blocks = size >> BLOCK_SHIFT;
     s->secs = size >> 9;
-    s->blockwp = qemu_malloc(s->blocks);
-    s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
-    s->iomemtype = cpu_register_io_memory(onenand_readfn,
-                    onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
-    if (!dinfo)
-        s->image = memset(qemu_malloc(size + (size >> 5)),
-                        0xff, size + (size >> 5));
-    else
-        s->bdrv = dinfo->bdrv;
-    s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
+    s->blockwp = g_malloc(s->blocks);
+    s->density_mask = (s->id.dev & 0x08)
+        ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
+    memory_region_init_io(&s->iomem, &onenand_ops, s, "onenand",
+                          0x10000 << s->shift);
+    if (!s->bdrv) {
+        s->image = memset(g_malloc(size + (size >> 5)),
+                          0xff, size + (size >> 5));
+    } else {
+        if (bdrv_is_read_only(s->bdrv)) {
+            error_report("Can't use a read-only drive");
+            return -1;
+        }
+        s->bdrv_cur = s->bdrv;
+    }
+    s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
                     0xff, (64 + 2) << PAGE_SHIFT);
-    s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
-    ram = qemu_get_ram_ptr(s->ram);
+    memory_region_init_ram(&s->ram, NULL, "onenand.ram", 0xc000 << s->shift);
+    ram = memory_region_get_ram_ptr(&s->ram);
     s->boot[0] = ram + (0x0000 << s->shift);
     s->boot[1] = ram + (0x8000 << s->shift);
     s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
     s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
     s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
     s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
+    onenand_mem_setup(s);
+    sysbus_init_irq(dev, &s->intr);
+    sysbus_init_mmio_region(dev, &s->container);
+    vmstate_register(&dev->qdev,
+                     ((s->shift & 0x7f) << 24)
+                     | ((s->id.man & 0xff) << 16)
+                     | ((s->id.dev & 0xff) << 8)
+                     | (s->id.ver & 0xff),
+                     &vmstate_onenand, s);
+    return 0;
+}
 
-    onenand_reset(s, 1);
+static SysBusDeviceInfo onenand_info = {
+    .init = onenand_initfn,
+    .qdev.name = "onenand",
+    .qdev.size = sizeof(OneNANDState),
+    .qdev.reset = onenand_system_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+        DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+        DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+        DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+        DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
+static void onenand_register_device(void)
+{
+    sysbus_register_withprop(&onenand_info);
 }
 
-void *onenand_raw_otp(void *opaque)
+void *onenand_raw_otp(DeviceState *onenand_device)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
-
-    return s->otp;
+    return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp;
 }
+
+device_init(onenand_register_device)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
new file mode 100644 (file)
index 0000000..2c1e475
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ * OpenCores Ethernet MAC 10/100 + subset of
+ * National Semiconductors DP83848C 10/100 PHY
+ *
+ * http://opencores.org/svnget,ethmac?file=%2Ftrunk%2F%2Fdoc%2Feth_speci.pdf
+ * http://cache.national.com/ds/DP/DP83848C.pdf
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "net.h"
+#include "sysemu.h"
+#include "trace.h"
+
+/* RECSMALL is not used because it breaks tap networking in linux:
+ * incoming ARP responses are too short
+ */
+#undef USE_RECSMALL
+
+#define GET_FIELD(v, field) (((v) & (field)) >> (field ## _LBN))
+#define GET_REGBIT(s, reg, field) ((s)->regs[reg] & (reg ## _ ## field))
+#define GET_REGFIELD(s, reg, field) \
+    GET_FIELD((s)->regs[reg], reg ## _ ## field)
+
+#define SET_FIELD(v, field, data) \
+    ((v) = (((v) & ~(field)) | (((data) << (field ## _LBN)) & (field))))
+#define SET_REGFIELD(s, reg, field, data) \
+    SET_FIELD((s)->regs[reg], reg ## _ ## field, data)
+
+/* PHY MII registers */
+enum {
+    MII_BMCR,
+    MII_BMSR,
+    MII_PHYIDR1,
+    MII_PHYIDR2,
+    MII_ANAR,
+    MII_ANLPAR,
+    MII_REG_MAX = 16,
+};
+
+typedef struct Mii {
+    uint16_t regs[MII_REG_MAX];
+    bool link_ok;
+} Mii;
+
+static void mii_set_link(Mii *s, bool link_ok)
+{
+    if (link_ok) {
+        s->regs[MII_BMSR] |= 0x4;
+        s->regs[MII_ANLPAR] |= 0x01e1;
+    } else {
+        s->regs[MII_BMSR] &= ~0x4;
+        s->regs[MII_ANLPAR] &= 0x01ff;
+    }
+    s->link_ok = link_ok;
+}
+
+static void mii_reset(Mii *s)
+{
+    memset(s->regs, 0, sizeof(s->regs));
+    s->regs[MII_BMCR] = 0x1000;
+    s->regs[MII_BMSR] = 0x7848; /* no ext regs */
+    s->regs[MII_PHYIDR1] = 0x2000;
+    s->regs[MII_PHYIDR2] = 0x5c90;
+    s->regs[MII_ANAR] = 0x01e1;
+    mii_set_link(s, s->link_ok);
+}
+
+static void mii_ro(Mii *s, uint16_t v)
+{
+}
+
+static void mii_write_bmcr(Mii *s, uint16_t v)
+{
+    if (v & 0x8000) {
+        mii_reset(s);
+    } else {
+        s->regs[MII_BMCR] = v;
+    }
+}
+
+static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
+{
+    static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
+        [MII_BMCR] = mii_write_bmcr,
+        [MII_BMSR] = mii_ro,
+        [MII_PHYIDR1] = mii_ro,
+        [MII_PHYIDR2] = mii_ro,
+    };
+
+    if (idx < MII_REG_MAX) {
+        trace_open_eth_mii_write(idx, v);
+        if (reg_write[idx]) {
+            reg_write[idx](s, v);
+        } else {
+            s->regs[idx] = v;
+        }
+    }
+}
+
+static uint16_t mii_read_host(Mii *s, unsigned idx)
+{
+    trace_open_eth_mii_read(idx, s->regs[idx]);
+    return s->regs[idx];
+}
+
+/* OpenCores Ethernet registers */
+enum {
+    MODER,
+    INT_SOURCE,
+    INT_MASK,
+    IPGT,
+    IPGR1,
+    IPGR2,
+    PACKETLEN,
+    COLLCONF,
+    TX_BD_NUM,
+    CTRLMODER,
+    MIIMODER,
+    MIICOMMAND,
+    MIIADDRESS,
+    MIITX_DATA,
+    MIIRX_DATA,
+    MIISTATUS,
+    MAC_ADDR0,
+    MAC_ADDR1,
+    HASH0,
+    HASH1,
+    TXCTRL,
+    REG_MAX,
+};
+
+enum {
+    MODER_RECSMALL = 0x10000,
+    MODER_PAD = 0x8000,
+    MODER_HUGEN = 0x4000,
+    MODER_RST = 0x800,
+    MODER_LOOPBCK = 0x80,
+    MODER_PRO = 0x20,
+    MODER_IAM = 0x10,
+    MODER_BRO = 0x8,
+    MODER_TXEN = 0x2,
+    MODER_RXEN = 0x1,
+};
+
+enum {
+    INT_SOURCE_RXB = 0x4,
+    INT_SOURCE_TXB = 0x1,
+};
+
+enum {
+    PACKETLEN_MINFL = 0xffff0000,
+    PACKETLEN_MINFL_LBN = 16,
+    PACKETLEN_MAXFL = 0xffff,
+    PACKETLEN_MAXFL_LBN = 0,
+};
+
+enum {
+    MIICOMMAND_WCTRLDATA = 0x4,
+    MIICOMMAND_RSTAT = 0x2,
+    MIICOMMAND_SCANSTAT = 0x1,
+};
+
+enum {
+    MIIADDRESS_RGAD = 0x1f00,
+    MIIADDRESS_RGAD_LBN = 8,
+    MIIADDRESS_FIAD = 0x1f,
+    MIIADDRESS_FIAD_LBN = 0,
+};
+
+enum {
+    MIITX_DATA_CTRLDATA = 0xffff,
+    MIITX_DATA_CTRLDATA_LBN = 0,
+};
+
+enum {
+    MIIRX_DATA_PRSD = 0xffff,
+    MIIRX_DATA_PRSD_LBN = 0,
+};
+
+enum {
+    MIISTATUS_LINKFAIL = 0x1,
+    MIISTATUS_LINKFAIL_LBN = 0,
+};
+
+enum {
+    MAC_ADDR0_BYTE2 = 0xff000000,
+    MAC_ADDR0_BYTE2_LBN = 24,
+    MAC_ADDR0_BYTE3 = 0xff0000,
+    MAC_ADDR0_BYTE3_LBN = 16,
+    MAC_ADDR0_BYTE4 = 0xff00,
+    MAC_ADDR0_BYTE4_LBN = 8,
+    MAC_ADDR0_BYTE5 = 0xff,
+    MAC_ADDR0_BYTE5_LBN = 0,
+};
+
+enum {
+    MAC_ADDR1_BYTE0 = 0xff00,
+    MAC_ADDR1_BYTE0_LBN = 8,
+    MAC_ADDR1_BYTE1 = 0xff,
+    MAC_ADDR1_BYTE1_LBN = 0,
+};
+
+enum {
+    TXD_LEN = 0xffff0000,
+    TXD_LEN_LBN = 16,
+    TXD_RD = 0x8000,
+    TXD_IRQ = 0x4000,
+    TXD_WR = 0x2000,
+    TXD_PAD = 0x1000,
+    TXD_CRC = 0x800,
+    TXD_UR = 0x100,
+    TXD_RTRY = 0xf0,
+    TXD_RTRY_LBN = 4,
+    TXD_RL = 0x8,
+    TXD_LC = 0x4,
+    TXD_DF = 0x2,
+    TXD_CS = 0x1,
+};
+
+enum {
+    RXD_LEN = 0xffff0000,
+    RXD_LEN_LBN = 16,
+    RXD_E = 0x8000,
+    RXD_IRQ = 0x4000,
+    RXD_WRAP = 0x2000,
+    RXD_CF = 0x100,
+    RXD_M = 0x80,
+    RXD_OR = 0x40,
+    RXD_IS = 0x20,
+    RXD_DN = 0x10,
+    RXD_TL = 0x8,
+    RXD_SF = 0x4,
+    RXD_CRC = 0x2,
+    RXD_LC = 0x1,
+};
+
+typedef struct desc {
+    uint32_t len_flags;
+    uint32_t buf_ptr;
+} desc;
+
+#define DEFAULT_PHY 1
+
+typedef struct OpenEthState {
+    SysBusDevice dev;
+    NICState *nic;
+    NICConf conf;
+    MemoryRegion reg_io;
+    MemoryRegion desc_io;
+    qemu_irq irq;
+
+    Mii mii;
+    uint32_t regs[REG_MAX];
+    unsigned tx_desc;
+    unsigned rx_desc;
+    desc desc[128];
+} OpenEthState;
+
+static desc *rx_desc(OpenEthState *s)
+{
+    return s->desc + s->rx_desc;
+}
+
+static desc *tx_desc(OpenEthState *s)
+{
+    return s->desc + s->tx_desc;
+}
+
+static void open_eth_update_irq(OpenEthState *s,
+        uint32_t old, uint32_t new)
+{
+    if (!old != !new) {
+        trace_open_eth_update_irq(new);
+        qemu_set_irq(s->irq, new);
+    }
+}
+
+static void open_eth_int_source_write(OpenEthState *s,
+        uint32_t val)
+{
+    uint32_t old_val = s->regs[INT_SOURCE];
+
+    s->regs[INT_SOURCE] = val;
+    open_eth_update_irq(s, old_val & s->regs[INT_MASK],
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_set_link_status(VLANClientState *nc)
+{
+    OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (GET_REGBIT(s, MIICOMMAND, SCANSTAT)) {
+        SET_REGFIELD(s, MIISTATUS, LINKFAIL, nc->link_down);
+    }
+    mii_set_link(&s->mii, !nc->link_down);
+}
+
+static void open_eth_reset(void *opaque)
+{
+    OpenEthState *s = opaque;
+
+    memset(s->regs, 0, sizeof(s->regs));
+    s->regs[MODER] = 0xa000;
+    s->regs[IPGT] = 0x12;
+    s->regs[IPGR1] = 0xc;
+    s->regs[IPGR2] = 0x12;
+    s->regs[PACKETLEN] = 0x400600;
+    s->regs[COLLCONF] = 0xf003f;
+    s->regs[TX_BD_NUM] = 0x40;
+    s->regs[MIIMODER] = 0x64;
+
+    s->tx_desc = 0;
+    s->rx_desc = 0x40;
+
+    mii_reset(&s->mii);
+    open_eth_set_link_status(&s->nic->nc);
+}
+
+static int open_eth_can_receive(VLANClientState *nc)
+{
+    OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    return GET_REGBIT(s, MODER, RXEN) &&
+        (s->regs[TX_BD_NUM] < 0x80) &&
+        (rx_desc(s)->len_flags & RXD_E);
+}
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static unsigned compute_mcast_idx(const uint8_t *ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry) {
+                crc = ((crc ^ POLYNOMIAL) | carry);
+            }
+        }
+    }
+    return crc >> 26;
+}
+
+static ssize_t open_eth_receive(VLANClientState *nc,
+        const uint8_t *buf, size_t size)
+{
+    OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL);
+    size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL);
+    size_t fcsl = 4;
+    bool miss = true;
+
+    trace_open_eth_receive((unsigned)size);
+
+    if (size >= 6) {
+        static const uint8_t bcast_addr[] = {
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        };
+        if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
+            miss = GET_REGBIT(s, MODER, BRO);
+        } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
+            unsigned mcast_idx = compute_mcast_idx(buf);
+            miss = !(s->regs[HASH0 + mcast_idx / 32] &
+                    (1 << (mcast_idx % 32)));
+            trace_open_eth_receive_mcast(
+                    mcast_idx, s->regs[HASH0], s->regs[HASH1]);
+        } else {
+            miss = GET_REGFIELD(s, MAC_ADDR1, BYTE0) != buf[0] ||
+                GET_REGFIELD(s, MAC_ADDR1, BYTE1) != buf[1] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE2) != buf[2] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE3) != buf[3] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE4) != buf[4] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE5) != buf[5];
+        }
+    }
+
+    if (miss && !GET_REGBIT(s, MODER, PRO)) {
+        trace_open_eth_receive_reject();
+        return size;
+    }
+
+#ifdef USE_RECSMALL
+    if (GET_REGBIT(s, MODER, RECSMALL) || size >= minfl) {
+#else
+    {
+#endif
+        static const uint8_t zero[64] = {0};
+        desc *desc = rx_desc(s);
+        size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
+
+        desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
+                RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
+
+        if (copy_size > size) {
+            copy_size = size;
+        } else {
+            fcsl = 0;
+        }
+        if (miss) {
+            desc->len_flags |= RXD_M;
+        }
+        if (GET_REGBIT(s, MODER, HUGEN) && size > maxfl) {
+            desc->len_flags |= RXD_TL;
+        }
+#ifdef USE_RECSMALL
+        if (size < minfl) {
+            desc->len_flags |= RXD_SF;
+        }
+#endif
+
+        cpu_physical_memory_write(desc->buf_ptr, buf, copy_size);
+
+        if (GET_REGBIT(s, MODER, PAD) && copy_size < minfl) {
+            if (minfl - copy_size > fcsl) {
+                fcsl = 0;
+            } else {
+                fcsl -= minfl - copy_size;
+            }
+            while (copy_size < minfl) {
+                size_t zero_sz = minfl - copy_size < sizeof(zero) ?
+                    minfl - copy_size : sizeof(zero);
+
+                cpu_physical_memory_write(desc->buf_ptr + copy_size,
+                        zero, zero_sz);
+                copy_size += zero_sz;
+            }
+        }
+
+        /* There's no FCS in the frames handed to us by the QEMU, zero fill it.
+         * Don't do it if the frame is cut at the MAXFL or padded with 4 or
+         * more bytes to the MINFL.
+         */
+        cpu_physical_memory_write(desc->buf_ptr + copy_size, zero, fcsl);
+        copy_size += fcsl;
+
+        SET_FIELD(desc->len_flags, RXD_LEN, copy_size);
+
+        if ((desc->len_flags & RXD_WRAP) || s->rx_desc == 0x7f) {
+            s->rx_desc = s->regs[TX_BD_NUM];
+        } else {
+            ++s->rx_desc;
+        }
+        desc->len_flags &= ~RXD_E;
+
+        trace_open_eth_receive_desc(desc->buf_ptr, desc->len_flags);
+
+        if (desc->len_flags & RXD_IRQ) {
+            open_eth_int_source_write(s,
+                    s->regs[INT_SOURCE] | INT_SOURCE_RXB);
+        }
+    }
+    return size;
+}
+
+static void open_eth_cleanup(VLANClientState *nc)
+{
+}
+
+static NetClientInfo net_open_eth_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = open_eth_can_receive,
+    .receive = open_eth_receive,
+    .cleanup = open_eth_cleanup,
+    .link_status_changed = open_eth_set_link_status,
+};
+
+static void open_eth_start_xmit(OpenEthState *s, desc *tx)
+{
+    uint8_t buf[65536];
+    unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
+    unsigned tx_len = len;
+
+    if ((tx->len_flags & TXD_PAD) &&
+            tx_len < GET_REGFIELD(s, PACKETLEN, MINFL)) {
+        tx_len = GET_REGFIELD(s, PACKETLEN, MINFL);
+    }
+    if (!GET_REGBIT(s, MODER, HUGEN) &&
+            tx_len > GET_REGFIELD(s, PACKETLEN, MAXFL)) {
+        tx_len = GET_REGFIELD(s, PACKETLEN, MAXFL);
+    }
+
+    trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
+
+    if (len > tx_len) {
+        len = tx_len;
+    }
+    cpu_physical_memory_read(tx->buf_ptr, buf, len);
+    if (tx_len > len) {
+        memset(buf + len, 0, tx_len - len);
+    }
+    qemu_send_packet(&s->nic->nc, buf, tx_len);
+
+    if (tx->len_flags & TXD_WR) {
+        s->tx_desc = 0;
+    } else {
+        ++s->tx_desc;
+        if (s->tx_desc >= s->regs[TX_BD_NUM]) {
+            s->tx_desc = 0;
+        }
+    }
+    tx->len_flags &= ~(TXD_RD | TXD_UR |
+            TXD_RTRY | TXD_RL | TXD_LC | TXD_DF | TXD_CS);
+    if (tx->len_flags & TXD_IRQ) {
+        open_eth_int_source_write(s, s->regs[INT_SOURCE] | INT_SOURCE_TXB);
+    }
+
+}
+
+static void open_eth_check_start_xmit(OpenEthState *s)
+{
+    desc *tx = tx_desc(s);
+    if (GET_REGBIT(s, MODER, TXEN) && s->regs[TX_BD_NUM] > 0 &&
+            (tx->len_flags & TXD_RD) &&
+            GET_FIELD(tx->len_flags, TXD_LEN) > 4) {
+        open_eth_start_xmit(s, tx);
+    }
+}
+
+static uint64_t open_eth_reg_read(void *opaque,
+        target_phys_addr_t addr, unsigned int size)
+{
+    static uint32_t (*reg_read[REG_MAX])(OpenEthState *s) = {
+    };
+    OpenEthState *s = opaque;
+    unsigned idx = addr / 4;
+    uint64_t v = 0;
+
+    if (idx < REG_MAX) {
+        if (reg_read[idx]) {
+            v = reg_read[idx](s);
+        } else {
+            v = s->regs[idx];
+        }
+    }
+    trace_open_eth_reg_read((uint32_t)addr, (uint32_t)v);
+    return v;
+}
+
+static void open_eth_ro(OpenEthState *s, uint32_t val)
+{
+}
+
+static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t set = val & ~s->regs[MODER];
+
+    if (set & MODER_RST) {
+        open_eth_reset(s);
+    }
+
+    s->regs[MODER] = val;
+
+    if (set & MODER_RXEN) {
+        s->rx_desc = s->regs[TX_BD_NUM];
+    }
+    if (set & MODER_TXEN) {
+        s->tx_desc = 0;
+        open_eth_check_start_xmit(s);
+    }
+}
+
+static void open_eth_int_source_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t old = s->regs[INT_SOURCE];
+
+    s->regs[INT_SOURCE] &= ~val;
+    open_eth_update_irq(s, old & s->regs[INT_MASK],
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t old = s->regs[INT_MASK];
+
+    s->regs[INT_MASK] = val;
+    open_eth_update_irq(s, s->regs[INT_SOURCE] & old,
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
+{
+    unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
+    unsigned rgad = GET_REGFIELD(s, MIIADDRESS, RGAD);
+
+    if (val & MIICOMMAND_WCTRLDATA) {
+        if (fiad == DEFAULT_PHY) {
+            mii_write_host(&s->mii, rgad,
+                    GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
+        }
+    }
+    if (val & MIICOMMAND_RSTAT) {
+        if (fiad == DEFAULT_PHY) {
+            SET_REGFIELD(s, MIIRX_DATA, PRSD,
+                    mii_read_host(&s->mii, rgad));
+        } else {
+            s->regs[MIIRX_DATA] = 0xffff;
+        }
+        SET_REGFIELD(s, MIISTATUS, LINKFAIL, s->nic->nc.link_down);
+    }
+}
+
+static void open_eth_mii_tx_host_write(OpenEthState *s, uint32_t val)
+{
+    SET_REGFIELD(s, MIITX_DATA, CTRLDATA, val);
+    if (GET_REGFIELD(s, MIIADDRESS, FIAD) == DEFAULT_PHY) {
+        mii_write_host(&s->mii, GET_REGFIELD(s, MIIADDRESS, RGAD),
+                GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
+    }
+}
+
+static void open_eth_reg_write(void *opaque,
+        target_phys_addr_t addr, uint64_t val, unsigned int size)
+{
+    static void (*reg_write[REG_MAX])(OpenEthState *s, uint32_t val) = {
+        [MODER] = open_eth_moder_host_write,
+        [INT_SOURCE] = open_eth_int_source_host_write,
+        [INT_MASK] = open_eth_int_mask_host_write,
+        [MIICOMMAND] = open_eth_mii_command_host_write,
+        [MIITX_DATA] = open_eth_mii_tx_host_write,
+        [MIISTATUS] = open_eth_ro,
+    };
+    OpenEthState *s = opaque;
+    unsigned idx = addr / 4;
+
+    if (idx < REG_MAX) {
+        trace_open_eth_reg_write((uint32_t)addr, (uint32_t)val);
+        if (reg_write[idx]) {
+            reg_write[idx](s, val);
+        } else {
+            s->regs[idx] = val;
+        }
+    }
+}
+
+static uint64_t open_eth_desc_read(void *opaque,
+        target_phys_addr_t addr, unsigned int size)
+{
+    OpenEthState *s = opaque;
+    uint64_t v = 0;
+
+    addr &= 0x3ff;
+    memcpy(&v, (uint8_t *)s->desc + addr, size);
+    trace_open_eth_desc_read((uint32_t)addr, (uint32_t)v);
+    return v;
+}
+
+static void open_eth_desc_write(void *opaque,
+        target_phys_addr_t addr, uint64_t val, unsigned int size)
+{
+    OpenEthState *s = opaque;
+
+    addr &= 0x3ff;
+    trace_open_eth_desc_write((uint32_t)addr, (uint32_t)val);
+    memcpy((uint8_t *)s->desc + addr, &val, size);
+    open_eth_check_start_xmit(s);
+}
+
+
+static MemoryRegionOps open_eth_reg_ops = {
+    .read = open_eth_reg_read,
+    .write = open_eth_reg_write,
+};
+
+static MemoryRegionOps open_eth_desc_ops = {
+    .read = open_eth_desc_read,
+    .write = open_eth_desc_write,
+};
+
+static int sysbus_open_eth_init(SysBusDevice *dev)
+{
+    OpenEthState *s = DO_UPCAST(OpenEthState, dev, dev);
+
+    memory_region_init_io(&s->reg_io, &open_eth_reg_ops, s,
+            "open_eth.regs", 0x54);
+    sysbus_init_mmio_region(dev, &s->reg_io);
+
+    memory_region_init_io(&s->desc_io, &open_eth_desc_ops, s,
+            "open_eth.desc", 0x400);
+    sysbus_init_mmio_region(dev, &s->desc_io);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
+                          s->dev.qdev.info->name, s->dev.qdev.id, s);
+    return 0;
+}
+
+static void qdev_open_eth_reset(DeviceState *dev)
+{
+    OpenEthState *d = DO_UPCAST(OpenEthState, dev.qdev, dev);
+    open_eth_reset(d);
+}
+
+static SysBusDeviceInfo open_eth_info = {
+    .qdev.name  = "open_eth",
+    .qdev.desc  = "Opencores 10/100 Mbit Ethernet",
+    .qdev.size  = sizeof(OpenEthState),
+    .qdev.reset = qdev_open_eth_reset,
+    .init       = sysbus_open_eth_init,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(OpenEthState, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void open_eth_register_devices(void)
+{
+    sysbus_register_withprop(&open_eth_info);
+}
+
+device_init(open_eth_register_devices)
index 6d2cf994ba6072c2c2fecf650fdb3ecfb0c75861..22fc275b626d940398c22ede174437af37b3438c 100644 (file)
@@ -2,6 +2,7 @@
  * OpenPIC emulation
  *
  * Copyright (c) 2004 Jocelyn Mayer
+ *               2011 Alexander Graf
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
 #define MAX_MBX     4
 #define MAX_TMR     4
 #define VECTOR_BITS 8
-#define MAX_IPI     0
+#define MAX_IPI     4
 
 #define VID (0x00000000)
 
 #elif defined(USE_MPCxxx)
 
-#define MAX_CPU     2
+#define MAX_CPU    15
 #define MAX_IRQ   128
 #define MAX_DBL     0
 #define MAX_MBX     0
@@ -127,14 +128,14 @@ enum {
 #define MPIC_MSI_REG_START        0x11C00
 #define MPIC_MSI_REG_SIZE         0x100
 #define MPIC_CPU_REG_START        0x20000
-#define MPIC_CPU_REG_SIZE         0x100
+#define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
 
 enum mpic_ide_bits {
-    IDR_EP     = 0,
-    IDR_CI0     = 1,
-    IDR_CI1     = 2,
-    IDR_P1     = 30,
-    IDR_P0     = 31,
+    IDR_EP     = 31,
+    IDR_CI0     = 30,
+    IDR_CI1     = 29,
+    IDR_P1     = 1,
+    IDR_P0     = 0,
 };
 
 #else
@@ -161,6 +162,16 @@ static inline int test_bit (uint32_t *field, int bit)
     return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
 }
 
+static int get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
+                                          int idx);
+static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
+                                       uint32_t val, int idx);
+
 enum {
     IRQ_EXTERNAL = 0x01,
     IRQ_INTERNAL = 0x02,
@@ -205,7 +216,11 @@ typedef struct IRQ_dst_t {
 
 typedef struct openpic_t {
     PCIDevice pci_dev;
-    int mem_index;
+    MemoryRegion mem;
+
+    /* Sub-regions */
+    MemoryRegion sub_io_mem[7];
+
     /* Global registers */
     uint32_t frep; /* Feature reporting register */
     uint32_t glbc; /* Global configuration register  */
@@ -461,46 +476,35 @@ static void openpic_reset (void *opaque)
     opp->glbc = 0x00000000;
 }
 
-static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
+static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
 {
-    uint32_t retval;
-
-    switch (reg) {
-    case IRQ_IPVP:
-        retval = opp->src[n_IRQ].ipvp;
-        break;
-    case IRQ_IDE:
-        retval = opp->src[n_IRQ].ide;
-        break;
-    }
+    return opp->src[n_IRQ].ide;
+}
 
-    return retval;
+static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].ipvp;
 }
 
-static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
-                                 uint32_t reg, uint32_t val)
+static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
 {
     uint32_t tmp;
 
-    switch (reg) {
-    case IRQ_IPVP:
-        /* NOTE: not fully accurate for special IRQs, but simple and
-           sufficient */
-        /* ACTIVITY bit is read-only */
-        opp->src[n_IRQ].ipvp =
-            (opp->src[n_IRQ].ipvp & 0x40000000) |
-            (val & 0x800F00FF);
-        openpic_update_irq(opp, n_IRQ);
-        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
-                n_IRQ, val, opp->src[n_IRQ].ipvp);
-        break;
-    case IRQ_IDE:
-        tmp = val & 0xC0000000;
-        tmp |= val & ((1 << MAX_CPU) - 1);
-        opp->src[n_IRQ].ide = tmp;
-        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
-        break;
-    }
+    tmp = val & 0xC0000000;
+    tmp |= val & ((1ULL << MAX_CPU) - 1);
+    opp->src[n_IRQ].ide = tmp;
+    DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
+}
+
+static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
+{
+    /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
+    /* ACTIVITY bit is read-only */
+    opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
+                         | (val & 0x800F00FF);
+    openpic_update_irq(opp, n_IRQ);
+    DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+            opp->src[n_IRQ].ipvp);
 }
 
 #if 0 // Code provision for Intel model
@@ -512,10 +516,10 @@ static uint32_t read_doorbell_register (openpic_t *opp,
 
     switch (offset) {
     case DBL_IPVP_OFFSET:
-        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl);
         break;
     case DBL_IDE_OFFSET:
-        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl);
         break;
     case DBL_DMR_OFFSET:
         retval = opp->doorbells[n_dbl].dmr;
@@ -530,10 +534,10 @@ static void write_doorbell_register (penpic_t *opp, int n_dbl,
 {
     switch (offset) {
     case DBL_IVPR_OFFSET:
-        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
+        write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value);
         break;
     case DBL_IDE_OFFSET:
-        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
+        write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value);
         break;
     case DBL_DMR_OFFSET:
         opp->doorbells[n_dbl].dmr = value;
@@ -553,10 +557,10 @@ static uint32_t read_mailbox_register (openpic_t *opp,
         retval = opp->mailboxes[n_mbx].mbr;
         break;
     case MBX_IVPR_OFFSET:
-        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx);
         break;
     case MBX_DMR_OFFSET:
-        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx);
         break;
     }
 
@@ -571,10 +575,10 @@ static void write_mailbox_register (openpic_t *opp, int n_mbx,
         opp->mailboxes[n_mbx].mbr = value;
         break;
     case MBX_IVPR_OFFSET:
-        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
+        write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value);
         break;
     case MBX_DMR_OFFSET:
-        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
+        write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value);
         break;
     }
 }
@@ -590,18 +594,27 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    addr &= 0xFF;
     switch (addr) {
-    case 0x00: /* FREP */
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
         break;
-    case 0x20: /* GLBC */
+    case 0x1000: /* FREP */
+        break;
+    case 0x1020: /* GLBC */
         if (val & 0x80000000 && opp->reset)
             opp->reset(opp);
         opp->glbc = val & ~0x80000000;
         break;
-    case 0x80: /* VENI */
+    case 0x1080: /* VENI */
         break;
-    case 0x90: /* PINT */
+    case 0x1090: /* PINT */
         for (idx = 0; idx < opp->nb_cpus; idx++) {
             if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
                 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
@@ -615,22 +628,20 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
         }
         opp->pint = val;
         break;
-#if MAX_IPI > 0
-    case 0xA0: /* IPI_IPVP */
-    case 0xB0:
-    case 0xC0:
-    case 0xD0:
+    case 0x10A0: /* IPI_IPVP */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
         {
             int idx;
-            idx = (addr - 0xA0) >> 4;
-            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
+            idx = (addr - 0x10A0) >> 4;
+            write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
         }
         break;
-#endif
-    case 0xE0: /* SPVE */
+    case 0x10E0: /* SPVE */
         opp->spve = val & 0x000000FF;
         break;
-    case 0xF0: /* TIFR */
+    case 0x10F0: /* TIFR */
         opp->tifr = val;
         break;
     default:
@@ -647,36 +658,43 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
         return retval;
-    addr &= 0xFF;
     switch (addr) {
-    case 0x00: /* FREP */
+    case 0x1000: /* FREP */
         retval = opp->frep;
         break;
-    case 0x20: /* GLBC */
+    case 0x1020: /* GLBC */
         retval = opp->glbc;
         break;
-    case 0x80: /* VENI */
+    case 0x1080: /* VENI */
         retval = opp->veni;
         break;
-    case 0x90: /* PINT */
+    case 0x1090: /* PINT */
         retval = 0x00000000;
         break;
-#if MAX_IPI > 0
-    case 0xA0: /* IPI_IPVP */
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
     case 0xB0:
-    case 0xC0:
-    case 0xD0:
+        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
+        break;
+    case 0x10A0: /* IPI_IPVP */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
         {
             int idx;
-            idx = (addr - 0xA0) >> 4;
-            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
+            idx = (addr - 0x10A0) >> 4;
+            retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
         }
         break;
-#endif
-    case 0xE0: /* SPVE */
+    case 0x10E0: /* SPVE */
         retval = opp->spve;
         break;
-    case 0xF0: /* TIFR */
+    case 0x10F0: /* TIFR */
         retval = opp->tifr;
         break;
     default:
@@ -710,10 +728,10 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
         opp->timers[idx].tibc = val;
         break;
     case 0x20: /* TIVP */
-        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
         break;
     case 0x30: /* TIDE */
-        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
+        write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
         break;
     }
 }
@@ -740,10 +758,10 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
         retval = opp->timers[idx].tibc;
         break;
     case 0x20: /* TIPV */
-        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
         break;
     case 0x30: /* TIDE */
-        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
@@ -763,10 +781,10 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
     idx = addr >> 5;
     if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */
-        write_IRQreg(opp, idx, IRQ_IDE, val);
+        write_IRQreg_ide(opp, idx, val);
     } else {
         /* EXVP / IFEVP / IEEVP */
-        write_IRQreg(opp, idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(opp, idx, val);
     }
 }
 
@@ -784,38 +802,40 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr)
     idx = addr >> 5;
     if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */
-        retval = read_IRQreg(opp, idx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, idx);
     } else {
         /* EXVP / IFEVP / IEEVP */
-        retval = read_IRQreg(opp, idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, idx);
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
 
     return retval;
 }
 
-static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)
+static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
+                                       uint32_t val, int idx)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
-    int idx, s_IRQ, n_IRQ;
+    int s_IRQ, n_IRQ;
 
-    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
+            addr, val);
     if (addr & 0xF)
         return;
-    addr &= 0x1FFF0;
-    idx = addr / 0x1000;
     dst = &opp->dst[idx];
     addr &= 0xFF0;
     switch (addr) {
 #if MAX_IPI > 0
-    case 0x40: /* PIPD */
+    case 0x40: /* IPIDR */
     case 0x50:
     case 0x60:
     case 0x70:
         idx = (addr - 0x40) >> 4;
-        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
+        /* we use IDE as mask which CPUs to deliver the IPI to still. */
+        write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
+                         opp->src[opp->irq_ipi0 + idx].ide | val);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
         break;
@@ -852,20 +872,24 @@ static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t v
     }
 }
 
-static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
+static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
+                                          int idx)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
     uint32_t retval;
-    int idx, n_IRQ;
+    int n_IRQ;
 
-    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
         return retval;
-    addr &= 0x1FFF0;
-    idx = addr / 0x1000;
     dst = &opp->dst[idx];
     addr &= 0xFF0;
     switch (addr) {
@@ -905,18 +929,22 @@ static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
                 src->pending = 0;
             }
+
+            if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
+                src->ide &= ~(1 << idx);
+                if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
+                    /* trigger on CPUs that didn't know about it yet */
+                    openpic_set_irq(opp, n_IRQ, 1);
+                    openpic_set_irq(opp, n_IRQ, 0);
+                    /* if all CPUs knew about it, set active bit again */
+                    set_bit(&src->ipvp, IPVP_ACTIVITY);
+                }
+            }
         }
         break;
     case 0xB0: /* PEOI */
         retval = 0;
         break;
-#if MAX_IPI > 0
-    case 0x40: /* IDE */
-    case 0x50:
-        idx = (addr - 0x40) >> 4;
-        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
-        break;
-#endif
     default:
         break;
     }
@@ -925,6 +953,11 @@ static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
     return retval;
 }
 
+static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr)
+{
+    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
+}
+
 static void openpic_buggy_write (void *opaque,
                                  target_phys_addr_t addr, uint32_t val)
 {
@@ -984,47 +1017,34 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const openpic_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_writel,
-};
+static uint64_t openpic_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    openpic_t *opp = opaque;
 
-static CPUReadMemoryFunc * const openpic_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_readl,
-};
+    switch (size) {
+    case 4: return openpic_readl(opp, addr);
+    default: return openpic_buggy_read(opp, addr);
+    }
+}
 
-static void openpic_map(PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
+static void openpic_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t data, unsigned size)
 {
-    openpic_t *opp;
+    openpic_t *opp = opaque;
 
-    DPRINTF("Map OpenPIC\n");
-    opp = (openpic_t *)pci_dev;
-    /* Global registers */
-    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
-            addr + 0x1000, addr + 0x1000 + 0x100);
-    /* Timer registers */
-    DPRINTF("Register OPENPIC timer %08x => %08x\n",
-            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
-    /* Interrupt source registers */
-    DPRINTF("Register OPENPIC src   %08x => %08x\n",
-            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
-    /* Per CPU registers */
-    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
-            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
-    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
-#if 0 // Don't implement ISU for now
-    opp_io_memory = cpu_register_io_memory(openpic_src_read,
-                                           openpic_src_write, NULL
-                                           DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
-                                 opp_io_memory);
-#endif
+    switch (size) {
+    case 4: return openpic_writel(opp, addr, data);
+    default: return openpic_buggy_write(opp, addr, data);
+    }
 }
 
+static const MemoryRegionOps openpic_ops = {
+    .read = openpic_read,
+    .write = openpic_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 {
     unsigned int i;
@@ -1161,7 +1181,7 @@ static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
     qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 }
 
-qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out)
 {
     openpic_t *opp;
@@ -1180,14 +1200,22 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
         pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
         pci_conf[0x3d] = 0x00; // no interrupt pin
 
+        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
+#if 0 // Don't implement ISU for now
+        opp_io_memory = cpu_register_io_memory(openpic_src_read,
+                                               openpic_src_write, NULL
+                                               DEVICE_NATIVE_ENDIAN);
+        cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
+                                     opp_io_memory);
+#endif
+
         /* Register I/O spaces */
-        pci_register_bar(&opp->pci_dev, 0, 0x40000,
-                               PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
+        pci_register_bar(&opp->pci_dev, 0,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
     } else {
-        opp = qemu_mallocz(sizeof(openpic_t));
+        opp = g_malloc0(sizeof(openpic_t));
+        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
     }
-    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
-                                            DEVICE_LITTLE_ENDIAN);
 
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
@@ -1223,8 +1251,8 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
     opp->irq_raise = openpic_irq_raise;
     opp->reset = openpic_reset;
 
-    if (pmem_index)
-        *pmem_index = opp->mem_index;
+    if (pmem)
+        *pmem = &opp->mem;
 
     return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
 }
@@ -1248,7 +1276,7 @@ static void mpic_reset (void *opaque)
 
     mpp->glbc = 0x80000000;
     /* Initialise controller registers */
-    mpp->frep = 0x004f0002;
+    mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
     mpp->veni = VENI;
     mpp->pint = 0x00000000;
     mpp->spve = 0x0000FFFF;
@@ -1257,6 +1285,10 @@ static void mpic_reset (void *opaque)
         mpp->src[i].ipvp = 0x80800000;
         mpp->src[i].ide  = 0x00000001;
     }
+    /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
+    for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
+        mpp->src[i].ide = 0;
+    }
     /* Initialise IRQ destinations */
     for (i = 0; i < MAX_CPU; i++) {
         mpp->dst[i].pctp      = 0x0000000F;
@@ -1297,13 +1329,13 @@ static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t va
         mpp->timers[idx].tibc = val;
         break;
     case 0x20: /* GTIVPR */
-        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
         break;
     case 0x30: /* GTIDR & TFRR */
         if ((addr & 0xF0) == 0xF0)
             mpp->dst[cpu].tfrr = val;
         else
-            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
         break;
     }
 }
@@ -1329,13 +1361,13 @@ static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
         retval = mpp->timers[idx].tibc;
         break;
     case 0x20: /* TIPV */
-        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
         break;
     case 0x30: /* TIDR */
         if ((addr &0xF0) == 0XF0)
             retval = mpp->dst[cpu].tfrr;
         else
-            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
@@ -1358,10 +1390,10 @@ static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1382,10 +1414,10 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1408,10 +1440,10 @@ static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1432,10 +1464,10 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1458,10 +1490,10 @@ static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1482,10 +1514,10 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1508,10 +1540,10 @@ static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1531,10 +1563,10 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1542,125 +1574,136 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const mpic_glb_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_gbl_write,
-};
-
-static CPUReadMemoryFunc * const mpic_glb_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_gbl_read,
-};
-
-static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_timer_write,
-};
-
-static CPUReadMemoryFunc * const mpic_tmr_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_timer_read,
-};
-
-static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_cpu_write,
-};
-
-static CPUReadMemoryFunc * const mpic_cpu_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_cpu_read,
+static const MemoryRegionOps mpic_glb_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   openpic_gbl_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   openpic_gbl_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_ext_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_ext_write,
+static const MemoryRegionOps mpic_tmr_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_timer_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_timer_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_ext_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_ext_read,
+static const MemoryRegionOps mpic_cpu_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   openpic_cpu_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   openpic_cpu_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_int_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_int_write,
+static const MemoryRegionOps mpic_ext_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_ext_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_ext_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_int_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_int_read,
+static const MemoryRegionOps mpic_int_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_int_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_int_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_msg_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_msg_write,
+static const MemoryRegionOps mpic_msg_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_msg_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_msg_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_msg_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_msg_read,
-};
-static CPUWriteMemoryFunc * const mpic_msi_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_msi_write,
-};
-
-static CPUReadMemoryFunc * const mpic_msi_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_msi_read,
+static const MemoryRegionOps mpic_msi_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_msi_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_msi_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
-                        qemu_irq **irqs, qemu_irq irq_out)
+qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
+                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
 {
-    openpic_t *mpp;
-    int i;
+    openpic_t    *mpp;
+    int           i;
     struct {
-        CPUReadMemoryFunc * const *read;
-        CPUWriteMemoryFunc * const *write;
-        target_phys_addr_t start_addr;
-        ram_addr_t size;
+        const char             *name;
+        MemoryRegionOps const  *ops;
+        target_phys_addr_t      start_addr;
+        ram_addr_t              size;
     } const list[] = {
-        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
-        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
-        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
-        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
-        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
-        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
-        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
+        {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
+        {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
+        {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
+        {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
+        {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
+        {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
+        {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
     };
 
-    /* XXX: for now, only one CPU is supported */
-    if (nb_cpus != 1)
-        return NULL;
+    mpp = g_malloc0(sizeof(openpic_t));
 
-    mpp = qemu_mallocz(sizeof(openpic_t));
+    memory_region_init(&mpp->mem, "mpic", 0x40000);
+    memory_region_add_subregion(address_space, base, &mpp->mem);
 
     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
-        int mem_index;
 
-        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
-                                           DEVICE_BIG_ENDIAN);
-        if (mem_index < 0) {
-            goto free;
-        }
-        cpu_register_physical_memory(base + list[i].start_addr,
-                                     list[i].size, mem_index);
+        memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
+                              list[i].name, list[i].size);
+
+        memory_region_add_subregion(&mpp->mem, list[i].start_addr,
+                                    &mpp->sub_io_mem[i]);
     }
 
     mpp->nb_cpus = nb_cpus;
@@ -1679,8 +1722,4 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
     qemu_register_reset(mpic_reset, mpp);
 
     return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
-
-free:
-    qemu_free(mpp);
-    return NULL;
 }
index 0957c1ff009ee4f36e71cc672040874524d76826..715f0847bf435e5812859d3a18a37f16ead36d83 100644 (file)
@@ -11,8 +11,8 @@ enum {
     OPENPIC_OUTPUT_NB,
 };
 
-qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
-                        qemu_irq **irqs, qemu_irq irq_out);
-qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
+qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out);
+qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
+                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
 #endif /* __OPENPIC_H__ */
index f22d7775eebff9af40d5646c7335a27c955fba63..094bfde369d5ab612adbfa297c72b7f70a55a3ed 100644 (file)
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -25,6 +25,7 @@
 #include "arm-misc.h"
 #include "devices.h"
 #include "loader.h"
+#include "exec-memory.h"
 
 static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
 {
@@ -53,16 +54,12 @@ static void static_write(void *opaque, target_phys_addr_t offset,
 #endif
 }
 
-static CPUReadMemoryFunc * const static_readfn[] = {
-    static_readb,
-    static_readh,
-    static_readw,
-};
-
-static CPUWriteMemoryFunc * const static_writefn[] = {
-    static_write,
-    static_write,
-    static_write,
+static const MemoryRegionOps static_ops = {
+    .old_mmio = {
+        .read = { static_readb, static_readh, static_readw, },
+        .write = { static_write, static_write, static_write, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Palm Tunsgten|E support */
@@ -94,7 +91,7 @@ static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
 {
     uWireSlave *tsc;
 
-    tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]);
+    tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
 
     omap_uwire_attach(cpu->microwire, tsc, 0);
     omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
@@ -163,24 +160,24 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
     qemu_irq *misc_gpio;
 
     omap_mmc_handlers(cpu->mmc,
-                    omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO],
+                    qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
                     qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
                             [PALMTE_MMC_SWITCH_GPIO]));
 
     misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
-    omap_gpio_out_set(cpu->gpio, PALMTE_MMC_POWER_GPIO,        misc_gpio[0]);
-    omap_gpio_out_set(cpu->gpio, PALMTE_SPEAKER_GPIO,  misc_gpio[1]);
-    omap_gpio_out_set(cpu->gpio, 11,                   misc_gpio[2]);
-    omap_gpio_out_set(cpu->gpio, 12,                   misc_gpio[3]);
-    omap_gpio_out_set(cpu->gpio, 13,                   misc_gpio[4]);
-    omap_mpuio_out_set(cpu->mpuio, 1,                  misc_gpio[5]);
-    omap_mpuio_out_set(cpu->mpuio, 3,                  misc_gpio[6]);
+    qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,    misc_gpio[0]);
+    qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,      misc_gpio[1]);
+    qdev_connect_gpio_out(cpu->gpio, 11,                       misc_gpio[2]);
+    qdev_connect_gpio_out(cpu->gpio, 12,                       misc_gpio[3]);
+    qdev_connect_gpio_out(cpu->gpio, 13,                       misc_gpio[4]);
+    omap_mpuio_out_set(cpu->mpuio, 1,                          misc_gpio[5]);
+    omap_mpuio_out_set(cpu->mpuio, 3,                          misc_gpio[6]);
 
     /* Reset some inputs to initial state.  */
-    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USBDETECT_GPIO]);
-    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USB_OR_DC_GPIO]);
-    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[4]);
-    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_HEADPHONES_GPIO]);
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
+    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
     qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
     qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
     qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
@@ -198,37 +195,39 @@ static void palmte_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     struct omap_mpu_state_s *cpu;
     int flash_size = 0x00800000;
     int sdram_size = palmte_binfo.ram_size;
-    int io;
     static uint32_t cs0val = 0xffffffff;
     static uint32_t cs1val = 0x0000e1a0;
     static uint32_t cs2val = 0x0000e1a0;
     static uint32_t cs3val = 0xe1a0e1a0;
     int rom_size, rom_loaded = 0;
     DisplayState *ds = get_displaystate();
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *cs = g_new(MemoryRegion, 4);
 
-    cpu = omap310_mpu_init(sdram_size, cpu_model);
+    cpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
 
     /* External Flash (EMIFS) */
-    cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
-                                 qemu_ram_alloc(NULL, "palmte.flash",
-                                                flash_size) | IO_MEM_ROM);
-
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
-                    OMAP_CS0_SIZE - flash_size, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
+    memory_region_init_ram(flash, NULL, "palmte.flash", flash_size);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
+
+    memory_region_init_io(&cs[0], &static_ops, &cs0val, "palmte-cs0",
+                          OMAP_CS0_SIZE - flash_size);
+    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
+                                &cs[0]);
+    memory_region_init_io(&cs[1], &static_ops, &cs1val, "palmte-cs1",
+                          OMAP_CS1_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
+    memory_region_init_io(&cs[2], &static_ops, &cs2val, "palmte-cs2",
+                          OMAP_CS2_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
+    memory_region_init_io(&cs[3], &static_ops, &cs3val, "palmte-cs3",
+                          OMAP_CS3_SIZE);
+    memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
 
     palmte_microwire_setup(cpu);
 
index ce311aa424658e337a4e8f2b04b8677a6b51cc34..8494d94f69e5cdc20b62274275aa5c559bc78370 100644 (file)
@@ -64,7 +64,7 @@
 
 #define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
 
-struct ParallelState {
+typedef struct ParallelState {
     uint8_t dataw;
     uint8_t datar;
     uint8_t status;
@@ -77,7 +77,7 @@ struct ParallelState {
     uint32_t last_read_offset; /* For debugging */
     /* Memory-mapped interface */
     int it_shift;
-};
+} ParallelState;
 
 typedef struct ISAParallelState {
     ISADevice dev;
@@ -120,7 +120,7 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
             if (val & PARA_CTR_STROBE) {
                 s->status &= ~PARA_STS_BUSY;
                 if ((s->control & PARA_CTR_STROBE) == 0)
-                    qemu_chr_write(s->chr, &s->dataw, 1);
+                    qemu_chr_fe_write(s->chr, &s->dataw, 1);
             } else {
                 if (s->control & PARA_CTR_INTEN) {
                     s->irq_pending = 1;
@@ -150,7 +150,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
         if (s->dataw == val)
             return;
         pdebug("wd%02x\n", val);
-        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
         s->dataw = val;
         break;
     case PARA_REG_STS:
@@ -170,11 +170,11 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             } else {
                 dir = 0;
             }
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
+            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
             parm &= ~PARA_CTR_DIR;
         }
 
-        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
         s->control = val;
         break;
     case PARA_REG_EPP_ADDR:
@@ -183,7 +183,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("wa%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("wa%02x t\n", val);
             }
@@ -197,7 +197,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("we%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("we%02x t\n", val);
             }
@@ -222,7 +222,7 @@ parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%04x s\n", val);
         return;
     }
-    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%04x t\n", val);
@@ -245,7 +245,7 @@ parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%08x s\n", val);
         return;
     }
-    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%08x t\n", val);
@@ -297,13 +297,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
     addr &= 7;
     switch(addr) {
     case PARA_REG_DATA:
-        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
         if (s->last_read_offset != addr || s->datar != ret)
             pdebug("rd%02x\n", ret);
         s->datar = ret;
         break;
     case PARA_REG_STS:
-        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
         ret &= ~PARA_STS_TMOUT;
         if (s->epp_timeout)
             ret |= PARA_STS_TMOUT;
@@ -315,7 +315,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
         /* s->control has some bits fixed to 1. It is zero only when
            it has not been yet written to.  */
         if (s->control == 0) {
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
             if (s->last_read_offset != addr)
                 pdebug("rc%02x\n", ret);
             s->control = ret;
@@ -332,7 +332,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
             pdebug("ra%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("ra%02x t\n", ret);
             }
@@ -346,7 +346,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
             pdebug("re%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("re%02x t\n", ret);
             }
@@ -374,7 +374,7 @@ parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
         pdebug("re%04x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le16_to_cpu(eppdata);
 
     if (err) {
@@ -401,7 +401,7 @@ parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
         pdebug("re%08x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le32_to_cpu(eppdata);
 
     if (err) {
@@ -448,6 +448,29 @@ static void parallel_reset(void *opaque)
 
 static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
 
+static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
+    { 0, 8, 1,
+      .read = parallel_ioport_read_hw,
+      .write = parallel_ioport_write_hw },
+    { 4, 1, 2,
+      .read = parallel_ioport_eppdata_read_hw2,
+      .write = parallel_ioport_eppdata_write_hw2 },
+    { 4, 1, 4,
+      .read = parallel_ioport_eppdata_read_hw4,
+      .write = parallel_ioport_eppdata_write_hw4 },
+    { 0x400, 8, 1,
+      .read = parallel_ioport_ecp_read,
+      .write = parallel_ioport_ecp_write },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
+    { 0, 8, 1,
+      .read = parallel_ioport_read_sw,
+      .write = parallel_ioport_write_sw },
+    PORTIO_END_OF_LIST(),
+};
+
 static int parallel_isa_initfn(ISADevice *dev)
 {
     static int index;
@@ -473,45 +496,19 @@ static int parallel_isa_initfn(ISADevice *dev)
     isa_init_irq(dev, &s->irq, isa->isairq);
     qemu_register_reset(parallel_reset, s);
 
-    if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+    if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
         s->hw_driver = 1;
         s->status = dummy;
     }
 
-    if (s->hw_driver) {
-        register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
-        register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
-        isa_init_ioport_range(dev, base, 8);
-
-        register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
-        register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
-        register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
-        register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
-        isa_init_ioport(dev, base+4);
-        register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
-        register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
-        isa_init_ioport_range(dev, base+0x400, 8);
-    }
-    else {
-        register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
-        register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
-        isa_init_ioport_range(dev, base, 8);
-    }
+    isa_register_portio_list(dev, base,
+                             (s->hw_driver
+                              ? &isa_parallel_portio_hw_list[0]
+                              : &isa_parallel_portio_sw_list[0]),
+                             s, "parallel");
     return 0;
 }
 
-ParallelState *parallel_init(int index, CharDriverState *chr)
-{
-    ISADevice *dev;
-
-    dev = isa_create("isa-parallel");
-    qdev_prop_set_uint32(&dev->qdev, "index", index);
-    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
-    if (qdev_init(&dev->qdev) < 0)
-        return NULL;
-    return &DO_UPCAST(ISAParallelState, dev, dev)->state;
-}
-
 /* Memory mapped interface */
 static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr)
 {
@@ -571,12 +568,13 @@ static CPUWriteMemoryFunc * const parallel_mm_write_sw[] = {
 };
 
 /* If fd is zero, it means that the parallel device uses the console */
-ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr)
+bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr)
 {
     ParallelState *s;
     int io_sw;
 
-    s = qemu_mallocz(sizeof(ParallelState));
+    s = g_malloc0(sizeof(ParallelState));
     s->irq = irq;
     s->chr = chr;
     s->it_shift = it_shift;
@@ -585,7 +583,7 @@ ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq
     io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw,
                                    s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 8 << it_shift, io_sw);
-    return s;
+    return true;
 }
 
 static ISADeviceInfo parallel_isa_info = {
diff --git a/hw/pc.c b/hw/pc.c
index 07b4c5168748e20f16cae07e3b592ea522345c88..0a7b5971240bc19c85c144dbae382757701c25cb 100644 (file)
--- a/hw/pc.c
+++ b/hw/pc.c
 #include "sysemu.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+#ifdef CONFIG_MARU
+#include "../tizen/src/hw/maru_overlay.h"
+#include "../tizen/src/hw/maru_brightness.h"
+#endif
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -76,26 +83,26 @@ struct e820_entry {
     uint64_t address;
     uint64_t length;
     uint32_t type;
-} __attribute((__packed__, __aligned__(4)));
+} QEMU_PACKED __attribute((__aligned__(4)));
 
 struct e820_table {
     uint32_t count;
     struct e820_entry entry[E820_NR_ENTRIES];
-} __attribute((__packed__, __aligned__(4)));
+} QEMU_PACKED __attribute((__aligned__(4)));
 
 static struct e820_table e820_table;
+struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
 
-void isa_irq_handler(void *opaque, int n, int level)
+void gsi_handler(void *opaque, int n, int level)
 {
-    IsaIrqState *isa = (IsaIrqState *)opaque;
+    GSIState *s = opaque;
 
-    DPRINTF("isa_irqs: %s irq %d\n", level? "raise" : "lower", n);
-    if (n < 16) {
-        qemu_set_irq(isa->i8259[n], level);
+    DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n);
+    if (n < ISA_NUM_IRQS) {
+        qemu_set_irq(s->i8259_irq[n], level);
     }
-    if (isa->ioapic)
-        qemu_set_irq(isa->ioapic[n], level);
-};
+    qemu_set_irq(s->ioapic_irq[n], level);
+}
 
 static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 {
@@ -153,9 +160,6 @@ int cpu_get_pic_interrupt(CPUState *env)
 
     intno = apic_get_interrupt(env->apic_state);
     if (intno >= 0) {
-        /* set irq request if a PIC irq is still pending */
-        /* XXX: improve that */
-        pic_update_irq(isa_pic);
         return intno;
     }
     /* read the irq from the PIC */
@@ -191,23 +195,24 @@ static void pic_irq_request(void *opaque, int irq, int level)
 
 #define REG_EQUIPMENT_BYTE          0x14
 
-static int cmos_get_fd_drive_type(int fd0)
+static int cmos_get_fd_drive_type(FDriveType fd0)
 {
     int val;
 
     switch (fd0) {
-    case 0:
+    case FDRIVE_DRV_144:
         /* 1.44 Mb 3"5 drive */
         val = 4;
         break;
-    case 1:
+    case FDRIVE_DRV_288:
         /* 2.88 Mb 3"5 drive */
         val = 5;
         break;
-    case 2:
+    case FDRIVE_DRV_120:
         /* 1.2 Mb 5"5 drive */
         val = 2;
         break;
+    case FDRIVE_DRV_NONE:
     default:
         val = 0;
         break;
@@ -331,11 +336,12 @@ static void pc_cmos_init_late(void *opaque)
 
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *idebus0, BusState *idebus1,
-                  FDCtrl *floppy_controller, ISADevice *s)
+                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
+                  ISADevice *s)
 {
-    int val;
-    int fd0, fd1, nb;
+    int val, nb, nb_heads, max_track, last_sect, i;
+    FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
+    BlockDriverState *fd[MAX_FD];
     static pc_cmos_init_late_arg arg;
 
     /* various important CMOS locations needed by PC/Bochs bios */
@@ -377,19 +383,28 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
     }
 
     /* floppy type */
-
-    fd0 = fdctrl_get_drive_type(floppy_controller, 0);
-    fd1 = fdctrl_get_drive_type(floppy_controller, 1);
-
-    val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
+    if (floppy) {
+        fdc_get_bs(fd, floppy);
+        for (i = 0; i < 2; i++) {
+            if (fd[i] && bdrv_is_inserted(fd[i])) {
+                bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
+                                              &last_sect, FDRIVE_DRV_NONE,
+                                              &fd_type[i]);
+            }
+        }
+    }
+    val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
+        cmos_get_fd_drive_type(fd_type[1]);
     rtc_set_memory(s, 0x10, val);
 
     val = 0;
     nb = 0;
-    if (fd0 < 3)
+    if (fd_type[0] < FDRIVE_DRV_NONE) {
         nb++;
-    if (fd1 < 3)
+    }
+    if (fd_type[1] < FDRIVE_DRV_NONE) {
         nb++;
+    }
     switch (nb) {
     case 0:
         break;
@@ -414,6 +429,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
 /* port 92 stuff: could be split off */
 typedef struct Port92State {
     ISADevice dev;
+    MemoryRegion io;
     uint8_t outport;
     qemu_irq *a20_out;
 } Port92State;
@@ -465,13 +481,22 @@ static void port92_reset(DeviceState *d)
     s->outport &= ~1;
 }
 
+static const MemoryRegionPortio port92_portio[] = {
+    { 0, 1, 1, .read = port92_read, .write = port92_write },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps port92_ops = {
+    .old_portio = port92_portio
+};
+
 static int port92_initfn(ISADevice *dev)
 {
     Port92State *s = DO_UPCAST(Port92State, dev, dev);
 
-    register_ioport_read(0x92, 1, 1, port92_read, s);
-    register_ioport_write(0x92, 1, 1, port92_write, s);
-    isa_init_ioport(dev, 0x92);
+    memory_region_init_io(&s->io, &port92_ops, s, "port92", 1);
+    isa_register_ioport(dev, &s->io, 0x92);
+
     s->outport = 0;
     return 0;
 }
@@ -536,8 +561,7 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
         /* LGPL'ed VGA BIOS messages */
     case 0x501:
     case 0x502:
-        fprintf(stderr, "VGA BIOS panic, line %d\n", val);
-        exit(1);
+        exit((val << 1) | 1);
     case 0x500:
     case 0x503:
 #ifdef DEBUG_BIOS
@@ -578,6 +602,7 @@ static void *bochs_bios_init(void)
     register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
     register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
 
+    register_ioport_write(0x501, 1, 1, bochs_bios_write, NULL);
     register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
     register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
     register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
@@ -604,7 +629,7 @@ static void *bochs_bios_init(void)
      * of nodes, one word for each VCPU->node and one word for each node to
      * hold the amount of memory.
      */
-    numa_fw_cfg = qemu_mallocz((1 + smp_cpus + nb_numa_nodes) * 8);
+    numa_fw_cfg = g_malloc0((1 + smp_cpus + nb_numa_nodes) * 8);
     numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
     for (i = 0; i < smp_cpus; i++) {
         for (j = 0; j < nb_numa_nodes; j++) {
@@ -775,7 +800,7 @@ static void load_linux(void *fw_cfg,
 
         initrd_addr = (initrd_max-initrd_size) & ~4095;
 
-        initrd_data = qemu_malloc(initrd_size);
+        initrd_data = g_malloc(initrd_size);
         load_image(initrd_filename, initrd_data);
 
         fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
@@ -793,8 +818,8 @@ static void load_linux(void *fw_cfg,
     setup_size = (setup_size+1)*512;
     kernel_size -= setup_size;
 
-    setup  = qemu_malloc(setup_size);
-    kernel = qemu_malloc(kernel_size);
+    setup  = g_malloc(setup_size);
+    kernel = g_malloc(kernel_size);
     fseek(f, 0, SEEK_SET);
     if (fread(setup, 1, setup_size, f) != setup_size) {
         fprintf(stderr, "fread() failed\n");
@@ -919,7 +944,6 @@ static CPUState *pc_new_cpu(const char *cpu_model)
         exit(1);
     }
     if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
-        env->cpuid_apic_id = env->cpu_index;
         env->apic_state = apic_init(env, env->cpuid_apic_id);
     }
     qemu_register_reset(pc_cpu_reset, env);
@@ -945,49 +969,43 @@ void pc_cpus_init(const char *cpu_model)
     }
 }
 
-void pc_memory_init(ram_addr_t ram_size,
+void pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_filename,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
-                    ram_addr_t *below_4g_mem_size_p,
-                    ram_addr_t *above_4g_mem_size_p)
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size,
+                    MemoryRegion *rom_memory,
+                    MemoryRegion **ram_memory)
 {
     char *filename;
     int ret, linux_boot, i;
-    ram_addr_t ram_addr, bios_offset, option_rom_offset;
-    ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+    MemoryRegion *ram, *bios, *isa_bios, *option_rom_mr;
+    MemoryRegion *ram_below_4g, *ram_above_4g;
     int bios_size, isa_bios_size;
     void *fw_cfg;
 
-    if (ram_size >= 0xe0000000 ) {
-        above_4g_mem_size = ram_size - 0xe0000000;
-        below_4g_mem_size = 0xe0000000;
-    } else {
-        below_4g_mem_size = ram_size;
-    }
-    *above_4g_mem_size_p = above_4g_mem_size;
-    *below_4g_mem_size_p = below_4g_mem_size;
-
-#if TARGET_PHYS_ADDR_BITS == 32
-    if (above_4g_mem_size > 0) {
-        hw_error("To much RAM for 32-bit physical address");
-    }
-#endif
     linux_boot = (kernel_filename != NULL);
 
-    /* allocate RAM */
-    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
-                              below_4g_mem_size + above_4g_mem_size);
-    cpu_register_physical_memory(0, 0xa0000, ram_addr);
-    cpu_register_physical_memory(0x100000,
-                 below_4g_mem_size - 0x100000,
-                 ram_addr + 0x100000);
-#if TARGET_PHYS_ADDR_BITS > 32
+    /* Allocate RAM.  We allocate it as a single memory region and use
+     * aliases to address portions of it, mostly for backwards compatiblity
+     * with older qemus that used qemu_ram_alloc().
+     */
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "pc.ram",
+                           below_4g_mem_size + above_4g_mem_size);
+    *ram_memory = ram;
+    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
+    memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
+                             0, below_4g_mem_size);
+    memory_region_add_subregion(system_memory, 0, ram_below_4g);
     if (above_4g_mem_size > 0) {
-        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
-                                     ram_addr + below_4g_mem_size);
+        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
+        memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
+                                 below_4g_mem_size, above_4g_mem_size);
+        memory_region_add_subregion(system_memory, 0x100000000ULL,
+                                    ram_above_4g);
     }
-#endif
 
     /* BIOS load */
     if (bios_name == NULL)
@@ -1002,7 +1020,9 @@ void pc_memory_init(ram_addr_t ram_size,
         (bios_size % 65536) != 0) {
         goto bios_error;
     }
-    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+    bios = g_malloc(sizeof(*bios));
+    memory_region_init_ram(bios, NULL, "pc.bios", bios_size);
+    memory_region_set_readonly(bios, true);
     ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
     if (ret != 0) {
     bios_error:
@@ -1010,22 +1030,32 @@ void pc_memory_init(ram_addr_t ram_size,
         exit(1);
     }
     if (filename) {
-        qemu_free(filename);
+        g_free(filename);
     }
     /* map the last 128KB of the BIOS in ISA space */
     isa_bios_size = bios_size;
     if (isa_bios_size > (128 * 1024))
         isa_bios_size = 128 * 1024;
-    cpu_register_physical_memory(0x100000 - isa_bios_size,
-                                 isa_bios_size,
-                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
-
-    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
-    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
+    isa_bios = g_malloc(sizeof(*isa_bios));
+    memory_region_init_alias(isa_bios, "isa-bios", bios,
+                             bios_size - isa_bios_size, isa_bios_size);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        0x100000 - isa_bios_size,
+                                        isa_bios,
+                                        1);
+    memory_region_set_readonly(isa_bios, true);
+
+    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
+    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        PC_ROM_MIN_VGA,
+                                        option_rom_mr,
+                                        1);
 
     /* map all the bios at the top of memory */
-    cpu_register_physical_memory((uint32_t)(-bios_size),
-                                 bios_size, bios_offset | IO_MEM_ROM);
+    memory_region_add_subregion(rom_memory,
+                                (uint32_t)(-bios_size),
+                                bios);
 
     fw_cfg = bochs_bios_init();
     rom_set_fw(fw_cfg);
@@ -1050,13 +1080,18 @@ void pc_vga_init(PCIBus *pci_bus)
         if (pci_bus) {
             pci_cirrus_vga_init(pci_bus);
         } else {
-            isa_cirrus_vga_init();
+            isa_cirrus_vga_init(get_system_memory());
         }
     } else if (vmsvga_enabled) {
-        if (pci_bus)
-            pci_vmsvga_init(pci_bus);
-        else
+        if (pci_bus) {
+            if (!pci_vmsvga_init(pci_bus)) {
+                fprintf(stderr, "Warning: vmware_vga not available,"
+                        " using standard VGA instead\n");
+                pci_vga_init(pci_bus);
+            }
+        } else {
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+        }
 #ifdef CONFIG_SPICE
     } else if (qxl_enabled) {
         if (pci_bus)
@@ -1067,20 +1102,22 @@ void pc_vga_init(PCIBus *pci_bus)
     } else if (std_vga_enabled) {
         if (pci_bus) {
             pci_vga_init(pci_bus);
-            pci_overlay_init(pci_bus);
-            pci_brightness_init(pci_bus);
         } else {
             isa_vga_init();
         }
-    } else if (tizen_vga_enabled) {
+#ifdef CONFIG_MARU
+    } else if (maru_vga_enabled) {
         if (pci_bus) {
-            pci_tizen_vga_init(pci_bus);
-            pci_overlay_init(pci_bus);
-            pci_brightness_init(pci_bus);
+            pci_maru_vga_init(pci_bus);
+            pci_maru_overlay_init(pci_bus);
+            pci_maru_brightness_init(pci_bus);
         } else {
             isa_vga_init();
         }
     }
+#else
+    }
+#endif
 }
 
 static void cpu_request_exit(void *opaque, int irq, int level)
@@ -1092,16 +1129,16 @@ static void cpu_request_exit(void *opaque, int irq, int level)
     }
 }
 
-void pc_basic_device_init(qemu_irq *isa_irq,
-                          FDCtrl **floppy_controller,
-                          ISADevice **rtc_state)
+void pc_basic_device_init(qemu_irq *gsi,
+                          ISADevice **rtc_state,
+                          ISADevice **floppy,
+                          bool no_vmport)
 {
     int i;
     DriveInfo *fd[MAX_FD];
-    PITState *pit;
     qemu_irq rtc_irq = NULL;
     qemu_irq *a20_line;
-    ISADevice *i8042, *port92;
+    ISADevice *i8042, *port92, *vmmouse, *pit;
     qemu_irq *cpu_exit_irq;
 
     register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
@@ -1109,18 +1146,20 @@ void pc_basic_device_init(qemu_irq *isa_irq,
     register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
     if (!no_hpet) {
-        DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL);
+        DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
 
-        for (i = 0; i < 24; i++) {
-            sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
+        if (hpet) {
+            for (i = 0; i < GSI_NUM_PINS; i++) {
+                sysbus_connect_irq(sysbus_from_qdev(hpet), i, gsi[i]);
+            }
+            rtc_irq = qdev_get_gpio_in(hpet, 0);
         }
-        rtc_irq = qdev_get_gpio_in(hpet, 0);
     }
     *rtc_state = rtc_init(2000, rtc_irq);
 
     qemu_register_boot_set(pc_boot_set, *rtc_state);
 
-    pit = pit_init(0x40, isa_get_irq(0));
+    pit = pit_init(0x40, 0);
     pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
@@ -1138,7 +1177,16 @@ void pc_basic_device_init(qemu_irq *isa_irq,
     a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
     i8042 = isa_create_simple("i8042");
     i8042_setup_a20_line(i8042, &a20_line[0]);
-    vmmouse_init(i8042);
+    if (!no_vmport) {
+        vmport_init();
+        vmmouse = isa_try_create("vmmouse");
+    } else {
+        vmmouse = NULL;
+    }
+    if (vmmouse) {
+        qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
+        qdev_init_nofail(&vmmouse->qdev);
+    }
     port92 = isa_create_simple("port92");
     port92_init(port92, &a20_line[1]);
 
@@ -1148,7 +1196,7 @@ void pc_basic_device_init(qemu_irq *isa_irq,
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    *floppy_controller = fdctrl_init_isa(fd);
+    *floppy = fdctrl_init_isa(fd);
 }
 
 void pc_pci_device_init(PCIBus *pci_bus)
diff --git a/hw/pc.h b/hw/pc.h
old mode 100755 (executable)
new mode 100644 (file)
index 2358bce..b22ad39
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -2,9 +2,13 @@
 #define HW_PC_H
 
 #include "qemu-common.h"
+#include "memory.h"
 #include "ioport.h"
 #include "isa.h"
 #include "fdc.h"
+#include "net.h"
+#include "memory.h"
+#include "ioapic.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
 
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
                          CharDriverState *chr);
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             int be);
-SerialState *serial_isa_init(int index, CharDriverState *chr);
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            target_phys_addr_t base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian);
+static inline bool serial_isa_init(int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-serial");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
+
 void serial_set_frequency(SerialState *s, uint32_t frequency);
 
 /* parallel.c */
-
-typedef struct ParallelState ParallelState;
-ParallelState *parallel_init(int index, CharDriverState *chr);
-ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr);
+static inline bool parallel_init(int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-parallel");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
+
+bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr);
 
 /* i8259.c */
 
-typedef struct PicState2 PicState2;
-extern PicState2 *isa_pic;
-void pic_set_irq(int irq, int level);
-void pic_set_irq_new(void *opaque, int irq, int level);
+typedef struct PicState PicState;
+extern PicState *isa_pic;
 qemu_irq *i8259_init(qemu_irq parent_irq);
-int pic_read_irq(PicState2 *s);
-void pic_update_irq(PicState2 *s);
-uint32_t pic_intack_read(PicState2 *s);
+int pic_read_irq(PicState *s);
+int pic_get_output(PicState *s);
 void pic_info(Monitor *mon);
 void irq_info(Monitor *mon);
 
-/* ISA */
-#define IOAPIC_NUM_PINS 0x18
+/* Global System Interrupts */
+
+#define GSI_NUM_PINS IOAPIC_NUM_PINS
 
-typedef struct isa_irq_state {
-    qemu_irq *i8259;
-    qemu_irq ioapic[IOAPIC_NUM_PINS];
-} IsaIrqState;
+typedef struct GSIState {
+    qemu_irq i8259_irq[ISA_NUM_IRQS];
+    qemu_irq ioapic_irq[IOAPIC_NUM_PINS];
+} GSIState;
 
-void isa_irq_handler(void *opaque, int n, int level);
+void gsi_handler(void *opaque, int n, int level);
 
 /* i8254.c */
 
 #define PIT_FREQ 1193182
 
-typedef struct PITState PITState;
+static inline ISADevice *pit_init(int base, int irq)
+{
+    ISADevice *dev;
 
-PITState *pit_init(int base, qemu_irq irq);
-void pit_set_gate(PITState *pit, int channel, int val);
-int pit_get_gate(PITState *pit, int channel);
-int pit_get_initial_count(PITState *pit, int channel);
-int pit_get_mode(PITState *pit, int channel);
-int pit_get_out(PITState *pit, int channel, int64_t current_time);
+    dev = isa_create("isa-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void pit_set_gate(ISADevice *dev, int channel, int val);
+int pit_get_gate(ISADevice *dev, int channel);
+int pit_get_initial_count(ISADevice *dev, int channel);
+int pit_get_mode(ISADevice *dev, int channel);
+int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
 
 void hpet_pit_disable(void);
 void hpet_pit_enable(void);
 
 /* vmport.c */
-void vmport_init(void);
+static inline void vmport_init(void)
+{
+    isa_create_simple("vmport");
+}
 void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
-
-/* vmmouse.c */
-void *vmmouse_init(void *m);
+void vmmouse_get_data(uint32_t *data);
+void vmmouse_set_data(const uint32_t *data);
 
 /* pckbd.c */
 
 void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   target_phys_addr_t base, ram_addr_t size,
+                   MemoryRegion *region, ram_addr_t size,
                    target_phys_addr_t mask);
 void i8042_isa_mouse_fake_event(void *opaque);
 void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
@@ -88,22 +130,25 @@ void pc_cmos_set_s3_resume(void *opaque, int irq, int level);
 void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
 
 void pc_cpus_init(const char *cpu_model);
-void pc_memory_init(ram_addr_t ram_size,
+void pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_filename,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
-                    ram_addr_t *below_4g_mem_size_p,
-                    ram_addr_t *above_4g_mem_size_p);
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size,
+                    MemoryRegion *rom_memory,
+                    MemoryRegion **ram_memory);
 qemu_irq *pc_allocate_cpu_irq(void);
 void pc_vga_init(PCIBus *pci_bus);
-void pc_basic_device_init(qemu_irq *isa_irq,
-                          FDCtrl **floppy_controller,
-                          ISADevice **rtc_state);
+void pc_basic_device_init(qemu_irq *gsi,
+                          ISADevice **rtc_state,
+                          ISADevice **floppy,
+                          bool no_vmport);
 void pc_init_ne2k_isa(NICInfo *nd);
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *ide0, BusState *ide1,
-                  FDCtrl *floppy_controller, ISADevice *s);
+                  ISADevice *floppy, BusState *ide0, BusState *ide1,
+                  ISADevice *s);
 void pc_pci_device_init(PCIBus *pci_bus);
 
 typedef void (*cpu_set_smm_t)(int smm, void *arg);
@@ -128,15 +173,24 @@ void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 extern int no_hpet;
 
 /* pcspk.c */
-void pcspk_init(PITState *);
+void pcspk_init(ISADevice *pit);
 int pcspk_audio_init(qemu_irq *pic);
 
 /* piix_pci.c */
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
-void i440fx_init_memory_mappings(PCII440FXState *d);
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
+                    qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    ram_addr_t ram_size,
+                    target_phys_addr_t pci_hole_start,
+                    target_phys_addr_t pci_hole_size,
+                    target_phys_addr_t pci_hole64_start,
+                    target_phys_addr_t pci_hole64_size,
+                    MemoryRegion *pci_memory,
+                    MemoryRegion *ram_memory);
 
 /* piix4.c */
 extern PCIDevice *piix4_dev;
@@ -150,26 +204,49 @@ enum vga_retrace_method {
 
 extern enum vga_retrace_method vga_retrace_method;
 
-int isa_vga_init(void);
-int pci_vga_init(PCIBus *bus);
-int pci_tizen_vga_init(PCIBus *bus);
-int pci_overlay_init(PCIBus *bus);
-int pci_brightness_init(PCIBus *bus);
-int pci_get_brightness(void);
+static inline int isa_vga_init(void)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-vga");
+    if (!dev) {
+        fprintf(stderr, "Warning: isa-vga not available\n");
+        return 0;
+    }
+    qdev_init_nofail(&dev->qdev);
+    return 1;
+}
 
-/* codec_accel.c */
-int pci_codec_init(PCIBus *bus);
+int pci_vga_init(PCIBus *bus);
+#ifdef CONFIG_MARU
+int pci_maru_vga_init(PCIBus *bus);
+#endif
 
 int isa_vga_mm_init(target_phys_addr_t vram_base,
-                    target_phys_addr_t ctrl_base, int it_shift);
+                    target_phys_addr_t ctrl_base, int it_shift,
+                    MemoryRegion *address_space);
 
 /* cirrus_vga.c */
 void pci_cirrus_vga_init(PCIBus *bus);
-void isa_cirrus_vga_init(void);
+void isa_cirrus_vga_init(MemoryRegion *address_space);
 
 /* ne2000.c */
-
-void isa_ne2000_init(int base, int irq, NICInfo *nd);
+static inline bool isa_ne2000_init(int base, int irq, NICInfo *nd)
+{
+    ISADevice *dev;
+
+    qemu_check_nic_model(nd, "ne2k_isa");
+
+    dev = isa_try_create("ne2k_isa");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq",    irq);
+    qdev_set_nic_properties(&dev->qdev, nd);
+    qdev_init_nofail(&dev->qdev);
+    return true;
+}
 
 /* e820 types */
 #define E820_RAM        1
@@ -179,5 +256,5 @@ void isa_ne2000_init(int base, int irq, NICInfo *nd);
 #define E820_UNUSABLE   5
 
 int e820_add_entry(uint64_t, uint64_t, uint32_t);
-int svcamera_pci_init(PCIBus *bus);
+
 #endif
index ca0ed9e209b6b381647b2a0487d3d83d0ac46d06..05000e3cc1ce0419144fe63908d93dc268dbe244 100644 (file)
@@ -22,6 +22,8 @@
  * THE SOFTWARE.
  */
 
+#include <glib.h>
+
 #include "hw.h"
 #include "pc.h"
 #include "apic.h"
 #include "boards.h"
 #include "ide.h"
 #include "kvm.h"
+#include "kvmclock.h"
 #include "sysemu.h"
 #include "sysbus.h"
 #include "arch_init.h"
 #include "blockdev.h"
+#include "smbus.h"
+#include "xen.h"
+#include "memory.h"
+#include "exec-memory.h"
+#ifdef CONFIG_XEN
+#  include <xen/hvm/hvm_info_table.h>
+#endif
 
 #define MAX_IDE_BUS 2
 
@@ -43,7 +53,7 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
 static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
 static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
 
-static void ioapic_init(IsaIrqState *isa_irq_state)
+static void ioapic_init(GSIState *gsi_state)
 {
     DeviceState *dev;
     SysBusDevice *d;
@@ -55,18 +65,21 @@ static void ioapic_init(IsaIrqState *isa_irq_state)
     sysbus_mmio_map(d, 0, 0xfec00000);
 
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        isa_irq_state->ioapic[i] = qdev_get_gpio_in(dev, i);
+        gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
     }
 }
 
 /* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
+static void pc_init1(MemoryRegion *system_memory,
+                     MemoryRegion *system_io,
+                     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,
-                     int pci_enabled)
+                     int pci_enabled,
+                     int kvmclock_enabled)
 {
     int i;
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
@@ -74,48 +87,95 @@ static void pc_init1(ram_addr_t ram_size,
     PCII440FXState *i440fx_state;
     int piix3_devfn = -1;
     qemu_irq *cpu_irq;
-    qemu_irq *isa_irq;
+    qemu_irq *gsi;
     qemu_irq *i8259;
     qemu_irq *cmos_s3;
     qemu_irq *smi_irq;
-    IsaIrqState *isa_irq_state;
+    GSIState *gsi_state;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    FDCtrl *floppy_controller;
     BusState *idebus[MAX_IDE_BUS];
     ISADevice *rtc_state;
+    ISADevice *floppy;
+    MemoryRegion *ram_memory;
+    MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
 
     pc_cpus_init(cpu_model);
 
-    vmport_init();
+    if (kvmclock_enabled) {
+        kvmclock_create();
+    }
 
-    /* allocate ram and load rom/bios */
-    pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename,
-                   &below_4g_mem_size, &above_4g_mem_size);
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        above_4g_mem_size = 0;
+        below_4g_mem_size = ram_size;
+    }
 
-    cpu_irq = pc_allocate_cpu_irq();
-    i8259 = i8259_init(cpu_irq[0]);
-    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
-    isa_irq_state->i8259 = i8259;
     if (pci_enabled) {
-        ioapic_init(isa_irq_state);
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = system_memory;
     }
-    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        pc_memory_init(system_memory,
+                       kernel_filename, kernel_cmdline, initrd_filename,
+                       below_4g_mem_size, above_4g_mem_size,
+                       pci_enabled ? rom_memory : system_memory, &ram_memory);
+    }
+
+    gsi_state = g_malloc0(sizeof(*gsi_state));
+    gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
 
     if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, gsi,
+                              system_memory, system_io, ram_size,
+                              below_4g_mem_size,
+                              0x100000000ULL - below_4g_mem_size,
+                              0x100000000ULL + above_4g_mem_size,
+                              (sizeof(target_phys_addr_t) == 4
+                               ? 0
+                               : ((uint64_t)1 << 62)),
+                              pci_memory, ram_memory);
     } else {
         pci_bus = NULL;
         i440fx_state = NULL;
-        isa_bus_new(NULL);
+        isa_bus_new(NULL, system_io);
+        no_hpet = 1;
+    }
+    isa_bus_irqs(gsi);
+
+    if (!xen_enabled()) {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(cpu_irq[0]);
+    } else {
+        i8259 = xen_interrupt_controller_init();
+    }
+
+    for (i = 0; i < ISA_NUM_IRQS; i++) {
+        gsi_state->i8259_irq[i] = i8259[i];
+    }
+    if (pci_enabled) {
+        ioapic_init(gsi_state);
     }
-    isa_bus_irqs(isa_irq);
 
-    pc_register_ferr_irq(isa_get_irq(13));
+    pc_register_ferr_irq(gsi[13]);
 
     pc_vga_init(pci_enabled? pci_bus: NULL);
 
+    if (xen_enabled()) {
+        pci_create_simple(pci_bus, -1, "xen-platform");
+    }
+
     /* init basic PC hardware */
-    pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
+    pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled());
 
     for(i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
@@ -126,18 +186,14 @@ 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);
+        if (xen_enabled()) {
+            dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
+        } else {
+            dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+        }
         idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
         idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
     } else {
@@ -149,51 +205,34 @@ static void pc_init1(ram_addr_t ram_size,
         }
     }
 
-    audio_init(isa_irq, pci_enabled ? pci_bus : NULL);
+    audio_init(gsi, pci_enabled ? pci_bus : NULL);
 
     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
-                 idebus[0], idebus[1], floppy_controller, rtc_state);
+                 floppy, idebus[0], idebus[1], rtc_state);
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
     }
 
     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);
+        if (!xen_enabled()) {
+            cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+        } else {
+            cmos_s3 = qemu_allocate_irqs(xen_cmos_set_s3_resume, rtc_state, 1);
+        }
         smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
         /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                              isa_get_irq(9), *cmos_s3, *smi_irq,
+                              gsi[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);
-        }
-    }
-
-    if (i440fx_state) {
-        i440fx_init_memory_mappings(i440fx_state);
+        smbus_eeprom_init(smbus, 8, NULL, 0);
     }
 
     if (pci_enabled) {
         pc_pci_device_init(pci_bus);
     }
-
-    if (pci_enabled) {
-        svcamera_pci_init(pci_bus);
-    }
-
-#ifdef CONFIG_FFMPEG
-       if (pci_enabled) {
-               pci_codec_init(pci_bus);        
-       }
-#endif
 }
 
 static void pc_init_pci(ram_addr_t ram_size,
@@ -203,9 +242,25 @@ static void pc_init_pci(ram_addr_t ram_size,
                         const char *initrd_filename,
                         const char *cpu_model)
 {
-    pc_init1(ram_size, boot_device,
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
              kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 1);
+             initrd_filename, cpu_model, 1, 1);
+}
+
+static void pc_init_pci_no_kvmclock(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)
+{
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 0);
 }
 
 static void pc_init_isa(ram_addr_t ram_size,
@@ -217,13 +272,33 @@ static void pc_init_isa(ram_addr_t ram_size,
 {
     if (cpu_model == NULL)
         cpu_model = "486";
-    pc_init1(ram_size, boot_device,
+    pc_init1(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
              kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 0);
+             initrd_filename, cpu_model, 0, 1);
 }
 
-static QEMUMachine pc_machine = {
-    .name = "pc-0.14",
+#ifdef CONFIG_XEN
+static void pc_xen_hvm_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)
+{
+    if (xen_hvm_init() != 0) {
+        hw_error("xen hardware virtual machine initialisation failed");
+    }
+    pc_init_pci_no_kvmclock(ram_size, boot_device,
+                            kernel_filename, kernel_cmdline,
+                            initrd_filename, cpu_model);
+    xen_vcpu_init();
+}
+#endif
+
+static QEMUMachine pc_machine_v1_0 = {
+    .name = "pc-1.0",
     .alias = "pc",
     .desc = "Standard PC",
     .init = pc_init_pci,
@@ -231,10 +306,53 @@ static QEMUMachine pc_machine = {
     .is_default = 1,
 };
 
+static QEMUMachine pc_machine_v0_15 = {
+    .name = "pc-0.15",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .is_default = 1,
+};
+
+static QEMUMachine pc_machine_v0_14 = {
+    .name = "pc-0.14",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "qxl",
+            .property = "revision",
+            .value    = stringify(2),
+        },{
+            .driver   = "qxl-vga",
+            .property = "revision",
+            .value    = stringify(2),
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-balloon-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    },
+};
+
 static QEMUMachine pc_machine_v0_13 = {
     .name = "pc-0.13",
     .desc = "Standard PC",
-    .init = pc_init_pci,
+    .init = pc_init_pci_no_kvmclock,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
         {
@@ -253,6 +371,26 @@ static QEMUMachine pc_machine_v0_13 = {
             .driver   = "PCI",
             .property = "command_serr_enable",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-balloon-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "AC97",
+            .property = "use_broken_id",
+            .value    = stringify(1),
         },
         { /* end of list */ }
     },
@@ -261,7 +399,7 @@ static QEMUMachine pc_machine_v0_13 = {
 static QEMUMachine pc_machine_v0_12 = {
     .name = "pc-0.12",
     .desc = "Standard PC",
-    .init = pc_init_pci,
+    .init = pc_init_pci_no_kvmclock,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
         {
@@ -284,6 +422,26 @@ static QEMUMachine pc_machine_v0_12 = {
             .driver   = "PCI",
             .property = "command_serr_enable",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-balloon-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "AC97",
+            .property = "use_broken_id",
+            .value    = stringify(1),
         },
         { /* end of list */ }
     }
@@ -292,7 +450,7 @@ static QEMUMachine pc_machine_v0_12 = {
 static QEMUMachine pc_machine_v0_11 = {
     .name = "pc-0.11",
     .desc = "Standard PC, qemu 0.11",
-    .init = pc_init_pci,
+    .init = pc_init_pci_no_kvmclock,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
         {
@@ -323,6 +481,26 @@ static QEMUMachine pc_machine_v0_11 = {
             .driver   = "PCI",
             .property = "command_serr_enable",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-balloon-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "AC97",
+            .property = "use_broken_id",
+            .value    = stringify(1),
         },
         { /* end of list */ }
     }
@@ -331,7 +509,7 @@ static QEMUMachine pc_machine_v0_11 = {
 static QEMUMachine pc_machine_v0_10 = {
     .name = "pc-0.10",
     .desc = "Standard PC, qemu 0.10",
-    .init = pc_init_pci,
+    .init = pc_init_pci_no_kvmclock,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
         {
@@ -374,6 +552,26 @@ static QEMUMachine pc_machine_v0_10 = {
             .driver   = "PCI",
             .property = "command_serr_enable",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-balloon-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "AC97",
+            .property = "use_broken_id",
+            .value    = stringify(1),
         },
         { /* end of list */ }
     },
@@ -386,14 +584,29 @@ static QEMUMachine isapc_machine = {
     .max_cpus = 1,
 };
 
+#ifdef CONFIG_XEN
+static QEMUMachine xenfv_machine = {
+    .name = "xenfv",
+    .desc = "Xen Fully-virtualized PC",
+    .init = pc_xen_hvm_init,
+    .max_cpus = HVM_MAX_VCPUS,
+    .default_machine_opts = "accel=xen",
+};
+#endif
+
 static void pc_machine_init(void)
 {
-    qemu_register_machine(&pc_machine);
+    qemu_register_machine(&pc_machine_v1_0);
+    qemu_register_machine(&pc_machine_v0_15);
+    qemu_register_machine(&pc_machine_v0_14);
     qemu_register_machine(&pc_machine_v0_13);
     qemu_register_machine(&pc_machine_v0_12);
     qemu_register_machine(&pc_machine_v0_11);
     qemu_register_machine(&pc_machine_v0_10);
     qemu_register_machine(&isapc_machine);
+#ifdef CONFIG_XEN
+    qemu_register_machine(&xenfv_machine);
+#endif
 }
 
 machine_init(pc_machine_init);
index 478fe9b836dbda4cf957033bce55de25af388a05..12f61fea6e2398834b843df97c152faf82e44472 100644 (file)
@@ -91,7 +91,8 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
      */
     dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
     dinfo->bus = scsibus->busnr;
-    scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false);
+    scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
+                                        false, -1);
     if (!scsidev) {
         return -1;
     }
@@ -127,7 +128,8 @@ void drive_hot_add(Monitor *mon, const QDict *qdict)
         if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
             goto err;
         }
-        dev = pci_find_device(pci_find_root_bus(dom), pci_bus, slot, 0);
+        dev = pci_find_device(pci_find_root_bus(dom), pci_bus,
+                              PCI_DEVFN(slot, 0));
         if (!dev) {
             monitor_printf(mon, "no pci device with address %s\n", pci_addr);
             goto err;
@@ -277,7 +279,7 @@ static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
         return -1;
     }
 
-    d = pci_find_device(pci_find_root_bus(dom), bus, slot, 0);
+    d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0));
     if (!d) {
         monitor_printf(mon, "slot %d empty\n", slot);
         return -1;
index c5a0aa89794fe7886650677383865d9e22466b09..636171c16f6220f9584f474b993752509451eddc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * PCI stubs for plathome that doesn't support pci bus.
+ * PCI stubs for platforms that don't support pci bus.
  *
  * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
  *                    VA Linux Systems Japan K.K.
 #include "sysemu.h"
 #include "monitor.h"
 #include "pci.h"
+#include "qmp-commands.h"
 
-static void pci_error_message(Monitor *mon)
+PciInfoList *qmp_query_pci(Error **errp)
 {
-    monitor_printf(mon, "PCI devices not supported\n");
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
 }
 
-void do_pci_info(Monitor *mon, QObject **ret_data)
-{
-    pci_error_message(mon);
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
+static void pci_error_message(Monitor *mon)
 {
-    pci_error_message(mon);
+    monitor_printf(mon, "PCI devices not supported\n");
 }
 
 int do_pcie_aer_inejct_error(Monitor *mon,
index d5bbba975b0a04132dd10b98bf2c4943f5c749ad..399227fc3d6e2028492f4702b13f88179e48b2d0 100644 (file)
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -29,8 +29,8 @@
 #include "net.h"
 #include "sysemu.h"
 #include "loader.h"
-#include "qemu-objects.h"
 #include "range.h"
+#include "qmp-commands.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -126,6 +126,13 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
     bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
 }
 
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
+{
+    assert(irq_num >= 0);
+    assert(irq_num < bus->nirq);
+    return !!bus->irq_count[irq_num];
+}
+
 /* Update interrupt status bit in config space on interrupt
  * state change. */
 static void pci_update_irq_status(PCIDevice *dev)
@@ -161,7 +168,7 @@ void pci_device_reset(PCIDevice *dev)
     dev->irq_state = 0;
     pci_update_irq_status(dev);
     pci_device_deassert_intx(dev);
-    /* Clear all writeable bits */
+    /* Clear all writable bits */
     pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
                                  pci_get_word(dev->wmask + PCI_COMMAND) |
                                  pci_get_word(dev->w1cmask + PCI_COMMAND));
@@ -216,7 +223,7 @@ static int pcibus_reset(BusState *qbus)
 static void pci_host_bus_register(int domain, PCIBus *bus)
 {
     struct PCIHostBus *host;
-    host = qemu_mallocz(sizeof(*host));
+    host = g_malloc0(sizeof(*host));
     host->domain = domain;
     host->bus = bus;
     QLIST_INSERT_HEAD(&host_buses, host, next);
@@ -256,11 +263,16 @@ int pci_find_domain(const PCIBus *bus)
 }
 
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
-                         const char *name, int devfn_min)
+                         const char *name,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min)
 {
     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
     assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;
+    bus->address_space_mem = address_space_mem;
+    bus->address_space_io = address_space_io;
 
     /* host bridge */
     QLIST_INIT(&bus->child);
@@ -269,13 +281,17 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
     vmstate_register(NULL, -1, &vmstate_pcibus, bus);
 }
 
-PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min)
+PCIBus *pci_bus_new(DeviceState *parent, const char *name,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    uint8_t devfn_min)
 {
     PCIBus *bus;
 
-    bus = qemu_mallocz(sizeof(*bus));
+    bus = g_malloc0(sizeof(*bus));
     bus->qbus.qdev_allocated = 1;
-    pci_bus_new_inplace(bus, parent, name, devfn_min);
+    pci_bus_new_inplace(bus, parent, name, address_space_mem,
+                        address_space_io, devfn_min);
     return bus;
 }
 
@@ -286,7 +302,7 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
     bus->map_irq = map_irq;
     bus->irq_opaque = irq_opaque;
     bus->nirq = nirq;
-    bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
+    bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
 }
 
 void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
@@ -296,18 +312,17 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
     bus->hotplug_qdev = qdev;
 }
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
-{
-    bus->mem_base = base;
-}
-
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *irq_opaque, int devfn_min, int nirq)
+                         void *irq_opaque,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min, int nirq)
 {
     PCIBus *bus;
 
-    bus = pci_bus_new(parent, name, devfn_min);
+    bus = pci_bus_new(parent, name, address_space_mem,
+                      address_space_io, devfn_min);
     pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
     return bus;
 }
@@ -326,13 +341,13 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
     int i;
 
     assert(size == pci_config_size(s));
-    config = qemu_malloc(size);
+    config = g_malloc(size);
 
     qemu_get_buffer(f, config, size);
     for (i = 0; i < size; ++i) {
         if ((config[i] ^ s->config[i]) &
             s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
-            qemu_free(config);
+            g_free(config);
             return -EINVAL;
         }
     }
@@ -340,7 +355,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 
     pci_update_mappings(s);
 
-    qemu_free(config);
+    g_free(config);
     return 0;
 }
 
@@ -558,7 +573,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
         return NULL;
     }
 
-    *devfnp = slot << 3;
+    *devfnp = PCI_DEVFN(slot, 0);
     return pci_find_bus(pci_find_root_bus(dom), bus);
 }
 
@@ -700,29 +715,30 @@ static void pci_config_alloc(PCIDevice *pci_dev)
 {
     int config_size = pci_config_size(pci_dev);
 
-    pci_dev->config = qemu_mallocz(config_size);
-    pci_dev->cmask = qemu_mallocz(config_size);
-    pci_dev->wmask = qemu_mallocz(config_size);
-    pci_dev->w1cmask = qemu_mallocz(config_size);
-    pci_dev->used = qemu_mallocz(config_size);
+    pci_dev->config = g_malloc0(config_size);
+    pci_dev->cmask = g_malloc0(config_size);
+    pci_dev->wmask = g_malloc0(config_size);
+    pci_dev->w1cmask = g_malloc0(config_size);
+    pci_dev->used = g_malloc0(config_size);
 }
 
 static void pci_config_free(PCIDevice *pci_dev)
 {
-    qemu_free(pci_dev->config);
-    qemu_free(pci_dev->cmask);
-    qemu_free(pci_dev->wmask);
-    qemu_free(pci_dev->w1cmask);
-    qemu_free(pci_dev->used);
+    g_free(pci_dev->config);
+    g_free(pci_dev->cmask);
+    g_free(pci_dev->wmask);
+    g_free(pci_dev->w1cmask);
+    g_free(pci_dev->used);
 }
 
 /* -1 for devfn means auto assign */
 static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
                                          const char *name, int devfn,
-                                         PCIConfigReadFunc *config_read,
-                                         PCIConfigWriteFunc *config_write,
-                                         bool is_bridge)
+                                         const PCIDeviceInfo *info)
 {
+    PCIConfigReadFunc *config_read = info->config_read;
+    PCIConfigWriteFunc *config_write = info->config_write;
+
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
@@ -743,13 +759,29 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     pci_dev->irq_state = 0;
     pci_config_alloc(pci_dev);
 
-    if (!is_bridge) {
-        pci_set_default_subsystem_id(pci_dev);
+    pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
+    pci_config_set_device_id(pci_dev->config, info->device_id);
+    pci_config_set_revision(pci_dev->config, info->revision);
+    pci_config_set_class(pci_dev->config, info->class_id);
+
+    if (!info->is_bridge) {
+        if (info->subsystem_vendor_id || info->subsystem_id) {
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+                         info->subsystem_vendor_id);
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+                         info->subsystem_id);
+        } else {
+            pci_set_default_subsystem_id(pci_dev);
+        }
+    } else {
+        /* subsystem_vendor_id/subsystem_id are only for header type 0 */
+        assert(!info->subsystem_vendor_id);
+        assert(!info->subsystem_id);
     }
     pci_init_cmask(pci_dev);
     pci_init_wmask(pci_dev);
     pci_init_w1cmask(pci_dev);
-    if (is_bridge) {
+    if (info->is_bridge) {
         pci_init_wmask_bridge(pci_dev);
     }
     if (pci_init_multifunction(bus, pci_dev)) {
@@ -776,29 +808,26 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
     pci_config_free(pci_dev);
 }
 
+/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write)
 {
     PCIDevice *pci_dev;
+    PCIDeviceInfo info = {
+        .config_read = config_read,
+        .config_write = config_write,
+    };
 
-    pci_dev = qemu_mallocz(instance_size);
-    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
-                                     config_read, config_write,
-                                     PCI_HEADER_TYPE_NORMAL);
+    pci_dev = g_malloc0(instance_size);
+    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
     if (pci_dev == NULL) {
         hw_error("PCI: can't register device\n");
     }
     return pci_dev;
 }
 
-static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
-                                          target_phys_addr_t addr)
-{
-    return addr + bus->mem_base;
-}
-
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {
     PCIIORegion *r;
@@ -808,14 +837,7 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
         r = &pci_dev->io_regions[i];
         if (!r->size || r->addr == PCI_BAR_UNMAPPED)
             continue;
-        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
-            isa_unassign_ioport(r->addr, r->filtered_size);
-        } else {
-            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
-                                                         r->addr),
-                                         r->filtered_size,
-                                         IO_MEM_UNASSIGNED);
-        }
+        memory_region_del_subregion(r->address_space, r->memory);
     }
 }
 
@@ -832,18 +854,18 @@ static int pci_unregister_device(DeviceState *dev)
 
     pci_unregister_io_regions(pci_dev);
     pci_del_option_rom(pci_dev);
-    qemu_free(pci_dev->romfile);
+    g_free(pci_dev->romfile);
     do_pci_unregister_device(pci_dev);
     return 0;
 }
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, uint8_t type,
-                            PCIMapIORegionFunc *map_func)
+                      uint8_t type, MemoryRegion *memory)
 {
     PCIIORegion *r;
     uint32_t addr;
     uint64_t wmask;
+    pcibus_t size = memory_region_size(memory);
 
     assert(region_num >= 0);
     assert(region_num < PCI_NUM_REGIONS);
@@ -856,14 +878,13 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     r = &pci_dev->io_regions[region_num];
     r->addr = PCI_BAR_UNMAPPED;
     r->size = size;
-    r->filtered_size = size;
     r->type = type;
-    r->map_func = map_func;
+    r->memory = NULL;
 
     wmask = ~(size - 1);
     addr = pci_bar(pci_dev, region_num);
     if (region_num == PCI_ROM_SLOT) {
-        /* ROM enable bit is writeable */
+        /* ROM enable bit is writable */
         wmask |= PCI_ROM_ADDRESS_ENABLE;
     }
     pci_set_long(pci_dev->config + addr, type);
@@ -875,41 +896,16 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
         pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
         pci_set_long(pci_dev->cmask + addr, 0xffffffff);
     }
+    pci_dev->io_regions[region_num].memory = memory;
+    pci_dev->io_regions[region_num].address_space
+        = type & PCI_BASE_ADDRESS_SPACE_IO
+        ? pci_dev->bus->address_space_io
+        : pci_dev->bus->address_space_mem;
 }
 
-static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
-                              uint8_t type)
+pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
 {
-    pcibus_t base = *addr;
-    pcibus_t limit = *addr + *size - 1;
-    PCIDevice *br;
-
-    for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) {
-        uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
-
-        if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-            if (!(cmd & PCI_COMMAND_IO)) {
-                goto no_map;
-            }
-        } else {
-            if (!(cmd & PCI_COMMAND_MEMORY)) {
-                goto no_map;
-            }
-        }
-
-        base = MAX(base, pci_bridge_get_base(br, type));
-        limit = MIN(limit, pci_bridge_get_limit(br, type));
-    }
-
-    if (base > limit) {
-        goto no_map;
-    }
-    *addr = base;
-    *size = limit - base + 1;
-    return;
-no_map:
-    *addr = PCI_BAR_UNMAPPED;
-    *size = 0;
+    return pci_dev->io_regions[region_num].addr;
 }
 
 static pcibus_t pci_bar_address(PCIDevice *d,
@@ -981,7 +977,7 @@ static void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
     int i;
-    pcibus_t new_addr, filtered_size;
+    pcibus_t new_addr;
 
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
@@ -992,51 +988,18 @@ static void pci_update_mappings(PCIDevice *d)
 
         new_addr = pci_bar_address(d, i, r->type, r->size);
 
-        /* bridge filtering */
-        filtered_size = r->size;
-        if (new_addr != PCI_BAR_UNMAPPED) {
-            pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
-        }
-
         /* This bar isn't changed */
-        if (new_addr == r->addr && filtered_size == r->filtered_size)
+        if (new_addr == r->addr)
             continue;
 
         /* now do the real mapping */
         if (r->addr != PCI_BAR_UNMAPPED) {
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                int class;
-                /* NOTE: specific hack for IDE in PC case:
-                   only one byte must be mapped. */
-                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-                if (class == 0x0101 && r->size == 4) {
-                    isa_unassign_ioport(r->addr + 2, 1);
-                } else {
-                    isa_unassign_ioport(r->addr, r->filtered_size);
-                }
-            } else {
-                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
-                                             r->filtered_size,
-                                             IO_MEM_UNASSIGNED);
-                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
-            }
+            memory_region_del_subregion(r->address_space, r->memory);
         }
         r->addr = new_addr;
-        r->filtered_size = filtered_size;
         if (r->addr != PCI_BAR_UNMAPPED) {
-            /*
-             * TODO: currently almost all the map funcions assumes
-             * filtered_size == size and addr & ~(size - 1) == addr.
-             * However with bridge filtering, they aren't always true.
-             * Teach them such cases, such that filtered_size < size and
-             * addr & (size - 1) != 0.
-             */
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                r->map_func(d, i, r->addr, r->filtered_size, r->type);
-            } else {
-                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
-                            r->filtered_size, r->type);
-            }
+            memory_region_add_subregion_overlap(r->address_space,
+                                                r->addr, r->memory, 1);
         }
     }
 }
@@ -1064,8 +1027,7 @@ uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len)
 {
     uint32_t val = 0;
-    assert(len == 1 || len == 2 || len == 4);
-    len = MIN(len, pci_config_size(d) - address);
+
     memcpy(&val, d->config + address, len);
     return le32_to_cpu(val);
 }
@@ -1073,9 +1035,8 @@ uint32_t pci_default_read_config(PCIDevice *d,
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
     int i, was_irq_disabled = pci_irq_disabled(d);
-    uint32_t config_size = pci_config_size(d);
 
-    for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
+    for (i = 0; i < l; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];
         uint8_t w1cmask = d->w1cmask[addr + i];
         assert(!(wmask & w1cmask));
@@ -1145,6 +1106,7 @@ static const pci_class_desc pci_class_descriptions[] =
     { 0x0400, "Video controller", "video"},
     { 0x0401, "Audio controller", "sound"},
     { 0x0402, "Phone"},
+    { 0x0403, "Audio controller", "sound"},
     { 0x0480, "Multimedia controller"},
     { 0x0500, "RAM controller", "memory"},
     { 0x0501, "Flash controller", "flash"},
@@ -1202,276 +1164,194 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
     }
 }
 
-static void pci_device_print(Monitor *mon, QDict *device)
+static const pci_class_desc *get_class_desc(int class)
 {
-    QDict *qdict;
-    QListEntry *entry;
-    uint64_t addr, size;
-
-    monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
-    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
-                        qdict_get_int(device, "slot"),
-                        qdict_get_int(device, "function"));
-    monitor_printf(mon, "    ");
-
-    qdict = qdict_get_qdict(device, "class_info");
-    if (qdict_haskey(qdict, "desc")) {
-        monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
-    } else {
-        monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
-    }
-
-    qdict = qdict_get_qdict(device, "id");
-    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
-                        qdict_get_int(qdict, "device"),
-                        qdict_get_int(qdict, "vendor"));
+    const pci_class_desc *desc;
 
-    if (qdict_haskey(device, "irq")) {
-        monitor_printf(mon, "      IRQ %" PRId64 ".\n",
-                            qdict_get_int(device, "irq"));
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class) {
+        desc++;
     }
 
-    if (qdict_haskey(device, "pci_bridge")) {
-        QDict *info;
-
-        qdict = qdict_get_qdict(device, "pci_bridge");
-
-        info = qdict_get_qdict(qdict, "bus");
-        monitor_printf(mon, "      BUS %" PRId64 ".\n",
-                            qdict_get_int(info, "number"));
-        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
-                            qdict_get_int(info, "secondary"));
-        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
-                            qdict_get_int(info, "subordinate"));
+    return desc;
+}
 
-        info = qdict_get_qdict(qdict, "io_range");
-        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-                       qdict_get_int(info, "limit"));
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
 
-        info = qdict_get_qdict(qdict, "memory_range");
-        monitor_printf(mon,
-                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-                       qdict_get_int(info, "limit"));
+static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
+{
+    PciMemoryRegionList *head = NULL, *cur_item = NULL;
+    int i;
 
-        info = qdict_get_qdict(qdict, "prefetchable_range");
-        monitor_printf(mon, "      prefetchable memory range "
-                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-        qdict_get_int(info, "limit"));
-    }
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        const PCIIORegion *r = &dev->io_regions[i];
+        PciMemoryRegionList *region;
 
-    QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
-        qdict = qobject_to_qdict(qlist_entry_obj(entry));
-        monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+        if (!r->size) {
+            continue;
+        }
 
-        addr = qdict_get_int(qdict, "address");
-        size = qdict_get_int(qdict, "size");
+        region = g_malloc0(sizeof(*region));
+        region->value = g_malloc0(sizeof(*region->value));
 
-        if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
-            monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
-                                " [0x%04"FMT_PCIBUS"].\n",
-                                addr, addr + size - 1);
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            region->value->type = g_strdup("io");
         } else {
-            monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
-                               " [0x%08"FMT_PCIBUS"].\n",
-                                qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
-                                qdict_get_bool(qdict, "prefetch") ?
-                                " prefetchable" : "", addr, addr + size - 1);
+            region->value->type = g_strdup("memory");
+            region->value->has_prefetch = true;
+            region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
+            region->value->has_mem_type_64 = true;
+            region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
         }
-    }
 
-    monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+        region->value->bar = i;
+        region->value->address = r->addr;
+        region->value->size = r->size;
 
-    if (qdict_haskey(device, "pci_bridge")) {
-        qdict = qdict_get_qdict(device, "pci_bridge");
-        if (qdict_haskey(qdict, "devices")) {
-            QListEntry *dev;
-            QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
-                pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
-            }
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = region;
+        } else {
+            cur_item->next = region;
+            cur_item = region;
         }
     }
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
-{
-    QListEntry *bus, *dev;
 
-    QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
-        QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
-        QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
-            pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
-        }
-    }
+    return head;
 }
 
-static QObject *pci_get_dev_class(const PCIDevice *dev)
+static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
 {
-    int class;
-    const pci_class_desc *desc;
+    PciBridgeInfo *info;
 
-    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
-    desc = pci_class_descriptions;
-    while (desc->desc && class != desc->class)
-        desc++;
+    info = g_malloc0(sizeof(*info));
 
-    if (desc->desc) {
-        return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
-                                  desc->desc, class);
-    } else {
-        return qobject_from_jsonf("{ 'class': %d }", class);
-    }
-}
+    info->bus.number = dev->config[PCI_PRIMARY_BUS];
+    info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
+    info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
 
-static QObject *pci_get_dev_id(const PCIDevice *dev)
-{
-    return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
-                              pci_get_word(dev->config + PCI_VENDOR_ID),
-                              pci_get_word(dev->config + PCI_DEVICE_ID));
-}
+    info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
+    info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
+    info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
 
-static QObject *pci_get_regions_list(const PCIDevice *dev)
-{
-    int i;
-    QList *regions_list;
-
-    regions_list = qlist_new();
-
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        QObject *obj;
-        const PCIIORegion *r = &dev->io_regions[i];
+    info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
+    info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
 
-        if (!r->size) {
-            continue;
-        }
+    info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
+    info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+    info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
 
-        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
-                                     "'address': %" PRId64 ", "
-                                     "'size': %" PRId64 " }",
-                                     i, r->addr, r->size);
-        } else {
-            int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
-
-            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
-                                     "'mem_type_64': %i, 'prefetch': %i, "
-                                     "'address': %" PRId64 ", "
-                                     "'size': %" PRId64 " }",
-                                     i, mem_type_64,
-                                     r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
-                                     r->addr, r->size);
+    if (dev->config[PCI_SECONDARY_BUS] != 0) {
+        PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+        if (child_bus) {
+            info->has_devices = true;
+            info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
         }
-
-        qlist_append_obj(regions_list, obj);
     }
 
-    return QOBJECT(regions_list);
+    return info;
 }
 
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
-
-static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
+static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
 {
+    const pci_class_desc *desc;
+    PciDeviceInfo *info;
     uint8_t type;
-    QObject *obj;
+    int class;
 
-    obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"
-                              " 'qdev_id': %s }",
-                              bus_num,
-                              PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-                              pci_get_dev_class(dev), pci_get_dev_id(dev),
-                              pci_get_regions_list(dev),
-                              dev->qdev.id ? dev->qdev.id : "");
+    info = g_malloc0(sizeof(*info));
+    info->bus = bus_num;
+    info->slot = PCI_SLOT(dev->devfn);
+    info->function = PCI_FUNC(dev->devfn);
+
+    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+    info->class_info.class = class;
+    desc = get_class_desc(class);
+    if (desc->desc) {
+        info->class_info.has_desc = true;
+        info->class_info.desc = g_strdup(desc->desc);
+    }
+
+    info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
+    info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
+    info->regions = qmp_query_pci_regions(dev);
+    info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
 
     if (dev->config[PCI_INTERRUPT_PIN] != 0) {
-        QDict *qdict = qobject_to_qdict(obj);
-        qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+        info->has_irq = true;
+        info->irq = dev->config[PCI_INTERRUPT_LINE];
     }
 
     type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
     if (type == PCI_HEADER_TYPE_BRIDGE) {
-        QDict *qdict;
-        QObject *pci_bridge;
-
-        pci_bridge = qobject_from_jsonf("{ 'bus': "
-        "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
-        "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
-        "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
-        "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
-        dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
-        dev->config[PCI_SUBORDINATE_BUS],
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                               PCI_BASE_ADDRESS_MEM_PREFETCH),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                                PCI_BASE_ADDRESS_MEM_PREFETCH));
-
-        if (dev->config[PCI_SECONDARY_BUS] != 0) {
-            PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
-
-            if (child_bus) {
-                qdict = qobject_to_qdict(pci_bridge);
-                qdict_put_obj(qdict, "devices",
-                              pci_get_devices_list(child_bus,
-                                                   dev->config[PCI_SECONDARY_BUS]));
-            }
-        }
-        qdict = qobject_to_qdict(obj);
-        qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+        info->has_pci_bridge = true;
+        info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
     }
 
-    return obj;
+    return info;
 }
 
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
 {
-    int devfn;
+    PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
     PCIDevice *dev;
-    QList *dev_list;
-
-    dev_list = qlist_new();
+    int devfn;
 
     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
         dev = bus->devices[devfn];
         if (dev) {
-            qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
+            info = g_malloc0(sizeof(*info));
+            info->value = qmp_query_pci_device(dev, bus, bus_num);
+
+            /* XXX: waiting for the qapi to support GSList */
+            if (!cur_item) {
+                head = cur_item = info;
+            } else {
+                cur_item->next = info;
+                cur_item = info;
+            }
         }
     }
 
-    return QOBJECT(dev_list);
+    return head;
 }
 
-static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
+static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
 {
+    PciInfo *info = NULL;
+
     bus = pci_find_bus(bus, bus_num);
     if (bus) {
-        return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
-                                  bus_num, pci_get_devices_list(bus, bus_num));
+        info = g_malloc0(sizeof(*info));
+        info->bus = bus_num;
+        info->devices = qmp_query_pci_devices(bus, bus_num);
     }
 
-    return NULL;
+    return info;
 }
 
-void do_pci_info(Monitor *mon, QObject **ret_data)
+PciInfoList *qmp_query_pci(Error **errp)
 {
-    QList *bus_list;
+    PciInfoList *info, *head = NULL, *cur_item = NULL;
     struct PCIHostBus *host;
 
-    bus_list = qlist_new();
-
     QLIST_FOREACH(host, &host_buses, next) {
-        QObject *obj = pci_get_bus_dict(host->bus, 0);
-        if (obj) {
-            qlist_append_obj(bus_list, obj);
+        info = g_malloc0(sizeof(*info));
+        info->value = qmp_query_pci_bus(host->bus, 0);
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
         }
     }
 
-    *ret_data = QOBJECT(bus_list);
+    return head;
 }
 
 static const char * const pci_nic_models[] = {
@@ -1543,22 +1423,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
     return res;
 }
 
-static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
-{
-    pci_update_mappings(d);
-}
-
-void pci_bridge_update_mappings(PCIBus *b)
-{
-    PCIBus *child;
-
-    pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn);
-
-    QLIST_FOREACH(child, &b->child, sibling) {
-        pci_bridge_update_mappings(child);
-    }
-}
-
 /* Whether a given bus number is in range of the secondary
  * bus of the given bridge device. */
 static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
@@ -1603,14 +1467,14 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
     return NULL;
 }
 
-PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function)
+PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
 {
     bus = pci_find_bus(bus, bus_num);
 
     if (!bus)
         return NULL;
 
-    return bus->devices[PCI_DEVFN(slot, function)];
+    return bus->devices[devfn];
 }
 
 static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
@@ -1618,7 +1482,7 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     PCIDevice *pci_dev = (PCIDevice *)qdev;
     PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
     PCIBus *bus;
-    int devfn, rc;
+    int rc;
     bool is_default_rom;
 
     /* initialize cap_present for pci_is_express() and pci_config_size() */
@@ -1627,10 +1491,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     }
 
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
-    devfn = pci_dev->devfn;
-    pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
-                                     info->config_read, info->config_write,
-                                     info->is_bridge);
+    pci_dev = do_pci_register_device(pci_dev, bus, base->name,
+                                     pci_dev->devfn, info);
     if (pci_dev == NULL)
         return -1;
     if (qdev->hotplugged && info->no_hotplug) {
@@ -1638,16 +1500,18 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
         do_pci_unregister_device(pci_dev);
         return -1;
     }
-    rc = info->init(pci_dev);
-    if (rc != 0) {
-        do_pci_unregister_device(pci_dev);
-        return rc;
+    if (info->init) {
+        rc = info->init(pci_dev);
+        if (rc != 0) {
+            do_pci_unregister_device(pci_dev);
+            return rc;
+        }
     }
 
     /* rom loading */
     is_default_rom = false;
     if (pci_dev->romfile == NULL && info->romfile != NULL) {
-        pci_dev->romfile = qemu_strdup(info->romfile);
+        pci_dev->romfile = g_strdup(info->romfile);
         is_default_rom = true;
     }
     pci_add_option_rom(pci_dev, is_default_rom);
@@ -1708,6 +1572,21 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
     return DO_UPCAST(PCIDevice, qdev, dev);
 }
 
+PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
+                                        bool multifunction,
+                                        const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_try_create(&bus->qbus, name);
+    if (!dev) {
+        return NULL;
+    }
+    qdev_prop_set_uint32(dev, "addr", devfn);
+    qdev_prop_set_bit(dev, "multifunction", multifunction);
+    return DO_UPCAST(PCIDevice, qdev, dev);
+}
+
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
                                            bool multifunction,
                                            const char *name)
@@ -1727,6 +1606,11 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
     return pci_create_simple_multifunction(bus, devfn, false, name);
 }
 
+PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_try_create_multifunction(bus, devfn, false, name);
+}
+
 static int pci_find_space(PCIDevice *pdev, uint8_t size)
 {
     int config_size = pci_config_size(pdev);
@@ -1758,9 +1642,23 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
     return next;
 }
 
-static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
+static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
 {
-    cpu_register_physical_memory(addr, size, pdev->rom_offset);
+    uint8_t next, prev, found = 0;
+
+    if (!(pdev->used[offset])) {
+        return 0;
+    }
+
+    assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
+
+    for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
+         prev = next + PCI_CAP_LIST_NEXT) {
+        if (next <= offset && next > found) {
+            found = next;
+        }
+    }
+    return found;
 }
 
 /* Patch the PCI vendor and device ids in a PCI rom image if necessary.
@@ -1848,13 +1746,14 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
 
     path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
     if (path == NULL) {
-        path = qemu_strdup(pdev->romfile);
+        path = g_strdup(pdev->romfile);
     }
 
     size = get_image_size(path);
     if (size < 0) {
         error_report("%s: failed to find romfile \"%s\"",
                      __FUNCTION__, pdev->romfile);
+        g_free(path);
         return -1;
     }
     if (size & (size - 1)) {
@@ -1865,30 +1764,31 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
     else
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
-    pdev->rom_offset = qemu_ram_alloc(&pdev->qdev, name, size);
-
-    ptr = qemu_get_ram_ptr(pdev->rom_offset);
+    pdev->has_rom = true;
+    memory_region_init_ram(&pdev->rom, &pdev->qdev, name, size);
+    ptr = memory_region_get_ram_ptr(&pdev->rom);
     load_image(path, ptr);
-    qemu_free(path);
+    g_free(path);
 
     if (is_default_rom) {
         /* Only the default rom images will be patched (if needed). */
         pci_patch_ids(pdev, ptr, size);
     }
 
-    pci_register_bar(pdev, PCI_ROM_SLOT, size,
-                     0, pci_map_option_rom);
+    qemu_put_ram_ptr(ptr);
+
+    pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
 
     return 0;
 }
 
 static void pci_del_option_rom(PCIDevice *pdev)
 {
-    if (!pdev->rom_offset)
+    if (!pdev->has_rom)
         return;
 
-    qemu_ram_free(pdev->rom_offset);
-    pdev->rom_offset = 0;
+    memory_region_destroy(&pdev->rom);
+    pdev->has_rom = false;
 }
 
 /*
@@ -1902,11 +1802,30 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
                        uint8_t offset, uint8_t size)
 {
     uint8_t *config;
+    int i, overlapping_cap;
+
     if (!offset) {
         offset = pci_find_space(pdev, size);
         if (!offset) {
             return -ENOSPC;
         }
+    } else {
+        /* Verify that capabilities don't overlap.  Note: device assignment
+         * depends on this check to verify that the device is not broken.
+         * Should never trigger for emulated devices, but it's helpful
+         * for debugging these. */
+        for (i = offset; i < offset + size; i++) {
+            overlapping_cap = pci_find_capability_at_offset(pdev, i);
+            if (overlapping_cap) {
+                fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
+                        "Attempt to add PCI capability %x at offset "
+                        "%x overlaps existing capability %x at offset %x\n",
+                        pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        cap_id, offset, overlapping_cap, i);
+                return -EINVAL;
+            }
+        }
     }
 
     config = pdev->config + offset;
@@ -1929,7 +1848,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
     if (!offset)
         return;
     pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
-    /* Make capability writeable again */
+    /* Make capability writable again */
     memset(pdev->wmask + offset, 0xff, size);
     memset(pdev->w1cmask + offset, 0, size);
     /* Clear cmask as device-specific registers can't be checked */
@@ -1940,12 +1859,6 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
         pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
 }
 
-/* Reserve space for capability at a known offset (to call after load). */
-void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
-{
-    memset(pdev->used + offset, 0xff, size);
-}
-
 uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
 {
     return pci_find_capability_list(pdev, cap_id, NULL);
@@ -2058,7 +1971,7 @@ static char *pcibus_get_dev_path(DeviceState *dev)
     path_len = domain_len + slot_len * slot_depth;
 
     /* Allocate memory, fill in the terminating null byte. */
-    path = qemu_malloc(path_len + 1 /* For '\0' */);
+    path = g_malloc(path_len + 1 /* For '\0' */);
     path[path_len] = '\0';
 
     /* First field is the domain. */
@@ -2115,3 +2028,13 @@ int pci_qdev_find_device(const char *id, PCIDevice **pdev)
 
     return rc;
 }
+
+MemoryRegion *pci_address_space(PCIDevice *dev)
+{
+    return dev->bus->address_space_mem;
+}
+
+MemoryRegion *pci_address_space_io(PCIDevice *dev)
+{
+    return dev->bus->address_space_io;
+}
index e08606435159f9ab7d1ed9138a9bdcc65c563a02..b0473b0d8d20e74c5d2603216ac4f0026a7a60eb 100644 (file)
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -2,9 +2,10 @@
 #define QEMU_PCI_H
 
 #include "qemu-common.h"
-#include "qobject.h"
 
 #include "qdev.h"
+#include "memory.h"
+#include "dma.h"
 
 /* PCI includes legacy ISA access.  */
 #include "isa.h"
@@ -16,6 +17,7 @@
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 #define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
 #define PCI_FUNC(devfn)         ((devfn) & 0x07)
+#define PCI_SLOT_MAX            32
 #define PCI_FUNC_MAX            8
 
 /* Class, Vendor and Device IDs from Linux's pci_ids.h */
@@ -73,7 +75,8 @@
 #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
 #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
 #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
-#define PCI_DEVICE_ID_VIRTIO_EXAMPLE     0x1010
+
+#define PCI_DEVICE_ID_VIRTIO_GL          0x1006
 
 #define FMT_PCIBUS                      PRIx64
 
@@ -89,9 +92,9 @@ typedef struct PCIIORegion {
     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
 #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
     pcibus_t size;
-    pcibus_t filtered_size;
     uint8_t type;
-    PCIMapIORegionFunc *map_func;
+    MemoryRegion *memory;
+    MemoryRegion *address_space;
 } PCIIORegion;
 
 #define PCI_ROM_SLOT 6
@@ -131,7 +134,7 @@ struct PCIDevice {
     /* PCI config space */
     uint8_t *config;
 
-    /* Used to enable config checks on load. Note that writeable bits are
+    /* Used to enable config checks on load. Note that writable bits are
      * never checked even if set in cmask. */
     uint8_t *cmask;
 
@@ -172,11 +175,13 @@ struct PCIDevice {
     /* Space to store MSIX table */
     uint8_t *msix_table_page;
     /* MMIO index used to map MSIX table and pending bit entries. */
-    int msix_mmio_index;
+    MemoryRegion msix_mmio;
     /* Reference-count for entries actually in use by driver. */
     unsigned *msix_entry_used;
     /* Region including the MSI-X table */
     uint32_t msix_bar_size;
+    /* MSIX function mask set or MSIX disabled */
+    bool msix_function_masked;
     /* Version id needed for VMState */
     int32_t version_id;
 
@@ -188,7 +193,8 @@ struct PCIDevice {
 
     /* Location of option rom */
     char *romfile;
-    ram_addr_t rom_offset;
+    bool has_rom;
+    MemoryRegion rom;
     uint32_t rom_bar;
 };
 
@@ -198,16 +204,14 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                PCIConfigWriteFunc *config_write);
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, uint8_t type,
-                            PCIMapIORegionFunc *map_func);
+                      uint8_t attr, MemoryRegion *memory);
+pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
 int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
                        uint8_t offset, uint8_t size);
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
-void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
-
 uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
 
 
@@ -217,6 +221,8 @@ void pci_default_write_config(PCIDevice *d,
                               uint32_t address, uint32_t val, int len);
 void pci_device_save(PCIDevice *s, QEMUFile *f);
 int pci_device_load(PCIDevice *s, QEMUFile *f);
+MemoryRegion *pci_address_space(PCIDevice *dev);
+MemoryRegion *pci_address_space_io(PCIDevice *dev);
 
 typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -230,19 +236,27 @@ typedef enum {
 typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
                               PCIHotplugState state);
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
-                         const char *name, int devfn_min);
-PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min);
+                         const char *name,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min);
+PCIBus *pci_bus_new(DeviceState *parent, const char *name,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    uint8_t devfn_min);
 void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                   void *irq_opaque, int nirq);
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
 void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *irq_opaque, int devfn_min, int nirq);
+                         void *irq_opaque,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min, int nirq);
 void pci_device_reset(PCIDevice *dev);
 void pci_bus_reset(PCIBus *bus);
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base);
-
 PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
                         const char *default_devaddr);
 PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
@@ -252,7 +266,7 @@ void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDe
 PCIBus *pci_find_root_bus(int domain);
 int pci_find_domain(const PCIBus *bus);
 PCIBus *pci_find_bus(PCIBus *bus, int bus_num);
-PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function);
+PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
 int pci_qdev_find_device(const char *id, PCIDevice **pdev);
 PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
 
@@ -261,10 +275,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
 int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                      unsigned *slotp);
 
-void do_pci_info_print(Monitor *mon, const QObject *data);
-void do_pci_info(Monitor *mon, QObject **ret_data);
-void pci_bridge_update_mappings(PCIBus *b);
-
 void pci_device_deassert_intx(PCIDevice *dev);
 
 static inline void
@@ -429,6 +439,13 @@ typedef struct {
     PCIConfigReadFunc *config_read;
     PCIConfigWriteFunc *config_write;
 
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t class_id;
+    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
+    uint16_t subsystem_id;              /* only for header type = 0 */
+
     /*
      * pci-to-pci bridge or normal device.
      * This doesn't mean pci host switch.
@@ -454,8 +471,12 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
                                            bool multifunction,
                                            const char *name);
+PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
+                                        bool multifunction,
+                                        const char *name);
 PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
 PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
+PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name);
 
 static inline int pci_is_express(const PCIDevice *d)
 {
@@ -467,4 +488,70 @@ static inline uint32_t pci_config_size(const PCIDevice *d)
     return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
 }
 
+/* DMA access functions */
+static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
+                             void *buf, dma_addr_t len, DMADirection dir)
+{
+    cpu_physical_memory_rw(addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE);
+    return 0;
+}
+
+static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+                               void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
+                                const void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+#define PCI_DMA_DEFINE_LDST(_l, _s, _bits)                              \
+    static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev,      \
+                                                   dma_addr_t addr)     \
+    {                                                                   \
+        return ld##_l##_phys(addr);                                     \
+    }                                                                   \
+    static inline void st##_s##_pci_dma(PCIDevice *dev,                 \
+                          dma_addr_t addr, uint##_bits##_t val)         \
+    {                                                                   \
+        st##_s##_phys(addr, val);                                       \
+    }
+
+PCI_DMA_DEFINE_LDST(ub, b, 8);
+PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
+PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
+PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
+PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
+PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
+PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
+
+#undef PCI_DMA_DEFINE_LDST
+
+static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
+                                dma_addr_t *plen, DMADirection dir)
+{
+    target_phys_addr_t len = *plen;
+    void *buf;
+
+    buf = cpu_physical_memory_map(addr, &len, dir == DMA_DIRECTION_FROM_DEVICE);
+    *plen = len;
+    return buf;
+}
+
+static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
+                                 DMADirection dir, dma_addr_t access_len)
+{
+    cpu_physical_memory_unmap(buffer, len, dir == DMA_DIRECTION_FROM_DEVICE,
+                              access_len);
+}
+
+static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
+                                       int alloc_hint)
+{
+    qemu_sglist_init(qsg, alloc_hint);
+}
+
 #endif
index 464d89708f95a4a67ba9891aef17ad4add014c49..650d1650c57d17cc812dd771bf7862f135cd772d 100644 (file)
@@ -135,6 +135,76 @@ pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
     return limit;
 }
 
+static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
+                                  uint8_t type, const char *name,
+                                  MemoryRegion *space,
+                                  MemoryRegion *parent_space,
+                                  bool enabled)
+{
+    pcibus_t base = pci_bridge_get_base(&bridge->dev, type);
+    pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type);
+    /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly.
+     * Apparently no way to do this with existing memory APIs. */
+    pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0;
+
+    memory_region_init_alias(alias, name, space, base, size);
+    memory_region_add_subregion_overlap(parent_space, base, alias, 1);
+}
+
+static void pci_bridge_cleanup_alias(MemoryRegion *alias,
+                                     MemoryRegion *parent_space)
+{
+    memory_region_del_subregion(parent_space, alias);
+    memory_region_destroy(alias);
+}
+
+static void pci_bridge_region_init(PCIBridge *br)
+{
+    PCIBus *parent = br->dev.bus;
+    uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND);
+
+    pci_bridge_init_alias(br, &br->alias_pref_mem,
+                          PCI_BASE_ADDRESS_MEM_PREFETCH,
+                          "pci_bridge_pref_mem",
+                          &br->address_space_mem,
+                          parent->address_space_mem,
+                          cmd & PCI_COMMAND_MEMORY);
+    pci_bridge_init_alias(br, &br->alias_mem,
+                          PCI_BASE_ADDRESS_SPACE_MEMORY,
+                          "pci_bridge_mem",
+                          &br->address_space_mem,
+                          parent->address_space_mem,
+                          cmd & PCI_COMMAND_MEMORY);
+    pci_bridge_init_alias(br, &br->alias_io,
+                          PCI_BASE_ADDRESS_SPACE_IO,
+                          "pci_bridge_io",
+                          &br->address_space_io,
+                          parent->address_space_io,
+                          cmd & PCI_COMMAND_IO);
+   /* TODO: optinal VGA and VGA palette snooping support. */
+}
+
+static void pci_bridge_region_cleanup(PCIBridge *br)
+{
+    PCIBus *parent = br->dev.bus;
+    pci_bridge_cleanup_alias(&br->alias_io,
+                             parent->address_space_io);
+    pci_bridge_cleanup_alias(&br->alias_mem,
+                             parent->address_space_mem);
+    pci_bridge_cleanup_alias(&br->alias_pref_mem,
+                             parent->address_space_mem);
+}
+
+static void pci_bridge_update_mappings(PCIBridge *br)
+{
+    /* Make updates atomic to: handle the case of one VCPU updating the bridge
+     * while another accesses an unaffected region. */
+    memory_region_transaction_begin();
+    pci_bridge_region_cleanup(br);
+    pci_bridge_region_init(br);
+    memory_region_transaction_commit();
+}
+
 /* default write_config function for PCI-to-PCI bridge */
 void pci_bridge_write_config(PCIDevice *d,
                              uint32_t address, uint32_t val, int len)
@@ -145,13 +215,15 @@ void pci_bridge_write_config(PCIDevice *d,
 
     pci_default_write_config(d, address, val, len);
 
-    if (/* io base/limit */
+    if (ranges_overlap(address, len, PCI_COMMAND, 2) ||
+
+        /* io base/limit */
         ranges_overlap(address, len, PCI_IO_BASE, 2) ||
 
         /* memory base/limit, prefetchable base/limit and
            io base/limit upper 16 */
         ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
-        pci_bridge_update_mappings(&s->sec_bus);
+        pci_bridge_update_mappings(s);
     }
 
     newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
@@ -246,7 +318,11 @@ int pci_bridge_initfn(PCIDevice *dev)
                         br->bus_name);
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
-
+    sec_bus->address_space_mem = &br->address_space_mem;
+    memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
+    sec_bus->address_space_io = &br->address_space_io;
+    memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
+    pci_bridge_region_init(br);
     QLIST_INIT(&sec_bus->child);
     QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
     return 0;
@@ -258,6 +334,9 @@ int pci_bridge_exitfn(PCIDevice *pci_dev)
     PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
     assert(QLIST_EMPTY(&s->sec_bus.child));
     QLIST_REMOVE(&s->sec_bus, sibling);
+    pci_bridge_region_cleanup(s);
+    memory_region_destroy(&s->address_space_mem);
+    memory_region_destroy(&s->address_space_io);
     /* qbus_free() is called automatically by qdev_free() */
     return 0;
 }
index 7c40155b95c2d155ad529bd62c177f8f69cf6aaf..44c6c207a9fc1ebd23f3de795efe8fbec0bd38f5 100644 (file)
@@ -44,7 +44,21 @@ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
     uint8_t bus_num = addr >> 16;
     uint8_t devfn = addr >> 8;
 
-    return pci_find_device(bus, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
+    return pci_find_device(bus, bus_num, devfn);
+}
+
+void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
+                                  uint32_t limit, uint32_t val, uint32_t len)
+{
+    assert(len <= 4);
+    pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
+}
+
+uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t len)
+{
+    assert(len <= 4);
+    return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
 }
 
 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
@@ -52,12 +66,14 @@ void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
     PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
 
-    if (!pci_dev)
+    if (!pci_dev) {
         return;
+    }
 
     PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
                 __func__, pci_dev->name, config_addr, val, len);
-    pci_dev->config_write(pci_dev, config_addr, val, len);
+    pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
+                                 val, len);
 }
 
 uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
@@ -66,94 +82,84 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
     uint32_t val;
 
-    assert(len == 1 || len == 2 || len == 4);
     if (!pci_dev) {
         return ~0x0;
     }
 
-    val = pci_dev->config_read(pci_dev, config_addr, len);
+    val = pci_host_config_read_common(pci_dev, config_addr,
+                                      PCI_CONFIG_SPACE_SIZE, len);
     PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
                 __func__, pci_dev->name, config_addr, val, len);
 
     return val;
 }
 
-static void pci_host_config_write(ReadWriteHandler *handler,
-                                  pcibus_t addr, uint32_t val, int len)
+static void pci_host_config_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t val, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+    PCIHostState *s = opaque;
 
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+    PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
                 __func__, addr, len, val);
     s->config_reg = val;
 }
 
-static uint32_t pci_host_config_read(ReadWriteHandler *handler,
-                                     pcibus_t addr, int len)
+static uint64_t pci_host_config_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+    PCIHostState *s = opaque;
     uint32_t val = s->config_reg;
 
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+    PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
                 __func__, addr, len, val);
     return val;
 }
 
-static void pci_host_data_write(ReadWriteHandler *handler,
-                                pcibus_t addr, uint32_t val, int len)
+static void pci_host_data_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
-    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
-                addr, len, val);
+    PCIHostState *s = opaque;
+    PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
+                addr, len, (unsigned)val);
     if (s->config_reg & (1u << 31))
         pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
 }
 
-static uint32_t pci_host_data_read(ReadWriteHandler *handler,
-                                   pcibus_t addr, int len)
+static uint64_t pci_host_data_read(void *opaque,
+                                   target_phys_addr_t addr, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+    PCIHostState *s = opaque;
     uint32_t val;
     if (!(s->config_reg & (1 << 31)))
         return 0xffffffff;
     val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
-    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
+    PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
                 addr, len, val);
     return val;
 }
 
-static void pci_host_init(PCIHostState *s)
-{
-    s->conf_handler.write = pci_host_config_write;
-    s->conf_handler.read = pci_host_config_read;
-    s->data_handler.write = pci_host_data_write;
-    s->data_handler.read = pci_host_data_read;
-}
+const MemoryRegionOps pci_host_conf_le_ops = {
+    .read = pci_host_config_read,
+    .write = pci_host_config_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
-int pci_host_conf_register_mmio(PCIHostState *s, int endian)
-{
-    pci_host_init(s);
-    return cpu_register_io_memory_simple(&s->conf_handler, endian);
-}
+const MemoryRegionOps pci_host_conf_be_ops = {
+    .read = pci_host_config_read,
+    .write = pci_host_config_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
 
-void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
-{
-    pci_host_init(s);
-    register_ioport_simple(&s->conf_handler, ioport, 4, 4);
-    sysbus_init_ioports(&s->busdev, ioport, 4);
-}
+const MemoryRegionOps pci_host_data_le_ops = {
+    .read = pci_host_data_read,
+    .write = pci_host_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+const MemoryRegionOps pci_host_data_be_ops = {
+    .read = pci_host_data_read,
+    .write = pci_host_data_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
 
-int pci_host_data_register_mmio(PCIHostState *s, int endian)
-{
-    pci_host_init(s);
-    return cpu_register_io_memory_simple(&s->data_handler, endian);
-}
 
-void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
-{
-    pci_host_init(s);
-    register_ioport_simple(&s->data_handler, ioport, 4, 1);
-    register_ioport_simple(&s->data_handler, ioport, 4, 2);
-    register_ioport_simple(&s->data_handler, ioport, 4, 4);
-    sysbus_init_ioports(&s->busdev, ioport, 4);
-}
index 0a585951e07b7b2bdb51cbe6e450b67979a1ae25..0211086d70741120665b033e5651d8001c861c12 100644 (file)
 #define PCI_HOST_H
 
 #include "sysbus.h"
-#include "rwhandler.h"
 
 struct PCIHostState {
     SysBusDevice busdev;
-    ReadWriteHandler conf_handler;
-    ReadWriteHandler data_handler;
+    MemoryRegion conf_mem;
+    MemoryRegion data_mem;
+    MemoryRegion *address_space;
     uint32_t config_reg;
     PCIBus *bus;
 };
 
+/* common internal helpers for PCI/PCIe hosts, cut off overflows */
+void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
+                                  uint32_t limit, uint32_t val, uint32_t len);
+uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t len);
+
 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
 uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
 
-/* for mmio */
-int pci_host_conf_register_mmio(PCIHostState *s, int endian);
-int pci_host_data_register_mmio(PCIHostState *s, int endian);
-
-/* for ioio */
-void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s);
-void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s);
+extern const MemoryRegionOps pci_host_conf_le_ops;
+extern const MemoryRegionOps pci_host_conf_be_ops;
+extern const MemoryRegionOps pci_host_data_le_ops;
+extern const MemoryRegionOps pci_host_data_be_ops;
 
 #endif /* PCI_HOST_H */
index 97b819d8a8c0583de83c7cf447d592a9a6932b2c..83f38934ec97b4a41e9d125ae7adfa4d99b220ef 100644 (file)
@@ -24,7 +24,6 @@
 #define PCI_CLASS_DISPLAY_OTHER          0x0380
 
 #define PCI_CLASS_MULTIMEDIA_AUDIO       0x0401
-#define PCI_CLASS_MULTIMEDIA_OTHER              0x0480
 
 #define PCI_CLASS_MEMORY_RAM             0x0500
 
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
 #define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
 
-#define PCI_VENDOR_ID_SAMSUNG                   0x144d
-
-#define PCI_VENDOR_ID_TIZEN                             0xC9B5
-#define PCI_DEVICE_ID_VIRTUAL_OVERLAY    0x1010
-#define PCI_DEVICE_ID_VIRTUAL_BRIGHTNESS 0x1014                 
-#define PCI_DEVICE_ID_VIRTUAL_CAMERA    0x1018
-#define PCI_DEVICE_ID_VIRTUAL_CODEC             0x101C
-
 #define PCI_VENDOR_ID_SUN                0x108e
 #define PCI_DEVICE_ID_SUN_EBUS           0x1000
 #define PCI_DEVICE_ID_SUN_SIMBA          0x5000
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
 #define PCI_DEVICE_ID_INTEL_82801AA_5    0x2415
+#define PCI_DEVICE_ID_INTEL_82801D       0x24CD
 #define PCI_DEVICE_ID_INTEL_ESB_9        0x25ab
 #define PCI_DEVICE_ID_INTEL_82371SB_0    0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1    0x7010
 #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
+
+#define PCI_VENDOR_ID_XEN               0x5853
+#define PCI_DEVICE_ID_XEN_PLATFORM      0x0001
index e3c93a3cc58397202e1ba88b17c1bb4854eef1ed..96690b72d38f770227df4e5cf4ed92f589ee0d07 100644 (file)
@@ -16,15 +16,16 @@ extern struct BusInfo pci_bus_info;
 
 struct PCIBus {
     BusState qbus;
-    int devfn_min;
+    uint8_t devfn_min;
     pci_set_irq_fn set_irq;
     pci_map_irq_fn map_irq;
     pci_hotplug_fn hotplug;
     DeviceState *hotplug_qdev;
     void *irq_opaque;
-    PCIDevice *devices[256];
+    PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
     PCIDevice *parent_dev;
-    target_phys_addr_t mem_base;
+    MemoryRegion *address_space_mem;
+    MemoryRegion *address_space_io;
 
     QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
     QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
@@ -40,6 +41,24 @@ struct PCIBridge {
 
     /* private member */
     PCIBus sec_bus;
+    /*
+     * Memory regions for the bridge's address spaces.  These regions are not
+     * directly added to system_memory/system_io or its descendants.
+     * Bridge's secondary bus points to these, so that devices
+     * under the bridge see these regions as its address spaces.
+     * The regions are as large as the entire address space -
+     * they don't take into account any windows.
+     */
+    MemoryRegion address_space_mem;
+    MemoryRegion address_space_io;
+    /*
+     * Aliases for each of the address space windows that the bridge
+     * can forward. Mapped into the bridge's parent's address space,
+     * as subregions.
+     */
+    MemoryRegion alias_pref_mem;
+    MemoryRegion alias_mem;
+    MemoryRegion alias_io;
     pci_map_irq_fn map_irq;
     const char *bus_name;
 };
index dd0bed4f1cf00ffd00f5b2eace8103a25d606432..e8357c3ea6fb718233dae933c5f115d0abfb70ab 100644 (file)
 #define  PCI_CAP_ID_AGP3       0x0E    /* AGP Target PCI-PCI bridge */
 #define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
 #define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
+#define  PCI_CAP_ID_SATA       0x12    /* Serial ATA */
 #define  PCI_CAP_ID_AF         0x13    /* PCI Advanced Features */
 #define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
 #define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
 #define  PCI_PM_CAP_PME_CLOCK  0x0008  /* PME clock required */
 #define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
 #define  PCI_PM_CAP_DSI                0x0020  /* Device specific initialization */
-#define  PCI_PM_CAP_AUX_POWER  0x01C0  /* Auxilliary power support mask */
+#define  PCI_PM_CAP_AUX_POWER  0x01C0  /* Auxiliary power support mask */
 #define  PCI_PM_CAP_D1         0x0200  /* D1 power state support */
 #define  PCI_PM_CAP_D2         0x0400  /* D2 power state support */
 #define  PCI_PM_CAP_PME                0x0800  /* PME pin supported */
 #define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit devices */
 #define PCI_MSI_MASK_64                16      /* Mask bits register for 64-bit devices */
 
-/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+/* MSI-X registers */
 #define PCI_MSIX_FLAGS         2
 #define  PCI_MSIX_FLAGS_QSIZE  0x7FF
 #define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
 #define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
-#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_TABLE         4
+#define PCI_MSIX_PBA           8
+#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
+
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE            16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
+#define  PCI_MSIX_ENTRY_DATA           8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
+#define   PCI_MSIX_ENTRY_CTRL_MASKBIT  1
 
 /* CompactPCI Hotswap Register */
 
 #define  PCI_X_STATUS_266MHZ   0x40000000      /* 266 MHz capable */
 #define  PCI_X_STATUS_533MHZ   0x80000000      /* 533 MHz capable */
 
+/* PCI Bridge Subsystem ID registers */
+
+#define PCI_SSVID_VENDOR_ID     4      /* PCI-Bridge subsystem vendor id register */
+#define PCI_SSVID_DEVICE_ID     6      /* PCI-Bridge subsystem device id register */
+
 /* PCI Express capability registers */
 
 #define PCI_EXP_FLAGS          2       /* Capabilities register */
 #define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
 #define  PCI_EXP_LNKCAP_L1EL   0x00038000 /* L1 Exit Latency */
 #define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* L1 Clock Power Management */
-#define  PCI_EXP_LNKCAP_SDERC  0x00080000 /* Suprise Down Error Reporting Capable */
+#define  PCI_EXP_LNKCAP_SDERC  0x00080000 /* Surprise Down Error Reporting Capable */
 #define  PCI_EXP_LNKCAP_DLLLARC        0x00100000 /* Data Link Layer Link Active Reporting Capable */
 #define  PCI_EXP_LNKCAP_LBNC   0x00200000 /* Link Bandwidth Notification Capability */
 #define  PCI_EXP_LNKCAP_PN     0xff000000 /* Port Number */
 #define  PCI_EXP_LNKCTL_LABIE  0x0800  /* Lnk Autonomous Bandwidth Interrupt Enable */
 #define PCI_EXP_LNKSTA         18      /* Link Status */
 #define  PCI_EXP_LNKSTA_CLS    0x000f  /* Current Link Speed */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
 #define  PCI_EXP_LNKSTA_NLW    0x03f0  /* Nogotiated Link Width */
+#define  PCI_EXP_LNKSTA_NLW_SHIFT 4    /* start of NLW mask in link status */
 #define  PCI_EXP_LNKSTA_LT     0x0800  /* Link Training */
 #define  PCI_EXP_LNKSTA_SLC    0x1000  /* Slot Clock Configuration */
 #define  PCI_EXP_LNKSTA_DLLLA  0x2000  /* Data Link Layer Link Active */
 #define  PCI_EXP_RTCTL_CRSSVE  0x10    /* CRS Software Visibility Enable */
 #define PCI_EXP_RTCAP          30      /* Root Capabilities */
 #define PCI_EXP_RTSTA          32      /* Root Status */
+#define PCI_EXP_RTSTA_PME      0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING  0x20000 /* PME pending */
 #define PCI_EXP_DEVCAP2                36      /* Device Capabilities 2 */
 #define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
+#define  PCI_EXP_DEVCAP2_LTR   0x800   /* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MASK     0xc0000 /* OBFF support mechanism */
+#define  PCI_EXP_OBFF_MSG      0x40000 /* New message signaling */
+#define  PCI_EXP_OBFF_WAKE     0x80000 /* Re-use WAKE# for OBFF */
 #define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_ARI   0x20    /* Alternative Routing-ID */
+#define  PCI_EXP_IDO_REQ_EN    0x100   /* ID-based ordering request enable */
+#define  PCI_EXP_IDO_CMP_EN    0x200   /* ID-based ordering completion enable */
+#define  PCI_EXP_LTR_EN                0x400   /* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MSGA_EN  0x2000  /* OBFF enable with Message type A */
+#define  PCI_EXP_OBFF_MSGB_EN  0x4000  /* OBFF enable with Message type B */
+#define  PCI_EXP_OBFF_WAKE_EN  0x6000  /* OBFF using WAKE# signaling */
 #define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
 #define PCI_EXP_SLTCTL2                56      /* Slot Control 2 */
 
 #define PCI_EXT_CAP_ID_VC      2
 #define PCI_EXT_CAP_ID_DSN     3
 #define PCI_EXT_CAP_ID_PWR     4
+#define PCI_EXT_CAP_ID_VNDR    11
+#define PCI_EXT_CAP_ID_ACS     13
 #define PCI_EXT_CAP_ID_ARI     14
 #define PCI_EXT_CAP_ID_ATS     15
 #define PCI_EXT_CAP_ID_SRIOV   16
+#define PCI_EXT_CAP_ID_LTR     24
 
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
 #define PCI_ERR_ROOT_FIRST_FATAL       0x00000010      /* First Fatal */
 #define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020      /* Non-Fatal Received */
 #define PCI_ERR_ROOT_FATAL_RCV         0x00000040      /* Fatal Received */
-#define PCI_ERR_ROOT_COR_SRC   52
-#define PCI_ERR_ROOT_SRC       54
+#define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
 
 /* Virtual Channel */
 #define PCI_VC_PORT_REG1       4
 #define  PCI_SRIOV_VFM_MO      0x2     /* Active.MigrateOut */
 #define  PCI_SRIOV_VFM_AV      0x3     /* Active.Available */
 
+#define PCI_LTR_MAX_SNOOP_LAT  0x4
+#define PCI_LTR_MAX_NOSNOOP_LAT        0x6
+#define  PCI_LTR_VALUE_MASK    0x000003ff
+#define  PCI_LTR_SCALE_MASK    0x00001c00
+#define  PCI_LTR_SCALE_SHIFT   10
+
+/* Access Control Service */
+#define PCI_ACS_CAP            0x04    /* ACS Capability Register */
+#define  PCI_ACS_SV            0x01    /* Source Validation */
+#define  PCI_ACS_TB            0x02    /* Translation Blocking */
+#define  PCI_ACS_RR            0x04    /* P2P Request Redirect */
+#define  PCI_ACS_CR            0x08    /* P2P Completion Redirect */
+#define  PCI_ACS_UF            0x10    /* Upstream Forwarding */
+#define  PCI_ACS_EC            0x20    /* P2P Egress Control */
+#define  PCI_ACS_DT            0x40    /* Direct Translated P2P */
+#define PCI_ACS_CTRL           0x06    /* ACS Control Register */
+#define PCI_ACS_EGRESS_CTL_V   0x08    /* ACS Egress Control Vector */
+
 #endif /* LINUX_PCI_REGS_H */
index 6a113a9327bb1e4759b064c28c4dae490f2db6e2..5c9eb2f0ac305f9ae678e89ad70490d5ca43db05 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"
@@ -176,8 +175,16 @@ static void hotplug_event_notify(PCIDevice *dev)
     }
 }
 
+static void hotplug_event_clear(PCIDevice *dev)
+{
+    hotplug_event_update_event_status(dev);
+    if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
+        qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0);
+    }
+}
+
 /*
- * A PCI Express Hot-Plug Event has occured, so update slot status register
+ * A PCI Express Hot-Plug Event has occurred, so update slot status register
  * and notify OS of the event if necessary.
  *
  * 6.7.3 PCI Express Hot-Plug Events
@@ -321,6 +328,10 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
     uint8_t *exp_cap = dev->config + pos;
     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
 
+    if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
+        hotplug_event_clear(dev);
+    }
+
     if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
         return;
     }
index bc909e279339d082536c226ae2ec1a96f1cbcd89..a213fbaee86c4ff274fc37c0ef337195f93e6bdc 100644 (file)
--- a/hw/pcie.h
+++ b/hw/pcie.h
@@ -40,7 +40,7 @@ typedef enum {
      *
      * Not all the bits of slot control register match with the ones of
      * slot status. Not some bits of slot status register is used to
-     * show status, not to report event occurence.
+     * show status, not to report event occurrence.
      * So such bits must be masked out when checking the software
      * notification condition.
      */
index 6e653ddb92b0f5577b8a9aca2b815165500aaf0a..62c06eafd62663d8f4f568bac1624aedb996c51e 100644 (file)
@@ -38,6 +38,9 @@
 #define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
     PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
 
+#define PCI_ERR_SRC_COR_OFFS    0
+#define PCI_ERR_SRC_UNCOR_OFFS  2
+
 /* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
 static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
 {
@@ -108,7 +111,7 @@ int pcie_aer_init(PCIDevice *dev, uint16_t offset)
     if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
         return -EINVAL;
     }
-    dev->exp.aer_log.log = qemu_mallocz(sizeof dev->exp.aer_log.log[0] *
+    dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
                                         dev->exp.aer_log.log_max);
 
     pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
@@ -162,7 +165,7 @@ int pcie_aer_init(PCIDevice *dev, uint16_t offset)
 
 void pcie_aer_exit(PCIDevice *dev)
 {
-    qemu_free(dev->exp.aer_log.log);
+    g_free(dev->exp.aer_log.log);
 }
 
 static void pcie_aer_update_uncor_status(PCIDevice *dev)
@@ -320,7 +323,8 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         if (root_status & PCI_ERR_ROOT_COR_RCV) {
             root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
         } else {
-            pci_set_word(aer_cap + PCI_ERR_ROOT_COR_SRC, msg->source_id);
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS,
+                         msg->source_id);
         }
         root_status |= PCI_ERR_ROOT_COR_RCV;
         break;
@@ -341,7 +345,8 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
             root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
         } else {
-            pci_set_word(aer_cap + PCI_ERR_ROOT_SRC, msg->source_id);
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
+                         PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
         }
         root_status |= PCI_ERR_ROOT_UNCOR_RCV;
     }
@@ -410,7 +415,7 @@ static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
     int i;
 
     assert(err->status);
-    assert(err->status & (err->status - 1));
+    assert(!(err->status & (err->status - 1)));
 
     errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
     errcap |= PCI_ERR_CAP_FEP(first_bit);
@@ -490,7 +495,7 @@ static int pcie_aer_record_error(PCIDevice *dev,
     int fep = PCI_ERR_CAP_FEP(errcap);
 
     assert(err->status);
-    assert(err->status & (err->status - 1));
+    assert(!(err->status & (err->status - 1)));
 
     if (errcap & PCI_ERR_CAP_MHRE &&
         (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
@@ -612,7 +617,7 @@ static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
 /*
  * non-Function specific error must be recorded in all functions.
  * It is the responsibility of the caller of this function.
- * It is also caller's responsiblity to determine which function should
+ * It is also caller's responsibility to determine which function should
  * report the rerror.
  *
  * 6.2.4 Error Logging
@@ -785,16 +790,6 @@ static const VMStateDescription vmstate_pcie_aer_err = {
     }
 };
 
-#define VMSTATE_PCIE_AER_ERRS(_field, _state, _field_num, _vmsd, _type) { \
-    .name       = (stringify(_field)),                                    \
-    .version_id = 0,                                                      \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),     \
-    .size       = sizeof(_type),                                          \
-    .vmsd       = &(_vmsd),                                               \
-    .flags      = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT,           \
-    .offset     = vmstate_offset_pointer(_state, _field, _type),          \
-}
-
 const VMStateDescription vmstate_pcie_aer_log = {
     .name = "PCIE_AER_ERROR_LOG",
     .version_id = 1,
@@ -803,7 +798,7 @@ const VMStateDescription vmstate_pcie_aer_log = {
     .fields     = (VMStateField[]) {
         VMSTATE_UINT16(log_num, PCIEAERLog),
         VMSTATE_UINT16(log_max, PCIEAERLog),
-        VMSTATE_PCIE_AER_ERRS(log, PCIEAERLog, log_num,
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
                               vmstate_pcie_aer_err, PCIEAERErr),
         VMSTATE_END_OF_LIST()
     }
@@ -984,20 +979,21 @@ int do_pcie_aer_inejct_error(Monitor *mon,
     if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) {
         char *e = NULL;
         error_status = strtoul(error_name, &e, 0);
-        correctable = !!qdict_get_int(qdict, "correctable");
+        correctable = qdict_get_try_bool(qdict, "correctable", 0);
         if (!e || *e != '\0') {
             monitor_printf(mon, "invalid error status value. \"%s\"",
                            error_name);
             return -EINVAL;
         }
     }
+    err.status = error_status;
     err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
 
     err.flags = 0;
     if (correctable) {
         err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
     }
-    if (qdict_get_int(qdict, "advisory_non_fatal")) {
+    if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) {
         err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
     }
     if (qdict_haskey(qdict, "header0")) {
index 21069eed83656c0663ba80a4dcf4c09ec8e5978b..28bbe72b37079b9aabbca85e5191b815ebc67095 100644 (file)
@@ -22,6 +22,7 @@
 #include "hw.h"
 #include "pci.h"
 #include "pcie_host.h"
+#include "exec-memory.h"
 
 /*
  * PCI express mmcfig address
@@ -49,99 +50,71 @@ static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
                                                      uint32_t mmcfg_addr)
 {
     return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
-                           PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)),
-                           PCI_FUNC(PCIE_MMCFG_DEVFN(mmcfg_addr)));
+                           PCIE_MMCFG_DEVFN(mmcfg_addr));
 }
 
-static void pcie_mmcfg_data_write(PCIBus *s,
-                                  uint32_t mmcfg_addr, uint32_t val, int len)
+static void pcie_mmcfg_data_write(void *opaque, target_phys_addr_t mmcfg_addr,
+                                  uint64_t val, unsigned len)
 {
+    PCIExpressHost *e = opaque;
+    PCIBus *s = e->pci.bus;
     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
+    uint32_t addr;
+    uint32_t limit;
 
-    if (!pci_dev)
+    if (!pci_dev) {
         return;
-
-    pci_dev->config_write(pci_dev,
-                          PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len);
+    }
+    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
+    limit = pci_config_size(pci_dev);
+    if (limit <= addr) {
+        /* conventional pci device can be behind pcie-to-pci bridge.
+           256 <= addr < 4K has no effects. */
+        return;
+    }
+    pci_host_config_write_common(pci_dev, addr, limit, val, len);
 }
 
-static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len)
+static uint64_t pcie_mmcfg_data_read(void *opaque,
+                                     target_phys_addr_t mmcfg_addr,
+                                     unsigned len)
 {
-    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr);
+    PCIExpressHost *e = opaque;
+    PCIBus *s = e->pci.bus;
+    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
+    uint32_t addr;
+    uint32_t limit;
 
-    assert(len == 1 || len == 2 || len == 4);
     if (!pci_dev) {
         return ~0x0;
     }
-    return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len);
-}
-
-static void pcie_mmcfg_data_writeb(void *opaque,
-                                   target_phys_addr_t addr, uint32_t value)
-{
-    PCIExpressHost *e = opaque;
-    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1);
-}
-
-static void pcie_mmcfg_data_writew(void *opaque,
-                                   target_phys_addr_t addr, uint32_t value)
-{
-    PCIExpressHost *e = opaque;
-    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2);
-}
-
-static void pcie_mmcfg_data_writel(void *opaque,
-                                   target_phys_addr_t addr, uint32_t value)
-{
-    PCIExpressHost *e = opaque;
-    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4);
-}
-
-static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr)
-{
-    PCIExpressHost *e = opaque;
-    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1);
-}
-
-static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr)
-{
-    PCIExpressHost *e = opaque;
-    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2);
-}
-
-static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr)
-{
-    PCIExpressHost *e = opaque;
-    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4);
+    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
+    limit = pci_config_size(pci_dev);
+    if (limit <= addr) {
+        /* conventional pci device can be behind pcie-to-pci bridge.
+           256 <= addr < 4K has no effects. */
+        return ~0x0;
+    }
+    return pci_host_config_read_common(pci_dev, addr, limit, len);
 }
 
-
-static CPUWriteMemoryFunc * const pcie_mmcfg_write[] =
-{
-    pcie_mmcfg_data_writeb,
-    pcie_mmcfg_data_writew,
-    pcie_mmcfg_data_writel,
-};
-
-static CPUReadMemoryFunc * const pcie_mmcfg_read[] =
-{
-    pcie_mmcfg_data_readb,
-    pcie_mmcfg_data_readw,
-    pcie_mmcfg_data_readl,
+static const MemoryRegionOps pcie_mmcfg_ops = {
+    .read = pcie_mmcfg_data_read,
+    .write = pcie_mmcfg_data_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
 #define PCIE_BASE_ADDR_UNMAPPED  ((target_phys_addr_t)-1ULL)
 
-int pcie_host_init(PCIExpressHost *e)
+int pcie_host_init(PCIExpressHost *e, uint32_t size)
 {
+    assert(!(size & (size - 1)));       /* power of 2 */
+    assert(size >= PCIE_MMCFG_SIZE_MIN);
+    assert(size <= PCIE_MMCFG_SIZE_MAX);
     e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
-    e->mmio_index =
-        cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e,
-                               DEVICE_NATIVE_ENDIAN);
-    if (e->mmio_index < 0) {
-        return -1;
-    }
+    e->size = size;
+    memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size);
 
     return 0;
 }
@@ -149,29 +122,23 @@ int pcie_host_init(PCIExpressHost *e)
 void pcie_host_mmcfg_unmap(PCIExpressHost *e)
 {
     if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
-        cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED);
+        memory_region_del_subregion(get_system_memory(), &e->mmio);
         e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
     }
 }
 
-void pcie_host_mmcfg_map(PCIExpressHost *e,
-                         target_phys_addr_t addr, uint32_t size)
+void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr)
 {
-    assert(!(size & (size - 1)));       /* power of 2 */
-    assert(size >= PCIE_MMCFG_SIZE_MIN);
-    assert(size <= PCIE_MMCFG_SIZE_MAX);
-
     e->base_addr = addr;
-    e->size = size;
-    cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index);
+    memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
 }
 
 void pcie_host_mmcfg_update(PCIExpressHost *e,
                             int enable,
-                            target_phys_addr_t addr, uint32_t size)
+                            target_phys_addr_t addr)
 {
     pcie_host_mmcfg_unmap(e);
     if (enable) {
-        pcie_host_mmcfg_map(e, addr, size);
+        pcie_host_mmcfg_map(e, addr);
     }
 }
index a2026617b72042fa6d0b11f6d813336dfc52d59c..0074508b434141db19eb5efaf2574f05089578ff 100644 (file)
@@ -22,6 +22,7 @@
 #define PCIE_HOST_H
 
 #include "pci_host.h"
+#include "memory.h"
 
 struct PCIExpressHost {
     PCIHostState pci;
@@ -34,16 +35,15 @@ struct PCIExpressHost {
     /* the size of MMCONFIG area. It's host bridge dependent */
     target_phys_addr_t  size;
 
-    /* result of cpu_register_io_memory() to map MMCONFIG area */
-    int mmio_index;
+    /* MMCONFIG mmio area */
+    MemoryRegion mmio;
 };
 
-int pcie_host_init(PCIExpressHost *e);
+int pcie_host_init(PCIExpressHost *e, uint32_t size);
 void pcie_host_mmcfg_unmap(PCIExpressHost *e);
-void pcie_host_mmcfg_map(PCIExpressHost *e,
-                         target_phys_addr_t addr, uint32_t size);
+void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr);
 void pcie_host_mmcfg_update(PCIExpressHost *e,
                             int enable,
-                            target_phys_addr_t addr, uint32_t size);
+                            target_phys_addr_t addr);
 
 #endif /* PCIE_HOST_H */
index 340dcdb3c4b72c4b7176ce0cb12029f3073ff0f0..8a36f5cfc7a6d9f2480eb66c4c189f32cd0ac014 100644 (file)
@@ -76,7 +76,7 @@ void pcie_chassis_create(uint8_t chassis_number)
     if (c) {
         return;
     }
-    c = qemu_mallocz(sizeof(*c));
+    c = g_malloc0(sizeof(*c));
     c->number = chassis_number;
     QLIST_INIT(&c->slots);
     QLIST_INSERT_HEAD(&chassis, c, next);
index ae65c04da139debf94fb14b0c0c4a624e9494a1f..06b40c540c0d174bb70a439aa6ce5e9bc694b6c7 100644 (file)
@@ -400,33 +400,27 @@ static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value
         kbd_write_data(s, 0, value & 0xff);
 }
 
-static CPUReadMemoryFunc * const kbd_mm_read[] = {
-    &kbd_mm_readb,
-    &kbd_mm_readb,
-    &kbd_mm_readb,
-};
-
-static CPUWriteMemoryFunc * const kbd_mm_write[] = {
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
+static const MemoryRegionOps i8042_mmio_ops = {
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .old_mmio = {
+        .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
+        .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
+    },
 };
 
 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   target_phys_addr_t base, ram_addr_t size,
+                   MemoryRegion *region, ram_addr_t size,
                    target_phys_addr_t mask)
 {
-    KBDState *s = qemu_mallocz(sizeof(KBDState));
-    int s_io_memory;
+    KBDState *s = g_malloc0(sizeof(KBDState));
 
     s->irq_kbd = kbd_irq;
     s->irq_mouse = mouse_irq;
     s->mask = mask;
 
     vmstate_register(NULL, 0, &vmstate_kbd, s);
-    s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, s_io_memory);
+
+    memory_region_init_io(region, &i8042_mmio_ops, s, "i8042", size);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
@@ -435,7 +429,8 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
 
 typedef struct ISAKBDState {
     ISADevice dev;
-    KBDState  kbd;
+    KBDState kbd;
+    MemoryRegion io[2];
 } ISAKBDState;
 
 void i8042_isa_mouse_fake_event(void *opaque)
@@ -464,19 +459,37 @@ static const VMStateDescription vmstate_kbd_isa = {
     }
 };
 
+static const MemoryRegionPortio i8042_data_portio[] = {
+    { 0, 1, 1, .read = kbd_read_data, .write = kbd_write_data },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionPortio i8042_cmd_portio[] = {
+    { 0, 1, 1, .read = kbd_read_status, .write = kbd_write_command },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps i8042_data_ops = {
+    .old_portio = i8042_data_portio
+};
+
+static const MemoryRegionOps i8042_cmd_ops = {
+    .old_portio = i8042_cmd_portio
+};
+
 static int i8042_initfn(ISADevice *dev)
 {
-    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+    ISAKBDState *isa_s = DO_UPCAST(ISAKBDState, dev, dev);
+    KBDState *s = &isa_s->kbd;
 
     isa_init_irq(dev, &s->irq_kbd, 1);
     isa_init_irq(dev, &s->irq_mouse, 12);
 
-    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
-    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
-    isa_init_ioport(dev, 0x60);
-    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
-    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
-    isa_init_ioport(dev, 0x64);
+    memory_region_init_io(isa_s->io + 0, &i8042_data_ops, s, "i8042-data", 1);
+    isa_register_ioport(dev, isa_s->io + 0, 0x60);
+
+    memory_region_init_io(isa_s->io + 1, &i8042_cmd_ops, s, "i8042-cmd", 1);
+    isa_register_ioport(dev, isa_s->io + 1, 0x64);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
index 339a4019679778e1bd493ed89d3d3bb09b5c2c84..4e164da3ac74da6b43436def2d6b91f2ac8641d6 100644 (file)
@@ -31,6 +31,7 @@
 #include "net.h"
 #include "loader.h"
 #include "qemu-timer.h"
+#include "dma.h"
 
 #include "pcnet.h"
 
@@ -46,6 +47,7 @@
 typedef struct {
     PCIDevice pci_dev;
     PCNetState state;
+    MemoryRegion io_bar;
 } PCIPCNetState;
 
 static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
@@ -54,9 +56,9 @@ static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
 #ifdef PCNET_DEBUG
     printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
 #endif
-    /* Check APROMWE bit to enable write access */
-    if (pcnet_bcr_readw(s,2) & 0x100)
+    if (BCR_APROMWE(s)) {
         s->prom[addr & 15] = val;
+    }
 }
 
 static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
@@ -69,25 +71,65 @@ static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
+static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
-    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+    PCNetState *d = opaque;
 
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
-           addr, size);
-#endif
+    if (addr < 0x10) {
+        if (!BCR_DWIO(d) && size == 1) {
+            return pcnet_aprom_readb(d, addr);
+        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
+            return pcnet_aprom_readb(d, addr) |
+                   (pcnet_aprom_readb(d, addr + 1) << 8);
+        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
+            return pcnet_aprom_readb(d, addr) |
+                   (pcnet_aprom_readb(d, addr + 1) << 8) |
+                   (pcnet_aprom_readb(d, addr + 2) << 16) |
+                   (pcnet_aprom_readb(d, addr + 3) << 24);
+        }
+    } else {
+        if (size == 2) {
+            return pcnet_ioport_readw(d, addr);
+        } else if (size == 4) {
+            return pcnet_ioport_readl(d, addr);
+        }
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
 
-    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
-    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+static void pcnet_ioport_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t data, unsigned size)
+{
+    PCNetState *d = opaque;
 
-    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
-    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
-    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
-    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+    if (addr < 0x10) {
+        if (!BCR_DWIO(d) && size == 1) {
+            pcnet_aprom_writeb(d, addr, data);
+        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
+            pcnet_aprom_writeb(d, addr, data & 0xff);
+            pcnet_aprom_writeb(d, addr + 1, data >> 8);
+        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
+            pcnet_aprom_writeb(d, addr, data & 0xff);
+            pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
+            pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
+            pcnet_aprom_writeb(d, addr + 3, data >> 24);
+        }
+    } else {
+        if (size == 2) {
+            pcnet_ioport_writew(d, addr, data);
+        } else if (size == 4) {
+            pcnet_ioport_writel(d, addr, data);
+        }
+    }
 }
 
+static const MemoryRegionOps pcnet_io_ops = {
+    .read = pcnet_ioport_read,
+    .write = pcnet_ioport_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     PCNetState *d = opaque;
@@ -202,41 +244,24 @@ static const VMStateDescription vmstate_pci_pcnet = {
 
 /* PCI interface */
 
-static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
-    &pcnet_mmio_writeb,
-    &pcnet_mmio_writew,
-    &pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
-    &pcnet_mmio_readb,
-    &pcnet_mmio_readw,
-    &pcnet_mmio_readl
+static const MemoryRegionOps pcnet_mmio_ops = {
+    .old_mmio = {
+        .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
+        .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
-}
-
 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
                                       uint8_t *buf, int len, int do_bswap)
 {
-    cpu_physical_memory_write(addr, buf, len);
+    pci_dma_write(dma_opaque, addr, buf, len);
 }
 
 static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
                                      uint8_t *buf, int len, int do_bswap)
 {
-    cpu_physical_memory_read(addr, buf, len);
+    pci_dma_read(dma_opaque, addr, buf, len);
 }
 
 static void pci_pcnet_cleanup(VLANClientState *nc)
@@ -250,7 +275,8 @@ static int pci_pcnet_uninit(PCIDevice *dev)
 {
     PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
 
-    cpu_unregister_io_memory(d->state.mmio_index);
+    memory_region_destroy(&d->state.mmio);
+    memory_region_destroy(&d->io_bar);
     qemu_del_timer(d->state.poll_timer);
     qemu_free_timer(d->state.poll_timer);
     qemu_del_vlan_client(&d->state.nic->nc);
@@ -262,6 +288,7 @@ static NetClientInfo net_pci_pcnet_info = {
     .size = sizeof(NICState),
     .can_receive = pcnet_can_receive,
     .receive = pcnet_receive,
+    .link_status_changed = pcnet_set_link_status,
     .cleanup = pci_pcnet_cleanup,
 };
 
@@ -278,39 +305,35 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
 
     pci_conf = pci_dev->config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
     pci_set_word(pci_conf + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_conf[PCI_REVISION_ID] = 0x10;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
 
     pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
     pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
 
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
     pci_conf[PCI_MIN_GNT] = 0x06;
     pci_conf[PCI_MAX_LAT] = 0xff;
 
     /* Handler for memory-mapped I/O */
-    s->mmio_index =
-      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state,
-                             DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&d->state.mmio, &pcnet_mmio_ops, s, "pcnet-mmio",
+                          PCNET_PNPMMIO_SIZE);
 
-    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+    memory_region_init_io(&d->io_bar, &pcnet_io_ops, s, "pcnet-io",
+                          PCNET_IOPORT_SIZE);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
 
-    pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+    pci_register_bar(pci_dev, 1, 0, &s->mmio);
 
     s->irq = pci_dev->irq[0];
     s->phys_mem_read = pci_physical_memory_read;
     s->phys_mem_write = pci_physical_memory_write;
+    s->dma_opaque = 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;
         }
     }
@@ -332,6 +355,10 @@ static PCIDeviceInfo pcnet_info = {
     .qdev.vmsd  = &vmstate_pci_pcnet,
     .init       = pci_pcnet_init,
     .exit       = pci_pcnet_uninit,
+    .vendor_id  = PCI_VENDOR_ID_AMD,
+    .device_id  = PCI_DEVICE_ID_AMD_LANCE,
+    .revision   = 0x10,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
         DEFINE_PROP_END_OF_LIST(),
index db52dc59e18ade68945faaaef8efd5566edbe03f..cba253ba7b80e21057ceaaab42ac5a71779794d1 100644 (file)
@@ -58,24 +58,6 @@ struct qemu_ether_header {
     uint16_t ether_type;
 };
 
-/* BUS CONFIGURATION REGISTERS */
-#define BCR_MSRDA    0
-#define BCR_MSWRA    1
-#define BCR_MC       2
-#define BCR_LNKST    4
-#define BCR_LED1     5
-#define BCR_LED2     6
-#define BCR_LED3     7
-#define BCR_FDC      9
-#define BCR_BSBC     18
-#define BCR_EECAS    19
-#define BCR_SWS      20
-#define BCR_PLAT     22
-
-#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
-#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
-#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
-
 #define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
 #define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
 #define CSR_STOP(S)      !!(((S)->csr[0])&0x0004)
@@ -113,23 +95,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;
@@ -1215,6 +1197,13 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
     return size_;
 }
 
+void pcnet_set_link_status(VLANClientState *nc)
+{
+    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    d->lnkst = nc->link_down ? 0 : 0x40;
+}
+
 static void pcnet_transmit(PCNetState *s)
 {
     target_phys_addr_t xmit_cxda = 0;
@@ -1336,7 +1325,7 @@ static void pcnet_poll_timer(void *opaque)
     pcnet_update_irq(s);
 
     if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
-        uint64_t now = qemu_get_clock(vm_clock) * 33;
+        uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
         if (!s->timer || !now)
             s->timer = now;
         else {
@@ -1348,7 +1337,7 @@ static void pcnet_poll_timer(void *opaque)
                 CSR_POLL(s) = t;
         }
         qemu_mod_timer(s->poll_timer,
-            pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
+            pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
     }
 }
 
@@ -1557,19 +1546,6 @@ uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
 void pcnet_h_reset(void *opaque)
 {
     PCNetState *s = opaque;
-    int i;
-    uint16_t checksum;
-
-    /* Initialize the PROM */
-
-    memcpy(s->prom, s->conf.macaddr.a, 6);
-    s->prom[12] = s->prom[13] = 0x00;
-    s->prom[14] = s->prom[15] = 0x57;
-
-    for (i = 0,checksum = 0; i < 16; i++)
-        checksum += s->prom[i];
-    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
-
 
     s->bcr[BCR_MSRDA] = 0x0005;
     s->bcr[BCR_MSWRA] = 0x0005;
@@ -1736,7 +1712,10 @@ void pcnet_common_cleanup(PCNetState *d)
 
 int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
 {
-    s->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, s);
+    int i;
+    uint16_t checksum;
+
+    s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
@@ -1744,5 +1723,32 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
 
     add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
 
+    /* Initialize the PROM */
+
+    /*
+      Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
+      page 95
+    */
+    memcpy(s->prom, s->conf.macaddr.a, 6);
+    /* Reserved Location: must be 00h */
+    s->prom[6] = s->prom[7] = 0x00;
+    /* Reserved Location: must be 00h */
+    s->prom[8] = 0x00;
+    /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
+    s->prom[9] = 0x11;
+    /* User programmable space, init with 0 */
+    s->prom[10] = s->prom[11] = 0x00;
+    /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
+       and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
+    s->prom[12] = s->prom[13] = 0x00;
+    /* Must be ASCII W (57h) if compatibility to AMD
+       driver software is desired */
+    s->prom[14] = s->prom[15] = 0x57;
+
+    for (i = 0, checksum = 0; i < 16; i++) {
+        checksum += s->prom[i];
+    }
+    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+
     return 0;
 }
index 534bdf9c2be32f839652f7ba7762a905c6dd267e..edc81c90ac928c52fd40bebbfe8ec721d861728a 100644 (file)
@@ -4,6 +4,26 @@
 #define PCNET_LOOPTEST_CRC     1
 #define PCNET_LOOPTEST_NOCRC   2
 
+#include "memory.h"
+
+/* BUS CONFIGURATION REGISTERS */
+#define BCR_MSRDA    0
+#define BCR_MSWRA    1
+#define BCR_MC       2
+#define BCR_LNKST    4
+#define BCR_LED1     5
+#define BCR_LED2     6
+#define BCR_LED3     7
+#define BCR_FDC      9
+#define BCR_BSBC     18
+#define BCR_EECAS    19
+#define BCR_SWS      20
+#define BCR_PLAT     22
+
+#define BCR_APROMWE(S)   !!((S)->bcr[BCR_MC  ] & 0x0100)
+#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
+#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
+#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
 
 typedef struct PCNetState_st PCNetState;
 
@@ -16,16 +36,17 @@ struct PCNetState_st {
     uint8_t prom[16];
     uint16_t csr[128];
     uint16_t bcr[32];
+    int xmit_pos;
     uint64_t timer;
-    int mmio_index, xmit_pos;
+    MemoryRegion mmio;
     uint8_t buffer[4096];
-    int tx_busy;
     qemu_irq irq;
     void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
                          uint8_t *buf, int len, int do_bswap);
     void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
                           uint8_t *buf, int len, int do_bswap);
     void *dma_opaque;
+    int tx_busy;
     int looptest;
 };
 
@@ -37,6 +58,7 @@ uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
 uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
 int pcnet_can_receive(VLANClientState *nc);
 ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
+void pcnet_set_link_status(VLANClientState *nc);
 void pcnet_common_cleanup(PCNetState *d);
 int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
 extern const VMStateDescription vmstate_pcnet;
index 26a0ecb9dfb8612e8fe8eb9dacfca775cc81ecc8..7fa2d36620e91c48289a1eaa2af2c1090e7538ff 100644 (file)
@@ -37,7 +37,7 @@ typedef struct {
     uint8_t sample_buf[PCSPK_BUF_LEN];
     QEMUSoundCard card;
     SWVoiceOut *voice;
-    PITState *pit;
+    ISADevice *pit;
     unsigned int pit_count;
     unsigned int samples;
     unsigned int play_pos;
@@ -118,7 +118,7 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
     int out;
 
     s->dummy_refresh_clock ^= (1 << 4);
-    out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
+    out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5;
 
     return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
 }
@@ -137,7 +137,7 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-void pcspk_init(PITState *pit)
+void pcspk_init(ISADevice *pit)
 {
     PCSpkState *s = &pcspk_state;
 
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
new file mode 100644 (file)
index 0000000..fb4ba29
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
+ * board.
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2011 PetaLogix
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "xilinx.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "pc.h"
+#include "exec-memory.h"
+
+#include "microblaze_pic_cpu.h"
+#include "xilinx_axidma.h"
+
+#define LMB_BRAM_SIZE  (128 * 1024)
+#define FLASH_SIZE     (32 * 1024 * 1024)
+
+static struct
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+} boot_info;
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->regs[5] = boot_info.cmdline;
+    env->regs[7] = boot_info.fdt;
+    env->sregs[SR_PC] = boot_info.bootstrap_pc;
+    env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
+    /* setup pvr to match kernel setting */
+    env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK;
+    env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI;
+    env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8);
+    env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK;
+    env->pvr.regs[4] = 0xc56b8000;
+    env->pvr.regs[5] = 0xc56be000;
+}
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb"
+static int petalogix_load_device_tree(target_phys_addr_t addr,
+                                      uint32_t ramsize,
+                                      target_phys_addr_t initrd_base,
+                                      target_phys_addr_t initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "mb.dtb" override.  */
+    fdt = load_device_tree("mb.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            g_free(path);
+        }
+        if (!fdt) {
+            return 0;
+        }
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0) {
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    }
+    cpu_physical_memory_write(addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+            g_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x30000000LL;
+}
+
+#define MEMORY_BASEADDR 0x50000000
+#define FLASH_BASEADDR 0x86000000
+#define INTC_BASEADDR 0x81800000
+#define TIMER_BASEADDR 0x83c00000
+#define UART16550_BASEADDR 0x83e00000
+#define AXIENET_BASEADDR 0x82780000
+#define AXIDMA_BASEADDR 0x84600000
+
+static void
+petalogix_ml605_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)
+{
+    MemoryRegion *address_space_mem = get_system_memory();
+    DeviceState *dev;
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    int i;
+    target_phys_addr_t ddr_base = MEMORY_BASEADDR;
+    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    qemu_irq irq[32], *cpu_irq;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "microblaze";
+    }
+    env = cpu_init(cpu_model);
+
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* Attach emulated BRAM through the LMB.  */
+    memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_ml605.lmb_bram",
+                           LMB_BRAM_SIZE);
+    memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram);
+
+    memory_region_init_ram(phys_ram, NULL, "petalogix_ml605.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, ddr_base, phys_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* 5th parameter 2 means bank-width
+     * 10th paremeter 0 means little-endian */
+    pflash_cfi01_register(FLASH_BASEADDR,
+                          NULL, "petalogix_ml605.flash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          2, 0x89, 0x18, 0x0000, 0x0, 0);
+
+
+    cpu_irq = microblaze_pic_init_cpu(env);
+    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
+                   irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
+
+    /* 2 timers at irq 2 @ 100 Mhz.  */
+    xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
+
+    /* axi ethernet and dma initialization. TODO: Dynamically connect them.  */
+    {
+        static struct XilinxDMAConnection dmach;
+
+        xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
+                                  irq[3], 0x1000, 0x1000);
+        xilinx_axiethernetdma_create(&dmach, 0x84600000,
+                                     irq[1], irq[0], 100 * 1000000);
+    }
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        uint32_t base32;
+        int big_endian = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        big_endian = 1;
+#endif
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high,
+                               big_endian, ELF_MACHINE, 0);
+        base32 = entry;
+        if (base32 == 0xc0000000) {
+            kernel_size = load_elf(kernel_filename, translate_kernel_address,
+                                   NULL, &entry, NULL, NULL,
+                                   big_endian, ELF_MACHINE, 0);
+        }
+        /* Always boot into physical ram.  */
+        boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+        /* If it wasn't an ELF image, try an u-boot image.  */
+        if (kernel_size < 0) {
+            target_phys_addr_t uentry, loadaddr;
+
+            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+            boot_info.bootstrap_pc = uentry;
+            high = (loadaddr + kernel_size + 3) & ~3;
+        }
+
+        /* Not an ELF image nor an u-boot image, try a RAW image.  */
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ddr_base,
+                                              ram_size);
+            boot_info.bootstrap_pc = ddr_base;
+            high = (ddr_base + kernel_size + 3) & ~3;
+        }
+
+        boot_info.cmdline = high + 4096;
+        if (kernel_cmdline && strlen(kernel_cmdline)) {
+            pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
+        }
+        /* Provide a device-tree.  */
+        boot_info.fdt = boot_info.cmdline + 4096;
+        petalogix_load_device_tree(boot_info.fdt, ram_size,
+                                   0, 0,
+                                   kernel_cmdline);
+    }
+}
+
+static QEMUMachine petalogix_ml605_machine = {
+    .name = "petalogix-ml605",
+    .desc = "PetaLogix linux refdesign for xilinx ml605 little endian",
+    .init = petalogix_ml605_init,
+    .is_default = 0
+};
+
+static void petalogix_ml605_machine_init(void)
+{
+    qemu_register_machine(&petalogix_ml605_machine);
+}
+
+machine_init(petalogix_ml605_machine_init);
index 42de45963ba959179ad858015d13d7644dd55c0a..17da2fd87c57aa3349c15df905b0065782e2809a 100644 (file)
@@ -35,6 +35,9 @@
 #include "loader.h"
 #include "elf.h"
 #include "blockdev.h"
+#include "exec-memory.h"
+
+#include "microblaze_pic_cpu.h"
 
 #define LMB_BRAM_SIZE  (128 * 1024)
 #define FLASH_SIZE     (16 * 1024 * 1024)
@@ -75,7 +78,7 @@ static int petalogix_load_device_tree(target_phys_addr_t addr,
         path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
         if (path) {
             fdt = load_device_tree(path, &fdt_size);
-            qemu_free(path);
+            g_free(path);
         }
         if (!fdt)
             return 0;
@@ -93,7 +96,7 @@ static int petalogix_load_device_tree(target_phys_addr_t addr,
         path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
         if (path) {
             fdt_size = load_image_targphys(path, addr, 0x10000);
-           qemu_free(path);
+           g_free(path);
         }
     }
 
@@ -123,10 +126,10 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
     DriveInfo *dinfo;
     int i;
     target_phys_addr_t ddr_base = 0x90000000;
-    ram_addr_t phys_lmb_bram;
-    ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
+    MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
     qemu_irq irq[32], *cpu_irq;
+    MemoryRegion *sysmem = get_system_memory();
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -138,17 +141,17 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
     qemu_register_reset(main_cpu_reset, env);
 
     /* Attach emulated BRAM through the LMB.  */
-    phys_lmb_bram = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.lmb_bram",
-                                   LMB_BRAM_SIZE);
-    cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE,
-                                 phys_lmb_bram | IO_MEM_RAM);
+    memory_region_init_ram(phys_lmb_bram, NULL,
+                           "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE);
+    memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
 
-    phys_ram = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.ram", ram_size);
-    cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
+    memory_region_init_ram(phys_ram, NULL, "petalogix_s3adsp1800.ram",
+                           ram_size);
+    memory_region_add_subregion(sysmem, ddr_base, phys_ram);
 
-    phys_flash = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE);
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(0xa0000000, phys_flash,
+    pflash_cfi01_register(0xa0000000,
+                          NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                           FLASH_SIZE >> 16,
                           1, 0x89, 0x18, 0x0000, 0x0, 1);
@@ -167,16 +170,21 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
     if (kernel_filename) {
         uint64_t entry, low, high;
         uint32_t base32;
+        int big_endian = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        big_endian = 1;
+#endif
 
         /* Boots a kernel elf binary.  */
         kernel_size = load_elf(kernel_filename, NULL, NULL,
                                &entry, &low, &high,
-                               1, ELF_MACHINE, 0);
+                               big_endian, ELF_MACHINE, 0);
         base32 = entry;
         if (base32 == 0xc0000000) {
             kernel_size = load_elf(kernel_filename, translate_kernel_address,
                                    NULL, &entry, NULL, NULL,
-                                   1, ELF_MACHINE, 0);
+                                   big_endian, ELF_MACHINE, 0);
         }
         /* Always boot into physical ram.  */
         boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
@@ -212,7 +220,7 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
 
 static QEMUMachine petalogix_s3adsp1800_machine = {
     .name = "petalogix-s3adsp1800",
-    .desc = "Petalogix linux refdesign for xilinx Spartan 3ADSP1800",
+    .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800",
     .init = petalogix_s3adsp1800_init,
     .is_default = 1
 };
index fb20dfb6ff3eb35f6079bd78b960509e609d6ab7..69b8e3d5399cd8d1dcb941cd19f757bff1dd29f5 100644 (file)
@@ -40,6 +40,7 @@
 #include "flash.h"
 #include "block.h"
 #include "qemu-timer.h"
+#include "exec-memory.h"
 
 #define PFLASH_BUG(fmt, ...) \
 do { \
@@ -74,8 +75,7 @@ struct pflash_t {
     target_phys_addr_t counter;
     unsigned int writeblock_size;
     QEMUTimer *timer;
-    ram_addr_t off;
-    int fl_mem;
+    MemoryRegion mem;
     void *storage;
 };
 
@@ -89,8 +89,7 @@ static void pflash_timer (void *opaque)
     if (pfl->bypass) {
         pfl->wcycle = 2;
     } else {
-        cpu_register_physical_memory(pfl->base, pfl->total_len,
-                        pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+        memory_region_rom_device_set_readable(&pfl->mem, true);
         pfl->wcycle = 0;
     }
     pfl->cmd = 0;
@@ -263,7 +262,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
 
     if (!pfl->wcycle) {
         /* Set the device in I/O access mode */
-        cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+        memory_region_rom_device_set_readable(&pfl->mem, false);
     }
 
     switch (pfl->wcycle) {
@@ -422,8 +421,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
            __func__, offset, pfl->wcycle, pfl->cmd, value);
 
  reset_flash:
-    cpu_register_physical_memory(pfl->base, pfl->total_len,
-                    pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+    memory_region_rom_device_set_readable(&pfl->mem, true);
 
     pfl->bypass = 0;
     pfl->wcycle = 0;
@@ -514,28 +512,20 @@ static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
     pflash_write(pfl, addr, value, 4, 0);
 }
 
-static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
-    &pflash_writeb_be,
-    &pflash_writew_be,
-    &pflash_writel_be,
+static const MemoryRegionOps pflash_cfi01_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
-    &pflash_readb_be,
-    &pflash_readw_be,
-    &pflash_readl_be,
-};
-
-static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
-    &pflash_writeb_le,
-    &pflash_writew_le,
-    &pflash_writel_le,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
-    &pflash_readb_le,
-    &pflash_readw_le,
-    &pflash_readl_le,
+static const MemoryRegionOps pflash_cfi01_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Count trailing zeroes of a 32 bits quantity */
@@ -574,12 +564,13 @@ static int ctz32 (uint32_t n)
     return ret;
 }
 
-pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi01_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3,
-                                int be)
+                                uint16_t id2, uint16_t id3, int be)
 {
     pflash_t *pfl;
     target_phys_addr_t total_len;
@@ -594,32 +585,25 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
         return NULL;
 #endif
 
-    pfl = qemu_mallocz(sizeof(pflash_t));
+    pfl = g_malloc0(sizeof(pflash_t));
 
-    /* FIXME: Allocate ram ourselves.  */
-    pfl->storage = qemu_get_ram_ptr(off);
-    if (be) {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
-                                             pflash_write_ops_be, pfl,
-                                             DEVICE_NATIVE_ENDIAN);
-    } else {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
-                                             pflash_write_ops_le, pfl,
-                                             DEVICE_NATIVE_ENDIAN);
-    }
-    pfl->off = off;
-    cpu_register_physical_memory(base, total_len,
-                    off | pfl->fl_mem | IO_MEM_ROMD);
+    memory_region_init_rom_device(
+        &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
+        qdev, name, size);
+    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
+    memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
 
     pfl->bs = bs;
     if (pfl->bs) {
         /* read the initial flash content */
         ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
         if (ret < 0) {
-            cpu_unregister_io_memory(pfl->fl_mem);
-            qemu_free(pfl);
+            memory_region_del_subregion(get_system_memory(), &pfl->mem);
+            memory_region_destroy(&pfl->mem);
+            g_free(pfl);
             return NULL;
         }
+        bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
 #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
@@ -628,7 +612,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
 #else
     pfl->ro = 0;
 #endif
-    pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
     pfl->base = base;
     pfl->sector_len = sector_len;
     pfl->total_len = total_len;
@@ -724,3 +708,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
 
     return pfl;
 }
+
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
+{
+    return &fl->mem;
+}
index 3594a36f8d7d7460c8b66e5d320dafaaf0512076..e5a63da595b8819a84ab2db06fd7cbe1e1793b39 100644 (file)
@@ -39,6 +39,7 @@
 #include "flash.h"
 #include "qemu-timer.h"
 #include "block.h"
+#include "exec-memory.h"
 
 //#define PFLASH_DEBUG
 #ifdef PFLASH_DEBUG
@@ -50,6 +51,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;
@@ -67,24 +70,38 @@ struct pflash_t {
     uint8_t cfi_len;
     uint8_t cfi_table[0x52];
     QEMUTimer *timer;
-    ram_addr_t off;
-    int fl_mem;
+    /* The device replicates the flash memory across its memory space.  Emulate
+     * that by having a container (.mem) filled with an array of aliases
+     * (.mem_mappings) pointing to the flash memory (.orig_mem).
+     */
+    MemoryRegion mem;
+    MemoryRegion *mem_mappings;    /* array; one per mapping */
+    MemoryRegion orig_mem;
     int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
-static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+/*
+ * Set up replicated mappings of the same region.
+ */
+static void pflash_setup_mappings(pflash_t *pfl)
 {
-    unsigned long phys_offset = pfl->fl_mem;
-    int i;
-
-    if (rom_mode)
-        phys_offset |= pfl->off | IO_MEM_ROMD;
-    pfl->rom_mode = rom_mode;
+    unsigned i;
+    target_phys_addr_t size = memory_region_size(&pfl->orig_mem);
+
+    memory_region_init(&pfl->mem, "pflash", pfl->mappings * size);
+    pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
+    for (i = 0; i < pfl->mappings; ++i) {
+        memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias",
+                                 &pfl->orig_mem, 0, size);
+        memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
+    }
+}
 
-    for (i = 0; i < pfl->mappings; i++)
-        cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
-                                     pfl->chip_len, phys_offset);
+static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+{
+    memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
 }
 
 static void pflash_timer (void *opaque)
@@ -112,10 +129,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;
@@ -185,7 +202,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
         default:
             goto flash_read;
         }
-        DPRINTF("%s: ID " TARGET_FMT_pld " %x\n", __func__, boff, ret);
+        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
         break;
     case 0xA0:
     case 0x10:
@@ -254,6 +271,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) {
@@ -363,7 +381,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
     case 4:
         switch (pfl->cmd) {
         case 0xA0:
-            /* Ignore writes while flash data write is occuring */
+            /* Ignore writes while flash data write is occurring */
             /* As we suppose write is immediate, this should never happen */
             return;
         case 0x80:
@@ -390,7 +408,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
             pflash_update(pfl, 0, pfl->chip_len);
             /* Let's wait 5 seconds before chip erase is done */
             qemu_mod_timer(pfl->timer,
-                           qemu_get_clock(vm_clock) + (get_ticks_per_sec() * 5));
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
             break;
         case 0x30:
             /* Sector erase */
@@ -403,7 +421,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
             pfl->status = 0x00;
             /* Let's wait 1/2 second before sector erase is done */
             qemu_mod_timer(pfl->timer,
-                           qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 2));
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
             break;
         default:
             DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
@@ -534,28 +552,20 @@ static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
     pflash_write(pfl, addr, value, 4, 0);
 }
 
-static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
-    &pflash_writeb_be,
-    &pflash_writew_be,
-    &pflash_writel_be,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
-    &pflash_readb_be,
-    &pflash_readw_be,
-    &pflash_readl_be,
+static const MemoryRegionOps pflash_cfi02_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
-    &pflash_writeb_le,
-    &pflash_writew_le,
-    &pflash_writel_le,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
-    &pflash_readb_le,
-    &pflash_readw_le,
-    &pflash_readl_le,
+static const MemoryRegionOps pflash_cfi02_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Count trailing zeroes of a 32 bits quantity */
@@ -594,7 +604,9 @@ static int ctz32 (uint32_t n)
     return ret;
 }
 
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi02_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int nb_mappings, int width,
                                 uint16_t id0, uint16_t id1,
@@ -613,33 +625,27 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
         total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
         return NULL;
 #endif
-    pfl = qemu_mallocz(sizeof(pflash_t));
-    /* FIXME: Allocate ram ourselves.  */
-    pfl->storage = qemu_get_ram_ptr(off);
-    if (be) {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
-                                             pflash_write_ops_be,
-                                             pfl, DEVICE_NATIVE_ENDIAN);
-    } else {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
-                                             pflash_write_ops_le,
-                                             pfl, DEVICE_NATIVE_ENDIAN);
-    }
-    pfl->off = off;
+    pfl = g_malloc0(sizeof(pflash_t));
+    memory_region_init_rom_device(
+        &pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
+        qdev, name, size);
+    pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
     pfl->base = base;
     pfl->chip_len = chip_len;
     pfl->mappings = nb_mappings;
-    pflash_register_memory(pfl, 1);
     pfl->bs = bs;
     if (pfl->bs) {
         /* read the initial flash content */
         ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
         if (ret < 0) {
-            cpu_unregister_io_memory(pfl->fl_mem);
-            qemu_free(pfl);
+            g_free(pfl);
             return NULL;
         }
+        bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
+    pflash_setup_mappings(pfl);
+    pfl->rom_mode = 1;
+    memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
 #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
        */
@@ -647,7 +653,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
 #else
     pfl->ro = 0;
 #endif
-    pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
     pfl->sector_len = sector_len;
     pfl->width = width;
     pfl->wcycle = 0;
index 72073cd0a094da3e292df2fbd0f5992911d18b03..2fd1171328efdfdd0bb613cedc42c042ae557d02 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,23 @@ 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)
 {
-    uint8_t *pci_conf;
-
-    isa_bus_new(&d->qdev);
-    register_savevm(&d->qdev, "PIIX4", 0, 2, piix_save, piix_load, d);
-
-    pci_conf = d->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);
+    PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
 
-    piix4_dev = d;
+    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
+    piix4_dev = &d->dev;
     qemu_register_reset(piix4_reset, d);
     return 0;
 }
@@ -111,10 +105,14 @@ 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,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
     },{
         /* end of list */
     }
index 358da58a800651e1cdcc3258fda33424f5caca9b..d183443b2f5d235f129115f033856a1263c92798 100644 (file)
@@ -29,6 +29,7 @@
 #include "isa.h"
 #include "sysbus.h"
 #include "range.h"
+#include "xen.h"
 
 /*
  * I440FX chipset data sheet.
 
 typedef PCIHostState I440FXState;
 
+#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
+#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
+#define XEN_PIIX_NUM_PIRQS      128ULL
+#define PIIX_PIRQC              0x60
+
 typedef struct PIIX3State {
     PCIDevice dev;
-    int pci_irq_levels[4];
+
+    /*
+     * bitmap to track pic levels.
+     * The pic level is the logical OR of all the PCI irqs mapped to it
+     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+     *
+     * PIRQ is mapped to PIC pins, we track it by
+     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
+     * pic_irq * PIIX_NUM_PIRQS + pirq
+     */
+#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+    uint64_t pic_levels;
+
     qemu_irq *pic;
+
+    /* This member isn't used. Just for save/load compatibility */
+    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
 } PIIX3State;
 
+typedef struct PAMMemoryRegion {
+    MemoryRegion mem;
+    bool initialized;
+} PAMMemoryRegion;
+
 struct PCII440FXState {
     PCIDevice dev;
-    target_phys_addr_t isa_page_descs[384 / 4];
+    MemoryRegion *system_memory;
+    MemoryRegion *pci_address_space;
+    MemoryRegion *ram_memory;
+    MemoryRegion pci_hole;
+    MemoryRegion pci_hole_64bit;
+    PAMMemoryRegion pam_regions[13];
+    MemoryRegion smram_region;
     uint8_t smm_enabled;
+    bool smram_enabled;
     PIIX3State *piix3;
 };
 
@@ -55,64 +90,80 @@ struct PCII440FXState {
 #define I440FX_PAM_SIZE 7
 #define I440FX_SMRAM    0x72
 
-static void piix3_set_irq(void *opaque, int irq_num, int level);
+static void piix3_set_irq(void *opaque, int pirq, int level);
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len);
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
    mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
 {
     int slot_addend;
     slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (irq_num + slot_addend) & 3;
+    return (pci_intx + slot_addend) & 3;
 }
 
-static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
+static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r,
+                       PAMMemoryRegion *mem)
 {
-    uint32_t addr;
+    if (mem->initialized) {
+        memory_region_del_subregion(d->system_memory, &mem->mem);
+        memory_region_destroy(&mem->mem);
+    }
 
     //    printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
     switch(r) {
     case 3:
         /* RAM */
-        cpu_register_physical_memory(start, end - start,
-                                     start);
+        memory_region_init_alias(&mem->mem, "pam-ram", d->ram_memory,
+                                 start, end - start);
         break;
     case 1:
         /* ROM (XXX: not quite correct) */
-        cpu_register_physical_memory(start, end - start,
-                                     start | IO_MEM_ROM);
+        memory_region_init_alias(&mem->mem, "pam-rom", d->ram_memory,
+                                 start, end - start);
+        memory_region_set_readonly(&mem->mem, true);
         break;
     case 2:
     case 0:
         /* XXX: should distinguish read/write cases */
-        for(addr = start; addr < end; addr += 4096) {
-            cpu_register_physical_memory(addr, 4096,
-                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
-        }
+        memory_region_init_alias(&mem->mem, "pam-pci", d->pci_address_space,
+                                 start, end - start);
         break;
     }
+    memory_region_add_subregion_overlap(d->system_memory,
+                                        start, &mem->mem, 1);
+    mem->initialized = true;
 }
 
 static void i440fx_update_memory_mappings(PCII440FXState *d)
 {
     int i, r;
-    uint32_t smram, addr;
+    uint32_t smram;
 
-    update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3);
+    memory_region_transaction_begin();
+    update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3,
+               &d->pam_regions[0]);
     for(i = 0; i < 12; i++) {
         r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
-        update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
+        update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r,
+                   &d->pam_regions[i+1]);
     }
     smram = d->dev.config[I440FX_SMRAM];
     if ((d->smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
-        cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
+        if (!d->smram_enabled) {
+            memory_region_del_subregion(d->system_memory, &d->smram_region);
+            d->smram_enabled = true;
+        }
     } else {
-        for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
-            cpu_register_physical_memory(addr, 4096,
-                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
+        if (d->smram_enabled) {
+            memory_region_add_subregion_overlap(d->system_memory, 0xa0000,
+                                                &d->smram_region, 1);
+            d->smram_enabled = false;
         }
     }
+    memory_region_transaction_commit();
 }
 
 static void i440fx_set_smm(int val, void *arg)
@@ -127,17 +178,6 @@ static void i440fx_set_smm(int val, void *arg)
 }
 
 
-/* XXX: suppress when better memory API. We make the assumption that
-   no device (in particular the VGA) changes the memory mappings in
-   the 0xa0000-0x100000 range */
-void i440fx_init_memory_mappings(PCII440FXState *d)
-{
-    int i;
-    for(i = 0; i < 96; i++) {
-        d->isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
-    }
-}
-
 static void i440fx_write_config(PCIDevice *dev,
                                 uint32_t address, uint32_t val, int len)
 {
@@ -162,9 +202,11 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
     i440fx_update_memory_mappings(d);
     qemu_get_8s(f, &d->smm_enabled);
 
-    if (version_id == 2)
-        for (i = 0; i < 4; i++)
-            d->piix3->pci_irq_levels[i] = qemu_get_be32(f);
+    if (version_id == 2) {
+        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+            qemu_get_be32(f); /* dummy load for compatibility */
+        }
+    }
 
     return 0;
 }
@@ -195,9 +237,16 @@ static int i440fx_pcihost_initfn(SysBusDevice *dev)
 {
     I440FXState *s = FROM_SYSBUS(I440FXState, dev);
 
-    pci_host_conf_register_ioport(0xcf8, s);
+    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
+                          "pci-conf-idx", 4);
+    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
+    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
+
+    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
+                          "pci-conf-data", 4);
+    sysbus_add_io(dev, 0xcfc, &s->data_mem);
+    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
 
-    pci_host_data_register_ioport(0xcfc, s);
     return 0;
 }
 
@@ -205,38 +254,78 @@ static int i440fx_initfn(PCIDevice *dev)
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82441);
-    d->dev.config[0x08] = 0x02; // revision
-    pci_config_set_class(d->dev.config, PCI_CLASS_BRIDGE_HOST);
-
     d->dev.config[I440FX_SMRAM] = 0x02;
 
     cpu_smm_register(&i440fx_set_smm, d);
     return 0;
 }
 
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic, ram_addr_t ram_size)
+static PCIBus *i440fx_common_init(const char *device_name,
+                                  PCII440FXState **pi440fx_state,
+                                  int *piix3_devfn,
+                                  qemu_irq *pic,
+                                  MemoryRegion *address_space_mem,
+                                  MemoryRegion *address_space_io,
+                                  ram_addr_t ram_size,
+                                  target_phys_addr_t pci_hole_start,
+                                  target_phys_addr_t pci_hole_size,
+                                  target_phys_addr_t pci_hole64_start,
+                                  target_phys_addr_t pci_hole64_size,
+                                  MemoryRegion *pci_address_space,
+                                  MemoryRegion *ram_memory)
 {
     DeviceState *dev;
     PCIBus *b;
     PCIDevice *d;
     I440FXState *s;
     PIIX3State *piix3;
+    PCII440FXState *f;
 
     dev = qdev_create(NULL, "i440FX-pcihost");
     s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
-    b = pci_bus_new(&s->busdev.qdev, NULL, 0);
+    s->address_space = address_space_mem;
+    b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
+                    address_space_io, 0);
     s->bus = b;
     qdev_init_nofail(dev);
 
-    d = pci_create_simple(b, 0, "i440FX");
+    d = pci_create_simple(b, 0, device_name);
     *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
-
-    piix3 = DO_UPCAST(PIIX3State, dev,
-                      pci_create_simple_multifunction(b, -1, true, "PIIX3"));
+    f = *pi440fx_state;
+    f->system_memory = address_space_mem;
+    f->pci_address_space = pci_address_space;
+    f->ram_memory = ram_memory;
+    memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space,
+                             pci_hole_start, pci_hole_size);
+    memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
+    memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64",
+                             f->pci_address_space,
+                             pci_hole64_start, pci_hole64_size);
+    if (pci_hole64_size) {
+        memory_region_add_subregion(f->system_memory, pci_hole64_start,
+                                    &f->pci_hole_64bit);
+    }
+    memory_region_init_alias(&f->smram_region, "smram-region",
+                             f->pci_address_space, 0xa0000, 0x20000);
+    f->smram_enabled = true;
+
+    /* Xen supports additional interrupt routes from the PCI devices to
+     * the IOAPIC: the four pins of each PCI device on the bus are also
+     * connected to the IOAPIC directly.
+     * These additional routes can be discovered through ACPI. */
+    if (xen_enabled()) {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
+        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+                piix3, XEN_PIIX_NUM_PIRQS);
+    } else {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
+        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
+                PIIX_NUM_PIRQS);
+    }
     piix3->pic = pic;
-    pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
+
     (*pi440fx_state)->piix3 = piix3;
 
     *piix3_devfn = piix3->dev.devfn;
@@ -246,33 +335,98 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
         ram_size = 255;
     (*pi440fx_state)->dev.config[0x57]=ram_size;
 
+    i440fx_update_memory_mappings(f);
+
+    return b;
+}
+
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
+                    qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    ram_addr_t ram_size,
+                    target_phys_addr_t pci_hole_start,
+                    target_phys_addr_t pci_hole_size,
+                    target_phys_addr_t pci_hole64_start,
+                    target_phys_addr_t pci_hole64_size,
+                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
+
+{
+    PCIBus *b;
+
+    b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic,
+                           address_space_mem, address_space_io, ram_size,
+                           pci_hole_start, pci_hole_size,
+                           pci_hole64_size, pci_hole64_size,
+                           pci_memory, ram_memory);
     return b;
 }
 
 /* PIIX3 PCI to ISA bridge */
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+    qemu_set_irq(piix3->pic[pic_irq],
+                 !!(piix3->pic_levels &
+                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
+                     (pic_irq * PIIX_NUM_PIRQS))));
+}
 
-static void piix3_set_irq(void *opaque, int irq_num, int level)
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+    int pic_irq;
+    uint64_t mask;
+
+    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+        return;
+    }
+
+    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+    piix3->pic_levels &= ~mask;
+    piix3->pic_levels |= mask * !!level;
+
+    piix3_set_irq_pic(piix3, pic_irq);
+}
+
+static void piix3_set_irq(void *opaque, int pirq, int level)
 {
-    int i, pic_irq, pic_level;
     PIIX3State *piix3 = opaque;
+    piix3_set_irq_level(piix3, pirq, level);
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+    int pirq;
+
+    piix3->pic_levels = 0;
+    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+        piix3_set_irq_level(piix3, pirq,
+                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
+    }
+}
 
-    piix3->pci_irq_levels[irq_num] = level;
-
-    /* now we change the pic irq level according to the piix irq mappings */
-    /* XXX: optimize */
-    pic_irq = piix3->dev.config[0x60 + irq_num];
-    if (pic_irq < 16) {
-        /* The pic level is the logical OR of all the PCI irqs mapped
-           to it */
-        pic_level = 0;
-        for (i = 0; i < 4; i++) {
-            if (pic_irq == piix3->dev.config[0x60 + i])
-                pic_level |= piix3->pci_irq_levels[i];
+static void piix3_write_config(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
+        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
+        int pic_irq;
+        piix3_update_irq_levels(piix3);
+        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+            piix3_set_irq_pic(piix3, pic_irq);
         }
-        qemu_set_irq(piix3->pic[pic_irq], pic_level);
     }
 }
 
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    xen_piix_pci_write_config_client(address, val, len);
+    piix3_write_config(dev, address, val, len);
+}
+
 static void piix3_reset(void *opaque)
 {
     PIIX3State *d = opaque;
@@ -310,7 +464,25 @@ static void piix3_reset(void *opaque)
     pci_conf[0xac] = 0x00;
     pci_conf[0xae] = 0x00;
 
-    memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels));
+    d->pic_levels = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_update_irq_levels(piix3);
+    return 0;
+}
+
+static void piix3_pre_save(void *opaque)
+{
+    int i;
+    PIIX3State *piix3 = opaque;
+
+    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+        piix3->pci_irq_levels_vmstate[i] =
+            pci_bus_get_irq_level(piix3->dev.bus, i);
+    }
 }
 
 static const VMStateDescription vmstate_piix3 = {
@@ -318,9 +490,12 @@ static const VMStateDescription vmstate_piix3 = {
     .version_id = 3,
     .minimum_version_id = 2,
     .minimum_version_id_old = 2,
+    .post_load = piix3_post_load,
+    .pre_save = piix3_pre_save,
     .fields      = (VMStateField []) {
         VMSTATE_PCI_DEVICE(dev, PIIX3State),
-        VMSTATE_INT32_ARRAY_V(pci_irq_levels, PIIX3State, 4, 3),
+        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+                              PIIX_NUM_PIRQS, 3),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -328,15 +503,8 @@ static const VMStateDescription vmstate_piix3 = {
 static int piix3_initfn(PCIDevice *dev)
 {
     PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
-    uint8_t *pci_conf;
-
-    isa_bus_new(&d->dev.qdev);
-
-    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_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
 
+    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
     qemu_register_reset(piix3_reset, d);
     return 0;
 }
@@ -351,6 +519,10 @@ static PCIDeviceInfo i440fx_info[] = {
         .no_hotplug   = 1,
         .init         = i440fx_initfn,
         .config_write = i440fx_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82441,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_BRIDGE_HOST,
     },{
         .qdev.name    = "PIIX3",
         .qdev.desc    = "ISA bridge",
@@ -359,6 +531,22 @@ static PCIDeviceInfo i440fx_info[] = {
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .init         = piix3_initfn,
+        .config_write = piix3_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
+    },{
+        .qdev.name    = "PIIX3-xen",
+        .qdev.desc    = "ISA bridge",
+        .qdev.size    = sizeof(PIIX3State),
+        .qdev.vmsd    = &vmstate_piix3,
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = piix3_initfn,
+        .config_write = piix3_write_config_xen,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
     },{
         /* end of list */
     }
index 77f0dbf137f0ede1aefdef16c2550e67c1081a99..707a161046e8d6be22e37823d059a401e18576e1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -133,7 +133,7 @@ static void pl011_write(void *opaque, target_phys_addr_t offset,
         /* ??? Check if transmitter is enabled.  */
         ch = value;
         if (s->chr)
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
         s->int_level |= PL011_INT_TX;
         pl011_update(s);
         break;
@@ -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..9a1cb710f39a85a3bed9c9c55ca7b341ab4f4ee6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -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;
 }
 
index c488f695116db43d95e8a4ca7416c3f6537241d3..017a313fdab30f1db83dfa142a24fab1ee92d71c 100644 (file)
@@ -80,9 +80,9 @@ static void pl031_interrupt(void * opaque)
 
 static uint32_t pl031_get_count(pl031_state *s)
 {
-    /* This assumes qemu_get_clock returns the time since the machine was
+    /* This assumes qemu_get_clock_ns returns the time since the machine was
        created.  */
-    return s->tick_offset + qemu_get_clock(vm_clock) / get_ticks_per_sec();
+    return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec();
 }
 
 static void pl031_set_alarm(pl031_state *s)
@@ -90,7 +90,7 @@ static void pl031_set_alarm(pl031_state *s)
     int64_t now;
     uint32_t ticks;
 
-    now = qemu_get_clock(vm_clock);
+    now = qemu_get_clock_ns(vm_clock);
     ticks = s->tick_offset + now / get_ticks_per_sec();
 
     /* The timer wraps around.  This subtraction also wraps in the same way,
@@ -161,7 +161,7 @@ static void pl031_write(void * opaque, target_phys_addr_t offset,
         pl031_update(s);
         break;
     case RTC_ICR:
-        /* The PL031 documentation (DDI0224B) states that the interupt is
+        /* The PL031 documentation (DDI0224B) states that the interrupt is
            cleared when bit 0 of the written value is set.  However the
            arm926e documentation (DDI0287B) states that the interrupt is
            cleared when any value is written.  */
@@ -217,7 +217,7 @@ static int pl031_init(SysBusDevice *dev)
     qemu_get_timedate(&tm, 0);
     s->tick_offset = mktimegm(&tm);
 
-    s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s);
+    s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s);
     return 0;
 }
 
diff --git a/hw/pl041.c b/hw/pl041.c
new file mode 100644 (file)
index 0000000..efd52ac
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the ARM AACI interface
+ * connected to a LM4549 codec.
+ *
+ * Limitations:
+ * - Supports only a playback on one channel (Versatile/Vexpress)
+ * - Supports only one TX FIFO in compact-mode or non-compact mode.
+ * - Supports playback of 12, 16, 18 and 20 bits samples.
+ * - Record is not supported.
+ * - The PL041 is hardwired to a LM4549 codec.
+ *
+ */
+
+#include "sysbus.h"
+
+#include "pl041.h"
+#include "lm4549.h"
+
+#if 0
+#define PL041_DEBUG_LEVEL 1
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1)
+#define DBG_L1(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L1(fmt, ...) \
+do { } while (0)
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2)
+#define DBG_L2(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L2(fmt, ...) \
+do { } while (0)
+#endif
+
+
+#define MAX_FIFO_DEPTH      (1024)
+#define DEFAULT_FIFO_DEPTH  (8)
+
+#define SLOT1_RW    (1 << 19)
+
+/* This FIFO only stores 20-bit samples on 32-bit words.
+   So its level is independent of the selected mode */
+typedef struct {
+    uint32_t level;
+    uint32_t data[MAX_FIFO_DEPTH];
+} pl041_fifo;
+
+typedef struct {
+    pl041_fifo tx_fifo;
+    uint8_t tx_enabled;
+    uint8_t tx_compact_mode;
+    uint8_t tx_sample_size;
+
+    pl041_fifo rx_fifo;
+    uint8_t rx_enabled;
+    uint8_t rx_compact_mode;
+    uint8_t rx_sample_size;
+} pl041_channel;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    uint32_t fifo_depth; /* FIFO depth in non-compact mode */
+
+    pl041_regfile regs;
+    pl041_channel fifo1;
+    lm4549_state codec;
+} pl041_state;
+
+
+static const unsigned char pl041_default_id[8] = {
+    0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+#if defined(PL041_DEBUG_LEVEL)
+#define REGISTER(name, offset) #name,
+static const char *pl041_regs_name[] = {
+    #include "pl041.hx"
+};
+#undef REGISTER
+#endif
+
+
+#if defined(PL041_DEBUG_LEVEL)
+static const char *get_reg_name(target_phys_addr_t offset)
+{
+    if (offset <= PL041_dr1_7) {
+        return pl041_regs_name[offset >> 2];
+    }
+
+    return "unknown";
+}
+#endif
+
+static uint8_t pl041_compute_periphid3(pl041_state *s)
+{
+    uint8_t id3 = 1; /* One channel */
+
+    /* Add the fifo depth information */
+    switch (s->fifo_depth) {
+    case 8:
+        id3 |= 0 << 3;
+        break;
+    case 32:
+        id3 |= 1 << 3;
+        break;
+    case 64:
+        id3 |= 2 << 3;
+        break;
+    case 128:
+        id3 |= 3 << 3;
+        break;
+    case 256:
+        id3 |= 4 << 3;
+        break;
+    case 512:
+        id3 |= 5 << 3;
+        break;
+    case 1024:
+        id3 |= 6 << 3;
+        break;
+    case 2048:
+        id3 |= 7 << 3;
+        break;
+    }
+
+    return id3;
+}
+
+static void pl041_reset(pl041_state *s)
+{
+    DBG_L1("pl041_reset\n");
+
+    memset(&s->regs, 0x00, sizeof(pl041_regfile));
+
+    s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY;
+    s->regs.sr1 = TXFE | RXFE | TXHE;
+    s->regs.isr1 = 0;
+
+    memset(&s->fifo1, 0x00, sizeof(s->fifo1));
+}
+
+
+static void pl041_fifo1_write(pl041_state *s, uint32_t value)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+
+    /* Push the value in the FIFO */
+    if (channel->tx_compact_mode == 0) {
+        /* Non-compact mode */
+
+        if (fifo->level < s->fifo_depth) {
+            /* Pad the value with 0 to obtain a 20-bit sample */
+            switch (channel->tx_sample_size) {
+            case 12:
+                value = (value << 8) & 0xFFFFF;
+                break;
+            case 16:
+                value = (value << 4) & 0xFFFFF;
+                break;
+            case 18:
+                value = (value << 2) & 0xFFFFF;
+                break;
+            case 20:
+            default:
+                break;
+            }
+
+            /* Store the sample in the FIFO */
+            fifo->data[fifo->level++] = value;
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    } else {
+        /* Compact mode */
+
+        if ((fifo->level + 2) < s->fifo_depth) {
+            uint32_t i = 0;
+            uint32_t sample = 0;
+
+            for (i = 0; i < 2; i++) {
+                sample = value & 0xFFFF;
+                value = value >> 16;
+
+                /* Pad each sample with 0 to obtain a 20-bit sample */
+                switch (channel->tx_sample_size) {
+                case 12:
+                    sample = sample << 8;
+                    break;
+                case 16:
+                default:
+                    sample = sample << 4;
+                    break;
+                }
+
+                /* Store the sample in the FIFO */
+                fifo->data[fifo->level++] = sample;
+            }
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    }
+
+    /* Update the status register */
+    if (fifo->level > 0) {
+        s->regs.sr1 &= ~(TXUNDERRUN | TXFE);
+    }
+
+    if (fifo->level >= (s->fifo_depth / 2)) {
+        s->regs.sr1 &= ~TXHE;
+    }
+
+    if (fifo->level >= s->fifo_depth) {
+        s->regs.sr1 |= TXFF;
+    }
+
+    DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1);
+}
+
+static void pl041_fifo1_transmit(pl041_state *s)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+    uint32_t slots = s->regs.txcr1 & TXSLOT_MASK;
+    uint32_t written_samples;
+
+    /* Check if FIFO1 transmit is enabled */
+    if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) {
+        if (fifo->level >= (s->fifo_depth / 2)) {
+            int i;
+
+            DBG_L1("Transfer FIFO level = %i\n", fifo->level);
+
+            /* Try to transfer the whole FIFO */
+            for (i = 0; i < (fifo->level / 2); i++) {
+                uint32_t left = fifo->data[i * 2];
+                uint32_t right = fifo->data[i * 2 + 1];
+
+                 /* Transmit two 20-bit samples to the codec */
+                if (lm4549_write_samples(&s->codec, left, right) == 0) {
+                    DBG_L1("Codec buffer full\n");
+                    break;
+                }
+            }
+
+            written_samples = i * 2;
+            if (written_samples > 0) {
+                /* Update the FIFO level */
+                fifo->level -= written_samples;
+
+                /* Move back the pending samples to the start of the FIFO */
+                for (i = 0; i < fifo->level; i++) {
+                    fifo->data[i] = fifo->data[written_samples + i];
+                }
+
+                /* Update the status register */
+                s->regs.sr1 &= ~TXFF;
+
+                if (fifo->level <= (s->fifo_depth / 2)) {
+                    s->regs.sr1 |= TXHE;
+                }
+
+                if (fifo->level == 0) {
+                    s->regs.sr1 |= TXFE | TXUNDERRUN;
+                    DBG_L1("Empty FIFO\n");
+                }
+            }
+        }
+    }
+}
+
+static void pl041_isr1_update(pl041_state *s)
+{
+    /* Update ISR1 */
+    if (s->regs.sr1 & TXUNDERRUN) {
+        s->regs.isr1 |= URINTR;
+    } else {
+        s->regs.isr1 &= ~URINTR;
+    }
+
+    if (s->regs.sr1 & TXHE) {
+        s->regs.isr1 |= TXINTR;
+    } else {
+        s->regs.isr1 &= ~TXINTR;
+    }
+
+    if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) {
+        s->regs.isr1 |= TXCINTR;
+    } else {
+        s->regs.isr1 &= ~TXCINTR;
+    }
+
+    /* Update the irq state */
+    qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
+    DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
+           s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1);
+}
+
+static void pl041_request_data(void *opaque)
+{
+    pl041_state *s = (pl041_state *)opaque;
+
+    /* Trigger pending transfers */
+    pl041_fifo1_transmit(s);
+    pl041_isr1_update(s);
+}
+
+static uint64_t pl041_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    int value;
+
+    if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) {
+        if (offset == PL041_periphid3) {
+            value = pl041_compute_periphid3(s);
+        } else {
+            value = pl041_default_id[(offset - PL041_periphid0) >> 2];
+        }
+
+        DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value);
+        return value;
+    } else if (offset <= PL041_dr4_7) {
+        value = *((uint32_t *)&s->regs + (offset >> 2));
+    } else {
+        DBG_L1("pl041_read: Reserved offset %x\n", (int)offset);
+        return 0;
+    }
+
+    switch (offset) {
+    case PL041_allints:
+        value = s->regs.isr1 & 0x7F;
+        break;
+    }
+
+    DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset,
+           get_reg_name(offset), value);
+
+    return value;
+}
+
+static void pl041_write(void *opaque, target_phys_addr_t offset,
+                             uint64_t value, unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    uint16_t control, data;
+    uint32_t result;
+
+    DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset,
+           get_reg_name(offset), (unsigned int)value);
+
+    /* Write the register */
+    if (offset <= PL041_dr4_7) {
+        *((uint32_t *)&s->regs + (offset >> 2)) = value;
+    } else {
+        DBG_L1("pl041_write: Reserved offset %x\n", (int)offset);
+        return;
+    }
+
+    /* Execute the actions */
+    switch (offset) {
+    case PL041_txcr1:
+    {
+        pl041_channel *channel = &s->fifo1;
+
+        uint32_t txen = s->regs.txcr1 & TXEN;
+        uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT;
+        uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0;
+#if defined(PL041_DEBUG_LEVEL)
+        uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT;
+        uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0;
+#endif
+
+        DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i "
+               "txfen = %i\n", txen, slots,  tsize, compact_mode, txfen);
+
+        channel->tx_enabled = txen;
+        channel->tx_compact_mode = compact_mode;
+
+        switch (tsize) {
+        case 0:
+            channel->tx_sample_size = 16;
+            break;
+        case 1:
+            channel->tx_sample_size = 18;
+            break;
+        case 2:
+            channel->tx_sample_size = 20;
+            break;
+        case 3:
+            channel->tx_sample_size = 12;
+            break;
+        }
+
+        DBG_L1("TX enabled = %i\n", channel->tx_enabled);
+        DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode);
+        DBG_L1("TX sample width = %i\n", channel->tx_sample_size);
+
+        /* Check if compact mode is allowed with selected tsize */
+        if (channel->tx_compact_mode == 1) {
+            if ((channel->tx_sample_size == 18) ||
+                (channel->tx_sample_size == 20)) {
+                channel->tx_compact_mode = 0;
+                DBG_L1("Compact mode not allowed with 18/20-bit sample size\n");
+            }
+        }
+
+        break;
+    }
+    case PL041_sl1tx:
+        s->regs.slfr &= ~SL1TXEMPTY;
+
+        control = (s->regs.sl1tx >> 12) & 0x7F;
+        data = (s->regs.sl2tx >> 4) & 0xFFFF;
+
+        if ((s->regs.sl1tx & SLOT1_RW) == 0) {
+            /* Write operation */
+            lm4549_write(&s->codec, control, data);
+        } else {
+            /* Read operation */
+            result = lm4549_read(&s->codec, control);
+
+            /* Store the returned value */
+            s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW;
+            s->regs.sl2rx = result << 4;
+
+            s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY);
+            s->regs.slfr |= SL1RXVALID | SL2RXVALID;
+        }
+        break;
+
+    case PL041_sl2tx:
+        s->regs.sl2tx = value;
+        s->regs.slfr &= ~SL2TXEMPTY;
+        break;
+
+    case PL041_intclr:
+        DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n",
+               s->regs.intclr, s->regs.isr1);
+
+        if (s->regs.intclr & TXUEC1) {
+            s->regs.sr1 &= ~TXUNDERRUN;
+        }
+        break;
+
+    case PL041_maincr:
+    {
+#if defined(PL041_DEBUG_LEVEL)
+        char debug[] = " AACIFE  SL1RXEN  SL1TXEN";
+        if (!(value & AACIFE)) {
+            debug[0] = '!';
+        }
+        if (!(value & SL1RXEN)) {
+            debug[8] = '!';
+        }
+        if (!(value & SL1TXEN)) {
+            debug[17] = '!';
+        }
+        DBG_L1("%s\n", debug);
+#endif
+
+        if ((s->regs.maincr & AACIFE) == 0) {
+            pl041_reset(s);
+        }
+        break;
+    }
+
+    case PL041_dr1_0:
+    case PL041_dr1_1:
+    case PL041_dr1_2:
+    case PL041_dr1_3:
+        pl041_fifo1_write(s, value);
+        break;
+    }
+
+    /* Transmit the FIFO content */
+    pl041_fifo1_transmit(s);
+
+    /* Update the ISR1 register */
+    pl041_isr1_update(s);
+}
+
+static void pl041_device_reset(DeviceState *d)
+{
+    pl041_state *s = DO_UPCAST(pl041_state, busdev.qdev, d);
+
+    pl041_reset(s);
+}
+
+static const MemoryRegionOps pl041_ops = {
+    .read = pl041_read,
+    .write = pl041_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl041_init(SysBusDevice *dev)
+{
+    pl041_state *s = FROM_SYSBUS(pl041_state, dev);
+
+    DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
+
+    /* Check the device properties */
+    switch (s->fifo_depth) {
+    case 8:
+    case 32:
+    case 64:
+    case 128:
+    case 256:
+    case 512:
+    case 1024:
+    case 2048:
+        break;
+    case 16:
+    default:
+        /* NC FIFO depth of 16 is not allowed because its id bits in
+           AACIPERIPHID3 overlap with the id for the default NC FIFO depth */
+        fprintf(stderr, "pl041: unsupported non-compact fifo depth [%i]\n",
+                s->fifo_depth);
+        return -1;
+    }
+
+    /* Connect the device to the sysbus */
+    memory_region_init_io(&s->iomem, &pl041_ops, s, "pl041", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    /* Init the codec */
+    lm4549_init(&s->codec, &pl041_request_data, (void *)s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl041_regfile = {
+    .name = "pl041_regfile",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
+        #include "pl041.hx"
+#undef REGISTER
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_fifo = {
+    .name = "pl041_fifo",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(level, pl041_fifo),
+        VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_channel = {
+    .name = "pl041_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(tx_enabled, pl041_channel),
+        VMSTATE_UINT8(tx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(tx_sample_size, pl041_channel),
+        VMSTATE_STRUCT(rx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(rx_enabled, pl041_channel),
+        VMSTATE_UINT8(rx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(rx_sample_size, pl041_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041 = {
+    .name = "pl041",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(fifo_depth, pl041_state),
+        VMSTATE_STRUCT(regs, pl041_state, 0,
+                       vmstate_pl041_regfile, pl041_regfile),
+        VMSTATE_STRUCT(fifo1, pl041_state, 0,
+                       vmstate_pl041_channel, pl041_channel),
+        VMSTATE_STRUCT(codec, pl041_state, 0,
+                       vmstate_lm4549_state, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo pl041_device_info = {
+    .init = pl041_init,
+    .qdev.name = "pl041",
+    .qdev.size = sizeof(pl041_state),
+    .qdev.vmsd = &vmstate_pl041,
+    .qdev.reset = pl041_device_reset,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        /* Non-compact FIFO depth property */
+        DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state,
+                           fifo_depth, DEFAULT_FIFO_DEPTH),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pl041_register_device(void)
+{
+    sysbus_register_withprop(&pl041_device_info);
+}
+
+device_init(pl041_register_device)
diff --git a/hw/pl041.h b/hw/pl041.h
new file mode 100644 (file)
index 0000000..1f22432
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_PL041_H
+#define HW_PL041_H
+
+/* Register file */
+#define REGISTER(name, offset) uint32_t name;
+typedef struct {
+    #include "pl041.hx"
+} pl041_regfile;
+#undef REGISTER
+
+/* Register addresses */
+#define REGISTER(name, offset) PL041_##name = offset,
+enum {
+    #include "pl041.hx"
+
+    PL041_periphid0 = 0xFE0,
+    PL041_periphid1 = 0xFE4,
+    PL041_periphid2 = 0xFE8,
+    PL041_periphid3 = 0xFEC,
+    PL041_pcellid0  = 0xFF0,
+    PL041_pcellid1  = 0xFF4,
+    PL041_pcellid2  = 0xFF8,
+    PL041_pcellid3  = 0xFFC,
+};
+#undef REGISTER
+
+/* Register bits */
+
+/* IEx */
+#define TXCIE           (1 << 0)
+#define RXTIE           (1 << 1)
+#define TXIE            (1 << 2)
+#define RXIE            (1 << 3)
+#define RXOIE           (1 << 4)
+#define TXUIE           (1 << 5)
+#define RXTOIE          (1 << 6)
+
+/* TXCRx */
+#define TXEN            (1 << 0)
+#define TXSLOT1         (1 << 1)
+#define TXSLOT2         (1 << 2)
+#define TXSLOT3         (1 << 3)
+#define TXSLOT4         (1 << 4)
+#define TXCOMPACT       (1 << 15)
+#define TXFEN           (1 << 16)
+
+#define TXSLOT_MASK_BIT (1)
+#define TXSLOT_MASK     (0xFFF << TXSLOT_MASK_BIT)
+
+#define TSIZE_MASK_BIT  (13)
+#define TSIZE_MASK      (0x3 << TSIZE_MASK_BIT)
+
+#define TSIZE_16BITS    (0x0 << TSIZE_MASK_BIT)
+#define TSIZE_18BITS    (0x1 << TSIZE_MASK_BIT)
+#define TSIZE_20BITS    (0x2 << TSIZE_MASK_BIT)
+#define TSIZE_12BITS    (0x3 << TSIZE_MASK_BIT)
+
+/* SRx */
+#define RXFE         (1 << 0)
+#define TXFE         (1 << 1)
+#define RXHF         (1 << 2)
+#define TXHE         (1 << 3)
+#define RXFF         (1 << 4)
+#define TXFF         (1 << 5)
+#define RXBUSY       (1 << 6)
+#define TXBUSY       (1 << 7)
+#define RXOVERRUN    (1 << 8)
+#define TXUNDERRUN   (1 << 9)
+#define RXTIMEOUT    (1 << 10)
+#define RXTOFE       (1 << 11)
+
+/* ISRx */
+#define TXCINTR      (1 << 0)
+#define RXTOINTR     (1 << 1)
+#define TXINTR       (1 << 2)
+#define RXINTR       (1 << 3)
+#define ORINTR       (1 << 4)
+#define URINTR       (1 << 5)
+#define RXTOFEINTR   (1 << 6)
+
+/* SLFR */
+#define SL1RXBUSY    (1 << 0)
+#define SL1TXBUSY    (1 << 1)
+#define SL2RXBUSY    (1 << 2)
+#define SL2TXBUSY    (1 << 3)
+#define SL12RXBUSY   (1 << 4)
+#define SL12TXBUSY   (1 << 5)
+#define SL1RXVALID   (1 << 6)
+#define SL1TXEMPTY   (1 << 7)
+#define SL2RXVALID   (1 << 8)
+#define SL2TXEMPTY   (1 << 9)
+#define SL12RXVALID  (1 << 10)
+#define SL12TXEMPTY  (1 << 11)
+#define RAWGPIOINT   (1 << 12)
+#define RWIS         (1 << 13)
+
+/* MAINCR */
+#define AACIFE       (1 << 0)
+#define LOOPBACK     (1 << 1)
+#define LOWPOWER     (1 << 2)
+#define SL1RXEN      (1 << 3)
+#define SL1TXEN      (1 << 4)
+#define SL2RXEN      (1 << 5)
+#define SL2TXEN      (1 << 6)
+#define SL12RXEN     (1 << 7)
+#define SL12TXEN     (1 << 8)
+#define DMAENABLE    (1 << 9)
+
+/* INTCLR */
+#define WISC         (1 << 0)
+#define RXOEC1       (1 << 1)
+#define RXOEC2       (1 << 2)
+#define RXOEC3       (1 << 3)
+#define RXOEC4       (1 << 4)
+#define TXUEC1       (1 << 5)
+#define TXUEC2       (1 << 6)
+#define TXUEC3       (1 << 7)
+#define TXUEC4       (1 << 8)
+#define RXTOFEC1     (1 << 9)
+#define RXTOFEC2     (1 << 10)
+#define RXTOFEC3     (1 << 11)
+#define RXTOFEC4     (1 << 12)
+
+#endif /* #ifndef HW_PL041_H */
diff --git a/hw/pl041.hx b/hw/pl041.hx
new file mode 100644 (file)
index 0000000..e972996
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+/* PL041 register file description */
+
+REGISTER( rxcr1,   0x00 )
+REGISTER( txcr1,   0x04 )
+REGISTER( sr1,     0x08 )
+REGISTER( isr1,    0x0C )
+REGISTER( ie1,     0x10 )
+REGISTER( rxcr2,   0x14 )
+REGISTER( txcr2,   0x18 )
+REGISTER( sr2,     0x1C )
+REGISTER( isr2,    0x20 )
+REGISTER( ie2,     0x24 )
+REGISTER( rxcr3,   0x28 )
+REGISTER( txcr3,   0x2C )
+REGISTER( sr3,     0x30 )
+REGISTER( isr3,    0x34 )
+REGISTER( ie3,     0x38 )
+REGISTER( rxcr4,   0x3C )
+REGISTER( txcr4,   0x40 )
+REGISTER( sr4,     0x44 )
+REGISTER( isr4,    0x48 )
+REGISTER( ie4,     0x4C )
+REGISTER( sl1rx,   0x50 )
+REGISTER( sl1tx,   0x54 )
+REGISTER( sl2rx,   0x58 )
+REGISTER( sl2tx,   0x5C )
+REGISTER( sl12rx,  0x60 )
+REGISTER( sl12tx,  0x64 )
+REGISTER( slfr,    0x68 )
+REGISTER( slistat, 0x6C )
+REGISTER( slien,   0x70 )
+REGISTER( intclr,  0x74 )
+REGISTER( maincr,  0x78 )
+REGISTER( reset,   0x7C )
+REGISTER( sync,    0x80 )
+REGISTER( allints, 0x84 )
+REGISTER( mainfr,  0x88 )
+REGISTER( unused,  0x8C )
+REGISTER( dr1_0,   0x90 )
+REGISTER( dr1_1,   0x94 )
+REGISTER( dr1_2,   0x98 )
+REGISTER( dr1_3,   0x9C )
+REGISTER( dr1_4,   0xA0 )
+REGISTER( dr1_5,   0xA4 )
+REGISTER( dr1_6,   0xA8 )
+REGISTER( dr1_7,   0xAC )
+REGISTER( dr2_0,   0xB0 )
+REGISTER( dr2_1,   0xB4 )
+REGISTER( dr2_2,   0xB8 )
+REGISTER( dr2_3,   0xBC )
+REGISTER( dr2_4,   0xC0 )
+REGISTER( dr2_5,   0xC4 )
+REGISTER( dr2_6,   0xC8 )
+REGISTER( dr2_7,   0xCC )
+REGISTER( dr3_0,   0xD0 )
+REGISTER( dr3_1,   0xD4 )
+REGISTER( dr3_2,   0xD8 )
+REGISTER( dr3_3,   0xDC )
+REGISTER( dr3_4,   0xE0 )
+REGISTER( dr3_5,   0xE4 )
+REGISTER( dr3_6,   0xE8 )
+REGISTER( dr3_7,   0xEC )
+REGISTER( dr4_0,   0xF0 )
+REGISTER( dr4_1,   0xF4 )
+REGISTER( dr4_2,   0xF8 )
+REGISTER( dr4_3,   0xFC )
+REGISTER( dr4_4,   0x100 )
+REGISTER( dr4_5,   0x104 )
+REGISTER( dr4_6,   0x108 )
+REGISTER( dr4_7,   0x10C )
index b155cc07b6e6b25fbbd597087c0739acc52ccd85..f7fa2e253cfd47cf55a90f024b0d6dcd0815dd52 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
index 1997b7cd2f460a60986b147d3dc5f323411661de..cf5adbe1fb2f30e9cb792a2e6bdba1d42254514c 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -24,34 +24,68 @@ do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
 #endif
 
 static const uint8_t pl061_id[12] =
+  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+static const uint8_t pl061_id_luminary[12] =
   { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
 
 typedef struct {
     SysBusDevice busdev;
-    int locked;
-    uint8_t data;
-    uint8_t old_data;
-    uint8_t dir;
-    uint8_t isense;
-    uint8_t ibe;
-    uint8_t iev;
-    uint8_t im;
-    uint8_t istate;
-    uint8_t afsel;
-    uint8_t dr2r;
-    uint8_t dr4r;
-    uint8_t dr8r;
-    uint8_t odr;
-    uint8_t pur;
-    uint8_t pdr;
-    uint8_t slr;
-    uint8_t den;
-    uint8_t cr;
-    uint8_t float_high;
+    uint32_t locked;
+    uint32_t data;
+    uint32_t old_data;
+    uint32_t dir;
+    uint32_t isense;
+    uint32_t ibe;
+    uint32_t iev;
+    uint32_t im;
+    uint32_t istate;
+    uint32_t afsel;
+    uint32_t dr2r;
+    uint32_t dr4r;
+    uint32_t dr8r;
+    uint32_t odr;
+    uint32_t pur;
+    uint32_t pdr;
+    uint32_t slr;
+    uint32_t den;
+    uint32_t cr;
+    uint32_t float_high;
+    uint32_t amsel;
     qemu_irq irq;
     qemu_irq out[8];
+    const unsigned char *id;
 } pl061_state;
 
+static const VMStateDescription vmstate_pl061 = {
+    .name = "pl061",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(locked, pl061_state),
+        VMSTATE_UINT32(data, pl061_state),
+        VMSTATE_UINT32(old_data, pl061_state),
+        VMSTATE_UINT32(dir, pl061_state),
+        VMSTATE_UINT32(isense, pl061_state),
+        VMSTATE_UINT32(ibe, pl061_state),
+        VMSTATE_UINT32(iev, pl061_state),
+        VMSTATE_UINT32(im, pl061_state),
+        VMSTATE_UINT32(istate, pl061_state),
+        VMSTATE_UINT32(afsel, pl061_state),
+        VMSTATE_UINT32(dr2r, pl061_state),
+        VMSTATE_UINT32(dr4r, pl061_state),
+        VMSTATE_UINT32(dr8r, pl061_state),
+        VMSTATE_UINT32(odr, pl061_state),
+        VMSTATE_UINT32(pur, pl061_state),
+        VMSTATE_UINT32(pdr, pl061_state),
+        VMSTATE_UINT32(slr, pl061_state),
+        VMSTATE_UINT32(den, pl061_state),
+        VMSTATE_UINT32(cr, pl061_state),
+        VMSTATE_UINT32(float_high, pl061_state),
+        VMSTATE_UINT32_V(amsel, pl061_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static void pl061_update(pl061_state *s)
 {
     uint8_t changed;
@@ -69,7 +103,7 @@ static void pl061_update(pl061_state *s)
     s->old_data = out;
     for (i = 0; i < 8; i++) {
         mask = 1 << i;
-        if ((changed & mask) && s->out) {
+        if (changed & mask) {
             DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
             qemu_set_irq(s->out[i], (out & mask) != 0);
         }
@@ -83,7 +117,7 @@ static uint32_t pl061_read(void *opaque, target_phys_addr_t offset)
     pl061_state *s = (pl061_state *)opaque;
 
     if (offset >= 0xfd0 && offset < 0x1000) {
-        return pl061_id[(offset - 0xfd0) >> 2];
+        return s->id[(offset - 0xfd0) >> 2];
     }
     if (offset < 0x400) {
         return s->data & (offset >> 2);
@@ -95,7 +129,7 @@ static uint32_t pl061_read(void *opaque, target_phys_addr_t offset)
         return s->isense;
     case 0x408: /* Interrupt both edges */
         return s->ibe;
-    case 0x40c: /* Interupt event */
+    case 0x40c: /* Interrupt event */
         return s->iev;
     case 0x410: /* Interrupt mask */
         return s->im;
@@ -125,6 +159,8 @@ static uint32_t pl061_read(void *opaque, target_phys_addr_t offset)
         return s->locked;
     case 0x524: /* Commit */
         return s->cr;
+    case 0x528: /* Analog mode select */
+        return s->amsel;
     default:
         hw_error("pl061_read: Bad offset %x\n", (int)offset);
         return 0;
@@ -145,19 +181,19 @@ static void pl061_write(void *opaque, target_phys_addr_t offset,
     }
     switch (offset) {
     case 0x400: /* Direction */
-        s->dir = value;
+        s->dir = value & 0xff;
         break;
     case 0x404: /* Interrupt sense */
-        s->isense = value;
+        s->isense = value & 0xff;
         break;
     case 0x408: /* Interrupt both edges */
-        s->ibe = value;
+        s->ibe = value & 0xff;
         break;
-    case 0x40c: /* Interupt event */
-        s->iev = value;
+    case 0x40c: /* Interrupt event */
+        s->iev = value & 0xff;
         break;
     case 0x410: /* Interrupt mask */
-        s->im = value;
+        s->im = value & 0xff;
         break;
     case 0x41c: /* Interrupt clear */
         s->istate &= ~value;
@@ -167,35 +203,38 @@ static void pl061_write(void *opaque, target_phys_addr_t offset,
         s->afsel = (s->afsel & ~mask) | (value & mask);
         break;
     case 0x500: /* 2mA drive */
-        s->dr2r = value;
+        s->dr2r = value & 0xff;
         break;
     case 0x504: /* 4mA drive */
-        s->dr4r = value;
+        s->dr4r = value & 0xff;
         break;
     case 0x508: /* 8mA drive */
-        s->dr8r = value;
+        s->dr8r = value & 0xff;
         break;
     case 0x50c: /* Open drain */
-        s->odr = value;
+        s->odr = value & 0xff;
         break;
     case 0x510: /* Pull-up */
-        s->pur = value;
+        s->pur = value & 0xff;
         break;
     case 0x514: /* Pull-down */
-        s->pdr = value;
+        s->pdr = value & 0xff;
         break;
     case 0x518: /* Slew rate control */
-        s->slr = value;
+        s->slr = value & 0xff;
         break;
     case 0x51c: /* Digital enable */
-        s->den = value;
+        s->den = value & 0xff;
         break;
     case 0x520: /* Lock */
         s->locked = (value != 0xacce551);
         break;
     case 0x524: /* Commit */
         if (!s->locked)
-            s->cr = value;
+            s->cr = value & 0xff;
+        break;
+    case 0x528:
+        s->amsel = value & 0xff;
         break;
     default:
         hw_error("pl061_write: Bad offset %x\n", (int)offset);
@@ -235,67 +274,11 @@ static CPUWriteMemoryFunc * const pl061_writefn[] = {
    pl061_write
 };
 
-static void pl061_save(QEMUFile *f, void *opaque)
-{
-    pl061_state *s = (pl061_state *)opaque;
-
-    qemu_put_be32(f, s->locked);
-    qemu_put_be32(f, s->data);
-    qemu_put_be32(f, s->old_data);
-    qemu_put_be32(f, s->dir);
-    qemu_put_be32(f, s->isense);
-    qemu_put_be32(f, s->ibe);
-    qemu_put_be32(f, s->iev);
-    qemu_put_be32(f, s->im);
-    qemu_put_be32(f, s->istate);
-    qemu_put_be32(f, s->afsel);
-    qemu_put_be32(f, s->dr2r);
-    qemu_put_be32(f, s->dr4r);
-    qemu_put_be32(f, s->dr8r);
-    qemu_put_be32(f, s->odr);
-    qemu_put_be32(f, s->pur);
-    qemu_put_be32(f, s->pdr);
-    qemu_put_be32(f, s->slr);
-    qemu_put_be32(f, s->den);
-    qemu_put_be32(f, s->cr);
-    qemu_put_be32(f, s->float_high);
-}
-
-static int pl061_load(QEMUFile *f, void *opaque, int version_id)
-{
-    pl061_state *s = (pl061_state *)opaque;
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->locked = qemu_get_be32(f);
-    s->data = qemu_get_be32(f);
-    s->old_data = qemu_get_be32(f);
-    s->dir = qemu_get_be32(f);
-    s->isense = qemu_get_be32(f);
-    s->ibe = qemu_get_be32(f);
-    s->iev = qemu_get_be32(f);
-    s->im = qemu_get_be32(f);
-    s->istate = qemu_get_be32(f);
-    s->afsel = qemu_get_be32(f);
-    s->dr2r = qemu_get_be32(f);
-    s->dr4r = qemu_get_be32(f);
-    s->dr8r = qemu_get_be32(f);
-    s->odr = qemu_get_be32(f);
-    s->pur = qemu_get_be32(f);
-    s->pdr = qemu_get_be32(f);
-    s->slr = qemu_get_be32(f);
-    s->den = qemu_get_be32(f);
-    s->cr = qemu_get_be32(f);
-    s->float_high = qemu_get_be32(f);
-
-    return 0;
-}
-
-static int pl061_init(SysBusDevice *dev)
+static int pl061_init(SysBusDevice *dev, const unsigned char *id)
 {
     int iomemtype;
     pl061_state *s = FROM_SYSBUS(pl061_state, dev);
-
+    s->id = id;
     iomemtype = cpu_register_io_memory(pl061_readfn,
                                        pl061_writefn, s,
                                        DEVICE_NATIVE_ENDIAN);
@@ -304,14 +287,37 @@ static int pl061_init(SysBusDevice *dev)
     qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
     qdev_init_gpio_out(&dev->qdev, s->out, 8);
     pl061_reset(s);
-    register_savevm(&dev->qdev, "pl061_gpio", -1, 1, pl061_save, pl061_load, s);
     return 0;
 }
 
+static int pl061_init_luminary(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id_luminary);
+}
+
+static int pl061_init_arm(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id);
+}
+
+static SysBusDeviceInfo pl061_info = {
+    .init = pl061_init_arm,
+    .qdev.name = "pl061",
+    .qdev.size = sizeof(pl061_state),
+    .qdev.vmsd = &vmstate_pl061,
+};
+
+static SysBusDeviceInfo pl061_luminary_info = {
+    .init = pl061_init_luminary,
+    .qdev.name = "pl061_luminary",
+    .qdev.size = sizeof(pl061_state),
+    .qdev.vmsd = &vmstate_pl061,
+};
+
 static void pl061_register_devices(void)
 {
-    sysbus_register_dev("pl061", sizeof(pl061_state),
-                        pl061_init);
+    sysbus_register_withprop(&pl061_info);
+    sysbus_register_withprop(&pl061_luminary_info);
 }
 
 device_init(pl061_register_devices)
index 901f04a84496548c5d6dd95caa97e6345de34f44..5ba3b0859b90da27c8871240caa703b07cb95776 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -199,10 +199,10 @@ again:
             if (size == 0) {
                 /* Transfer complete.  */
                 if (ch->lli) {
-                    ch->src = ldl_phys(ch->lli);
-                    ch->dest = ldl_phys(ch->lli + 4);
-                    ch->ctrl = ldl_phys(ch->lli + 12);
-                    ch->lli = ldl_phys(ch->lli + 8);
+                    ch->src = ldl_le_phys(ch->lli);
+                    ch->dest = ldl_le_phys(ch->lli + 4);
+                    ch->ctrl = ldl_le_phys(ch->lli + 12);
+                    ch->lli = ldl_le_phys(ch->lli + 8);
                 } else {
                     ch->conf &= ~PL080_CCONF_E;
                 }
index 06d2dfada694e35e3e15c0def03d6aaddb20d508..4ac710a6ec76fbf43992139069ec1355c3a6c61c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005-2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU LGPL
+ * This code is licensed under the GNU LGPL
  */
 
 #include "sysbus.h"
@@ -24,15 +24,25 @@ enum pl110_bppmode
     BPP_4,
     BPP_8,
     BPP_16,
-    BPP_32
+    BPP_32,
+    BPP_16_565, /* PL111 only */
+    BPP_12      /* PL111 only */
+};
+
+
+/* The Versatile/PB uses a slightly modified PL110 controller.  */
+enum pl110_version
+{
+    PL110,
+    PL110_VERSATILE,
+    PL111
 };
 
 typedef struct {
     SysBusDevice busdev;
     DisplayState *ds;
 
-    /* The Versatile/PB uses a slightly modified PL110 controller.  */
-    int versatile;
+    int version;
     uint32_t timing[4];
     uint32_t cr;
     uint32_t upbase;
@@ -43,6 +53,7 @@ typedef struct {
     int rows;
     enum pl110_bppmode bpp;
     int invalidate;
+    uint32_t mux_ctrl;
     uint32_t pallette[256];
     uint32_t raw_pallette[128];
     qemu_irq irq;
@@ -50,10 +61,10 @@ typedef struct {
 
 static const VMStateDescription vmstate_pl110 = {
     .name = "pl110",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_INT32(versatile, pl110_state),
+        VMSTATE_INT32(version, pl110_state),
         VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
         VMSTATE_UINT32(cr, pl110_state),
         VMSTATE_UINT32(upbase, pl110_state),
@@ -66,6 +77,7 @@ static const VMStateDescription vmstate_pl110 = {
         VMSTATE_INT32(invalidate, pl110_state),
         VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256),
         VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128),
+        VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -82,6 +94,17 @@ static const unsigned char pl110_versatile_id[] =
 #define pl110_versatile_id pl110_id
 #endif
 
+static const unsigned char pl111_id[] = {
+    0x11, 0x11, 0x24, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+/* Indexed by pl110_version */
+static const unsigned char *idregs[] = {
+    pl110_id,
+    pl110_versatile_id,
+    pl111_id
+};
+
 #include "pixel_ops.h"
 
 #define BITS 8
@@ -144,12 +167,40 @@ static void pl110_update_display(void *opaque)
     if (s->cr & PL110_CR_BGR)
         bpp_offset = 0;
     else
-        bpp_offset = 18;
+        bpp_offset = 24;
+
+    if ((s->version != PL111) && (s->bpp == BPP_16)) {
+        /* The PL110's native 16 bit mode is 5551; however
+         * most boards with a PL110 implement an external
+         * mux which allows bits to be reshuffled to give
+         * 565 format. The mux is typically controlled by
+         * an external system register.
+         * This is controlled by a GPIO input pin
+         * so boards can wire it up to their register.
+         *
+         * The PL111 straightforwardly implements both
+         * 5551 and 565 under control of the bpp field
+         * in the LCDControl register.
+         */
+        switch (s->mux_ctrl) {
+        case 3: /* 565 BGR */
+            bpp_offset = (BPP_16_565 - BPP_16);
+            break;
+        case 1: /* 5551 */
+            break;
+        case 0: /* 888; also if we have loaded vmstate from an old version */
+        case 2: /* 565 RGB */
+        default:
+            /* treat as 565 but honour BGR bit */
+            bpp_offset += (BPP_16_565 - BPP_16);
+            break;
+        }
+    }
 
     if (s->cr & PL110_CR_BEBO)
-        fn = fntable[s->bpp + 6 + bpp_offset];
+        fn = fntable[s->bpp + 8 + bpp_offset];
     else if (s->cr & PL110_CR_BEPO)
-        fn = fntable[s->bpp + 12 + bpp_offset];
+        fn = fntable[s->bpp + 16 + bpp_offset];
     else
         fn = fntable[s->bpp + bpp_offset];
 
@@ -167,6 +218,8 @@ static void pl110_update_display(void *opaque)
     case BPP_8:
         break;
     case BPP_16:
+    case BPP_16_565:
+    case BPP_12:
         src_width <<= 1;
         break;
     case BPP_32:
@@ -253,10 +306,7 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
     pl110_state *s = (pl110_state *)opaque;
 
     if (offset >= 0xfe0 && offset < 0x1000) {
-        if (s->versatile)
-            return pl110_versatile_id[(offset - 0xfe0) >> 2];
-        else
-            return pl110_id[(offset - 0xfe0) >> 2];
+        return idregs[s->version][(offset - 0xfe0) >> 2];
     }
     if (offset >= 0x200 && offset < 0x400) {
         return s->raw_pallette[(offset - 0x200) >> 2];
@@ -275,12 +325,14 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
     case 5: /* LCDLPBASE */
         return s->lpbase;
     case 6: /* LCDIMSC */
-       if (s->versatile)
-         return s->cr;
+        if (s->version != PL110) {
+            return s->cr;
+        }
         return s->int_mask;
     case 7: /* LCDControl */
-       if (s->versatile)
-         return s->int_mask;
+        if (s->version != PL110) {
+            return s->int_mask;
+        }
         return s->cr;
     case 8: /* LCDRIS */
         return s->int_status;
@@ -337,15 +389,17 @@ static void pl110_write(void *opaque, target_phys_addr_t offset,
         s->lpbase = val;
         break;
     case 6: /* LCDIMSC */
-        if (s->versatile)
+        if (s->version != PL110) {
             goto control;
+        }
     imsc:
         s->int_mask = val;
         pl110_update(s);
         break;
     case 7: /* LCDControl */
-        if (s->versatile)
+        if (s->version != PL110) {
             goto imsc;
+        }
     control:
         s->cr = val;
         s->bpp = (val >> 1) & 7;
@@ -374,6 +428,12 @@ static CPUWriteMemoryFunc * const pl110_writefn[] = {
    pl110_write
 };
 
+static void pl110_mux_ctrl_set(void *opaque, int line, int level)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    s->mux_ctrl = level;
+}
+
 static int pl110_init(SysBusDevice *dev)
 {
     pl110_state *s = FROM_SYSBUS(pl110_state, dev);
@@ -384,6 +444,7 @@ static int pl110_init(SysBusDevice *dev)
                                        DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1);
     s->ds = graphic_console_init(pl110_update_display,
                                  pl110_invalidate_display,
                                  NULL, NULL, s);
@@ -393,7 +454,14 @@ static int pl110_init(SysBusDevice *dev)
 static int pl110_versatile_init(SysBusDevice *dev)
 {
     pl110_state *s = FROM_SYSBUS(pl110_state, dev);
-    s->versatile = 1;
+    s->version = PL110_VERSATILE;
+    return pl110_init(dev);
+}
+
+static int pl111_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+    s->version = PL111;
     return pl110_init(dev);
 }
 
@@ -413,10 +481,19 @@ static SysBusDeviceInfo pl110_versatile_info = {
     .qdev.no_user = 1,
 };
 
+static SysBusDeviceInfo pl111_info = {
+    .init = pl111_init,
+    .qdev.name = "pl111",
+    .qdev.size = sizeof(pl110_state),
+    .qdev.vmsd = &vmstate_pl110,
+    .qdev.no_user = 1,
+};
+
 static void pl110_register_devices(void)
 {
     sysbus_register_withprop(&pl110_info);
     sysbus_register_withprop(&pl110_versatile_info);
+    sysbus_register_withprop(&pl111_info);
 }
 
 device_init(pl110_register_devices)
index b3c9077dcc2ba907d6f03e5715627be882fba426..1dce32a0c3494a69d19aeecb2fd619242b118a1b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005 CodeSourcery, LLC.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU LGPL
+ * This code is licensed under the GNU LGPL
  *
  * Framebuffer format conversion routines.
  */
 #include "pl110_template.h"
 #undef BORDER
 
-static drawfn glue(pl110_draw_fn_,BITS)[36] =
+static drawfn glue(pl110_draw_fn_,BITS)[48] =
 {
     glue(pl110_draw_line1_lblp_bgr,BITS),
     glue(pl110_draw_line2_lblp_bgr,BITS),
     glue(pl110_draw_line4_lblp_bgr,BITS),
     glue(pl110_draw_line8_lblp_bgr,BITS),
-    glue(pl110_draw_line16_lblp_bgr,BITS),
+    glue(pl110_draw_line16_555_lblp_bgr,BITS),
     glue(pl110_draw_line32_lblp_bgr,BITS),
+    glue(pl110_draw_line16_lblp_bgr,BITS),
+    glue(pl110_draw_line12_lblp_bgr,BITS),
 
     glue(pl110_draw_line1_bbbp_bgr,BITS),
     glue(pl110_draw_line2_bbbp_bgr,BITS),
     glue(pl110_draw_line4_bbbp_bgr,BITS),
     glue(pl110_draw_line8_bbbp_bgr,BITS),
-    glue(pl110_draw_line16_bbbp_bgr,BITS),
+    glue(pl110_draw_line16_555_bbbp_bgr,BITS),
     glue(pl110_draw_line32_bbbp_bgr,BITS),
+    glue(pl110_draw_line16_bbbp_bgr,BITS),
+    glue(pl110_draw_line12_bbbp_bgr,BITS),
 
     glue(pl110_draw_line1_lbbp_bgr,BITS),
     glue(pl110_draw_line2_lbbp_bgr,BITS),
     glue(pl110_draw_line4_lbbp_bgr,BITS),
     glue(pl110_draw_line8_lbbp_bgr,BITS),
-    glue(pl110_draw_line16_lbbp_bgr,BITS),
+    glue(pl110_draw_line16_555_lbbp_bgr,BITS),
     glue(pl110_draw_line32_lbbp_bgr,BITS),
+    glue(pl110_draw_line16_lbbp_bgr,BITS),
+    glue(pl110_draw_line12_lbbp_bgr,BITS),
 
     glue(pl110_draw_line1_lblp_rgb,BITS),
     glue(pl110_draw_line2_lblp_rgb,BITS),
     glue(pl110_draw_line4_lblp_rgb,BITS),
     glue(pl110_draw_line8_lblp_rgb,BITS),
-    glue(pl110_draw_line16_lblp_rgb,BITS),
+    glue(pl110_draw_line16_555_lblp_rgb,BITS),
     glue(pl110_draw_line32_lblp_rgb,BITS),
+    glue(pl110_draw_line16_lblp_rgb,BITS),
+    glue(pl110_draw_line12_lblp_rgb,BITS),
 
     glue(pl110_draw_line1_bbbp_rgb,BITS),
     glue(pl110_draw_line2_bbbp_rgb,BITS),
     glue(pl110_draw_line4_bbbp_rgb,BITS),
     glue(pl110_draw_line8_bbbp_rgb,BITS),
-    glue(pl110_draw_line16_bbbp_rgb,BITS),
+    glue(pl110_draw_line16_555_bbbp_rgb,BITS),
     glue(pl110_draw_line32_bbbp_rgb,BITS),
+    glue(pl110_draw_line16_bbbp_rgb,BITS),
+    glue(pl110_draw_line12_bbbp_rgb,BITS),
 
     glue(pl110_draw_line1_lbbp_rgb,BITS),
     glue(pl110_draw_line2_lbbp_rgb,BITS),
     glue(pl110_draw_line4_lbbp_rgb,BITS),
     glue(pl110_draw_line8_lbbp_rgb,BITS),
-    glue(pl110_draw_line16_lbbp_rgb,BITS),
+    glue(pl110_draw_line16_555_lbbp_rgb,BITS),
     glue(pl110_draw_line32_lbbp_rgb,BITS),
+    glue(pl110_draw_line16_lbbp_rgb,BITS),
+    glue(pl110_draw_line12_lbbp_rgb,BITS),
 };
 
 #undef BITS
@@ -299,6 +311,82 @@ static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_
     }
 }
 
+static void glue(pl110_draw_line16_555_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    /* RGB 555 plus an intensity bit (which we ignore) */
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        MSB = (data & 0x1f) << 3;
+        data >>= 6;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    /* RGB 444 with 4 bits of zeroes at the top of each halfword */
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+        LSB = (data & 0xf) << 4;
+        data >>= 4;
+        g = (data & 0xf) << 4;
+        data >>= 4;
+        MSB = (data & 0xf) << 4;
+        data >>= 8;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0xf) << 4;
+        data >>= 4;
+        g = (data & 0xf) << 4;
+        data >>= 4;
+        MSB = (data & 0xf) << 4;
+        data >>= 8;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
 #undef SWAP_PIXELS
 #undef NAME
 #undef SWAP_WORDS
index 36d9d02d6a5ef6011f35bd7e3ce0320c99081652..0943c09eca79d96a991f1ac214b38b3a7f2c6031 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "blockdev.h"
@@ -47,6 +47,8 @@ typedef struct {
     int linux_hack;
     uint32_t fifo[PL181_FIFO_LEN];
     qemu_irq irq[2];
+    /* GPIO outputs for 'card is readonly' and 'card inserted' */
+    qemu_irq cardstatus[2];
 } pl181_state;
 
 #define PL181_CMD_INDEX     0x3f
@@ -444,6 +446,9 @@ static void pl181_reset(void *opaque)
     s->linux_hack = 0;
     s->mask[0] = 0;
     s->mask[1] = 0;
+
+    /* We can assume our GPIO outputs have been wired up now */
+    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
 }
 
 static int pl181_init(SysBusDevice *dev)
@@ -457,6 +462,7 @@ static int pl181_init(SysBusDevice *dev)
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq[0]);
     sysbus_init_irq(dev, &s->irq[1]);
+    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
     dinfo = drive_get_next(IF_SD);
     s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
     qemu_register_reset(pl181_reset, s);
index 75f2ba196609a8ef49640f8bfdb976ca3cb13639..8dc7e42861085cc4bf9899d0de91234481d989ab 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
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 968aec1b16cdc039f81f1450762b4946b2364447..d29af0bb352182eb1167af049298766943b2a7dd 100644 (file)
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -50,7 +50,7 @@
 static void cpu_ppc_tb_stop (CPUState *env);
 static void cpu_ppc_tb_start (CPUState *env);
 
-static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+void ppc_set_irq(CPUState *env, int n_IRQ, int level)
 {
     unsigned int old_pending = env->pending_interrupts;
 
@@ -208,6 +208,7 @@ static void ppc970_set_irq (void *opaque, int pin, int level)
             } else {
                 LOG_IRQ("%s: restart the CPU\n", __func__);
                 env->halted = 0;
+                qemu_cpu_kick(env);
             }
             break;
         case PPC970_INPUT_HRESET:
@@ -246,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 */
@@ -300,6 +334,7 @@ static void ppc40x_set_irq (void *opaque, int pin, int level)
             } else {
                 LOG_IRQ("%s: restart the CPU\n", __func__);
                 env->halted = 0;
+                qemu_cpu_kick(env);
             }
             break;
         case PPC40x_INPUT_DEBUG:
@@ -388,25 +423,8 @@ void ppce500_irq_init (CPUState *env)
 }
 /*****************************************************************************/
 /* PowerPC time base and decrementer emulation */
-struct ppc_tb_t {
-    /* Time base management */
-    int64_t  tb_offset;    /* Compensation                    */
-    int64_t  atb_offset;   /* Compensation                    */
-    uint32_t tb_freq;      /* TB frequency                    */
-    /* Decrementer management */
-    uint64_t decr_next;    /* Tick for next decr interrupt    */
-    uint32_t decr_freq;    /* decrementer frequency           */
-    struct QEMUTimer *decr_timer;
-    /* Hypervisor decrementer management */
-    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
-    struct QEMUTimer *hdecr_timer;
-    uint64_t purr_load;
-    uint64_t purr_start;
-    void *opaque;
-};
 
-static inline uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk,
-                                      int64_t tb_offset)
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
 {
     /* TB time in tb periods */
     return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
@@ -417,7 +435,11 @@ uint64_t cpu_ppc_load_tbl (CPUState *env)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBL];
+    }
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
 
     return tb;
@@ -428,7 +450,7 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUState *env)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
 
     return tb >> 32;
@@ -436,6 +458,10 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUState *env)
 
 uint32_t cpu_ppc_load_tbu (CPUState *env)
 {
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBU];
+    }
+
     return _cpu_ppc_load_tbu(env);
 }
 
@@ -452,9 +478,9 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
     tb &= 0xFFFFFFFF00000000ULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
                      &tb_env->tb_offset, tb | (uint64_t)value);
 }
 
@@ -463,9 +489,9 @@ static inline void _cpu_ppc_store_tbu(CPUState *env, uint32_t value)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
     tb &= 0x00000000FFFFFFFFULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
                      &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
 }
 
@@ -479,7 +505,7 @@ uint64_t cpu_ppc_load_atbl (CPUState *env)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
 
     return tb;
@@ -490,7 +516,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
 
     return tb >> 32;
@@ -501,9 +527,9 @@ void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
     tb &= 0xFFFFFFFF00000000ULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
                      &tb_env->atb_offset, tb | (uint64_t)value);
 }
 
@@ -512,9 +538,9 @@ void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
     tb &= 0x00000000FFFFFFFFULL;
-    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
                      &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
 }
 
@@ -525,7 +551,7 @@ static void cpu_ppc_tb_stop (CPUState *env)
 
     /* If the time base is already frozen, do nothing */
     if (tb_env->tb_freq != 0) {
-        vmclk = qemu_get_clock(vm_clock);
+        vmclk = qemu_get_clock_ns(vm_clock);
         /* Get the time base */
         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
         /* Get the alternate time base */
@@ -547,7 +573,7 @@ static void cpu_ppc_tb_start (CPUState *env)
 
     /* If the time base is not frozen, do nothing */
     if (tb_env->tb_freq == 0) {
-        vmclk = qemu_get_clock(vm_clock);
+        vmclk = qemu_get_clock_ns(vm_clock);
         /* Get the time base from tb_offset */
         tb = tb_env->tb_offset;
         /* Get the alternate time base from atb_offset */
@@ -567,11 +593,14 @@ static inline uint32_t _cpu_ppc_load_decr(CPUState *env, uint64_t next)
     uint32_t decr;
     int64_t diff;
 
-    diff = next - qemu_get_clock(vm_clock);
-    if (diff >= 0)
+    diff = next - qemu_get_clock_ns(vm_clock);
+    if (diff >= 0) {
         decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
-    else
+    } else if (tb_env->flags & PPC_TIMER_BOOKE) {
+        decr = 0;
+    }  else {
         decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
+    }
     LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
 
     return decr;
@@ -581,6 +610,10 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
 {
     ppc_tb_t *tb_env = env->tb_env;
 
+    if (kvm_enabled()) {
+        return env->spr[SPR_DECR];
+    }
+
     return _cpu_ppc_load_decr(env, tb_env->decr_next);
 }
 
@@ -596,7 +629,7 @@ uint64_t cpu_ppc_load_purr (CPUState *env)
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t diff;
 
-    diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
+    diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
 
     return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
 }
@@ -629,20 +662,32 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
 
     LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
                 decr, value);
-    now = qemu_get_clock(vm_clock);
+
+    if (kvm_enabled()) {
+        /* KVM handles decrementer exceptions, we don't need our own timer */
+        return;
+    }
+
+    now = qemu_get_clock_ns(vm_clock);
     next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
-    if (is_excp)
+    if (is_excp) {
         next += *nextp - now;
-    if (next == now)
+    }
+    if (next == now) {
         next++;
+    }
     *nextp = next;
     /* Adjust timer */
     qemu_mod_timer(timer, next);
-    /* If we set a negative value and the decrementer was positive,
-     * raise an exception.
+
+    /* If we set a negative value and the decrementer was positive, raise an
+     * exception.
      */
-    if ((value & 0x80000000) && !(decr & 0x80000000))
+    if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
+        && (value & 0x80000000)
+        && !(decr & 0x80000000)) {
         (*raise_excp)(env);
+    }
 }
 
 static inline void _cpu_ppc_store_decr(CPUState *env, uint32_t decr,
@@ -690,7 +735,7 @@ void cpu_ppc_store_purr (CPUState *env, uint64_t value)
     ppc_tb_t *tb_env = env->tb_env;
 
     tb_env->purr_load = value;
-    tb_env->purr_start = qemu_get_clock(vm_clock);
+    tb_env->purr_start = qemu_get_clock_ns(vm_clock);
 }
 
 static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
@@ -714,14 +759,15 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
 {
     ppc_tb_t *tb_env;
 
-    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    tb_env = g_malloc0(sizeof(ppc_tb_t));
     env->tb_env = tb_env;
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
     /* Create new timer */
-    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env);
     if (0) {
         /* XXX: find a suitable condition to enable the hypervisor decrementer
          */
-        tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
+        tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env);
     } else {
         tb_env->hdecr_timer = NULL;
     }
@@ -759,11 +805,11 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 }
 
 /*****************************************************************************/
-/* Embedded PowerPC timers */
+/* PowerPC 40x timers */
 
 /* PIT, FIT & WDT */
-typedef struct ppcemb_timer_t ppcemb_timer_t;
-struct ppcemb_timer_t {
+typedef struct ppc40x_timer_t ppc40x_timer_t;
+struct ppc40x_timer_t {
     uint64_t pit_reload;  /* PIT auto-reload value        */
     uint64_t fit_next;    /* Tick for next FIT interrupt  */
     struct QEMUTimer *fit_timer;
@@ -779,13 +825,13 @@ static void cpu_4xx_fit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
-    now = qemu_get_clock(vm_clock);
+    ppc40x_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
     case 0:
         next = 1 << 9;
@@ -806,7 +852,7 @@ static void cpu_4xx_fit_cb (void *opaque)
     next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
     if (next == now)
         next++;
-    qemu_mod_timer(ppcemb_timer->fit_timer, next);
+    qemu_mod_timer(ppc40x_timer->fit_timer, next);
     env->spr[SPR_40x_TSR] |= 1 << 26;
     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
         ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
@@ -818,11 +864,11 @@ static void cpu_4xx_fit_cb (void *opaque)
 /* Programmable interval timer */
 static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
 {
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
-    ppcemb_timer = tb_env->opaque;
-    if (ppcemb_timer->pit_reload <= 1 ||
+    ppc40x_timer = tb_env->opaque;
+    if (ppc40x_timer->pit_reload <= 1 ||
         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
         /* Stop PIT */
@@ -830,9 +876,9 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
         qemu_del_timer(tb_env->decr_timer);
     } else {
         LOG_TB("%s: start PIT %016" PRIx64 "\n",
-                    __func__, ppcemb_timer->pit_reload);
-        now = qemu_get_clock(vm_clock);
-        next = now + muldiv64(ppcemb_timer->pit_reload,
+                    __func__, ppc40x_timer->pit_reload);
+        now = qemu_get_clock_ns(vm_clock);
+        next = now + muldiv64(ppc40x_timer->pit_reload,
                               get_ticks_per_sec(), tb_env->decr_freq);
         if (is_excp)
             next += tb_env->decr_next - now;
@@ -847,21 +893,21 @@ static void cpu_4xx_pit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     env->spr[SPR_40x_TSR] |= 1 << 27;
     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
+        ppc_set_irq(env, ppc40x_timer->decr_excp, 1);
     start_stop_pit(env, tb_env, 1);
     LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
            "%016" PRIx64 "\n", __func__,
            (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
-           ppcemb_timer->pit_reload);
+           ppc40x_timer->pit_reload);
 }
 
 /* Watchdog timer */
@@ -869,13 +915,13 @@ static void cpu_4xx_wdt_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
-    now = qemu_get_clock(vm_clock);
+    ppc40x_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
     case 0:
         next = 1 << 17;
@@ -901,13 +947,13 @@ static void cpu_4xx_wdt_cb (void *opaque)
     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
     case 0x0:
     case 0x1:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 31;
         break;
     case 0x2:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 30;
         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
             ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
@@ -935,12 +981,12 @@ static void cpu_4xx_wdt_cb (void *opaque)
 void store_40x_pit (CPUState *env, target_ulong val)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
-    ppcemb_timer->pit_reload = val;
+    ppc40x_timer->pit_reload = val;
     start_stop_pit(env, tb_env, 0);
 }
 
@@ -949,31 +995,7 @@ target_ulong load_40x_pit (CPUState *env)
     return cpu_ppc_load_decr(env);
 }
 
-void store_booke_tsr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    ppcemb_timer_t *ppcemb_timer;
-
-    ppcemb_timer = tb_env->opaque;
-
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
-    if (val & 0x80000000)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
-}
-
-void store_booke_tcr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env;
-
-    tb_env = env->tb_env;
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
-    start_stop_pit(env, tb_env, 1);
-    cpu_4xx_wdt_cb(env);
-}
-
-static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
 {
     CPUState *env = opaque;
     ppc_tb_t *tb_env = env->tb_env;
@@ -985,30 +1007,31 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
     /* XXX: we should also update all timers */
 }
 
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
-    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    tb_env = g_malloc0(sizeof(ppc_tb_t));
     env->tb_env = tb_env;
-    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
+    ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
     tb_env->tb_freq = freq;
     tb_env->decr_freq = freq;
-    tb_env->opaque = ppcemb_timer;
+    tb_env->opaque = ppc40x_timer;
     LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
-    if (ppcemb_timer != NULL) {
+    if (ppc40x_timer != NULL) {
         /* We use decr timer for PIT */
-        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
-        ppcemb_timer->fit_timer =
-            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
-        ppcemb_timer->wdt_timer =
-            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
-        ppcemb_timer->decr_excp = decr_excp;
+        tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
+        ppc40x_timer->fit_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
+        ppc40x_timer->wdt_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
+        ppc40x_timer->decr_excp = decr_excp;
     }
 
-    return &ppc_emb_set_tb_clk;
+    return &ppc_40x_set_tb_clk;
 }
 
 /*****************************************************************************/
@@ -1098,7 +1121,7 @@ int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
 {
     ppc_dcr_t *dcr_env;
 
-    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
+    dcr_env = g_malloc0(sizeof(ppc_dcr_t));
     dcr_env->read_error = read_error;
     dcr_env->write_error = write_error;
     env->dcr_env = dcr_env;
index 34f54cf5da42bddc02d902670b689f12a68e29f8..9f911704af1447cc7ae9e8a84de96d202495c2c3 100644 (file)
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -1,3 +1,5 @@
+void ppc_set_irq (CPUState *env, int n_IRQ, int level);
+
 /* PowerPC hardware exceptions management helpers */
 typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
 typedef struct clk_setup_t clk_setup_t;
@@ -11,6 +13,36 @@ static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
         (*clk->cb)(clk->opaque, freq);
 }
 
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation                    */
+    int64_t  atb_offset;   /* Compensation                    */
+    uint32_t tb_freq;      /* TB frequency                    */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt    */
+    uint32_t decr_freq;    /* decrementer frequency           */
+    struct QEMUTimer *decr_timer;
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+    void *opaque;
+    uint32_t flags;
+};
+
+/* PPC Timers flags */
+#define PPC_TIMER_BOOKE              (1 << 0) /* Enable Booke support */
+#define PPC_TIMER_E500               (1 << 1) /* Enable e500 support */
+#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
+                                               * the most significant bit
+                                               * changes from 0 to 1.
+                                               */
+#define PPC_DECR_ZERO_TRIGGERED      (1 << 3) /* Decr interrupt triggered when
+                                               * the decrementer reaches zero.
+                                               */
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
 clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
 /* Embedded PowerPC DCR management */
 typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
@@ -19,7 +51,7 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
                   int (*dcr_write_error)(int dcrn));
 int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
                       dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp);
 
 /* Embedded PowerPC reset */
@@ -36,6 +68,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 {
@@ -54,3 +87,6 @@ enum {
 #define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
+
+/* ppc_booke.c */
+void ppc_booke_timers_init(CPUState *env, uint32_t freq, uint32_t flags);
index e042a05b3b5fe3c945e112ce0b743120d57dccf6..d8fdf0930ab1e4a40facfbfdf2e9736b7920a3e8 100644 (file)
@@ -59,16 +59,21 @@ struct ppc4xx_bd_info_t {
 ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
                                 uint32_t flags);
 
-CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
-                         target_phys_addr_t ram_sizes[4],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init);
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
-                         target_phys_addr_t ram_sizes[2],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init);
+CPUState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        target_phys_addr_t ram_bases[4],
+                        target_phys_addr_t ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
+CPUState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        target_phys_addr_t ram_bases[2],
+                        target_phys_addr_t ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
 /* IBM STBxxx microcontrollers */
-CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2],
+CPUState *ppc_stb025_init (MemoryRegion ram_memories[2],
+                           target_phys_addr_t ram_bases[2],
                            target_phys_addr_t ram_sizes[2],
                            uint32_t sysclk, qemu_irq **picp,
                            ram_addr_t *offsetp);
index 9abede7e051cb50b9e8da6601b34817d87faa94e..672e9347ac24805eefca550f441d07e5d1cf33f7 100644 (file)
@@ -32,6 +32,7 @@
 #include "qemu-log.h"
 #include "loader.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define BIOS_FILENAME "ppc405_rom.bin"
 #define BIOS_SIZE (2048 * 1024)
@@ -136,16 +137,16 @@ static void ref405ep_fpga_writel (void *opaque,
     ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
 }
 
-static CPUReadMemoryFunc * const ref405ep_fpga_read[] = {
-    &ref405ep_fpga_readb,
-    &ref405ep_fpga_readw,
-    &ref405ep_fpga_readl,
-};
-
-static CPUWriteMemoryFunc * const ref405ep_fpga_write[] = {
-    &ref405ep_fpga_writeb,
-    &ref405ep_fpga_writew,
-    &ref405ep_fpga_writel,
+static const MemoryRegionOps ref405ep_fpga_ops = {
+    .old_mmio = {
+        .read = {
+            ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
+        },
+        .write = {
+            ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ref405ep_fpga_reset (void *opaque)
@@ -157,16 +158,15 @@ static void ref405ep_fpga_reset (void *opaque)
     fpga->reg1 = 0x0F;
 }
 
-static void ref405ep_fpga_init (uint32_t base)
+static void ref405ep_fpga_init (MemoryRegion *sysmem, uint32_t base)
 {
     ref405ep_fpga_t *fpga;
-    int fpga_memory;
+    MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
 
-    fpga = qemu_mallocz(sizeof(ref405ep_fpga_t));
-    fpga_memory = cpu_register_io_memory(ref405ep_fpga_read,
-                                         ref405ep_fpga_write, fpga,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x00000100, fpga_memory);
+    fpga = g_malloc0(sizeof(ref405ep_fpga_t));
+    memory_region_init_io(fpga_memory, &ref405ep_fpga_ops, fpga,
+                          "fpga", 0x00000100);
+    memory_region_add_subregion(sysmem, base, fpga_memory);
     qemu_register_reset(&ref405ep_fpga_reset, fpga);
 }
 
@@ -181,7 +181,10 @@ static void ref405ep_init (ram_addr_t ram_size,
     ppc4xx_bd_info_t bd;
     CPUPPCState *env;
     qemu_irq *pic;
-    ram_addr_t sram_offset, bios_offset, bdloc;
+    MemoryRegion *bios;
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    ram_addr_t bdloc;
+    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
     target_phys_addr_t ram_bases[2], ram_sizes[2];
     target_ulong sram_size;
     long bios_size;
@@ -192,26 +195,25 @@ static void ref405ep_init (ram_addr_t ram_size,
     int linux_boot;
     int fl_idx, fl_sectors, len;
     DriveInfo *dinfo;
+    MemoryRegion *sysmem = get_system_memory();
 
     /* XXX: fix this */
-    ram_bases[0] = qemu_ram_alloc(NULL, "ef405ep.ram", 0x08000000);
+    memory_region_init_ram(&ram_memories[0], NULL, "ef405ep.ram", 0x08000000);
+    ram_bases[0] = 0;
     ram_sizes[0] = 0x08000000;
+    memory_region_init(&ram_memories[1], "ef405ep.ram1", 0);
     ram_bases[1] = 0x00000000;
     ram_sizes[1] = 0x00000000;
     ram_size = 128 * 1024 * 1024;
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
-                        kernel_filename == NULL ? 0 : 1);
+    env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
+                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
     /* allocate SRAM */
     sram_size = 512 * 1024;
-    sram_offset = qemu_ram_alloc(NULL, "ef405ep.sram", sram_size);
-#ifdef DEBUG_BOARD_INIT
-    printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
-#endif
-    cpu_register_physical_memory(0xFFF00000, sram_size,
-                                 sram_offset | IO_MEM_RAM);
+    memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size);
+    memory_region_add_subregion(sysmem, 0xFFF00000, sram);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register BIOS\n", __func__);
@@ -221,15 +223,15 @@ static void ref405ep_init (ram_addr_t ram_size,
     dinfo = drive_get(IF_PFLASH, 0, fl_idx);
     if (dinfo) {
         bios_size = bdrv_getlength(dinfo->bdrv);
-        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", bios_size);
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx addr %lx '%s' %d\n",
-               fl_idx, bios_size, bios_offset, -bios_size,
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "ef405ep.bios", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
@@ -240,13 +242,14 @@ static void ref405ep_init (ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
         printf("Load BIOS from file\n");
 #endif
-        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", BIOS_SIZE);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE);
         if (bios_name == NULL)
             bios_name = BIOS_FILENAME;
         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
         if (filename) {
-            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
-            qemu_free(filename);
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+            g_free(filename);
         } else {
             bios_size = -1;
         }
@@ -256,14 +259,14 @@ static void ref405ep_init (ram_addr_t ram_size,
             exit(1);
         }
         bios_size = (bios_size + 0xfff) & ~0xfff;
-        cpu_register_physical_memory((uint32_t)(-bios_size),
-                                     bios_size, bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
     }
     /* Register FPGA */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register FPGA\n", __func__);
 #endif
-    ref405ep_fpga_init(0xF0300000);
+    ref405ep_fpga_init(sysmem, 0xF0300000);
     /* Register NVRAM */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register NVRAM\n", __func__);
@@ -350,7 +353,7 @@ static void ref405ep_init (ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: Done\n", __func__);
 #endif
-    printf("bdloc %016lx\n", (unsigned long)bdloc);
+    printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
 }
 
 static QEMUMachine ref405ep_machine = {
@@ -461,16 +464,12 @@ static void taihu_cpld_writel (void *opaque,
     taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
 }
 
-static CPUReadMemoryFunc * const taihu_cpld_read[] = {
-    &taihu_cpld_readb,
-    &taihu_cpld_readw,
-    &taihu_cpld_readl,
-};
-
-static CPUWriteMemoryFunc * const taihu_cpld_write[] = {
-    &taihu_cpld_writeb,
-    &taihu_cpld_writew,
-    &taihu_cpld_writel,
+static const MemoryRegionOps taihu_cpld_ops = {
+    .old_mmio = {
+        .read = { taihu_cpld_readb, taihu_cpld_readw, taihu_cpld_readl, },
+        .write = { taihu_cpld_writeb, taihu_cpld_writew, taihu_cpld_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void taihu_cpld_reset (void *opaque)
@@ -482,16 +481,14 @@ static void taihu_cpld_reset (void *opaque)
     cpld->reg1 = 0x80;
 }
 
-static void taihu_cpld_init (uint32_t base)
+static void taihu_cpld_init (MemoryRegion *sysmem, uint32_t base)
 {
     taihu_cpld_t *cpld;
-    int cpld_memory;
+    MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
 
-    cpld = qemu_mallocz(sizeof(taihu_cpld_t));
-    cpld_memory = cpu_register_io_memory(taihu_cpld_read,
-                                         taihu_cpld_write, cpld,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x00000100, cpld_memory);
+    cpld = g_malloc0(sizeof(taihu_cpld_t));
+    memory_region_init_io(cpld_memory, &taihu_cpld_ops, cpld, "cpld", 0x100);
+    memory_region_add_subregion(sysmem, base, cpld_memory);
     qemu_register_reset(&taihu_cpld_reset, cpld);
 }
 
@@ -504,7 +501,9 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 {
     char *filename;
     qemu_irq *pic;
-    ram_addr_t bios_offset;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *bios;
+    MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
     target_phys_addr_t ram_bases[2], ram_sizes[2];
     long bios_size;
     target_ulong kernel_base, initrd_base;
@@ -514,16 +513,20 @@ static void taihu_405ep_init(ram_addr_t ram_size,
     DriveInfo *dinfo;
 
     /* RAM is soldered to the board so the size cannot be changed */
-    ram_bases[0] = qemu_ram_alloc(NULL, "taihu_405ep.ram-0", 0x04000000);
+    memory_region_init_ram(&ram_memories[0], NULL,
+                           "taihu_405ep.ram-0", 0x04000000);
+    ram_bases[0] = 0;
     ram_sizes[0] = 0x04000000;
-    ram_bases[1] = qemu_ram_alloc(NULL, "taihu_405ep.ram-1", 0x04000000);
+    memory_region_init_ram(&ram_memories[1], NULL,
+                           "taihu_405ep.ram-1", 0x04000000);
+    ram_bases[1] = 0x04000000;
     ram_sizes[1] = 0x04000000;
     ram_size = 0x08000000;
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
-                  kernel_filename == NULL ? 0 : 1);
+    ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
+                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register BIOS\n", __func__);
@@ -536,14 +539,14 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         /* XXX: should check that size is 2MB */
         //        bios_size = 2 * 1024 * 1024;
         fl_sectors = (bios_size + 65535) >> 16;
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", bios_size);
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx addr %lx '%s' %d\n",
-               fl_idx, bios_size, bios_offset, -bios_size,
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "taihu_405ep.bios", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
@@ -556,10 +559,12 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #endif
         if (bios_name == NULL)
             bios_name = BIOS_FILENAME;
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", BIOS_SIZE);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE);
         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
         if (filename) {
-            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+            g_free(filename);
         } else {
             bios_size = -1;
         }
@@ -569,8 +574,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
             exit(1);
         }
         bios_size = (bios_size + 0xfff) & ~0xfff;
-        cpu_register_physical_memory((uint32_t)(-bios_size),
-                                     bios_size, bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
     }
     /* Register Linux flash */
     dinfo = drive_get(IF_PFLASH, 0, fl_idx);
@@ -581,12 +586,11 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx  addr " TARGET_FMT_lx " '%s'\n",
-               fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
+               " at addr " TARGET_FMT_lx " '%s'\n",
+               fl_idx, bios_size, (target_ulong)0xfc000000,
                bdrv_get_device_name(dinfo->bdrv));
 #endif
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.flash", bios_size);
-        pflash_cfi02_register(0xfc000000, bios_offset,
+        pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
@@ -596,7 +600,7 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register CPLD\n", __func__);
 #endif
-    taihu_cpld_init(0x50100000);
+    taihu_cpld_init(sysmem, 0x50100000);
     /* Load kernel */
     linux_boot = (kernel_filename != NULL);
     if (linux_boot) {
index 334187e53b4fb09b9a637e7a858254acdfb5d5e9..a6e74318829ad85a9cbdf21167b3b5c583c93e2c 100644 (file)
@@ -28,6 +28,7 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "qemu-log.h"
+#include "exec-memory.h"
 
 #define DEBUG_OPBA
 #define DEBUG_SDRAM
@@ -51,39 +52,42 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
         bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
     else
         bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
-    stl_phys(bdloc + 0x00, bd->bi_memstart);
-    stl_phys(bdloc + 0x04, bd->bi_memsize);
-    stl_phys(bdloc + 0x08, bd->bi_flashstart);
-    stl_phys(bdloc + 0x0C, bd->bi_flashsize);
-    stl_phys(bdloc + 0x10, bd->bi_flashoffset);
-    stl_phys(bdloc + 0x14, bd->bi_sramstart);
-    stl_phys(bdloc + 0x18, bd->bi_sramsize);
-    stl_phys(bdloc + 0x1C, bd->bi_bootflags);
-    stl_phys(bdloc + 0x20, bd->bi_ipaddr);
-    for (i = 0; i < 6; i++)
+    stl_be_phys(bdloc + 0x00, bd->bi_memstart);
+    stl_be_phys(bdloc + 0x04, bd->bi_memsize);
+    stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
+    stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
+    stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
+    stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
+    stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
+    stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
+    stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
+    for (i = 0; i < 6; i++) {
         stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
-    stw_phys(bdloc + 0x2A, bd->bi_ethspeed);
-    stl_phys(bdloc + 0x2C, bd->bi_intfreq);
-    stl_phys(bdloc + 0x30, bd->bi_busfreq);
-    stl_phys(bdloc + 0x34, bd->bi_baudrate);
-    for (i = 0; i < 4; i++)
+    }
+    stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
+    stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
+    stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
+    stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
+    for (i = 0; i < 4; i++) {
         stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
+    }
     for (i = 0; i < 32; i++) {
         stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
     }
-    stl_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
-    stl_phys(bdloc + 0x60, bd->bi_pci_busfreq);
-    for (i = 0; i < 6; i++)
+    stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
+    stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
+    for (i = 0; i < 6; i++) {
         stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+    }
     n = 0x6A;
     if (flags & 0x00000001) {
         for (i = 0; i < 6; i++)
             stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
     }
-    stl_phys(bdloc + n, bd->bi_opbfreq);
+    stl_be_phys(bdloc + n, bd->bi_opbfreq);
     n += 4;
     for (i = 0; i < 2; i++) {
-        stl_phys(bdloc + n, bd->bi_iic_fast[i]);
+        stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
         n += 4;
     }
 
@@ -169,7 +173,7 @@ static void ppc4xx_plb_init(CPUState *env)
 {
     ppc4xx_plb_t *plb;
 
-    plb = qemu_mallocz(sizeof(ppc4xx_plb_t));
+    plb = g_malloc0(sizeof(ppc4xx_plb_t));
     ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
     ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
     ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
@@ -245,7 +249,7 @@ static void ppc4xx_pob_init(CPUState *env)
 {
     ppc4xx_pob_t *pob;
 
-    pob = qemu_mallocz(sizeof(ppc4xx_pob_t));
+    pob = g_malloc0(sizeof(ppc4xx_pob_t));
     ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
     ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
     ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
@@ -256,6 +260,7 @@ static void ppc4xx_pob_init(CPUState *env)
 /* OPB arbitrer */
 typedef struct ppc4xx_opba_t ppc4xx_opba_t;
 struct ppc4xx_opba_t {
+    MemoryRegion io;
     uint8_t cr;
     uint8_t pr;
 };
@@ -354,16 +359,12 @@ static void opba_writel (void *opaque,
     opba_writeb(opaque, addr + 1, value >> 16);
 }
 
-static CPUReadMemoryFunc * const opba_read[] = {
-    &opba_readb,
-    &opba_readw,
-    &opba_readl,
-};
-
-static CPUWriteMemoryFunc * const opba_write[] = {
-    &opba_writeb,
-    &opba_writew,
-    &opba_writel,
+static const MemoryRegionOps opba_ops = {
+    .old_mmio = {
+        .read = { opba_readb, opba_readw, opba_readl, },
+        .write = { opba_writeb, opba_writew, opba_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ppc4xx_opba_reset (void *opaque)
@@ -378,15 +379,13 @@ static void ppc4xx_opba_reset (void *opaque)
 static void ppc4xx_opba_init(target_phys_addr_t base)
 {
     ppc4xx_opba_t *opba;
-    int io;
 
-    opba = qemu_mallocz(sizeof(ppc4xx_opba_t));
+    opba = g_malloc0(sizeof(ppc4xx_opba_t));
 #ifdef DEBUG_OPBA
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(opba_read, opba_write, opba,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x002, io);
+    memory_region_init_io(&opba->io, &opba_ops, opba, "opba", 0x002);
+    memory_region_add_subregion(get_system_memory(), base, &opba->io);
     qemu_register_reset(ppc4xx_opba_reset, opba);
 }
 
@@ -579,7 +578,7 @@ static void ppc405_ebc_init(CPUState *env)
 {
     ppc4xx_ebc_t *ebc;
 
-    ebc = qemu_mallocz(sizeof(ppc4xx_ebc_t));
+    ebc = g_malloc0(sizeof(ppc4xx_ebc_t));
     qemu_register_reset(&ebc_reset, ebc);
     ppc_dcr_register(env, EBC0_CFGADDR,
                      ebc, &dcr_read_ebc, &dcr_write_ebc);
@@ -662,7 +661,7 @@ static void ppc405_dma_init(CPUState *env, qemu_irq irqs[4])
 {
     ppc405_dma_t *dma;
 
-    dma = qemu_mallocz(sizeof(ppc405_dma_t));
+    dma = g_malloc0(sizeof(ppc405_dma_t));
     memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
     qemu_register_reset(&ppc405_dma_reset, dma);
     ppc_dcr_register(env, DMA0_CR0,
@@ -719,6 +718,7 @@ static void ppc405_dma_init(CPUState *env, qemu_irq irqs[4])
 /* GPIO */
 typedef struct ppc405_gpio_t ppc405_gpio_t;
 struct ppc405_gpio_t {
+    MemoryRegion io;
     uint32_t or;
     uint32_t tcr;
     uint32_t osrh;
@@ -786,16 +786,12 @@ static void ppc405_gpio_writel (void *opaque,
 #endif
 }
 
-static CPUReadMemoryFunc * const ppc405_gpio_read[] = {
-    &ppc405_gpio_readb,
-    &ppc405_gpio_readw,
-    &ppc405_gpio_readl,
-};
-
-static CPUWriteMemoryFunc * const ppc405_gpio_write[] = {
-    &ppc405_gpio_writeb,
-    &ppc405_gpio_writew,
-    &ppc405_gpio_writel,
+static const MemoryRegionOps ppc405_gpio_ops = {
+    .old_mmio = {
+        .read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
+        .write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ppc405_gpio_reset (void *opaque)
@@ -805,15 +801,13 @@ static void ppc405_gpio_reset (void *opaque)
 static void ppc405_gpio_init(target_phys_addr_t base)
 {
     ppc405_gpio_t *gpio;
-    int io;
 
-    gpio = qemu_mallocz(sizeof(ppc405_gpio_t));
+    gpio = g_malloc0(sizeof(ppc405_gpio_t));
 #ifdef DEBUG_GPIO
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(ppc405_gpio_read, ppc405_gpio_write, gpio,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x038, io);
+    memory_region_init_io(&gpio->io, &ppc405_gpio_ops, gpio, "pgio", 0x038);
+    memory_region_add_subregion(get_system_memory(), base, &gpio->io);
     qemu_register_reset(&ppc405_gpio_reset, gpio);
 }
 
@@ -828,7 +822,9 @@ enum {
 
 typedef struct ppc405_ocm_t ppc405_ocm_t;
 struct ppc405_ocm_t {
-    target_ulong offset;
+    MemoryRegion ram;
+    MemoryRegion isarc_ram;
+    MemoryRegion dsarc_ram;
     uint32_t isarc;
     uint32_t isacntl;
     uint32_t dsarc;
@@ -851,16 +847,15 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm,
         if (ocm->isacntl & 0x80000000) {
             /* Unmap previously assigned memory region */
             printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc);
-            cpu_register_physical_memory(ocm->isarc, 0x04000000,
-                                         IO_MEM_UNASSIGNED);
+            memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram);
         }
         if (isacntl & 0x80000000) {
             /* Map new instruction memory region */
 #ifdef DEBUG_OCM
             printf("OCM map ISA %08" PRIx32 "\n", isarc);
 #endif
-            cpu_register_physical_memory(isarc, 0x04000000,
-                                         ocm->offset | IO_MEM_RAM);
+            memory_region_add_subregion(get_system_memory(), isarc,
+                                        &ocm->isarc_ram);
         }
     }
     if (ocm->dsarc != dsarc ||
@@ -872,8 +867,8 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm,
 #ifdef DEBUG_OCM
                 printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc);
 #endif
-                cpu_register_physical_memory(ocm->dsarc, 0x04000000,
-                                             IO_MEM_UNASSIGNED);
+                memory_region_del_subregion(get_system_memory(),
+                                            &ocm->dsarc_ram);
             }
         }
         if (dsacntl & 0x80000000) {
@@ -883,8 +878,8 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm,
 #ifdef DEBUG_OCM
                 printf("OCM map DSA %08" PRIx32 "\n", dsarc);
 #endif
-                cpu_register_physical_memory(dsarc, 0x04000000,
-                                             ocm->offset | IO_MEM_RAM);
+                memory_region_add_subregion(get_system_memory(), dsarc,
+                                            &ocm->dsarc_ram);
             }
         }
     }
@@ -969,8 +964,11 @@ static void ppc405_ocm_init(CPUState *env)
 {
     ppc405_ocm_t *ocm;
 
-    ocm = qemu_mallocz(sizeof(ppc405_ocm_t));
-    ocm->offset = qemu_ram_alloc(NULL, "ppc405.ocm", 4096);
+    ocm = g_malloc0(sizeof(ppc405_ocm_t));
+    /* XXX: Size is 4096 or 0x04000000 */
+    memory_region_init_ram(&ocm->isarc_ram, NULL, "ppc405.ocm", 4096);
+    memory_region_init_alias(&ocm->dsarc_ram, "ppc405.dsarc", &ocm->isarc_ram,
+                             0, 4096);
     qemu_register_reset(&ocm_reset, ocm);
     ppc_dcr_register(env, OCM0_ISARC,
                      ocm, &dcr_read_ocm, &dcr_write_ocm);
@@ -987,6 +985,7 @@ static void ppc405_ocm_init(CPUState *env)
 typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
 struct ppc4xx_i2c_t {
     qemu_irq irq;
+    MemoryRegion iomem;
     uint8_t mdata;
     uint8_t lmadr;
     uint8_t hmadr;
@@ -1183,16 +1182,12 @@ static void ppc4xx_i2c_writel (void *opaque,
     ppc4xx_i2c_writeb(opaque, addr + 3, value);
 }
 
-static CPUReadMemoryFunc * const i2c_read[] = {
-    &ppc4xx_i2c_readb,
-    &ppc4xx_i2c_readw,
-    &ppc4xx_i2c_readl,
-};
-
-static CPUWriteMemoryFunc * const i2c_write[] = {
-    &ppc4xx_i2c_writeb,
-    &ppc4xx_i2c_writew,
-    &ppc4xx_i2c_writel,
+static const MemoryRegionOps i2c_ops = {
+    .old_mmio = {
+        .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, },
+        .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ppc4xx_i2c_reset (void *opaque)
@@ -1214,16 +1209,14 @@ static void ppc4xx_i2c_reset (void *opaque)
 static void ppc405_i2c_init(target_phys_addr_t base, qemu_irq irq)
 {
     ppc4xx_i2c_t *i2c;
-    int io;
 
-    i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
+    i2c = g_malloc0(sizeof(ppc4xx_i2c_t));
     i2c->irq = irq;
 #ifdef DEBUG_I2C
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(i2c_read, i2c_write, i2c,
-                                DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x011, io);
+    memory_region_init_io(&i2c->iomem, &i2c_ops, i2c, "i2c", 0x011);
+    memory_region_add_subregion(get_system_memory(), base, &i2c->iomem);
     qemu_register_reset(ppc4xx_i2c_reset, i2c);
 }
 
@@ -1231,6 +1224,7 @@ static void ppc405_i2c_init(target_phys_addr_t base, qemu_irq irq)
 /* General purpose timers */
 typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
 struct ppc4xx_gpt_t {
+    MemoryRegion iomem;
     int64_t tb_offset;
     uint32_t tb_freq;
     struct QEMUTimer *timer;
@@ -1347,7 +1341,7 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr)
     switch (addr) {
     case 0x00:
         /* Time base counter */
-        ret = muldiv64(qemu_get_clock(vm_clock) + gpt->tb_offset,
+        ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset,
                        gpt->tb_freq, get_ticks_per_sec());
         break;
     case 0x10:
@@ -1404,7 +1398,7 @@ static void ppc4xx_gpt_writel (void *opaque,
     case 0x00:
         /* Time base counter */
         gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq)
-            - qemu_get_clock(vm_clock);
+            - qemu_get_clock_ns(vm_clock);
         ppc4xx_gpt_compute_timer(gpt);
         break;
     case 0x10:
@@ -1451,16 +1445,12 @@ static void ppc4xx_gpt_writel (void *opaque,
     }
 }
 
-static CPUReadMemoryFunc * const gpt_read[] = {
-    &ppc4xx_gpt_readb,
-    &ppc4xx_gpt_readw,
-    &ppc4xx_gpt_readl,
-};
-
-static CPUWriteMemoryFunc * const gpt_write[] = {
-    &ppc4xx_gpt_writeb,
-    &ppc4xx_gpt_writew,
-    &ppc4xx_gpt_writel,
+static const MemoryRegionOps gpt_ops = {
+    .old_mmio = {
+        .read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
+        .write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ppc4xx_gpt_cb (void *opaque)
@@ -1495,18 +1485,17 @@ static void ppc4xx_gpt_init(target_phys_addr_t base, qemu_irq irqs[5])
 {
     ppc4xx_gpt_t *gpt;
     int i;
-    int io;
 
-    gpt = qemu_mallocz(sizeof(ppc4xx_gpt_t));
+    gpt = g_malloc0(sizeof(ppc4xx_gpt_t));
     for (i = 0; i < 5; i++) {
         gpt->irqs[i] = irqs[i];
     }
-    gpt->timer = qemu_new_timer(vm_clock, &ppc4xx_gpt_cb, gpt);
+    gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt);
 #ifdef DEBUG_GPT
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(gpt_read, gpt_write, gpt, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x0d4, io);
+    memory_region_init_io(&gpt->iomem, &gpt_ops, gpt, "gpt", 0x0d4);
+    memory_region_add_subregion(get_system_memory(), base, &gpt->iomem);
     qemu_register_reset(ppc4xx_gpt_reset, gpt);
 }
 
@@ -1728,7 +1717,7 @@ static void ppc405_mal_init(CPUState *env, qemu_irq irqs[4])
     ppc40x_mal_t *mal;
     int i;
 
-    mal = qemu_mallocz(sizeof(ppc40x_mal_t));
+    mal = g_malloc0(sizeof(ppc40x_mal_t));
     for (i = 0; i < 4; i++)
         mal->irqs[i] = irqs[i];
     qemu_register_reset(&ppc40x_mal_reset, mal);
@@ -2093,7 +2082,7 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
 {
     ppc405cr_cpc_t *cpc;
 
-    cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t));
+    cpc = g_malloc0(sizeof(ppc405cr_cpc_t));
     memcpy(cpc->clk_setup, clk_setup,
            PPC405CR_CLK_NB * sizeof(clk_setup_t));
     cpc->sysclk = sysclk;
@@ -2118,10 +2107,12 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
     qemu_register_reset(ppc405cr_cpc_reset, cpc);
 }
 
-CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
-                         target_phys_addr_t ram_sizes[4],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init)
+CPUState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        target_phys_addr_t ram_bases[4],
+                        target_phys_addr_t ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
 {
     clk_setup_t clk_setup[PPC405CR_CLK_NB];
     qemu_irq dma_irqs[4];
@@ -2139,7 +2130,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
     /* OBP arbitrer */
     ppc4xx_opba_init(0xef600600);
     /* Universal interrupt controller */
-    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] =
         ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
     irqs[PPCUIC_OUTPUT_CINT] =
@@ -2147,7 +2138,8 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
     pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
     *picp = pic;
     /* SDRAM controller */
-    ppc4xx_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
+    ppc4xx_sdram_init(env, pic[14], 1, ram_memories,
+                      ram_bases, ram_sizes, do_init);
     /* External bus controller */
     ppc405_ebc_init(env);
     /* DMA controller */
@@ -2158,12 +2150,14 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
     ppc405_dma_init(env, dma_irqs);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
     /* IIC controller */
     ppc405_i2c_init(0xef600500, pic[2]);
@@ -2430,7 +2424,7 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
 {
     ppc405ep_cpc_t *cpc;
 
-    cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t));
+    cpc = g_malloc0(sizeof(ppc405ep_cpc_t));
     memcpy(cpc->clk_setup, clk_setup,
            PPC405EP_CLK_NB * sizeof(clk_setup_t));
     cpc->jtagid = 0x20267049;
@@ -2462,10 +2456,12 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
 #endif
 }
 
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
-                         target_phys_addr_t ram_sizes[2],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init)
+CPUState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        target_phys_addr_t ram_bases[2],
+                        target_phys_addr_t ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
 {
     clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
     qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
@@ -2487,7 +2483,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
     /* OBP arbitrer */
     ppc4xx_opba_init(0xef600600);
     /* Universal interrupt controller */
-    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] =
         ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
     irqs[PPCUIC_OUTPUT_CINT] =
@@ -2496,7 +2492,8 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
     *picp = pic;
     /* SDRAM controller */
        /* XXX 405EP has no ECC interrupt */
-    ppc4xx_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init);
+    ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
+                      ram_bases, ram_sizes, do_init);
     /* External bus controller */
     ppc405_ebc_init(env);
     /* DMA controller */
@@ -2511,12 +2508,14 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
     ppc405_gpio_init(0xef600700);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
     /* OCM */
     ppc405_ocm_init(env);
index 1ed001a031682b024d71687a5e4a799d5b668cdf..cd8a95d52b26a2cb6f21e5a85c9b86dbad265530 100644 (file)
@@ -34,10 +34,12 @@ static const unsigned int ppc440ep_sdram_bank_sizes[] = {
     256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
 };
 
-CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
-                        const unsigned int pci_irq_nrs[4], int do_init,
-                        const char *cpu_model)
+CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
+                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
+                        int do_init, const char *cpu_model)
 {
+    MemoryRegion *ram_memories
+        = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
     target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
     target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
     CPUState *env;
@@ -45,8 +47,9 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     qemu_irq *irqs;
     qemu_irq *pci_irqs;
 
-    if (cpu_model == NULL)
-        cpu_model = "405"; // XXX: should be 440EP
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx"; // XXX: should be 440EP
+    }
     env = cpu_init(cpu_model);
     if (!env) {
         fprintf(stderr, "Unable to initialize CPU!\n");
@@ -56,7 +59,7 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     ppc_dcr_init(env, NULL, NULL);
 
     /* interrupt controller */
-    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
     irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
     pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
@@ -65,14 +68,15 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     memset(ram_bases, 0, sizeof(ram_bases));
     memset(ram_sizes, 0, sizeof(ram_sizes));
     *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
+                                    ram_memories,
                                     ram_bases, ram_sizes,
                                     ppc440ep_sdram_bank_sizes);
     /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
-    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_bases,
-                      ram_sizes, do_init);
+    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+                      ram_bases, ram_sizes, do_init);
 
     /* PCI */
-    pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
+    pci_irqs = g_malloc(sizeof(qemu_irq) * 4);
     pci_irqs[0] = pic[pci_irq_nrs[0]];
     pci_irqs[1] = pic[pci_irq_nrs[1]];
     pci_irqs[2] = pic[pci_irq_nrs[2]];
@@ -88,12 +92,14 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
 
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
 
     return env;
index a40f9176dbcf00e08536709e6258453d594ad392..9c27c36fd0b7c2aec31e39dfb362b1ea6fcc1903 100644 (file)
@@ -14,8 +14,8 @@
 
 #include "hw.h"
 
-CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
-                        const unsigned int pci_irq_nrs[4], int do_init,
-                        const char *cpu_model);
+CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size,
+                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
+                        int do_init, const char *cpu_model);
 
 #endif
index 34ddf454779b5bdada423dd22d4d8c603971aabe..b734e3a56c636e635ca6dd724fd45a6edcd6ecba 100644 (file)
 #include "hw.h"
 #include "pci.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "ppc440.h"
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "device_tree.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -44,13 +44,15 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
     char *filename;
     int fdt_size;
     void *fdt;
+    uint32_t tb_freq = 400000000;
+    uint32_t clock_freq = 400000000;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
         goto out;
     }
     fdt = load_device_tree(filename, &fdt_size);
-    qemu_free(filename);
+    g_free(filename);
     if (fdt == NULL) {
         goto out;
     }
@@ -77,11 +79,21 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
     if (ret < 0)
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
-    if (kvm_enabled())
-        kvmppc_fdt_update(fdt);
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
+    if (kvm_enabled()) {
+        tb_freq = kvmppc_get_tbfreq();
+        clock_freq = kvmppc_get_clockfreq();
+    }
+
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+                              clock_freq);
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+                              tb_freq);
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
-    qemu_free(fdt);
+    g_free(fdt);
 
 out:
 #endif
@@ -97,6 +109,7 @@ static void bamboo_init(ram_addr_t ram_size,
                         const char *cpu_model)
 {
     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
+    MemoryRegion *address_space_mem = get_system_memory();
     PCIBus *pcibus;
     CPUState *env;
     uint64_t elf_entry;
@@ -108,7 +121,8 @@ static void bamboo_init(ram_addr_t ram_size,
     int i;
 
     /* Setup CPU. */
-    env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1, cpu_model);
+    env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
+                        pci_irq_nrs, 1, cpu_model);
 
     if (pcibus) {
         /* Register network interfaces. */
@@ -156,8 +170,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 bc4ee019a53aab74bfa1bf9752b82ab56dab7e64..f969e44e1bbc5b8ebb75c15755f1ad76f94bc28e 100644 (file)
@@ -42,11 +42,13 @@ qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
                        uint32_t dcr_base, int has_ssr, int has_vr);
 
 ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               MemoryRegion ram_memories[],
                                target_phys_addr_t ram_bases[],
                                target_phys_addr_t ram_sizes[],
                                const unsigned int sdram_bank_sizes[]);
 
 void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        MemoryRegion ram_memories[],
                         target_phys_addr_t *ram_bases,
                         target_phys_addr_t *ram_sizes,
                         int do_init);
index 5f581fe2c4eaee80c4b44fd05febc333e2863c72..d18caa419214af4d1bb6e34a4f54ba80922b1eac 100644 (file)
@@ -24,8 +24,8 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc4xx.h"
-#include "sysemu.h"
 #include "qemu-log.h"
+#include "exec-memory.h"
 
 //#define DEBUG_MMIO
 //#define DEBUG_UNASSIGNED
@@ -39,7 +39,7 @@
 #endif
 
 /*****************************************************************************/
-/* Generic PowerPC 4xx processor instanciation */
+/* Generic PowerPC 4xx processor instantiation */
 CPUState *ppc4xx_init (const char *cpu_model,
                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
                        uint32_t sysclk)
@@ -56,7 +56,7 @@ CPUState *ppc4xx_init (const char *cpu_model,
     cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
     cpu_clk->opaque = env;
     /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
+    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
     tb_clk->opaque = env;
     ppc_dcr_init(env, NULL, NULL);
     /* Register qemu callbacks */
@@ -294,7 +294,7 @@ qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
     ppcuic_t *uic;
     int i;
 
-    uic = qemu_mallocz(sizeof(ppcuic_t));
+    uic = g_malloc0(sizeof(ppcuic_t));
     uic->dcr_base = dcr_base;
     uic->irqs = irqs;
     if (has_vr)
@@ -314,6 +314,8 @@ typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
 struct ppc4xx_sdram_t {
     uint32_t addr;
     int nbanks;
+    MemoryRegion containers[4]; /* used for clipping */
+    MemoryRegion *ram_memories;
     target_phys_addr_t ram_bases[4];
     target_phys_addr_t ram_sizes[4];
     uint32_t besr0;
@@ -396,16 +398,22 @@ static target_ulong sdram_size (uint32_t bcr)
     return size;
 }
 
-static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
+static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
+                          uint32_t *bcrp, uint32_t bcr, int enabled)
 {
+    unsigned n = bcrp - sdram->bcr;
+
     if (*bcrp & 0x00000001) {
         /* Unmap RAM */
 #ifdef DEBUG_SDRAM
         printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
                __func__, sdram_base(*bcrp), sdram_size(*bcrp));
 #endif
-        cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
-                                     IO_MEM_UNASSIGNED);
+        memory_region_del_subregion(get_system_memory(),
+                                    &sdram->containers[n]);
+        memory_region_del_subregion(&sdram->containers[n],
+                                    &sdram->ram_memories[n]);
+        memory_region_destroy(&sdram->containers[n]);
     }
     *bcrp = bcr & 0xFFDEE001;
     if (enabled && (bcr & 0x00000001)) {
@@ -413,8 +421,13 @@ static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
         printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
                __func__, sdram_base(bcr), sdram_size(bcr));
 #endif
-        cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
-                                     sdram_base(bcr) | IO_MEM_RAM);
+        memory_region_init(&sdram->containers[n], "sdram-containers",
+                           sdram_size(bcr));
+        memory_region_add_subregion(&sdram->containers[n], 0,
+                                    &sdram->ram_memories[n]);
+        memory_region_add_subregion(get_system_memory(),
+                                    sdram_base(bcr),
+                                    &sdram->containers[n]);
     }
 }
 
@@ -424,11 +437,12 @@ static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
 
     for (i = 0; i < sdram->nbanks; i++) {
         if (sdram->ram_sizes[i] != 0) {
-            sdram_set_bcr(&sdram->bcr[i],
+            sdram_set_bcr(sdram,
+                          &sdram->bcr[i],
                           sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
                           1);
         } else {
-            sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
+            sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
         }
     }
 }
@@ -442,9 +456,8 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
         printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
                __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
 #endif
-        cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
-                                     sdram_size(sdram->bcr[i]),
-                                     IO_MEM_UNASSIGNED);
+        memory_region_del_subregion(get_system_memory(),
+                                    &sdram->ram_memories[i]);
     }
 }
 
@@ -569,16 +582,16 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
             sdram->pmit = (val & 0xF8000000) | 0x07C00000;
             break;
         case 0x40: /* SDRAM_B0CR */
-            sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
             break;
         case 0x44: /* SDRAM_B1CR */
-            sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
             break;
         case 0x48: /* SDRAM_B2CR */
-            sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
             break;
         case 0x4C: /* SDRAM_B3CR */
-            sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
             break;
         case 0x80: /* SDRAM_TR */
             sdram->tr = val & 0x018FC01F;
@@ -622,15 +635,17 @@ static void sdram_reset (void *opaque)
 }
 
 void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        MemoryRegion *ram_memories,
                         target_phys_addr_t *ram_bases,
                         target_phys_addr_t *ram_sizes,
                         int do_init)
 {
     ppc4xx_sdram_t *sdram;
 
-    sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
+    sdram = g_malloc0(sizeof(ppc4xx_sdram_t));
     sdram->irq = irq;
     sdram->nbanks = nbanks;
+    sdram->ram_memories = ram_memories;
     memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t));
     memcpy(sdram->ram_bases, ram_bases,
            nbanks * sizeof(target_phys_addr_t));
@@ -654,11 +669,13 @@ void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
  * must be one of a small set of sizes. The number of banks and the supported
  * sizes varies by SoC. */
 ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               MemoryRegion ram_memories[],
                                target_phys_addr_t ram_bases[],
                                target_phys_addr_t ram_sizes[],
                                const unsigned int sdram_bank_sizes[])
 {
     ram_addr_t size_left = ram_size;
+    ram_addr_t base = 0;
     int i;
     int j;
 
@@ -669,8 +686,10 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
             if (bank_size <= size_left) {
                 char name[32];
                 snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
-                ram_bases[i] = qemu_ram_alloc(NULL, name, bank_size);
+                memory_region_init_ram(&ram_memories[i], NULL, name, bank_size);
+                ram_bases[i] = base;
                 ram_sizes[i] = bank_size;
+                base += ram_size;
                 size_left -= bank_size;
                 break;
             }
index f62f1f91d52cc78b64ff06259115e35399040f1d..339b38ec7ab793c1f3df3faddfbd42fc566680f8 100644 (file)
@@ -24,6 +24,7 @@
 #include "ppc4xx.h"
 #include "pci.h"
 #include "pci_host.h"
+#include "exec-memory.h"
 
 #undef DEBUG
 #ifdef DEBUG
@@ -285,50 +286,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],
@@ -342,12 +341,15 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     static int ppc4xx_pci_id;
     uint8_t *pci_conf;
 
-    controller = qemu_mallocz(sizeof(PPC4xxPCIState));
+    controller = g_malloc0(sizeof(PPC4xxPCIState));
 
     controller->pci_state.bus = pci_register_bus(NULL, "pci",
                                                  ppc4xx_pci_set_irq,
                                                  ppc4xx_pci_map_irq,
-                                                 pci_irqs, 0, 4);
+                                                 pci_irqs,
+                                                 get_system_memory(),
+                                                 get_system_io(),
+                                                 0, 4);
 
     controller->pci_dev = pci_register_device(controller->pci_state.bus,
                                               "host bridge", sizeof(PCIDevice),
@@ -366,10 +368,12 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
 
     /* CFGDATA */
-    index = pci_host_data_register_mmio(&controller->pci_state, 1);
-    if (index < 0)
-        goto free;
-    cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
+    memory_region_init_io(&controller->pci_state.data_mem,
+                          &pci_host_data_be_ops,
+                          &controller->pci_state, "pci-conf-data", 4);
+    memory_region_add_subregion(get_system_memory(),
+                                config_space + PCIC0_CFGDATA,
+                                &controller->pci_state.data_mem);
 
     /* Internal registers */
     index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
@@ -381,13 +385,13 @@ 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;
 
 free:
     printf("%s error\n", __func__);
-    qemu_free(controller);
+    g_free(controller);
     return NULL;
 }
diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c
new file mode 100644 (file)
index 0000000..8871945
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * QEMU PowerPC Booke hardware System Emulator
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "nvram.h"
+#include "qemu-log.h"
+#include "loader.h"
+
+
+/* Timer Control Register */
+
+#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
+#define TCR_WP_MASK   (0x3 << TCR_WP_SHIFT)
+#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
+#define TCR_WRC_MASK  (0x3 << TCR_WRC_SHIFT)
+#define TCR_WIE       (1 << 27) /* Watchdog Timer Interrupt Enable */
+#define TCR_DIE       (1 << 26) /* Decrementer Interrupt Enable */
+#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
+#define TCR_FP_MASK   (0x3 << TCR_FP_SHIFT)
+#define TCR_FIE       (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
+#define TCR_ARE       (1 << 22) /* Auto-Reload Enable */
+
+/* Timer Control Register (e500 specific fields) */
+
+#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
+#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
+#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
+#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
+
+/* Timer Status Register  */
+
+#define TSR_FIS       (1 << 26) /* Fixed-Interval Timer Interrupt Status */
+#define TSR_DIS       (1 << 27) /* Decrementer Interrupt Status */
+#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
+#define TSR_WRS_MASK  (0x3 << TSR_WRS_SHIFT)
+#define TSR_WIS       (1 << 30) /* Watchdog Timer Interrupt Status */
+#define TSR_ENW       (1 << 31) /* Enable Next Watchdog Timer */
+
+typedef struct booke_timer_t booke_timer_t;
+struct booke_timer_t {
+
+    uint64_t fit_next;
+    struct QEMUTimer *fit_timer;
+
+    uint64_t wdt_next;
+    struct QEMUTimer *wdt_timer;
+
+    uint32_t flags;
+};
+
+static void booke_update_irq(CPUState *env)
+{
+    ppc_set_irq(env, PPC_INTERRUPT_DECR,
+                (env->spr[SPR_BOOKE_TSR] & TSR_DIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
+
+    ppc_set_irq(env, PPC_INTERRUPT_WDT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_WIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
+
+    ppc_set_irq(env, PPC_INTERRUPT_FIT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_FIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
+}
+
+/* Return the location of the bit of time base at which the FIT will raise an
+   interrupt */
+static uint8_t booke_get_fit_target(CPUState *env, ppc_tb_t *tb_env)
+{
+    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Fixed-interval timer period extension */
+        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
+            >> TCR_E500_FPEXT_SHIFT;
+        fp = 63 - (fp | fpext << 2);
+    } else {
+        fp = env->fit_period[fp];
+    }
+
+    return fp;
+}
+
+/* Return the location of the bit of time base at which the WDT will raise an
+   interrupt */
+static uint8_t booke_get_wdt_target(CPUState *env, ppc_tb_t *tb_env)
+{
+    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Watchdog timer period extension */
+        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
+            >> TCR_E500_WPEXT_SHIFT;
+        wp = 63 - (wp | wpext << 2);
+    } else {
+        wp = env->wdt_period[wp];
+    }
+
+    return wp;
+}
+
+static void booke_update_fixed_timer(CPUState         *env,
+                                     uint8_t           target_bit,
+                                     uint64_t          *next,
+                                     struct QEMUTimer *timer)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t lapse;
+    uint64_t tb;
+    uint64_t period = 1 << (target_bit + 1);
+    uint64_t now;
+
+    now = qemu_get_clock_ns(vm_clock);
+    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
+
+    lapse = period - ((tb - (1 << target_bit)) & (period - 1));
+
+    *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq);
+
+    /* XXX: If expire time is now. We can't run the callback because we don't
+     * have access to it. So we just set the timer one nanosecond later.
+     */
+
+    if (*next == now) {
+        (*next)++;
+    }
+
+    qemu_mod_timer(timer, *next);
+}
+
+static void booke_decr_cb(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
+    booke_update_irq(env);
+
+    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
+        /* Auto Reload */
+        cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+    }
+}
+
+static void booke_fit_cb(void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+}
+
+static void booke_wdt_cb(void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+
+    /* TODO: There's lots of complicated stuff to do here */
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+}
+
+void store_booke_tsr(CPUState *env, target_ulong val)
+{
+    env->spr[SPR_BOOKE_TSR] &= ~val;
+    booke_update_irq(env);
+}
+
+void store_booke_tcr(CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer = tb_env->opaque;
+
+    tb_env = env->tb_env;
+    env->spr[SPR_BOOKE_TCR] = val;
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+
+}
+
+void ppc_booke_timers_init(CPUState *env, uint32_t freq, uint32_t flags)
+{
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env      = g_malloc0(sizeof(ppc_tb_t));
+    booke_timer = g_malloc0(sizeof(booke_timer_t));
+
+    env->tb_env = tb_env;
+    tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
+
+    tb_env->tb_freq    = freq;
+    tb_env->decr_freq  = freq;
+    tb_env->opaque     = booke_timer;
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env);
+
+    booke_timer->fit_timer =
+        qemu_new_timer_ns(vm_clock, &booke_fit_cb, env);
+    booke_timer->wdt_timer =
+        qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env);
+}
index ea8759324cd6510f3c34d75a5d36af691c23220f..af75e45cc2a3a0ec55e1a27f14353fd64e9af97a 100644 (file)
@@ -25,6 +25,8 @@
 #if !defined(__PPC_MAC_H__)
 #define __PPC_MAC_H__
 
+#include "memory.h"
+
 /* SMP is not enabled, for now */
 #define MAX_CPUS 1
 
 #define PROM_ADDR         0xfff00000
 
 #define KERNEL_LOAD_ADDR 0x01000000
-#define CMDLINE_ADDR     0x027ff000
-#define INITRD_LOAD_ADDR 0x02800000
+#define KERNEL_GAP       0x00100000
 
 #define ESCC_CLOCK 3686400
 
 /* Cuda */
-void cuda_init (int *cuda_mem_index, qemu_irq irq);
+void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq);
 
 /* MacIO */
-void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index);
+void macio_init (PCIBus *bus, int device_id, int is_oldworld,
+                 MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
+                 MemoryRegion *cuda_mem, void *nvram,
+                 int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem);
 
 /* Heathrow PIC */
-qemu_irq *heathrow_pic_init(int *pmem_index,
+qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
                             int nb_cpus, qemu_irq **irqs);
 
 /* Grackle PCI */
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io);
 
 /* UniNorth PCI */
-PCIBus *pci_pmac_init(qemu_irq *pic);
-PCIBus *pci_pmac_u3_init(qemu_irq *pic);
+PCIBus *pci_pmac_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io);
 
 /* Mac NVRAM */
 typedef struct MacIONVRAMState MacIONVRAMState;
 
-MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+MacIONVRAMState *macio_nvram_init (target_phys_addr_t size,
                                    unsigned int it_shift);
-void macio_nvram_map (void *opaque, target_phys_addr_t mem_base);
+void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
+                           target_phys_addr_t mem_base);
 void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len);
 uint32_t macio_nvram_read (void *opaque, uint32_t addr);
 void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val);
-
-/* adb.c */
-
-#define MAX_ADB_DEVICES 16
-
-#define ADB_MAX_OUT_LEN 16
-
-typedef struct ADBDevice ADBDevice;
-
-/* buf = NULL means polling */
-typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
-                              const uint8_t *buf, int len);
-typedef int ADBDeviceReset(ADBDevice *d);
-
-struct ADBDevice {
-    struct ADBBusState *bus;
-    int devaddr;
-    int handler;
-    ADBDeviceRequest *devreq;
-    ADBDeviceReset *devreset;
-    void *opaque;
-};
-
-typedef struct ADBBusState {
-    ADBDevice devices[MAX_ADB_DEVICES];
-    int nb_devices;
-    int poll_index;
-} ADBBusState;
-
-int adb_request(ADBBusState *s, uint8_t *buf_out,
-                const uint8_t *buf, int len);
-int adb_poll(ADBBusState *s, uint8_t *buf_out);
-
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
-                               ADBDeviceRequest *devreq,
-                               ADBDeviceReset *devreset,
-                               void *opaque);
-void adb_kbd_init(ADBBusState *bus);
-void adb_mouse_init(ADBBusState *bus);
-
-extern ADBBusState adb_bus;
-
 #endif /* !defined(__PPC_MAC_H__) */
index b9245f066a12bb8ed4a37cc85a4ac462fd6981b6..8c84f9e9a502f4f86e1c864c79b755c29a01342d 100644 (file)
@@ -49,6 +49,7 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
 #include "pc.h"
@@ -67,6 +68,7 @@
 #include "kvm_ppc.h"
 #include "hw/usb.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MAX_IDE_BUS 2
 #define CFG_ADDR 0xf0000510
 #endif
 
 /* UniN device */
-static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void unin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
 {
-    UNIN_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", addr, value);
+    UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value);
 }
 
-static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t unin_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     uint32_t value;
 
@@ -97,16 +100,10 @@ static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const unin_write[] = {
-    &unin_writel,
-    &unin_writel,
-    &unin_writel,
-};
-
-static CPUReadMemoryFunc * const unin_read[] = {
-    &unin_readl,
-    &unin_readl,
-    &unin_readl,
+static const MemoryRegionOps unin_ops = {
+    .read = unin_read,
+    .write = unin_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int fw_cfg_boot_set(void *opaque, const char *boot_device)
@@ -120,6 +117,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
 }
 
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
 /* PowerPC Mac99 hardware initialisation */
 static void ppc_core99_init (ram_addr_t ram_size,
                              const char *boot_device,
@@ -131,17 +133,17 @@ static void ppc_core99_init (ram_addr_t ram_size,
     CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **openpic_irqs;
-    int unin_memory;
+    MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset;
-    uint32_t kernel_base, initrd_base;
+    MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
+    target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0;
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
-    int nvram_mem_index;
     int bios_size;
-    int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
-    int ide_mem_index[3];
+    MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem;
+    MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
+    MemoryRegion *ide_mem[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
@@ -169,22 +171,23 @@ static void ppc_core99_init (ram_addr_t ram_size,
     }
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "ppc_core99.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_core99.ram", ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
 
     /* allocate and load BIOS */
-    bios_offset = qemu_ram_alloc(NULL, "ppc_core99.bios", BIOS_SIZE);
+    memory_region_init_ram(bios, NULL, "ppc_core99.bios", BIOS_SIZE);
     if (bios_name == NULL)
         bios_name = PROM_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_set_readonly(bios, true);
+    memory_region_add_subregion(get_system_memory(), PROM_ADDR, bios);
 
     /* Load OpenBIOS (ELF) */
     if (filename) {
         bios_size = load_elf(filename, NULL, NULL, NULL,
                              NULL, NULL, 1, ELF_MACHINE, 0);
 
-        qemu_free(filename);
+        g_free(filename);
     } else {
         bios_size = -1;
     }
@@ -220,7 +223,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         }
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
             initrd_size = load_image_targphys(initrd_filename, initrd_base,
                                               ram_size - initrd_base);
             if (initrd_size < 0) {
@@ -228,9 +231,11 @@ static void ppc_core99_init (ram_addr_t ram_size,
                          initrd_filename);
                 exit(1);
             }
+            cmdline_base = round_page(initrd_base + initrd_size);
         } else {
             initrd_base = 0;
             initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
         }
         ppc_boot_device = 'm';
     } else {
@@ -254,19 +259,16 @@ static void ppc_core99_init (ram_addr_t ram_size,
         }
     }
 
-    isa_mem_base = 0x80000000;
-
     /* Register 8 MB of ISA IO space */
     isa_mmio_init(0xf2000000, 0x00800000);
 
     /* UniN init */
-    unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
+    memory_region_init_io(unin_memory, &unin_ops, NULL, "unin", 0x1000);
+    memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory);
 
-    openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+    openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
     openpic_irqs[0] =
-        qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+        g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
     for (i = 0; i < smp_cpus; i++) {
         /* Mac99 IRQ connection between OpenPIC outputs pins
          * and PowerPC input pins
@@ -307,51 +309,45 @@ static void ppc_core99_init (ram_addr_t ram_size,
             exit(1);
         }
     }
-    pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
+    pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL);
     if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
         /* 970 gets a U3 bus */
-        pci_bus = pci_pmac_u3_init(pic);
+        pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
         machine_arch = ARCH_MAC99_U3;
     } else {
-        pci_bus = pci_pmac_init(pic);
+        pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
         machine_arch = ARCH_MAC99;
     }
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
 
-    escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
-                               serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
+    escc_mem = escc_init(0, pic[0x25], pic[0x24],
+                         serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
+    memory_region_init_alias(escc_bar, "escc-bar",
+                             escc_mem, 0, memory_region_size(escc_mem));
 
     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);
-    }
-    dbdma = DBDMA_init(&dbdma_mem_index);
+    ide_drive_get(hd, MAX_IDE_BUS);
+    dbdma = DBDMA_init(&dbdma_mem);
 
     /* 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[0] = NULL;
+    ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
+    ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
 
     /* cuda also initialize ADB */
     if (machine_arch == ARCH_MAC99_U3) {
         usb_enabled = 1;
     }
-    cuda_init(&cuda_mem_index, pic[0x19]);
+    cuda_init(&cuda_mem, pic[0x19]);
 
     adb_kbd_init(&adb_bus);
     adb_mouse_init(&adb_bus);
 
-    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
-               escc_mem_index);
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem,
+               dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
@@ -368,9 +364,9 @@ static void ppc_core99_init (ram_addr_t ram_size,
         graphic_depth = 15;
 
     /* The NewWorld NVRAM is not located in the MacIO device */
-    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 1);
+    nvr = macio_nvram_init(0x2000, 1);
     pmac_format_nvram_partition(nvr, 0x2000);
-    macio_nvram_map(nvr, 0xFFF04000);
+    macio_nvram_setup_bar(nvr, get_system_memory(), 0xFFF04000);
     /* No PCI init: the BIOS will do it */
 
     fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
@@ -380,8 +376,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
@@ -399,7 +395,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         uint8_t *hypercall;
 
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
-        hypercall = qemu_malloc(16);
+        hypercall = g_malloc(16);
         kvmppc_get_hypercall(env, hypercall, 16);
         fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
index 8a4e088a384ff0560ea0922e5a998a7cb616be90..aac3526f558faa1fa2f6aad5652667742e02d1c1 100644 (file)
@@ -26,6 +26,7 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
 #include "pc.h"
@@ -43,6 +44,7 @@
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MAX_IDE_BUS 2
 #define CFG_ADDR 0xf0000510
@@ -59,6 +61,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
 }
 
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
 static void ppc_heathrow_init (ram_addr_t ram_size,
                                const char *boot_device,
                                const char *kernel_filename,
@@ -66,18 +73,20 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                                const char *initrd_filename,
                                const char *cpu_model)
 {
+    MemoryRegion *sysmem = get_system_memory();
     CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **heathrow_irqs;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset;
-    uint32_t kernel_base, initrd_base;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    uint32_t kernel_base, initrd_base, cmdline_base = 0;
     int32_t kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
     int bios_size;
-    int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
-    int escc_mem_index, ide_mem_index[2];
+    MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem;
+    MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2];
     uint16_t ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
@@ -107,21 +116,22 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         exit(1);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_heathrow.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate and load BIOS */
-    bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);
+    memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE);
     if (bios_name == NULL)
         bios_name = PROM_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_set_readonly(bios, true);
+    memory_region_add_subregion(sysmem, PROM_ADDR, bios);
 
     /* Load OpenBIOS (ELF) */
     if (filename) {
         bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
                              1, ELF_MACHINE, 0);
-        qemu_free(filename);
+        g_free(filename);
     } else {
         bios_size = -1;
     }
@@ -157,7 +167,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         }
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
             initrd_size = load_image_targphys(initrd_filename, initrd_base,
                                               ram_size - initrd_base);
             if (initrd_size < 0) {
@@ -165,9 +175,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                          initrd_filename);
                 exit(1);
             }
+            cmdline_base = round_page(initrd_base + initrd_size);
         } else {
             initrd_base = 0;
             initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
         }
         ppc_boot_device = 'm';
     } else {
@@ -199,15 +211,13 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         }
     }
 
-    isa_mem_base = 0x80000000;
-
     /* Register 2 MB of ISA IO space */
     isa_mmio_init(0xfe000000, 0x00200000);
 
     /* XXX: we register only 1 output pin for heathrow PIC */
-    heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+    heathrow_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
     heathrow_irqs[0] =
-        qemu_mallocz(smp_cpus * sizeof(qemu_irq) * 1);
+        g_malloc0(smp_cpus * sizeof(qemu_irq) * 1);
     /* Connect the heathrow PIC outputs to the 6xx bus */
     for (i = 0; i < smp_cpus; i++) {
         switch (PPC_INPUT(env)) {
@@ -225,47 +235,45 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
         hw_error("Only 6xx bus is supported on heathrow machine\n");
     }
-    pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
-    pci_bus = pci_grackle_init(0xfec00000, pic);
+    pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
+    pci_bus = pci_grackle_init(0xfec00000, pic,
+                               get_system_memory(),
+                               get_system_io());
     pci_vga_init(pci_bus);
 
-    escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
+    escc_mem = escc_init(0, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
+    memory_region_init_alias(escc_bar, "escc-bar",
+                             escc_mem, 0, memory_region_size(escc_mem));
 
     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);
 
     /* 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]);
+    dbdma = DBDMA_init(&dbdma_mem);
+    ide_mem[0] = NULL;
+    ide_mem[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);
 
     /* cuda also initialize ADB */
-    cuda_init(&cuda_mem_index, pic[0x12]);
+    cuda_init(&cuda_mem, pic[0x12]);
 
     adb_kbd_init(&adb_bus);
     adb_mouse_init(&adb_bus);
 
-    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 4);
+    nvr = macio_nvram_init(0x2000, 4);
     pmac_format_nvram_partition(nvr, 0x2000);
 
-    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
-               escc_mem_index);
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem,
+               dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
@@ -283,8 +291,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
@@ -302,7 +310,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         uint8_t *hypercall;
 
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
-        hypercall = qemu_malloc(16);
+        hypercall = g_malloc(16);
         kvmppc_get_hypercall(env, hypercall, 16);
         fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
index 6b221221c273234882e3d6d23816377eef78e170..f22d5b98c5da1f3c3b9f6a1fd5a3140cbf88c180 100644 (file)
@@ -38,6 +38,7 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
@@ -82,7 +83,7 @@ static const int ide_irq[2] = { 13, 13 };
 static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
 static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
 
-//static PITState *pit;
+//static ISADevice *pit;
 
 /* ISA IO ports bridge */
 #define PPC_IO_BASE 0x80000000
@@ -105,7 +106,7 @@ static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
 {
 #if 0
     int out;
-    out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
+    out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock));
     dummy_refresh_clock ^= 1;
     return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
         (dummy_refresh_clock << 4);
@@ -115,21 +116,22 @@ static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
 
 /* PCI intack register */
 /* Read-only register (?) */
-static void _PPC_intack_write (void *opaque,
-                               target_phys_addr_t addr, uint32_t value)
+static void PPC_intack_write (void *opaque, target_phys_addr_t addr,
+                              uint64_t value, unsigned size)
 {
 #if 0
-    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx64 "\n", __func__, addr,
            value);
 #endif
 }
 
-static inline uint32_t _PPC_intack_read(target_phys_addr_t addr)
+static uint64_t PPC_intack_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     uint32_t retval = 0;
 
     if ((addr & 0xf) == 0)
-        retval = pic_intack_read(isa_pic);
+        retval = pic_read_irq(isa_pic);
 #if 0
     printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
            retval);
@@ -138,31 +140,10 @@ static inline uint32_t _PPC_intack_read(target_phys_addr_t addr)
     return retval;
 }
 
-static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static CPUWriteMemoryFunc * const PPC_intack_write[] = {
-    &_PPC_intack_write,
-    &_PPC_intack_write,
-    &_PPC_intack_write,
-};
-
-static CPUReadMemoryFunc * const PPC_intack_read[] = {
-    &PPC_intack_readb,
-    &PPC_intack_readw,
-    &PPC_intack_readl,
+static const MemoryRegionOps PPC_intack_ops = {
+    .read = PPC_intack_read,
+    .write = PPC_intack_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 /* PowerPC control and status registers */
@@ -243,17 +224,14 @@ static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const PPC_XCSR_write[] = {
-    &PPC_XCSR_writeb,
-    &PPC_XCSR_writew,
-    &PPC_XCSR_writel,
+static const MemoryRegionOps PPC_XCSR_ops = {
+    .old_mmio = {
+        .read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, },
+        .write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const PPC_XCSR_read[] = {
-    &PPC_XCSR_readb,
-    &PPC_XCSR_readw,
-    &PPC_XCSR_readl,
-};
 #endif
 
 /* Fake super-io ports for PREP platform (Intel 82378ZB) */
@@ -502,16 +480,12 @@ static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static CPUWriteMemoryFunc * const PPC_prep_io_write[] = {
-    &PPC_prep_io_writeb,
-    &PPC_prep_io_writew,
-    &PPC_prep_io_writel,
-};
-
-static CPUReadMemoryFunc * const PPC_prep_io_read[] = {
-    &PPC_prep_io_readb,
-    &PPC_prep_io_readw,
-    &PPC_prep_io_readl,
+static const MemoryRegionOps PPC_prep_io_ops = {
+    .old_mmio = {
+        .read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
+        .write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 #define NVRAM_SIZE        0x2000
@@ -533,13 +507,19 @@ static void ppc_prep_init (ram_addr_t ram_size,
                            const char *initrd_filename,
                            const char *cpu_model)
 {
+    MemoryRegion *sysmem = get_system_memory();
     CPUState *env = NULL;
     char *filename;
     nvram_t nvram;
     M48t59State *m48t59;
-    int PPC_io_memory;
+    MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
+    MemoryRegion *intack = g_new(MemoryRegion, 1);
+#if 0
+    MemoryRegion *xcsr = g_new(MemoryRegion, 1);
+#endif
     int linux_boot, i, nb_nics1, bios_size;
-    ram_addr_t ram_offset, bios_offset;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     uint32_t kernel_base, initrd_base;
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
@@ -549,7 +529,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DriveInfo *fd[MAX_FD];
 
-    sysctrl = qemu_mallocz(sizeof(sysctrl_t));
+    sysctrl = g_malloc0(sizeof(sysctrl_t));
 
     linux_boot = (kernel_filename != NULL);
 
@@ -573,11 +553,11 @@ static void ppc_prep_init (ram_addr_t ram_size,
     }
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "ppc_prep.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_prep.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate and load BIOS */
-    bios_offset = qemu_ram_alloc(NULL, "ppc_prep.bios", BIOS_SIZE);
+    memory_region_init_ram(bios, NULL, "ppc_prep.bios", BIOS_SIZE);
     if (bios_name == NULL)
         bios_name = BIOS_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
@@ -590,15 +570,15 @@ static void ppc_prep_init (ram_addr_t ram_size,
         target_phys_addr_t bios_addr;
         bios_size = (bios_size + 0xfff) & ~0xfff;
         bios_addr = (uint32_t)(-bios_size);
-        cpu_register_physical_memory(bios_addr, bios_size,
-                                     bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, bios_addr, bios);
         bios_size = load_image_targphys(filename, bios_addr, bios_size);
     }
     if (bios_size < 0 || bios_size > BIOS_SIZE) {
         hw_error("qemu: could not load PPC PREP bios '%s'\n", bios_name);
     }
     if (filename) {
-        qemu_free(filename);
+        g_free(filename);
     }
 
     if (linux_boot) {
@@ -647,22 +627,21 @@ static void ppc_prep_init (ram_addr_t ram_size,
     if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
         hw_error("Only 6xx bus is supported on PREP machine\n");
     }
-    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
-    pci_bus = pci_prep_init(i8259);
     /* Hmm, prep has no pci-isa bridge ??? */
-    isa_bus_new(NULL);
+    isa_bus_new(NULL, get_system_io());
+    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+    pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
     isa_bus_irqs(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
-    PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
-                                           PPC_prep_io_write, sysctrl,
-                                           DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
+    memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl,
+                          "ppc-io", 0x00800000);
+    memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory);
 
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
     //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
-    //    pit = pit_init(0x40, i8259[0]);
+    //    pit = pit_init(0x40, 0);
     rtc_init(2000, NULL);
 
     if (serial_hds[0])
@@ -672,7 +651,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
         nb_nics1 = NE2000_NB_MAX;
     for(i = 0; i < nb_nics1; i++) {
         if (nd_table[i].model == NULL) {
-           nd_table[i].model = qemu_strdup("ne2k_isa");
+           nd_table[i].model = g_strdup("ne2k_isa");
         }
         if (strcmp(nd_table[i].model, "ne2k_isa") == 0) {
             isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
@@ -681,15 +660,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],
@@ -720,15 +691,12 @@ static void ppc_prep_init (ram_addr_t ram_size,
     register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
     register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
     /* PCI intack location */
-    PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
-                                           PPC_intack_write, NULL,
-                                           DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
+    memory_region_init_io(intack, &PPC_intack_ops, NULL, "ppc-intack", 4);
+    memory_region_add_subregion(sysmem, 0xBFFFFFF0, intack);
     /* PowerPC control and status register group */
 #if 0
-    PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write,
-                                           NULL, DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
+    memory_region_init_io(xcsr, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000);
+    memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
 #endif
 
     if (usb_enabled) {
index b7670ae27ce6f48947eba35f4ea2f808081cb134..51b6abddd36aad112b2f4b13f88e78ce86d91331 100644 (file)
@@ -14,8 +14,6 @@
  * (at your option) any later version.
  */
 
-#include <dirent.h>
-
 #include "config.h"
 #include "qemu-common.h"
 #include "net.h"
 #include "kvm_ppc.h"
 #include "device_tree.h"
 #include "openpic.h"
-#include "ppce500.h"
+#include "ppc.h"
 #include "loader.h"
 #include "elf.h"
+#include "sysbus.h"
+#include "exec-memory.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
 #define MPC8544_PCI_REGS_SIZE      0x1000
 #define MPC8544_PCI_IO             0xE1000000
 #define MPC8544_PCI_IOLEN          0x10000
+#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000)
+#define MPC8544_SPIN_BASE          0xEF000000
 
-#ifdef CONFIG_FDT
-static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
+struct boot_info
 {
-    uint32_t cell;
-    int ret;
-
-    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
-    if (ret < 0) {
-        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
-        goto out;
-    }
-
-    ret = qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
-                                prop, cell);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't set guest /cpus/PowerPC,8544@0/%s\n", prop);
-        goto out;
-    }
-
-out:
-    return ret;
-}
-#endif
+    uint32_t dt_base;
+    uint32_t entry;
+};
 
-static int mpc8544_load_device_tree(target_phys_addr_t addr,
-                                     uint32_t ramsize,
-                                     target_phys_addr_t initrd_base,
-                                     target_phys_addr_t initrd_size,
-                                     const char *kernel_cmdline)
+static int mpc8544_load_device_tree(CPUState *env,
+                                    target_phys_addr_t addr,
+                                    uint32_t ramsize,
+                                    target_phys_addr_t initrd_base,
+                                    target_phys_addr_t initrd_size,
+                                    const char *kernel_cmdline)
 {
     int ret = -1;
 #ifdef CONFIG_FDT
-    uint32_t mem_reg_property[] = {0, ramsize};
+    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
     char *filename;
     int fdt_size;
     void *fdt;
+    uint8_t hypercall[16];
+    uint32_t clock_freq = 400000000;
+    uint32_t tb_freq = 400000000;
+    int i;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
         goto out;
     }
     fdt = load_device_tree(filename, &fdt_size);
-    qemu_free(filename);
+    g_free(filename);
     if (fdt == NULL) {
         goto out;
     }
@@ -103,15 +92,19 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
     if (ret < 0)
         fprintf(stderr, "couldn't set /memory/reg\n");
 
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                                    initrd_base);
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+    if (initrd_size) {
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                        initrd_base);
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+        }
 
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                                    (initrd_base + initrd_size));
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                        (initrd_base + initrd_size));
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        }
+    }
 
     ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                       kernel_cmdline);
@@ -119,36 +112,59 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
     if (kvm_enabled()) {
-        struct dirent *dirp;
-        DIR *dp;
-        char buf[128];
-
-        if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) {
-            printf("Can't open directory /proc/device-tree/cpus/\n");
-            ret = -1;
-            goto out;
-        }
+        /* Read out host's frequencies */
+        clock_freq = kvmppc_get_clockfreq();
+        tb_freq = kvmppc_get_tbfreq();
+
+        /* indicate KVM hypercall interface */
+        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
+                                    "linux,kvm");
+        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
+        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
+                             hypercall, sizeof(hypercall));
+    }
+
+    /* We need to generate the cpu nodes in reverse order, so Linux can pick
+       the first node as boot node and be happy */
+    for (i = smp_cpus - 1; i >= 0; i--) {
+        char cpu_name[128];
+        uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));
 
-        buf[0] = '\0';
-        while ((dirp = readdir(dp)) != NULL) {
-            if (strncmp(dirp->d_name, "PowerPC", 7) == 0) {
-                snprintf(buf, 128, "/cpus/%s", dirp->d_name);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (env->cpu_index == i) {
                 break;
             }
         }
-        closedir(dp);
-        if (buf[0] == '\0') {
-            printf("Unknow host!\n");
-            ret = -1;
-            goto out;
+
+        if (!env) {
+            continue;
         }
 
-        mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
-        mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
+        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
+        qemu_devtree_add_subnode(fdt, cpu_name);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
+        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
+                                  env->dcache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
+                                  env->icache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
+        if (env->cpu_index) {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
+            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
+            qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
+                                 &cpu_release_addr, sizeof(cpu_release_addr));
+        } else {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
+        }
     }
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
-    qemu_free(fdt);
+    g_free(fdt);
 
 out:
 #endif
@@ -156,6 +172,55 @@ out:
     return ret;
 }
 
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return ffs(size >> 10) - 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
+    target_phys_addr_t size;
+
+    size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = va & TARGET_PAGE_MASK;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+
+    env->tlb_dirty = true;
+}
+
+static void mpc8544ds_cpu_reset_sec(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+
+    /* Secondary CPU starts in halted state for now. Needs to change when
+       implementing non-kernel boot. */
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+}
+
+static void mpc8544ds_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(env);
+
+    /* Set initial guest state. */
+    env->halted = 0;
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = bi->dt_base;
+    env->nip = bi->entry;
+    mmubooke_create_initial_mapping(env, 0, 0);
+}
+
 static void mpc8544ds_init(ram_addr_t ram_size,
                          const char *boot_device,
                          const char *kernel_filename,
@@ -163,8 +228,10 @@ static void mpc8544ds_init(ram_addr_t ram_size,
                          const char *initrd_filename,
                          const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     PCIBus *pci_bus;
-    CPUState *env;
+    CPUState *env = NULL;
     uint64_t elf_entry;
     uint64_t elf_lowaddr;
     target_phys_addr_t entry=0;
@@ -175,48 +242,89 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     target_long initrd_size=0;
     int i=0;
     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
-    qemu_irq *irqs, *mpic, *pci_irqs;
+    qemu_irq **irqs, *mpic;
+    DeviceState *dev;
+    CPUState *firstenv = NULL;
+
+    /* Setup CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "e500v2_v30";
+    }
+
+    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
+    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+    for (i = 0; i < smp_cpus; i++) {
+        qemu_irq *input;
+        env = cpu_ppc_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to initialize CPU!\n");
+            exit(1);
+        }
+
+        if (!firstenv) {
+            firstenv = env;
+        }
 
-    /* Setup CPU */
-    env = cpu_ppc_init("e500v2_v30");
-    if (!env) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
+        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
+        input = (qemu_irq *)env->irq_inputs;
+        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
+        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
+        env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
+
+        ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
+
+        /* Register reset handler */
+        if (!i) {
+            /* Primary CPU */
+            struct boot_info *boot_info;
+            boot_info = g_malloc0(sizeof(struct boot_info));
+            qemu_register_reset(mpc8544ds_cpu_reset, env);
+            env->load_info = boot_info;
+        } else {
+            /* Secondary CPUs */
+            qemu_register_reset(mpc8544ds_cpu_reset_sec, env);
+        }
     }
 
+    env = firstenv;
+
     /* Fixup Memory size on a alignment boundary */
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
 
     /* Register Memory */
-    cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL,
-                                 "mpc8544ds.ram", ram_size));
+    memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* MPIC */
-    irqs = qemu_mallocz(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
-    irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
-    irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
-    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
+    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
+                     smp_cpus, irqs, NULL);
+
+    if (!mpic) {
+        cpu_abort(env, "MPIC failed to initialize\n");
+    }
 
     /* Serial */
     if (serial_hds[0]) {
-        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+        serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
     if (serial_hds[1]) {
-        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+        serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
+    /* General Utility device */
+    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
+
     /* PCI */
-    pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
-    pci_irqs[0] = mpic[pci_irq_nrs[0]];
-    pci_irqs[1] = mpic[pci_irq_nrs[1]];
-    pci_irqs[2] = mpic[pci_irq_nrs[2]];
-    pci_irqs[3] = mpic[pci_irq_nrs[3]];
-    pci_bus = ppce500_pci_init(pci_irqs, MPC8544_PCI_REGS_BASE);
+    dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
+                                mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
+                                mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
+                                NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
     if (!pci_bus)
         printf("couldn't create PCI controller!\n");
 
@@ -229,6 +337,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         }
     }
 
+    /* Register spinning region */
+    sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
+
     /* Load kernel. */
     if (kernel_filename) {
         kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
@@ -261,32 +372,33 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* If we're loading a kernel directly, we must load the device tree too. */
     if (kernel_filename) {
+        struct boot_info *boot_info;
+
+#ifndef CONFIG_FDT
+        cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
+#endif
         dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
-        if (mpc8544_load_device_tree(dt_base, ram_size,
+        if (mpc8544_load_device_tree(env, dt_base, ram_size,
                     initrd_base, initrd_size, kernel_cmdline) < 0) {
             fprintf(stderr, "couldn't load device tree\n");
             exit(1);
         }
 
-        cpu_synchronize_state(env);
-
-        /* Set initial guest state. */
-        env->gpr[1] = (16<<20) - 8;
-        env->gpr[3] = dt_base;
-        env->nip = entry;
-        /* XXX we currently depend on KVM to create some initial TLB entries. */
+        boot_info = env->load_info;
+        boot_info->entry = entry;
+        boot_info->dt_base = dt_base;
     }
 
-    if (kvm_enabled())
+    if (kvm_enabled()) {
         kvmppc_init();
-
-    return;
+    }
 }
 
 static QEMUMachine mpc8544ds_machine = {
     .name = "mpc8544ds",
     .desc = "mpc8544ds",
     .init = mpc8544ds_init,
+    .max_cpus = 15,
 };
 
 static void mpc8544ds_machine_init(void)
index 11edd03f16f56c396336f7459fe1438070ce84ae..960a5d0c608f826b7a0451ca0b11f70efccd79bb 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include "hw.h"
-#include "ppce500.h"
 #include "pci.h"
 #include "pci_host.h"
 #include "bswap.h"
@@ -29,7 +28,8 @@
 #define PCIE500_CFGADDR       0x0
 #define PCIE500_CFGDATA       0x4
 #define PCIE500_REG_BASE      0xC00
-#define PCIE500_REG_SIZE      (0x1000 - PCIE500_REG_BASE)
+#define PCIE500_ALL_SIZE      0x1000
+#define PCIE500_REG_SIZE      (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
 
 #define PPCE500_PCI_CONFIG_ADDR         0x0
 #define PPCE500_PCI_CONFIG_DATA         0x4
@@ -73,11 +73,13 @@ struct pci_inbound {
 };
 
 struct PPCE500PCIState {
+    PCIHostState pci_state;
     struct pci_outbound pob[PPCE500_PCI_NR_POBS];
     struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
     uint32_t gasket_time;
-    PCIHostState pci_state;
-    PCIDevice *pci_dev;
+    qemu_irq irq[4];
+    /* mmio maps */
+    int reg;
 };
 
 typedef struct PPCE500PCIState PPCE500PCIState;
@@ -87,6 +89,7 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr)
     PPCE500PCIState *pci = opaque;
     unsigned long win;
     uint32_t value = 0;
+    int idx;
 
     win = addr & 0xfe0;
 
@@ -95,24 +98,44 @@ static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr)
     case PPCE500_PCI_OW2:
     case PPCE500_PCI_OW3:
     case PPCE500_PCI_OW4:
+        idx = (addr >> 5) & 0x7;
         switch (addr & 0xC) {
-        case PCI_POTAR: value = pci->pob[(addr >> 5) & 0x7].potar; break;
-        case PCI_POTEAR: value = pci->pob[(addr >> 5) & 0x7].potear; break;
-        case PCI_POWBAR: value = pci->pob[(addr >> 5) & 0x7].powbar; break;
-        case PCI_POWAR: value = pci->pob[(addr >> 5) & 0x7].powar; break;
-        default: break;
+        case PCI_POTAR:
+            value = pci->pob[idx].potar;
+            break;
+        case PCI_POTEAR:
+            value = pci->pob[idx].potear;
+            break;
+        case PCI_POWBAR:
+            value = pci->pob[idx].powbar;
+            break;
+        case PCI_POWAR:
+            value = pci->pob[idx].powar;
+            break;
+        default:
+            break;
         }
         break;
 
     case PPCE500_PCI_IW3:
     case PPCE500_PCI_IW2:
     case PPCE500_PCI_IW1:
+        idx = ((addr >> 5) & 0x3) - 1;
         switch (addr & 0xC) {
-        case PCI_PITAR: value = pci->pib[(addr >> 5) & 0x3].pitar; break;
-        case PCI_PIWBAR: value = pci->pib[(addr >> 5) & 0x3].piwbar; break;
-        case PCI_PIWBEAR: value = pci->pib[(addr >> 5) & 0x3].piwbear; break;
-        case PCI_PIWAR: value = pci->pib[(addr >> 5) & 0x3].piwar; break;
-        default: break;
+        case PCI_PITAR:
+            value = pci->pib[idx].pitar;
+            break;
+        case PCI_PIWBAR:
+            value = pci->pib[idx].piwbar;
+            break;
+        case PCI_PIWBEAR:
+            value = pci->pib[idx].piwbear;
+            break;
+        case PCI_PIWAR:
+            value = pci->pib[idx].piwar;
+            break;
+        default:
+            break;
         };
         break;
 
@@ -140,6 +163,7 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr,
 {
     PPCE500PCIState *pci = opaque;
     unsigned long win;
+    int idx;
 
     win = addr & 0xfe0;
 
@@ -151,24 +175,44 @@ static void pci_reg_write4(void *opaque, target_phys_addr_t addr,
     case PPCE500_PCI_OW2:
     case PPCE500_PCI_OW3:
     case PPCE500_PCI_OW4:
+        idx = (addr >> 5) & 0x7;
         switch (addr & 0xC) {
-        case PCI_POTAR: pci->pob[(addr >> 5) & 0x7].potar = value; break;
-        case PCI_POTEAR: pci->pob[(addr >> 5) & 0x7].potear = value; break;
-        case PCI_POWBAR: pci->pob[(addr >> 5) & 0x7].powbar = value; break;
-        case PCI_POWAR: pci->pob[(addr >> 5) & 0x7].powar = value; break;
-        default: break;
+        case PCI_POTAR:
+            pci->pob[idx].potar = value;
+            break;
+        case PCI_POTEAR:
+            pci->pob[idx].potear = value;
+            break;
+        case PCI_POWBAR:
+            pci->pob[idx].powbar = value;
+            break;
+        case PCI_POWAR:
+            pci->pob[idx].powar = value;
+            break;
+        default:
+            break;
         };
         break;
 
     case PPCE500_PCI_IW3:
     case PPCE500_PCI_IW2:
     case PPCE500_PCI_IW1:
+        idx = ((addr >> 5) & 0x3) - 1;
         switch (addr & 0xC) {
-        case PCI_PITAR: pci->pib[(addr >> 5) & 0x3].pitar = value; break;
-        case PCI_PIWBAR: pci->pib[(addr >> 5) & 0x3].piwbar = value; break;
-        case PCI_PIWBEAR: pci->pib[(addr >> 5) & 0x3].piwbear = value; break;
-        case PCI_PIWAR: pci->pib[(addr >> 5) & 0x3].piwar = value; break;
-        default: break;
+        case PCI_PITAR:
+            pci->pib[idx].pitar = value;
+            break;
+        case PCI_PIWBAR:
+            pci->pib[idx].piwbar = value;
+            break;
+        case PCI_PIWBEAR:
+            pci->pib[idx].piwbear = value;
+            break;
+        case PCI_PIWAR:
+            pci->pib[idx].piwar = value;
+            break;
+        default:
+            break;
         };
         break;
 
@@ -198,7 +242,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,111 +260,125 @@ 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);
+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()
+    }
+};
 
-    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);
+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_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_ppce500_pci = {
+    .name = "ppce500_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        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_put_be32s(f, &controller->gasket_time);
+};
+
+static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+
+    sysbus_add_memory(dev, base + PCIE500_CFGADDR, &h->conf_mem);
+    sysbus_add_memory(dev, base + PCIE500_CFGDATA, &h->data_mem);
+    cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
+                                 s->reg);
 }
 
-static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id)
+static void e500_pci_unmap(SysBusDevice *dev, target_phys_addr_t base)
 {
-    PPCE500PCIState *controller = opaque;
-    int i;
+    PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
 
-    if (version_id != 1)
-        return -EINVAL;
+    sysbus_del_memory(dev, &h->conf_mem);
+    sysbus_del_memory(dev, &h->data_mem);
+    cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
+                                 IO_MEM_UNASSIGNED);
+}
 
-    pci_device_load(controller->pci_dev, f);
+#include "exec-memory.h"
 
-    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 int e500_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *h;
+    PPCE500PCIState *s;
+    PCIBus *b;
+    int i;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *address_space_io = get_system_io();
+
+    h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = DO_UPCAST(PPCE500PCIState, pci_state, h);
 
-    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);
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
     }
-    qemu_get_be32s(f, &controller->gasket_time);
+
+    b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
+                         mpc85xx_pci_map_irq, s->irq, address_space_mem,
+                         address_space_io, PCI_DEVFN(0x11, 0), 4);
+    s->pci_state.bus = b;
+
+    pci_create_simple(b, 0, "e500-host-bridge");
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, h,
+                          "pci-conf-idx", 4);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+                          "pci-conf-data", 4);
+    s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s,
+                                    DEVICE_BIG_ENDIAN);
+    sysbus_init_mmio_cb2(dev, e500_pci_map, e500_pci_unmap);
 
     return 0;
 }
 
-PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
+static PCIDeviceInfo e500_host_bridge_info = {
+    .qdev.name    = "e500-host-bridge",
+    .qdev.desc    = "Host bridge",
+    .qdev.size    = sizeof(PCIDevice),
+    .vendor_id    = PCI_VENDOR_ID_FREESCALE,
+    .device_id    = PCI_DEVICE_ID_MPC8533E,
+    .class_id     = PCI_CLASS_PROCESSOR_POWERPC,
+};
+
+static SysBusDeviceInfo e500_pcihost_info = {
+    .init         = e500_pcihost_initfn,
+    .qdev.name    = "e500-pcihost",
+    .qdev.size    = sizeof(PPCE500PCIState),
+    .qdev.vmsd    = &vmstate_ppce500_pci,
+};
+
+static void e500_pci_register(void)
 {
-    PPCE500PCIState *controller;
-    PCIDevice *d;
-    int index;
-    static int ppce500_pci_id;
-
-    controller = qemu_mallocz(sizeof(PPCE500PCIState));
-
-    controller->pci_state.bus = pci_register_bus(NULL, "pci",
-                                                 mpc85xx_pci_set_irq,
-                                                 mpc85xx_pci_map_irq,
-                                                 pci_irqs, PCI_DEVFN(0x11, 0),
-                                                 4);
-    d = pci_register_device(controller->pci_state.bus,
-                            "host bridge", sizeof(PCIDevice),
-                            0, NULL, NULL);
-
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E);
-    pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC);
-
-    controller->pci_dev = d;
-
-    /* CFGADDR */
-    index = pci_host_conf_register_mmio(&controller->pci_state,
-                                        DEVICE_BIG_ENDIAN);
-    if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
-
-    /* CFGDATA */
-    index = pci_host_data_register_mmio(&controller->pci_state,
-                                        DEVICE_BIG_ENDIAN);
-    if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
-
-    index = cpu_register_io_memory(e500_pci_reg_read,
-                                   e500_pci_reg_write, controller,
-                                   DEVICE_NATIVE_ENDIAN);
-    if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_REG_BASE,
-                                   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);
-
-    return controller->pci_state.bus;
-
-free:
-    printf("%s error\n", __func__);
-    qemu_free(controller);
-    return NULL;
+    sysbus_register_withprop(&e500_pcihost_info);
+    pci_qdev_register(&e500_host_bridge_info);
 }
+device_init(e500_pci_register);
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
new file mode 100644 (file)
index 0000000..2b52728
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * QEMU PowerPC e500v2 ePAPR spinning code
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: 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/>.
+ *
+ * This code is not really a device, but models an interface that usually
+ * firmware takes care of. It's used when QEMU plays the role of firmware.
+ *
+ * Specification:
+ *
+ * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "kvm.h"
+
+#define MAX_CPUS 32
+
+typedef struct spin_info {
+    uint64_t addr;
+    uint64_t r3;
+    uint32_t resv;
+    uint32_t pir;
+    uint64_t reserved;
+} __attribute__ ((packed)) SpinInfo;
+
+typedef struct spin_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    SpinInfo spin[MAX_CPUS];
+} SpinState;
+
+typedef struct spin_kick {
+    CPUState *env;
+    SpinInfo *spin;
+} SpinKick;
+
+static void spin_reset(void *opaque)
+{
+    SpinState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        SpinInfo *info = &s->spin[i];
+
+        info->pir = i;
+        info->r3 = i;
+        info->addr = 1;
+    }
+}
+
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return (ffs(size >> 10) - 1) >> 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa,
+                                     target_phys_addr_t len)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
+    target_phys_addr_t size;
+
+    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static void spin_kick(void *data)
+{
+    SpinKick *kick = data;
+    CPUState *env = kick->env;
+    SpinInfo *curspin = kick->spin;
+    target_phys_addr_t map_size = 64 * 1024 * 1024;
+    target_phys_addr_t map_start;
+
+    cpu_synchronize_state(env);
+    stl_p(&curspin->pir, env->spr[SPR_PIR]);
+    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
+    env->gpr[3] = ldq_p(&curspin->r3);
+    env->gpr[4] = 0;
+    env->gpr[5] = 0;
+    env->gpr[6] = 0;
+    env->gpr[7] = map_size;
+    env->gpr[8] = 0;
+    env->gpr[9] = 0;
+
+    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
+    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
+
+    env->halted = 0;
+    env->exception_index = -1;
+    env->stopped = 0;
+    qemu_cpu_kick(env);
+}
+
+static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned len)
+{
+    SpinState *s = opaque;
+    int env_idx = addr / sizeof(SpinInfo);
+    CPUState *env;
+    SpinInfo *curspin = &s->spin[env_idx];
+    uint8_t *curspin_p = (uint8_t*)curspin;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index == env_idx) {
+            break;
+        }
+    }
+
+    if (!env) {
+        /* Unknown CPU */
+        return;
+    }
+
+    if (!env->cpu_index) {
+        /* primary CPU doesn't spin */
+        return;
+    }
+
+    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
+    switch (len) {
+    case 1:
+        stb_p(curspin_p, value);
+        break;
+    case 2:
+        stw_p(curspin_p, value);
+        break;
+    case 4:
+        stl_p(curspin_p, value);
+        break;
+    }
+
+    if (!(ldq_p(&curspin->addr) & 1)) {
+        /* run CPU */
+        SpinKick kick = {
+            .env = env,
+            .spin = curspin,
+        };
+
+        run_on_cpu(env, spin_kick, &kick);
+    }
+}
+
+static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
+{
+    SpinState *s = opaque;
+    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
+
+    switch (len) {
+    case 1:
+        return ldub_p(spin_p);
+    case 2:
+        return lduw_p(spin_p);
+    case 4:
+        return ldl_p(spin_p);
+    default:
+        assert(0);
+    }
+}
+
+const MemoryRegionOps spin_rw_ops = {
+    .read = spin_read,
+    .write = spin_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int ppce500_spin_initfn(SysBusDevice *dev)
+{
+    SpinState *s;
+
+    s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
+
+    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
+                          sizeof(SpinInfo) * MAX_CPUS);
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    qemu_register_reset(spin_reset, s);
+
+    return 0;
+}
+
+static SysBusDeviceInfo ppce500_spin_info = {
+    .init         = ppce500_spin_initfn,
+    .qdev.name    = "e500-spin",
+    .qdev.size    = sizeof(SpinState),
+};
+
+static void ppce500_spin_register(void)
+{
+    sysbus_register_withprop(&ppce500_spin_info);
+}
+device_init(ppce500_spin_register);
index f88b8254c2749d47036b70938173a4f88c5a748c..149807a7d5047f04045241f82158e9c516e05c28 100644 (file)
@@ -110,19 +110,30 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
 }
 
-PCIBus *pci_prep_init(qemu_irq *pic)
+PCIBus *pci_prep_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io)
 {
     PREPPCIState *s;
     PCIDevice *d;
     int PPC_io_memory;
 
-    s = qemu_mallocz(sizeof(PREPPCIState));
+    s = g_malloc0(sizeof(PREPPCIState));
     s->bus = pci_register_bus(NULL, "pci",
-                              prep_set_irq, prep_map_irq, pic, 0, 4);
-
-    pci_host_conf_register_ioport(0xcf8, s);
-
-    pci_host_data_register_ioport(0xcfc, s);
+                              prep_set_irq, prep_map_irq, pic,
+                              address_space_mem,
+                              address_space_io,
+                              0, 4);
+
+    memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s,
+                          "pci-conf-idx", 1);
+    memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
+    sysbus_init_ioports(&s->busdev, 0xcf8, 1);
+
+    memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s,
+                          "pci-conf-data", 1);
+    memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
+    sysbus_init_ioports(&s->busdev, 0xcfc, 1);
 
     PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read,
                                            PPC_PCIIO_write, s,
index cd6851288c794b7b8ad8040b210333080133fa28..b6b481a51702fe3127dcf19377a1e7a4c9bcad42 100644 (file)
@@ -2,7 +2,10 @@
 #define QEMU_PREP_PCI_H
 
 #include "qemu-common.h"
+#include "memory.h"
 
-PCIBus *pci_prep_init(qemu_irq *pic);
+PCIBus *pci_prep_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io);
 
 #endif
index fb456ad4a4c413adf79800525df8c321c5e4bed1..de7d6f2df2537c336642eec4aba93cbbce2c8dc8 100644 (file)
@@ -11,4 +11,8 @@ void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
 /* arm_sysctl.c */
 void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id);
 
+/* arm_sysctl GPIO lines */
+#define ARM_SYSCTL_GPIO_MMC_WPROT 0
+#define ARM_SYSCTL_GPIO_MMC_CARDIN 1
+
 #endif
index 9ccf8cb738c93bdd04759b1db0b53fe026444947..beb2292a5d2eeddf1b5dacb703c7a15530dca177 100644 (file)
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -92,6 +92,7 @@ typedef struct {
        not the keyboard controller.  */
     int translate;
     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
+    int ledstate;
 } PS2KbdState;
 
 typedef struct {
@@ -110,14 +111,24 @@ typedef struct {
 
 /* Table to convert from PC scancodes to raw scancodes.  */
 static const unsigned char ps2_raw_keycode[128] = {
-          0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
-         21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
-         35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
-         50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
-         11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
-        114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
-         71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
-         19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+  0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
+ 11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
+114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+};
+static const unsigned char ps2_raw_keycode_set3[128] = {
+  0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
+ 47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
+114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
 };
 
 void ps2_queue(void *opaque, int b)
@@ -143,12 +154,16 @@ static void ps2_put_keycode(void *opaque, int keycode)
 {
     PS2KbdState *s = opaque;
 
-    /* XXX: add support for scancode sets 1 and 3 */
-    if (!s->translate && keycode < 0xe0 && s->scancode_set == 2)
-      {
-        if (keycode & 0x80)
+    /* XXX: add support for scancode set 1 */
+    if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
+        if (keycode & 0x80) {
             ps2_queue(&s->common, 0xf0);
-        keycode = ps2_raw_keycode[keycode & 0x7f];
+        }
+        if (s->scancode_set == 2) {
+            keycode = ps2_raw_keycode[keycode & 0x7f];
+        } else if (s->scancode_set == 3) {
+            keycode = ps2_raw_keycode_set3[keycode & 0x7f];
+        }
       }
     ps2_queue(&s->common, keycode);
 }
@@ -181,11 +196,17 @@ uint32_t ps2_read_data(void *opaque)
     return val;
 }
 
+static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
+{
+    s->ledstate = ledstate;
+    kbd_put_ledstate(ledstate);
+}
+
 static void ps2_reset_keyboard(PS2KbdState *s)
 {
     s->scan_enabled = 1;
     s->scancode_set = 2;
-    kbd_put_ledstate(0);
+    ps2_set_ledstate(s, 0);
 }
 
 void ps2_write_keyboard(void *opaque, int val)
@@ -260,7 +281,7 @@ void ps2_write_keyboard(void *opaque, int val)
         s->common.write_cmd = -1;
         break;
     case KBD_CMD_SET_LEDS:
-        kbd_put_ledstate(val);
+        ps2_set_ledstate(s, val);
         ps2_queue(&s->common, KBD_REPLY_ACK);
         s->common.write_cmd = -1;
         break;
@@ -543,6 +564,33 @@ static const VMStateDescription vmstate_ps2_common = {
     }
 };
 
+static bool ps2_keyboard_ledstate_needed(void *opaque)
+{
+    PS2KbdState *s = opaque;
+
+    return s->ledstate != 0; /* 0 is default state */
+}
+
+static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
+{
+    PS2KbdState *s = opaque;
+
+    kbd_put_ledstate(s->ledstate);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
+    .name = "ps2kbd/ledstate",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = ps2_kbd_ledstate_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(ledstate, PS2KbdState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static int ps2_kbd_post_load(void* opaque, int version_id)
 {
     PS2KbdState *s = (PS2KbdState*)opaque;
@@ -564,6 +612,14 @@ static const VMStateDescription vmstate_ps2_keyboard = {
         VMSTATE_INT32(translate, PS2KbdState),
         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ps2_keyboard_ledstate,
+            .needed = ps2_keyboard_ledstate_needed,
+        }, {
+            /* empty */
+        }
     }
 };
 
@@ -590,20 +646,24 @@ static const VMStateDescription vmstate_ps2_mouse = {
 
 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
 {
-    PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
+    PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
 
     s->common.update_irq = update_irq;
     s->common.update_arg = update_arg;
     s->scancode_set = 2;
     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
+#ifdef CONFIG_MARU
     qemu_add_ps2kbd_event_handler(ps2_put_keycode, s);
+#else
+    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+#endif
     qemu_register_reset(ps2_kbd_reset, s);
     return s;
 }
 
 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
 {
-    PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
+    PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
 
     s->common.update_irq = update_irq;
     s->common.update_arg = update_arg;
index 4ddbc597e64a4f1fb905682d81f8a77db4c8b6cf..b6cabd5b7d05613753d1408bc9775e72190270c5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GNU LGPL.
+ * This code is licensed under the GNU LGPL.
  */
 #include "hw.h"
 #include "qemu-timer.h"
@@ -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;
@@ -68,7 +68,7 @@ uint64_t ptimer_get_count(ptimer_state *s)
     uint64_t counter;
 
     if (s->enabled) {
-        now = qemu_get_clock(vm_clock);
+        now = qemu_get_clock_ns(vm_clock);
         /* Figure out the current counter value.  */
         if (now - s->next_event > 0
             || s->period == 0) {
@@ -122,7 +122,7 @@ void ptimer_set_count(ptimer_state *s, uint64_t count)
 {
     s->delta = count;
     if (s->enabled) {
-        s->next_event = qemu_get_clock(vm_clock);
+        s->next_event = qemu_get_clock_ns(vm_clock);
         ptimer_reload(s);
     }
 }
@@ -137,7 +137,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
         return;
     }
     s->enabled = oneshot ? 2 : 1;
-    s->next_event = qemu_get_clock(vm_clock);
+    s->next_event = qemu_get_clock_ns(vm_clock);
     ptimer_reload(s);
 }
 
@@ -159,7 +159,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period)
     s->period = period;
     s->period_frac = 0;
     if (s->enabled) {
-        s->next_event = qemu_get_clock(vm_clock);
+        s->next_event = qemu_get_clock_ns(vm_clock);
         ptimer_reload(s);
     }
 }
@@ -170,7 +170,7 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
     s->period = 1000000000ll / freq;
     s->period_frac = (1000000000ll << 32) / freq;
     if (s->enabled) {
-        s->next_event = qemu_get_clock(vm_clock);
+        s->next_event = qemu_get_clock_ns(vm_clock);
         ptimer_reload(s);
     }
 }
@@ -183,62 +183,35 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
     if (reload)
         s->delta = limit;
     if (s->enabled && reload) {
-        s->next_event = qemu_get_clock(vm_clock);
+        s->next_event = qemu_get_clock_ns(vm_clock);
         ptimer_reload(s);
     }
 }
 
-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)
 {
     ptimer_state *s;
 
-    s = (ptimer_state *)qemu_mallocz(sizeof(ptimer_state));
+    s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
     s->bh = bh;
-    s->timer = qemu_new_timer(vm_clock, ptimer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s);
     return s;
 }
index f73d33b1a857750b50f74fb38552895425194977..7e9838408bc44ed3927cbf8765c5e2f0fed10b40 100644 (file)
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -4,11 +4,13 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 #ifndef PXA_H
 # define PXA_H                 "pxa.h"
 
+#include "memory.h"
+
 /* Interrupt numbers */
 # define PXA2XX_PIC_SSP3       0
 # define PXA2XX_PIC_USBH2      2
 # define PXA2XX_INTERNAL_SIZE  0x40000
 
 /* pxa2xx_pic.c */
-qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
-
-/* pxa2xx_timer.c */
-void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs);
-void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4);
+DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
 
 /* pxa2xx_gpio.c */
 DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
-                CPUState *env, qemu_irq *pic, int lines);
+                CPUState *env, DeviceState *pic, int lines);
 void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
 
 /* pxa2xx_dma.c */
-typedef struct PXA2xxDMAState PXA2xxDMAState;
-PXA2xxDMAState *pxa255_dma_init(target_phys_addr_t base,
-                qemu_irq irq);
-PXA2xxDMAState *pxa27x_dma_init(target_phys_addr_t base,
-                qemu_irq irq);
-void pxa2xx_dma_request(PXA2xxDMAState *s, int req_num, int on);
+DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq);
+DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq);
 
 /* pxa2xx_lcd.c */
 typedef struct PXA2xxLCDState PXA2xxLCDState;
@@ -92,7 +86,8 @@ void pxa2xx_lcdc_oritentation(void *opaque, int angle);
 /* pxa2xx_mmci.c */
 typedef struct PXA2xxMMCIState PXA2xxMMCIState;
 PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
-                BlockDriverState *bd, qemu_irq irq, void *dma);
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma);
 void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
                 qemu_irq coverswitch);
 
@@ -125,9 +120,14 @@ typedef struct PXA2xxFIrState PXA2xxFIrState;
 
 typedef struct {
     CPUState *env;
-    qemu_irq *pic;
+    DeviceState *pic;
     qemu_irq reset;
-    PXA2xxDMAState *dma;
+    MemoryRegion sdram;
+    MemoryRegion internal;
+    MemoryRegion cm_iomem;
+    MemoryRegion mm_iomem;
+    MemoryRegion pm_iomem;
+    DeviceState *dma;
     DeviceState *gpio;
     PXA2xxLCDState *lcd;
     SSIBus **ssp;
@@ -153,38 +153,13 @@ typedef struct {
 
     /* Performance monitoring */
     uint32_t pmnc;
-
-    /* Real-Time clock */
-    target_phys_addr_t rtc_base;
-    uint32_t rttr;
-    uint32_t rtsr;
-    uint32_t rtar;
-    uint32_t rdar1;
-    uint32_t rdar2;
-    uint32_t ryar1;
-    uint32_t ryar2;
-    uint32_t swar1;
-    uint32_t swar2;
-    uint32_t piar;
-    uint32_t last_rcnr;
-    uint32_t last_rdcr;
-    uint32_t last_rycr;
-    uint32_t last_swcr;
-    uint32_t last_rtcpicr;
-    int64_t last_hz;
-    int64_t last_sw;
-    int64_t last_pi;
-    QEMUTimer *rtc_hz;
-    QEMUTimer *rtc_rdal1;
-    QEMUTimer *rtc_rdal2;
-    QEMUTimer *rtc_swal1;
-    QEMUTimer *rtc_swal2;
-    QEMUTimer *rtc_pi;
 } PXA2xxState;
 
 struct PXA2xxI2SState {
+    MemoryRegion iomem;
     qemu_irq irq;
-    PXA2xxDMAState *dma;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
     void (*data_req)(void *, int, int);
 
     uint32_t control[2];
@@ -206,7 +181,8 @@ struct PXA2xxI2SState {
 # define PA_FMT                        "0x%08lx"
 # define REG_FMT               "0x" TARGET_FMT_plx
 
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
-PXA2xxState *pxa255_init(unsigned int sdram_size);
+PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size,
+                         const char *revision);
+PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size);
 
 #endif /* PXA_H */
index d966846f94af643908ff074f77a9aeb46b6a87ac..e9a507ece56c5051bda6ce371c1be54189fa67e8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -13,7 +13,6 @@
 #include "pc.h"
 #include "i2c.h"
 #include "ssi.h"
-#include "qemu-timer.h"
 #include "qemu-char.h"
 #include "blockdev.h"
 
@@ -89,7 +88,8 @@ static PXASSPDef pxa27x_ssp[] = {
 #define PCMD0  0x80    /* Power Manager I2C Command register File 0 */
 #define PCMD31 0xfc    /* Power Manager I2C Command register File 31 */
 
-static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -108,13 +108,16 @@ static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
     switch (addr) {
     case PMCR:
-        s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+        /* Clear the write-one-to-clear bits... */
+        s->pm_regs[addr >> 2] &= ~(value & 0x2a);
+        /* ...and set the plain r/w bits */
+        s->pm_regs[addr >> 2] &= ~0x15;
         s->pm_regs[addr >> 2] |= value & 0x15;
         break;
 
@@ -135,44 +138,30 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_pm_readfn[] = {
-    pxa2xx_pm_read,
-    pxa2xx_pm_read,
-    pxa2xx_pm_read,
+static const MemoryRegionOps pxa2xx_pm_ops = {
+    .read = pxa2xx_pm_read,
+    .write = pxa2xx_pm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = {
-    pxa2xx_pm_write,
-    pxa2xx_pm_write,
-    pxa2xx_pm_write,
+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()
+    }
 };
 
-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;
-}
-
 #define CCCR   0x00    /* Core Clock Configuration register */
 #define CKEN   0x04    /* Clock Enable register */
 #define OSCC   0x08    /* Oscillator Configuration register */
 #define CCSR   0x0c    /* Core Clock Status register */
 
-static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -193,7 +182,7 @@ static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -216,42 +205,25 @@ static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_cm_readfn[] = {
-    pxa2xx_cm_read,
-    pxa2xx_cm_read,
-    pxa2xx_cm_read,
+static const MemoryRegionOps pxa2xx_cm_ops = {
+    .read = pxa2xx_cm_read,
+    .write = pxa2xx_cm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = {
-    pxa2xx_cm_write,
-    pxa2xx_cm_write,
-    pxa2xx_cm_write,
+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 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 uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
@@ -373,7 +345,7 @@ static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
         return s->pmnc;
     case CPCCNT:
         if (s->pmnc & 1)
-            return qemu_get_clock(vm_clock);
+            return qemu_get_clock_ns(vm_clock);
         else
             return 0;
     case CPINTEN:
@@ -482,7 +454,8 @@ static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
 #define BSCNTR3                0x60    /* Memory Buffer Strength Control register 3 */
 #define SA1110         0x64    /* SA-1110 Memory Compatibility register */
 
-static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -499,7 +472,7 @@ static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -516,41 +489,27 @@ static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_mm_readfn[] = {
-    pxa2xx_mm_read,
-    pxa2xx_mm_read,
-    pxa2xx_mm_read,
+static const MemoryRegionOps pxa2xx_mm_ops = {
+    .read = pxa2xx_mm_read,
+    .write = pxa2xx_mm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = {
-    pxa2xx_mm_write,
-    pxa2xx_mm_write,
-    pxa2xx_mm_write,
+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()
+    }
 };
 
-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;
-}
-
 /* Synchronous Serial Ports */
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq irq;
     int enable;
     SSIBus *bus;
@@ -657,7 +616,8 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
     pxa2xx_ssp_int_update(s);
 }
 
-static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
     uint32_t retval;
@@ -703,9 +663,10 @@ static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+    uint32_t value = value64;
 
     switch (addr) {
     case SSCR0:
@@ -792,16 +753,10 @@ static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_ssp_readfn[] = {
-    pxa2xx_ssp_read,
-    pxa2xx_ssp_read,
-    pxa2xx_ssp_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_ssp_writefn[] = {
-    pxa2xx_ssp_write,
-    pxa2xx_ssp_write,
-    pxa2xx_ssp_write,
+static const MemoryRegionOps pxa2xx_ssp_ops = {
+    .read = pxa2xx_ssp_read,
+    .write = pxa2xx_ssp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
@@ -853,15 +808,12 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
 
 static int pxa2xx_ssp_init(SysBusDevice *dev)
 {
-    int iomemtype;
     PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev);
 
     sysbus_init_irq(dev, &s->irq);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn,
-                                       pxa2xx_ssp_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0,
                     pxa2xx_ssp_save, pxa2xx_ssp_load, s);
 
@@ -886,14 +838,44 @@ static int pxa2xx_ssp_init(SysBusDevice *dev)
 #define RTCPICR                0x34    /* RTC Periodic Interrupt Counter register */
 #define PIAR           0x38    /* RTC Periodic Interrupt Alarm register */
 
-static inline void pxa2xx_rtc_int_update(PXA2xxState *s)
-{
-    qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553));
-}
-
-static void pxa2xx_rtc_hzupdate(PXA2xxState *s)
-{
-    int64_t rt = qemu_get_clock(rt_clock);
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t rdar1;
+    uint32_t rdar2;
+    uint32_t ryar1;
+    uint32_t ryar2;
+    uint32_t swar1;
+    uint32_t swar2;
+    uint32_t piar;
+    uint32_t last_rcnr;
+    uint32_t last_rdcr;
+    uint32_t last_rycr;
+    uint32_t last_swcr;
+    uint32_t last_rtcpicr;
+    int64_t last_hz;
+    int64_t last_sw;
+    int64_t last_pi;
+    QEMUTimer *rtc_hz;
+    QEMUTimer *rtc_rdal1;
+    QEMUTimer *rtc_rdal2;
+    QEMUTimer *rtc_swal1;
+    QEMUTimer *rtc_swal2;
+    QEMUTimer *rtc_pi;
+    qemu_irq rtc_irq;
+} PXA2xxRTCState;
+
+static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
+{
+    qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
+}
+
+static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *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_rdcr += ((rt - s->last_hz) << 15) /
@@ -901,23 +883,23 @@ static void pxa2xx_rtc_hzupdate(PXA2xxState *s)
     s->last_hz = rt;
 }
 
-static void pxa2xx_rtc_swupdate(PXA2xxState *s)
+static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
 {
-    int64_t rt = qemu_get_clock(rt_clock);
+    int64_t rt = qemu_get_clock_ms(rt_clock);
     if (s->rtsr & (1 << 12))
         s->last_swcr += (rt - s->last_sw) / 10;
     s->last_sw = rt;
 }
 
-static void pxa2xx_rtc_piupdate(PXA2xxState *s)
+static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
 {
-    int64_t rt = qemu_get_clock(rt_clock);
+    int64_t rt = qemu_get_clock_ms(rt_clock);
     if (s->rtsr & (1 << 15))
         s->last_swcr += rt - s->last_pi;
     s->last_pi = rt;
 }
 
-static inline void pxa2xx_rtc_alarm_update(PXA2xxState *s,
+static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
                 uint32_t rtsr)
 {
     if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
@@ -962,7 +944,7 @@ static inline void pxa2xx_rtc_alarm_update(PXA2xxState *s,
 
 static inline void pxa2xx_rtc_hz_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 0);
     pxa2xx_rtc_alarm_update(s, s->rtsr);
     pxa2xx_rtc_int_update(s);
@@ -970,7 +952,7 @@ static inline void pxa2xx_rtc_hz_tick(void *opaque)
 
 static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 4);
     pxa2xx_rtc_alarm_update(s, s->rtsr);
     pxa2xx_rtc_int_update(s);
@@ -978,7 +960,7 @@ static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
 
 static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 6);
     pxa2xx_rtc_alarm_update(s, s->rtsr);
     pxa2xx_rtc_int_update(s);
@@ -986,7 +968,7 @@ static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
 
 static inline void pxa2xx_rtc_swal1_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 8);
     pxa2xx_rtc_alarm_update(s, s->rtsr);
     pxa2xx_rtc_int_update(s);
@@ -994,7 +976,7 @@ static inline void pxa2xx_rtc_swal1_tick(void *opaque)
 
 static inline void pxa2xx_rtc_swal2_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 10);
     pxa2xx_rtc_alarm_update(s, s->rtsr);
     pxa2xx_rtc_int_update(s);
@@ -1002,7 +984,7 @@ static inline void pxa2xx_rtc_swal2_tick(void *opaque)
 
 static inline void pxa2xx_rtc_pi_tick(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
     s->rtsr |= (1 << 13);
     pxa2xx_rtc_piupdate(s);
     s->last_rtcpicr = 0;
@@ -1010,9 +992,10 @@ static inline void pxa2xx_rtc_pi_tick(void *opaque)
     pxa2xx_rtc_int_update(s);
 }
 
-static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
 
     switch (addr) {
     case RTTR:
@@ -1036,16 +1019,16 @@ static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
     case PIAR:
         return s->piar;
     case RCNR:
-        return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+        return s->last_rcnr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
                 (1000 * ((s->rttr & 0xffff) + 1));
     case RDCR:
-        return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+        return s->last_rdcr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
                 (1000 * ((s->rttr & 0xffff) + 1));
     case RYCR:
         return s->last_rycr;
     case SWCR:
         if (s->rtsr & (1 << 12))
-            return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
+            return s->last_swcr + (qemu_get_clock_ms(rt_clock) - s->last_sw) / 10;
         else
             return s->last_swcr;
     default:
@@ -1056,9 +1039,10 @@ static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    uint32_t value = value64;
 
     switch (addr) {
     case RTTR:
@@ -1158,20 +1142,15 @@ static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_rtc_readfn[] = {
-    pxa2xx_rtc_read,
-    pxa2xx_rtc_read,
-    pxa2xx_rtc_read,
+static const MemoryRegionOps pxa2xx_rtc_ops = {
+    .read = pxa2xx_rtc_read,
+    .write = pxa2xx_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pxa2xx_rtc_writefn[] = {
-    pxa2xx_rtc_write,
-    pxa2xx_rtc_write,
-    pxa2xx_rtc_write,
-};
-
-static void pxa2xx_rtc_init(PXA2xxState *s)
+static int pxa2xx_rtc_init(SysBusDevice *dev)
 {
+    PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev);
     struct tm tm;
     int wom;
 
@@ -1189,72 +1168,79 @@ static void pxa2xx_rtc_init(PXA2xxState *s)
     s->last_swcr = (tm.tm_hour << 19) |
             (tm.tm_min << 13) | (tm.tm_sec << 7);
     s->last_rtcpicr = 0;
-    s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
+    s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rt_clock);
+
+    s->rtc_hz    = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_hz_tick,    s);
+    s->rtc_rdal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal1_tick, s);
+    s->rtc_rdal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal2_tick, s);
+    s->rtc_swal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal1_tick, s);
+    s->rtc_swal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal2_tick, s);
+    s->rtc_pi    = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_pi_tick,    s);
 
-    s->rtc_hz    = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick,    s);
-    s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
-    s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
-    s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
-    s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
-    s->rtc_pi    = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick,    s);
+    sysbus_init_irq(dev, &s->rtc_irq);
+
+    memory_region_init_io(&s->iomem, &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    return 0;
 }
 
-static void pxa2xx_rtc_save(QEMUFile *f, void *opaque)
+static void pxa2xx_rtc_pre_save(void *opaque)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
 
     pxa2xx_rtc_hzupdate(s);
     pxa2xx_rtc_piupdate(s);
     pxa2xx_rtc_swupdate(s);
+}
 
-    qemu_put_be32s(f, &s->rttr);
-    qemu_put_be32s(f, &s->rtsr);
-    qemu_put_be32s(f, &s->rtar);
-    qemu_put_be32s(f, &s->rdar1);
-    qemu_put_be32s(f, &s->rdar2);
-    qemu_put_be32s(f, &s->ryar1);
-    qemu_put_be32s(f, &s->ryar2);
-    qemu_put_be32s(f, &s->swar1);
-    qemu_put_be32s(f, &s->swar2);
-    qemu_put_be32s(f, &s->piar);
-    qemu_put_be32s(f, &s->last_rcnr);
-    qemu_put_be32s(f, &s->last_rdcr);
-    qemu_put_be32s(f, &s->last_rycr);
-    qemu_put_be32s(f, &s->last_swcr);
-    qemu_put_be32s(f, &s->last_rtcpicr);
-    qemu_put_sbe64s(f, &s->last_hz);
-    qemu_put_sbe64s(f, &s->last_sw);
-    qemu_put_sbe64s(f, &s->last_pi);
-}
-
-static int pxa2xx_rtc_load(QEMUFile *f, void *opaque, int version_id)
+static int pxa2xx_rtc_post_load(void *opaque, int version_id)
 {
-    PXA2xxState *s = (PXA2xxState *) opaque;
-
-    qemu_get_be32s(f, &s->rttr);
-    qemu_get_be32s(f, &s->rtsr);
-    qemu_get_be32s(f, &s->rtar);
-    qemu_get_be32s(f, &s->rdar1);
-    qemu_get_be32s(f, &s->rdar2);
-    qemu_get_be32s(f, &s->ryar1);
-    qemu_get_be32s(f, &s->ryar2);
-    qemu_get_be32s(f, &s->swar1);
-    qemu_get_be32s(f, &s->swar2);
-    qemu_get_be32s(f, &s->piar);
-    qemu_get_be32s(f, &s->last_rcnr);
-    qemu_get_be32s(f, &s->last_rdcr);
-    qemu_get_be32s(f, &s->last_rycr);
-    qemu_get_be32s(f, &s->last_swcr);
-    qemu_get_be32s(f, &s->last_rtcpicr);
-    qemu_get_sbe64s(f, &s->last_hz);
-    qemu_get_sbe64s(f, &s->last_sw);
-    qemu_get_sbe64s(f, &s->last_pi);
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
 
     pxa2xx_rtc_alarm_update(s, s->rtsr);
 
     return 0;
 }
 
+static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
+    .name = "pxa2xx_rtc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = pxa2xx_rtc_pre_save,
+    .post_load = pxa2xx_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(rttr, PXA2xxRTCState),
+        VMSTATE_UINT32(rtsr, PXA2xxRTCState),
+        VMSTATE_UINT32(rtar, PXA2xxRTCState),
+        VMSTATE_UINT32(rdar1, PXA2xxRTCState),
+        VMSTATE_UINT32(rdar2, PXA2xxRTCState),
+        VMSTATE_UINT32(ryar1, PXA2xxRTCState),
+        VMSTATE_UINT32(ryar2, PXA2xxRTCState),
+        VMSTATE_UINT32(swar1, PXA2xxRTCState),
+        VMSTATE_UINT32(swar2, PXA2xxRTCState),
+        VMSTATE_UINT32(piar, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
+        VMSTATE_INT64(last_hz, PXA2xxRTCState),
+        VMSTATE_INT64(last_sw, PXA2xxRTCState),
+        VMSTATE_INT64(last_pi, PXA2xxRTCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
+    .init       = pxa2xx_rtc_init,
+    .qdev.name  = "pxa2xx_rtc",
+    .qdev.desc  = "PXA2xx RTC Controller",
+    .qdev.size  = sizeof(PXA2xxRTCState),
+    .qdev.vmsd  = &vmstate_pxa2xx_rtc_regs,
+};
+
 /* I2C Interface */
 typedef struct {
     i2c_slave i2c;
@@ -1262,10 +1248,13 @@ typedef struct {
 } PXA2xxI2CSlaveState;
 
 struct PXA2xxI2CState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
     PXA2xxI2CSlaveState *slave;
     i2c_bus *bus;
     qemu_irq irq;
-    target_phys_addr_t offset;
+    uint32_t offset;
+    uint32_t region_size;
 
     uint16_t control;
     uint16_t status;
@@ -1345,7 +1334,8 @@ static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
     return 1;
 }
 
-static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
 
@@ -1373,9 +1363,10 @@ static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
+    uint32_t value = value64;
     int ack;
 
     addr -= s->offset;
@@ -1442,16 +1433,10 @@ static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_i2c_readfn[] = {
-    pxa2xx_i2c_read,
-    pxa2xx_i2c_read,
-    pxa2xx_i2c_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_i2c_writefn[] = {
-    pxa2xx_i2c_write,
-    pxa2xx_i2c_write,
-    pxa2xx_i2c_write,
+static const MemoryRegionOps pxa2xx_i2c_ops = {
+    .read = pxa2xx_i2c_read,
+    .write = pxa2xx_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
@@ -1499,27 +1484,41 @@ static I2CSlaveInfo pxa2xx_i2c_slave_info = {
 PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
                 qemu_irq irq, uint32_t region_size)
 {
-    int iomemtype;
     DeviceState *dev;
-    PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState));
+    SysBusDevice *i2c_dev;
+    PXA2xxI2CState *s;
+
+    i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c"));
+    qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1);
+    qdev_prop_set_uint32(&i2c_dev->qdev, "offset",
+            base - (base & (~region_size) & TARGET_PAGE_MASK));
 
+    qdev_init_nofail(&i2c_dev->qdev);
+
+    sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
+    sysbus_connect_irq(i2c_dev, 0, irq);
+
+    s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev);
     /* FIXME: Should the slave device really be on a separate bus?  */
     dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0);
     s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev));
     s->slave->host = s;
 
-    s->irq = irq;
-    s->bus = i2c_init_bus(NULL, "i2c");
-    s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
+    return s;
+}
 
-    iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn,
-                    pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base & ~region_size,
-                    region_size + 1, iomemtype);
+static int pxa2xx_i2c_initfn(SysBusDevice *dev)
+{
+    PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev);
 
-    vmstate_register(NULL, base, &vmstate_pxa2xx_i2c, s);
+    s->bus = i2c_init_bus(&dev->qdev, "i2c");
 
-    return s;
+    memory_region_init_io(&s->iomem, &pxa2xx_i2c_ops, s,
+                          "pxa2xx-i2x", s->region_size);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
 }
 
 i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
@@ -1527,6 +1526,19 @@ i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
     return s->bus;
 }
 
+static SysBusDeviceInfo pxa2xx_i2c_info = {
+    .init       = pxa2xx_i2c_initfn,
+    .qdev.name  = "pxa2xx_i2c",
+    .qdev.desc  = "PXA2xx I2C Bus Controller",
+    .qdev.size  = sizeof(PXA2xxI2CState),
+    .qdev.vmsd  = &vmstate_pxa2xx_i2c,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
+        DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
 /* PXA Inter-IC Sound Controller */
 static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
 {
@@ -1553,8 +1565,8 @@ static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
     tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
             i2s->enable && !SACR_DPRL(i2s->control[1]);
 
-    pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
-    pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
+    qemu_set_irq(i2s->rx_dma, rfs);
+    qemu_set_irq(i2s->tx_dma, tfs);
 
     i2s->status &= 0xe0;
     if (i2s->fifo_len < 16 || !i2s->enable)
@@ -1582,7 +1594,8 @@ static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
 #define SADIV  0x60    /* Serial Audio Clock Divider register */
 #define SADR   0x80    /* Serial Audio Data register */
 
-static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
 
@@ -1614,7 +1627,7 @@ static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
     uint32_t *sample;
@@ -1631,7 +1644,7 @@ static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
         }
         if (value & (1 << 4))                          /* EFWR */
             printf("%s: Attempt to use special function\n", __FUNCTION__);
-        s->enable = ((value ^ 4) & 5) == 5;            /* ENB && !RST*/
+        s->enable = (value & 9) == 1;                  /* ENB && !RST*/
         pxa2xx_i2s_update(s);
         break;
     case SACR1:
@@ -1668,52 +1681,30 @@ static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_i2s_readfn[] = {
-    pxa2xx_i2s_read,
-    pxa2xx_i2s_read,
-    pxa2xx_i2s_read,
+static const MemoryRegionOps pxa2xx_i2s_ops = {
+    .read = pxa2xx_i2s_read,
+    .write = pxa2xx_i2s_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = {
-    pxa2xx_i2s_write,
-    pxa2xx_i2s_write,
-    pxa2xx_i2s_write,
+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_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 void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
 {
     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
@@ -1736,33 +1727,35 @@ static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
     pxa2xx_i2s_update(s);
 }
 
-static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
-                qemu_irq irq, PXA2xxDMAState *dma)
+static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
+                target_phys_addr_t base,
+                qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
 {
-    int iomemtype;
     PXA2xxI2SState *s = (PXA2xxI2SState *)
-            qemu_mallocz(sizeof(PXA2xxI2SState));
+            g_malloc0(sizeof(PXA2xxI2SState));
 
     s->irq = irq;
-    s->dma = dma;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
     s->data_req = pxa2xx_i2s_data_req;
 
     pxa2xx_i2s_reset(s);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn,
-                    pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_i2s_ops, s,
+                          "pxa2xx-i2s", 0x100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
-    register_savevm(NULL, "pxa2xx_i2s", base, 0,
-                    pxa2xx_i2s_save, pxa2xx_i2s_load, s);
+    vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
 
     return s;
 }
 
 /* PXA Fast Infra-red Communications Port */
 struct PXA2xxFIrState {
+    MemoryRegion iomem;
     qemu_irq irq;
-    PXA2xxDMAState *dma;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
     int enable;
     CharDriverState *chr;
 
@@ -1816,8 +1809,8 @@ static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
             (s->status[0] & (1 << 1));                 /* TUR */
     intr |= s->status[0] & 0x25;                       /* FRE, RAB, EIF */
 
-    pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1);
-    pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1);
+    qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
+    qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
 
     qemu_set_irq(s->irq, intr && s->enable);
 }
@@ -1830,7 +1823,8 @@ static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
 #define ICSR1  0x18    /* FICP Status register 1 */
 #define ICFOR  0x1c    /* FICP FIFO Occupancy Status register */
 
-static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
     uint8_t ret;
@@ -1868,9 +1862,10 @@ static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    uint32_t value = value64;
     uint8_t ch;
 
     switch (addr) {
@@ -1899,7 +1894,7 @@ static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
         else
             ch = ~value;
         if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
         break;
     case ICSR0:
         s->status[0] &= ~(value & 0x66);
@@ -1912,16 +1907,10 @@ static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_fir_readfn[] = {
-    pxa2xx_fir_read,
-    pxa2xx_fir_read,
-    pxa2xx_fir_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_fir_writefn[] = {
-    pxa2xx_fir_write,
-    pxa2xx_fir_write,
-    pxa2xx_fir_write,
+static const MemoryRegionOps pxa2xx_fir_ops = {
+    .read = pxa2xx_fir_read,
+    .write = pxa2xx_fir_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int pxa2xx_fir_is_empty(void *opaque)
@@ -1995,23 +1984,23 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
-                qemu_irq irq, PXA2xxDMAState *dma,
+static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
+                target_phys_addr_t base,
+                qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
                 CharDriverState *chr)
 {
-    int iomemtype;
     PXA2xxFIrState *s = (PXA2xxFIrState *)
-            qemu_mallocz(sizeof(PXA2xxFIrState));
+            g_malloc0(sizeof(PXA2xxFIrState));
 
     s->irq = irq;
-    s->dma = dma;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
     s->chr = chr;
 
     pxa2xx_fir_reset(s);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn,
-                    pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
     if (chr)
         qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
@@ -2034,12 +2023,13 @@ static void pxa2xx_reset(void *opaque, int line, int level)
 }
 
 /* Initialise a PXA270 integrated chip (ARM based core).  */
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
+PXA2xxState *pxa270_init(MemoryRegion *address_space,
+                         unsigned int sdram_size, const char *revision)
 {
     PXA2xxState *s;
-    int iomemtype, i;
+    int i;
     DriveInfo *dinfo;
-    s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
+    s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
 
     if (revision && strncmp(revision, "pxa27", 5)) {
         fprintf(stderr, "Machine requires a PXA27x processor.\n");
@@ -2056,19 +2046,24 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
 
     /* SDRAM & Internal Memory Storage */
-    cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
-                    sdram_size, qemu_ram_alloc(NULL, "pxa270.sdram",
-                                               sdram_size) | IO_MEM_RAM);
-    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
-                    0x40000, qemu_ram_alloc(NULL, "pxa270.internal",
-                                            0x40000) | IO_MEM_RAM);
+    memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size);
+    memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
+    memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000);
+    memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
+                                &s->internal);
 
     s->pic = pxa2xx_pic_init(0x40d00000, s->env);
 
-    s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+    s->dma = pxa27x_dma_init(0x40000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
 
-    pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0],
-                    s->pic[PXA27X_PIC_OST_4_11]);
+    sysbus_create_varargs("pxa27x-timer", 0x40a00000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
+                    qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
+                    NULL);
 
     s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
 
@@ -2078,34 +2073,36 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
         exit(1);
     }
     s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
-                              s->pic[PXA2XX_PIC_MMC], s->dma);
-
-    for (i = 0; pxa270_serial[i].io_base; i ++)
-        if (serial_hds[i])
-#ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa270_serial[i].io_base, 2,
-                           s->pic[pxa270_serial[i].irqn], 14857000/16,
-                           serial_hds[i], 1, 1);
-#else
-            serial_mm_init(pxa270_serial[i].io_base, 2,
-                           s->pic[pxa270_serial[i].irqn], 14857000/16,
-                           serial_hds[i], 1, 0);
-#endif
-        else
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
+
+    for (i = 0; pxa270_serial[i].io_base; i++) {
+        if (serial_hds[i]) {
+            serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
+                           qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
+                           14857000 / 16, serial_hds[i],
+                           DEVICE_NATIVE_ENDIAN);
+        } else {
             break;
+        }
+    }
     if (serial_hds[i])
-        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
-                        s->dma, serial_hds[i]);
+        s->fir = pxa2xx_fir_init(address_space, 0x40800000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
+                        serial_hds[i]);
 
-    s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD]);
+    s->lcd = pxa2xx_lcdc_init(0x44000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
 
     s->cm_base = 0x41300000;
     s->cm_regs[CCCR >> 2] = 0x02000210;        /* 416.0 MHz */
     s->clkcfg = 0x00000009;            /* Turbo mode active */
-    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);
+    memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
+    memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
 
@@ -2113,48 +2110,47 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     s->mm_regs[MDMRS >> 2] = 0x00020002;
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;        /* Two PC Card sockets */
-    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);
+    memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
+    memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
+    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);
+    memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
+    memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
+    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);
+    s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
     for (i = 0; pxa27x_ssp[i].io_base; i ++) {
         DeviceState *dev;
         dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
-                                   s->pic[pxa27x_ssp[i].irqn]);
+                        qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
         s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
     }
 
     if (usb_enabled) {
         sysbus_create_simple("sysbus-ohci", 0x4c000000,
-                             s->pic[PXA2XX_PIC_USBH1]);
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
     }
 
     s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
     s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
 
-    s->rtc_base = 0x40900000;
-    iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
-                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
-    pxa2xx_rtc_init(s);
-    register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
-                    pxa2xx_rtc_load, s);
+    sysbus_create_simple("pxa2xx_rtc", 0x40900000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
 
-    s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
-    s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
 
-    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+    s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
 
-    s->kp = pxa27x_keypad_init(0x41500000, s->pic[PXA2XX_PIC_KEYPAD]);
+    s->kp = pxa27x_keypad_init(0x41500000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
 
     /* GPIO1 resets the processor */
     /* The handler can be overridden by board-specific code */
@@ -2163,13 +2159,13 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
 }
 
 /* Initialise a PXA255 integrated chip (ARM based core).  */
-PXA2xxState *pxa255_init(unsigned int sdram_size)
+PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
 {
     PXA2xxState *s;
-    int iomemtype, i;
+    int i;
     DriveInfo *dinfo;
 
-    s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
+    s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
 
     s->env = cpu_init("pxa255");
     if (!s->env) {
@@ -2179,18 +2175,24 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
 
     /* SDRAM & Internal Memory Storage */
-    cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size,
-                    qemu_ram_alloc(NULL, "pxa255.sdram",
-                                   sdram_size) | IO_MEM_RAM);
-    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE,
-                    qemu_ram_alloc(NULL, "pxa255.internal",
-                                   PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM);
+    memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size);
+    memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
+    memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
+                           PXA2XX_INTERNAL_SIZE);
+    memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
+                                &s->internal);
 
     s->pic = pxa2xx_pic_init(0x40d00000, s->env);
 
-    s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+    s->dma = pxa255_dma_init(0x40000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
 
-    pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0]);
+    sysbus_create_varargs("pxa25x-timer", 0x40a00000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
+                    NULL);
 
     s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
 
@@ -2200,35 +2202,36 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
         exit(1);
     }
     s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
-                              s->pic[PXA2XX_PIC_MMC], s->dma);
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
 
-    for (i = 0; pxa255_serial[i].io_base; i ++)
+    for (i = 0; pxa255_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa255_serial[i].io_base, 2,
-                           s->pic[pxa255_serial[i].irqn], 14745600/16,
-                           serial_hds[i], 1, 1);
-#else
-            serial_mm_init(pxa255_serial[i].io_base, 2,
-                           s->pic[pxa255_serial[i].irqn], 14745600/16,
-                           serial_hds[i], 1, 0);
-#endif
+            serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
+                           qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
+                           14745600 / 16, serial_hds[i],
+                           DEVICE_NATIVE_ENDIAN);
         } else {
             break;
         }
+    }
     if (serial_hds[i])
-        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
-                        s->dma, serial_hds[i]);
+        s->fir = pxa2xx_fir_init(address_space, 0x40800000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
+                        serial_hds[i]);
 
-    s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD]);
+    s->lcd = pxa2xx_lcdc_init(0x44000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
 
     s->cm_base = 0x41300000;
     s->cm_regs[CCCR >> 2] = 0x02000210;        /* 416.0 MHz */
     s->clkcfg = 0x00000009;            /* Turbo mode active */
-    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);
+    memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
+    memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
 
@@ -2236,46 +2239,44 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     s->mm_regs[MDMRS >> 2] = 0x00020002;
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;        /* Two PC Card sockets */
-    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);
+    memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
+    memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
+    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);
+    memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
+    memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
+    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);
+    s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
     for (i = 0; pxa255_ssp[i].io_base; i ++) {
         DeviceState *dev;
         dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
-                                   s->pic[pxa255_ssp[i].irqn]);
+                        qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
         s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
     }
 
     if (usb_enabled) {
         sysbus_create_simple("sysbus-ohci", 0x4c000000,
-                             s->pic[PXA2XX_PIC_USBH1]);
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
     }
 
     s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
     s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
 
-    s->rtc_base = 0x40900000;
-    iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
-                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
-    pxa2xx_rtc_init(s);
-    register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
-                    pxa2xx_rtc_load, s);
+    sysbus_create_simple("pxa2xx_rtc", 0x40900000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
 
-    s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
-    s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
 
-    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+    s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
 
     /* GPIO1 resets the processor */
     /* The handler can be overridden by board-specific code */
@@ -2287,6 +2288,8 @@ static void pxa2xx_register_devices(void)
 {
     i2c_register_slave(&pxa2xx_i2c_slave_info);
     sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
+    sysbus_register_withprop(&pxa2xx_i2c_info);
+    sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
 }
 
 device_init(pxa2xx_register_devices)
index b512d34501da1280548c8e93d0bcbfe936ed3f0b..07ec2dbb66978d7dd64b94049d850d396606b2e6 100644 (file)
@@ -5,11 +5,17 @@
  * Copyright (c) 2006 Thorsten Zitterell
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
 #include "pxa.h"
+#include "sysbus.h"
+
+#define PXA255_DMA_NUM_CHANNELS 16
+#define PXA27X_DMA_NUM_CHANNELS 32
+
+#define PXA2XX_DMA_NUM_REQUESTS 75
 
 typedef struct {
     target_phys_addr_t descr;
@@ -20,11 +26,8 @@ typedef struct {
     int request;
 } PXA2xxDMAChannel;
 
-/* Allow the DMA to be used as a PIC.  */
-typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
-
-struct PXA2xxDMAState {
-    pxa2xx_dma_handler_t handler;
+typedef struct PXA2xxDMAState {
+    SysBusDevice busdev;
     qemu_irq irq;
 
     uint32_t stopintr;
@@ -39,16 +42,11 @@ struct PXA2xxDMAState {
     int channels;
     PXA2xxDMAChannel *chan;
 
-    uint8_t *req;
+    uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
 
     /* Flag to avoid recursive DMA invocations.  */
     int running;
-};
-
-#define PXA255_DMA_NUM_CHANNELS        16
-#define PXA27X_DMA_NUM_CHANNELS        32
-
-#define PXA2XX_DMA_NUM_REQUESTS        75
+} PXA2xxDMAState;
 
 #define DCSR0  0x0000  /* DMA Control / Status register for Channel 0 */
 #define DCSR31 0x007c  /* DMA Control / Status register for Channel 31 */
@@ -428,74 +426,42 @@ static CPUWriteMemoryFunc * const pxa2xx_dma_writefn[] = {
     pxa2xx_dma_write
 };
 
-static void pxa2xx_dma_save(QEMUFile *f, void *opaque)
+static void pxa2xx_dma_request(void *opaque, int req_num, int on)
 {
-    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
-    int i;
-
-    qemu_put_be32(f, s->channels);
-
-    qemu_put_be32s(f, &s->stopintr);
-    qemu_put_be32s(f, &s->eorintr);
-    qemu_put_be32s(f, &s->rasintr);
-    qemu_put_be32s(f, &s->startintr);
-    qemu_put_be32s(f, &s->endintr);
-    qemu_put_be32s(f, &s->align);
-    qemu_put_be32s(f, &s->pio);
-
-    qemu_put_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
-    for (i = 0; i < s->channels; i ++) {
-        qemu_put_betl(f, s->chan[i].descr);
-        qemu_put_betl(f, s->chan[i].src);
-        qemu_put_betl(f, s->chan[i].dest);
-        qemu_put_be32s(f, &s->chan[i].cmd);
-        qemu_put_be32s(f, &s->chan[i].state);
-        qemu_put_be32(f, s->chan[i].request);
-    };
-}
+    PXA2xxDMAState *s = opaque;
+    int ch;
+    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
+        hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
 
-static int pxa2xx_dma_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
-    int i;
-
-    if (qemu_get_be32(f) != s->channels)
-        return -EINVAL;
-
-    qemu_get_be32s(f, &s->stopintr);
-    qemu_get_be32s(f, &s->eorintr);
-    qemu_get_be32s(f, &s->rasintr);
-    qemu_get_be32s(f, &s->startintr);
-    qemu_get_be32s(f, &s->endintr);
-    qemu_get_be32s(f, &s->align);
-    qemu_get_be32s(f, &s->pio);
-
-    qemu_get_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
-    for (i = 0; i < s->channels; i ++) {
-        s->chan[i].descr = qemu_get_betl(f);
-        s->chan[i].src = qemu_get_betl(f);
-        s->chan[i].dest = qemu_get_betl(f);
-        qemu_get_be32s(f, &s->chan[i].cmd);
-        qemu_get_be32s(f, &s->chan[i].state);
-        s->chan[i].request = qemu_get_be32(f);
-    };
+    if (!(s->req[req_num] & DRCMR_MAPVLD))
+        return;
+    ch = s->req[req_num] & DRCMR_CHLNUM;
 
-    return 0;
+    if (!s->chan[ch].request && on)
+        s->chan[ch].state |= DCSR_RASINTR;
+    else
+        s->chan[ch].state &= ~DCSR_RASINTR;
+    if (s->chan[ch].request && !on)
+        s->chan[ch].state |= DCSR_EORINT;
+
+    s->chan[ch].request = on;
+    if (on) {
+        pxa2xx_dma_run(s);
+        pxa2xx_dma_update(s, ch);
+    }
 }
 
-static PXA2xxDMAState *pxa2xx_dma_init(target_phys_addr_t base,
-                qemu_irq irq, int channels)
+static int pxa2xx_dma_init(SysBusDevice *dev)
 {
     int i, iomemtype;
     PXA2xxDMAState *s;
-    s = (PXA2xxDMAState *)
-            qemu_mallocz(sizeof(PXA2xxDMAState));
+    s = FROM_SYSBUS(PXA2xxDMAState, dev);
+
+    if (s->channels <= 0) {
+        return -1;
+    }
 
-    s->channels = channels;
-    s->chan = qemu_mallocz(sizeof(PXA2xxDMAChannel) * s->channels);
-    s->irq = irq;
-    s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
-    s->req = qemu_mallocz(sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+    s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);
 
     memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);
     for (i = 0; i < s->channels; i ++)
@@ -503,47 +469,100 @@ static PXA2xxDMAState *pxa2xx_dma_init(target_phys_addr_t base,
 
     memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
 
+    qdev_init_gpio_in(&dev->qdev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
+
     iomemtype = cpu_register_io_memory(pxa2xx_dma_readfn,
                     pxa2xx_dma_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x00010000, iomemtype);
+    sysbus_init_mmio(dev, 0x00010000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
 
-    register_savevm(NULL, "pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s);
-
-    return s;
+    return 0;
 }
 
-PXA2xxDMAState *pxa27x_dma_init(target_phys_addr_t base,
-                qemu_irq irq)
+DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq)
 {
-    return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
 }
 
-PXA2xxDMAState *pxa255_dma_init(target_phys_addr_t base,
-                qemu_irq irq)
+DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq)
 {
-    return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
 }
 
-void pxa2xx_dma_request(PXA2xxDMAState *s, int req_num, int on)
+static bool is_version_0(void *opaque, int version_id)
 {
-    int ch;
-    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
-        hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
+    return version_id == 0;
+}
 
-    if (!(s->req[req_num] & DRCMR_MAPVLD))
-        return;
-    ch = s->req[req_num] & DRCMR_CHLNUM;
+static VMStateDescription vmstate_pxa2xx_dma_chan = {
+    .name = "pxa2xx_dma_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINTTL(descr, PXA2xxDMAChannel),
+        VMSTATE_UINTTL(src, PXA2xxDMAChannel),
+        VMSTATE_UINTTL(dest, PXA2xxDMAChannel),
+        VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
+        VMSTATE_UINT32(state, PXA2xxDMAChannel),
+        VMSTATE_INT32(request, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
 
-    if (!s->chan[ch].request && on)
-        s->chan[ch].state |= DCSR_RASINTR;
-    else
-        s->chan[ch].state &= ~DCSR_RASINTR;
-    if (s->chan[ch].request && !on)
-        s->chan[ch].state |= DCSR_EORINT;
+static VMStateDescription vmstate_pxa2xx_dma = {
+    .name = "pxa2xx_dma",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UNUSED_TEST(is_version_0, 4),
+        VMSTATE_UINT32(stopintr, PXA2xxDMAState),
+        VMSTATE_UINT32(eorintr, PXA2xxDMAState),
+        VMSTATE_UINT32(rasintr, PXA2xxDMAState),
+        VMSTATE_UINT32(startintr, PXA2xxDMAState),
+        VMSTATE_UINT32(endintr, PXA2xxDMAState),
+        VMSTATE_UINT32(align, PXA2xxDMAState),
+        VMSTATE_UINT32(pio, PXA2xxDMAState),
+        VMSTATE_BUFFER(req, PXA2xxDMAState),
+        VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
+                vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
 
-    s->chan[ch].request = on;
-    if (on) {
-        pxa2xx_dma_run(s);
-        pxa2xx_dma_update(s, ch);
-    }
+static SysBusDeviceInfo pxa2xx_dma_info = {
+    .init       = pxa2xx_dma_init,
+    .qdev.name  = "pxa2xx-dma",
+    .qdev.desc  = "PXA2xx DMA controller",
+    .qdev.size  = sizeof(PXA2xxDMAState),
+    .qdev.vmsd  = &vmstate_pxa2xx_dma,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pxa2xx_dma_register(void)
+{
+    sysbus_register_withprop(&pxa2xx_dma_info);
 }
+device_init(pxa2xx_dma_register);
index 789965d88b1a718e6802e7712933318a73112049..200b0cfe3a97cdcd3ae4bd2f8e5606819bf105e1 100644 (file)
@@ -253,7 +253,7 @@ static CPUWriteMemoryFunc * const pxa2xx_gpio_writefn[] = {
 };
 
 DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
-                CPUState *env, qemu_irq *pic, int lines)
+                CPUState *env, DeviceState *pic, int lines)
 {
     DeviceState *dev;
 
@@ -263,9 +263,12 @@ DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
     qdev_init_nofail(dev);
 
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[PXA2XX_PIC_GPIO_0]);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[PXA2XX_PIC_GPIO_1]);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[PXA2XX_PIC_GPIO_X]);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
 
     return dev;
 }
index 4c999171b965730f9603bd9b56bad15c62fb20b1..e33959d25cf24cba923634d845d73212146eee67 100644 (file)
 struct PXA2xxKeyPadState {
     qemu_irq    irq;
     struct  keymap *map;
+    int         pressed_cnt;
+    int         alt_code;
 
     uint32_t    kpc;
     uint32_t    kpdk;
     uint32_t    kprec;
     uint32_t    kpmk;
     uint32_t    kpas;
-    uint32_t    kpasmkp0;
-    uint32_t    kpasmkp1;
-    uint32_t    kpasmkp2;
-    uint32_t    kpasmkp3;
+    uint32_t    kpasmkp[4];
     uint32_t    kpkdi;
 };
 
+static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
+{
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        *col = i * 2;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << *row))
+                return;
+        }
+        *col = i * 2 + 1;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << (*row + 16)))
+                return;
+        }
+    }
+}
+
 static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
 {
-    int row, col,rel;
+    int row, col, rel, assert_irq = 0;
+    uint32_t val;
+
+    if (keycode == 0xe0) {
+        kp->alt_code = 1;
+        return;
+    }
 
     if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
         return;
@@ -108,46 +131,43 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
 
         rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
         keycode &= ~(0x80); /* strip qemu key release bit */
+        if (kp->alt_code) {
+            keycode |= 0x80;
+            kp->alt_code = 0;
+        }
+
         row = kp->map[keycode].row;
         col = kp->map[keycode].column;
         if(row == -1 || col == -1)
             return;
-        switch (col) {
-        case 0:
-        case 1:
-            if(rel)
-                kp->kpasmkp0 = ~(0xffffffff);
-            else
-                kp->kpasmkp0 |= KPASMKPx_MKC(row,col);
-            break;
-        case 2:
-        case 3:
-            if(rel)
-                kp->kpasmkp1 = ~(0xffffffff);
-            else
-                kp->kpasmkp1 |= KPASMKPx_MKC(row,col);
-            break;
-        case 4:
-        case 5:
-            if(rel)
-                kp->kpasmkp2 = ~(0xffffffff);
-            else
-                kp->kpasmkp2 |= KPASMKPx_MKC(row,col);
-            break;
-        case 6:
-        case 7:
-            if(rel)
-                kp->kpasmkp3 = ~(0xffffffff);
-            else
-                kp->kpasmkp3 |= KPASMKPx_MKC(row,col);
-            break;
-        } /* switch */
+
+        val = KPASMKPx_MKC(row, col);
+        if (rel) {
+            if (kp->kpasmkp[col / 2] & val) {
+                kp->kpasmkp[col / 2] &= ~val;
+                kp->pressed_cnt--;
+                assert_irq = 1;
+            }
+        } else {
+            if (!(kp->kpasmkp[col / 2] & val)) {
+                kp->kpasmkp[col / 2] |= val;
+                kp->pressed_cnt++;
+                assert_irq = 1;
+            }
+        }
+        kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
+        if (kp->pressed_cnt == 1) {
+            kp->kpas &= ~((0xf << 4) | 0xf);
+            if (rel)
+                pxa27x_keypad_find_pressed_key(kp, &row, &col);
+            kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
+        }
         goto out;
     }
     return;
 
 out:
-    if(kp->kpc & KPC_MIE) {
+    if (assert_irq && (kp->kpc & KPC_MIE)) {
         kp->kpc |= KPC_MI;
         qemu_irq_raise(kp->irq);
     }
@@ -194,16 +214,16 @@ static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset)
         return s->kpas;
         break;
     case KPASMKP0:
-        return s->kpasmkp0;
+        return s->kpasmkp[0];
         break;
     case KPASMKP1:
-        return s->kpasmkp1;
+        return s->kpasmkp[1];
         break;
     case KPASMKP2:
-        return s->kpasmkp2;
+        return s->kpasmkp[2];
         break;
     case KPASMKP3:
-        return s->kpasmkp3;
+        return s->kpasmkp[3];
         break;
     case KPKDI:
         return s->kpkdi;
@@ -237,16 +257,16 @@ static void pxa2xx_keypad_write(void *opaque,
         s->kpas = value;
         break;
     case KPASMKP0:
-        s->kpasmkp0 = value;
+        s->kpasmkp[0] = value;
         break;
     case KPASMKP1:
-        s->kpasmkp1 = value;
+        s->kpasmkp[1] = value;
         break;
     case KPASMKP2:
-        s->kpasmkp2 = value;
+        s->kpasmkp[2] = value;
         break;
     case KPASMKP3:
-        s->kpasmkp3 = value;
+        s->kpasmkp[3] = value;
         break;
     case KPKDI:
         s->kpkdi = value;
@@ -269,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->kpasmkp0);
-    qemu_put_be32s(f, &s->kpasmkp1);
-    qemu_put_be32s(f, &s->kpasmkp2);
-    qemu_put_be32s(f, &s->kpasmkp3);
-    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->kpasmkp0);
-    qemu_get_be32s(f, &s->kpasmkp1);
-    qemu_get_be32s(f, &s->kpasmkp2);
-    qemu_get_be32s(f, &s->kpasmkp3);
-    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)
@@ -310,15 +312,14 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
     int iomemtype;
     PXA2xxKeyPadState *s;
 
-    s = (PXA2xxKeyPadState *) qemu_mallocz(sizeof(PXA2xxKeyPadState));
+    s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
     s->irq = irq;
 
     iomemtype = cpu_register_io_memory(pxa2xx_keypad_readfn,
                     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..b73290cb3f7ad8df4930cdf32ac17685824d4481 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,25 +64,13 @@ 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;
 };
 
-typedef struct __attribute__ ((__packed__)) {
+typedef struct QEMU_PACKED {
     uint32_t fdaddr;
     uint32_t fsaddr;
     uint32_t fidr;
@@ -663,7 +665,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
     }
 }
 
-static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s,
+static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
                 target_phys_addr_t addr, int *miny, int *maxy)
 {
     int src_width, dest_width;
@@ -690,7 +692,7 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s,
                                fn, s->dma_ch[0].palette, miny, maxy);
 }
 
-static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s,
+static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
                target_phys_addr_t addr, int *miny, int *maxy)
 {
     int src_width, dest_width;
@@ -718,6 +720,67 @@ static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s,
                                miny, maxy);
 }
 
+static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
+                target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, -dest_width, -s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
+               target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, -s->dest_width, dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
 static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
 {
     int width, height;
@@ -728,10 +791,11 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
     height = LCCR2_LPP(s->control[2]) + 1;
 
     if (width != s->xres || height != s->yres) {
-        if (s->orientation)
+        if (s->orientation == 90 || s->orientation == 270) {
             qemu_console_resize(s->ds, height, width);
-        else
+        } else {
             qemu_console_resize(s->ds, width, height);
+        }
         s->invalidated = 1;
         s->xres = width;
         s->yres = height;
@@ -795,10 +859,24 @@ static void pxa2xx_update_display(void *opaque)
     }
 
     if (miny >= 0) {
-        if (s->orientation)
-            dpy_update(s->ds, miny, 0, maxy - miny, s->xres);
-        else
-            dpy_update(s->ds, 0, miny, s->xres, maxy - miny);
+        switch (s->orientation) {
+        case 0:
+            dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
+            break;
+        case 90:
+            dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
+            break;
+        case 180:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
+            break;
+        case 270:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
+            break;
+        }
     }
     pxa2xx_lcdc_int_update(s);
 
@@ -820,10 +898,19 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle)
 {
     PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
 
-    if (angle) {
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert;
-    } else {
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz;
+    switch (angle) {
+    case 0:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
+        break;
+    case 90:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
+        break;
+    case 180:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
+        break;
+    case 270:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
+        break;
     }
 
     s->orientation = angle;
@@ -831,74 +918,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 +945,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
@@ -922,7 +986,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq)
     int iomemtype;
     PXA2xxLCDState *s;
 
-    s = (PXA2xxLCDState *) qemu_mallocz(sizeof(PXA2xxLCDState));
+    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
     s->invalidated = 1;
     s->irq = irq;
 
@@ -970,8 +1034,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 24d409d1a1eb87d06841d5a9211add723539429f..1de497929bb58207415a5194c4c78fb6effa9e5c 100644 (file)
 #include "hw.h"
 #include "pxa.h"
 #include "sd.h"
+#include "qdev.h"
 
 struct PXA2xxMMCIState {
     qemu_irq irq;
-    void *dma;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
 
     SDState *card;
 
@@ -102,10 +104,8 @@ static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
     if (s->cmdat & CMDAT_DMA_EN) {
         mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
 
-        pxa2xx_dma_request(s->dma,
-                        PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ));
-        pxa2xx_dma_request(s->dma,
-                        PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ));
+        qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
+        qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
     }
 
     qemu_set_irq(s->irq, !!(s->intreq & ~mask));
@@ -518,14 +518,16 @@ static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
 }
 
 PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
-                BlockDriverState *bd, qemu_irq irq, void *dma)
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma)
 {
     int iomemtype;
     PXA2xxMMCIState *s;
 
-    s = (PXA2xxMMCIState *) qemu_mallocz(sizeof(PXA2xxMMCIState));
+    s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState));
     s->irq = irq;
-    s->dma = dma;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
 
     iomemtype = cpu_register_io_memory(pxa2xx_mmci_readfn,
                     pxa2xx_mmci_writefn, s, DEVICE_NATIVE_ENDIAN);
index 50d4649f60db66baa817c288bd6ce8da85e7cea0..74c6817baffea1d8ce5510cc80dbc675314fb71b 100644 (file)
@@ -136,7 +136,7 @@ PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base)
     PXA2xxPCMCIAState *s;
 
     s = (PXA2xxPCMCIAState *)
-            qemu_mallocz(sizeof(PXA2xxPCMCIAState));
+            g_malloc0(sizeof(PXA2xxPCMCIAState));
 
     /* Socket I/O Memory Space */
     iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_io_readfn,
index a36da233d391dc68dbd15a29c2024139912c66f3..bdd82e6bf2e7bf4c47cec12962ad210565361a52 100644 (file)
@@ -5,11 +5,12 @@
  * Copyright (c) 2006 Thorsten Zitterell
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
 #include "pxa.h"
+#include "sysbus.h"
 
 #define ICIP   0x00    /* Interrupt Controller IRQ Pending register */
 #define ICMR   0x04    /* Interrupt Controller Mask register */
@@ -31,6 +32,7 @@
 #define PXA2XX_PIC_SRCS        40
 
 typedef struct {
+    SysBusDevice busdev;
     CPUState *cpu_env;
     uint32_t int_enabled[2];
     uint32_t int_pending[2];
@@ -241,51 +243,17 @@ static CPUWriteMemoryFunc * const pxa2xx_pic_writefn[] = {
     pxa2xx_pic_mem_write,
 };
 
-static void pxa2xx_pic_save(QEMUFile *f, void *opaque)
+static int pxa2xx_pic_post_load(void *opaque, int version_id)
 {
-    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-    int i;
-
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->int_enabled[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->int_pending[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->is_fiq[i]);
-    qemu_put_be32s(f, &s->int_idle);
-    for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
-        qemu_put_be32s(f, &s->priority[i]);
-}
-
-static int pxa2xx_pic_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-    int i;
-
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->int_enabled[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->int_pending[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->is_fiq[i]);
-    qemu_get_be32s(f, &s->int_idle);
-    for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
-        qemu_get_be32s(f, &s->priority[i]);
-
     pxa2xx_pic_update(opaque);
     return 0;
 }
 
-qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
+DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
 {
-    PXA2xxPICState *s;
+    DeviceState *dev = qdev_create(NULL, "pxa2xx_pic");
     int iomemtype;
-    qemu_irq *qi;
-
-    s = (PXA2xxPICState *)
-            qemu_mallocz(sizeof(PXA2xxPICState));
-    if (!s)
-        return NULL;
+    PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, sysbus_from_qdev(dev));
 
     s->cpu_env = env;
 
@@ -296,18 +264,53 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
     s->is_fiq[0] = 0;
     s->is_fiq[1] = 0;
 
-    qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
+    qdev_init_nofail(dev);
+
+    qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
 
     /* Enable IC memory-mapped registers access.  */
     iomemtype = cpu_register_io_memory(pxa2xx_pic_readfn,
                     pxa2xx_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+    sysbus_init_mmio(sysbus_from_qdev(dev), 0x00100000, iomemtype);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
 
     /* Enable IC coprocessor access.  */
     cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
 
-    register_savevm(NULL, "pxa2xx_pic", 0, 0, pxa2xx_pic_save,
-                    pxa2xx_pic_load, s);
+    return dev;
+}
+
+static VMStateDescription vmstate_pxa2xx_pic_regs = {
+    .name = "pxa2xx_pic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
+        VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
+        VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
+        VMSTATE_UINT32(int_idle, PXA2xxPICState),
+        VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
+        VMSTATE_END_OF_LIST(),
+    },
+};
 
-    return qi;
+static int pxa2xx_pic_initfn(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo pxa2xx_pic_info = {
+    .init       = pxa2xx_pic_initfn,
+    .qdev.name  = "pxa2xx_pic",
+    .qdev.desc  = "PXA2xx PIC",
+    .qdev.size  = sizeof(PXA2xxPICState),
+    .qdev.vmsd  = &vmstate_pxa2xx_pic_regs,
+};
+
+static void pxa2xx_pic_register(void)
+{
+    sysbus_register_withprop(&pxa2xx_pic_info);
 }
+device_init(pxa2xx_pic_register);
index b556d11870e8a81ccbaeb5a128704f258d619a77..4235e42639afa5e8f540b59cbb8a5604a5494628 100644 (file)
@@ -4,13 +4,14 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Copyright (c) 2006 Thorsten Zitterell
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "pxa.h"
+#include "sysbus.h"
 
 #define OSMR0  0x00
 #define OSMR1  0x04
@@ -59,13 +60,14 @@ static int pxa2xx_timer4_freq[8] = {
     [5 ... 7] = 0,
 };
 
+typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
+
 typedef struct {
     uint32_t value;
-    int level;
     qemu_irq irq;
     QEMUTimer *qtimer;
     int num;
-    void *info;
+    PXA2xxTimerInfo *info;
 } PXA2xxTimer0;
 
 typedef struct {
@@ -77,22 +79,34 @@ typedef struct {
     uint32_t control;
 } PXA2xxTimer4;
 
-typedef struct {
+struct PXA2xxTimerInfo {
+    SysBusDevice busdev;
+    uint32_t flags;
+
     int32_t clock;
     int32_t oldclock;
     uint64_t lastload;
     uint32_t freq;
     PXA2xxTimer0 timer[4];
-    PXA2xxTimer4 *tm4;
     uint32_t events;
     uint32_t irq_enabled;
     uint32_t reset3;
     uint32_t snapshot;
-} pxa2xx_timer_info;
+
+    qemu_irq irq4;
+    PXA2xxTimer4 tm4[8];
+};
+
+#define PXA2XX_TIMER_HAVE_TM4  0
+
+static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
+{
+    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
+}
 
 static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int i;
     uint32_t now_vm;
     uint64_t new_qemu;
@@ -109,7 +123,7 @@ static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
 
 static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     uint32_t now_vm;
     uint64_t new_qemu;
     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
@@ -136,7 +150,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
 
 static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int tm = 0;
 
     switch (offset) {
@@ -153,11 +167,11 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OSMR6:  tm ++;
     case OSMR5:  tm ++;
     case OSMR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         return s->tm4[tm].tm.value;
     case OSCR:
-        return s->clock + muldiv64(qemu_get_clock(vm_clock) -
+        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
                         s->lastload, s->freq, get_ticks_per_sec());
     case OSCR11: tm ++;
     case OSCR10: tm ++;
@@ -167,13 +181,13 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OSCR6:  tm ++;
     case OSCR5:  tm ++;
     case OSCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
 
         if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
             if (s->tm4[tm - 1].freq)
                 s->snapshot = s->tm4[tm - 1].clock + muldiv64(
-                                qemu_get_clock(vm_clock) -
+                                qemu_get_clock_ns(vm_clock) -
                                 s->tm4[tm - 1].lastload,
                                 s->tm4[tm - 1].freq, get_ticks_per_sec());
             else
@@ -182,7 +196,7 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
 
         if (!s->tm4[tm].freq)
             return s->tm4[tm].clock;
-        return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
                         s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
     case OIER:
         return s->irq_enabled;
@@ -198,7 +212,7 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OMCR6:  tm ++;
     case OMCR5:  tm ++;
     case OMCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         return s->tm4[tm].control;
     case OSNR:
@@ -215,7 +229,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
                 uint32_t value)
 {
     int i, tm = 0;
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
 
     switch (offset) {
     case OSMR3:  tm ++;
@@ -223,7 +237,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSMR1:  tm ++;
     case OSMR0:
         s->timer[tm].value = value;
-        pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
+        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
         break;
     case OSMR11: tm ++;
     case OSMR10: tm ++;
@@ -233,14 +247,14 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSMR6:  tm ++;
     case OSMR5:  tm ++;
     case OSMR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].tm.value = value;
-        pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         break;
     case OSCR:
         s->oldclock = s->clock;
-        s->lastload = qemu_get_clock(vm_clock);
+        s->lastload = qemu_get_clock_ns(vm_clock);
         s->clock = value;
         pxa2xx_timer_update(s, s->lastload);
         break;
@@ -252,10 +266,10 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSCR6:  tm ++;
     case OSCR5:  tm ++;
     case OSCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].oldclock = s->tm4[tm].clock;
-        s->tm4[tm].lastload = qemu_get_clock(vm_clock);
+        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
         s->tm4[tm].clock = value;
         pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
         break;
@@ -263,20 +277,13 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
         s->irq_enabled = value & 0xfff;
         break;
     case OSSR: /* Status register */
+        value &= s->events;
         s->events &= ~value;
-        for (i = 0; i < 4; i ++, value >>= 1) {
-            if (s->timer[i].level && (value & 1)) {
-                s->timer[i].level = 0;
+        for (i = 0; i < 4; i ++, value >>= 1)
+            if (value & 1)
                 qemu_irq_lower(s->timer[i].irq);
-            }
-        }
-        if (s->tm4) {
-            for (i = 0; i < 8; i ++, value >>= 1)
-                if (s->tm4[i].tm.level && (value & 1))
-                    s->tm4[i].tm.level = 0;
-            if (!(s->events & 0xff0))
-                qemu_irq_lower(s->tm4->tm.irq);
-        }
+        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
+            qemu_irq_lower(s->irq4);
         break;
     case OWER: /* XXX: Reset on OSMR3 match? */
         s->reset3 = value;
@@ -285,7 +292,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OMCR6:  tm ++;
     case OMCR5:  tm ++;
     case OMCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].control = value & 0x0ff;
         /* XXX Stop if running (shouldn't happen) */
@@ -293,14 +300,14 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
             s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
         else {
             s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         }
         break;
     case OMCR11: tm ++;
     case OMCR10: tm ++;
     case OMCR9:  tm ++;
     case OMCR8:  tm += 4;
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].control = value & 0x3ff;
         /* XXX Stop if running (shouldn't happen) */
@@ -309,7 +316,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
                     pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
         else {
             s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         }
         break;
     default:
@@ -333,10 +340,9 @@ static CPUWriteMemoryFunc * const pxa2xx_timer_writefn[] = {
 static void pxa2xx_timer_tick(void *opaque)
 {
     PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
-    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+    PXA2xxTimerInfo *i = t->info;
 
     if (i->irq_enabled & (1 << t->num)) {
-        t->level = 1;
         i->events |= 1 << t->num;
         qemu_irq_raise(t->irq);
     }
@@ -351,140 +357,162 @@ static void pxa2xx_timer_tick(void *opaque)
 static void pxa2xx_timer_tick4(void *opaque)
 {
     PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
-    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
+    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
 
     pxa2xx_timer_tick(&t->tm);
     if (t->control & (1 << 3))
         t->clock = 0;
     if (t->control & (1 << 6))
-        pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
-}
-
-static void pxa2xx_timer_save(QEMUFile *f, void *opaque)
-{
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
-    int i;
-
-    qemu_put_be32s(f, (uint32_t *) &s->clock);
-    qemu_put_be32s(f, (uint32_t *) &s->oldclock);
-    qemu_put_be64s(f, &s->lastload);
-
-    for (i = 0; i < 4; i ++) {
-        qemu_put_be32s(f, &s->timer[i].value);
-        qemu_put_be32(f, s->timer[i].level);
-    }
-    if (s->tm4)
-        for (i = 0; i < 8; i ++) {
-            qemu_put_be32s(f, &s->tm4[i].tm.value);
-            qemu_put_be32(f, s->tm4[i].tm.level);
-            qemu_put_sbe32s(f, &s->tm4[i].oldclock);
-            qemu_put_sbe32s(f, &s->tm4[i].clock);
-            qemu_put_be64s(f, &s->tm4[i].lastload);
-            qemu_put_be32s(f, &s->tm4[i].freq);
-            qemu_put_be32s(f, &s->tm4[i].control);
-        }
-
-    qemu_put_be32s(f, &s->events);
-    qemu_put_be32s(f, &s->irq_enabled);
-    qemu_put_be32s(f, &s->reset3);
-    qemu_put_be32s(f, &s->snapshot);
+        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
+    if (i->events & 0xff0)
+        qemu_irq_raise(i->irq4);
 }
 
-static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id)
+static int pxa25x_timer_post_load(void *opaque, int version_id)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int64_t now;
     int i;
 
-    qemu_get_be32s(f, (uint32_t *) &s->clock);
-    qemu_get_be32s(f, (uint32_t *) &s->oldclock);
-    qemu_get_be64s(f, &s->lastload);
-
-    now = qemu_get_clock(vm_clock);
-    for (i = 0; i < 4; i ++) {
-        qemu_get_be32s(f, &s->timer[i].value);
-        s->timer[i].level = qemu_get_be32(f);
-    }
+    now = qemu_get_clock_ns(vm_clock);
     pxa2xx_timer_update(s, now);
 
-    if (s->tm4)
-        for (i = 0; i < 8; i ++) {
-            qemu_get_be32s(f, &s->tm4[i].tm.value);
-            s->tm4[i].tm.level = qemu_get_be32(f);
-            qemu_get_sbe32s(f, &s->tm4[i].oldclock);
-            qemu_get_sbe32s(f, &s->tm4[i].clock);
-            qemu_get_be64s(f, &s->tm4[i].lastload);
-            qemu_get_be32s(f, &s->tm4[i].freq);
-            qemu_get_be32s(f, &s->tm4[i].control);
+    if (pxa2xx_timer_has_tm4(s))
+        for (i = 0; i < 8; i ++)
             pxa2xx_timer_update4(s, now, i);
-        }
-
-    qemu_get_be32s(f, &s->events);
-    qemu_get_be32s(f, &s->irq_enabled);
-    qemu_get_be32s(f, &s->reset3);
-    qemu_get_be32s(f, &s->snapshot);
 
     return 0;
 }
 
-static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
-                qemu_irq *irqs)
+static int pxa2xx_timer_init(SysBusDevice *dev)
 {
     int i;
     int iomemtype;
-    pxa2xx_timer_info *s;
+    PXA2xxTimerInfo *s;
 
-    s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
+    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
     s->irq_enabled = 0;
     s->oldclock = 0;
     s->clock = 0;
-    s->lastload = qemu_get_clock(vm_clock);
+    s->lastload = qemu_get_clock_ns(vm_clock);
     s->reset3 = 0;
 
     for (i = 0; i < 4; i ++) {
         s->timer[i].value = 0;
-        s->timer[i].irq = irqs[i];
+        sysbus_init_irq(dev, &s->timer[i].irq);
         s->timer[i].info = s;
         s->timer[i].num = i;
-        s->timer[i].level = 0;
-        s->timer[i].qtimer = qemu_new_timer(vm_clock,
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
                         pxa2xx_timer_tick, &s->timer[i]);
     }
+    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
+        sysbus_init_irq(dev, &s->irq4);
+
+        for (i = 0; i < 8; i ++) {
+            s->tm4[i].tm.value = 0;
+            s->tm4[i].tm.info = s;
+            s->tm4[i].tm.num = i + 4;
+            s->tm4[i].freq = 0;
+            s->tm4[i].control = 0x0;
+            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+        }
+    }
 
     iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
                     pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    sysbus_init_mmio(dev, 0x00001000, iomemtype);
 
-    register_savevm(NULL, "pxa2xx_timer", 0, 0,
-                    pxa2xx_timer_save, pxa2xx_timer_load, s);
-
-    return s;
+    return 0;
 }
 
-void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs)
+static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
+    .name = "pxa2xx_timer0",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(value, PXA2xxTimer0),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
+    .name = "pxa2xx_timer4",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_INT32(oldclock, PXA2xxTimer4),
+        VMSTATE_INT32(clock, PXA2xxTimer4),
+        VMSTATE_UINT64(lastload, PXA2xxTimer4),
+        VMSTATE_UINT32(freq, PXA2xxTimer4),
+        VMSTATE_UINT32(control, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
 {
-    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
-    s->freq = PXA25X_FREQ;
-    s->tm4 = NULL;
+    return pxa2xx_timer_has_tm4(opaque);
 }
 
-void pxa27x_timer_init(target_phys_addr_t base,
-                qemu_irq *irqs, qemu_irq irq4)
-{
-    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
-    int i;
-    s->freq = PXA27X_FREQ;
-    s->tm4 = (PXA2xxTimer4 *) qemu_mallocz(8 *
-                    sizeof(PXA2xxTimer4));
-    for (i = 0; i < 8; i ++) {
-        s->tm4[i].tm.value = 0;
-        s->tm4[i].tm.irq = irq4;
-        s->tm4[i].tm.info = s;
-        s->tm4[i].tm.num = i + 4;
-        s->tm4[i].tm.level = 0;
-        s->tm4[i].freq = 0;
-        s->tm4[i].control = 0x0;
-        s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock,
-                        pxa2xx_timer_tick4, &s->tm4[i]);
+static const VMStateDescription vmstate_pxa2xx_timer_regs = {
+    .name = "pxa2xx_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pxa25x_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(clock, PXA2xxTimerInfo),
+        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
+        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_UINT32(events, PXA2xxTimerInfo),
+        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
+        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
+        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
+                        pxa2xx_timer_has_tm4_test, 0,
+                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
     }
-}
+};
+
+static SysBusDeviceInfo pxa25x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa25x-timer",
+    .qdev.desc  = "PXA25x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa27x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa27x-timer",
+    .qdev.desc  = "PXA27x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, true),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pxa2xx_timer_register(void)
+{
+    sysbus_register_withprop(&pxa25x_timer_dev_info);
+    sysbus_register_withprop(&pxa27x_timer_dev_info);
+};
+device_init(pxa2xx_timer_register);
index a493087a520db00934330833d63cc104ec3ee4db..f0b811c80665c591879ef72f9357b6930eb023cd 100644 (file)
@@ -51,7 +51,7 @@ static int parse_bit(DeviceState *dev, Property *prop, const char *str)
 
 static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
 {
-    uint8_t *p = qdev_get_prop_ptr(dev, prop);
+    uint32_t *p = qdev_get_prop_ptr(dev, prop);
     return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
 }
 
@@ -93,6 +93,35 @@ PropertyInfo qdev_prop_uint8 = {
     .print = print_uint8,
 };
 
+/* --- 8bit hex value --- */
+
+static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    *ptr = strtoul(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx8, *ptr);
+}
+
+PropertyInfo qdev_prop_hex8 = {
+    .name  = "hex8",
+    .type  = PROP_TYPE_UINT8,
+    .size  = sizeof(uint8_t),
+    .parse = parse_hex8,
+    .print = print_hex8,
+};
+
 /* --- 16bit integer --- */
 
 static int parse_uint16(DeviceState *dev, Property *prop, const char *str)
@@ -275,14 +304,14 @@ static int parse_string(DeviceState *dev, Property *prop, const char *str)
     char **ptr = qdev_get_prop_ptr(dev, prop);
 
     if (*ptr)
-        qemu_free(*ptr);
-    *ptr = qemu_strdup(str);
+        g_free(*ptr);
+    *ptr = g_strdup(str);
     return 0;
 }
 
 static void free_string(DeviceState *dev, Property *prop)
 {
-    qemu_free(*(char **)qdev_get_prop_ptr(dev, prop));
+    g_free(*(char **)qdev_get_prop_ptr(dev, prop));
 }
 
 static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len)
@@ -312,7 +341,7 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str)
     bs = bdrv_find(str);
     if (bs == NULL)
         return -ENOENT;
-    if (bdrv_attach(bs, dev) < 0)
+    if (bdrv_attach_dev(bs, dev) < 0)
         return -EEXIST;
     *ptr = bs;
     return 0;
@@ -323,7 +352,7 @@ static void free_drive(DeviceState *dev, Property *prop)
     BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
 
     if (*ptr) {
-        bdrv_detach(*ptr, dev);
+        bdrv_detach_dev(*ptr, dev);
         blockdev_auto_del(*ptr);
     }
 }
@@ -351,8 +380,13 @@ static int parse_chr(DeviceState *dev, Property *prop, const char *str)
     CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
 
     *ptr = qemu_chr_find(str);
-    if (*ptr == NULL)
+    if (*ptr == NULL) {
         return -ENOENT;
+    }
+    if ((*ptr)->avail_connections < 1) {
+        return -EEXIST;
+    }
+    --(*ptr)->avail_connections;
     return 0;
 }
 
@@ -519,6 +553,8 @@ static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
         return -EINVAL;
     if (fn > 7)
         return -EINVAL;
+    if (slot > 31)
+        return -EINVAL;
     *ptr = slot << 3 | fn;
     return 0;
 }
@@ -673,7 +709,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va
 {
     int res;
 
-    res = bdrv_attach(value, dev);
+    res = bdrv_attach_dev(value, dev);
     if (res < 0) {
         error_report("Can't attach drive %s to %s.%s: %s",
                      bdrv_get_device_name(value),
@@ -763,7 +799,7 @@ static int qdev_add_one_global(QemuOpts *opts, void *opaque)
 {
     GlobalProperty *g;
 
-    g = qemu_mallocz(sizeof(*g));
+    g = g_malloc0(sizeof(*g));
     g->driver   = qemu_opt_get(opts, "driver");
     g->property = qemu_opt_get(opts, "property");
     g->value    = qemu_opt_get(opts, "value");
index c7fec44a83e5e8f1fa9f6c1327690a2a97bc9368..106407f226dee0cd5e0dc98dab3e8a00bd89a455 100644 (file)
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -36,6 +36,7 @@ static bool qdev_hot_removed = false;
 
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 static BusState *main_system_bus;
+static void main_system_bus_create(void);
 
 DeviceInfo *device_info_list;
 
@@ -84,13 +85,13 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     DeviceState *dev;
 
     assert(bus->info == info->bus_info);
-    dev = qemu_mallocz(info->size);
+    dev = g_malloc0(info->size);
     dev->info = info;
     dev->parent_bus = bus;
     qdev_prop_set_defaults(dev, dev->info->props);
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
     qdev_prop_set_globals(dev);
-    QLIST_INSERT_HEAD(&bus->children, dev, sibling);
+    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
     if (qdev_hotplug) {
         assert(bus->allow_hotplug);
         dev->hotplugged = 1;
@@ -105,6 +106,23 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
    and allows properties to be set.  qdev_init should be called to
    initialize the actual device emulation.  */
 DeviceState *qdev_create(BusState *bus, const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_try_create(bus, name);
+    if (!dev) {
+        if (bus) {
+            hw_error("Unknown device '%s' for bus '%s'\n", name,
+                     bus->info->name);
+        } else {
+            hw_error("Unknown device '%s' for default sysbus\n", name);
+        }
+    }
+
+    return dev;
+}
+
+DeviceState *qdev_try_create(BusState *bus, const char *name)
 {
     DeviceInfo *info;
 
@@ -114,7 +132,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
 
     info = qdev_find_info(bus->info, name);
     if (!info) {
-        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
+        return NULL;
     }
 
     return qdev_create_from_info(bus, info);
@@ -168,7 +186,7 @@ int qdev_device_help(QemuOpts *opts)
         return 1;
     }
 
-    if (!qemu_opt_get(opts, "?")) {
+    if (!driver || !qemu_opt_get(opts, "?")) {
         return 0;
     }
 
@@ -189,6 +207,12 @@ int qdev_device_help(QemuOpts *opts)
         }
         error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
     }
+    for (prop = info->bus_info->props; prop && prop->name; prop++) {
+        if (!prop->info->parse) {
+            continue;           /* no way to set it, don't show */
+        }
+        error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
+    }
     return 1;
 }
 
@@ -277,6 +301,9 @@ int qdev_init(DeviceState *dev)
                                        dev->alias_required_for_version);
     }
     dev->state = DEV_STATE_INITIALIZED;
+    if (dev->hotplugged && dev->info->reset) {
+        dev->info->reset(dev);
+    }
     return 0;
 }
 
@@ -313,8 +340,7 @@ static int qdev_reset_one(DeviceState *dev, void *opaque)
 BusState *sysbus_get_default(void)
 {
     if (!main_system_bus) {
-        main_system_bus = qbus_create(&system_bus_info, NULL,
-                                      "main-system-bus");
+        main_system_bus_create();
     }
     return main_system_bus;
 }
@@ -346,7 +372,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
@@ -358,7 +385,7 @@ void qdev_init_nofail(DeviceState *dev)
     DeviceInfo *info = dev->info;
 
     if (qdev_init(dev) < 0) {
-        error_report("Initialization of device %s failed\n", info->name);
+        error_report("Initialization of device %s failed", info->name);
         exit(1);
     }
 }
@@ -381,13 +408,13 @@ void qdev_free(DeviceState *dev)
         if (dev->opts)
             qemu_opts_del(dev->opts);
     }
-    QLIST_REMOVE(dev, sibling);
+    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
     for (prop = dev->info->props; prop && prop->name; prop++) {
         if (prop->info->free) {
             prop->info->free(dev, prop);
         }
     }
-    qemu_free(dev);
+    g_free(dev);
 }
 
 void qdev_machine_creation_done(void)
@@ -446,7 +473,7 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
 
 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
 {
-    qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
+    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
     if (nd->vlan)
         qdev_prop_set_vlan(dev, "vlan", nd->vlan);
     if (nd->netdev)
@@ -455,6 +482,7 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
         qdev_prop_exists(dev, "vectors")) {
         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
     }
+    nd->instantiated = 1;
 }
 
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
@@ -482,7 +510,7 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
         }
     }
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         err = qdev_walk_children(dev, devfn, busfn, opaque);
         if (err < 0) {
             return err;
@@ -532,7 +560,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
         return bus;
     }
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
             ret = qbus_find_recursive(child, name, info);
             if (ret) {
@@ -548,7 +576,7 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
     DeviceState *dev, *ret;
     BusState *child;
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id && strcmp(dev->id, id) == 0)
             return dev;
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
@@ -581,7 +609,7 @@ static void qbus_list_dev(BusState *bus)
     const char *sep = " ";
 
     error_printf("devices at \"%s\":", bus->name);
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         error_printf("%s\"%s\"", sep, dev->info->name);
         if (dev->id)
             error_printf("/\"%s\"", dev->id);
@@ -612,17 +640,17 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
      *   (2) driver name
      *   (3) driver alias, if present
      */
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id  &&  strcmp(dev->id, elem) == 0) {
             return dev;
         }
     }
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (strcmp(dev->info->name, elem) == 0) {
             return dev;
         }
     }
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
             return dev;
         }
@@ -728,17 +756,17 @@ void qbus_create_inplace(BusState *bus, BusInfo *info,
 
     if (name) {
         /* use supplied name */
-        bus->name = qemu_strdup(name);
+        bus->name = g_strdup(name);
     } else if (parent && parent->id) {
         /* parent device has id -> use it for bus name */
         len = strlen(parent->id) + 16;
-        buf = qemu_malloc(len);
+        buf = g_malloc(len);
         snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
         bus->name = buf;
     } else {
         /* no id -> use lowercase bus type for bus name */
         len = strlen(info->name) + 16;
-        buf = qemu_malloc(len);
+        buf = g_malloc(len);
         len = snprintf(buf, len, "%s.%d", info->name,
                        parent ? parent->num_child_bus : 0);
         for (i = 0; i < len; i++)
@@ -746,7 +774,7 @@ void qbus_create_inplace(BusState *bus, BusInfo *info,
         bus->name = buf;
     }
 
-    QLIST_INIT(&bus->children);
+    QTAILQ_INIT(&bus->children);
     if (parent) {
         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
         parent->num_child_bus++;
@@ -761,17 +789,27 @@ BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
 {
     BusState *bus;
 
-    bus = qemu_mallocz(info->size);
+    bus = g_malloc0(info->size);
     bus->qdev_allocated = 1;
     qbus_create_inplace(bus, info, parent, name);
     return bus;
 }
 
+static void main_system_bus_create(void)
+{
+    /* assign main_system_bus before qbus_create_inplace()
+     * in order to make "if (bus != main_system_bus)" work */
+    main_system_bus = g_malloc0(system_bus_info.size);
+    main_system_bus->qdev_allocated = 1;
+    qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
+                        "main-system-bus");
+}
+
 void qbus_free(BusState *bus)
 {
     DeviceState *dev;
 
-    while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
+    while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
         qdev_free(dev);
     }
     if (bus->parent) {
@@ -781,9 +819,9 @@ void qbus_free(BusState *bus)
         assert(bus != main_system_bus); /* main_system_bus is never freed */
         qemu_unregister_reset(qbus_reset_all_fn, bus);
     }
-    qemu_free((void*)bus->name);
+    g_free((void*)bus->name);
     if (bus->qdev_allocated) {
-        qemu_free(bus);
+        g_free(bus);
     }
 }
 
@@ -840,7 +878,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
     qdev_printf("bus: %s\n", bus->name);
     indent += 2;
     qdev_printf("type %s\n", bus->info->name);
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         qdev_print(mon, dev, indent);
     }
 }
@@ -903,7 +941,7 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
         if (dev->parent_bus->info->get_fw_dev_path) {
             d = dev->parent_bus->info->get_fw_dev_path(dev);
             l += snprintf(p + l, size - l, "%s", d);
-            qemu_free(d);
+            g_free(d);
         } else {
             l += snprintf(p + l, size - l, "%s", dev->info->name);
         }
index 9808f85119700449c9eca96d36f0aaba4e3c5270..36a4198c898f8c99396b50077e1db4c077a34db2 100644 (file)
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -42,7 +42,7 @@ struct DeviceState {
     qemu_irq *gpio_in;
     QLIST_HEAD(, BusState) child_bus;
     int num_child_bus;
-    QLIST_ENTRY(DeviceState) sibling;
+    QTAILQ_ENTRY(DeviceState) sibling;
     int instance_id_alias;
     int alias_required_for_version;
 };
@@ -73,7 +73,7 @@ struct BusState {
     const char *name;
     int allow_hotplug;
     int qdev_allocated;
-    QLIST_HEAD(, DeviceState) children;
+    QTAILQ_HEAD(ChildrenHead, DeviceState) children;
     QLIST_ENTRY(BusState) sibling;
 };
 
@@ -122,6 +122,7 @@ typedef struct GlobalProperty {
 /*** Board API.  This should go away once we have a machine config file.  ***/
 
 DeviceState *qdev_create(BusState *bus, const char *name);
+DeviceState *qdev_try_create(BusState *bus, const char *name);
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts);
 int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
@@ -223,6 +224,7 @@ extern PropertyInfo qdev_prop_uint16;
 extern PropertyInfo qdev_prop_uint32;
 extern PropertyInfo qdev_prop_int32;
 extern PropertyInfo qdev_prop_uint64;
+extern PropertyInfo qdev_prop_hex8;
 extern PropertyInfo qdev_prop_hex32;
 extern PropertyInfo qdev_prop_hex64;
 extern PropertyInfo qdev_prop_string;
@@ -266,6 +268,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
 #define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
+#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
 #define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
 #define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
index 76f43e646c12ebb594ec3c994ae66c679cfc281d..367aad19f443e472c8655ef7e6615b80a915f0f8 100644 (file)
@@ -19,6 +19,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "qemu-timer.h"
 #include "qxl.h"
 
 static const char *qxl_type[] = {
@@ -223,7 +224,8 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
     if (!qxl->cmdlog) {
         return;
     }
-    fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
+    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+            qxl->id, ring);
     fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
             qxl_name(qxl_type, ext->cmd.type),
             compat ? "(compat)" : "");
index 58965e0179dcadfdb1b318e36bdefd6bdb99d406..2c51ba9806d6eaa20dfed725d2eb95ccc6a7a130 100644 (file)
@@ -28,16 +28,16 @@ static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
     int len, i;
 
     src += (qxl->guest_primary.surface.height - rect->top - 1) *
-        qxl->guest_primary.stride;
-    dst += rect->top  * qxl->guest_primary.stride;
+        qxl->guest_primary.abs_stride;
+    dst += rect->top  * qxl->guest_primary.abs_stride;
     src += rect->left * qxl->guest_primary.bytes_pp;
     dst += rect->left * qxl->guest_primary.bytes_pp;
     len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
 
     for (i = rect->top; i < rect->bottom; i++) {
         memcpy(dst, src, len);
-        dst += qxl->guest_primary.stride;
-        src -= qxl->guest_primary.stride;
+        dst += qxl->guest_primary.abs_stride;
+        src -= qxl->guest_primary.abs_stride;
     }
 }
 
@@ -45,7 +45,8 @@ void qxl_render_resize(PCIQXLDevice *qxl)
 {
     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
 
-    qxl->guest_primary.stride = sc->stride;
+    qxl->guest_primary.qxl_stride = sc->stride;
+    qxl->guest_primary.abs_stride = abs(sc->stride);
     qxl->guest_primary.resized++;
     switch (sc->format) {
     case SPICE_SURFACE_FMT_16_555:
@@ -75,23 +76,30 @@ void qxl_render_update(PCIQXLDevice *qxl)
     VGACommonState *vga = &qxl->vga;
     QXLRect dirty[32], update;
     void *ptr;
-    int i;
+    int i, redraw = 0;
+
+    if (!is_buffer_shared(vga->ds->surface)) {
+        dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__);
+        qxl->guest_primary.resized++;
+        qxl->guest_primary.commands++;
+        redraw = 1;
+    }
 
     if (qxl->guest_primary.resized) {
         qxl->guest_primary.resized = 0;
 
         if (qxl->guest_primary.flipped) {
-            qemu_free(qxl->guest_primary.flipped);
+            g_free(qxl->guest_primary.flipped);
             qxl->guest_primary.flipped = NULL;
         }
         qemu_free_displaysurface(vga->ds);
 
-        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
-        if (qxl->guest_primary.stride < 0) {
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
+        if (qxl->guest_primary.qxl_stride < 0) {
             /* spice surface is upside down -> need extra buffer to flip */
-            qxl->guest_primary.stride = -qxl->guest_primary.stride;
-            qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
-                                                     qxl->guest_primary.stride);
+            qxl->guest_primary.flipped =
+                g_malloc(qxl->guest_primary.surface.width *
+                         qxl->guest_primary.abs_stride);
             ptr = qxl->guest_primary.flipped;
         } else {
             ptr = qxl->guest_primary.data;
@@ -100,7 +108,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
                __FUNCTION__,
                qxl->guest_primary.surface.width,
                qxl->guest_primary.surface.height,
-               qxl->guest_primary.stride,
+               qxl->guest_primary.qxl_stride,
                qxl->guest_primary.bytes_pp,
                qxl->guest_primary.bits_pp,
                qxl->guest_primary.flipped ? "yes" : "no");
@@ -108,7 +116,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
             qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
                                             qxl->guest_primary.surface.height,
                                             qxl->guest_primary.bits_pp,
-                                            qxl->guest_primary.stride,
+                                            qxl->guest_primary.abs_stride,
                                             ptr);
         dpy_resize(vga->ds);
     }
@@ -124,8 +132,12 @@ void qxl_render_update(PCIQXLDevice *qxl)
     update.bottom = qxl->guest_primary.surface.height;
 
     memset(dirty, 0, sizeof(dirty));
-    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
-                                 dirty, ARRAY_SIZE(dirty), 1);
+    qxl_spice_update_area(qxl, 0, &update,
+                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
+    if (redraw) {
+        memset(dirty, 0, sizeof(dirty));
+        dirty[0] = update;
+    }
 
     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
         if (qemu_spice_rect_is_empty(dirty+i)) {
@@ -185,7 +197,6 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
     QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
     QXLCursor *cursor;
     QEMUCursor *c;
-    int x = -1, y = -1;
 
     if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
         return;
@@ -198,8 +209,6 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
     }
     switch (cmd->type) {
     case QXL_CURSOR_SET:
-        x = cmd->u.set.position.x;
-        y = cmd->u.set.position.y;
         cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
         if (cursor->chunk.data_size != cursor->data_size) {
             fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
@@ -209,18 +218,20 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
         if (c == NULL) {
             c = cursor_builtin_left_ptr();
         }
-        qemu_mutex_lock_iothread();
-        qxl->ssd.ds->cursor_define(c);
-        qxl->ssd.ds->mouse_set(x, y, 1);
-        qemu_mutex_unlock_iothread();
-        cursor_put(c);
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.cursor) {
+            cursor_put(qxl->ssd.cursor);
+        }
+        qxl->ssd.cursor = c;
+        qxl->ssd.mouse_x = cmd->u.set.position.x;
+        qxl->ssd.mouse_y = cmd->u.set.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
         break;
     case QXL_CURSOR_MOVE:
-        x = cmd->u.position.x;
-        y = cmd->u.position.y;
-        qemu_mutex_lock_iothread();
-        qxl->ssd.ds->mouse_set(x, y, 1);
-        qemu_mutex_unlock_iothread();
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qxl->ssd.mouse_x = cmd->u.position.x;
+        qxl->ssd.mouse_y = cmd->u.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
         break;
     }
 }
index fe4212bff04e73afa3d46de513d14eea44089b29..41500e9ea4328d8b8b7ab691ae648c84913400c9 100644 (file)
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -18,8 +18,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
 #include "qemu-common.h"
 #include "qemu-timer.h"
 #include "qemu-queue.h"
@@ -120,11 +118,130 @@ static QXLMode qxl_modes[] = {
 static PCIQXLDevice *qxl0;
 
 static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static void qxl_destroy_primary(PCIQXLDevice *d);
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
 static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
 
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+{
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+#endif
+    if (qxl->guestdebug) {
+        va_list ap;
+        va_start(ap, msg);
+        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
+        vfprintf(stderr, msg, ap);
+        fprintf(stderr, "\n");
+        va_end(ap);
+    }
+}
+
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async)
+{
+    if (async == QXL_SYNC) {
+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
+                        dirty_rects, num_dirty_rects, clear_dirty_region);
+    } else {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
+                                    clear_dirty_region, 0);
+#else
+        abort();
+#endif
+    }
+}
+
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
+                                                    uint32_t id)
+{
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_surfaces.cmds[id] = 0;
+    qxl->guest_surfaces.count--;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+                                           qxl_async_io async)
+{
+    if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+        abort();
+#else
+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
+                                        (uint64_t)id);
+#endif
+    } else {
+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+        qxl_spice_destroy_surface_wait_complete(qxl, id);
+    }
+}
+
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
+{
+    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
+}
+#endif
+
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count)
+{
+    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
+}
+
+void qxl_spice_oom(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->oom(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+}
+
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
+{
+    qemu_mutex_lock(&qxl->track_lock);
+    memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
+    qxl->guest_surfaces.count = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
+{
+    if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+        abort();
+#else
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
+#endif
+    } else {
+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+        qxl_spice_destroy_surfaces_complete(qxl);
+    }
+}
+
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_cursor = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+
 static inline uint32_t msb_mask(uint32_t val)
 {
     uint32_t mask;
@@ -147,7 +264,7 @@ static ram_addr_t qxl_rom_size(void)
 
 static void init_qxl_rom(PCIQXLDevice *d)
 {
-    QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
+    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
     QXLModes *modes = (QXLModes *)(rom + 1);
     uint32_t ram_header_size;
     uint32_t surface0_area_size;
@@ -214,6 +331,7 @@ static void init_qxl_ram(PCIQXLDevice *d)
     d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
     d->ram->int_pending = cpu_to_le32(0);
     d->ram->int_mask    = cpu_to_le32(0);
+    d->ram->update_surface = 0;
     SPICE_RING_INIT(&d->ram->cmd_ring);
     SPICE_RING_INIT(&d->ram->cursor_ring);
     SPICE_RING_INIT(&d->ram->release_ring);
@@ -223,39 +341,37 @@ static void init_qxl_ram(PCIQXLDevice *d)
 }
 
 /* can be called from spice server thread context */
-static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
+static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
 {
     while (addr < end) {
-        cpu_physical_memory_set_dirty(addr);
+        memory_region_set_dirty(mr, addr);
         addr += TARGET_PAGE_SIZE;
     }
 }
 
 static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
 {
-    ram_addr_t addr = qxl->rom_offset;
-    qxl_set_dirty(addr, addr + qxl->rom_size);
+    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
 }
 
 /* called from spice server thread context only */
 static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
 {
-    ram_addr_t addr = qxl->vga.vram_offset;
     void *base = qxl->vga.vram_ptr;
     intptr_t offset;
 
     offset = ptr - base;
     offset &= ~(TARGET_PAGE_SIZE-1);
     assert(offset < qxl->vga.vram_size);
-    qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE);
+    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
 }
 
 /* can be called from spice server thread context */
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
 {
-    ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset;
-    ram_addr_t end  = qxl->vga.vram_offset + qxl->vga.vram_size;
-    qxl_set_dirty(addr, end);
+    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
+    ram_addr_t end  = qxl->vga.vram_size;
+    qxl_set_dirty(&qxl->vga.vram, addr, end);
 }
 
 /*
@@ -270,6 +386,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
         QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
         uint32_t id = le32_to_cpu(cmd->surface_id);
         PANIC_ON(id >= NUM_SURFACES);
+        qemu_mutex_lock(&qxl->track_lock);
         if (cmd->type == QXL_SURFACE_CMD_CREATE) {
             qxl->guest_surfaces.cmds[id] = ext->cmd.data;
             qxl->guest_surfaces.count++;
@@ -280,13 +397,16 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
             qxl->guest_surfaces.cmds[id] = 0;
             qxl->guest_surfaces.count--;
         }
+        qemu_mutex_unlock(&qxl->track_lock);
         break;
     }
     case QXL_CMD_CURSOR:
     {
         QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
         if (cmd->type == QXL_CURSOR_SET) {
+            qemu_mutex_lock(&qxl->track_lock);
             qxl->guest_cursor = ext->cmd.data;
+            qemu_mutex_unlock(&qxl->track_lock);
         }
         break;
     }
@@ -336,6 +456,58 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
     info->n_surfaces = NUM_SURFACES;
 }
 
+static const char *qxl_mode_to_string(int mode)
+{
+    switch (mode) {
+    case QXL_MODE_COMPAT:
+        return "compat";
+    case QXL_MODE_NATIVE:
+        return "native";
+    case QXL_MODE_UNDEFINED:
+        return "undefined";
+    case QXL_MODE_VGA:
+        return "vga";
+    }
+    return "INVALID";
+}
+
+static const char *io_port_to_string(uint32_t io_port)
+{
+    if (io_port >= QXL_IO_RANGE_SIZE) {
+        return "out of range";
+    }
+    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
+        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
+        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
+        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
+        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
+        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
+        [QXL_IO_RESET]                  = "QXL_IO_RESET",
+        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
+        [QXL_IO_LOG]                    = "QXL_IO_LOG",
+        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
+        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
+        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
+        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
+        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
+        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
+        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
+        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
+        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
+        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
+        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
+                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
+#endif
+    };
+    return io_port_to_string[io_port];
+}
+
 /* called from spice server thread context only */
 static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
 {
@@ -343,27 +515,34 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
     SimpleSpiceUpdate *update;
     QXLCommandRing *ring;
     QXLCommand *cmd;
-    int notify;
+    int notify, ret;
 
     switch (qxl->mode) {
     case QXL_MODE_VGA:
         dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
-        update = qemu_spice_create_update(&qxl->ssd);
-        if (update == NULL) {
-            return false;
+        ret = false;
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.update != NULL) {
+            update = qxl->ssd.update;
+            qxl->ssd.update = NULL;
+            *ext = update->ext;
+            ret = true;
         }
-        *ext = update->ext;
-        qxl_log_command(qxl, "vga", ext);
-        return true;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        if (ret) {
+            dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
+            qxl_log_command(qxl, "vga", ext);
+        }
+        return ret;
     case QXL_MODE_COMPAT:
     case QXL_MODE_NATIVE:
     case QXL_MODE_UNDEFINED:
-        dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
-               qxl->cmdflags ? "compat" : "native");
+        dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
         ring = &qxl->ram->cmd_ring;
         if (SPICE_RING_IS_EMPTY(ring)) {
             return false;
         }
+        dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
         SPICE_RING_CONS_ITEM(ring, cmd);
         ext->cmd      = *cmd;
         ext->group_id = MEMSLOT_GROUP_GUEST;
@@ -557,6 +736,38 @@ static int interface_flush_resources(QXLInstance *sin)
     return ret;
 }
 
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
+
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    uint32_t current_async;
+
+    qemu_mutex_lock(&qxl->async_lock);
+    current_async = qxl->current_async;
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qemu_mutex_unlock(&qxl->async_lock);
+
+    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
+    switch (current_async) {
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        qxl_create_guest_primary_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        qxl_spice_destroy_surfaces_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
+        break;
+    }
+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
+}
+
+#endif
+
 static const QXLInterface qxl_interface = {
     .base.type               = SPICE_INTERFACE_QXL,
     .base.description        = "qxl gpu",
@@ -576,6 +787,9 @@ static const QXLInterface qxl_interface = {
     .req_cursor_notification = interface_req_cursor_notification,
     .notify_update           = interface_notify_update,
     .flush_resources         = interface_flush_resources,
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    .async_complete          = interface_async_complete,
+#endif
 };
 
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -595,10 +809,10 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
         return;
     }
     dprint(d, 1, "%s\n", __FUNCTION__);
-    qxl_destroy_primary(d);
+    qxl_destroy_primary(d, QXL_SYNC);
 }
 
-static void qxl_set_irq(PCIQXLDevice *d)
+static void qxl_update_irq(PCIQXLDevice *d)
 {
     uint32_t pending = le32_to_cpu(d->ram->int_pending);
     uint32_t mask    = le32_to_cpu(d->ram->int_mask);
@@ -607,35 +821,19 @@ static void qxl_set_irq(PCIQXLDevice *d)
     qxl_ring_set_dirty(d);
 }
 
-static void qxl_write_config(PCIDevice *d, uint32_t address,
-                             uint32_t val, int len)
-{
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d);
-    VGACommonState *vga = &qxl->vga;
-
-    vga_dirty_log_stop(vga);
-    pci_default_write_config(d, address, val, len);
-    if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) {
-        vga->map_addr = 0;
-    }
-    vga_dirty_log_start(vga);
-}
-
 static void qxl_check_state(PCIQXLDevice *d)
 {
     QXLRam *ram = d->ram;
 
-    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
-    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+    assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
 }
 
 static void qxl_reset_state(PCIQXLDevice *d)
 {
-    QXLRam *ram = d->ram;
     QXLRom *rom = d->rom;
 
-    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
-    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+    qxl_check_state(d);
     d->shadow_rom.update_id = cpu_to_le32(0);
     *rom = d->shadow_rom;
     qxl_rom_set_dirty(d);
@@ -662,10 +860,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
            loadvm ? " (loadvm)" : "");
 
-    qemu_mutex_unlock_iothread();
-    d->ssd.worker->reset_cursor(d->ssd.worker);
-    d->ssd.worker->reset_image_cache(d->ssd.worker);
-    qemu_mutex_lock_iothread();
+    qxl_spice_reset_cursor(d);
+    qxl_spice_reset_image_cache(d);
     qxl_reset_surfaces(d);
     qxl_reset_memslots(d);
 
@@ -694,13 +890,28 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 
     if (qxl->mode != QXL_MODE_VGA) {
         dprint(qxl, 1, "%s\n", __FUNCTION__);
-        qxl_destroy_primary(qxl);
+        qxl_destroy_primary(qxl, QXL_SYNC);
         qxl_soft_reset(qxl);
     }
     vga_ioport_write(opaque, addr, val);
 }
 
-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+static const MemoryRegionPortio qxl_vga_portio_list[] = {
+    { 0x04,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
+
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
+                            qxl_async_io async)
 {
     static const int regions[] = {
         QXL_RAM_RANGE_INDEX,
@@ -748,10 +959,10 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
 
     switch (pci_region) {
     case QXL_RAM_RANGE_INDEX:
-        virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
         break;
     case QXL_VRAM_RANGE_INDEX:
-        virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
         break;
     default:
         /* should not happen */
@@ -766,11 +977,11 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
     memslot.generation = d->rom->slot_generation = 0;
     qxl_rom_set_dirty(d);
 
-    dprint(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+    dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n",
            __FUNCTION__, memslot.slot_id,
            memslot.virt_start, memslot.virt_end);
 
-    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
     d->guest_slots[slot_id].delta = delta;
@@ -780,14 +991,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
 static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
 {
     dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
-    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
+    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
     d->guest_slots[slot_id].active = 0;
 }
 
 static void qxl_reset_memslots(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
-    d->ssd.worker->reset_memslots(d->ssd.worker);
+    qxl_spice_reset_memslots(d);
     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
 }
 
@@ -795,10 +1006,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
     d->mode = QXL_MODE_UNDEFINED;
-    qemu_mutex_unlock_iothread();
-    d->ssd.worker->destroy_surfaces(d->ssd.worker);
-    qemu_mutex_lock_iothread();
-    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
 }
 
 /* called from spice server thread context only */
@@ -823,7 +1031,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
     }
 }
 
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
+{
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
+                                     qxl_async_io async)
 {
     QXLDevSurfaceCreate surface;
     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
@@ -851,24 +1066,27 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
 
     qxl->mode = QXL_MODE_NATIVE;
     qxl->cmdflags = 0;
-    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
 
-    /* for local rendering */
-    qxl_render_resize(qxl);
+    if (async == QXL_SYNC) {
+        qxl_create_guest_primary_complete(qxl);
+    }
 }
 
-static void qxl_destroy_primary(PCIQXLDevice *d)
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
+ * done (in QXL_SYNC case), 0 otherwise. */
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
 {
     if (d->mode == QXL_MODE_UNDEFINED) {
-        return;
+        return 0;
     }
 
     dprint(d, 1, "%s\n", __FUNCTION__);
 
     d->mode = QXL_MODE_UNDEFINED;
-    qemu_mutex_unlock_iothread();
-    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
-    qemu_mutex_lock_iothread();
+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+    qxl_spice_reset_cursor(d);
+    return 1;
 }
 
 static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
@@ -891,17 +1109,17 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
         .mem        = devmem + d->shadow_rom.draw_area_offset,
     };
 
-    dprint(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__,
-           modenr, mode->x_res, mode->y_res, mode->bits, devmem);
+    dprint(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n",
+           __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem);
     if (!loadvm) {
         qxl_hard_reset(d, 0);
     }
 
     d->guest_slots[0].slot = slot;
-    qxl_add_memslot(d, 0, devmem);
+    qxl_add_memslot(d, 0, devmem, QXL_SYNC);
 
     d->guest_primary.surface = surface;
-    qxl_create_guest_primary(d, 0);
+    qxl_create_guest_primary(d, 0, QXL_SYNC);
 
     d->mode = QXL_MODE_COMPAT;
     d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
@@ -915,10 +1133,15 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
     qxl_rom_set_dirty(d);
 }
 
-static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ioport_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
     PCIQXLDevice *d = opaque;
-    uint32_t io_port = addr - d->io_base;
+    uint32_t io_port = addr;
+    qxl_async_io async = QXL_SYNC;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    uint32_t orig_io_port = io_port;
+#endif
 
     switch (io_port) {
     case QXL_IO_RESET:
@@ -926,52 +1149,103 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case QXL_IO_MEMSLOT_ADD:
     case QXL_IO_MEMSLOT_DEL:
     case QXL_IO_CREATE_PRIMARY:
+    case QXL_IO_UPDATE_IRQ:
+    case QXL_IO_LOG:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+#endif
         break;
     default:
-        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
+        if (d->mode != QXL_MODE_VGA) {
             break;
-        dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+        }
+        dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
+            __func__, io_port, io_port_to_string(io_port));
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        /* be nice to buggy guest drivers */
+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        }
+#endif
         return;
     }
 
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    /* we change the io_port to avoid ifdeffery in the main switch */
+    orig_io_port = io_port;
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA_ASYNC:
+        io_port = QXL_IO_UPDATE_AREA;
+        goto async_common;
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+        io_port = QXL_IO_MEMSLOT_ADD;
+        goto async_common;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        io_port = QXL_IO_CREATE_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+        io_port = QXL_IO_DESTROY_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
+        goto async_common;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
+        goto async_common;
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+async_common:
+        async = QXL_ASYNC;
+        qemu_mutex_lock(&d->async_lock);
+        if (d->current_async != QXL_UNDEFINED_IO) {
+            qxl_guest_bug(d, "%d async started before last (%d) complete",
+                io_port, d->current_async);
+            qemu_mutex_unlock(&d->async_lock);
+            return;
+        }
+        d->current_async = orig_io_port;
+        qemu_mutex_unlock(&d->async_lock);
+        dprint(d, 2, "start async %d (%"PRId64")\n", io_port, val);
+        break;
+    default:
+        break;
+    }
+#endif
+
     switch (io_port) {
     case QXL_IO_UPDATE_AREA:
     {
         QXLRect update = d->ram->update_area;
-        qemu_mutex_unlock_iothread();
-        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
-                                   &update, NULL, 0, 0);
-        qemu_mutex_lock_iothread();
+        qxl_spice_update_area(d, d->ram->update_surface,
+                              &update, NULL, 0, 0, async);
         break;
     }
     case QXL_IO_NOTIFY_CMD:
-        d->ssd.worker->wakeup(d->ssd.worker);
+        qemu_spice_wakeup(&d->ssd);
         break;
     case QXL_IO_NOTIFY_CURSOR:
-        d->ssd.worker->wakeup(d->ssd.worker);
+        qemu_spice_wakeup(&d->ssd);
         break;
     case QXL_IO_UPDATE_IRQ:
-        qxl_set_irq(d);
+        qxl_update_irq(d);
         break;
     case QXL_IO_NOTIFY_OOM:
-        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
-            break;
-        }
-        pthread_yield();
         if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
             break;
         }
         d->oom_running = 1;
-        d->ssd.worker->oom(d->ssd.worker);
+        qxl_spice_oom(d);
         d->oom_running = 0;
         break;
     case QXL_IO_SET_MODE:
-        dprint(d, 1, "QXL_SET_MODE %d\n", val);
+        dprint(d, 1, "QXL_SET_MODE %d\n", (int)val);
         qxl_set_mode(d, val, 0);
         break;
     case QXL_IO_LOG:
         if (d->guestdebug) {
-            fprintf(stderr, "qxl/guest: %s", d->ram->log_buf);
+            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
+                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
         }
         break;
     case QXL_IO_RESET:
@@ -979,38 +1253,102 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         qxl_hard_reset(d, 0);
         break;
     case QXL_IO_MEMSLOT_ADD:
-        PANIC_ON(val >= NUM_MEMSLOTS);
-        PANIC_ON(d->guest_slots[val].active);
+        if (val >= NUM_MEMSLOTS) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
+            break;
+        }
+        if (d->guest_slots[val].active) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active");
+            break;
+        }
         d->guest_slots[val].slot = d->ram->mem_slot;
-        qxl_add_memslot(d, val, 0);
+        qxl_add_memslot(d, val, 0, async);
         break;
     case QXL_IO_MEMSLOT_DEL:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
+            break;
+        }
         qxl_del_memslot(d, val);
         break;
     case QXL_IO_CREATE_PRIMARY:
-        PANIC_ON(val != 0);
-        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
+        if (val != 0) {
+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
         d->guest_primary.surface = d->ram->create_surface;
-        qxl_create_guest_primary(d, 0);
+        qxl_create_guest_primary(d, 0, async);
         break;
     case QXL_IO_DESTROY_PRIMARY:
-        PANIC_ON(val != 0);
-        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n");
-        qxl_destroy_primary(d);
+        if (val != 0) {
+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
+               qxl_mode_to_string(d->mode));
+        if (!qxl_destroy_primary(d, async)) {
+            dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
+                    qxl_mode_to_string(d->mode));
+            goto cancel_async;
+        }
         break;
     case QXL_IO_DESTROY_SURFACE_WAIT:
-        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+        if (val >= NUM_SURFACES) {
+            qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
+                             "%d >= NUM_SURFACES", async, val);
+            goto cancel_async;
+        }
+        qxl_spice_destroy_surface_wait(d, val, async);
         break;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case QXL_IO_FLUSH_RELEASE: {
+        QXLReleaseRing *ring = &d->ram->release_ring;
+        if (ring->prod - ring->cons + 1 == ring->num_items) {
+            fprintf(stderr,
+                "ERROR: no flush, full release ring [p%d,%dc]\n",
+                ring->prod, ring->cons);
+        }
+        qxl_push_free_res(d, 1 /* flush */);
+        dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n",
+            qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+            d->num_free_res, d->last_release);
+        break;
+    }
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+        dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC"
+                     " (%"PRId64") (%s, s#=%d, res#=%d)\n",
+               val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+               d->num_free_res);
+        qxl_spice_flush_surfaces_async(d);
+        break;
+#endif
     case QXL_IO_DESTROY_ALL_SURFACES:
-        d->ssd.worker->destroy_surfaces(d->ssd.worker);
+        d->mode = QXL_MODE_UNDEFINED;
+        qxl_spice_destroy_surfaces(d, async);
         break;
     default:
         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
         abort();
     }
+    return;
+cancel_async:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    if (async) {
+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        qemu_mutex_lock(&d->async_lock);
+        d->current_async = QXL_UNDEFINED_IO;
+        qemu_mutex_unlock(&d->async_lock);
+    }
+#else
+    return;
+#endif
 }
 
-static uint32_t ioport_read(void *opaque, uint32_t addr)
+static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     PCIQXLDevice *d = opaque;
 
@@ -1018,42 +1356,14 @@ static uint32_t ioport_read(void *opaque, uint32_t addr)
     return 0xff;
 }
 
-static void qxl_map(PCIDevice *pci, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    static const char *names[] = {
-        [ QXL_IO_RANGE_INDEX ]   = "ioports",
-        [ QXL_RAM_RANGE_INDEX ]  = "devram",
-        [ QXL_ROM_RANGE_INDEX ]  = "rom",
-        [ QXL_VRAM_RANGE_INDEX ] = "vram",
-    };
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci);
-
-    dprint(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__,
-            region_num, names[region_num], addr, size);
-
-    switch (region_num) {
-    case QXL_IO_RANGE_INDEX:
-        register_ioport_write(addr, size, 1, ioport_write, pci);
-        register_ioport_read(addr, size, 1, ioport_read, pci);
-        qxl->io_base = addr;
-        break;
-    case QXL_RAM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM);
-        qxl->vga.map_addr = addr;
-        qxl->vga.map_end = addr + size;
-        if (qxl->id == 0) {
-            vga_dirty_log_start(&qxl->vga);
-        }
-        break;
-    case QXL_ROM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM);
-        break;
-    case QXL_VRAM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM);
-        break;
-    }
-}
+static const MemoryRegionOps qxl_io_ops = {
+    .read = ioport_read,
+    .write = ioport_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
 
 static void pipe_read(void *opaque)
 {
@@ -1064,10 +1374,9 @@ static void pipe_read(void *opaque)
     do {
         len = read(d->pipe[0], &dummy, sizeof(dummy));
     } while (len == sizeof(dummy));
-    qxl_set_irq(d);
+    qxl_update_irq(d);
 }
 
-/* called from spice server thread context only */
 static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
 {
     uint32_t old_pending;
@@ -1078,8 +1387,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
     if ((old_pending & le_events) == le_events) {
         return;
     }
-    if (pthread_self() == d->main) {
-        qxl_set_irq(d);
+    if (qemu_thread_is_self(&d->main)) {
+        qxl_update_irq(d);
     } else {
         if (write(d->pipe[1], d, 1) != 1) {
             dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
@@ -1093,15 +1402,11 @@ static void init_pipe_signaling(PCIQXLDevice *d)
        dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
        return;
    }
-#ifdef CONFIG_IOTHREAD
    fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
-#else
-   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
-#endif
    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
    fcntl(d->pipe[0], F_SETOWN, getpid());
 
-   d->main = pthread_self();
+   qemu_thread_get_self(&d->main);
    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
 }
 
@@ -1163,17 +1468,27 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
     }
 }
 
-static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+static void qxl_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
 {
     PCIQXLDevice *qxl = opaque;
-    qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
-
-    if (!running && qxl->mode == QXL_MODE_NATIVE) {
-        /* dirty all vram (which holds surfaces) to make sure it is saved */
+    qemu_spice_vm_change_state_handler(&qxl->ssd, running, state);
+
+    if (running) {
+        /*
+         * if qxl_send_events was called from spice server context before
+         * migration ended, qxl_update_irq for these events might not have been
+         * called
+         */
+         qxl_update_irq(qxl);
+    } else if (qxl->mode == QXL_MODE_NATIVE) {
+        /* dirty all vram (which holds surfaces) and devram (primary surface)
+         * to make sure they are saved */
         /* FIXME #1: should go out during "live" stage */
         /* FIXME #2: we only need to save the areas which are actually used */
-        ram_addr_t addr = qxl->vram_offset;
-        qxl_set_dirty(addr, addr + qxl->vram_size);
+        qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size);
+        qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
+                      qxl->shadow_rom.surface0_area_size);
     }
 }
 
@@ -1209,7 +1524,6 @@ static DisplayChangeListener display_listener = {
 static int qxl_init_common(PCIQXLDevice *qxl)
 {
     uint8_t* config = qxl->pci.config;
-    uint32_t pci_device_id;
     uint32_t pci_device_rev;
     uint32_t io_size;
 
@@ -1217,29 +1531,31 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     qxl->generation = 1;
     qxl->num_memslots = NUM_MEMSLOTS;
     qxl->num_surfaces = NUM_SURFACES;
+    qemu_mutex_init(&qxl->track_lock);
+    qemu_mutex_init(&qxl->async_lock);
+    qxl->current_async = QXL_UNDEFINED_IO;
 
     switch (qxl->revision) {
     case 1: /* spice 0.4 -- qxl-1 */
-        pci_device_id  = QXL_DEVICE_ID_STABLE;
         pci_device_rev = QXL_REVISION_STABLE_V04;
         break;
     case 2: /* spice 0.6 -- qxl-2 */
-        pci_device_id  = QXL_DEVICE_ID_STABLE;
         pci_device_rev = QXL_REVISION_STABLE_V06;
         break;
-    default: /* experimental */
-        pci_device_id  = QXL_DEVICE_ID_DEVEL;
-        pci_device_rev = 1;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case 3: /* qxl-3 */
+#endif
+    default:
+        pci_device_rev = QXL_DEFAULT_REVISION;
         break;
     }
 
-    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
-    pci_config_set_device_id(config, pci_device_id);
     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
 
     qxl->rom_size = qxl_rom_size();
-    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
+    memory_region_init_ram(&qxl->rom_bar, &qxl->pci.qdev, "qxl.vrom",
+                           qxl->rom_size);
     init_qxl_rom(qxl);
     init_qxl_ram(qxl);
 
@@ -1250,26 +1566,32 @@ static int qxl_init_common(PCIQXLDevice *qxl)
         qxl->vram_size = 4096;
     }
     qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
-    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
+    memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram",
+                           qxl->vram_size);
 
     io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
     if (qxl->revision == 1) {
         io_size = 8;
     }
 
+    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
+                          "qxl-ioports", io_size);
+    if (qxl->id == 0) {
+        vga_dirty_log_start(&qxl->vga);
+    }
+
+
     pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
-                     io_size, PCI_BASE_ADDRESS_SPACE_IO, qxl_map);
+                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
 
     pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
-                     qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     qxl_map);
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
 
     pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
-                     qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     qxl_map);
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
 
-    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar);
 
     qxl->ssd.qxl.base.sif = &qxl_interface.base;
     qxl->ssd.qxl.id = qxl->id;
@@ -1287,6 +1609,7 @@ static int qxl_init_primary(PCIDevice *dev)
     PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
     VGACommonState *vga = &qxl->vga;
     ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+    PortioList *qxl_vga_port_list = g_new(PortioList, 1);
 
     qxl->id = 0;
 
@@ -1294,23 +1617,17 @@ static int qxl_init_primary(PCIDevice *dev)
         ram_size = 32 * 1024 * 1024;
     }
     vga_common_init(vga, ram_size);
-    vga_init(vga);
-    register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga);
-    register_ioport_write(0x3b4,  2, 1, qxl_vga_ioport_write, vga);
-    register_ioport_write(0x3d4,  2, 1, qxl_vga_ioport_write, vga);
-    register_ioport_write(0x3ba,  1, 1, qxl_vga_ioport_write, vga);
-    register_ioport_write(0x3da,  1, 1, qxl_vga_ioport_write, vga);
+    vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
+    portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
+    portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
 
     vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
                                    qxl_hw_screen_dump, qxl_hw_text_update, qxl);
-    qxl->ssd.ds = vga->ds;
-    qxl->ssd.bufsize = (16 * 1024 * 1024);
-    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
+    qemu_spice_display_init_common(&qxl->ssd, vga->ds);
 
     qxl0 = qxl;
     register_displaychangelistener(vga->ds, &display_listener);
 
-    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_VGA);
     return qxl_init_common(qxl);
 }
 
@@ -1326,11 +1643,10 @@ static int qxl_init_secondary(PCIDevice *dev)
         ram_size = 16 * 1024 * 1024;
     }
     qxl->vga.vram_size = ram_size;
-    qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
-                                          qxl->vga.vram_size);
-    qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
+    memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram",
+                           qxl->vga.vram_size);
+    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
 
-    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_OTHER);
     return qxl_init_common(qxl);
 }
 
@@ -1359,12 +1675,25 @@ static int qxl_pre_load(void *opaque)
     return 0;
 }
 
+static void qxl_create_memslots(PCIQXLDevice *d)
+{
+    int i;
+
+    for (i = 0; i < NUM_MEMSLOTS; i++) {
+        if (!d->guest_slots[i].active) {
+            continue;
+        }
+        dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i);
+        qxl_add_memslot(d, i, 0, QXL_SYNC);
+    }
+}
+
 static int qxl_post_load(void *opaque, int version)
 {
     PCIQXLDevice* d = opaque;
     uint8_t *ram_start = d->vga.vram_ptr;
     QXLCommandExt *cmds;
-    int in, out, i, newmode;
+    int in, out, newmode;
 
     dprint(d, 1, "%s: start\n", __FUNCTION__);
 
@@ -1377,26 +1706,24 @@ static int qxl_post_load(void *opaque, int version)
 
     d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
 
-    dprint(d, 1, "%s: restore mode\n", __FUNCTION__);
+    dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__,
+        qxl_mode_to_string(d->mode));
     newmode = d->mode;
     d->mode = QXL_MODE_UNDEFINED;
+
     switch (newmode) {
     case QXL_MODE_UNDEFINED:
         break;
     case QXL_MODE_VGA:
+        qxl_create_memslots(d);
         qxl_enter_vga_mode(d);
         break;
     case QXL_MODE_NATIVE:
-        for (i = 0; i < NUM_MEMSLOTS; i++) {
-            if (!d->guest_slots[i].active) {
-                continue;
-            }
-            qxl_add_memslot(d, i, 0);
-        }
-        qxl_create_guest_primary(d, 1);
+        qxl_create_memslots(d);
+        qxl_create_guest_primary(d, 1, QXL_SYNC);
 
         /* replay surface-create and cursor-set commands */
-        cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
+        cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
         for (in = 0, out = 0; in < NUM_SURFACES; in++) {
             if (d->guest_surfaces.cmds[in] == 0) {
                 continue;
@@ -1406,15 +1733,19 @@ static int qxl_post_load(void *opaque, int version)
             cmds[out].group_id = MEMSLOT_GROUP_GUEST;
             out++;
         }
-        cmds[out].cmd.data = d->guest_cursor;
-        cmds[out].cmd.type = QXL_CMD_CURSOR;
-        cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-        out++;
-        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
-        qemu_free(cmds);
+        if (d->guest_cursor) {
+            cmds[out].cmd.data = d->guest_cursor;
+            cmds[out].cmd.type = QXL_CMD_CURSOR;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        qxl_spice_loadvm_commands(d, cmds, out);
+        g_free(cmds);
 
         break;
     case QXL_MODE_COMPAT:
+        /* note: no need to call qxl_create_memslots, qxl_set_mode
+         * creates the mem slot. */
         qxl_set_mode(d, d->shadow_rom.mode, 1);
         break;
     }
@@ -1483,6 +1814,19 @@ static VMStateDescription qxl_vmstate = {
     },
 };
 
+static Property qxl_properties[] = {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
 static PCIDeviceInfo qxl_info_primary = {
     .qdev.name    = "qxl-vga",
     .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
@@ -1491,17 +1835,11 @@ static PCIDeviceInfo qxl_info_primary = {
     .qdev.vmsd    = &qxl_vmstate,
     .no_hotplug   = 1,
     .init         = qxl_init_primary,
-    .config_write = qxl_write_config,
     .romfile      = "vgabios-qxl.bin",
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .device_id    = QXL_DEVICE_ID_STABLE,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+    .qdev.props   = qxl_properties,
 };
 
 static PCIDeviceInfo qxl_info_secondary = {
@@ -1511,15 +1849,10 @@ static PCIDeviceInfo qxl_info_secondary = {
     .qdev.reset   = qxl_reset_handler,
     .qdev.vmsd    = &qxl_vmstate,
     .init         = qxl_init_secondary,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .device_id    = QXL_DEVICE_ID_STABLE,
+    .class_id     = PCI_CLASS_DISPLAY_OTHER,
+    .qdev.props   = qxl_properties,
 };
 
 static void qxl_register(void)
index f6c450d32d6c4f2c0983301a740dbd913deb00aa..766aa6d68ea9644c37cce7073455645a6db063b9 100644 (file)
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -4,6 +4,7 @@
 #include "hw.h"
 #include "pci.h"
 #include "vga_int.h"
+#include "qemu-thread.h"
 
 #include "ui/qemu-spice.h"
 #include "ui/spice-display.h"
@@ -15,6 +16,8 @@ enum qxl_mode {
     QXL_MODE_NATIVE,
 };
 
+#define QXL_UNDEFINED_IO UINT32_MAX
+
 typedef struct PCIQXLDevice {
     PCIDevice          pci;
     SimpleSpiceDisplay ssd;
@@ -30,6 +33,9 @@ typedef struct PCIQXLDevice {
     int32_t            num_memslots;
     int32_t            num_surfaces;
 
+    uint32_t           current_async;
+    QemuMutex          async_lock;
+
     struct guest_slots {
         QXLMemSlot     slot;
         void           *ptr;
@@ -42,7 +48,8 @@ typedef struct PCIQXLDevice {
         QXLSurfaceCreate surface;
         uint32_t       commands;
         uint32_t       resized;
-        int32_t        stride;
+        int32_t        qxl_stride;
+        uint32_t       abs_stride;
         uint32_t       bits_pp;
         uint32_t       bytes_pp;
         uint8_t        *data, *flipped;
@@ -55,8 +62,10 @@ typedef struct PCIQXLDevice {
     } guest_surfaces;
     QXLPHYSICAL        guest_cursor;
 
+    QemuMutex          track_lock;
+
     /* thread signaling */
-    pthread_t          main;
+    QemuThread         main;
     int                pipe[2];
 
     /* ram pci bar */
@@ -72,19 +81,19 @@ typedef struct PCIQXLDevice {
     QXLRom             *rom;
     QXLModes           *modes;
     uint32_t           rom_size;
-    uint64_t           rom_offset;
+    MemoryRegion       rom_bar;
 
     /* vram pci bar */
     uint32_t           vram_size;
-    uint64_t           vram_offset;
+    MemoryRegion       vram_bar;
 
     /* io bar */
-    uint32_t           io_base;
+    MemoryRegion       io_bar;
 } PCIQXLDevice;
 
 #define PANIC_ON(x) if ((x)) {                         \
     printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
-    exit(-1);                                          \
+    abort();                                           \
 }
 
 #define dprint(_qxl, _level, _fmt, ...)                                 \
@@ -95,8 +104,27 @@ typedef struct PCIQXLDevice {
         }                                                               \
     } while (0)
 
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
+#else
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06
+#endif
+
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async);
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count);
+void qxl_spice_oom(PCIQXLDevice *qxl);
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
 
 /* qxl-logger.c */
 void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
@@ -106,3 +134,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
 void qxl_render_resize(PCIQXLDevice *qxl);
 void qxl_render_update(PCIQXLDevice *qxl);
 void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
+                                 struct QXLRect *area,
+                                 uint32_t clear_dirty_region,
+                                 int is_vga);
+#endif
index a0f8c1f201655b808be8aca672711b58e06c1a84..b65fd427b79bb47ea4c8a83e145d52bcb33b6fd2 100644 (file)
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -37,6 +37,7 @@
 #include "usb.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define FLASH_BASE 0x00000000
 #define FLASH_SIZE 0x02000000
@@ -81,6 +82,7 @@ typedef struct {
 
 /* output pin */
     qemu_irq irl;
+    MemoryRegion iomem;
 } r2d_fpga_t;
 
 enum r2d_fpga_irq {
@@ -167,31 +169,25 @@ r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const r2d_fpga_readfn[] = {
-    r2d_fpga_read,
-    r2d_fpga_read,
-    NULL,
+static const MemoryRegionOps r2d_fpga_ops = {
+    .old_mmio = {
+        .read = { r2d_fpga_read, r2d_fpga_read, NULL, },
+        .write = { r2d_fpga_write, r2d_fpga_write, NULL, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const r2d_fpga_writefn[] = {
-    r2d_fpga_write,
-    r2d_fpga_write,
-    NULL,
-};
-
-static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
+static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
+                               target_phys_addr_t base, qemu_irq irl)
 {
-    int iomemtype;
     r2d_fpga_t *s;
 
-    s = qemu_mallocz(sizeof(r2d_fpga_t));
+    s = g_malloc0(sizeof(r2d_fpga_t));
 
     s->irl = irl;
 
-    iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
-                                      r2d_fpga_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x40, iomemtype);
+    memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
     return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
 }
 
@@ -209,7 +205,7 @@ static void main_cpu_reset(void *opaque)
     env->pc = s->vector;
 }
 
-static struct __attribute__((__packed__))
+static struct QEMU_PACKED
 {
     int mount_root_rdonly;
     int ramdisk_flags;
@@ -231,10 +227,11 @@ static void r2d_init(ram_addr_t ram_size,
     CPUState *env;
     ResetData *reset_info;
     struct SH7750State *s;
-    ram_addr_t sdram_addr;
+    MemoryRegion *sdram = g_new(MemoryRegion, 1);
     qemu_irq *irq;
     DriveInfo *dinfo;
     int i;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     if (!cpu_model)
         cpu_model = "SH7751R";
@@ -244,21 +241,22 @@ static void r2d_init(ram_addr_t ram_size,
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info = g_malloc0(sizeof(ResetData));
     reset_info->env = env;
     reset_info->vector = env->pc;
     qemu_register_reset(main_cpu_reset, reset_info);
 
     /* Allocate memory space */
-    sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE);
-    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
+    memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE);
+    memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
     /* Register peripherals */
     s = sh7750_init(env);
-    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
+    irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
     sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
                           irq[PCI_INTC], irq[PCI_INTD], NULL);
 
-    sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
+    sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
+               irq[SM501], serial_hds[2]);
 
     /* onboard CF (True IDE mode, Master only). */
     dinfo = drive_get(IF_IDE, 0, 0);
@@ -267,7 +265,7 @@ static void r2d_init(ram_addr_t ram_size,
 
     /* onboard flash memory */
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi02_register(0x0, qemu_ram_alloc(NULL, "r2d.flash", FLASH_SIZE),
+    pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (16 * 1024),
                           FLASH_SIZE >> 16,
                           1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
index 0a9d98d1d529e0e31737e421fdd98427190014d7..33e10709c6f3433e096c65850ee21c02afaa48c8 100644 (file)
@@ -50,7 +50,7 @@ do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } whi
 typedef struct dma_pagetable_entry {
     int32_t frame;
     int32_t owner;
-} __attribute__((packed)) dma_pagetable_entry;
+} QEMU_PACKED dma_pagetable_entry;
 
 #define DMA_PAGESIZE    4096
 #define DMA_REG_ENABLE  1
@@ -104,7 +104,7 @@ static void set_next_tick(rc4030State *s)
 
     tm_hz = 1000 / (s->itr + 1);
 
-    qemu_mod_timer(s->periodic_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(s->periodic_timer, qemu_get_clock_ns(vm_clock) +
                    get_ticks_per_sec() / tm_hz);
 }
 
@@ -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));
@@ -789,8 +789,8 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
     struct rc4030DMAState *p;
     int i;
 
-    s = (rc4030_dma *)qemu_mallocz(sizeof(rc4030_dma) * n);
-    p = (struct rc4030DMAState *)qemu_mallocz(sizeof(struct rc4030DMAState) * n);
+    s = (rc4030_dma *)g_malloc0(sizeof(rc4030_dma) * n);
+    p = (struct rc4030DMAState *)g_malloc0(sizeof(struct rc4030DMAState) * n);
     for (i = 0; i < n; i++) {
         p->opaque = opaque;
         p->n = i;
@@ -806,12 +806,12 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
     rc4030State *s;
     int s_chipset, s_jazzio;
 
-    s = qemu_mallocz(sizeof(rc4030State));
+    s = g_malloc0(sizeof(rc4030State));
 
     *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
     *dmas = rc4030_allocate_dmas(s, 4);
 
-    s->periodic_timer = qemu_new_timer(vm_clock, rc4030_periodic_timer, s);
+    s->periodic_timer = qemu_new_timer_ns(vm_clock, rc4030_periodic_timer, s);
     s->timer_irq = timer;
     s->jazz_bus_irq = jazz_bus;
 
index 6eb6c6a1f103d28a781e7eb654d3d3aef56ffa30..9a8e63c8f5b1209fdcc2df3a92ae6ffaad989969 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
 #include "sysemu.h"
 #include "boards.h"
 #include "bitbang_i2c.h"
-#include "sysbus.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     bitbang_i2c_interface *bitbang;
     int out;
     int in;
 } RealViewI2CState;
 
-static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset)
+static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
 {
     RealViewI2CState *s = (RealViewI2CState *)opaque;
 
@@ -42,7 +44,7 @@ static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
-                               uint32_t value)
+                               uint64_t value, unsigned size)
 {
     RealViewI2CState *s = (RealViewI2CState *)opaque;
 
@@ -60,30 +62,22 @@ static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
     s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
 }
 
-static CPUReadMemoryFunc * const realview_i2c_readfn[] = {
-   realview_i2c_read,
-   realview_i2c_read,
-   realview_i2c_read
-};
-
-static CPUWriteMemoryFunc * const realview_i2c_writefn[] = {
-   realview_i2c_write,
-   realview_i2c_write,
-   realview_i2c_write
+static const MemoryRegionOps realview_i2c_ops = {
+    .read = realview_i2c_read,
+    .write = realview_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int realview_i2c_init(SysBusDevice *dev)
 {
     RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
     i2c_bus *bus;
-    int iomemtype;
 
     bus = i2c_init_bus(&dev->qdev, "i2c");
     s->bitbang = bitbang_i2c_init(bus);
-    iomemtype = cpu_register_io_memory(realview_i2c_readfn,
-                                       realview_i2c_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &realview_i2c_ops, s,
+                          "realview-i2c", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -104,17 +98,6 @@ static struct arm_boot_info realview_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
 };
 
-static void secondary_cpu_reset(void *opaque)
-{
-  CPUState *env = opaque;
-
-  cpu_reset(env);
-  /* Set entry point for secondary CPUs.  This assumes we're using
-     the init code from arm_boot.c.  Real hardware resets all CPUs
-     the same.  */
-  env->regs[15] = SMP_BOOT_ADDR;
-}
-
 /* The following two lists must be consistent.  */
 enum realview_board_type {
     BOARD_EB,
@@ -137,11 +120,16 @@ static void realview_init(ram_addr_t ram_size,
                      enum realview_board_type board_type)
 {
     CPUState *env = NULL;
-    ram_addr_t ram_offset;
-    DeviceState *dev;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
+    DeviceState *dev, *sysctl, *gpio2, *pl041;
     SysBusDevice *busdev;
     qemu_irq *irqp;
     qemu_irq pic[64];
+    qemu_irq mmc_irq[2];
     PCIBus *pci_bus;
     NICInfo *nd;
     i2c_bus *i2c;
@@ -176,9 +164,6 @@ static void realview_init(ram_addr_t ram_size,
         }
         irqp = arm_pic_init_cpu(env);
         cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
-        if (n > 0) {
-            qemu_register_reset(secondary_cpu_reset, env);
-        }
     }
     if (arm_feature(env, ARM_FEATURE_V7)) {
         if (is_mpcore) {
@@ -198,27 +183,31 @@ static void realview_init(ram_addr_t ram_size,
         /* Core tile RAM.  */
         low_ram_size = ram_size - 0x20000000;
         ram_size = 0x20000000;
-        ram_offset = qemu_ram_alloc(NULL, "realview.lowmem", low_ram_size);
-        cpu_register_physical_memory(0x20000000, low_ram_size,
-                                     ram_offset | IO_MEM_RAM);
+        memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size);
+        memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "realview.highmem", ram_size);
+    memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size);
     low_ram_size = ram_size;
     if (low_ram_size > 0x10000000)
       low_ram_size = 0x10000000;
     /* SDRAM at address zero.  */
-    cpu_register_physical_memory(0, low_ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_alias(ram_alias, "realview.alias",
+                             ram_hi, 0, low_ram_size);
+    memory_region_add_subregion(sysmem, 0, ram_alias);
     if (is_pb) {
         /* And again at a high address.  */
-        cpu_register_physical_memory(0x70000000, ram_size,
-                                     ram_offset | IO_MEM_RAM);
+        memory_region_add_subregion(sysmem, 0x70000000, ram_hi);
     } else {
         ram_size = low_ram_size;
     }
 
     sys_id = is_pb ? 0x01780500 : 0xc1400400;
-    arm_sysctl_init(0x10000000, sys_id, proc_id);
+    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);
 
     if (is_mpcore) {
         dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
@@ -243,6 +232,12 @@ static void realview_init(ram_addr_t ram_size,
         pic[n] = qdev_get_gpio_in(dev, n);
     }
 
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[19]);
+
     sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
     sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
 
@@ -257,15 +252,41 @@ static void realview_init(ram_addr_t ram_size,
     sysbus_create_simple("sp804", 0x10011000, pic[4]);
     sysbus_create_simple("sp804", 0x10012000, pic[5]);
 
-    sysbus_create_simple("pl110_versatile", 0x10020000, pic[23]);
-
-    sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
+    sysbus_create_simple("pl061", 0x10013000, pic[6]);
+    sysbus_create_simple("pl061", 0x10014000, pic[7]);
+    gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]);
+
+    sysbus_create_simple("pl111", 0x10020000, pic[23]);
+
+    dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
+    /* Wire up MMC card detect and read-only signals. These have
+     * to go to both the PL061 GPIO and the sysctl register.
+     * Note that the PL181 orders these lines (readonly,inserted)
+     * and the PL061 has them the other way about. Also the card
+     * detect line is inverted.
+     */
+    mmc_irq[0] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT),
+        qdev_get_gpio_in(gpio2, 1));
+    mmc_irq[1] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
+        qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
+    qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
+    qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
 
     sysbus_create_simple("pl031", 0x10017000, pic[10]);
 
     if (!is_pb) {
-        dev = sysbus_create_varargs("realview_pci", 0x60000000,
-                                    pic[48], pic[49], pic[50], pic[51], NULL);
+        dev = qdev_create(NULL, "realview_pci");
+        busdev = sysbus_from_qdev(dev);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */
+        sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */
+        sysbus_mmio_map(busdev, 2, 0x63000000); /* PCI I/O */
+        sysbus_connect_irq(busdev, 0, pic[48]);
+        sysbus_connect_irq(busdev, 1, pic[49]);
+        sysbus_connect_irq(busdev, 2, pic[50]);
+        sysbus_connect_irq(busdev, 3, pic[51]);
         pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
         if (usb_enabled) {
             usb_ohci_init_pci(pci_bus, -1);
@@ -279,8 +300,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 {
@@ -356,9 +377,8 @@ static void realview_init(ram_addr_t ram_size,
        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, "realview.hack", 0x1000);
-    cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
-                                 ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000);
+    memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
 
     realview_binfo.ram_size = ram_size;
     realview_binfo.kernel_filename = kernel_filename;
index db908b64399851083f456b395b94358eb89425e4..cd6a44d9d0a4506494ca2fa38a32c79bb6605509 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -23,39 +23,37 @@ gic_get_current_cpu(void)
 
 typedef struct {
     gic_state gic;
-    int iomemtype;
+    MemoryRegion iomem;
+    MemoryRegion container;
 } RealViewGICState;
 
-static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset)
+static uint64_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset,
+                                      unsigned size)
 {
     gic_state *s = (gic_state *)opaque;
     return gic_cpu_read(s, gic_get_current_cpu(), offset);
 }
 
 static void realview_gic_cpu_write(void *opaque, target_phys_addr_t offset,
-                          uint32_t value)
+                                   uint64_t value, unsigned size)
 {
     gic_state *s = (gic_state *)opaque;
     gic_cpu_write(s, gic_get_current_cpu(), offset, value);
 }
 
-static CPUReadMemoryFunc * const realview_gic_cpu_readfn[] = {
-   realview_gic_cpu_read,
-   realview_gic_cpu_read,
-   realview_gic_cpu_read
+static const MemoryRegionOps realview_gic_cpu_ops = {
+    .read = realview_gic_cpu_read,
+    .write = realview_gic_cpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const realview_gic_cpu_writefn[] = {
-   realview_gic_cpu_write,
-   realview_gic_cpu_write,
-   realview_gic_cpu_write
-};
-
-static void realview_gic_map(SysBusDevice *dev, target_phys_addr_t base)
+static void realview_gic_map_setup(RealViewGICState *s)
 {
-    RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
-    cpu_register_physical_memory(base, 0x1000, s->iomemtype);
-    cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+    memory_region_init(&s->container, "realview-gic-container", 0x2000);
+    memory_region_init_io(&s->iomem, &realview_gic_cpu_ops, &s->gic,
+                          "realview-gic", 0x1000);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
 }
 
 static int realview_gic_init(SysBusDevice *dev)
@@ -63,10 +61,8 @@ static int realview_gic_init(SysBusDevice *dev)
     RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
 
     gic_init(&s->gic);
-    s->iomemtype = cpu_register_io_memory(realview_gic_cpu_readfn,
-                                          realview_gic_cpu_writefn, s,
-                                          DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map);
+    realview_gic_map_setup(s);
+    sysbus_init_mmio_region(dev, &s->container);
     return 0;
 }
 
index a22530cf89f09826d1b4d1aa010357647b473d8e..aa8ed0a919d8ef7ab3a0ce6e647fff0366d6413e 100644 (file)
  *  2010-Feb-04  Frediano Ziglio:   Rewrote timer support using QEMU timer only
  *                                  when strictly needed (required for for
  *                                  Darwin)
+ *  2011-Mar-22  Benjamin Poirier:  Implemented VLAN offloading
  */
 
+/* For crc32 */
+#include <zlib.h>
+
 #include "hw.h"
 #include "pci.h"
+#include "dma.h"
 #include "qemu-timer.h"
 #include "net.h"
 #include "loader.h"
 #include "sysemu.h"
+#include "iov.h"
 
 /* debug RTL8139 card */
 //#define DEBUG_RTL8139 1
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
-/* Calculate CRCs properly on Rx packets */
-#define RTL8139_CALCULATE_RXCRC 1
-
-#if defined(RTL8139_CALCULATE_RXCRC)
-/* For crc32 */
-#include <zlib.h>
-#endif
-
 #define SET_MASKED(input, mask, curr) \
     ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
 
 #define MOD2(input, size) \
     ( ( input ) & ( size - 1 )  )
 
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETH_P_IP    0x0800      /* Internet Protocol packet */
+#define ETH_P_8021Q 0x8100      /* 802.1Q VLAN Extended Header  */
+#define ETH_MTU     1500
+
+#define VLAN_TCI_LEN 2
+#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. */
@@ -416,9 +428,6 @@ typedef struct RTL8139TallyCounters
 /* Clears all tally counters */
 static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
 
-/* Writes tally counters to specified physical memory address */
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters);
-
 typedef struct RTL8139State {
     PCIDevice dev;
     uint8_t phys[8]; /* mac address */
@@ -463,7 +472,6 @@ typedef struct RTL8139State {
 
     NICState *nic;
     NICConf conf;
-    int rtl8139_mmio_io_addr;
 
     /* C ring mode */
     uint32_t   currTxDesc;
@@ -495,15 +503,21 @@ typedef struct RTL8139State {
     QEMUTimer *timer;
     int64_t TimerExpire;
 
+    MemoryRegion bar_io;
+    MemoryRegion bar_mem;
+
     /* Support migration to/from old versions */
     int rtl8139_mmio_io_addr_dummy;
 } RTL8139State;
 
+/* Writes tally counters to memory via DMA */
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
+
 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)
     {
@@ -514,8 +528,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;
 
@@ -525,8 +539,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:
@@ -534,13 +548,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;
@@ -553,7 +567,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)
     {
@@ -563,7 +578,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;
 
@@ -588,7 +603,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;
@@ -596,8 +611,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;
@@ -606,8 +621,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 */
@@ -625,8 +640,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;
@@ -659,8 +673,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)
     {
@@ -670,12 +684,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;
     }
 
@@ -691,8 +705,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));
 }
@@ -756,19 +770,19 @@ 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)
             {
-                cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
-                                           buf, size-wrapped );
+                pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+                              buf, size-wrapped);
             }
 
             /* reset buffer pointer */
             s->RxBufAddr = 0;
 
-            cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
-                                       buf + (size-wrapped), wrapped );
+            pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+                          buf + (size-wrapped), wrapped);
 
             s->RxBufAddr = wrapped;
 
@@ -777,13 +791,13 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
     }
 
     /* non-wrapping path or overwrapping enabled */
-    cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size );
+    pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size);
 
     s->RxBufAddr += size;
 }
 
 #define MIN_BUF_SIZE 60
-static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
+static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
 {
 #if TARGET_PHYS_ADDR_BITS > 32
     return low | ((target_phys_addr_t)high << 32);
@@ -817,20 +831,22 @@ static int rtl8139_can_receive(VLANClientState *nc)
 static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
 {
     RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    /* size is the length of the buffer passed to the driver */
     int size = size_;
+    const uint8_t *dot1q_buf = NULL;
 
     uint32_t packet_header = 0;
 
-    uint8_t buf1[60];
+    uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
     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;
     }
 
@@ -838,21 +854,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;
@@ -862,7 +878,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;
@@ -871,7 +887,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;
@@ -883,7 +899,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;
@@ -893,7 +909,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;
@@ -907,7 +923,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;
@@ -917,14 +933,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;
@@ -933,17 +949,20 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         }
     }
 
-    /* if too small buffer, then expand it */
-    if (size < MIN_BUF_SIZE) {
+    /* if too small buffer, then expand it
+     * Include some tailroom in case a vlan tag is later removed. */
+    if (size < MIN_BUF_SIZE + VLAN_HLEN) {
         memcpy(buf1, buf, size);
-        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
         buf = buf1;
-        size = MIN_BUF_SIZE;
+        if (size < MIN_BUF_SIZE) {
+            size = MIN_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 */
 
@@ -961,32 +980,33 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 /* w3 high 32bit of Rx buffer ptr */
 
         int descriptor = s->currCPlusRxDesc;
-        target_phys_addr_t cplus_rx_ring_desc;
+        dma_addr_t cplus_rx_ring_desc;
 
         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 = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
+            s->RxRingAddrLO, cplus_rx_ring_desc);
 
         uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
 
-        cpu_physical_memory_read(cplus_rx_ring_desc,    (uint8_t *)&val, 4);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
         rxdw0 = le32_to_cpu(val);
-        cpu_physical_memory_read(cplus_rx_ring_desc+4,  (uint8_t *)&val, 4);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
         rxdw1 = le32_to_cpu(val);
-        cpu_physical_memory_read(cplus_rx_ring_desc+8,  (uint8_t *)&val, 4);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc+8, (uint8_t *)&val, 4);
         rxbufLO = le32_to_cpu(val);
-        cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
+        pci_dma_read(&s->dev, 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;
@@ -1001,12 +1021,34 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
 
+        /* write VLAN info to descriptor variables. */
+        if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
+                &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
+            dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
+            size -= VLAN_HLEN;
+            /* if too small buffer, use the tailroom added duing expansion */
+            if (size < MIN_BUF_SIZE) {
+                size = MIN_BUF_SIZE;
+            }
+
+            rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
+            /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+            rxdw1 |= CP_RX_TAVA | le16_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;
+        }
+
         /* TODO: scatter the packet over available receive ring descriptors space */
 
         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;
@@ -1019,10 +1061,17 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
             return size_;
         }
 
-        target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
+        dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
         /* receive/copy to target memory */
-        cpu_physical_memory_write( rx_addr, buf, size );
+        if (dot1q_buf) {
+            pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN);
+            pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN,
+                          buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
+                          size - 2 * ETHER_ADDR_LEN);
+        } else {
+            pci_dma_write(&s->dev, rx_addr, buf, size);
+        }
 
         if (s->CpCmd & CPlusRxChkSum)
         {
@@ -1030,12 +1079,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         }
 
         /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
-        val = cpu_to_le32(crc32(0, buf, size));
-#else
-        val = 0;
-#endif
-        cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4);
+        val = cpu_to_le32(crc32(0, buf, size_));
+        pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4);
 
 /* first segment of received packet flag */
 #define CP_RX_STATUS_FS (1<<29)
@@ -1079,14 +1124,11 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
         rxdw0 |= (size+4);
 
-        /* reset VLAN tag flag */
-        rxdw1 &= ~CP_RX_TAVA;
-
         /* update ring data */
         val = cpu_to_le32(rxdw0);
-        cpu_physical_memory_write(cplus_rx_ring_desc,    (uint8_t *)&val, 4);
+        pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
         val = cpu_to_le32(rxdw1);
-        cpu_physical_memory_write(cplus_rx_ring_desc+4,  (uint8_t *)&val, 4);
+        pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
 
         /* update tally counter */
         ++s->tally_counters.RxOk;
@@ -1101,12 +1143,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);
@@ -1115,8 +1157,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;
@@ -1136,12 +1179,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         rtl8139_write_buffer(s, buf, size);
 
         /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
         val = cpu_to_le32(crc32(0, buf, size));
-#else
-        val = 0;
-#endif
-
         rtl8139_write_buffer(s, (uint8_t *)&val, 4);
 
         /* correct buffer write pointer */
@@ -1149,8 +1187,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;
@@ -1189,18 +1227,6 @@ static void rtl8139_reset(DeviceState *d)
 
     rtl8139_update_irq(s);
 
-    /* prepare eeprom */
-    s->eeprom.contents[0] = 0x8129;
-#if 1
-    // PCI vendor and device ID should be mirrored here
-    s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
-    s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
-#endif
-
-    s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
-    s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
-    s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
-
     /* mark all status registers as owned by host */
     for (i = 0; i < 4; ++i)
     {
@@ -1282,50 +1308,51 @@ static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
     counters->TxUndrn = 0;
 }
 
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters)
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
 {
+    RTL8139TallyCounters *tally_counters = &s->tally_counters;
     uint16_t val16;
     uint32_t val32;
     uint64_t val64;
 
     val64 = cpu_to_le64(tally_counters->TxOk);
-    cpu_physical_memory_write(tc_addr + 0,    (uint8_t *)&val64, 8);
+    pci_dma_write(&s->dev, tc_addr + 0,     (uint8_t *)&val64, 8);
 
     val64 = cpu_to_le64(tally_counters->RxOk);
-    cpu_physical_memory_write(tc_addr + 8,    (uint8_t *)&val64, 8);
+    pci_dma_write(&s->dev, tc_addr + 8,     (uint8_t *)&val64, 8);
 
     val64 = cpu_to_le64(tally_counters->TxERR);
-    cpu_physical_memory_write(tc_addr + 16,    (uint8_t *)&val64, 8);
+    pci_dma_write(&s->dev, tc_addr + 16,    (uint8_t *)&val64, 8);
 
     val32 = cpu_to_le32(tally_counters->RxERR);
-    cpu_physical_memory_write(tc_addr + 24,    (uint8_t *)&val32, 4);
+    pci_dma_write(&s->dev, tc_addr + 24,    (uint8_t *)&val32, 4);
 
     val16 = cpu_to_le16(tally_counters->MissPkt);
-    cpu_physical_memory_write(tc_addr + 28,    (uint8_t *)&val16, 2);
+    pci_dma_write(&s->dev, tc_addr + 28,    (uint8_t *)&val16, 2);
 
     val16 = cpu_to_le16(tally_counters->FAE);
-    cpu_physical_memory_write(tc_addr + 30,    (uint8_t *)&val16, 2);
+    pci_dma_write(&s->dev, tc_addr + 30,    (uint8_t *)&val16, 2);
 
     val32 = cpu_to_le32(tally_counters->Tx1Col);
-    cpu_physical_memory_write(tc_addr + 32,    (uint8_t *)&val32, 4);
+    pci_dma_write(&s->dev, tc_addr + 32,    (uint8_t *)&val32, 4);
 
     val32 = cpu_to_le32(tally_counters->TxMCol);
-    cpu_physical_memory_write(tc_addr + 36,    (uint8_t *)&val32, 4);
+    pci_dma_write(&s->dev, tc_addr + 36,    (uint8_t *)&val32, 4);
 
     val64 = cpu_to_le64(tally_counters->RxOkPhy);
-    cpu_physical_memory_write(tc_addr + 40,    (uint8_t *)&val64, 8);
+    pci_dma_write(&s->dev, tc_addr + 40,    (uint8_t *)&val64, 8);
 
     val64 = cpu_to_le64(tally_counters->RxOkBrd);
-    cpu_physical_memory_write(tc_addr + 48,    (uint8_t *)&val64, 8);
+    pci_dma_write(&s->dev, tc_addr + 48,    (uint8_t *)&val64, 8);
 
     val32 = cpu_to_le32(tally_counters->RxOkMul);
-    cpu_physical_memory_write(tc_addr + 56,    (uint8_t *)&val32, 4);
+    pci_dma_write(&s->dev, tc_addr + 56,    (uint8_t *)&val32, 4);
 
     val16 = cpu_to_le16(tally_counters->TxAbt);
-    cpu_physical_memory_write(tc_addr + 60,    (uint8_t *)&val16, 2);
+    pci_dma_write(&s->dev, tc_addr + 60,    (uint8_t *)&val16, 2);
 
     val16 = cpu_to_le16(tally_counters->TxUndrn);
-    cpu_physical_memory_write(tc_addr + 62,    (uint8_t *)&val16, 2);
+    pci_dma_write(&s->dev, tc_addr + 62,    (uint8_t *)&val16, 2);
 }
 
 /* Loads values of tally counters from VM state file */
@@ -1356,27 +1383,27 @@ 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;
     }
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xe3, s->bChipCmdState);
 
     /* Deassert reset pin before next read */
@@ -1391,11 +1418,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;
 }
@@ -1407,7 +1434,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;
 }
@@ -1416,11 +1443,11 @@ 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;
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xff84, s->CpCmd);
 
     s->CpCmd = val;
@@ -1430,33 +1457,33 @@ 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;
 }
 
-static int rtl8139_config_writeable(RTL8139State *s)
+static int rtl8139_config_writable(RTL8139State *s)
 {
     if (s->Cfg9346 & Cfg9346_Unlock)
     {
         return 1;
     }
 
-    DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n"));
+    DPRINTF("Configuration registers are write-protected\n");
 
     return 0;
 }
@@ -1465,12 +1492,12 @@ 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 */
+    /* mask unwritable bits */
     uint32_t mask = 0x4cff;
 
-    if (1 || !rtl8139_config_writeable(s))
+    if (1 || !rtl8139_config_writable(s))
     {
         /* Speed setting and autonegotiation enable bits are read-only */
         mask |= 0x3000;
@@ -1487,7 +1514,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;
 }
@@ -1496,9 +1523,9 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
 
     s->BasicModeStatus = val;
@@ -1508,7 +1535,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;
 }
@@ -1517,9 +1544,9 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0x31, s->Cfg9346);
 
     uint32_t opmode = val & 0xc0;
@@ -1560,7 +1587,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;
 }
@@ -1569,12 +1596,13 @@ 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))
+    if (!rtl8139_config_writable(s)) {
         return;
+    }
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xf8, s->Config0);
 
     s->Config0 = val;
@@ -1584,7 +1612,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;
 }
@@ -1593,12 +1621,13 @@ 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))
+    if (!rtl8139_config_writable(s)) {
         return;
+    }
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xC, s->Config1);
 
     s->Config1 = val;
@@ -1608,7 +1637,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;
 }
@@ -1617,12 +1646,13 @@ 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))
+    if (!rtl8139_config_writable(s)) {
         return;
+    }
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0x8F, s->Config3);
 
     s->Config3 = val;
@@ -1632,7 +1662,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;
 }
@@ -1641,12 +1671,13 @@ 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))
+    if (!rtl8139_config_writable(s)) {
         return;
+    }
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0x0a, s->Config4);
 
     s->Config4 = val;
@@ -1656,7 +1687,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;
 }
@@ -1665,9 +1696,9 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0x80, s->Config5);
 
     s->Config5 = val;
@@ -1677,7 +1708,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;
 }
@@ -1686,11 +1717,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);
 
@@ -1699,7 +1730,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;
@@ -1711,16 +1742,16 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
 
     s->RxConfig = val;
@@ -1728,34 +1759,64 @@ 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;
 }
 
-static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt)
+static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
+    int do_interrupt, const uint8_t *dot1q_buf)
 {
+    struct iovec *iov = NULL;
+
     if (!size)
     {
-        DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n"));
+        DPRINTF("+++ empty ethernet frame\n");
         return;
     }
 
+    if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
+        iov = (struct iovec[3]) {
+            { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+            { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
+            { .iov_base = buf + ETHER_ADDR_LEN * 2,
+                .iov_len = size - ETHER_ADDR_LEN * 2 },
+        };
+    }
+
     if (TxLoopBack == (s->TxConfig & TxLoopBack))
     {
-        DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
+        size_t buf2_size;
+        uint8_t *buf2;
+
+        if (iov) {
+            buf2_size = iov_size(iov, 3);
+            buf2 = g_malloc(buf2_size);
+            iov_to_buf(iov, 3, buf2, 0, buf2_size);
+            buf = buf2;
+        }
+
+        DPRINTF("+++ transmit loopback mode\n");
         rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt);
+
+        if (iov) {
+            g_free(buf2);
+        }
     }
     else
     {
-        qemu_send_packet(&s->nic->nc, buf, size);
+        if (iov) {
+            qemu_sendv_packet(&s->nic->nc, iov, 3);
+        } else {
+            qemu_send_packet(&s->nic->nc, buf, size);
+        }
     }
 }
 
@@ -1763,35 +1824,36 @@ 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);
+    pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize);
 
     /* Mark descriptor as transferred */
     s->TxStatus[descriptor] |= TxHostOwns;
     s->TxStatus[descriptor] |= TxStatOK;
 
-    rtl8139_transfer_frame(s, txbuffer, txsize, 0);
+    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;
@@ -1891,45 +1953,40 @@ 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 ;
     }
 
     int descriptor = s->currCPlusTxDesc;
 
-    target_phys_addr_t cplus_tx_ring_desc =
-        rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
+    dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
 
     /* 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 "
+        "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
+        s->TxAddr[0], cplus_tx_ring_desc);
 
     uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
 
-    cpu_physical_memory_read(cplus_tx_ring_desc,    (uint8_t *)&val, 4);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc,    (uint8_t *)&val, 4);
     txdw0 = le32_to_cpu(val);
-    /* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
-    cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)&val, 4);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc+4,  (uint8_t *)&val, 4);
     txdw1 = le32_to_cpu(val);
-    cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)&val, 4);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc+8,  (uint8_t *)&val, 4);
     txbufLO = le32_to_cpu(val);
-    cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
+    pci_dma_read(&s->dev, 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));
-
-    /* TODO: the following discard cast should clean clang analyzer output */
-    (void)txdw1;
+    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)
@@ -1954,9 +2011,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* w0 bits 0...15 : buffer size */
 #define CP_TX_BUFFER_SIZE (1<<16)
 #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (1<<17)
-/* w1 bits 0...15 : VLAN tag */
+/* w1 add tag flag */
+#define CP_TX_TAGC (1<<17)
+/* w1 bits 0...15 : VLAN tag (big endian) */
 #define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
 /* w2 low  32bit of Rx buffer ptr */
 /* w3 high 32bit of Rx buffer ptr */
@@ -1975,46 +2032,50 @@ 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;
     }
 
     int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
-    target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
+    dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
 
     /* make sure we have enough space to assemble the packet */
     if (!s->cplus_txbuffer)
     {
         s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
-        s->cplus_txbuffer = qemu_malloc(s->cplus_txbuffer_len);
+        s->cplus_txbuffer = g_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)
     {
         s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
-        s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+        s->cplus_txbuffer = g_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;
@@ -2025,10 +2086,12 @@ 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 "
+            DMA_ADDR_FMT" 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);
+    pci_dma_read(&s->dev, tx_addr,
+                 s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
     s->cplus_txbuffer_offset += txsize;
 
     /* seek to next Rx descriptor */
@@ -2055,15 +2118,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
     /* update ring data */
     val = cpu_to_le32(txdw0);
-    cpu_physical_memory_write(cplus_tx_ring_desc,    (uint8_t *)&val, 4);
-    /* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
-//    val = cpu_to_le32(txdw1);
-//    cpu_physical_memory_write(cplus_tx_ring_desc+4,  &val, 4);
+    pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
 
     /* Now decide if descriptor being processed is holding the last segment of packet */
     if (txdw0 & CP_TX_LS)
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor));
+        uint8_t dot1q_buffer_space[VLAN_HLEN];
+        uint16_t *dot1q_buffer;
+
+        DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
+            descriptor);
 
         /* can transfer fully assembled packet */
 
@@ -2071,6 +2135,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         int      saved_size    = s->cplus_txbuffer_offset;
         int      saved_buffer_len = s->cplus_txbuffer_len;
 
+        /* create vlan tag */
+        if (txdw1 & CP_TX_TAGC) {
+            /* the vlan tag is in BE byte order in the descriptor
+             * BE + le_to_cpu() + ~swap()~ = cpu */
+            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);
+            /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
+            dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
+        } else {
+            dot1q_buffer = NULL;
+        }
+
         /* reset the card space to protect from recursive call */
         s->cplus_txbuffer = NULL;
         s->cplus_txbuffer_offset = 0;
@@ -2078,11 +2157,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"));
-
-            #define ETH_P_IP   0x0800          /* Internet Protocol packet     */
-            #define ETH_HLEN    14
-            #define ETH_MTU     1500
+            DPRINTF("+++ C+ mode offloaded task checksum\n");
 
             /* ip packet header */
             ip_header *ip = NULL;
@@ -2096,7 +2171,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;
@@ -2105,7 +2180,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);
@@ -2118,7 +2195,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 */
@@ -2128,17 +2205,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;
@@ -2162,8 +2240,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 */
@@ -2181,13 +2260,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)
                         {
@@ -2209,7 +2291,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;
 
@@ -2224,11 +2307,14 @@ 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));
-                        rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0);
+                        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);
 
                         /* add transferred count to TCP sequence number */
                         p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
@@ -2240,7 +2326,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];
@@ -2255,7 +2341,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;
@@ -2267,13 +2354,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;
@@ -2285,7 +2374,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;
                     }
@@ -2299,9 +2389,10 @@ 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);
+        rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
+            (uint8_t *) dot1q_buffer);
 
         /* restore card space if there was no recursion and reset offset */
         if (!s->cplus_txbuffer)
@@ -2312,12 +2403,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         }
         else
         {
-            qemu_free(saved_buffer);
+            g_free(saved_buffer);
         }
     }
     else
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n"));
+        DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
     }
 
     return 1;
@@ -2335,8 +2426,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
     {
@@ -2361,7 +2452,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);
     }
 }
 
@@ -2374,7 +2466,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;
@@ -2384,7 +2477,7 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
             target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
 
             /* dump tally counters to specified memory location */
-            RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters);
+            RTL8139TallyCounters_dma_write(s, tc_addr);
 
             /* mark dump completed */
             s->TxStatus[0] &= ~0x8;
@@ -2393,7 +2486,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 */
@@ -2409,7 +2503,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;
 }
@@ -2441,7 +2535,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;
 }
@@ -2450,14 +2544,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;
 }
@@ -2466,20 +2560,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)
@@ -2487,7 +2581,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;
 }
@@ -2497,14 +2591,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;
 
@@ -2515,21 +2609,21 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0x1e00, s->IntrMask);
 
     s->IntrMask = val;
 
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
     rtl8139_update_irq(s);
 
 }
@@ -2538,14 +2632,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
 
@@ -2556,7 +2650,7 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
 #else
     uint16_t newStatus = s->IntrStatus & ~val;
 
-    /* mask unwriteable bits */
+    /* mask unwritable bits */
     newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
 
     /* writing 1 to interrupt status register bit clears it */
@@ -2570,7 +2664,7 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
      * and probably emulated is slower is better to assume this resetting was
      * done before testing on previous rtl8139_update_irq lead to IRQ loosing
      */
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
     rtl8139_update_irq(s);
 
 #endif
@@ -2578,11 +2672,11 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
 
 static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
 {
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
 
     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
 
@@ -2598,9 +2692,9 @@ 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 */
+    /* mask unwritable bits */
     val = SET_MASKED(val, 0xf000, s->MultiIntr);
 
     s->MultiIntr = val;
@@ -2610,7 +2704,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;
 }
@@ -2619,8 +2713,6 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
 {
     RTL8139State *s = opaque;
 
-    addr &= 0xff;
-
     switch (addr)
     {
         case MAC0 ... MAC0+5:
@@ -2658,11 +2750,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;
@@ -2674,27 +2767,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;
     }
 }
@@ -2703,8 +2798,6 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
 {
     RTL8139State *s = opaque;
 
-    addr &= 0xfe;
-
     switch (addr)
     {
         case IntrMask:
@@ -2730,14 +2823,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;
 
@@ -2750,7 +2843,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);
@@ -2763,7 +2857,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;
@@ -2802,12 +2896,10 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
 {
     RTL8139State *s = opaque;
 
-    addr &= 0xfc;
-
     switch (addr)
     {
         case RxMissed:
-            DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n"));
+            DPRINTF("RxMissed clearing on write\n");
             s->RxMissed = 0;
             break;
 
@@ -2832,31 +2924,32 @@ 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"));
-            s->TCTR_base = qemu_get_clock(vm_clock);
+            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(vm_clock));
+                rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
             }
             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);
@@ -2870,8 +2963,6 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
     RTL8139State *s = opaque;
     int ret;
 
-    addr &= 0xff;
-
     switch (addr)
     {
         case MAC0 ... MAC0+5:
@@ -2907,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;
     }
@@ -2944,8 +3035,6 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
     RTL8139State *s = opaque;
     uint32_t ret;
 
-    addr &= 0xfe; /* mask lower bit */
-
     switch (addr)
     {
         case IntrMask:
@@ -2976,15 +3065,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:
@@ -3004,12 +3093,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;
     }
 
@@ -3021,14 +3110,12 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
     RTL8139State *s = opaque;
     uint32_t ret;
 
-    addr &= 0xfc; /* also mask low 2 bits */
-
     switch (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:
@@ -3053,34 +3140,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(vm_clock) - s->TCTR_base,
+            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;
     }
 
@@ -3156,7 +3243,7 @@ static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
 static int rtl8139_post_load(void *opaque, int version_id)
 {
     RTL8139State* s = opaque;
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
     if (version_id < 4) {
         s->cplus_enabled = s->CpCmd != 0;
     }
@@ -3182,13 +3269,13 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
 static void rtl8139_pre_save(void *opaque)
 {
     RTL8139State* s = opaque;
-    int64_t current_time = qemu_get_clock(vm_clock);
+    int64_t current_time = qemu_get_clock_ns(vm_clock);
 
     /* set IntrStatus correctly */
     rtl8139_set_next_tctr_time(s, current_time);
     s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
                        get_ticks_per_sec());
-    s->rtl8139_mmio_io_addr_dummy = s->rtl8139_mmio_io_addr;
+    s->rtl8139_mmio_io_addr_dummy = 0;
 }
 
 static const VMStateDescription vmstate_rtl8139 = {
@@ -3284,39 +3371,35 @@ static const VMStateDescription vmstate_rtl8139 = {
 /***********************************************************/
 /* PCI RTL8139 definitions */
 
-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
-
-    cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
-}
-
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
-
-    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
-    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
-
-    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
-    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
-
-    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
-    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
-}
+static const MemoryRegionPortio rtl8139_portio[] = {
+    { 0, 0x100, 1, .read = rtl8139_ioport_readb, },
+    { 0, 0x100, 1, .write = rtl8139_ioport_writeb, },
+    { 0, 0x100, 2, .read = rtl8139_ioport_readw, },
+    { 0, 0x100, 2, .write = rtl8139_ioport_writew, },
+    { 0, 0x100, 4, .read = rtl8139_ioport_readl, },
+    { 0, 0x100, 4, .write = rtl8139_ioport_writel, },
+    PORTIO_END_OF_LIST()
+};
 
-static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
-    rtl8139_mmio_readb,
-    rtl8139_mmio_readw,
-    rtl8139_mmio_readl,
+static const MemoryRegionOps rtl8139_io_ops = {
+    .old_portio = rtl8139_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const rtl8139_mmio_write[3] = {
-    rtl8139_mmio_writeb,
-    rtl8139_mmio_writew,
-    rtl8139_mmio_writel,
+static const MemoryRegionOps rtl8139_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            rtl8139_mmio_readb,
+            rtl8139_mmio_readw,
+            rtl8139_mmio_readl,
+        },
+        .write = {
+            rtl8139_mmio_writeb,
+            rtl8139_mmio_writew,
+            rtl8139_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void rtl8139_timer(void *opaque)
@@ -3325,13 +3408,13 @@ 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;
     }
 
     s->IntrStatus |= PCSTimeout;
     rtl8139_update_irq(s);
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
 }
 
 static void rtl8139_cleanup(VLANClientState *nc)
@@ -3345,9 +3428,10 @@ static int pci_rtl8139_uninit(PCIDevice *dev)
 {
     RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
 
-    cpu_unregister_io_memory(s->rtl8139_mmio_io_addr);
+    memory_region_destroy(&s->bar_io);
+    memory_region_destroy(&s->bar_mem);
     if (s->cplus_txbuffer) {
-        qemu_free(s->cplus_txbuffer);
+        g_free(s->cplus_txbuffer);
         s->cplus_txbuffer = NULL;
     }
     qemu_del_timer(s->timer);
@@ -3370,28 +3454,29 @@ static int pci_rtl8139_init(PCIDevice *dev)
     uint8_t *pci_conf;
 
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139);
-    pci_conf[PCI_REVISION_ID] = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
-    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin 0 */
+    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin A */
     /* TODO: start of capability list, but no capability
      * list bit in status register, and offset 0xdc seems unused. */
     pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
 
-    /* I/O handler for memory-mapped I/O */
-    s->rtl8139_mmio_io_addr =
-        cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s,
-                               DEVICE_LITTLE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
-
-    pci_register_bar(&s->dev, 1, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
+    memory_region_init_io(&s->bar_io, &rtl8139_io_ops, s, "rtl8139", 0x100);
+    memory_region_init_io(&s->bar_mem, &rtl8139_mmio_ops, s, "rtl8139", 0x100);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
+    /* prepare eeprom */
+    s->eeprom.contents[0] = 0x8129;
+#if 1
+    /* PCI vendor and device ID should be mirrored here */
+    s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
+    s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
+#endif
+    s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
+    s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
+    s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
+
     s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
                           dev->qdev.info->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
@@ -3401,8 +3486,8 @@ static int pci_rtl8139_init(PCIDevice *dev)
     s->cplus_txbuffer_offset = 0;
 
     s->TimerExpire = 0;
-    s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
-    rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+    s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s);
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
 
     add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0");
 
@@ -3416,7 +3501,11 @@ static PCIDeviceInfo rtl8139_info = {
     .qdev.vmsd  = &vmstate_rtl8139,
     .init       = pci_rtl8139_init,
     .exit       = pci_rtl8139_uninit,
-    .romfile    = "pxe-rtl8139.bin",
+    .romfile    = "pxe-rtl8139.rom",
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8139,
+    .revision   = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(RTL8139State, conf),
         DEFINE_PROP_END_OF_LIST(),
index 784dc01b97d2e5a7f7fc48e8b4967cbc81e94b3c..c4b9a99e6ec27f7fff91fe7ddc4afcf0a856cba2 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),
@@ -58,6 +60,9 @@ static const VirtIOBindings virtio_s390_bindings;
 
 static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
 
+/* length of VirtIO device pages */
+const target_phys_addr_t virtio_size = S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
+
 VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
 {
     VirtIOS390Bus *bus;
@@ -123,7 +128,8 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
 {
     VirtIODevice *vdev;
 
-    vdev = virtio_blk_init((DeviceState *)dev, &dev->block);
+    vdev = virtio_blk_init((DeviceState *)dev, &dev->block,
+                           &dev->block_serial);
     if (!vdev) {
         return -1;
     }
@@ -139,7 +145,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;
     }
@@ -160,7 +166,7 @@ static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
                 (vq * VIRTIO_VQCONFIG_LEN) +
                 VIRTIO_VQCONFIG_OFFS_TOKEN;
 
-    return ldq_phys(token_off);
+    return ldq_be_phys(token_off);
 }
 
 static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
@@ -214,8 +220,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
         vring = s390_virtio_next_ring(bus);
         virtio_queue_set_addr(dev->vdev, i, vring);
         virtio_queue_set_vector(dev->vdev, i, i);
-        stq_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring);
-        stw_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i));
+        stq_be_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring);
+        stw_be_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i));
     }
 
     cur_offs = dev->dev_offs;
@@ -223,7 +229,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_le_phys(cur_offs, dev->host_features);
 
     dev->feat_offs = cur_offs + dev->feat_len;
     cur_offs += dev->feat_len * 2;
@@ -233,7 +239,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,11 +253,8 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
 
     /* Update guest supported feature bitmap */
 
-    features = ldl_phys(dev->feat_offs);
-    if (vdev->set_features) {
-        vdev->set_features(vdev, features);
-    }
-    vdev->guest_features = features;
+    features = bswap32(ldl_be_phys(dev->feat_offs));
+    virtio_set_features(vdev, features);
 }
 
 VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
@@ -267,7 +271,7 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
     DeviceState *dev;
     int i;
 
-    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
         _dev = (VirtIOS390Device *)dev;
         for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
             if (!virtio_queue_get_addr(_dev->vdev, i))
@@ -290,7 +294,7 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
     VirtIOS390Device *_dev;
     DeviceState *dev;
 
-    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
         _dev = (VirtIOS390Device *)dev;
         if (_dev->dev_offs == mem) {
             return _dev;
@@ -304,9 +308,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 +333,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,9 +349,11 @@ 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),
+        DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
@@ -353,8 +364,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..f1bece738ba0957c8854fe350647f760fec44147 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 */
@@ -32,7 +33,7 @@
 #define VIRTIO_VQCONFIG_LEN            24
 
 #define VIRTIO_RING_LEN                        (TARGET_PAGE_SIZE * 3)
-#define S390_DEVICE_PAGES              256
+#define S390_DEVICE_PAGES              512
 
 typedef struct VirtIOS390Device {
     DeviceState qdev;
@@ -41,10 +42,10 @@ typedef struct VirtIOS390Device {
     uint8_t feat_len;
     VirtIODevice *vdev;
     BlockConf block;
+    char *block_serial;
     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 f29b624e41e757c6a68f3786340228cfefcb2d16..61b67e8c3a428ed6158ba20c3428a0fe63c9eb52 100644 (file)
@@ -29,6 +29,7 @@
 #include "hw/virtio.h"
 #include "hw/sysbus.h"
 #include "kvm.h"
+#include "exec-memory.h"
 
 #include "hw/s390-virtio-bus.h"
 
 static VirtIOS390Bus *s390_bus;
 static CPUState **ipi_states;
 
-void irq_info(Monitor *mon);
-void pic_info(Monitor *mon);
-
-void irq_info(Monitor *mon)
-{
-}
-
-void pic_info(Monitor *mon)
-{
-}
-
 CPUState *s390_cpu_addr2state(uint16_t cpu_addr)
 {
     if (cpu_addr >= smp_cpus) {
@@ -82,13 +72,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,
@@ -108,6 +97,7 @@ int s390_virtio_hypercall(CPUState *env)
 
         dev = s390_virtio_bus_find_mem(s390_bus, mem);
         virtio_reset(dev->vdev);
+        stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0);
         s390_virtio_device_sync(dev);
         break;
     }
@@ -128,12 +118,39 @@ int s390_virtio_hypercall(CPUState *env)
         break;
     }
 
-    env->regs[2] = r;
-    return 0;
+    return r;
+}
+
+/*
+ * The number of running CPUs. On s390 a shutdown is the state of all CPUs
+ * being either stopped or disabled (for interrupts) waiting. We have to
+ * track this number to call the shutdown sequence accordingly. This
+ * number is modified either on startup or while holding the big qemu lock.
+ */
+static unsigned s390_running_cpus;
+
+void s390_add_running_cpu(CPUState *env)
+{
+    if (env->halted) {
+        s390_running_cpus++;
+        env->halted = 0;
+        env->exception_index = -1;
+    }
+}
+
+unsigned s390_del_running_cpu(CPUState *env)
+{
+    if (env->halted == 0) {
+        assert(s390_running_cpus >= 1);
+        s390_running_cpus--;
+        env->halted = 1;
+        env->exception_index = EXCP_HLT;
+    }
+    return s390_running_cpus;
 }
 
 /* PC hardware initialisation */
-static void s390_init(ram_addr_t ram_size,
+static void s390_init(ram_addr_t my_ram_size,
                       const char *boot_device,
                       const char *kernel_filename,
                       const char *kernel_cmdline,
@@ -141,32 +158,53 @@ static void s390_init(ram_addr_t ram_size,
                       const char *cpu_model)
 {
     CPUState *env = NULL;
-    ram_addr_t ram_addr;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     ram_addr_t kernel_size = 0;
     ram_addr_t initrd_offset;
     ram_addr_t initrd_size = 0;
+    int shift = 0;
+    uint8_t *storage_keys;
+    void *virtio_region;
+    target_phys_addr_t virtio_region_len;
+    target_phys_addr_t virtio_region_start;
     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);
+    /* s390x ram size detection needs a 16bit multiplier + an increment. So
+       guests > 64GB can be specified in 2MB steps etc. */
+    while ((my_ram_size >> (20 + shift)) > 65535) {
+        shift++;
     }
+    my_ram_size = my_ram_size >> (20 + shift) << (20 + shift);
+
+    /* lets propagate the changed ram size into the global variable. */
+    ram_size = my_ram_size;
 
     /* get a BUS */
-    s390_bus = s390_virtio_bus_init(&ram_size);
+    s390_bus = s390_virtio_bus_init(&my_ram_size);
 
     /* allocate RAM */
-    ram_addr = qemu_ram_alloc(NULL, "s390.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_addr);
+    memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
+
+    /* clear virtio region */
+    virtio_region_len = my_ram_size - ram_size;
+    virtio_region_start = ram_size;
+    virtio_region = cpu_physical_memory_map(virtio_region_start,
+                                            &virtio_region_len, true);
+    memset(virtio_region, 0, virtio_region_len);
+    cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
+                              virtio_region_len);
+
+    /* allocate storage keys */
+    storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
 
     /* init CPUs */
     if (cpu_model == NULL) {
         cpu_model = "host";
     }
 
-    ipi_states = qemu_malloc(sizeof(CPUState *) * smp_cpus);
+    ipi_states = g_malloc(sizeof(CPUState *) * smp_cpus);
 
     for (i = 0; i < smp_cpus; i++) {
         CPUState *tmp_env;
@@ -178,15 +216,16 @@ 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;
-    env->exception_index = 0;
+    /* One CPU has to run */
+    s390_add_running_cpu(env);
 
     if (kernel_filename) {
         kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
 
-        if (lduw_phys(KERN_IMAGE_START) != 0x0dd0) {
+        if (lduw_be_phys(KERN_IMAGE_START) != 0x0dd0) {
             fprintf(stderr, "Specified image is not an s390 boot image\n");
             exit(1);
         }
@@ -204,6 +243,7 @@ static void s390_init(ram_addr_t ram_size,
 
         bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
         bios_size = load_image(bios_filename, qemu_get_ram_ptr(ZIPL_LOAD_ADDR));
+        g_free(bios_filename);
 
         if ((long)bios_size < 0) {
             hw_error("could not load bootloader '%s'\n", bios_name);
@@ -224,13 +264,13 @@ static void s390_init(ram_addr_t ram_size,
         }
         initrd_size = load_image(initrd_filename, qemu_get_ram_ptr(initrd_offset));
 
-        stq_phys(INITRD_PARM_START, initrd_offset);
-        stq_phys(INITRD_PARM_SIZE, initrd_size);
+        stq_be_phys(INITRD_PARM_START, initrd_offset);
+        stq_be_phys(INITRD_PARM_SIZE, initrd_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) + 1);
     }
 
     /* Create VirtIO network adapters */
@@ -239,7 +279,7 @@ static void s390_init(ram_addr_t ram_size,
         DeviceState *dev;
 
         if (!nd->model) {
-            nd->model = qemu_strdup("virtio");
+            nd->model = g_strdup("virtio");
         }
 
         if (strcmp(nd->model, "virtio")) {
index c9d37ad2b7d1e2c307a1cb9bd18a7c168359fea2..f0658ac596c11b99463ebd34d4179e5a952aaaba 100644 (file)
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -766,7 +766,7 @@ static void complete (SB16State *s)
                     if (s->aux_ts) {
                         qemu_mod_timer (
                             s->aux_ts,
-                            qemu_get_clock (vm_clock) + ticks
+                            qemu_get_clock_ns (vm_clock) + ticks
                             );
                     }
                 }
@@ -1341,12 +1341,21 @@ static const VMStateDescription vmstate_sb16 = {
     }
 };
 
+static const MemoryRegionPortio sb16_ioport_list[] = {
+    {  4, 1, 1, .write = mixer_write_indexb },
+    {  4, 1, 2, .write = mixer_write_indexw },
+    {  5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
+    {  6, 1, 1, .read = dsp_read, .write = dsp_write },
+    { 10, 1, 1, .read = dsp_read },
+    { 12, 1, 1, .write = dsp_write },
+    { 12, 4, 1, .read = dsp_read },
+    PORTIO_END_OF_LIST(),
+};
+
+
 static int sb16_initfn (ISADevice *dev)
 {
-    static const uint8_t dsp_write_ports[] = {0x6, 0xc};
-    static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
     SB16State *s;
-    int i;
 
     s = DO_UPCAST (SB16State, dev, dev);
 
@@ -1361,27 +1370,12 @@ static int sb16_initfn (ISADevice *dev)
     s->csp_regs[9] = 0xf8;
 
     reset_mixer (s);
-    s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
+    s->aux_ts = qemu_new_timer_ns (vm_clock, aux_timer, s);
     if (!s->aux_ts) {
         dolog ("warning: Could not create auxiliary timer\n");
     }
 
-    for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
-        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
-        isa_init_ioport(dev, s->port + dsp_write_ports[i]);
-    }
-
-    for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
-        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
-        isa_init_ioport(dev, s->port + dsp_read_ports[i]);
-    }
-
-    register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
-    register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
-    isa_init_ioport(dev, s->port + 0x4);
-    register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
-    register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
-    isa_init_ioport(dev, s->port + 0x5);
+    isa_register_portio_list (dev, s->port, sb16_ioport_list, s, "sb16");
 
     DMA_register_channel (s->hdma, SB_read_DMA, s);
     DMA_register_channel (s->dma, SB_read_DMA, s);
index ceeb4ecb9182d8bd0cdad5ce75203f303da67268..64e709ee9fed70be92c60d916d6c364adaf48894 100644 (file)
 #include "scsi-defs.h"
 #include "qdev.h"
 #include "blockdev.h"
+#include "trace.h"
 
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
+static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
+static void scsi_req_dequeue(SCSIRequest *req);
 
 static struct BusInfo scsi_bus_info = {
     .name  = "SCSI",
     .size  = sizeof(SCSIBus),
     .get_fw_dev_path = scsibus_get_fw_dev_path,
     .props = (Property[]) {
+        DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
         DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
+        DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
 static int next_scsi_bus;
 
 /* Create a scsi bus, and attach devices to it.  */
-void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
-                  scsi_completionfn complete)
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
 {
     qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
     bus->busnr = next_scsi_bus++;
-    bus->tcq = tcq;
-    bus->ndev = ndev;
-    bus->complete = complete;
+    bus->info = info;
     bus->qbus.allow_hotplug = 1;
 }
 
+static void scsi_dma_restart_bh(void *opaque)
+{
+    SCSIDevice *s = opaque;
+    SCSIRequest *req, *next;
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
+        scsi_req_ref(req);
+        if (req->retry) {
+            req->retry = false;
+            switch (req->cmd.mode) {
+            case SCSI_XFER_FROM_DEV:
+            case SCSI_XFER_TO_DEV:
+                scsi_req_continue(req);
+                break;
+            case SCSI_XFER_NONE:
+                scsi_req_dequeue(req);
+                scsi_req_enqueue(req);
+                break;
+            }
+        }
+        scsi_req_unref(req);
+    }
+}
+
+void scsi_req_retry(SCSIRequest *req)
+{
+    /* No need to save a reference, because scsi_dma_restart_bh just
+     * looks at the request list.  */
+    req->retry = true;
+}
+
+static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
+{
+    SCSIDevice *s = opaque;
+
+    if (!running) {
+        return;
+    }
+    if (!s->bh) {
+        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
 static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
     SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
     SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+    SCSIDevice *d;
     int rc = -1;
 
-    if (dev->id == -1) {
-        for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
-            if (bus->devs[dev->id] == NULL)
-                break;
-        }
+    if (dev->channel > bus->info->max_channel) {
+        error_report("bad scsi channel id: %d", dev->channel);
+        goto err;
     }
-    if (dev->id >= bus->ndev) {
+    if (dev->id != -1 && dev->id > bus->info->max_target) {
         error_report("bad scsi device id: %d", dev->id);
         goto err;
     }
 
-    if (bus->devs[dev->id]) {
-        qdev_free(&bus->devs[dev->id]->qdev);
+    if (dev->id == -1) {
+        int id = -1;
+        if (dev->lun == -1) {
+            dev->lun = 0;
+        }
+        do {
+            d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
+        } while (d && d->lun == dev->lun && id <= bus->info->max_target);
+        if (id > bus->info->max_target) {
+            error_report("no free target");
+            goto err;
+        }
+        dev->id = id;
+    } else if (dev->lun == -1) {
+        int lun = -1;
+        do {
+            d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
+        } while (d && d->lun == lun && lun < bus->info->max_lun);
+        if (lun > bus->info->max_lun) {
+            error_report("no free lun");
+            goto err;
+        }
+        dev->lun = lun;
+    } else {
+        d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
+        if (dev->lun == d->lun && dev != d) {
+            qdev_free(&d->qdev);
+        }
     }
-    bus->devs[dev->id] = dev;
 
     dev->info = info;
     QTAILQ_INIT(&dev->requests);
     rc = dev->info->init(dev);
-    if (rc != 0) {
-        bus->devs[dev->id] = NULL;
+    if (rc == 0) {
+        dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
+                                                         dev);
     }
 
 err:
@@ -67,13 +141,13 @@ err:
 static int scsi_qdev_exit(DeviceState *qdev)
 {
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
 
-    assert(bus->devs[dev->id] != NULL);
-    if (bus->devs[dev->id]->info->destroy) {
-        bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
+    if (dev->vmsentry) {
+        qemu_del_vm_change_state_handler(dev->vmsentry);
+    }
+    if (dev->info->destroy) {
+        dev->info->destroy(dev);
     }
-    bus->devs[dev->id] = NULL;
     return 0;
 }
 
@@ -88,7 +162,7 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
 
 /* handle legacy '-drive if=scsi,...' cmd line args */
 SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
-                                      int unit, bool removable)
+                                      int unit, bool removable, int bootindex)
 {
     const char *driver;
     DeviceState *dev;
@@ -96,6 +170,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
     driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
     dev = qdev_create(&bus->qbus, driver);
     qdev_prop_set_uint32(dev, "scsi-id", unit);
+    if (bootindex >= 0) {
+        qdev_prop_set_int32(dev, "bootindex", bootindex);
+    }
     if (qdev_prop_exists(dev, "removable")) {
         qdev_prop_set_bit(dev, "removable", removable);
     }
@@ -115,13 +192,13 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     int res = 0, unit;
 
     loc_push_none(&loc);
-    for (unit = 0; unit < bus->ndev; unit++) {
+    for (unit = 0; unit < bus->info->max_target; unit++) {
         dinfo = drive_get(IF_SCSI, bus->busnr, unit);
         if (dinfo == NULL) {
             continue;
         }
         qemu_opts_loc_restore(dinfo->opts);
-        if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) {
+        if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) {
             res = -1;
             break;
         }
@@ -130,125 +207,560 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     return res;
 }
 
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
+/* SCSIReqOps implementation for invalid commands.  */
+
+static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
+{
+    scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
+    scsi_req_complete(req, CHECK_CONDITION);
+    return 0;
+}
+
+static const struct SCSIReqOps reqops_invalid_opcode = {
+    .size         = sizeof(SCSIRequest),
+    .send_command = scsi_invalid_command
+};
+
+/* SCSIReqOps implementation for unit attention conditions.  */
+
+static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
+{
+    if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) {
+        scsi_req_build_sense(req, req->dev->unit_attention);
+    } else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
+        scsi_req_build_sense(req, req->bus->unit_attention);
+    }
+    scsi_req_complete(req, CHECK_CONDITION);
+    return 0;
+}
+
+static const struct SCSIReqOps reqops_unit_attention = {
+    .size         = sizeof(SCSIRequest),
+    .send_command = scsi_unit_attention
+};
+
+/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
+   an invalid LUN.  */
+
+typedef struct SCSITargetReq SCSITargetReq;
+
+struct SCSITargetReq {
+    SCSIRequest req;
+    int len;
+    uint8_t buf[2056];
+};
+
+static void store_lun(uint8_t *outbuf, int lun)
+{
+    if (lun < 256) {
+        outbuf[1] = lun;
+        return;
+    }
+    outbuf[1] = (lun & 255);
+    outbuf[0] = (lun >> 8) | 0x40;
+}
+
+static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
+{
+    DeviceState *qdev;
+    int i, len, n;
+    int channel, id;
+    bool found_lun0;
+
+    if (r->req.cmd.xfer < 16) {
+        return false;
+    }
+    if (r->req.cmd.buf[2] > 2) {
+        return false;
+    }
+    channel = r->req.dev->channel;
+    id = r->req.dev->id;
+    found_lun0 = false;
+    n = 0;
+    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            if (dev->lun == 0) {
+                found_lun0 = true;
+            }
+            n += 8;
+        }
+    }
+    if (!found_lun0) {
+        n += 8;
+    }
+    len = MIN(n + 8, r->req.cmd.xfer & ~7);
+    if (len > sizeof(r->buf)) {
+        /* TODO: > 256 LUNs? */
+        return false;
+    }
+
+    memset(r->buf, 0, len);
+    stl_be_p(&r->buf, n);
+    i = found_lun0 ? 8 : 16;
+    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            store_lun(&r->buf[i], dev->lun);
+            i += 8;
+        }
+    }
+    assert(i == n + 8);
+    r->len = len;
+    return true;
+}
+
+static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
+{
+    assert(r->req.dev->lun != r->req.lun);
+    if (r->req.cmd.buf[1] & 0x2) {
+        /* Command support data - optional, not implemented */
+        return false;
+    }
+
+    if (r->req.cmd.buf[1] & 0x1) {
+        /* Vital product data */
+        uint8_t page_code = r->req.cmd.buf[2];
+        if (r->req.cmd.xfer < 4) {
+            return false;
+        }
+
+        r->buf[r->len++] = page_code ; /* this page */
+        r->buf[r->len++] = 0x00;
+
+        switch (page_code) {
+        case 0x00: /* Supported page codes, mandatory */
+        {
+            int pages;
+            pages = r->len++;
+            r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
+            r->buf[pages] = r->len - pages - 1; /* number of pages */
+            break;
+        }
+        default:
+            return false;
+        }
+        /* done with EVPD */
+        assert(r->len < sizeof(r->buf));
+        r->len = MIN(r->req.cmd.xfer, r->len);
+        return true;
+    }
+
+    /* Standard INQUIRY data */
+    if (r->req.cmd.buf[2] != 0) {
+        return false;
+    }
+
+    /* PAGE CODE == 0 */
+    if (r->req.cmd.xfer < 5) {
+        return -1;
+    }
+
+    r->len = MIN(r->req.cmd.xfer, 36);
+    memset(r->buf, 0, r->len);
+    if (r->req.lun != 0) {
+        r->buf[0] = TYPE_NO_LUN;
+    } else {
+        r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
+        r->buf[2] = 5; /* Version */
+        r->buf[3] = 2 | 0x10; /* HiSup, response data format */
+        r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
+        r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
+        memcpy(&r->buf[8], "QEMU    ", 8);
+        memcpy(&r->buf[16], "QEMU TARGET     ", 16);
+        strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
+    }
+    return true;
+}
+
+static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    switch (buf[0]) {
+    case REPORT_LUNS:
+        if (!scsi_target_emulate_report_luns(r)) {
+            goto illegal_request;
+        }
+        break;
+    case INQUIRY:
+        if (!scsi_target_emulate_inquiry(r)) {
+            goto illegal_request;
+        }
+        break;
+    case REQUEST_SENSE:
+        if (req->cmd.xfer < 4) {
+            goto illegal_request;
+        }
+        r->len = scsi_device_get_sense(r->req.dev, r->buf,
+                                       MIN(req->cmd.xfer, sizeof r->buf),
+                                       (req->cmd.buf[1] & 1) == 0);
+        if (r->req.dev->sense_is_ua) {
+            if (r->req.dev->info->unit_attention_reported) {
+                r->req.dev->info->unit_attention_reported(req->dev);
+            }
+            r->req.dev->sense_len = 0;
+            r->req.dev->sense_is_ua = false;
+        }
+        break;
+    default:
+        scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    illegal_request:
+        scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    }
+
+    if (!r->len) {
+        scsi_req_complete(req, GOOD);
+    }
+    return r->len;
+}
+
+static void scsi_target_read_data(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+    uint32_t n;
+
+    n = r->len;
+    if (n > 0) {
+        r->len = 0;
+        scsi_req_data(&r->req, n);
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
+}
+
+static uint8_t *scsi_target_get_buf(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    return r->buf;
+}
+
+static const struct SCSIReqOps reqops_target_command = {
+    .size         = sizeof(SCSITargetReq),
+    .send_command = scsi_target_send_command,
+    .read_data    = scsi_target_read_data,
+    .get_buf      = scsi_target_get_buf,
+};
+
+
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private)
 {
     SCSIRequest *req;
 
-    req = qemu_mallocz(size);
+    req = g_malloc0(reqops->size);
+    req->refcount = 1;
     req->bus = scsi_bus_from_device(d);
     req->dev = d;
     req->tag = tag;
     req->lun = lun;
+    req->hba_private = hba_private;
     req->status = -1;
-    req->enqueued = true;
-    QTAILQ_INSERT_TAIL(&d->requests, req, next);
+    req->sense_len = 0;
+    req->ops = reqops;
+    trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
     return req;
 }
 
-SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag)
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          uint8_t *buf, void *hba_private)
 {
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
     SCSIRequest *req;
+    SCSICommand cmd;
+
+    if (scsi_req_parse(&cmd, d, buf) != 0) {
+        trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
+        req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
+    } else {
+        trace_scsi_req_parsed(d->id, lun, tag, buf[0],
+                              cmd.mode, cmd.xfer);
+        if (cmd.lba != -1) {
+            trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
+                                      cmd.lba);
+        }
+
+        if ((d->unit_attention.key == UNIT_ATTENTION ||
+             bus->unit_attention.key == UNIT_ATTENTION) &&
+            (buf[0] != INQUIRY &&
+             buf[0] != REPORT_LUNS &&
+             buf[0] != GET_CONFIGURATION &&
+             buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
+
+             /*
+              * If we already have a pending unit attention condition,
+              * report this one before triggering another one.
+              */
+             !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
+            req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
+                                 hba_private);
+        } else if (lun != d->lun ||
+            buf[0] == REPORT_LUNS ||
+            (buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) {
+            req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
+                                 hba_private);
+        } else {
+            req = d->info->alloc_req(d, tag, lun, buf, hba_private);
+        }
+    }
+
+    req->cmd = cmd;
+    switch (buf[0]) {
+    case INQUIRY:
+        trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
+        break;
+    case TEST_UNIT_READY:
+        trace_scsi_test_unit_ready(d->id, lun, tag);
+        break;
+    case REPORT_LUNS:
+        trace_scsi_report_luns(d->id, lun, tag);
+        break;
+    case REQUEST_SENSE:
+        trace_scsi_request_sense(d->id, lun, tag);
+        break;
+    default:
+        break;
+    }
+
+    return req;
+}
+
+uint8_t *scsi_req_get_buf(SCSIRequest *req)
+{
+    return req->ops->get_buf(req);
+}
+
+static void scsi_clear_unit_attention(SCSIRequest *req)
+{
+    SCSISense *ua;
+    if (req->dev->unit_attention.key != UNIT_ATTENTION &&
+        req->bus->unit_attention.key != UNIT_ATTENTION) {
+        return;
+    }
+
+    /*
+     * If an INQUIRY command enters the enabled command state,
+     * the device server shall [not] clear any unit attention condition;
+     * See also MMC-6, paragraphs 6.5 and 6.6.2.
+     */
+    if (req->cmd.buf[0] == INQUIRY ||
+        req->cmd.buf[0] == GET_CONFIGURATION ||
+        req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
+        return;
+    }
+
+    if (req->dev->unit_attention.key == UNIT_ATTENTION) {
+        ua = &req->dev->unit_attention;
+    } else {
+        ua = &req->bus->unit_attention;
+    }
+
+    /*
+     * If a REPORT LUNS command enters the enabled command state, [...]
+     * the device server shall clear any pending unit attention condition
+     * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
+     */
+    if (req->cmd.buf[0] == REPORT_LUNS &&
+        !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc &&
+          ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) {
+        return;
+    }
+
+    *ua = SENSE_CODE(NO_SENSE);
+}
+
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
+{
+    int ret;
+
+    assert(len >= 14);
+    if (!req->sense_len) {
+        return 0;
+    }
+
+    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
 
-    QTAILQ_FOREACH(req, &d->requests, next) {
-        if (req->tag == tag) {
-            return req;
+    /*
+     * FIXME: clearing unit attention conditions upon autosense should be done
+     * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
+     * (SAM-5, 5.14).
+     *
+     * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
+     * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
+     * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
+     */
+    if (req->dev->sense_is_ua) {
+        if (req->dev->info->unit_attention_reported) {
+            req->dev->info->unit_attention_reported(req->dev);
         }
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
     }
-    return NULL;
+    return ret;
+}
+
+int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
+{
+    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
+}
+
+void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
+{
+    trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
+                               sense.key, sense.asc, sense.ascq);
+    memset(req->sense, 0, 18);
+    req->sense[0] = 0xf0;
+    req->sense[2] = sense.key;
+    req->sense[7] = 10;
+    req->sense[12] = sense.asc;
+    req->sense[13] = sense.ascq;
+    req->sense_len = 18;
+}
+
+int32_t scsi_req_enqueue(SCSIRequest *req)
+{
+    int32_t rc;
+
+    assert(!req->enqueued);
+    scsi_req_ref(req);
+    req->enqueued = true;
+    QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+
+    scsi_req_ref(req);
+    rc = req->ops->send_command(req, req->cmd.buf);
+    scsi_req_unref(req);
+    return rc;
 }
 
 static void scsi_req_dequeue(SCSIRequest *req)
 {
+    trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
+    req->retry = false;
     if (req->enqueued) {
         QTAILQ_REMOVE(&req->dev->requests, req, next);
         req->enqueued = false;
+        scsi_req_unref(req);
     }
 }
 
-void scsi_req_free(SCSIRequest *req)
+static int scsi_get_performance_length(int num_desc, int type, int data_type)
 {
-    scsi_req_dequeue(req);
-    qemu_free(req);
+    /* MMC-6, paragraph 6.7.  */
+    switch (type) {
+    case 0:
+        if ((data_type & 3) == 0) {
+            /* Each descriptor is as in Table 295 - Nominal performance.  */
+            return 16 * num_desc + 8;
+        } else {
+            /* Each descriptor is as in Table 296 - Exceptions.  */
+            return 6 * num_desc + 8;
+        }
+    case 1:
+    case 4:
+    case 5:
+        return 8 * num_desc + 8;
+    case 2:
+        return 2048 * num_desc + 8;
+    case 3:
+        return 16 * num_desc + 8;
+    default:
+        return 8;
+    }
 }
 
-static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
+static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
 {
-    switch (cmd[0] >> 5) {
+    switch (buf[0] >> 5) {
     case 0:
-        req->cmd.xfer = cmd[4];
-        req->cmd.len = 6;
+        cmd->xfer = buf[4];
+        cmd->len = 6;
         /* length 0 means 256 blocks */
-        if (req->cmd.xfer == 0)
-            req->cmd.xfer = 256;
+        if (cmd->xfer == 0) {
+            cmd->xfer = 256;
+        }
         break;
     case 1:
     case 2:
-        req->cmd.xfer = cmd[8] | (cmd[7] << 8);
-        req->cmd.len = 10;
+        cmd->xfer = lduw_be_p(&buf[7]);
+        cmd->len = 10;
         break;
     case 4:
-        req->cmd.xfer = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24);
-        req->cmd.len = 16;
+        cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
+        cmd->len = 16;
         break;
     case 5:
-        req->cmd.xfer = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24);
-        req->cmd.len = 12;
+        cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
+        cmd->len = 12;
         break;
     default:
         return -1;
     }
 
-    switch(cmd[0]) {
+    switch (buf[0]) {
     case TEST_UNIT_READY:
-    case REZERO_UNIT:
+    case REWIND:
     case START_STOP:
-    case SEEK_6:
+    case SET_CAPACITY:
     case WRITE_FILEMARKS:
+    case WRITE_FILEMARKS_16:
     case SPACE:
     case RESERVE:
     case RELEASE:
     case ERASE:
     case ALLOW_MEDIUM_REMOVAL:
-    case VERIFY:
+    case VERIFY_10:
     case SEEK_10:
     case SYNCHRONIZE_CACHE:
+    case SYNCHRONIZE_CACHE_16:
+    case LOCATE_16:
     case LOCK_UNLOCK_CACHE:
     case LOAD_UNLOAD:
     case SET_CD_SPEED:
     case SET_LIMITS:
-    case WRITE_LONG:
+    case WRITE_LONG_10:
     case MOVE_MEDIUM:
     case UPDATE_BLOCK:
-        req->cmd.xfer = 0;
+    case RESERVE_TRACK:
+    case SET_READ_AHEAD:
+    case PRE_FETCH:
+    case PRE_FETCH_16:
+    case ALLOW_OVERWRITE:
+        cmd->xfer = 0;
         break;
     case MODE_SENSE:
         break;
-    case WRITE_SAME:
-        req->cmd.xfer = 1;
+    case WRITE_SAME_10:
+        cmd->xfer = 1;
         break;
-    case READ_CAPACITY:
-        req->cmd.xfer = 8;
+    case READ_CAPACITY_10:
+        cmd->xfer = 8;
         break;
     case READ_BLOCK_LIMITS:
-        req->cmd.xfer = 6;
-        break;
-    case READ_POSITION:
-        req->cmd.xfer = 20;
+        cmd->xfer = 6;
         break;
     case SEND_VOLUME_TAG:
-        req->cmd.xfer *= 40;
-        break;
-    case MEDIUM_SCAN:
-        req->cmd.xfer *= 8;
+        /* GPCMD_SET_STREAMING from multimedia commands.  */
+        if (dev->type == TYPE_ROM) {
+            cmd->xfer = buf[10] | (buf[9] << 8);
+        } else {
+            cmd->xfer = buf[9] | (buf[8] << 8);
+        }
         break;
     case WRITE_10:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_6:
     case WRITE_12:
     case WRITE_VERIFY_12:
     case WRITE_16:
     case WRITE_VERIFY_16:
-        req->cmd.xfer *= req->dev->blocksize;
+        cmd->xfer *= dev->blocksize;
         break;
     case READ_10:
     case READ_6:
@@ -256,53 +768,97 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
     case RECOVER_BUFFERED_DATA:
     case READ_12:
     case READ_16:
-        req->cmd.xfer *= req->dev->blocksize;
+        cmd->xfer *= dev->blocksize;
+        break;
+    case FORMAT_UNIT:
+        /* MMC mandates the parameter list to be 12-bytes long.  Parameters
+         * for block devices are restricted to the header right now.  */
+        if (dev->type == TYPE_ROM && (buf[1] & 16)) {
+            cmd->xfer = 12;
+        } else {
+            cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
+        }
         break;
     case INQUIRY:
-        req->cmd.xfer = cmd[4] | (cmd[3] << 8);
+    case RECEIVE_DIAGNOSTIC:
+    case SEND_DIAGNOSTIC:
+        cmd->xfer = buf[4] | (buf[3] << 8);
+        break;
+    case READ_CD:
+    case READ_BUFFER:
+    case WRITE_BUFFER:
+    case SEND_CUE_SHEET:
+        cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
+        break;
+    case PERSISTENT_RESERVE_OUT:
+        cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
         break;
+    case ERASE_12:
+        if (dev->type == TYPE_ROM) {
+            /* MMC command GET PERFORMANCE.  */
+            cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
+                                                    buf[10], buf[1] & 0x1f);
+        }
+        break;
+    case MECHANISM_STATUS:
+    case READ_DVD_STRUCTURE:
+    case SEND_DVD_STRUCTURE:
     case MAINTENANCE_OUT:
     case MAINTENANCE_IN:
-        if (req->dev->type == TYPE_ROM) {
+        if (dev->type == TYPE_ROM) {
             /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
-            req->cmd.xfer = cmd[9] | (cmd[8] << 8);
+            cmd->xfer = buf[9] | (buf[8] << 8);
         }
         break;
     }
     return 0;
 }
 
-static int scsi_req_stream_length(SCSIRequest *req, uint8_t *cmd)
+static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
 {
-    switch(cmd[0]) {
+    switch (buf[0]) {
     /* stream commands */
+    case ERASE_12:
+    case ERASE_16:
+        cmd->xfer = 0;
+        break;
     case READ_6:
     case READ_REVERSE:
     case RECOVER_BUFFERED_DATA:
     case WRITE_6:
-        req->cmd.len = 6;
-        req->cmd.xfer = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16);
-        if (cmd[1] & 0x01) /* fixed */
-            req->cmd.xfer *= req->dev->blocksize;
+        cmd->len = 6;
+        cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
+        if (buf[1] & 0x01) { /* fixed */
+            cmd->xfer *= dev->blocksize;
+        }
         break;
     case REWIND:
     case START_STOP:
-        req->cmd.len = 6;
-        req->cmd.xfer = 0;
+        cmd->len = 6;
+        cmd->xfer = 0;
+        break;
+    case SPACE_16:
+        cmd->xfer = buf[13] | (buf[12] << 8);
+        break;
+    case READ_POSITION:
+        cmd->xfer = buf[8] | (buf[7] << 8);
+        break;
+    case FORMAT_UNIT:
+        cmd->xfer = buf[4] | (buf[3] << 8);
         break;
     /* generic commands */
     default:
-        return scsi_req_length(req, cmd);
+        return scsi_req_length(cmd, dev, buf);
     }
     return 0;
 }
 
-static void scsi_req_xfer_mode(SCSIRequest *req)
+static void scsi_cmd_xfer_mode(SCSICommand *cmd)
 {
-    switch (req->cmd.buf[0]) {
+    switch (cmd->buf[0]) {
     case WRITE_6:
     case WRITE_10:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_12:
     case WRITE_VERIFY_12:
     case WRITE_16:
@@ -322,53 +878,45 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case SEARCH_HIGH:
     case SEARCH_LOW:
     case UPDATE_BLOCK:
-    case WRITE_LONG:
-    case WRITE_SAME:
+    case WRITE_LONG_10:
+    case WRITE_SAME_10:
     case SEARCH_HIGH_12:
     case SEARCH_EQUAL_12:
     case SEARCH_LOW_12:
-    case SET_WINDOW:
     case MEDIUM_SCAN:
     case SEND_VOLUME_TAG:
-    case WRITE_LONG_2:
+    case SEND_CUE_SHEET:
+    case SEND_DVD_STRUCTURE:
     case PERSISTENT_RESERVE_OUT:
     case MAINTENANCE_OUT:
-        req->cmd.mode = SCSI_XFER_TO_DEV;
+        cmd->mode = SCSI_XFER_TO_DEV;
         break;
     default:
-        if (req->cmd.xfer)
-            req->cmd.mode = SCSI_XFER_FROM_DEV;
+        if (cmd->xfer)
+            cmd->mode = SCSI_XFER_FROM_DEV;
         else {
-            req->cmd.mode = SCSI_XFER_NONE;
+            cmd->mode = SCSI_XFER_NONE;
         }
         break;
     }
 }
 
-static uint64_t scsi_req_lba(SCSIRequest *req)
+static uint64_t scsi_cmd_lba(SCSICommand *cmd)
 {
-    uint8_t *buf = req->cmd.buf;
+    uint8_t *buf = cmd->buf;
     uint64_t lba;
 
     switch (buf[0] >> 5) {
     case 0:
-        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
-              (((uint64_t) buf[1] & 0x1f) << 16);
+        lba = ldl_be_p(&buf[0]) & 0x1fffff;
         break;
     case 1:
     case 2:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+    case 5:
+        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
         break;
     case 4:
-        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
-              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
-              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
-              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
-        break;
-    case 5:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+        lba = ldq_be_p(&buf[2]);
         break;
     default:
         lba = -1;
@@ -377,37 +925,196 @@ static uint64_t scsi_req_lba(SCSIRequest *req)
     return lba;
 }
 
-int scsi_req_parse(SCSIRequest *req, uint8_t *buf)
+int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
 {
     int rc;
 
-    if (req->dev->type == TYPE_TAPE) {
-        rc = scsi_req_stream_length(req, buf);
+    if (dev->type == TYPE_TAPE) {
+        rc = scsi_req_stream_length(cmd, dev, buf);
     } else {
-        rc = scsi_req_length(req, buf);
+        rc = scsi_req_length(cmd, dev, buf);
     }
     if (rc != 0)
         return rc;
 
-    memcpy(req->cmd.buf, buf, req->cmd.len);
-    scsi_req_xfer_mode(req);
-    req->cmd.lba = scsi_req_lba(req);
+    memcpy(cmd->buf, buf, cmd->len);
+    scsi_cmd_xfer_mode(cmd);
+    cmd->lba = scsi_cmd_lba(cmd);
     return 0;
 }
 
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+const struct SCSISense sense_code_NO_SENSE = {
+    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
+};
+
+/* LUN not ready, Manual intervention required */
+const struct SCSISense sense_code_LUN_NOT_READY = {
+    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
+};
+
+/* LUN not ready, Medium not present */
+const struct SCSISense sense_code_NO_MEDIUM = {
+    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
+};
+
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x00
+};
+
+/* Hardware error, internal target failure */
+const struct SCSISense sense_code_TARGET_FAILURE = {
+    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
+};
+
+/* Illegal request, invalid command operation code */
+const struct SCSISense sense_code_INVALID_OPCODE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
+};
+
+/* Illegal request, LBA out of range */
+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in CDB */
+const struct SCSISense sense_code_INVALID_FIELD = {
+    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
+};
+
+/* Illegal request, LUN not supported */
+const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
+};
+
+/* Illegal request, Saving parameters not supported */
+const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
+};
+
+/* Illegal request, Incompatible medium installed */
+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
+    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
+};
+
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
+};
+
+/* Command aborted, I/O process terminated */
+const struct SCSISense sense_code_IO_ERROR = {
+    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
+};
+
+/* Command aborted, I_T Nexus loss occurred */
+const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
+    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
+};
+
+/* Command aborted, Logical Unit failure */
+const struct SCSISense sense_code_LUN_FAILURE = {
+    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
+};
+
+/* Unit attention, Power on, reset or bus device reset occurred */
+const struct SCSISense sense_code_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
+};
+
+/* Unit attention, No medium */
+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
+};
+
+/* Unit attention, Medium may have changed */
+const struct SCSISense sense_code_MEDIUM_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
+};
+
+/* Unit attention, Reported LUNs data has changed */
+const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
+};
+
+/* Unit attention, Device internal reset */
+const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
+};
+
+/*
+ * scsi_build_sense
+ *
+ * Convert between fixed and descriptor sense buffers
+ */
+int scsi_build_sense(uint8_t *in_buf, int in_len,
+                     uint8_t *buf, int len, bool fixed)
+{
+    bool fixed_in;
+    SCSISense sense;
+    if (!fixed && len < 8) {
+        return 0;
+    }
+
+    if (in_len == 0) {
+        sense.key = NO_SENSE;
+        sense.asc = 0;
+        sense.ascq = 0;
+    } else {
+        fixed_in = (in_buf[0] & 2) == 0;
+
+        if (fixed == fixed_in) {
+            memcpy(buf, in_buf, MIN(len, in_len));
+            return MIN(len, in_len);
+        }
+
+        if (fixed_in) {
+            sense.key = in_buf[2];
+            sense.asc = in_buf[12];
+            sense.ascq = in_buf[13];
+        } else {
+            sense.key = in_buf[1];
+            sense.asc = in_buf[2];
+            sense.ascq = in_buf[3];
+        }
+    }
+
+    memset(buf, 0, len);
+    if (fixed) {
+        /* Return fixed format sense buffer */
+        buf[0] = 0xf0;
+        buf[2] = sense.key;
+        buf[7] = 10;
+        buf[12] = sense.asc;
+        buf[13] = sense.ascq;
+        return MIN(len, 18);
+    } else {
+        /* Return descriptor format sense buffer */
+        buf[0] = 0x72;
+        buf[1] = sense.key;
+        buf[2] = sense.asc;
+        buf[3] = sense.ascq;
+        return 8;
+    }
+}
+
 static const char *scsi_command_name(uint8_t cmd)
 {
     static const char *names[] = {
         [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
-        [ REZERO_UNIT              ] = "REZERO_UNIT",
-        /* REWIND and REZERO_UNIT use the same operation code */
+        [ REWIND                   ] = "REWIND",
         [ REQUEST_SENSE            ] = "REQUEST_SENSE",
         [ FORMAT_UNIT              ] = "FORMAT_UNIT",
         [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
         [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS",
         [ READ_6                   ] = "READ_6",
         [ WRITE_6                  ] = "WRITE_6",
-        [ SEEK_6                   ] = "SEEK_6",
+        [ SET_CAPACITY             ] = "SET_CAPACITY",
         [ READ_REVERSE             ] = "READ_REVERSE",
         [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
         [ SPACE                    ] = "SPACE",
@@ -425,19 +1132,17 @@ static const char *scsi_command_name(uint8_t cmd)
         [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
         [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
         [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
-
-        [ SET_WINDOW               ] = "SET_WINDOW",
-        [ READ_CAPACITY            ] = "READ_CAPACITY",
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
         [ READ_10                  ] = "READ_10",
         [ WRITE_10                 ] = "WRITE_10",
         [ SEEK_10                  ] = "SEEK_10",
-        [ WRITE_VERIFY             ] = "WRITE_VERIFY",
-        [ VERIFY                   ] = "VERIFY",
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
+        [ VERIFY_10                ] = "VERIFY_10",
         [ SEARCH_HIGH              ] = "SEARCH_HIGH",
         [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
         [ SEARCH_LOW               ] = "SEARCH_LOW",
         [ SET_LIMITS               ] = "SET_LIMITS",
-        [ PRE_FETCH                ] = "PRE_FETCH",
+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
         /* READ_POSITION and PRE_FETCH use the same operation code */
         [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
         [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
@@ -448,11 +1153,14 @@ static const char *scsi_command_name(uint8_t cmd)
         [ WRITE_BUFFER             ] = "WRITE_BUFFER",
         [ READ_BUFFER              ] = "READ_BUFFER",
         [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
-        [ READ_LONG                ] = "READ_LONG",
-        [ WRITE_LONG               ] = "WRITE_LONG",
+        [ READ_LONG_10             ] = "READ_LONG_10",
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
         [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
-        [ WRITE_SAME               ] = "WRITE_SAME",
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
+        [ UNMAP                    ] = "UNMAP",
         [ READ_TOC                 ] = "READ_TOC",
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
         [ LOG_SELECT               ] = "LOG_SELECT",
         [ LOG_SENSE                ] = "LOG_SENSE",
         [ MODE_SELECT_10           ] = "MODE_SELECT_10",
@@ -461,27 +1169,51 @@ static const char *scsi_command_name(uint8_t cmd)
         [ MODE_SENSE_10            ] = "MODE_SENSE_10",
         [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
         [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
+        [ ATA_PASSTHROUGH          ] = "ATA_PASSTHROUGH",
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
+        [ READ_16                  ] = "READ_16",
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
+        [ WRITE_16                 ] = "WRITE_16",
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+        [ VERIFY_16                ] = "VERIFY_16",
+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
+        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
+        [ LOCATE_16                ] = "LOCATE_16",
+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
+        [ REPORT_LUNS              ] = "REPORT_LUNS",
+        [ BLANK                    ] = "BLANK",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
         [ WRITE_12                 ] = "WRITE_12",
+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
+        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
         [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+        [ VERIFY_12                ] = "VERIFY_12",
         [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
         [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
         [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
         [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
-        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG",
-        [ WRITE_LONG_2             ] = "WRITE_LONG_2",
-
-        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
-        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
-        [ READ_16                  ] = "READ_16",
-        [ WRITE_16                 ] = "WRITE_16",
-        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
-        [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN",
-        [ REPORT_LUNS              ] = "REPORT_LUNS",
-        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
+        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
+        [ READ_CD                  ] = "READ_CD",
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
         [ SET_CD_SPEED             ] = "SET_CD_SPEED",
-        [ BLANK                    ] = "BLANK",
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
     };
 
     if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
@@ -489,6 +1221,47 @@ static const char *scsi_command_name(uint8_t cmd)
     return names[cmd];
 }
 
+SCSIRequest *scsi_req_ref(SCSIRequest *req)
+{
+    req->refcount++;
+    return req;
+}
+
+void scsi_req_unref(SCSIRequest *req)
+{
+    if (--req->refcount == 0) {
+        if (req->ops->free_req) {
+            req->ops->free_req(req);
+        }
+        g_free(req);
+    }
+}
+
+/* Tell the device that we finished processing this chunk of I/O.  It
+   will start the next chunk or complete the command.  */
+void scsi_req_continue(SCSIRequest *req)
+{
+    trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
+    if (req->cmd.mode == SCSI_XFER_TO_DEV) {
+        req->ops->write_data(req);
+    } else {
+        req->ops->read_data(req);
+    }
+}
+
+/* Called by the devices when data is ready for the HBA.  The HBA should
+   start a DMA operation to read or fill the device's data buffer.
+   Once it completes, calling scsi_req_continue will restart I/O.  */
+void scsi_req_data(SCSIRequest *req, int len)
+{
+    if (req->io_canceled) {
+        trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
+    } else {
+        trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+        req->bus->info->transfer_data(req, len);
+    }
+}
+
 void scsi_req_print(SCSIRequest *req)
 {
     FILE *fp = stderr;
@@ -517,31 +1290,106 @@ void scsi_req_print(SCSIRequest *req)
     }
 }
 
-void scsi_req_complete(SCSIRequest *req)
+void scsi_req_complete(SCSIRequest *req, int status)
 {
-    assert(req->status != -1);
+    assert(req->status == -1);
+    req->status = status;
+
+    assert(req->sense_len < sizeof(req->sense));
+    if (status == GOOD) {
+        req->sense_len = 0;
+    }
+
+    if (req->sense_len) {
+        memcpy(req->dev->sense, req->sense, req->sense_len);
+        req->dev->sense_len = req->sense_len;
+        req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
+    } else {
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
+    }
+
+    /*
+     * Unit attention state is now stored in the device's sense buffer
+     * if the HBA didn't do autosense.  Clear the pending unit attention
+     * flags.
+     */
+    scsi_clear_unit_attention(req);
+
+    scsi_req_ref(req);
     scsi_req_dequeue(req);
-    req->bus->complete(req->bus, SCSI_REASON_DONE,
-                       req->tag,
-                       req->status);
+    req->bus->info->complete(req, req->status);
+    scsi_req_unref(req);
 }
 
-static char *scsibus_get_fw_dev_path(DeviceState *dev)
+void scsi_req_cancel(SCSIRequest *req)
 {
-    SCSIDevice *d = (SCSIDevice*)dev;
-    SCSIBus *bus = scsi_bus_from_device(d);
-    char path[100];
-    int i;
+    if (!req->enqueued) {
+        return;
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->io_canceled = true;
+    if (req->ops->cancel_io) {
+        req->ops->cancel_io(req);
+    }
+    if (req->bus->info->cancel) {
+        req->bus->info->cancel(req);
+    }
+    scsi_req_unref(req);
+}
 
-    for (i = 0; i < bus->ndev; i++) {
-        if (bus->devs[i] == d) {
-            break;
-        }
+void scsi_req_abort(SCSIRequest *req, int status)
+{
+    if (!req->enqueued) {
+        return;
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->io_canceled = true;
+    if (req->ops->cancel_io) {
+        req->ops->cancel_io(req);
     }
+    scsi_req_complete(req, status);
+    scsi_req_unref(req);
+}
 
-    assert(i != bus->ndev);
+void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
+{
+    SCSIRequest *req;
 
-    snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
+    while (!QTAILQ_EMPTY(&sdev->requests)) {
+        req = QTAILQ_FIRST(&sdev->requests);
+        scsi_req_cancel(req);
+    }
+    sdev->unit_attention = sense;
+}
+
+static char *scsibus_get_fw_dev_path(DeviceState *dev)
+{
+    SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+    char path[100];
+
+    snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
+             qdev_fw_name(dev), d->id, d->lun);
 
     return strdup(path);
 }
+
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
+{
+    DeviceState *qdev;
+    SCSIDevice *target_dev = NULL;
+
+    QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            if (dev->lun == lun) {
+                return dev;
+            }
+            target_dev = dev;
+        }
+    }
+    return target_dev;
+}
index 413cce07b5a4084d1fdd7d3bc931583600e4d311..354ed7b55baf3ab3c083fa63883bf6bf4e6d9ea7 100644 (file)
  */
 
 #define TEST_UNIT_READY       0x00
-#define REZERO_UNIT           0x01
+#define REWIND                0x01
 #define REQUEST_SENSE         0x03
 #define FORMAT_UNIT           0x04
 #define READ_BLOCK_LIMITS     0x05
 #define REASSIGN_BLOCKS       0x07
 #define READ_6                0x08
 #define WRITE_6               0x0a
-#define SEEK_6                0x0b
+#define SET_CAPACITY          0x0b
 #define READ_REVERSE          0x0f
 #define WRITE_FILEMARKS       0x10
 #define SPACE                 0x11
 #define RECEIVE_DIAGNOSTIC    0x1c
 #define SEND_DIAGNOSTIC       0x1d
 #define ALLOW_MEDIUM_REMOVAL  0x1e
-
-#define SET_WINDOW            0x24
-#define READ_CAPACITY         0x25
+#define READ_CAPACITY_10      0x25
 #define READ_10               0x28
 #define WRITE_10              0x2a
 #define SEEK_10               0x2b
-#define WRITE_VERIFY          0x2e
-#define VERIFY                0x2f
+#define LOCATE_10             0x2b
+#define WRITE_VERIFY_10       0x2e
+#define VERIFY_10             0x2f
 #define SEARCH_HIGH           0x30
 #define SEARCH_EQUAL          0x31
 #define SEARCH_LOW            0x32
 #define WRITE_BUFFER          0x3b
 #define READ_BUFFER           0x3c
 #define UPDATE_BLOCK          0x3d
-#define READ_LONG             0x3e
-#define WRITE_LONG            0x3f
+#define READ_LONG_10          0x3e
+#define WRITE_LONG_10         0x3f
 #define CHANGE_DEFINITION     0x40
-#define WRITE_SAME            0x41
+#define WRITE_SAME_10         0x41
+#define UNMAP                 0x42
 #define READ_TOC              0x43
+#define REPORT_DENSITY_SUPPORT 0x44
+#define GET_CONFIGURATION     0x46
+#define GET_EVENT_STATUS_NOTIFICATION 0x4a
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
+#define RESERVE_TRACK         0x53
 #define MODE_SELECT_10        0x55
 #define RESERVE_10            0x56
 #define RELEASE_10            0x57
 #define MODE_SENSE_10         0x5a
+#define SEND_CUE_SHEET        0x5d
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define VARLENGTH_CDB         0x7f
+#define WRITE_FILEMARKS_16    0x80
+#define ALLOW_OVERWRITE       0x82
+#define EXTENDED_COPY         0x83
+#define ATA_PASSTHROUGH       0x85
+#define ACCESS_CONTROL_IN     0x86
+#define ACCESS_CONTROL_OUT    0x87
+#define READ_16               0x88
+#define COMPARE_AND_WRITE     0x89
+#define WRITE_16              0x8a
+#define WRITE_VERIFY_16       0x8e
+#define VERIFY_16             0x8f
+#define PRE_FETCH_16          0x90
+#define SPACE_16              0x91
+#define SYNCHRONIZE_CACHE_16  0x91
+#define LOCATE_16             0x92
 #define WRITE_SAME_16         0x93
+#define ERASE_16              0x93
+#define SERVICE_ACTION_IN_16  0x9e
+#define WRITE_LONG_16         0x9f
+#define REPORT_LUNS           0xa0
+#define BLANK                 0xa1
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
+#define LOAD_UNLOAD           0xa6
+#define SET_READ_AHEAD        0xa7
 #define READ_12               0xa8
 #define WRITE_12              0xaa
+#define SERVICE_ACTION_IN_12  0xab
+#define ERASE_12              0xac
+#define READ_DVD_STRUCTURE    0xad
 #define WRITE_VERIFY_12       0xae
+#define VERIFY_12             0xaf
 #define SEARCH_HIGH_12        0xb0
 #define SEARCH_EQUAL_12       0xb1
 #define SEARCH_LOW_12         0xb2
 #define READ_ELEMENT_STATUS   0xb8
 #define SEND_VOLUME_TAG       0xb6
-#define WRITE_LONG_2          0xea
+#define READ_DEFECT_DATA_12   0xb7
+#define SET_CD_SPEED          0xbb
+#define MECHANISM_STATUS      0xbd
+#define READ_CD               0xbe
+#define SEND_DVD_STRUCTURE    0xbf
 
-/* from hw/scsi-generic.c */
-#define REWIND 0x01
-#define REPORT_DENSITY_SUPPORT 0x44
-#define GET_CONFIGURATION 0x46
-#define READ_16 0x88
-#define WRITE_16 0x8a
-#define WRITE_VERIFY_16 0x8e
-#define SERVICE_ACTION_IN 0x9e
-#define REPORT_LUNS 0xa0
-#define LOAD_UNLOAD 0xa6
-#define SET_CD_SPEED 0xbb
-#define BLANK 0xa1
+/*
+ * SERVICE ACTION IN subcodes
+ */
+#define SAI_READ_CAPACITY_16  0x10
 
 /*
  *  SAM Status codes
 
 #define TYPE_DISK           0x00
 #define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
 #define TYPE_PROCESSOR      0x03    /* HP scanners use this */
 #define TYPE_WORM           0x04    /* Treated as ROM by our system */
 #define TYPE_ROM            0x05
 #define TYPE_MOD            0x07    /* Magneto-optical disk -
                                     * - treated as TYPE_DISK */
 #define TYPE_MEDIUM_CHANGER 0x08
-#define TYPE_ENCLOSURE     0x0d    /* Enclosure Services Device */
+#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
+#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
+#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
+#define TYPE_OSD            0x11    /* Object-storage Device */
+#define TYPE_WLUN           0x1e    /* Well known LUN */
+#define TYPE_NOT_PRESENT    0x1f
+#define TYPE_INACTIVE       0x20
 #define TYPE_NO_LUN         0x7f
 
+/* Mode page codes for mode sense/set */
+#define MODE_PAGE_R_W_ERROR                   0x01
+#define MODE_PAGE_HD_GEOMETRY                 0x04
+#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
+#define MODE_PAGE_CACHING                     0x08
+#define MODE_PAGE_AUDIO_CTL                   0x0e
+#define MODE_PAGE_POWER                       0x1a
+#define MODE_PAGE_FAULT_FAIL                  0x1c
+#define MODE_PAGE_TO_PROTECT                  0x1d
+#define MODE_PAGE_CAPABILITIES                0x2a
+#define MODE_PAGE_ALLS                        0x3f
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+ * of MODE_PAGE_SENSE_POWER */
+#define MODE_PAGE_CDROM                       0x0d
+
+/* Event notification classes for GET EVENT STATUS NOTIFICATION */
+#define GESN_NO_EVENTS                0
+#define GESN_OPERATIONAL_CHANGE       1
+#define GESN_POWER_MANAGEMENT         2
+#define GESN_EXTERNAL_REQUEST         3
+#define GESN_MEDIA                    4
+#define GESN_MULTIPLE_HOSTS           5
+#define GESN_DEVICE_BUSY              6
+
+/* Event codes for MEDIA event status notification */
+#define MEC_NO_CHANGE                 0
+#define MEC_EJECT_REQUESTED           1
+#define MEC_NEW_MEDIA                 2
+#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
+#define MEC_MEDIA_CHANGED             4 /* only for media changers */
+#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
+#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
+
+#define MS_TRAY_OPEN                  1
+#define MS_MEDIA_PRESENT              2
+
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
index 488eedd2cd8b4988c137ad451d1aa671a936b2a0..673948c51f86c1ec70767c78b0593eca54800705 100644 (file)
@@ -12,7 +12,7 @@
  *  2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
  *                                 MODE SENSE response.
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  *
  * Note that this file only handles the SCSI architecture model and device
  * commands.  Emulation of interface/link layer protocols is handled by
@@ -37,352 +37,310 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi-defs.h"
 #include "sysemu.h"
 #include "blockdev.h"
+#include "block_int.h"
+
+#ifdef __linux
+#include <scsi/sg.h>
+#endif
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
 
-#define SCSI_REQ_STATUS_RETRY           0x01
-#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
-#define SCSI_REQ_STATUS_RETRY_READ      0x00
-#define SCSI_REQ_STATUS_RETRY_WRITE     0x02
-#define SCSI_REQ_STATUS_RETRY_FLUSH     0x04
-
 typedef struct SCSIDiskState SCSIDiskState;
 
-typedef struct SCSISense {
-    uint8_t key;
-} SCSISense;
-
 typedef struct SCSIDiskReq {
     SCSIRequest req;
-    /* ??? We should probably keep track of whether the data transfer is
-       a read or a write.  Currently we rely on the host getting it right.  */
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     uint64_t sector;
     uint32_t sector_count;
+    uint32_t buflen;
     struct iovec iov;
     QEMUIOVector qiov;
-    uint32_t status;
+    BlockAcctCookie acct;
 } SCSIDiskReq;
 
 struct SCSIDiskState
 {
     SCSIDevice qdev;
-    BlockDriverState *bs;
-    /* The qemu block layer uses a fixed 512 byte sector size.
-       This is the number of 512 byte blocks in a single scsi sector.  */
-    int cluster_size;
     uint32_t removable;
-    uint64_t max_lba;
+    bool media_changed;
+    bool media_event;
+    bool eject_request;
     QEMUBH *bh;
     char *version;
     char *serial;
-    SCSISense sense;
+    bool tray_open;
+    bool tray_locked;
 };
 
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
 
-static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
-        uint32_t lun)
+static void scsi_free_request(SCSIRequest *req)
 {
-    SCSIRequest *req;
-    SCSIDiskReq *r;
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
-    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
-    r = DO_UPCAST(SCSIDiskReq, req, req);
-    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
-    return r;
+    if (r->iov.iov_base) {
+        qemu_vfree(r->iov.iov_base);
+    }
 }
 
-static void scsi_remove_request(SCSIDiskReq *r)
+/* Helper function for command completion with sense.  */
+static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
 {
-    qemu_vfree(r->iov.iov_base);
-    scsi_req_free(&r->req);
+    DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
+            r->req.tag, sense.key, sense.asc, sense.ascq);
+    scsi_req_build_sense(&r->req, sense);
+    scsi_req_complete(&r->req, CHECK_CONDITION);
 }
 
-static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
+/* Cancel a pending data transfer.  */
+static void scsi_cancel_io(SCSIRequest *req)
 {
-    return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
-}
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
-static void scsi_disk_clear_sense(SCSIDiskState *s)
-{
-    memset(&s->sense, 0, sizeof(s->sense));
-}
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
 
-static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key)
-{
-    s->sense.key = key;
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it the moment scsi_req_cancel is called, independent of whether
+         * bdrv_aio_cancel completes the request or not.  */
+        scsi_req_unref(&r->req);
+    }
+    r->req.aiocb = NULL;
 }
 
-static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code)
+static uint32_t scsi_init_iovec(SCSIDiskReq *r)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
-    r->req.status = status;
-    scsi_disk_set_sense(s, sense_code);
-}
-
-/* Helper function for command completion.  */
-static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
-{
-    DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
-            r->req.tag, status, sense);
-    scsi_req_set_status(r, status, sense);
-    scsi_req_complete(&r->req);
-    scsi_remove_request(r);
-}
-
-/* Cancel a pending data transfer.  */
-static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIDiskReq *r;
-    DPRINTF("Cancel tag=0x%x\n", tag);
-    r = scsi_find_request(s, tag);
-    if (r) {
-        if (r->req.aiocb)
-            bdrv_aio_cancel(r->req.aiocb);
-        r->req.aiocb = NULL;
-        scsi_remove_request(r);
+    if (!r->iov.iov_base) {
+        r->buflen = SCSI_DMA_BUF_SIZE;
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
     }
+    r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    return r->qiov.size / 512;
 }
 
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     int n;
 
-    r->req.aiocb = NULL;
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
 
     if (ret) {
-        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
-            return;
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
         }
     }
 
-    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
 
-    n = r->iov.iov_len / 512;
+    n = r->qiov.size / 512;
     r->sector += n;
     r->sector_count -= n;
-    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
+    scsi_req_data(&r->req, r->qiov.size);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
+static void scsi_flush_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
 
-static void scsi_read_request(SCSIDiskReq *r)
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIRequest *req)
 {
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
     if (r->sector_count == (uint32_t)-1) {
         DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
         r->sector_count = 0;
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
+        scsi_req_data(&r->req, r->iov.iov_len);
         return;
     }
     DPRINTF("Read sector_count=%d\n", r->sector_count);
     if (r->sector_count == 0) {
-        scsi_command_complete(r, GOOD, NO_SENSE);
+        /* This also clears the sense buffer for REQUEST SENSE.  */
+        scsi_req_complete(&r->req, GOOD);
         return;
     }
 
     /* No data transfer may already be in progress */
     assert(r->req.aiocb == NULL);
 
-    n = r->sector_count;
-    if (n > SCSI_DMA_BUF_SIZE / 512)
-        n = SCSI_DMA_BUF_SIZE / 512;
-
-    r->iov.iov_len = n * 512;
-    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-    r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
-                              scsi_read_complete, r);
-    if (r->req.aiocb == NULL) {
-        scsi_read_complete(r, -EIO);
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_read_complete(r, -EINVAL);
+        return;
     }
-}
 
-/* Read more data from scsi device into buffer.  */
-static void scsi_read_data(SCSIDevice *d, uint32_t tag)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIDiskReq *r;
-
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad read tag 0x%x\n", tag);
-        /* ??? This is the wrong error.  */
-        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
+    if (s->tray_open) {
+        scsi_read_complete(r, -ENOMEDIUM);
         return;
     }
 
-    scsi_read_request(r);
+    n = scsi_init_iovec(r);
+    bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+    r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                              scsi_read_complete, r);
+    if (r->req.aiocb == NULL) {
+        scsi_read_complete(r, -EIO);
+    }
 }
 
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+/*
+ * scsi_handle_rw_error has two return values.  0 means that the error
+ * must be ignored, 1 means that the error has been processed and the
+ * caller should not do anything else for this request.  Note that
+ * scsi_handle_rw_error always manages its reference counts, independent
+ * of the return value.
+ */
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
 {
-    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
+    int is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+    BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
 
     if (action == BLOCK_ERR_IGNORE) {
-        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read);
         return 0;
     }
 
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
 
-        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
-        r->status |= SCSI_REQ_STATUS_RETRY | type;
-
-        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(0);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
+        vm_stop(RUN_STATE_IO_ERROR);
+        bdrv_iostatus_set_err(s->qdev.conf.bs, error);
+        scsi_req_retry(&r->req);
     } else {
-        if (type == SCSI_REQ_STATUS_RETRY_READ) {
-            r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
+        switch (error) {
+        case ENOMEDIUM:
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            break;
+        case ENOMEM:
+            scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
+            break;
+        case EINVAL:
+            scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+            break;
+        default:
+            scsi_check_condition(r, SENSE_CODE(IO_ERROR));
+            break;
         }
-        scsi_command_complete(r, CHECK_CONDITION,
-                HARDWARE_ERROR);
-        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read);
     }
-
     return 1;
 }
 
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    uint32_t len;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
-    r->req.aiocb = NULL;
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
 
     if (ret) {
-        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
-            return;
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
         }
     }
 
-    n = r->iov.iov_len / 512;
+    n = r->qiov.size / 512;
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
-        scsi_command_complete(r, GOOD, NO_SENSE);
+        scsi_req_complete(&r->req, GOOD);
     } else {
-        len = r->sector_count * 512;
-        if (len > SCSI_DMA_BUF_SIZE) {
-            len = SCSI_DMA_BUF_SIZE;
-        }
-        r->iov.iov_len = len;
-        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
+        scsi_init_iovec(r);
+        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
+        scsi_req_data(&r->req, r->qiov.size);
+    }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
     }
 }
 
-static void scsi_write_request(SCSIDiskReq *r)
+static void scsi_write_data(SCSIRequest *req)
 {
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
     /* No data transfer may already be in progress */
     assert(r->req.aiocb == NULL);
 
-    n = r->iov.iov_len / 512;
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_write_complete(r, -EINVAL);
+        return;
+    }
+
+    n = r->qiov.size / 512;
     if (n) {
-        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-        r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
-                                   scsi_write_complete, r);
+        if (s->tray_open) {
+            scsi_write_complete(r, -ENOMEDIUM);
+            return;
+        }
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
+        r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                                       scsi_write_complete, r);
         if (r->req.aiocb == NULL) {
-            scsi_write_complete(r, -EIO);
+            scsi_write_complete(r, -ENOMEM);
         }
     } else {
-        /* Invoke completion routine to fetch data from host.  */
+        /* Called for the first time.  Ask the driver to send us more data.  */
         scsi_write_complete(r, 0);
     }
 }
 
-/* Write data to a scsi device.  Returns nonzero on failure.
-   The transfer may complete asynchronously.  */
-static int scsi_write_data(SCSIDevice *d, uint32_t tag)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIDiskReq *r;
-
-    DPRINTF("Write data tag=0x%x\n", tag);
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad write tag 0x%x\n", tag);
-        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
-        return 1;
-    }
-
-    scsi_write_request(r);
-
-    return 0;
-}
-
-static void scsi_dma_restart_bh(void *opaque)
-{
-    SCSIDiskState *s = opaque;
-    SCSIRequest *req;
-    SCSIDiskReq *r;
-
-    qemu_bh_delete(s->bh);
-    s->bh = NULL;
-
-    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
-        r = DO_UPCAST(SCSIDiskReq, req, req);
-        if (r->status & SCSI_REQ_STATUS_RETRY) {
-            int status = r->status;
-            int ret;
-
-            r->status &=
-                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
-
-            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
-            case SCSI_REQ_STATUS_RETRY_READ:
-                scsi_read_request(r);
-                break;
-            case SCSI_REQ_STATUS_RETRY_WRITE:
-                scsi_write_request(r);
-                break;
-            case SCSI_REQ_STATUS_RETRY_FLUSH:
-                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
-                if (ret == 0) {
-                    scsi_command_complete(r, GOOD, NO_SENSE);
-                }
-            }
-        }
-    }
-}
-
-static void scsi_dma_restart_cb(void *opaque, int running, int reason)
-{
-    SCSIDiskState *s = opaque;
-
-    if (!running)
-        return;
-
-    if (!s->bh) {
-        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
-        qemu_bh_schedule(s->bh);
-    }
-}
-
 /* Return a pointer to the data buffer.  */
-static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
+static uint8_t *scsi_get_buf(SCSIRequest *req)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIDiskReq *r;
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad buffer tag 0x%x\n", tag);
-        return NULL;
-    }
     return (uint8_t *)r->iov.iov_base;
 }
 
@@ -406,11 +364,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             return -1;
         }
 
-        if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
-            outbuf[buflen++] = 5;
-        } else {
-            outbuf[buflen++] = 0;
-        }
+        outbuf[buflen++] = s->qdev.type & 0x1f;
         outbuf[buflen++] = page_code ; // this page
         outbuf[buflen++] = 0x00;
 
@@ -422,9 +376,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
                     "buffer size %zd\n", req->cmd.xfer);
             pages = buflen++;
             outbuf[buflen++] = 0x00; // list of supported pages (this page)
-            outbuf[buflen++] = 0x80; // unit serial number
+            if (s->serial) {
+                outbuf[buflen++] = 0x80; // unit serial number
+            }
             outbuf[buflen++] = 0x83; // device identification
-            if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) {
+            if (s->qdev.type == TYPE_DISK) {
                 outbuf[buflen++] = 0xb0; // block limits
                 outbuf[buflen++] = 0xb2; // thin provisioning
             }
@@ -433,12 +389,20 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         }
         case 0x80: /* Device serial number, optional */
         {
-            int l = strlen(s->serial);
+            int l;
 
-            if (l > req->cmd.xfer)
+            if (!s->serial) {
+                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
+                return -1;
+            }
+
+            l = strlen(s->serial);
+            if (l > req->cmd.xfer) {
                 l = req->cmd.xfer;
-            if (l > 20)
+            }
+            if (l > 20) {
                 l = 20;
+            }
 
             DPRINTF("Inquiry EVPD[Serial number] "
                     "buffer size %zd\n", req->cmd.xfer);
@@ -451,10 +415,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         case 0x83: /* Device identification page, mandatory */
         {
             int max_len = 255 - 8;
-            int id_len = strlen(bdrv_get_device_name(s->bs));
+            int id_len = strlen(bdrv_get_device_name(s->qdev.conf.bs));
 
-            if (id_len > max_len)
+            if (id_len > max_len) {
                 id_len = max_len;
+            }
             DPRINTF("Inquiry EVPD[Device identification] "
                     "buffer size %zd\n", req->cmd.xfer);
 
@@ -464,7 +429,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             outbuf[buflen++] = 0;   // reserved
             outbuf[buflen++] = id_len; // length of data following
 
-            memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
+            memcpy(outbuf+buflen, bdrv_get_device_name(s->qdev.conf.bs), id_len);
             buflen += id_len;
             break;
         }
@@ -477,7 +442,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             unsigned int opt_io_size =
                     s->qdev.conf.opt_io_size / s->qdev.blocksize;
 
-            if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+            if (s->qdev.type == TYPE_ROM) {
                 DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
                         page_code);
                 return -1;
@@ -537,23 +502,16 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     }
 
     buflen = req->cmd.xfer;
-    if (buflen > SCSI_MAX_INQUIRY_LEN)
+    if (buflen > SCSI_MAX_INQUIRY_LEN) {
         buflen = SCSI_MAX_INQUIRY_LEN;
-
-    memset(outbuf, 0, buflen);
-
-    if (req->lun || req->cmd.buf[1] >> 5) {
-        outbuf[0] = 0x7f;      /* LUN not supported */
-        return buflen;
     }
+    memset(outbuf, 0, buflen);
 
-    if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
-        outbuf[0] = 5;
-        outbuf[1] = 0x80;
+    outbuf[0] = s->qdev.type & 0x1f;
+    outbuf[1] = s->removable ? 0x80 : 0;
+    if (s->qdev.type == TYPE_ROM) {
         memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
     } else {
-        outbuf[0] = 0;
-        outbuf[1] = s->removable ? 0x80 : 0;
         memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
     }
     memcpy(&outbuf[8], "QEMU    ", 8);
@@ -577,16 +535,254 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     }
 
     /* Sync data transfer and TCQ.  */
-    outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
+    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
     return buflen;
 }
 
-static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+static inline bool media_is_dvd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    return nb_sectors > CD_MAX_SECTORS;
+}
+
+static inline bool media_is_cd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    return nb_sectors <= CD_MAX_SECTORS;
+}
+
+static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
+                                   uint8_t *outbuf)
+{
+    static const int rds_caps_size[5] = {
+        [0] = 2048 + 4,
+        [1] = 4 + 4,
+        [3] = 188 + 4,
+        [4] = 2048 + 4,
+    };
+
+    uint8_t media = r->req.cmd.buf[1];
+    uint8_t layer = r->req.cmd.buf[6];
+    uint8_t format = r->req.cmd.buf[7];
+    int size = -1;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if (media != 0) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return -1;
+    }
+
+    if (format != 0xff) {
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            return -1;
+        }
+        if (media_is_cd(s)) {
+            scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
+            return -1;
+        }
+        if (format >= ARRAY_SIZE(rds_caps_size)) {
+            return -1;
+        }
+        size = rds_caps_size[format];
+        memset(outbuf, 0, size);
+    }
+
+    switch (format) {
+    case 0x00: {
+        /* Physical format information */
+        uint64_t nb_sectors;
+        if (layer != 0) {
+            goto fail;
+        }
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+
+        outbuf[4] = 1;   /* DVD-ROM, part version 1 */
+        outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+        outbuf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+        outbuf[7] = 0;   /* default densities */
+
+        stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
+        stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
+        break;
+    }
+
+    case 0x01: /* DVD copyright information, all zeros */
+        break;
+
+    case 0x03: /* BCA information - invalid field for no BCA info */
+        return -1;
+
+    case 0x04: /* DVD disc manufacturing information, all zeros */
+        break;
+
+    case 0xff: { /* List capabilities */
+        int i;
+        size = 4;
+        for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
+            if (!rds_caps_size[i]) {
+                continue;
+            }
+            outbuf[size] = i;
+            outbuf[size + 1] = 0x40; /* Not writable, readable */
+            stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
+            size += 4;
+        }
+        break;
+     }
+
+    default:
+        return -1;
+    }
+
+    /* Size of buffer, not including 2 byte size field */
+    stw_be_p(outbuf, size - 2);
+    return size;
+
+fail:
+    return -1;
+}
+
+static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
+{
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* Event notification descriptor */
+    event_code = MEC_NO_CHANGE;
+    if (media_status != MS_TRAY_OPEN) {
+        if (s->media_event) {
+            event_code = MEC_NEW_MEDIA;
+            s->media_event = false;
+        } else if (s->eject_request) {
+            event_code = MEC_EJECT_REQUESTED;
+            s->eject_request = false;
+        }
+    }
+
+    outbuf[0] = event_code;
+    outbuf[1] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    outbuf[2] = 0;
+    outbuf[3] = 0;
+    return 4;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
+                                              uint8_t *outbuf)
+{
+    int size;
+    uint8_t *buf = r->req.cmd.buf;
+    uint8_t notification_class_request = buf[4];
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if ((buf[1] & 1) == 0) {
+        /* asynchronous */
+        return -1;
+    }
+
+    size = 4;
+    outbuf[0] = outbuf[1] = 0;
+    outbuf[3] = 1 << GESN_MEDIA; /* supported events */
+    if (notification_class_request & (1 << GESN_MEDIA)) {
+        outbuf[2] = GESN_MEDIA;
+        size += scsi_event_status_media(s, &outbuf[size]);
+    } else {
+        outbuf[2] = 0x80;
+    }
+    stw_be_p(outbuf, size - 4);
+    return size;
+}
+
+static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
+{
+    int current;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM;
+    memset(outbuf, 0, 40);
+    stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
+    stw_be_p(&outbuf[6], current);
+    /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
+    outbuf[10] = 0x03; /* persistent, current */
+    outbuf[11] = 8; /* two profiles */
+    stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
+    outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
+    stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
+    outbuf[18] = (current == MMC_PROFILE_CD_ROM);
+    /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
+    stw_be_p(&outbuf[20], 1);
+    outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[23] = 8;
+    stl_be_p(&outbuf[24], 1); /* SCSI */
+    outbuf[28] = 1; /* DBE = 1, mandatory */
+    /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
+    stw_be_p(&outbuf[32], 3);
+    outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[35] = 4;
+    outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
+    /* TODO: Random readable, CD read, DVD read, drive serial number,
+       power management */
+    return 40;
+}
+
+static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
+{
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    memset(outbuf, 0, 8);
+    outbuf[5] = 1; /* CD-ROM */
+    return 8;
+}
+
+static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
                            int page_control)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    BlockDriverState *bdrv = s->bs;
+    static const int mode_sense_valid[0x3f] = {
+        [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
+        [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
+        [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_R_W_ERROR]              = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
+        [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
+    };
+
+    BlockDriverState *bdrv = s->qdev.conf.bs;
     int cylinders, heads, secs;
+    uint8_t *p = *p_outbuf;
+
+    if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
+        return -1;
+    }
+
+    p[0] = page;
 
     /*
      * If Changeable Values are requested, a mask denoting those mode parameters
@@ -595,14 +791,13 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
      * The buffer was already menset to zero by the caller of this function.
      */
     switch (page) {
-    case 4: /* Rigid disk device geometry page. */
-        p[0] = 4;
+    case MODE_PAGE_HD_GEOMETRY:
         p[1] = 0x16;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         /* if a geometry hint is available, use it */
-        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
+        bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
         p[2] = (cylinders >> 16) & 0xff;
         p[3] = (cylinders >> 8) & 0xff;
         p[4] = cylinders & 0xff;
@@ -625,22 +820,21 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         /* Medium rotation rate [rpm], 5400 rpm */
         p[20] = (5400 >> 8) & 0xff;
         p[21] = 5400 & 0xff;
-        return p[1] + 2;
+        break;
 
-    case 5: /* Flexible disk device geometry page. */
-        p[0] = 5;
+    case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
         p[1] = 0x1e;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         /* Transfer rate [kbit/s], 5Mbit/s */
         p[2] = 5000 >> 8;
         p[3] = 5000 & 0xff;
         /* if a geometry hint is available, use it */
-        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
+        bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
         p[4] = heads & 0xff;
         p[5] = secs & 0xff;
-        p[6] = s->cluster_size * 2;
+        p[6] = s->qdev.blocksize >> 8;
         p[8] = (cylinders >> 8) & 0xff;
         p[9] = cylinders & 0xff;
         /* Write precomp start cylinder, disabled */
@@ -664,80 +858,93 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         /* Medium rotation rate [rpm], 5400 rpm */
         p[28] = (5400 >> 8) & 0xff;
         p[29] = 5400 & 0xff;
-        return p[1] + 2;
+        break;
 
-    case 8: /* Caching page.  */
+    case MODE_PAGE_CACHING:
         p[0] = 8;
         p[1] = 0x12;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
-        if (bdrv_enable_write_cache(s->bs)) {
+        if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
             p[2] = 4; /* WCE */
         }
-        return p[1] + 2;
+        break;
 
-    case 0x2a: /* CD Capabilities and Mechanical Status page. */
-        if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
-            return 0;
-        p[0] = 0x2a;
+    case MODE_PAGE_R_W_ERROR:
+        p[1] = 10;
+        p[2] = 0x80; /* Automatic Write Reallocation Enabled */
+        if (s->qdev.type == TYPE_ROM) {
+            p[3] = 0x20; /* Read Retry Count */
+        }
+        break;
+
+    case MODE_PAGE_AUDIO_CTL:
+        p[1] = 14;
+        break;
+
+    case MODE_PAGE_CAPABILITIES:
         p[1] = 0x14;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
-        p[2] = 3; // CD-R & CD-RW read
-        p[3] = 0; // Writing not supported
+
+        p[2] = 0x3b; /* CD-R & CD-RW read */
+        p[3] = 0; /* Writing not supported */
         p[4] = 0x7f; /* Audio, composite, digital out,
                         mode 2 form 1&2, multi session */
         p[5] = 0xff; /* CD DA, DA accurate, RW supported,
                         RW corrected, C2 errors, ISRC,
                         UPC, Bar code */
-        p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0);
+        p[6] = 0x2d | (s->tray_locked ? 2 : 0);
         /* Locking supported, jumper present, eject, tray */
         p[7] = 0; /* no volume & mute control, no
                      changer */
-        p[8] = (50 * 176) >> 8; // 50x read speed
+        p[8] = (50 * 176) >> 8; /* 50x read speed */
         p[9] = (50 * 176) & 0xff;
-        p[10] = 0 >> 8; // No volume
-        p[11] = 0 & 0xff;
-        p[12] = 2048 >> 8; // 2M buffer
+        p[10] = 2 >> 8; /* Two volume levels */
+        p[11] = 2 & 0xff;
+        p[12] = 2048 >> 8; /* 2M buffer */
         p[13] = 2048 & 0xff;
-        p[14] = (16 * 176) >> 8; // 16x read speed current
+        p[14] = (16 * 176) >> 8; /* 16x read speed current */
         p[15] = (16 * 176) & 0xff;
-        p[18] = (16 * 176) >> 8; // 16x write speed
+        p[18] = (16 * 176) >> 8; /* 16x write speed */
         p[19] = (16 * 176) & 0xff;
-        p[20] = (16 * 176) >> 8; // 16x write speed current
+        p[20] = (16 * 176) >> 8; /* 16x write speed current */
         p[21] = (16 * 176) & 0xff;
-        return p[1] + 2;
+        break;
 
     default:
-        return 0;
+        return -1;
     }
+
+    *p_outbuf += p[1] + 2;
+    return p[1] + 2;
 }
 
-static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
+static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint64_t nb_sectors;
-    int page, dbd, buflen, page_control;
+    int page, dbd, buflen, ret, page_control;
     uint8_t *p;
     uint8_t dev_specific_param;
 
-    dbd = req->cmd.buf[1]  & 0x8;
-    page = req->cmd.buf[2] & 0x3f;
-    page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+    dbd = r->req.cmd.buf[1]  & 0x8;
+    page = r->req.cmd.buf[2] & 0x3f;
+    page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
     DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
-        (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
-    memset(outbuf, 0, req->cmd.xfer);
+        (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
+    memset(outbuf, 0, r->req.cmd.xfer);
     p = outbuf;
 
-    if (bdrv_is_read_only(s->bs)) {
+    if (bdrv_is_read_only(s->qdev.conf.bs)) {
         dev_specific_param = 0x80; /* Readonly.  */
     } else {
         dev_specific_param = 0x00;
     }
 
-    if (req->cmd.buf[0] == MODE_SENSE) {
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
         p[1] = 0; /* Default media type.  */
         p[2] = dev_specific_param;
         p[3] = 0; /* Block descriptor length.  */
@@ -749,44 +956,44 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
         p += 8;
     }
 
-    bdrv_get_geometry(s->bs, &nb_sectors);
-    if (!dbd && nb_sectors) {
-        if (req->cmd.buf[0] == MODE_SENSE) {
+    /* MMC prescribes that CD/DVD drives have no block descriptors.  */
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
+        if (r->req.cmd.buf[0] == MODE_SENSE) {
             outbuf[3] = 8; /* Block descriptor length  */
         } else { /* MODE_SENSE_10 */
             outbuf[7] = 8; /* Block descriptor length  */
         }
-        nb_sectors /= s->cluster_size;
-        if (nb_sectors > 0xffffff)
+        nb_sectors /= (s->qdev.blocksize / 512);
+        if (nb_sectors > 0xffffff) {
             nb_sectors = 0;
+        }
         p[0] = 0; /* media density code */
         p[1] = (nb_sectors >> 16) & 0xff;
         p[2] = (nb_sectors >> 8) & 0xff;
         p[3] = nb_sectors & 0xff;
         p[4] = 0; /* reserved */
         p[5] = 0; /* bytes 5-7 are the sector size in bytes */
-        p[6] = s->cluster_size * 2;
+        p[6] = s->qdev.blocksize >> 8;
         p[7] = 0;
         p += 8;
     }
 
-    if (page_control == 3) { /* Saved Values */
-        return -1; /* ILLEGAL_REQUEST */
+    if (page_control == 3) {
+        /* Saved Values */
+        scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
+        return -1;
     }
 
-    switch (page) {
-    case 0x04:
-    case 0x05:
-    case 0x08:
-    case 0x2a:
-        p += mode_sense_page(req, page, p, page_control);
-        break;
-    case 0x3f:
-        p += mode_sense_page(req, 0x08, p, page_control);
-        p += mode_sense_page(req, 0x2a, p, page_control);
-        break;
-    default:
-        return -1; /* ILLEGAL_REQUEST */
+    if (page == 0x3f) {
+        for (page = 0; page <= 0x3e; page++) {
+            mode_sense_page(s, page, &p, page_control);
+        }
+    } else {
+        ret = mode_sense_page(s, page, &p, page_control);
+        if (ret == -1) {
+            return -1;
+        }
     }
 
     buflen = p - outbuf;
@@ -795,14 +1002,15 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
      * following data that is available to be transferred. The mode data
      * length does not include itself.
      */
-    if (req->cmd.buf[0] == MODE_SENSE) {
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
         outbuf[0] = buflen - 1;
     } else { /* MODE_SENSE_10 */
         outbuf[0] = ((buflen - 2) >> 8) & 0xff;
         outbuf[1] = (buflen - 2) & 0xff;
     }
-    if (buflen > req->cmd.xfer)
-        buflen = req->cmd.xfer;
+    if (buflen > r->req.cmd.xfer) {
+        buflen = r->req.cmd.xfer;
+    }
     return buflen;
 }
 
@@ -815,9 +1023,9 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     msf = req->cmd.buf[1] & 2;
     format = req->cmd.buf[2] & 0xf;
     start_track = req->cmd.buf[6];
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
-    nb_sectors /= s->cluster_size;
+    nb_sectors /= s->qdev.blocksize / 512;
     switch (format) {
     case 0:
         toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
@@ -836,135 +1044,187 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     default:
         return -1;
     }
-    if (toclen > req->cmd.xfer)
+    if (toclen > req->cmd.xfer) {
         toclen = req->cmd.xfer;
+    }
     return toclen;
 }
 
-static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
+static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    bool start = req->cmd.buf[4] & 1;
+    bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+
+    if (s->qdev.type == TYPE_ROM && loej) {
+        if (!start && !s->tray_open && s->tray_locked) {
+            scsi_check_condition(r,
+                                 bdrv_is_inserted(s->qdev.conf.bs)
+                                 ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
+                                 : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
+            return -1;
+        }
+        bdrv_eject(s->qdev.conf.bs, !start);
+        s->tray_open = !start;
+    }
+    return 0;
+}
+
+static int scsi_disk_emulate_command(SCSIDiskReq *r)
 {
     SCSIRequest *req = &r->req;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
+    uint8_t *outbuf;
     int buflen = 0;
-    int ret;
 
+    if (!r->iov.iov_base) {
+        /*
+         * FIXME: we shouldn't return anything bigger than 4k, but the code
+         * requires the buffer to be as big as req->cmd.xfer in several
+         * places.  So, do not allow CDBs with a very large ALLOCATION
+         * LENGTH.  The real fix would be to modify scsi_read_data and
+         * dma_buf_read, so that they return data beyond the buflen
+         * as all zeros.
+         */
+        if (req->cmd.xfer > 65536) {
+            goto illegal_request;
+        }
+        r->buflen = MAX(4096, req->cmd.xfer);
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
+    }
+
+    outbuf = r->iov.iov_base;
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
-        if (!bdrv_is_inserted(s->bs))
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
             goto not_ready;
-       break;
-    case REQUEST_SENSE:
-        if (req->cmd.xfer < 4)
-            goto illegal_request;
-        memset(outbuf, 0, 4);
-        buflen = 4;
-        if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) {
-            memset(outbuf, 0, 18);
-            buflen = 18;
-            outbuf[7] = 10;
-            /* asc 0x3a, ascq 0: Medium not present */
-            outbuf[12] = 0x3a;
-            outbuf[13] = 0;
-        }
-        outbuf[0] = 0xf0;
-        outbuf[1] = 0;
-        outbuf[2] = s->sense.key;
-        scsi_disk_clear_sense(s);
+        }
         break;
     case INQUIRY:
         buflen = scsi_disk_emulate_inquiry(req, outbuf);
-        if (buflen < 0)
+        if (buflen < 0) {
             goto illegal_request;
-       break;
+        }
+        break;
     case MODE_SENSE:
     case MODE_SENSE_10:
-        buflen = scsi_disk_emulate_mode_sense(req, outbuf);
-        if (buflen < 0)
+        buflen = scsi_disk_emulate_mode_sense(r, outbuf);
+        if (buflen < 0) {
             goto illegal_request;
+        }
         break;
     case READ_TOC:
         buflen = scsi_disk_emulate_read_toc(req, outbuf);
-        if (buflen < 0)
+        if (buflen < 0) {
             goto illegal_request;
+        }
         break;
     case RESERVE:
-        if (req->cmd.buf[1] & 1)
+        if (req->cmd.buf[1] & 1) {
             goto illegal_request;
+        }
         break;
     case RESERVE_10:
-        if (req->cmd.buf[1] & 3)
+        if (req->cmd.buf[1] & 3) {
             goto illegal_request;
+        }
         break;
     case RELEASE:
-        if (req->cmd.buf[1] & 1)
+        if (req->cmd.buf[1] & 1) {
             goto illegal_request;
+        }
         break;
     case RELEASE_10:
-        if (req->cmd.buf[1] & 3)
+        if (req->cmd.buf[1] & 3) {
             goto illegal_request;
+        }
         break;
     case START_STOP:
-        if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) {
-            /* load/eject medium */
-            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
+        if (scsi_disk_emulate_start_stop(r) < 0) {
+            return -1;
         }
-       break;
+        break;
     case ALLOW_MEDIUM_REMOVAL:
-        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
-       break;
-    case READ_CAPACITY:
+        s->tray_locked = req->cmd.buf[4] & 1;
+        bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
+        break;
+    case READ_CAPACITY_10:
         /* The normal LEN field for this command is zero.  */
-       memset(outbuf, 0, 8);
-       bdrv_get_geometry(s->bs, &nb_sectors);
-        if (!nb_sectors)
+        memset(outbuf, 0, 8);
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+        if (!nb_sectors) {
             goto not_ready;
-        nb_sectors /= s->cluster_size;
+        }
+        if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
+            goto illegal_request;
+        }
+        nb_sectors /= s->qdev.blocksize / 512;
         /* Returned value is the address of the last sector.  */
         nb_sectors--;
         /* Remember the new size for read/write sanity checking. */
-        s->max_lba = nb_sectors;
+        s->qdev.max_lba = nb_sectors;
         /* Clip to 2TB, instead of returning capacity modulo 2TB. */
-        if (nb_sectors > UINT32_MAX)
+        if (nb_sectors > UINT32_MAX) {
             nb_sectors = UINT32_MAX;
+        }
         outbuf[0] = (nb_sectors >> 24) & 0xff;
         outbuf[1] = (nb_sectors >> 16) & 0xff;
         outbuf[2] = (nb_sectors >> 8) & 0xff;
         outbuf[3] = nb_sectors & 0xff;
         outbuf[4] = 0;
         outbuf[5] = 0;
-        outbuf[6] = s->cluster_size * 2;
+        outbuf[6] = s->qdev.blocksize >> 8;
         outbuf[7] = 0;
         buflen = 8;
-       break;
-    case SYNCHRONIZE_CACHE:
-        ret = bdrv_flush(s->bs);
-        if (ret < 0) {
-            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
-                return -1;
-            }
+        break;
+    case REQUEST_SENSE:
+        /* Just return "NO SENSE".  */
+        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
+                                  (req->cmd.buf[1] & 1) == 0);
+        break;
+    case MECHANISM_STATUS:
+        buflen = scsi_emulate_mechanism_status(s, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
         }
         break;
     case GET_CONFIGURATION:
-        memset(outbuf, 0, 8);
-        /* ??? This should probably return much more information.  For now
-           just return the basic header indicating the CD-ROM profile.  */
-        outbuf[7] = 8; // CD-ROM
-        buflen = 8;
+        buflen = scsi_get_configuration(s, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case GET_EVENT_STATUS_NOTIFICATION:
+        buflen = scsi_get_event_status_notification(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case READ_DVD_STRUCTURE:
+        buflen = scsi_read_dvd_structure(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
         break;
-    case SERVICE_ACTION_IN:
+    case SERVICE_ACTION_IN_16:
         /* Service Action In subcommands. */
-        if ((req->cmd.buf[1] & 31) == 0x10) {
+        if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
             DPRINTF("SAI READ CAPACITY(16)\n");
             memset(outbuf, 0, req->cmd.xfer);
-            bdrv_get_geometry(s->bs, &nb_sectors);
-            if (!nb_sectors)
+            bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+            if (!nb_sectors) {
                 goto not_ready;
-            nb_sectors /= s->cluster_size;
+            }
+            if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
+                goto illegal_request;
+            }
+            nb_sectors /= s->qdev.blocksize / 512;
             /* Returned value is the address of the last sector.  */
             nb_sectors--;
             /* Remember the new size for read/write sanity checking. */
-            s->max_lba = nb_sectors;
+            s->qdev.max_lba = nb_sectors;
             outbuf[0] = (nb_sectors >> 56) & 0xff;
             outbuf[1] = (nb_sectors >> 48) & 0xff;
             outbuf[2] = (nb_sectors >> 40) & 0xff;
@@ -975,7 +1235,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             outbuf[7] = nb_sectors & 0xff;
             outbuf[8] = 0;
             outbuf[9] = 0;
-            outbuf[10] = s->cluster_size * 2;
+            outbuf[10] = s->qdev.blocksize >> 8;
             outbuf[11] = 0;
             outbuf[12] = 0;
             outbuf[13] = get_physical_block_exp(&s->qdev.conf);
@@ -991,33 +1251,26 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         }
         DPRINTF("Unsupported Service Action In\n");
         goto illegal_request;
-    case REPORT_LUNS:
-        if (req->cmd.xfer < 16)
-            goto illegal_request;
-        memset(outbuf, 0, 16);
-        outbuf[3] = 8;
-        buflen = 16;
-        break;
-    case VERIFY:
-        break;
-    case REZERO_UNIT:
-        DPRINTF("Rezero Unit\n");
-        if (!bdrv_is_inserted(s->bs)) {
-            goto not_ready;
-        }
+    case VERIFY_10:
         break;
     default:
-        goto illegal_request;
+        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+        return -1;
     }
-    scsi_req_set_status(r, GOOD, NO_SENSE);
     return buflen;
 
 not_ready:
-    scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
+    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+    } else {
+        scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
+    }
     return -1;
 
 illegal_request:
-    scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
+    if (r->req.status == -1) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    }
     return -1;
 }
 
@@ -1026,34 +1279,17 @@ illegal_request:
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
    and zero if the command does not transfer any data.  */
 
-static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
-                                 uint8_t *buf, int lun)
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    uint32_t len;
-    int is_write;
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int32_t len;
     uint8_t command;
-    uint8_t *outbuf;
-    SCSIDiskReq *r;
     int rc;
 
     command = buf[0];
-    r = scsi_find_request(s, tag);
-    if (r) {
-        BADF("Tag 0x%x already in use\n", tag);
-        scsi_cancel_io(d, tag);
-    }
-    /* ??? Tags are not unique for different luns.  We only implement a
-       single lun, so this should not matter.  */
-    r = scsi_new_request(s, tag, lun);
-    outbuf = (uint8_t *)r->iov.iov_base;
-    is_write = 0;
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
-
-    if (scsi_req_parse(&r->req, buf) != 0) {
-        BADF("Unsupported command length, command %x\n", command);
-        goto fail;
-    }
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
+
 #ifdef DEBUG_SCSI
     {
         int i;
@@ -1064,15 +1300,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     }
 #endif
 
-    if (lun || buf[1] >> 5) {
-        /* Only LUN 0 supported.  */
-        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
-        if (command != REQUEST_SENSE && command != INQUIRY)
-            goto fail;
-    }
     switch (command) {
     case TEST_UNIT_READY:
-    case REQUEST_SENSE:
     case INQUIRY:
     case MODE_SENSE:
     case MODE_SENSE_10:
@@ -1082,48 +1311,59 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     case RELEASE_10:
     case START_STOP:
     case ALLOW_MEDIUM_REMOVAL:
-    case READ_CAPACITY:
-    case SYNCHRONIZE_CACHE:
+    case READ_CAPACITY_10:
     case READ_TOC:
+    case READ_DVD_STRUCTURE:
     case GET_CONFIGURATION:
-    case SERVICE_ACTION_IN:
-    case REPORT_LUNS:
-    case VERIFY:
-    case REZERO_UNIT:
-        rc = scsi_disk_emulate_command(r, outbuf);
+    case GET_EVENT_STATUS_NOTIFICATION:
+    case MECHANISM_STATUS:
+    case SERVICE_ACTION_IN_16:
+    case REQUEST_SENSE:
+    case VERIFY_10:
+        rc = scsi_disk_emulate_command(r);
         if (rc < 0) {
             return 0;
         }
 
         r->iov.iov_len = rc;
         break;
+    case SYNCHRONIZE_CACHE:
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+        if (r->req.aiocb == NULL) {
+            scsi_flush_complete(r, -EIO);
+        }
+        return 0;
     case READ_6:
     case READ_10:
     case READ_12:
     case READ_16:
-        len = r->req.cmd.xfer / d->blocksize;
+        len = r->req.cmd.xfer / s->qdev.blocksize;
         DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
-        r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
+        }
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
         break;
     case WRITE_6:
     case WRITE_10:
     case WRITE_12:
     case WRITE_16:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_VERIFY_12:
     case WRITE_VERIFY_16:
-        len = r->req.cmd.xfer / d->blocksize;
+        len = r->req.cmd.xfer / s->qdev.blocksize;
         DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
                 (command & 0xe) == 0xe ? "And Verify " : "",
                 r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
-        r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
-        is_write = 1;
+        }
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
         break;
     case MODE_SELECT:
         DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
@@ -1141,21 +1381,19 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
             goto fail;
         }
         break;
-    case SEEK_6:
     case SEEK_10:
-        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
-                r->req.cmd.lba);
-        if (r->req.cmd.lba > s->max_lba) {
+        DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
         break;
     case WRITE_SAME_16:
-        len = r->req.cmd.xfer / d->blocksize;
+        len = r->req.cmd.xfer / s->qdev.blocksize;
 
         DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
                 r->req.cmd.lba, len);
 
-        if (r->req.cmd.lba > s->max_lba) {
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
 
@@ -1166,8 +1404,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
             goto fail;
         }
 
-        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
-                          len * s->cluster_size);
+        rc = bdrv_discard(s->qdev.conf.bs,
+                          r->req.cmd.lba * (s->qdev.blocksize / 512),
+                          len * (s->qdev.blocksize / 512));
         if (rc < 0) {
             /* XXX: better error code ?*/
             goto fail;
@@ -1176,36 +1415,26 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
         break;
     default:
         DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+        return 0;
     fail:
-        scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
         return 0;
     illegal_lba:
-        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
+        scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
         return 0;
     }
     if (r->sector_count == 0 && r->iov.iov_len == 0) {
-        scsi_command_complete(r, GOOD, NO_SENSE);
+        scsi_req_complete(&r->req, GOOD);
     }
     len = r->sector_count * 512 + r->iov.iov_len;
-    if (is_write) {
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
         return -len;
     } else {
-        if (!r->sector_count)
+        if (!r->sector_count) {
             r->sector_count = -1;
-        return len;
-    }
-}
-
-static void scsi_disk_purge_requests(SCSIDiskState *s)
-{
-    SCSIDiskReq *r;
-
-    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
-        r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
-        if (r->req.aiocb) {
-            bdrv_aio_cancel(r->req.aiocb);
         }
-        scsi_remove_request(r);
+        return len;
     }
 }
 
@@ -1214,96 +1443,361 @@ static void scsi_disk_reset(DeviceState *dev)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
     uint64_t nb_sectors;
 
-    scsi_disk_purge_requests(s);
+    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
 
-    bdrv_get_geometry(s->bs, &nb_sectors);
-    nb_sectors /= s->cluster_size;
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    nb_sectors /= s->qdev.blocksize / 512;
     if (nb_sectors) {
         nb_sectors--;
     }
-    s->max_lba = nb_sectors;
+    s->qdev.max_lba = nb_sectors;
 }
 
 static void scsi_destroy(SCSIDevice *dev)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
 
-    scsi_disk_purge_requests(s);
+    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
-static int scsi_disk_initfn(SCSIDevice *dev)
+static void scsi_cd_change_media_cb(void *opaque, bool load)
+{
+    SCSIDiskState *s = opaque;
+
+    /*
+     * 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.
+     *
+     * media_changed governs the state machine used for unit attention
+     * report.  media_event is used by GET EVENT STATUS NOTIFICATION.
+     */
+    s->media_changed = load;
+    s->tray_open = !load;
+    s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
+    s->media_event = true;
+    s->eject_request = false;
+}
+
+static void scsi_cd_eject_request_cb(void *opaque, bool force)
+{
+    SCSIDiskState *s = opaque;
+
+    s->eject_request = true;
+    if (force) {
+        s->tray_locked = false;
+    }
+}
+
+static bool scsi_cd_is_tray_open(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_open;
+}
+
+static bool scsi_cd_is_medium_locked(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps scsi_cd_block_ops = {
+    .change_media_cb = scsi_cd_change_media_cb,
+    .eject_request_cb = scsi_cd_eject_request_cb,
+    .is_tray_open = scsi_cd_is_tray_open,
+    .is_medium_locked = scsi_cd_is_medium_locked,
+};
+
+static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    if (s->media_changed) {
+        s->media_changed = false;
+        s->qdev.unit_attention = SENSE_CODE(MEDIUM_CHANGED);
+    }
+}
+
+static int scsi_initfn(SCSIDevice *dev)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    int is_cd;
     DriveInfo *dinfo;
 
     if (!s->qdev.conf.bs) {
         error_report("scsi-disk: drive property not set");
         return -1;
     }
-    s->bs = s->qdev.conf.bs;
-    is_cd = bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM;
 
-    if (!is_cd && !bdrv_is_inserted(s->bs)) {
+    if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) {
         error_report("Device needs media, but drive is empty");
         return -1;
     }
 
     if (!s->serial) {
         /* try to fall back to value set with legacy -drive serial=... */
-        dinfo = drive_get_by_blockdev(s->bs);
-        s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
+        dinfo = drive_get_by_blockdev(s->qdev.conf.bs);
+        if (*dinfo->serial) {
+            s->serial = g_strdup(dinfo->serial);
+        }
     }
 
     if (!s->version) {
-        s->version = qemu_strdup(QEMU_VERSION);
+        s->version = g_strdup(QEMU_VERSION);
     }
 
-    if (bdrv_is_sg(s->bs)) {
+    if (bdrv_is_sg(s->qdev.conf.bs)) {
         error_report("scsi-disk: unwanted /dev/sg*");
         return -1;
     }
 
-    if (is_cd) {
-        s->qdev.blocksize = 2048;
-    } else {
-        s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    if (s->removable) {
+        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
     }
-    s->cluster_size = s->qdev.blocksize / 512;
-    s->bs->buffer_alignment = s->qdev.blocksize;
+    bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
 
-    s->qdev.type = TYPE_DISK;
-    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
-    bdrv_set_removable(s->bs, is_cd);
-    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
+    bdrv_iostatus_enable(s->qdev.conf.bs);
+    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
     return 0;
 }
 
-static SCSIDeviceInfo scsi_disk_info = {
-    .qdev.name    = "scsi-disk",
-    .qdev.fw_name = "disk",
-    .qdev.desc    = "virtual scsi disk or cdrom",
-    .qdev.size    = sizeof(SCSIDiskState),
-    .qdev.reset   = scsi_disk_reset,
-    .init         = scsi_disk_initfn,
-    .destroy      = scsi_destroy,
+static int scsi_hd_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    s->qdev.type = TYPE_DISK;
+    return scsi_initfn(&s->qdev);
+}
+
+static int scsi_cd_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = 2048;
+    s->qdev.type = TYPE_ROM;
+    s->removable = true;
+    return scsi_initfn(&s->qdev);
+}
+
+static int scsi_disk_initfn(SCSIDevice *dev)
+{
+    DriveInfo *dinfo;
+
+    if (!dev->conf.bs) {
+        return scsi_initfn(dev);  /* ... and die there */
+    }
+
+    dinfo = drive_get_by_blockdev(dev->conf.bs);
+    if (dinfo->media_cd) {
+        return scsi_cd_initfn(dev);
+    } else {
+        return scsi_hd_initfn(dev);
+    }
+}
+
+static const SCSIReqOps scsi_disk_reqops = {
+    .size         = sizeof(SCSIDiskReq),
+    .free_req     = scsi_free_request,
     .send_command = scsi_send_command,
     .read_data    = scsi_read_data,
     .write_data   = scsi_write_data,
     .cancel_io    = scsi_cancel_io,
     .get_buf      = scsi_get_buf,
-    .qdev.props   = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),
-        DEFINE_PROP_STRING("ver",  SCSIDiskState, version),
-        DEFINE_PROP_STRING("serial",  SCSIDiskState, serial),
-        DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+};
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     uint8_t *buf, void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+    SCSIRequest *req;
+
+    req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
+    return req;
+}
+
+#ifdef __linux__
+static int get_device_type(SCSIDiskState *s)
+{
+    BlockDriverState *bdrv = s->qdev.conf.bs;
+    uint8_t cmd[16];
+    uint8_t buf[36];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = INQUIRY;
+    cmd[4] = sizeof(buf);
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
+        return -1;
+    }
+    s->qdev.type = buf[0];
+    s->removable = (buf[1] & 0x80) != 0;
+    return 0;
+}
+
+static int scsi_block_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    int sg_version;
+    int rc;
+
+    if (!s->qdev.conf.bs) {
+        error_report("scsi-block: drive property not set");
+        return -1;
+    }
+
+    /* check we are using a driver managing SG_IO (version 3 and after) */
+    if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+        sg_version < 30000) {
+        error_report("scsi-block: scsi generic interface too old");
+        return -1;
+    }
+
+    /* get device type from INQUIRY data */
+    rc = get_device_type(s);
+    if (rc < 0) {
+        error_report("scsi-block: INQUIRY failed");
+        return -1;
+    }
+
+    /* Make a guess for the block size, we'll fix it when the guest sends.
+     * READ CAPACITY.  If they don't, they likely would assume these sizes
+     * anyway. (TODO: check in /sys).
+     */
+    if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
+        s->qdev.blocksize = 2048;
+    } else {
+        s->qdev.blocksize = 512;
+    }
+    return scsi_initfn(&s->qdev);
+}
+
+static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
+                                           uint32_t lun, uint8_t *buf,
+                                           void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+
+    switch (buf[0]) {
+    case READ_6:
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        /* MMC writing cannot be done via pread/pwrite, because it sometimes
+         * involves writing beyond the maximum LBA or to negative LBA (lead-in).
+         * And once you do these writes, reading from the block device is
+         * unreliable, too.  It is even possible that reads deliver random data
+         * from the host page cache (this is probably a Linux bug).
+         *
+         * We might use scsi_disk_reqops as long as no writing commands are
+         * seen, but performance usually isn't paramount on optical media.  So,
+         * just make scsi-block operate the same as scsi-generic for them.
+         */
+        if (s->qdev.type != TYPE_ROM) {
+            return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
+                                  hba_private);
+        }
+    }
+
+    return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
+                          hba_private);
+}
+#endif
+
+#define DEFINE_SCSI_DISK_PROPERTIES()                           \
+    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),          \
+    DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
+    DEFINE_PROP_STRING("serial",  SCSIDiskState, serial)
+
+static SCSIDeviceInfo scsi_disk_info[] = {
+    {
+        .qdev.name    = "scsi-hd",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI disk",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_hd_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "scsi-cd",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI CD-ROM",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_cd_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+#ifdef __linux__
+    },{
+        .qdev.name    = "scsi-block",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "SCSI block device passthrough",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_block_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_block_new_request,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+#endif
+    },{
+        .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI disk or CD-ROM (legacy)",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_disk_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    }
 };
 
 static void scsi_disk_register_devices(void)
 {
-    scsi_qdev_register(&scsi_disk_info);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
+        scsi_qdev_register(&scsi_disk_info[i]);
+    }
 }
 device_init(scsi_disk_register_devices)
index 9be1cca4c3515941f7f98cd5b34de243150817b2..e62044f3955d9242d9baa6faeced5c0711342a91 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Written by Laurent Vivier <Laurent.Vivier@bull.net>
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  *
  */
 
@@ -39,15 +39,18 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 
 #define SCSI_SENSE_BUF_SIZE 96
 
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
+#define SG_ERR_DRIVER_TIMEOUT  0x06
+#define SG_ERR_DRIVER_SENSE    0x08
+
+#define SG_ERR_DID_OK          0x00
+#define SG_ERR_DID_NO_CONNECT  0x01
+#define SG_ERR_DID_BUS_BUSY    0x02
+#define SG_ERR_DID_TIME_OUT    0x03
 
 #ifndef MAX_UINT
 #define MAX_UINT ((unsigned int)-1)
 #endif
 
-typedef struct SCSIGenericState SCSIGenericState;
-
 typedef struct SCSIGenericReq {
     SCSIRequest req;
     uint8_t *buf;
@@ -56,95 +59,94 @@ typedef struct SCSIGenericReq {
     sg_io_hdr_t io_header;
 } SCSIGenericReq;
 
-struct SCSIGenericState
-{
-    SCSIDevice qdev;
-    BlockDriverState *bs;
-    int lun;
-    int driver_status;
-    uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
-    uint8_t senselen;
-};
-
-static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
+static void scsi_free_request(SCSIRequest *req)
 {
-    SCSIRequest *req;
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
-    req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
-    return DO_UPCAST(SCSIGenericReq, req, req);
-}
-
-static void scsi_remove_request(SCSIGenericReq *r)
-{
-    qemu_free(r->buf);
-    scsi_req_free(&r->req);
-}
-
-static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag)
-{
-    return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag));
+    g_free(r->buf);
 }
 
 /* Helper function for command completion.  */
 static void scsi_command_complete(void *opaque, int ret)
 {
+    int status;
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
 
-    s->driver_status = r->io_header.driver_status;
-    if (s->driver_status & SG_ERR_DRIVER_SENSE)
-        s->senselen = r->io_header.sb_len_wr;
+    r->req.aiocb = NULL;
+    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+        r->req.sense_len = r->io_header.sb_len_wr;
+    }
 
-    if (ret != 0)
-        r->req.status = BUSY;
-    else {
-        if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
-            r->req.status = BUSY;
+    if (ret != 0) {
+        switch (ret) {
+        case -EDOM:
+            status = TASK_SET_FULL;
+            break;
+        case -ENOMEM:
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
+            break;
+        default:
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
+            break;
+        }
+    } else {
+        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
+            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
+            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
+            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
+            status = BUSY;
             BADF("Driver Timeout\n");
-        } else if (r->io_header.status)
-            r->req.status = r->io_header.status;
-        else if (s->driver_status & SG_ERR_DRIVER_SENSE)
-            r->req.status = CHECK_CONDITION;
-        else
-            r->req.status = GOOD;
+        } else if (r->io_header.host_status) {
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
+        } else if (r->io_header.status) {
+            status = r->io_header.status;
+        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+            status = CHECK_CONDITION;
+        } else {
+            status = GOOD;
+        }
     }
     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
-            r, r->req.tag, r->req.status);
+            r, r->req.tag, status);
 
-    scsi_req_complete(&r->req);
-    scsi_remove_request(r);
+    scsi_req_complete(&r->req, status);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 /* Cancel a pending data transfer.  */
-static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
+static void scsi_cancel_io(SCSIRequest *req)
 {
-    DPRINTF("scsi_cancel_io 0x%x\n", tag);
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-    SCSIGenericReq *r;
-    DPRINTF("Cancel tag=0x%x\n", tag);
-    r = scsi_find_request(s, tag);
-    if (r) {
-        if (r->req.aiocb)
-            bdrv_aio_cancel(r->req.aiocb);
-        r->req.aiocb = NULL;
-        scsi_remove_request(r);
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
+
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it independent of whether bdrv_aio_cancel completes the request
+         * or not.  */
+        scsi_req_unref(&r->req);
     }
+    r->req.aiocb = NULL;
 }
 
 static int execute_command(BlockDriverState *bdrv,
                            SCSIGenericReq *r, int direction,
                           BlockDriverCompletionFunc *complete)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
-
     r->io_header.interface_id = 'S';
     r->io_header.dxfer_direction = direction;
     r->io_header.dxferp = r->buf;
     r->io_header.dxfer_len = r->buflen;
     r->io_header.cmdp = r->req.cmd.buf;
     r->io_header.cmd_len = r->req.cmd.len;
-    r->io_header.mx_sb_len = sizeof(s->sensebuf);
-    r->io_header.sbp = s->sensebuf;
+    r->io_header.mx_sb_len = sizeof(r->req.sense);
+    r->io_header.sbp = r->req.sense;
     r->io_header.timeout = MAX_UINT;
     r->io_header.usr_ptr = r;
     r->io_header.flags |= SG_FLAG_DIRECT_IO;
@@ -152,7 +154,7 @@ static int execute_command(BlockDriverState *bdrv,
     r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
     if (r->req.aiocb == NULL) {
         BADF("execute_command: read failed !\n");
-        return -1;
+        return -ENOMEM;
     }
 
     return 0;
@@ -161,8 +163,10 @@ static int execute_command(BlockDriverState *bdrv,
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIDevice *s = r->req.dev;
     int len;
 
+    r->req.aiocb = NULL;
     if (ret) {
         DPRINTF("IO error ret %d\n", ret);
         scsi_command_complete(r, ret);
@@ -172,61 +176,56 @@ static void scsi_read_complete(void * opaque, int ret)
     DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
 
     r->len = -1;
-    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
-    if (len == 0)
+    if (len == 0) {
         scsi_command_complete(r, 0);
+    } else {
+        /* Snoop READ CAPACITY output to set the blocksize.  */
+        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
+            s->blocksize = ldl_be_p(&r->buf[4]);
+            s->max_lba = ldl_be_p(&r->buf[0]);
+        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
+                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+            s->blocksize = ldl_be_p(&r->buf[8]);
+            s->max_lba = ldq_be_p(&r->buf[0]);
+        }
+        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
+
+        scsi_req_data(&r->req, len);
+        if (!r->req.io_canceled) {
+            scsi_req_unref(&r->req);
+        }
+    }
 }
 
 /* Read more data from scsi device into buffer.  */
-static void scsi_read_data(SCSIDevice *d, uint32_t tag)
+static void scsi_read_data(SCSIRequest *req)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-    SCSIGenericReq *r;
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
-    DPRINTF("scsi_read_data 0x%x\n", tag);
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad read tag 0x%x\n", tag);
-        /* ??? This is the wrong error.  */
-        scsi_command_complete(r, -EINVAL);
-        return;
-    }
+    DPRINTF("scsi_read_data 0x%x\n", req->tag);
 
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
     if (r->len == -1) {
         scsi_command_complete(r, 0);
         return;
     }
 
-    if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
-    {
-        s->senselen = MIN(r->len, s->senselen);
-        memcpy(r->buf, s->sensebuf, s->senselen);
-        r->io_header.driver_status = 0;
-        r->io_header.status = 0;
-        r->io_header.dxfer_len  = s->senselen;
-        r->len = -1;
-        DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
-        DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
-                r->buf[0], r->buf[1], r->buf[2], r->buf[3],
-                r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, s->senselen);
-        return;
-    }
-
-    ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
-    if (ret == -1) {
-        scsi_command_complete(r, -EINVAL);
-        return;
+    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
     }
 }
 
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+    SCSIDevice *s = r->req.dev;
 
     DPRINTF("scsi_write_complete() ret = %d\n", ret);
+    r->req.aiocb = NULL;
     if (ret) {
         DPRINTF("IO error\n");
         scsi_command_complete(r, ret);
@@ -234,9 +233,9 @@ static void scsi_write_complete(void * opaque, int ret)
     }
 
     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
-        s->qdev.type == TYPE_TAPE) {
-        s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
-        DPRINTF("block size %d\n", s->qdev.blocksize);
+        s->type == TYPE_TAPE) {
+        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+        DPRINTF("block size %d\n", s->blocksize);
     }
 
     scsi_command_complete(r, ret);
@@ -244,66 +243,33 @@ static void scsi_write_complete(void * opaque, int ret)
 
 /* Write data to a scsi device.  Returns nonzero on failure.
    The transfer may complete asynchronously.  */
-static int scsi_write_data(SCSIDevice *d, uint32_t tag)
+static void scsi_write_data(SCSIRequest *req)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-    SCSIGenericReq *r;
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
-    DPRINTF("scsi_write_data 0x%x\n", tag);
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad write tag 0x%x\n", tag);
-        /* ??? This is the wrong error.  */
-        scsi_command_complete(r, -EINVAL);
-        return 0;
-    }
-
+    DPRINTF("scsi_write_data 0x%x\n", req->tag);
     if (r->len == 0) {
         r->len = r->buflen;
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->len);
-        return 0;
+        scsi_req_data(&r->req, r->len);
+        return;
     }
 
-    ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
-    if (ret == -1) {
-        scsi_command_complete(r, -EINVAL);
-        return 1;
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
     }
-
-    return 0;
 }
 
 /* Return a pointer to the data buffer.  */
-static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
+static uint8_t *scsi_get_buf(SCSIRequest *req)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-    SCSIGenericReq *r;
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad buffer tag 0x%x\n", tag);
-        return NULL;
-    }
-    return r->buf;
-}
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
-static void scsi_req_fixup(SCSIRequest *req)
-{
-    switch(req->cmd.buf[0]) {
-    case WRITE_10:
-        req->cmd.buf[1] &= ~0x08;      /* disable FUA */
-        break;
-    case READ_10:
-        req->cmd.buf[1] &= ~0x08;      /* disable FUA */
-        break;
-    case REWIND:
-    case START_STOP:
-        if (req->dev->type == TYPE_TAPE) {
-            /* force IMMED, otherwise qemu waits end of command */
-            req->cmd.buf[1] = 0x01;
-        }
-        break;
-    }
+    return r->buf;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -311,46 +277,12 @@ static void scsi_req_fixup(SCSIRequest *req)
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
    and zero if the command does not transfer any data.  */
 
-static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
-                                 uint8_t *cmd, int lun)
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-    SCSIGenericReq *r;
-    SCSIBus *bus;
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
-    if (cmd[0] != REQUEST_SENSE &&
-        (lun != s->lun || (cmd[1] >> 5) != s->lun)) {
-        DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
-
-        s->sensebuf[0] = 0x70;
-        s->sensebuf[1] = 0x00;
-        s->sensebuf[2] = ILLEGAL_REQUEST;
-        s->sensebuf[3] = 0x00;
-        s->sensebuf[4] = 0x00;
-        s->sensebuf[5] = 0x00;
-        s->sensebuf[6] = 0x00;
-        s->senselen = 7;
-        s->driver_status = SG_ERR_DRIVER_SENSE;
-        bus = scsi_bus_from_device(d);
-        bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
-        return 0;
-    }
-
-    r = scsi_find_request(s, tag);
-    if (r) {
-        BADF("Tag 0x%x already in use %p\n", tag, r);
-        scsi_cancel_io(d, tag);
-    }
-    r = scsi_new_request(d, tag, lun);
-
-    if (-1 == scsi_req_parse(&r->req, cmd)) {
-        BADF("Unsupported command length, command %x\n", cmd[0]);
-        scsi_remove_request(r);
-        return 0;
-    }
-    scsi_req_fixup(&r->req);
-
     DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
             r->req.cmd.xfer, cmd[0]);
 
@@ -366,12 +298,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
 
     if (r->req.cmd.xfer == 0) {
         if (r->buf != NULL)
-            qemu_free(r->buf);
+            g_free(r->buf);
         r->buflen = 0;
         r->buf = NULL;
-        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
-        if (ret == -1) {
-            scsi_command_complete(r, -EINVAL);
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
+        if (ret < 0) {
+            scsi_command_complete(r, ret);
             return 0;
         }
         return 0;
@@ -379,8 +313,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
 
     if (r->buflen != r->req.cmd.xfer) {
         if (r->buf != NULL)
-            qemu_free(r->buf);
-        r->buf = qemu_malloc(r->req.cmd.xfer);
+            g_free(r->buf);
+        r->buf = g_malloc(r->req.cmd.xfer);
         r->buflen = r->req.cmd.xfer;
     }
 
@@ -389,39 +323,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
         r->len = 0;
         return -r->req.cmd.xfer;
+    } else {
+        return r->req.cmd.xfer;
     }
-
-    return r->req.cmd.xfer;
-}
-
-static int get_blocksize(BlockDriverState *bdrv)
-{
-    uint8_t cmd[10];
-    uint8_t buf[8];
-    uint8_t sensebuf[8];
-    sg_io_hdr_t io_header;
-    int ret;
-
-    memset(cmd, 0, sizeof(cmd));
-    memset(buf, 0, sizeof(buf));
-    cmd[0] = READ_CAPACITY;
-
-    memset(&io_header, 0, sizeof(io_header));
-    io_header.interface_id = 'S';
-    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
-    io_header.dxfer_len = sizeof(buf);
-    io_header.dxferp = buf;
-    io_header.cmdp = cmd;
-    io_header.cmd_len = sizeof(cmd);
-    io_header.mx_sb_len = sizeof(sensebuf);
-    io_header.sbp = sensebuf;
-    io_header.timeout = 6000; /* XXX */
-
-    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0)
-        return -1;
-
-    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
 }
 
 static int get_stream_blocksize(BlockDriverState *bdrv)
@@ -449,120 +353,125 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
     io_header.timeout = 6000; /* XXX */
 
     ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0)
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
         return -1;
-
-    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
-}
-
-static void scsi_generic_purge_requests(SCSIGenericState *s)
-{
-    SCSIGenericReq *r;
-
-    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
-        r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
-        if (r->req.aiocb) {
-            bdrv_aio_cancel(r->req.aiocb);
-        }
-        scsi_remove_request(r);
     }
+    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
 }
 
 static void scsi_generic_reset(DeviceState *dev)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+    SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
 
-    scsi_generic_purge_requests(s);
+    scsi_device_purge_requests(s, SENSE_CODE(RESET));
 }
 
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_destroy(SCSIDevice *s)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-
-    scsi_generic_purge_requests(s);
-    blockdev_mark_auto_del(s->qdev.conf.bs);
+    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
+    blockdev_mark_auto_del(s->conf.bs);
 }
 
-static int scsi_generic_initfn(SCSIDevice *dev)
+static int scsi_generic_initfn(SCSIDevice *s)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
     int sg_version;
     struct sg_scsi_id scsiid;
 
-    if (!s->qdev.conf.bs) {
+    if (!s->conf.bs) {
         error_report("scsi-generic: drive property not set");
         return -1;
     }
-    s->bs = s->qdev.conf.bs;
 
     /* check we are really using a /dev/sg* file */
-    if (!bdrv_is_sg(s->bs)) {
+    if (!bdrv_is_sg(s->conf.bs)) {
         error_report("scsi-generic: not /dev/sg*");
         return -1;
     }
 
-    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
         error_report("Device doesn't support drive option werror");
         return -1;
     }
-    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
+    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
         error_report("Device doesn't support drive option rerror");
         return -1;
     }
 
     /* check we are using a driver managing SG_IO (version 3 and after */
-    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
         sg_version < 30000) {
         error_report("scsi-generic: scsi generic interface too old");
         return -1;
     }
 
     /* get LUN of the /dev/sg? */
-    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
+    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
         error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
         return -1;
     }
 
     /* define device state */
-    s->lun = scsiid.lun;
-    DPRINTF("LUN %d\n", s->lun);
-    s->qdev.type = scsiid.scsi_type;
-    DPRINTF("device type %d\n", s->qdev.type);
-    if (s->qdev.type == TYPE_TAPE) {
-        s->qdev.blocksize = get_stream_blocksize(s->bs);
-        if (s->qdev.blocksize == -1)
-            s->qdev.blocksize = 0;
-    } else {
-        s->qdev.blocksize = get_blocksize(s->bs);
-        /* removable media returns 0 if not present */
-        if (s->qdev.blocksize <= 0) {
-            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
-                s->qdev.blocksize = 2048;
-            else
-                s->qdev.blocksize = 512;
+    s->type = scsiid.scsi_type;
+    DPRINTF("device type %d\n", s->type);
+    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
+        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
+    }
+
+    switch (s->type) {
+    case TYPE_TAPE:
+        s->blocksize = get_stream_blocksize(s->conf.bs);
+        if (s->blocksize == -1) {
+            s->blocksize = 0;
         }
+        break;
+
+        /* Make a guess for block devices, we'll fix it when the guest sends.
+         * READ CAPACITY.  If they don't, they likely would assume these sizes
+         * anyway. (TODO: they could also send MODE SENSE).
+         */
+    case TYPE_ROM:
+    case TYPE_WORM:
+        s->blocksize = 2048;
+        break;
+    default:
+        s->blocksize = 512;
+        break;
     }
-    DPRINTF("block size %d\n", s->qdev.blocksize);
-    s->driver_status = 0;
-    memset(s->sensebuf, 0, sizeof(s->sensebuf));
-    bdrv_set_removable(s->bs, 0);
+
+    DPRINTF("block size %d\n", s->blocksize);
     return 0;
 }
 
+const SCSIReqOps scsi_generic_req_ops = {
+    .size         = sizeof(SCSIGenericReq),
+    .free_req     = scsi_free_request,
+    .send_command = scsi_send_command,
+    .read_data    = scsi_read_data,
+    .write_data   = scsi_write_data,
+    .cancel_io    = scsi_cancel_io,
+    .get_buf      = scsi_get_buf,
+};
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     uint8_t *buf, void *hba_private)
+{
+    SCSIRequest *req;
+
+    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
+    return req;
+}
+
 static SCSIDeviceInfo scsi_generic_info = {
     .qdev.name    = "scsi-generic",
+    .qdev.fw_name = "disk",
     .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
-    .qdev.size    = sizeof(SCSIGenericState),
+    .qdev.size    = sizeof(SCSIDevice),
     .qdev.reset   = scsi_generic_reset,
     .init         = scsi_generic_initfn,
     .destroy      = scsi_destroy,
-    .send_command = scsi_send_command,
-    .read_data    = scsi_read_data,
-    .write_data   = scsi_write_data,
-    .cancel_io    = scsi_cancel_io,
-    .get_buf      = scsi_get_buf,
+    .alloc_req    = scsi_new_request,
     .qdev.props   = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
+        DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
index d3b5d56cd60299e500646d93fce3f1a3e4c71df0..ab6e9523278fb68cd13f28a0404bc68a7cd89a18 100644 (file)
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,23 +3,19 @@
 
 #include "qdev.h"
 #include "block.h"
-#include "block_int.h"
+#include "sysemu.h"
 
 #define MAX_SCSI_DEVS  255
 
 #define SCSI_CMD_BUF_SIZE     16
 
-/* scsi-disk.c */
-enum scsi_reason {
-    SCSI_REASON_DONE, /* Command complete.  */
-    SCSI_REASON_DATA  /* Transfer complete, more data required.  */
-};
-
 typedef struct SCSIBus SCSIBus;
+typedef struct SCSIBusInfo SCSIBusInfo;
+typedef struct SCSICommand SCSICommand;
 typedef struct SCSIDevice SCSIDevice;
 typedef struct SCSIDeviceInfo SCSIDeviceInfo;
-typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag,
-                                  uint32_t arg);
+typedef struct SCSIRequest SCSIRequest;
+typedef struct SCSIReqOps SCSIReqOps;
 
 enum SCSIXferMode {
     SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
@@ -27,33 +23,59 @@ enum SCSIXferMode {
     SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
 };
 
-typedef struct SCSIRequest {
+typedef struct SCSISense {
+    uint8_t key;
+    uint8_t asc;
+    uint8_t ascq;
+} SCSISense;
+
+#define SCSI_SENSE_BUF_SIZE 96
+
+struct SCSICommand {
+    uint8_t buf[SCSI_CMD_BUF_SIZE];
+    int len;
+    size_t xfer;
+    uint64_t lba;
+    enum SCSIXferMode mode;
+};
+
+struct SCSIRequest {
     SCSIBus           *bus;
     SCSIDevice        *dev;
+    const SCSIReqOps  *ops;
+    uint32_t          refcount;
     uint32_t          tag;
     uint32_t          lun;
     uint32_t          status;
-    struct {
-        uint8_t buf[SCSI_CMD_BUF_SIZE];
-        int len;
-        size_t xfer;
-        uint64_t lba;
-        enum SCSIXferMode mode;
-    } cmd;
+    SCSICommand       cmd;
     BlockDriverAIOCB  *aiocb;
+    uint8_t sense[SCSI_SENSE_BUF_SIZE];
+    uint32_t sense_len;
     bool enqueued;
+    bool io_canceled;
+    bool retry;
+    void *hba_private;
     QTAILQ_ENTRY(SCSIRequest) next;
-} SCSIRequest;
+};
 
 struct SCSIDevice
 {
     DeviceState qdev;
+    VMChangeStateEntry *vmsentry;
+    QEMUBH *bh;
     uint32_t id;
     BlockConf conf;
     SCSIDeviceInfo *info;
+    SCSISense unit_attention;
+    bool sense_is_ua;
+    uint8_t sense[SCSI_SENSE_BUF_SIZE];
+    uint32_t sense_len;
     QTAILQ_HEAD(, SCSIRequest) requests;
+    uint32_t channel;
+    uint32_t lun;
     int blocksize;
     int type;
+    uint64_t max_lba;
 };
 
 /* cdrom.c */
@@ -61,33 +83,43 @@ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
 int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
 
 /* scsi-bus.c */
+struct SCSIReqOps {
+    size_t size;
+    void (*free_req)(SCSIRequest *req);
+    int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
+    void (*read_data)(SCSIRequest *req);
+    void (*write_data)(SCSIRequest *req);
+    void (*cancel_io)(SCSIRequest *req);
+    uint8_t *(*get_buf)(SCSIRequest *req);
+};
+
 typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
 struct SCSIDeviceInfo {
     DeviceInfo qdev;
     scsi_qdev_initfn init;
     void (*destroy)(SCSIDevice *s);
-    int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf,
-                            int lun);
-    void (*read_data)(SCSIDevice *s, uint32_t tag);
-    int (*write_data)(SCSIDevice *s, uint32_t tag);
-    void (*cancel_io)(SCSIDevice *s, uint32_t tag);
-    uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
+    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+                              uint8_t *buf, void *hba_private);
+    void (*unit_attention_reported)(SCSIDevice *s);
+};
+
+struct SCSIBusInfo {
+    int tcq;
+    int max_channel, max_target, max_lun;
+    void (*transfer_data)(SCSIRequest *req, uint32_t arg);
+    void (*complete)(SCSIRequest *req, uint32_t arg);
+    void (*cancel)(SCSIRequest *req);
 };
 
-typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
-              int unit);
 struct SCSIBus {
     BusState qbus;
     int busnr;
 
-    int tcq, ndev;
-    scsi_completionfn complete;
-
-    SCSIDevice *devs[MAX_SCSI_DEVS];
+    SCSISense unit_attention;
+    const SCSIBusInfo *info;
 };
 
-void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
-                  scsi_completionfn complete);
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
 void scsi_qdev_register(SCSIDeviceInfo *info);
 
 static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
@@ -96,15 +128,84 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
 }
 
 SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
-                                      int unit, bool removable);
+                                      int unit, bool removable, int bootindex);
 int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
 
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
-SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag);
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+extern const struct SCSISense sense_code_NO_SENSE;
+/* LUN not ready, Manual intervention required */
+extern const struct SCSISense sense_code_LUN_NOT_READY;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
+/* Hardware error, internal target failure */
+extern const struct SCSISense sense_code_TARGET_FAILURE;
+/* Illegal request, invalid command operation code */
+extern const struct SCSISense sense_code_INVALID_OPCODE;
+/* Illegal request, LBA out of range */
+extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
+/* Illegal request, Invalid field in CDB */
+extern const struct SCSISense sense_code_INVALID_FIELD;
+/* Illegal request, LUN not supported */
+extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
+/* Illegal request, Saving parameters not supported */
+extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
+/* Illegal request, Incompatible format */
+extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
+/* Command aborted, I/O process terminated */
+extern const struct SCSISense sense_code_IO_ERROR;
+/* Command aborted, I_T Nexus loss occurred */
+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+/* Command aborted, Logical Unit failure */
+extern const struct SCSISense sense_code_LUN_FAILURE;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
+/* Unit attention, Power on, reset or bus device reset occurred */
+extern const struct SCSISense sense_code_RESET;
+/* Unit attention, Medium may have changed*/
+extern const struct SCSISense sense_code_MEDIUM_CHANGED;
+/* Unit attention, Reported LUNs data has changed */
+extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
+/* Unit attention, Device internal reset */
+extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
+
+#define SENSE_CODE(x) sense_code_ ## x
+
+int scsi_sense_valid(SCSISense sense);
+int scsi_build_sense(uint8_t *in_buf, int in_len,
+                     uint8_t *buf, int len, bool fixed);
+
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          uint8_t *buf, void *hba_private);
+int32_t scsi_req_enqueue(SCSIRequest *req);
 void scsi_req_free(SCSIRequest *req);
+SCSIRequest *scsi_req_ref(SCSIRequest *req);
+void scsi_req_unref(SCSIRequest *req);
 
-int scsi_req_parse(SCSIRequest *req, uint8_t *buf);
+void scsi_req_build_sense(SCSIRequest *req, SCSISense sense);
 void scsi_req_print(SCSIRequest *req);
-void scsi_req_complete(SCSIRequest *req);
+void scsi_req_continue(SCSIRequest *req);
+void scsi_req_data(SCSIRequest *req, int len);
+void scsi_req_complete(SCSIRequest *req, int status);
+uint8_t *scsi_req_get_buf(SCSIRequest *req);
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
+void scsi_req_abort(SCSIRequest *req, int status);
+void scsi_req_cancel(SCSIRequest *req);
+void scsi_req_retry(SCSIRequest *req);
+void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
+int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
+
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi_generic_req_ops;
 
 #endif
diff --git a/hw/sd.c b/hw/sd.c
index 0b90232d14dfee2326a89f01b254fb04b5fa1e27..10e26ade583400772dc924d57d85019f4d034b03 100644 (file)
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -31,7 +31,6 @@
 
 #include "hw.h"
 #include "block.h"
-#include "block_int.h"
 #include "sd.h"
 
 //#define DEBUG_SD 1
@@ -393,9 +392,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     } else {
         sect = 0;
     }
-    sect <<= 9;
-
-    size = sect + 1;
+    size = sect << 9;
 
     sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
 
@@ -411,9 +408,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     sd->bdrv = bdrv;
 
     if (sd->wp_groups)
-        qemu_free(sd->wp_groups);
+        g_free(sd->wp_groups);
     sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
-    sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
+    sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
     memset(sd->function_group, 0, sizeof(int) * 6);
     sd->erase_start = 0;
     sd->erase_end = 0;
@@ -422,14 +419,10 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     sd->pwd_len = 0;
 }
 
-static void sd_cardchange(void *opaque, int reason)
+static void sd_cardchange(void *opaque, bool load)
 {
     SDState *sd = opaque;
 
-    if (!(reason & CHANGE_MEDIA)) {
-        return;
-    }
-
     qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
     if (bdrv_is_inserted(sd->bdrv)) {
         sd_reset(sd, sd->bdrv);
@@ -437,6 +430,10 @@ static void sd_cardchange(void *opaque, int reason)
     }
 }
 
+static const BlockDevOps sd_block_ops = {
+    .change_media_cb = sd_cardchange,
+};
+
 /* We do not model the chip select pin, so allow the board to select
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
@@ -445,13 +442,14 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
 {
     SDState *sd;
 
-    sd = (SDState *) qemu_mallocz(sizeof(SDState));
+    sd = (SDState *) g_malloc0(sizeof(SDState));
     sd->buf = qemu_blockalign(bs, 512);
     sd->spi = is_spi;
     sd->enable = 1;
     sd_reset(sd, bs);
     if (sd->bdrv) {
-        bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+        bdrv_attach_dev_nofail(sd->bdrv, sd);
+        bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
     }
     return sd;
 }
@@ -460,8 +458,8 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
 {
     sd->readonly_cb = readonly;
     sd->inserted_cb = insert;
-    qemu_set_irq(readonly, bdrv_is_read_only(sd->bdrv));
-    qemu_set_irq(insert, bdrv_is_inserted(sd->bdrv));
+    qemu_set_irq(readonly, sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0);
+    qemu_set_irq(insert, sd->bdrv ? bdrv_is_inserted(sd->bdrv) : 0);
 }
 
 static void sd_erase(SDState *sd)
@@ -1103,8 +1101,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
             break;
         }
         break;
-   
-       case 52:
+
+    case 52:
     case 53:
         /* CMD52, CMD53: reserved for SDIO cards
          * (see the SDIO Simplified Specification V2.0)
@@ -1115,7 +1113,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
         sd->card_status |= ILLEGAL_COMMAND;
         return sd_r0;
 
-
     /* Application specific commands (Class 8) */
     case 55:   /* CMD55:  APP_CMD */
         if (sd->rca != rca)
@@ -1451,14 +1448,8 @@ void sd_write_data(SDState *sd, uint8_t value)
         break;
 
     case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sd->blk_len) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
-            sd->blk_written ++;
-            sd->data_start += sd->blk_len;
-            sd->data_offset = 0;
+        if (sd->data_offset == 0) {
+            /* Start of the block - lets check the address is valid */
             if (sd->data_start + sd->blk_len > sd->size) {
                 sd->card_status |= ADDRESS_ERROR;
                 break;
@@ -1467,6 +1458,15 @@ void sd_write_data(SDState *sd, uint8_t value)
                 sd->card_status |= WP_VIOLATION;
                 break;
             }
+        }
+        sd->data[sd->data_offset++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written++;
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
             sd->csd[14] |= 0x40;
 
             /* Bzzzzzzztt .... Operation complete.  */
index 2c4af61a2b4f33ae0fafee9341d123ccafd941f9..d35c7a920776bbeacb13f2a90964b3d73928b0c6 100644 (file)
@@ -153,6 +153,7 @@ struct SerialState {
     int poll_msl;
 
     struct QEMUTimer *modem_status_poll;
+    MemoryRegion io;
 };
 
 typedef struct ISASerialState {
@@ -274,7 +275,7 @@ static void serial_update_parameters(SerialState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
-    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
@@ -287,7 +288,7 @@ static void serial_update_msl(SerialState *s)
 
     qemu_del_timer(s->modem_status_poll);
 
-    if (qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
+    if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
         s->poll_msl = -1;
         return;
     }
@@ -312,13 +313,13 @@ static void serial_update_msl(SerialState *s)
        We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
 
     if (s->poll_msl)
-        qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + get_ticks_per_sec() / 100);
+        qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
 }
 
 static void serial_xmit(void *opaque)
 {
     SerialState *s = opaque;
-    uint64_t new_xmit_ts = qemu_get_clock(vm_clock);
+    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
 
     if (s->tsr_retry <= 0) {
         if (s->fcr & UART_FCR_FE) {
@@ -334,7 +335,7 @@ static void serial_xmit(void *opaque)
     if (s->mcr & UART_MCR_LOOP) {
         /* in loopback mode, say that we just received a char */
         serial_receive1(s, &s->tsr, 1);
-    } else if (qemu_chr_write(s->chr, &s->tsr, 1) != 1) {
+    } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
         if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
             s->tsr_retry++;
             qemu_mod_timer(s->transmit_timer,  new_xmit_ts + s->char_transmit_time);
@@ -350,7 +351,7 @@ static void serial_xmit(void *opaque)
         s->tsr_retry = 0;
     }
 
-    s->last_xmit_ts = qemu_get_clock(vm_clock);
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
     if (!(s->lsr & UART_LSR_THRE))
         qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time);
 
@@ -467,7 +468,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break_enable = (val >> 6) & 1;
             if (break_enable != s->last_break_enable) {
                 s->last_break_enable = break_enable;
-                qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
                                &break_enable);
             }
         }
@@ -482,7 +483,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 
             if (s->poll_msl >= 0 && old_mcr != s->mcr) {
 
-                qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
 
                 flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
 
@@ -491,10 +492,10 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                 if (val & UART_MCR_DTR)
                     flags |= CHR_TIOCM_DTR;
 
-                qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
                 /* Update the modem status after a one-character-send wait-time, since there may be a response
                    from the device/computer at the other end of the serial line */
-                qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + s->char_transmit_time);
+                qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time);
             }
         }
         break;
@@ -525,7 +526,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
                 if (s->recv_fifo.count == 0)
                     s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
                 else
-                    qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
+                    qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
                 s->timeout_ipending = 0;
             } else {
                 ret = s->rbr;
@@ -641,7 +642,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
         }
         s->lsr |= UART_LSR_DR;
         /* call the timeout receive callback in 4 char transmit time */
-        qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
+        qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
     } else {
         if (s->lsr & UART_LSR_DR)
             s->lsr |= UART_LSR_OE;
@@ -720,7 +721,7 @@ static void serial_reset(void *opaque)
     fifo_clear(s,RECV_FIFO);
     fifo_clear(s,XMIT_FIFO);
 
-    s->last_xmit_ts = qemu_get_clock(vm_clock);
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
 
     s->thr_ipending = 0;
     s->last_break_enable = 0;
@@ -734,10 +735,10 @@ static void serial_init_core(SerialState *s)
        exit(1);
     }
 
-    s->modem_status_poll = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
+    s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
 
-    s->fifo_timeout_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
-    s->transmit_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_xmit, s);
+    s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
+    s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s);
 
     qemu_register_reset(serial_reset, s);
 
@@ -755,6 +756,15 @@ void serial_set_frequency(SerialState *s, uint32_t frequency)
 static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
 static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 
+static const MemoryRegionPortio serial_portio[] = {
+    { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps serial_io_ops = {
+    .old_portio = serial_portio
+};
+
 static int serial_isa_initfn(ISADevice *dev)
 {
     static int index;
@@ -776,24 +786,11 @@ static int serial_isa_initfn(ISADevice *dev)
     serial_init_core(s);
     qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
 
-    register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
-    register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
-    isa_init_ioport_range(dev, isa->iobase, 8);
+    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
+    isa_register_ioport(dev, &s->io, isa->iobase);
     return 0;
 }
 
-SerialState *serial_isa_init(int index, CharDriverState *chr)
-{
-    ISADevice *dev;
-
-    dev = isa_create("isa-serial");
-    qdev_prop_set_uint32(&dev->qdev, "index", index);
-    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
-    if (qdev_init(&dev->qdev) < 0)
-        return NULL;
-    return &DO_UPCAST(ISASerialState, dev, dev)->state;
-}
-
 static const VMStateDescription vmstate_isa_serial = {
     .name = "serial",
     .version_id = 3,
@@ -809,7 +806,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
 {
     SerialState *s;
 
-    s = qemu_mallocz(sizeof(SerialState));
+    s = g_malloc0(sizeof(SerialState));
 
     s->irq = irq;
     s->baudbase = baudbase;
@@ -824,126 +821,47 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
 }
 
 /* Memory mapped interface */
-static uint32_t serial_mm_readb(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-
-    return serial_ioport_read(s, addr >> s->it_shift) & 0xFF;
-}
-
-static void serial_mm_writeb(void *opaque, target_phys_addr_t addr,
-                             uint32_t value)
-{
-    SerialState *s = opaque;
-
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
-}
-
-static uint32_t serial_mm_readw_be(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
-    val = bswap16(val);
-    return val;
-}
-
-static uint32_t serial_mm_readw_le(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
-    return val;
-}
-
-static void serial_mm_writew_be(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
+static uint64_t serial_mm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     SerialState *s = opaque;
-
-    value = bswap16(value);
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
+    return serial_ioport_read(s, addr >> s->it_shift);
 }
 
-static void serial_mm_writew_le(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
+static void serial_mm_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size)
 {
     SerialState *s = opaque;
-
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
-}
-
-static uint32_t serial_mm_readl_be(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift);
-    val = bswap32(val);
-    return val;
-}
-
-static uint32_t serial_mm_readl_le(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift);
-    return val;
-}
-
-static void serial_mm_writel_be(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
-{
-    SerialState *s = opaque;
-
-    value = bswap32(value);
+    value &= ~0u >> (32 - (size * 8));
     serial_ioport_write(s, addr >> s->it_shift, value);
 }
 
-static void serial_mm_writel_le(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
-{
-    SerialState *s = opaque;
-
-    serial_ioport_write(s, addr >> s->it_shift, value);
-}
-
-static CPUReadMemoryFunc * const serial_mm_read_be[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_be,
-    &serial_mm_readl_be,
-};
-
-static CPUWriteMemoryFunc * const serial_mm_write_be[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_be,
-    &serial_mm_writel_be,
-};
-
-static CPUReadMemoryFunc * const serial_mm_read_le[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_le,
-    &serial_mm_readl_le,
-};
-
-static CPUWriteMemoryFunc * const serial_mm_write_le[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_le,
-    &serial_mm_writel_le,
+static const MemoryRegionOps serial_mm_ops[3] = {
+    [DEVICE_NATIVE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+    },
+    [DEVICE_LITTLE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_LITTLE_ENDIAN,
+    },
+    [DEVICE_BIG_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_BIG_ENDIAN,
+    },
 };
 
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             int be)
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            target_phys_addr_t base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian end)
 {
     SerialState *s;
-    int s_io_memory;
 
-    s = qemu_mallocz(sizeof(SerialState));
+    s = g_malloc0(sizeof(SerialState));
 
     s->it_shift = it_shift;
     s->irq = irq;
@@ -953,18 +871,10 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
     serial_init_core(s);
     vmstate_register(NULL, base, &vmstate_serial, s);
 
-    if (ioregister) {
-        if (be) {
-            s_io_memory = cpu_register_io_memory(serial_mm_read_be,
-                                                 serial_mm_write_be, s,
-                                                 DEVICE_NATIVE_ENDIAN);
-        } else {
-            s_io_memory = cpu_register_io_memory(serial_mm_read_le,
-                                                 serial_mm_write_le, s,
-                                                 DEVICE_NATIVE_ENDIAN);
-        }
-        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
-    }
+    memory_region_init_io(&s->io, &serial_mm_ops[end], s,
+                          "serial", 8 << it_shift);
+    memory_region_add_subregion(address_space, base, &s->io);
+
     serial_update_msl(s);
     return s;
 }
diff --git a/hw/sga.c b/hw/sga.c
new file mode 100644 (file)
index 0000000..7ef750a
--- /dev/null
+++ b/hw/sga.c
@@ -0,0 +1,56 @@
+/*
+ * QEMU dummy ISA device for loading sgabios option rom.
+ *
+ * Copyright (c) 2011 Glauber Costa, Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * sgabios code originally available at code.google.com/p/sgabios
+ *
+ */
+#include "pci.h"
+#include "pc.h"
+#include "loader.h"
+#include "sysemu.h"
+
+#define SGABIOS_FILENAME "sgabios.bin"
+
+typedef struct ISAGAState {
+    ISADevice dev;
+} ISASGAState;
+
+static int isa_cirrus_vga_initfn(ISADevice *dev)
+{
+    rom_add_vga(SGABIOS_FILENAME);
+    return 0;
+}
+
+static ISADeviceInfo sga_info = {
+    .qdev.name    = "sga",
+    .qdev.desc    = "Serial Graphics Adapter",
+    .qdev.size    = sizeof(ISASGAState),
+    .init         = isa_cirrus_vga_initfn,
+};
+
+static void sga_register(void)
+{
+      isa_qdev_register(&sga_info);
+}
+
+device_init(sga_register);
index 19d5bf8537e5bb00c5b710a1691a3c40507bdc72..9f3ea9285fa8bf6470151f277d519cd3dee241a8 100644 (file)
@@ -29,7 +29,6 @@
 #include "sh7750_regs.h"
 #include "sh7750_regnames.h"
 #include "sh_intc.h"
-#include "exec-all.h"
 #include "cpu.h"
 
 #define NB_DEVICES 4
@@ -713,7 +712,7 @@ SH7750State *sh7750_init(CPUSH4State * cpu)
     int sh7750_io_memory;
     int sh7750_mm_cache_and_tlb; /* memory mapped cache and tlb */
 
-    s = qemu_mallocz(sizeof(SH7750State));
+    s = g_malloc0(sizeof(SH7750State));
     s->cpu = cpu;
     s->periph_freq = 60000000; /* 60MHz */
     sh7750_io_memory = cpu_register_io_memory(sh7750_mem_read,
index 5a23a2ca20aba43681ffdce93bf05febdeb44bd9..6ec13ab6fec4e54de7ee3414e147d1c347327e7f 100644 (file)
@@ -23,9 +23,9 @@
  * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and
  * in 0x1f000000 - 0x1fffffff (area 7 address)
  */
-#define SH7750_P4_BASE       0xff000000        /* Accessable only in
-                                          priveleged mode */
-#define SH7750_A7_BASE       0x1f000000        /* Accessable only using TLB */
+#define SH7750_P4_BASE       0xff000000        /* Accessible only in
+                                          privileged mode */
+#define SH7750_A7_BASE       0x1f000000        /* Accessible only using TLB */
 
 #define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
 #define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
index 0734da90f099c891c262e0c75a5b623541939bd3..e07424f2a1651b2d9bb0b740ae0dad0006acca09 100644 (file)
@@ -5,7 +5,7 @@
  * Based on sh_timer.c and arm_timer.c by Paul Brook
  * Copyright (c) 2005-2006 CodeSourcery.
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sh_intc.h"
@@ -382,13 +382,14 @@ void sh_intc_register_sources(struct intc_desc *desc,
 
        sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
        s = sh_intc_source(desc, vect->enum_id);
-       if (s)
-           s->vect = vect->vect;
+        if (s) {
+            s->vect = vect->vect;
 
 #ifdef DEBUG_INTC_SOURCES
-       printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
-              vect->enum_id, s->vect, s->enable_count, s->enable_max);
+            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
+                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
 #endif
+        }
     }
 
     if (groups) {
@@ -431,7 +432,7 @@ int sh_intc_init(struct intc_desc *desc,
     desc->nr_prio_regs = nr_prio_regs;
 
     i = sizeof(struct intc_source) * nr_sources;
-    desc->sources = qemu_mallocz(i);
+    desc->sources = g_malloc0(i);
 
     for (i = 0; i < desc->nr_sources; i++) {
         struct intc_source *source = desc->sources + i;
index e99d8dbfb50347608e91daed9d99afc23b9baceb..36f39300d580f03a98301b424348061b8f847717 100644 (file)
 #include "pci.h"
 #include "pci_host.h"
 #include "bswap.h"
+#include "exec-memory.h"
 
 typedef struct SHPCIState {
     SysBusDevice busdev;
     PCIBus *bus;
     PCIDevice *dev;
     qemu_irq irq[4];
-    int memconfig;
+    MemoryRegion memconfig_p4;
+    MemoryRegion memconfig_a7;
+    MemoryRegion isa;
     uint32_t par;
     uint32_t mbr;
     uint32_t iobr;
 } SHPCIState;
 
-static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
+static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint64_t val,
+                              unsigned size)
 {
     SHPCIState *pcic = p;
     switch(addr) {
@@ -53,10 +57,10 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
         break;
     case 0x1c8:
         if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
-            cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
-                                         IO_MEM_UNASSIGNED);
+            memory_region_del_subregion(get_system_memory(), &pcic->isa);
             pcic->iobr = val & 0xfffc0001;
-            isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
+            memory_region_add_subregion(get_system_memory(),
+                                        pcic->iobr & 0xfffc0000, &pcic->isa);
         }
         break;
     case 0x220:
@@ -65,7 +69,8 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
+static uint64_t sh_pci_reg_read (void *p, target_phys_addr_t addr,
+                                 unsigned size)
 {
     SHPCIState *pcic = p;
     switch(addr) {
@@ -83,14 +88,14 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
     return 0;
 }
 
-typedef struct {
-    CPUReadMemoryFunc * const r[3];
-    CPUWriteMemoryFunc * const w[3];
-} MemOp;
-
-static MemOp sh_pci_reg = {
-    { NULL, NULL, sh_pci_reg_read },
-    { NULL, NULL, sh_pci_reg_write },
+static const MemoryRegionOps sh_pci_reg_ops = {
+    .read = sh_pci_reg_read,
+    .write = sh_pci_reg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static int sh_pci_map_irq(PCIDevice *d, int irq_num)
@@ -109,11 +114,23 @@ static void sh_pci_map(SysBusDevice *dev, target_phys_addr_t base)
 {
     SHPCIState *s = FROM_SYSBUS(SHPCIState, dev);
 
-    cpu_register_physical_memory(P4ADDR(base), 0x224, s->memconfig);
-    cpu_register_physical_memory(A7ADDR(base), 0x224, s->memconfig);
-
+    memory_region_add_subregion(get_system_memory(),
+                                P4ADDR(base),
+                                &s->memconfig_p4);
+    memory_region_add_subregion(get_system_memory(),
+                                A7ADDR(base),
+                                &s->memconfig_a7);
     s->iobr = 0xfe240000;
-    isa_mmio_init(s->iobr, 0x40000);
+    memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
+}
+
+static void sh_pci_unmap(SysBusDevice *dev, target_phys_addr_t base)
+{
+    SHPCIState *s = FROM_SYSBUS(SHPCIState, dev);
+
+    memory_region_del_subregion(get_system_memory(), &s->memconfig_p4);
+    memory_region_del_subregion(get_system_memory(), &s->memconfig_a7);
+    memory_region_del_subregion(get_system_memory(), &s->isa);
 }
 
 static int sh_pci_init_device(SysBusDevice *dev)
@@ -127,18 +144,24 @@ static int sh_pci_init_device(SysBusDevice *dev)
     }
     s->bus = pci_register_bus(&s->busdev.qdev, "pci",
                               sh_pci_set_irq, sh_pci_map_irq,
-                              s->irq, PCI_DEVFN(0, 0), 4);
-    s->memconfig = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w,
-                                          s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio_cb(dev, 0x224, sh_pci_map);
+                              s->irq,
+                              get_system_memory(),
+                              get_system_io(),
+                              PCI_DEVFN(0, 0), 4);
+    memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
+                          "sh_pci", 0x224);
+    memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
+                             0, 0x224);
+    isa_mmio_setup(&s->isa, 0x40000);
+    sysbus_init_mmio_cb2(dev, sh_pci_map, sh_pci_unmap);
+    sysbus_init_mmio_region(dev, &s->memconfig_a7);
+    sysbus_init_mmio_region(dev, &s->isa);
     s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
     return 0;
 }
 
 static int sh_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_HITACHI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_HITACHI_SH7751R);
     pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
     pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
@@ -149,6 +172,8 @@ static PCIDeviceInfo sh_pci_host_info = {
     .qdev.name = "sh_pci_host",
     .qdev.size = sizeof(PCIDevice),
     .init      = sh_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_HITACHI,
+    .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
 };
 
 static void sh_pci_register_devices(void)
index 191f4a60c6f7676e4f77f3c6377225833332f528..a20c59ef77d36de91b8a58e4cfba7dfa35286e5e 100644 (file)
@@ -105,7 +105,7 @@ static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
     case 0x0c: /* FTDR / TDR */
         if (s->chr) {
             ch = val;
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
        }
        s->dr = val;
        s->flags &= ~SH_SERIAL_FLAG_TDE;
@@ -361,7 +361,7 @@ void sh_serial_init (target_phys_addr_t base, int feat,
     sh_serial_state *s;
     int s_io_memory;
 
-    s = qemu_mallocz(sizeof(sh_serial_state));
+    s = g_malloc0(sizeof(sh_serial_state));
 
     s->feat = feat;
     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
index 5eec6b7c14bdf75d1ea8f57058c0951a47a4130d..dca3c94210b76c2f3144dfb76578cb14a4705feb 100644 (file)
@@ -5,7 +5,7 @@
  * Based on arm_timer.c by Paul Brook
  * Copyright (c) 2005-2006 CodeSourcery.
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "hw.h"
@@ -188,7 +188,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
     sh_timer_state *s;
     QEMUBH *bh;
 
-    s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state));
+    s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
     s->freq = freq;
     s->feat = feat;
     s->tcor = 0xffffffff;
@@ -311,7 +311,7 @@ void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq,
     tmu012_state *s;
     int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
 
-    s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state));
+    s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
     s->feat = feat;
     s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
     s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
index 638bf16e349ff4b1d8866d860480e08909dbc4fb..dbf47642df9c0b21a13abce62f293b301dbf799c 100644 (file)
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -28,7 +28,6 @@
    More information in target-sh4/README.sh4
 */
 #include "hw.h"
-#include "pc.h"
 #include "sh.h"
 #include "sysemu.h"
 #include "boards.h"
 #define BIOS_FILENAME "shix_bios.bin"
 #define BIOS_ADDRESS 0xA0000000
 
-void irq_info(Monitor *mon)
-{
-    /* XXXXX */
-}
-
-void pic_info(Monitor *mon)
-{
-    /* XXXXX */
-}
-
 static void shix_init(ram_addr_t ram_size,
                const char *boot_device,
               const char *kernel_filename, const char *kernel_cmdline,
index a83e5b8272360e6176b7b377c73f3ded51c2e983..329c251845f704ea6ce13bcda614b3e1068f3091 100644 (file)
 struct SLAVIO_INTCTLState;
 
 typedef struct SLAVIO_CPUINTCTLState {
-    uint32_t intreg_pending;
     struct SLAVIO_INTCTLState *master;
+    uint32_t intreg_pending;
     uint32_t cpu;
     uint32_t irl_out;
 } SLAVIO_CPUINTCTLState;
 
 typedef struct SLAVIO_INTCTLState {
     SysBusDevice busdev;
-    uint32_t intregm_pending;
-    uint32_t intregm_disabled;
-    uint32_t target_cpu;
 #ifdef DEBUG_IRQ_COUNT
     uint64_t irq_count[32];
 #endif
     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
+    uint32_t intregm_pending;
+    uint32_t intregm_disabled;
+    uint32_t target_cpu;
 } SLAVIO_INTCTLState;
 
 #define INTCTL_MAXADDR 0xf
index 198360d5731d934d071ea6c0fd6b145245f8a927..1f5a2d733087dcf3fe39d35c544078fa49cdc153 100644 (file)
 typedef struct MiscState {
     SysBusDevice busdev;
     qemu_irq irq;
+    qemu_irq fdc_tc;
     uint32_t dummy;
     uint8_t config;
     uint8_t aux1, aux2;
     uint8_t diag, mctrl;
     uint8_t sysctrl;
     uint16_t leds;
-    qemu_irq fdc_tc;
 } MiscState;
 
 typedef struct APCState {
index 5511313687c2048ce130ec13cc6a8a8be18db21e..84449baa71b1e2df501529f1a3873f1b681f2176 100644 (file)
@@ -48,16 +48,16 @@ typedef struct CPUTimerState {
     qemu_irq irq;
     ptimer_state *timer;
     uint32_t count, counthigh, reached;
-    uint64_t limit;
-    // processor only
+    /* processor only */
     uint32_t running;
+    uint64_t limit;
 } CPUTimerState;
 
 typedef struct SLAVIO_TIMERState {
     SysBusDevice busdev;
     uint32_t num_cpus;
-    CPUTimerState cputimer[MAX_CPUS + 1];
     uint32_t cputimer_mode;
+    CPUTimerState cputimer[MAX_CPUS + 1];
 } SLAVIO_TIMERState;
 
 typedef struct TimerContext {
@@ -381,7 +381,7 @@ static int slavio_timer_init1(SysBusDevice *dev)
     TimerContext *tc;
 
     for (i = 0; i <= MAX_CPUS; i++) {
-        tc = qemu_mallocz(sizeof(TimerContext));
+        tc = g_malloc0(sizeof(TimerContext));
         tc->s = s;
         tc->timer_index = i;
 
index 0f0bf96609b0dcedccda4f518816ccc8aef890ce..297bc9c31802c1dd2a6c79531e80eff0a50ef534 100644 (file)
@@ -459,7 +459,7 @@ typedef struct SM501State {
     target_phys_addr_t base;
     uint32_t local_mem_size_index;
     uint8_t * local_mem;
-    ram_addr_t local_mem_offset;
+    MemoryRegion local_mem_region;
     uint32_t last_width;
     uint32_t last_height;
 
@@ -726,7 +726,8 @@ static void sm501_2d_operation(SM501State * s)
     }
 }
 
-static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_system_config_read(void *opaque, target_phys_addr_t addr,
+                                         unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -778,12 +779,12 @@ static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static void sm501_system_config_write(void *opaque,
-                                     target_phys_addr_t addr, uint32_t value)
+static void sm501_system_config_write(void *opaque, target_phys_addr_t addr,
+                                      uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
-                 addr, value);
+                 (uint32_t)addr, (uint32_t)value);
 
     switch(addr) {
     case SM501_SYSTEM_CONTROL:
@@ -821,21 +822,19 @@ static void sm501_system_config_write(void *opaque,
 
     default:
        printf("sm501 system config : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, value);
+              " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_system_config_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_system_config_read,
-};
-
-static CPUWriteMemoryFunc * const sm501_system_config_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_system_config_write,
+static const MemoryRegionOps sm501_system_config_ops = {
+    .read = sm501_system_config_read,
+    .write = sm501_system_config_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
@@ -864,7 +863,8 @@ static void sm501_palette_write(void *opaque,
     *(uint32_t*)&s->dc_palette[addr] = value;
 }
 
-static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -958,13 +958,12 @@ static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static void sm501_disp_ctrl_write(void *opaque,
-                                          target_phys_addr_t addr,
-                                          uint32_t value)
+static void sm501_disp_ctrl_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
-                 addr, value);
+                 (unsigned)addr, (unsigned)value);
 
     switch(addr) {
     case SM501_DC_PANEL_CONTROL:
@@ -1059,24 +1058,23 @@ static void sm501_disp_ctrl_write(void *opaque,
 
     default:
        printf("sm501 disp ctrl : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, value);
+              " addr=%x, val=%x\n", (int)addr, (unsigned)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_disp_ctrl_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_disp_ctrl_read,
+static const MemoryRegionOps sm501_disp_ctrl_ops = {
+    .read = sm501_disp_ctrl_read,
+    .write = sm501_disp_ctrl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_disp_ctrl_write,
-};
-
-static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -1095,12 +1093,12 @@ static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static void sm501_2d_engine_write(void *opaque,
-                                  target_phys_addr_t addr, uint32_t value)
+static void sm501_2d_engine_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
-                  addr, value);
+                  (unsigned)addr, (unsigned)value);
 
     switch(addr) {
     case SM501_2D_SOURCE:
@@ -1148,21 +1146,19 @@ static void sm501_2d_engine_write(void *opaque,
         break;
     default:
         printf("sm501 2d engine : not implemented register write."
-               " addr=%x, val=%x\n", (int)addr, value);
+               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_2d_engine_read,
-};
-
-static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_2d_engine_write,
+static const MemoryRegionOps sm501_2d_engine_ops = {
+    .read = sm501_2d_engine_read,
+    .write = sm501_2d_engine_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* draw line functions for all console modes */
@@ -1276,7 +1272,7 @@ static void sm501_draw_crt(SM501State * s)
     int y_start = -1;
     ram_addr_t page_min = ~0l;
     ram_addr_t page_max = 0l;
-    ram_addr_t offset = s->local_mem_offset;
+    ram_addr_t offset = 0;
 
     /* choose draw_line function */
     switch (s->dc_crt_control & 3) {
@@ -1333,7 +1329,8 @@ static void sm501_draw_crt(SM501State * s)
 
        /* check dirty flags for each line */
        for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
-           if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG))
+            if (memory_region_get_dirty(&s->local_mem_region, page,
+                                        DIRTY_MEMORY_VGA))
                update = 1;
 
        /* draw line and change status */
@@ -1372,8 +1369,9 @@ static void sm501_draw_crt(SM501State * s)
 
     /* clear dirty flags */
     if (page_min != ~0l) {
-       cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                       VGA_DIRTY_FLAG);
+       memory_region_reset_dirty(&s->local_mem_region,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
     }
 }
 
@@ -1385,17 +1383,17 @@ static void sm501_update_display(void *opaque)
        sm501_draw_crt(s);
 }
 
-void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
-                CharDriverState *chr)
+void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
 {
     SM501State * s;
     DeviceState *dev;
-    int sm501_system_config_index;
-    int sm501_disp_ctrl_index;
-    int sm501_2d_engine_index;
+    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
 
     /* allocate management data region */
-    s = (SM501State *)qemu_mallocz(sizeof(SM501State));
+    s = (SM501State *)g_malloc0(sizeof(SM501State));
     s->base = base;
     s->local_mem_size_index
        = get_local_mem_size_index(local_mem_bytes);
@@ -1407,27 +1405,26 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
     s->dc_crt_control = 0x00010000;
 
     /* allocate local memory */
-    s->local_mem_offset = qemu_ram_alloc(NULL, "sm501.local", local_mem_bytes);
-    s->local_mem = qemu_get_ram_ptr(s->local_mem_offset);
-    cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset);
+    memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
+                           local_mem_bytes);
+    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
+    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
 
     /* map mmio */
-    sm501_system_config_index
-       = cpu_register_io_memory(sm501_system_config_readfn,
-                                sm501_system_config_writefn, s,
-                                 DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET,
-                                0x6c, sm501_system_config_index);
-    sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn,
-                                                  sm501_disp_ctrl_writefn, s,
-                                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
-                                 0x1000, sm501_disp_ctrl_index);
-    sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
-                                                   sm501_2d_engine_writefn, s,
-                                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
-                                 0x54, sm501_2d_engine_index);
+    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
+                          "sm501-system-config", 0x6c);
+    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
+                                sm501_system_config);
+    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
+                          "sm501-disp-ctrl", 0x1000);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_DC,
+                                sm501_disp_ctrl);
+    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
+                          "sm501-2d-engine", 0x54);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                sm501_2d_engine);
 
     /* bridge to usb host emulation module */
     dev = qdev_create(NULL, "sysbus-ohci");
@@ -1440,15 +1437,10 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
 
     /* bridge to serial emulation module */
     if (chr) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
-                       NULL, /* TODO : chain irq to IRL */
-                       115200, chr, 1, 1);
-#else
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+        serial_mm_init(address_space_mem,
+                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
                        NULL, /* TODO : chain irq to IRL */
-                       115200, chr, 1, 0);
-#endif
+                       115200, chr, DEVICE_NATIVE_ENDIAN);
     }
 
     /* create qemu graphic console */
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 a3ae1de824db2d69c1f770c37cac41553b4b831e..c9ba43e8d0596158af476832ccdf4a4fa5edff8a 100644 (file)
 struct smbios_header {
     uint16_t length;
     uint8_t type;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 struct smbios_field {
     struct smbios_header header;
     uint8_t type;
     uint16_t offset;
     uint8_t data[];
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 struct smbios_table {
     struct smbios_header header;
     uint8_t data[];
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 #define SMBIOS_FIELD_ENTRY 0
 #define SMBIOS_TABLE_ENTRY 1
@@ -105,9 +105,9 @@ void smbios_add_field(int type, int offset, int len, void *data)
 
     if (!smbios_entries) {
         smbios_entries_len = sizeof(uint16_t);
-        smbios_entries = qemu_mallocz(smbios_entries_len);
+        smbios_entries = g_malloc0(smbios_entries_len);
     }
-    smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+    smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
                                                   sizeof(*field) + len);
     field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
     field->header.type = SMBIOS_FIELD_ENTRY;
@@ -192,10 +192,10 @@ int smbios_entry_add(const char *t)
 
         if (!smbios_entries) {
             smbios_entries_len = sizeof(uint16_t);
-            smbios_entries = qemu_mallocz(smbios_entries_len);
+            smbios_entries = g_malloc0(smbios_entries_len);
         }
 
-        smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
                                                       sizeof(*table) + size);
         table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
         table->header.type = SMBIOS_TABLE_ENTRY;
index 3a5169dbd34756b9da03ee33e8a8695da2bba6c9..94e3641f9a6d1260385cf75d38e0cdc72ebdda1e 100644 (file)
@@ -26,7 +26,7 @@ struct smbios_structure_header {
     uint8_t type;
     uint8_t length;
     uint16_t handle;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 0 - BIOS Information */
 struct smbios_type_0 {
@@ -42,7 +42,7 @@ struct smbios_type_0 {
     uint8_t system_bios_minor_release;
     uint8_t embedded_controller_major_release;
     uint8_t embedded_controller_minor_release;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 1 - System Information */
 struct smbios_type_1 {
@@ -55,7 +55,7 @@ struct smbios_type_1 {
     uint8_t wake_up_type;
     uint8_t sku_number_str;
     uint8_t family_str;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 3 - System Enclosure (v2.3) */
 struct smbios_type_3 {
@@ -74,7 +74,7 @@ struct smbios_type_3 {
     uint8_t number_of_power_cords;
     uint8_t contained_element_count;
     // contained elements follow
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 4 - Processor Information (v2.0) */
 struct smbios_type_4 {
@@ -94,7 +94,7 @@ struct smbios_type_4 {
     uint16_t l1_cache_handle;
     uint16_t l2_cache_handle;
     uint16_t l3_cache_handle;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 16 - Physical Memory Array
  *   Associated with one type 17 (Memory Device).
@@ -107,7 +107,7 @@ struct smbios_type_16 {
     uint32_t maximum_capacity;
     uint16_t memory_error_information_handle;
     uint16_t number_of_memory_devices;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 /* SMBIOS type 17 - Memory Device
  *   Associated with one type 19
  */
@@ -124,7 +124,7 @@ struct smbios_type_17 {
     uint8_t bank_locator_str;
     uint8_t memory_type;
     uint16_t type_detail;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 19 - Memory Array Mapped Address */
 struct smbios_type_19 {
@@ -133,7 +133,7 @@ struct smbios_type_19 {
     uint32_t ending_address;
     uint16_t memory_array_handle;
     uint8_t partition_width;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 20 - Memory Device Mapped Address */
 struct smbios_type_20 {
@@ -145,18 +145,18 @@ struct smbios_type_20 {
     uint8_t partition_row_position;
     uint8_t interleave_position;
     uint8_t interleaved_data_depth;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 32 - System Boot Information */
 struct smbios_type_32 {
     struct smbios_structure_header header;
     uint8_t reserved[6];
     uint8_t boot_status;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 /* SMBIOS type 127 -- End-of-table */
 struct smbios_type_127 {
     struct smbios_structure_header header;
-} __attribute__((__packed__));
+} QEMU_PACKED;
 
 #endif /*QEMU_SMBIOS_H */
index e4645391501a7775e73cd6d5c08acabb6000c13c..ff027c814f7d0b690dc2f0c7c26f2d74d8548227 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 /* TODO: Implement PEC.  */
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..5d080abed7826c5d7182489e96ab41843068eea8 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 = g_malloc0(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);
+    }
+}
index dafea5cc6e26613dd83e3216eb0e1a44d3ecd83a..fc8c4984a7a668e497b0036230f43502a477de8c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005 CodeSourcery, LLC.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 
 #include "sysbus.h"
@@ -43,7 +43,7 @@ typedef struct {
     uint8_t data[NUM_PACKETS][2048];
     uint8_t int_level;
     uint8_t int_mask;
-    int mmio_index;
+    MemoryRegion mmio;
 } smc91c111_state;
 
 static const VMStateDescription vmstate_smc91c111 = {
@@ -252,8 +252,9 @@ static void smc91c111_queue_tx(smc91c111_state *s, int packet)
     smc91c111_do_tx(s);
 }
 
-static void smc91c111_reset(smc91c111_state *s)
+static void smc91c111_reset(DeviceState *dev)
 {
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, sysbus_from_qdev(dev));
     s->bank = 0;
     s->tx_fifo_len = 0;
     s->tx_fifo_done_len = 0;
@@ -302,7 +303,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
         case 5:
             SET_HIGH(rcr, value);
             if (s->rcr & RCR_SOFT_RST)
-                smc91c111_reset(s);
+                smc91c111_reset(&s->busdev.qdev);
             return;
         case 10: case 11: /* RPCR */
             /* Ignored */
@@ -716,16 +717,15 @@ static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t
     return size;
 }
 
-static CPUReadMemoryFunc * const smc91c111_readfn[] = {
-    smc91c111_readb,
-    smc91c111_readw,
-    smc91c111_readl
-};
-
-static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
-    smc91c111_writeb,
-    smc91c111_writew,
-    smc91c111_writel
+static const MemoryRegionOps smc91c111_mem_ops = {
+    /* The special case for 32 bit writes to 0xc means we can't just
+     * set .impl.min/max_access_size to 1, unfortunately
+     */
+    .old_mmio = {
+        .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
+        .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void smc91c111_cleanup(VLANClientState *nc)
@@ -746,16 +746,11 @@ static NetClientInfo net_smc91c111_info = {
 static int smc91c111_init1(SysBusDevice *dev)
 {
     smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
-
-    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
-                                           smc91c111_writefn, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 16, s->mmio_index);
+    memory_region_init_io(&s->mmio, &smc91c111_mem_ops, s,
+                          "smc91c111-mmio", 16);
+    sysbus_init_mmio_region(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    smc91c111_reset(s);
-
     s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
                           dev->qdev.info->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
@@ -768,6 +763,7 @@ static SysBusDeviceInfo smc91c111_info = {
     .qdev.name  = "smc91c111",
     .qdev.size  = sizeof(smc91c111_state),
     .qdev.vmsd = &vmstate_smc91c111,
+    .qdev.reset = smc91c111_reset,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
         DEFINE_PROP_END_OF_LIST(),
index 23ec51695abdb0e9b323fc160cad6ce5e9a49bee..03bc8468dd244789aa6aca850d996d222f2a498e 100644 (file)
@@ -48,7 +48,7 @@ static int fifo_size;
 static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
 {
     if (ch->bytes > fifo_size)
-        fifo_buf = qemu_realloc(fifo_buf, fifo_size = ch->bytes);
+        fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes);
 
     /* Implement as transfer_fifo2linear + transfer_linear2fifo.  */
     ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
@@ -84,7 +84,7 @@ struct dma_s {
 
 static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
 {
-    int64_t now = qemu_get_clock(vm_clock);
+    int64_t now = qemu_get_clock_ns(vm_clock);
     struct dma_s *dma = (struct dma_s *) ch->dma;
 
     qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq);
@@ -239,14 +239,14 @@ void soc_dma_reset(struct soc_dma_s *soc)
 struct soc_dma_s *soc_dma_init(int n)
 {
     int i;
-    struct dma_s *s = qemu_mallocz(sizeof(*s) + n * sizeof(*s->ch));
+    struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch));
 
     s->chnum = n;
     s->soc.ch = s->ch;
     for (i = 0; i < n; i ++) {
         s->ch[i].dma = &s->soc;
         s->ch[i].num = i;
-        s->ch[i].timer = qemu_new_timer(vm_clock, soc_dma_ch_run, &s->ch[i]);
+        s->ch[i].timer = qemu_new_timer_ns(vm_clock, soc_dma_ch_run, &s->ch[i]);
     }
 
     soc_dma_reset(&s->soc);
@@ -261,7 +261,7 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, target_phys_addr_t virt_base,
     struct memmap_entry_s *entry;
     struct dma_s *dma = (struct dma_s *) soc;
 
-    dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) *
+    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
                     (dma->memmap_size + 1));
     entry = soc_dma_lookup(dma, virt_base);
 
@@ -313,7 +313,7 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
     struct memmap_entry_s *entry;
     struct dma_s *dma = (struct dma_s *) soc;
 
-    dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) *
+    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
                     (dma->memmap_size + 1));
     entry = soc_dma_lookup(dma, virt_base);
 
index c0ebb8d71529c48ab11bc2070ecee0bf123ee339..904b26c5a80545120f30325a79e868d560d58e8d 100644 (file)
@@ -18,6 +18,8 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "memory.h"
+
 struct soc_dma_s;
 struct soc_dma_ch_s;
 typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
@@ -105,9 +107,3 @@ static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
 {
     return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1);
 }
-
-static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma,
-                ram_addr_t offset, target_phys_addr_t virt_base, size_t size)
-{
-    return soc_dma_port_add_mem(dma, qemu_get_ram_ptr(offset), virt_base, size);
-}
diff --git a/hw/spapr.c b/hw/spapr.c
new file mode 100644 (file)
index 0000000..5a98d86
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * 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 "cpus.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+
+#include "hw/boards.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/spapr_pci.h"
+#include "hw/xics.h"
+
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "pci.h"
+
+#include "exec-memory.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_RMA_SLOF           128UL
+
+#define TIMEBASE_FREQ           512000000ULL
+
+#define MAX_CPUS                256
+#define XICS_IRQS              1024
+
+#define SPAPR_PCI_BUID          0x800000020000001ULL
+#define SPAPR_PCI_MEM_WIN_ADDR  (0x10000000000ULL + 0xA0000000)
+#define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
+#define SPAPR_PCI_IO_WIN_ADDR   (0x10000000000ULL + 0x80000000)
+
+#define PHANDLE_XICP            0x00001111
+
+sPAPREnvironment *spapr;
+
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
+{
+    uint32_t irq;
+    qemu_irq qirq;
+
+    if (hint) {
+        irq = hint;
+        /* FIXME: we should probably check for collisions somehow */
+    } else {
+        irq = spapr->next_irq++;
+    }
+
+    qirq = xics_find_qirq(spapr->icp, irq);
+    if (!qirq) {
+        return NULL;
+    }
+
+    if (irq_num) {
+        *irq_num = irq;
+    }
+
+    return qirq;
+}
+
+static void *spapr_create_fdt_skel(const char *cpu_model,
+                                   target_phys_addr_t rma_size,
+                                   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_rma[] = { 0, cpu_to_be64(rma_size) };
+    uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size),
+                                           cpu_to_be64(ram_size - rma_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\0hcall-bulk";
+    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+    int i;
+    char *modelname;
+    int smt = kvmppc_smt_threads();
+
+#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 = g_malloc0(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", "IBM pSeries (emulated by qemu)")));
+
+    _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)));
+
+    /*
+     * Because we don't always invoke any firmware, we can't rely on
+     * that to do BAR allocation.  Long term, we should probably do
+     * that ourselves, but for now, this setting (plus advertising the
+     * current BARs as 0) causes sufficiently recent kernels to to the
+     * BAR assignment themselves */
+    _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* memory node(s) */
+    _FDT((fdt_begin_node(fdt, "memory@0")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "memory")));
+    _FDT((fdt_property(fdt, "reg", mem_reg_property_rma,
+                       sizeof(mem_reg_property_rma))));
+    _FDT((fdt_end_node(fdt)));
+
+    if (ram_size > rma_size) {
+        char mem_name[32];
+
+        sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size);
+        _FDT((fdt_begin_node(fdt, mem_name)));
+        _FDT((fdt_property_string(fdt, "device_type", "memory")));
+        _FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma,
+                           sizeof(mem_reg_property_nonrma))));
+        _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 = g_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 servers_prop[smp_threads];
+        uint32_t gservers_prop[smp_threads * 2];
+        char *nodename;
+        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                           0xffffffff, 0xffffffff};
+        uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
+        uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
+
+        if ((index % smt) != 0) {
+            continue;
+        }
+
+        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", tbfreq)));
+        _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
+        _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)));
+
+        /* Build interrupt servers and gservers properties */
+        for (i = 0; i < smp_threads; i++) {
+            servers_prop[i] = cpu_to_be32(index + i);
+            /* Hack, direct the group queues back to cpu 0 */
+            gservers_prop[i*2] = cpu_to_be32(index + i);
+            gservers_prop[i*2 + 1] = 0;
+        }
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s",
+                           servers_prop, sizeof(servers_prop))));
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+                           gservers_prop, sizeof(gservers_prop))));
+
+        if (env->mmu_model & POWERPC_MMU_1TSEG) {
+            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
+                               segs, sizeof(segs))));
+        }
+
+        /* Advertise VMX/VSX (vector extensions) if available
+         *   0 / no property == no vector extensions
+         *   1               == VMX / Altivec available
+         *   2               == VSX available */
+        if (env->insns_flags & PPC_ALTIVEC) {
+            uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
+
+            _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
+        }
+
+        /* Advertise DFP (Decimal Floating Point) if available
+         *   0 / no property == no DFP
+         *   1               == DFP available */
+        if (env->insns_flags2 & PPC2_DFP) {
+            _FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
+        }
+
+        _FDT((fdt_end_node(fdt)));
+    }
+
+    g_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")));
+
+    _FDT((fdt_property_string(fdt, "device_type",
+                              "PowerPC-External-Interrupt-Presentation")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+    _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_property_cell(fdt, "#interrupt-cells", 2)));
+    _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
+    _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
+
+    _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;
+    sPAPRPHBState *phb;
+
+    fdt = g_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);
+    }
+
+    QLIST_FOREACH(phb, &spapr->phbs, list) {
+        ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
+    }
+
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup PCI 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");
+    }
+
+    spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+
+    _FDT((fdt_pack(fdt)));
+
+    cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
+
+    g_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;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    target_phys_addr_t rma_alloc_size, rma_size;
+    uint32_t initrd_base;
+    long kernel_size, initrd_size, fw_size;
+    long pteg_shift = 17;
+    char *filename;
+
+    spapr = g_malloc0(sizeof(*spapr));
+    QLIST_INIT(&spapr->phbs);
+
+    cpu_ppc_hypercall = emulate_spapr_hypercall;
+
+    /* Allocate RMA if necessary */
+    rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem);
+
+    if (rma_alloc_size == -1) {
+        hw_error("qemu: Unable to create RMA\n");
+        exit(1);
+    }
+    if (rma_alloc_size && (rma_alloc_size < ram_size)) {
+        rma_size = rma_alloc_size;
+    } else {
+        rma_size = ram_size;
+    }
+
+    /* We place the device tree just below either the top of the RMA,
+     * or just below 2GB, whichever is lowere, so that it can be
+     * processed with 32-bit real mode code if necessary */
+    spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE;
+    spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = kvm_enabled() ? "host" : "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 */
+    spapr->ram_limit = ram_size;
+    if (spapr->ram_limit > rma_alloc_size) {
+        ram_addr_t nonrma_base = rma_alloc_size;
+        ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size;
+
+        memory_region_init_ram(ram, NULL, "ppc_spapr.ram", nonrma_size);
+        memory_region_add_subregion(sysmem, nonrma_base, ram);
+    }
+
+    /* 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_memalign(spapr->htab_size, 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;
+
+        /* Tell KVM that we're in PAPR mode */
+        env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
+                             ((pteg_shift + 7) - 18);
+        env->spr[SPR_HIOR] = 0;
+
+        if (kvm_enabled()) {
+            kvmppc_set_papr(env);
+        }
+    }
+
+    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);
+    }
+    g_free(filename);
+
+    /* Set up Interrupt Controller */
+    spapr->icp = xics_system_init(XICS_IRQS);
+    spapr->next_irq = 16;
+
+    /* Set up VIO bus */
+    spapr->vio_bus = spapr_vio_bus_init();
+
+    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i,
+                             serial_hds[i]);
+        }
+    }
+
+    /* Set up PCI */
+    spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
+                     SPAPR_PCI_MEM_WIN_ADDR,
+                     SPAPR_PCI_MEM_WIN_SIZE,
+                     SPAPR_PCI_IO_WIN_ADDR);
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = g_strdup("ibmveth");
+        }
+
+        if (strcmp(nd->model, "ibmveth") == 0) {
+            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd);
+        } else {
+            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
+        }
+    }
+
+    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
+        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i);
+    }
+
+    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 (rma_size < (MIN_RMA_SLOF << 20)) {
+            fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+                    "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
+            exit(1);
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
+        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);
+        }
+        g_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, rma_size,
+                                            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..df88f6a
--- /dev/null
@@ -0,0 +1,310 @@
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+#include "hw/xics.h"
+
+struct VIOsPAPRBus;
+struct sPAPRPHBState;
+struct icp_state;
+
+typedef struct sPAPREnvironment {
+    struct VIOsPAPRBus *vio_bus;
+    QLIST_HEAD(, sPAPRPHBState) phbs;
+    struct icp_state *icp;
+
+    target_phys_addr_t ram_limit;
+    void *htab;
+    long htab_size;
+    target_phys_addr_t fdt_addr, rtas_addr;
+    long rtas_size;
+    void *fdt_skel;
+    target_ulong entry_point;
+    int next_irq;
+    int rtc_offset;
+} 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);
+
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num);
+
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+    return ldl_be_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+    stl_be_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..84281be
--- /dev/null
@@ -0,0 +1,707 @@
+#include "sysemu.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "qemu-char.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 page_shift = 12;
+    target_ulong raddr;
+    target_ulong i;
+    uint8_t *hpte;
+
+    /* only handle 4k and 16M pages for now */
+    if (pteh & HPTE_V_LARGE) {
+#if 0 /* We don't support 64k pages yet */
+        if ((ptel & 0xf000) == 0x1000) {
+            /* 64k page */
+        } else
+#endif
+        if ((ptel & 0xff000) == 0) {
+            /* 16M page */
+            page_shift = 24;
+            /* lowest AVA bit must be 0 for 16M pages */
+            if (pteh & 0x80) {
+                return H_PARAMETER;
+            }
+        } else {
+            return H_PARAMETER;
+        }
+    }
+
+    raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
+
+    if (raddr < spapr->ram_limit) {
+        /* Regular RAM - should have WIMG=0010 */
+        if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
+            return H_PARAMETER;
+        }
+    } else {
+        /* Looks like an IO address */
+        /* FIXME: What WIMG combinations could be sensible for IO?
+         * For now we allow WIMG=010x, but are there others? */
+        /* FIXME: Should we check against registered IO addresses? */
+        if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
+            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;
+}
+
+enum {
+    REMOVE_SUCCESS = 0,
+    REMOVE_NOT_FOUND = 1,
+    REMOVE_PARM = 2,
+    REMOVE_HW = 3,
+};
+
+static target_ulong remove_hpte(CPUState *env, target_ulong ptex,
+                                target_ulong avpn,
+                                target_ulong flags,
+                                target_ulong *vp, target_ulong *rp)
+{
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return REMOVE_PARM;
+    }
+
+    hpte = env->external_htab + (ptex * 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 REMOVE_NOT_FOUND;
+    }
+    *vp = v & ~HPTE_V_HVLOCK;
+    *rp = r;
+    stq_p(hpte, 0);
+    rb = compute_tlbie_rb(v, r, ptex);
+    ppc_tlb_invalidate_one(env, rb);
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return REMOVE_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];
+    int ret;
+
+    ret = remove_hpte(env, pte_index, avpn, flags,
+                      &args[0], &args[1]);
+
+    switch (ret) {
+    case REMOVE_SUCCESS:
+        return H_SUCCESS;
+
+    case REMOVE_NOT_FOUND:
+        return H_NOT_FOUND;
+
+    case REMOVE_PARM:
+        return H_PARAMETER;
+
+    case REMOVE_HW:
+        return H_HARDWARE;
+    }
+
+    assert(0);
+}
+
+#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
+#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
+#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
+#define   H_BULK_REMOVE_END            0xc000000000000000ULL
+#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
+#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
+#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
+#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
+#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
+#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
+#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
+#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
+#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
+#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
+#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
+
+#define H_BULK_REMOVE_MAX_BATCH        4
+
+static target_ulong h_bulk_remove(CPUState *env, sPAPREnvironment *spapr,
+                                  target_ulong opcode, target_ulong *args)
+{
+    int i;
+
+    for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
+        target_ulong *tsh = &args[i*2];
+        target_ulong tsl = args[i*2 + 1];
+        target_ulong v, r, ret;
+
+        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
+            break;
+        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
+            return H_PARAMETER;
+        }
+
+        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
+        *tsh |= H_BULK_REMOVE_RESPONSE;
+
+        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
+            *tsh |= H_BULK_REMOVE_PARM;
+            return H_PARAMETER;
+        }
+
+        ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl,
+                          (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
+                          &v, &r);
+
+        *tsh |= ret << 60;
+
+        switch (ret) {
+        case REMOVE_SUCCESS:
+            *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
+            break;
+
+        case REMOVE_PARM:
+            return H_PARAMETER;
+
+        case REMOVE_HW:
+            return H_HARDWARE;
+        }
+    }
+
+    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_be_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_be_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_be_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_be_phys(rtas_r3);
+    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
+    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
+
+    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+                           nret, rtas_r3 + 12 + 4*nargs);
+}
+
+static target_ulong h_logical_load(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    target_ulong size = args[0];
+    target_ulong addr = args[1];
+
+    switch (size) {
+    case 1:
+        args[0] = ldub_phys(addr);
+        return H_SUCCESS;
+    case 2:
+        args[0] = lduw_phys(addr);
+        return H_SUCCESS;
+    case 4:
+        args[0] = ldl_phys(addr);
+        return H_SUCCESS;
+    case 8:
+        args[0] = ldq_phys(addr);
+        return H_SUCCESS;
+    }
+    return H_PARAMETER;
+}
+
+static target_ulong h_logical_store(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong size = args[0];
+    target_ulong addr = args[1];
+    target_ulong val  = args[2];
+
+    switch (size) {
+    case 1:
+        stb_phys(addr, val);
+        return H_SUCCESS;
+    case 2:
+        stw_phys(addr, val);
+        return H_SUCCESS;
+    case 4:
+        stl_phys(addr, val);
+        return H_SUCCESS;
+    case 8:
+        stq_phys(addr, val);
+        return H_SUCCESS;
+    }
+    return H_PARAMETER;
+}
+
+static target_ulong h_logical_icbi(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    /* Nothing to do on emulation, KVM will trap this in the kernel */
+    return H_SUCCESS;
+}
+
+static target_ulong h_logical_dcbf(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    /* Nothing to do on emulation, KVM will trap this in the kernel */
+    return H_SUCCESS;
+}
+
+static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
+
+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-bulk */
+    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+
+    /* 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);
+
+    /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
+     * here between the "CI" and the "CACHE" variants, they will use whatever
+     * mapping attributes qemu is using. When using KVM, the kernel will
+     * enforce the attributes more strongly
+     */
+    spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
+    spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
+    spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
+    spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
+    spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
+    spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+
+    /* 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..abe1297
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * 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;
+
+    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)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+}
+
+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_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 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_pci.c b/hw/spapr_pci.c
new file mode 100644 (file)
index 0000000..9b6a032
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * QEMU sPAPR PCI host originated from Uninorth PCI host
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
+ * Copyright (C) 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 "pci.h"
+#include "pci_host.h"
+#include "hw/spapr.h"
+#include "hw/spapr_pci.h"
+#include "exec-memory.h"
+#include <libfdt.h>
+
+#include "hw/pci_internals.h"
+
+static const uint32_t bars[] = {
+    PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
+    PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
+    PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
+    /*, PCI_ROM_ADDRESS*/
+};
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr,
+                           uint64_t buid, uint32_t config_addr)
+{
+    DeviceState *qdev;
+    int devfn = (config_addr >> 8) & 0xFF;
+    sPAPRPHBState *phb;
+
+    QLIST_FOREACH(phb, &spapr->phbs, list) {
+        if (phb->buid != buid) {
+            continue;
+        }
+
+        QTAILQ_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) {
+            PCIDevice *dev = (PCIDevice *)qdev;
+            if (dev->devfn == devfn) {
+                return dev;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
+                                     uint32_t token, uint32_t nargs,
+                                     target_ulong args,
+                                     uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0) & 0xFF;
+    val = pci_default_read_config(dev, addr, size);
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, val);
+}
+
+static void rtas_read_pci_config(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0) & 0xFF;
+    val = pci_default_read_config(dev, addr, size);
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, val);
+}
+
+static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
+                                      uint32_t token, uint32_t nargs,
+                                      target_ulong args,
+                                      uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    val = rtas_ld(args, 4);
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0) & 0xFF;
+    pci_default_write_config(dev, addr, val, size);
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_write_pci_config(sPAPREnvironment *spapr,
+                                  uint32_t token, uint32_t nargs,
+                                  target_ulong args,
+                                  uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    val = rtas_ld(args, 2);
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0) & 0xFF;
+    pci_default_write_config(dev, addr, val, size);
+    rtas_st(rets, 0, 0);
+}
+
+static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    /*
+     * Here we need to convert pci_dev + irq_num to some unique value
+     * which is less than number of IRQs on the specific bus (now it
+     * is 16).  At the moment irq_num == device_id (number of the
+     * slot?)
+     * FIXME: we should swizzle in fn and irq_num
+     */
+    return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI;
+}
+
+static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
+{
+    /*
+     * Here we use the number returned by pci_spapr_map_irq to find a
+     * corresponding qemu_irq.
+     */
+    sPAPRPHBState *phb = opaque;
+
+    qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
+}
+
+static int spapr_phb_init(SysBusDevice *s)
+{
+    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+    int i;
+
+    /* Initialize the LSI table */
+    for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) {
+        qemu_irq qirq;
+        uint32_t num;
+
+        qirq = spapr_allocate_irq(0, &num);
+        if (!qirq) {
+            return -1;
+        }
+
+        phb->lsi_table[i].dt_irq = num;
+        phb->lsi_table[i].qirq = qirq;
+    }
+
+    return 0;
+}
+
+static int spapr_main_pci_host_init(PCIDevice *d)
+{
+    return 0;
+}
+
+static PCIDeviceInfo spapr_main_pci_host_info = {
+    .qdev.name = "spapr-pci-host-bridge",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = spapr_main_pci_host_init,
+};
+
+static void spapr_register_devices(void)
+{
+    sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
+                        spapr_phb_init);
+    pci_qdev_register(&spapr_main_pci_host_info);
+}
+
+device_init(spapr_register_devices)
+
+static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    assert(0);
+}
+
+static void spapr_io_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t data, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, data);
+        return;
+    case 2:
+        cpu_outw(addr, data);
+        return;
+    case 4:
+        cpu_outl(addr, data);
+        return;
+    }
+    assert(0);
+}
+
+static MemoryRegionOps spapr_io_ops = {
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .read = spapr_io_read,
+    .write = spapr_io_write
+};
+
+void spapr_create_phb(sPAPREnvironment *spapr,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    sPAPRPHBState *phb;
+    PCIBus *bus;
+    char namebuf[strlen(busname)+11];
+
+    dev = qdev_create(NULL, "spapr-pci-host-bridge");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    phb = FROM_SYSBUS(sPAPRPHBState, s);
+
+    phb->mem_win_addr = mem_win_addr;
+
+    sprintf(namebuf, "%s-mem", busname);
+    memory_region_init(&phb->memspace, namebuf, INT64_MAX);
+
+    sprintf(namebuf, "%s-memwindow", busname);
+    memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
+                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size);
+    memory_region_add_subregion(get_system_memory(), mem_win_addr,
+                                &phb->memwindow);
+
+    phb->io_win_addr = io_win_addr;
+
+    /* On ppc, we only have MMIO no specific IO space from the CPU
+     * perspective.  In theory we ought to be able to embed the PCI IO
+     * memory region direction in the system memory space.  However,
+     * if any of the IO BAR subregions use the old_portio mechanism,
+     * that won't be processed properly unless accessed from the
+     * system io address space.  This hack to bounce things via
+     * system_io works around the problem until all the users of
+     * old_portion are updated */
+    sprintf(namebuf, "%s-io", busname);
+    memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    /* FIXME: fix to support multiple PHBs */
+    memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
+
+    sprintf(namebuf, "%s-iowindow", busname);
+    memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
+                          namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    memory_region_add_subregion(get_system_memory(), io_win_addr,
+                                &phb->iowindow);
+
+    phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname,
+                                                 pci_spapr_set_irq,
+                                                 pci_spapr_map_irq,
+                                                 phb,
+                                                 &phb->memspace, &phb->iospace,
+                                                 PCI_DEVFN(0, 0),
+                                                 SPAPR_PCI_NUM_LSI);
+
+    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+
+    QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+
+    /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */
+}
+
+/* Macros to operate with address in OF binding to PCI */
+#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
+#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
+#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
+#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
+#define b_ss(x)         b_x((x), 24, 2) /* the space code */
+#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
+#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
+#define b_fff(x)        b_x((x), 8, 3)  /* function number */
+#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
+
+static uint32_t regtype_to_ss(uint8_t type)
+{
+    if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        return 3;
+    }
+    if (type == PCI_BASE_ADDRESS_SPACE_IO) {
+        return 1;
+    }
+    return 2;
+}
+
+int spapr_populate_pci_devices(sPAPRPHBState *phb,
+                               uint32_t xics_phandle,
+                               void *fdt)
+{
+    PCIBus *bus = phb->host_state.bus;
+    int bus_off, node_off = 0, devid, fn, i, n, devices;
+    DeviceState *qdev;
+    char nodename[256];
+    struct {
+        uint32_t hi;
+        uint64_t addr;
+        uint64_t size;
+    } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
+          assigned_addresses[PCI_NUM_REGIONS];
+    uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
+    struct {
+        uint32_t hi;
+        uint64_t child;
+        uint64_t parent;
+        uint64_t size;
+    } __attribute__((packed)) ranges[] = {
+        {
+            cpu_to_be32(b_ss(1)), cpu_to_be64(0),
+            cpu_to_be64(phb->io_win_addr),
+            cpu_to_be64(memory_region_size(&phb->iospace)),
+        },
+        {
+            cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
+            cpu_to_be64(phb->mem_win_addr),
+            cpu_to_be64(memory_region_size(&phb->memwindow)),
+        },
+    };
+    uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
+    uint32_t interrupt_map_mask[] = {
+        cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+    uint32_t interrupt_map[bus->nirq][7];
+
+    /* Start populating the FDT */
+    sprintf(nodename, "pci@%" PRIx64, phb->buid);
+    bus_off = fdt_add_subnode(fdt, 0, nodename);
+    if (bus_off < 0) {
+        return bus_off;
+    }
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            return ret;                                            \
+        }                                                          \
+    } while (0)
+
+    /* Write PHB properties */
+    _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
+    _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
+    _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
+    _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
+    _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
+    _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
+                     &interrupt_map_mask, sizeof(interrupt_map_mask)));
+
+    /* Populate PCI devices and allocate IRQs */
+    devices = 0;
+    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
+        PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+        int irq_index = pci_spapr_map_irq(dev, 0);
+        uint32_t *irqmap = interrupt_map[devices];
+        uint8_t *config = dev->config;
+
+        devid = dev->devfn >> 3;
+        fn = dev->devfn & 7;
+
+        sprintf(nodename, "pci@%u,%u", devid, fn);
+
+        /* Allocate interrupt from the map */
+        if (devid > bus->nirq)  {
+            printf("Unexpected behaviour in spapr_populate_pci_devices,"
+                    "wrong devid %u\n", devid);
+            exit(-1);
+        }
+        irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+        irqmap[1] = 0;
+        irqmap[2] = 0;
+        irqmap[3] = 0;
+        irqmap[4] = cpu_to_be32(xics_phandle);
+        irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq);
+        irqmap[6] = cpu_to_be32(0x8);
+
+        /* Add node to FDT */
+        node_off = fdt_add_subnode(fdt, bus_off, nodename);
+        if (node_off < 0) {
+            return node_off;
+        }
+
+        _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
+                              pci_get_word(&config[PCI_VENDOR_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
+                              pci_get_word(&config[PCI_DEVICE_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
+                              pci_get_byte(&config[PCI_REVISION_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
+                              pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
+        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
+                              pci_get_word(&config[PCI_SUBSYSTEM_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
+                              pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
+
+        /* Config space region comes first */
+        reg[0].hi = cpu_to_be32(
+            b_n(0) |
+            b_p(0) |
+            b_t(0) |
+            b_ss(0/*config*/) |
+            b_bbbbbbbb(0) |
+            b_ddddd(devid) |
+            b_fff(fn));
+        reg[0].addr = 0;
+        reg[0].size = 0;
+
+        n = 0;
+        for (i = 0; i < ARRAY_SIZE(bars); ++i) {
+            if (0 == dev->io_regions[i].size) {
+                continue;
+            }
+
+            reg[n+1].hi = cpu_to_be32(
+                b_n(0) |
+                b_p(0) |
+                b_t(0) |
+                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
+                b_bbbbbbbb(0) |
+                b_ddddd(devid) |
+                b_fff(fn) |
+                b_rrrrrrrr(bars[i]));
+            reg[n+1].addr = 0;
+            reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
+
+            assigned_addresses[n].hi = cpu_to_be32(
+                b_n(1) |
+                b_p(0) |
+                b_t(0) |
+                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
+                b_bbbbbbbb(0) |
+                b_ddddd(devid) |
+                b_fff(fn) |
+                b_rrrrrrrr(bars[i]));
+
+            /*
+             * Writing zeroes to assigned_addresses causes the guest kernel to
+             * reassign BARs
+             */
+            assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
+            assigned_addresses[n].size = reg[n+1].size;
+
+            ++n;
+        }
+        _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
+        _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
+                         assigned_addresses,
+                         sizeof(assigned_addresses[0])*(n)));
+        _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
+                              pci_get_byte(&config[PCI_INTERRUPT_PIN])));
+
+        ++devices;
+    }
+
+    /* Write interrupt map */
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
+                     devices * sizeof(interrupt_map[0])));
+
+    return 0;
+}
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
new file mode 100644 (file)
index 0000000..213340c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * QEMU SPAPR PCI BUS definitions
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy <aik@au1.ibm.com>
+ *
+ * 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 !defined(__HW_SPAPR_H__)
+#error Please include spapr.h before this file!
+#endif
+
+#if !defined(__HW_SPAPR_PCI_H__)
+#define __HW_SPAPR_PCI_H__
+
+#include "hw/pci_host.h"
+#include "hw/xics.h"
+
+#define SPAPR_PCI_NUM_LSI   16
+
+typedef struct sPAPRPHBState {
+    SysBusDevice busdev;
+    PCIHostState host_state;
+
+    uint64_t buid;
+
+    MemoryRegion memspace, iospace;
+    target_phys_addr_t mem_win_addr, io_win_addr;
+    MemoryRegion memwindow, iowindow;
+
+    struct {
+        uint32_t dt_irq;
+        qemu_irq qirq;
+    } lsi_table[SPAPR_PCI_NUM_LSI];
+
+    QLIST_ENTRY(sPAPRPHBState) list;
+} sPAPRPHBState;
+
+#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
+#define SPAPR_PCI_IO_WIN_SIZE        0x10000
+
+void spapr_create_phb(sPAPREnvironment *spapr,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr);
+
+int spapr_populate_pci_devices(sPAPRPHBState *phb,
+                               uint32_t xics_phandle,
+                               void *fdt);
+
+#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
new file mode 100644 (file)
index 0000000..d1ac74c
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * 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,
+                                                 SPAPR_VTY_BASE_ADDRESS);
+
+    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, spapr->rtc_offset);
+
+    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_set_time_of_day(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    struct tm tm;
+
+    tm.tm_year = rtas_ld(args, 0) - 1900;
+    tm.tm_mon = rtas_ld(args, 1) - 1;
+    tm.tm_mday = rtas_ld(args, 2);
+    tm.tm_hour = rtas_ld(args, 3);
+    tm.tm_min = rtas_ld(args, 4);
+    tm.tm_sec = rtas_ld(args, 5);
+
+    /* Just generate a monitor event for the change */
+    rtc_change_mon_event(&tm);
+    spapr->rtc_offset = qemu_timedate_diff(&tm);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+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("set-time-of-day", rtas_set_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..464fe87
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * 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"
+#include "hw/xics.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),
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        if (dev->reg == reg) {
+            return dev;
+        }
+    }
+
+    return NULL;
+}
+
+static char *vio_format_dev_name(VIOsPAPRDevice *dev)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    char *name;
+
+    /* Device tree style name device@reg */
+    if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
+        return NULL;
+    }
+
+    return name;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+                            void *fdt)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    int vdevice_off, node_off, ret;
+    char *dt_name;
+
+    vdevice_off = fdt_path_offset(fdt, "/vdevice");
+    if (vdevice_off < 0) {
+        return vdevice_off;
+    }
+
+    dt_name = vio_format_dev_name(dev);
+    if (!dt_name) {
+        return -ENOMEM;
+    }
+
+    node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
+    free(dt_name);
+    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 = kvmppc_create_spapr_tce(dev->reg,
+                                                  dev->rtce_window_size,
+                                                  &dev->kvmtce_fd);
+
+        if (!dev->rtce_table) {
+            dev->rtce_table = g_malloc0(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;
+    }
+
+    QTAILQ_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;
+
+    /* Don't overwrite ids assigned on the command line */
+    if (!dev->qdev.id) {
+        id = vio_format_dev_name(dev);
+        if (!id) {
+            return -1;
+        }
+        dev->qdev.id = id;
+    }
+
+    dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
+    if (!dev->qirq) {
+        return -1;
+    }
+
+    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
+static int compare_reg(const void *p1, const void *p2)
+{
+    VIOsPAPRDevice const *dev1, *dev2;
+
+    dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
+    dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
+
+    if (dev1->reg < dev2->reg) {
+        return -1;
+    }
+    if (dev1->reg == dev2->reg) {
+        return 0;
+    }
+
+    /* dev1->reg > dev2->reg */
+    return 1;
+}
+
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+    DeviceState *qdev, **qdevs;
+    int i, num, ret = 0;
+
+    /* Count qdevs on the bus list */
+    num = 0;
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
+        num++;
+    }
+
+    /* Copy out into an array of pointers */
+    qdevs = g_malloc(sizeof(qdev) * num);
+    num = 0;
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
+        qdevs[num++] = qdev;
+    }
+
+    /* Sort the array */
+    qsort(qdevs, num, sizeof(qdev), compare_reg);
+
+    /* Hack alert. Give the devices to libfdt in reverse order, we happen
+     * to know that will mean they are in forward order in the tree. */
+    for (i = num - 1; i >= 0; i--) {
+        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
+
+        ret = vio_make_devnode(dev, fdt);
+
+        if (ret < 0) {
+            goto out;
+        }
+    }
+
+    ret = 0;
+out:
+    free(qdevs);
+
+    return ret;
+}
+
+int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
+{
+    VIOsPAPRDevice *dev;
+    char *name, *path;
+    int ret, offset;
+
+    dev = spapr_vty_get_default(bus);
+    if (!dev)
+        return 0;
+
+    offset = fdt_path_offset(fdt, "/chosen");
+    if (offset < 0) {
+        return offset;
+    }
+
+    name = vio_format_dev_name(dev);
+    if (!name) {
+        return -ENOMEM;
+    }
+
+    if (asprintf(&path, "/vdevice/%s", name) < 0) {
+        path = NULL;
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
+out:
+    free(name);
+    free(path);
+
+    return ret;
+}
+#endif /* CONFIG_FDT */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
new file mode 100644 (file)
index 0000000..9fcd304
--- /dev/null
@@ -0,0 +1,117 @@
+#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,
+};
+
+#define SPAPR_VTY_BASE_ADDRESS     0x30000000
+
+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;
+    int kvmtce_fd;
+    VIOsPAPR_CRQ crq;
+} VIOsPAPRDevice;
+
+#define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \
+        DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \
+        DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \
+                           default_dma_window)
+
+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_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
+
+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);
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
+
+VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
+
+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..00e2d2d
--- /dev/null
@@ -0,0 +1,969 @@
+/*
+ * 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 */
+    SCSIRequest             *sreq;
+    uint32_t                qtag; /* qemu tag != srp tag */
+    int                     lun;
+    int                     active;
+    long                    data_len;
+    int                     writing;
+    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(vscsi_req *req)
+{
+    if (req->sreq != NULL) {
+        scsi_req_unref(req->sreq);
+    }
+    req->sreq = NULL;
+    req->active = 0;
+}
+
+static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
+{
+    int channel = 0, id = 0;
+
+retry:
+    switch (srp_lun >> 62) {
+    case 0:
+        if ((srp_lun >> 56) != 0) {
+            channel = (srp_lun >> 56) & 0x3f;
+            id = (srp_lun >> 48) & 0xff;
+            srp_lun <<= 16;
+            goto retry;
+        }
+        *lun = (srp_lun >> 48) & 0xff;
+        break;
+
+    case 1:
+        *lun = (srp_lun >> 48) & 0x3fff;
+        break;
+    case 2:
+        channel = (srp_lun >> 53) & 0x7;
+        id = (srp_lun >> 56) & 0x3f;
+        *lun = (srp_lun >> 48) & 0x1f;
+        break;
+    case 3:
+        *lun = -1;
+        return NULL;
+    default:
+        abort();
+    }
+
+    return scsi_device_find(bus, channel, id, *lun);
+}
+
+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;
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    uint8_t *buf;
+    int rc = 0;
+
+    dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n",
+            sreq->tag, len, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (len) {
+        buf = scsi_req_get_buf(sreq);
+        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        scsi_req_abort(req->sreq, CHECK_CONDITION);
+        return;
+    }
+
+    /* Start next chunk */
+    req->data_len -= rc;
+    scsi_req_continue(sreq);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    int32_t res_in = 0, res_out = 0;
+
+    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
+            reason, sreq->tag, status, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (status == CHECK_CONDITION) {
+        req->senselen = scsi_req_get_sense(req->sreq, req->sense,
+                                           sizeof(req->sense));
+        dprintf("VSCSI: Sense data, %d bytes:\n", len);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                req->sense[0], req->sense[1], req->sense[2], req->sense[3],
+                req->sense[4], req->sense[5], req->sense[6], req->sense[7]);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                req->sense[8], req->sense[9], req->sense[10], req->sense[11],
+                req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
+    }
+
+    dprintf("VSCSI: Command complete err=%d\n", status);
+    if (status == 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, status, res_in, res_out);
+    vscsi_put_req(req);
+}
+
+static void vscsi_request_cancelled(SCSIRequest *sreq)
+{
+    vscsi_req *req = sreq->hba_private;
+
+    vscsi_put_req(req);
+}
+
+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, lun;
+
+    sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
+    if (!sdev) {
+        dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
+        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->lun = lun;
+    req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
+    n = scsi_req_enqueue(req->sreq);
+
+    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;
+        } else if (n < 0) {
+            req->data_len = -n;
+        }
+        scsi_req_continue(req->sreq);
+    }
+    /* 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");
+        g_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(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 const struct SCSIBusInfo vscsi_scsi_info = {
+    .tcq = true,
+    .max_channel = 7, /* logical unit addressing format */
+    .max_target = 63,
+    .max_lun = 31,
+
+    .transfer_data = vscsi_transfer_data,
+    .complete = vscsi_command_complete,
+    .cancel = vscsi_request_cancelled
+};
+
+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, &vscsi_scsi_info);
+    if (!dev->qdev.hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    return 0;
+}
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vscsi");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_init_nofail(dev);
+}
+
+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_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 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..386ccf7
--- /dev/null
@@ -0,0 +1,215 @@
+#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_fe_write() return value */
+    qemu_chr_fe_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    if (!dev->chardev) {
+        fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
+        exit(1);
+    }
+
+    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+                          vty_receive, NULL, dev);
+
+    return 0;
+}
+
+/* Forward declaration */
+static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
+
+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;
+    uint8_t buf[16];
+
+    sdev = vty_lookup(spapr, reg);
+    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;
+    uint8_t buf[16];
+
+    sdev = vty_lookup(spapr, reg);
+    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)
+{
+    DeviceState *dev;
+
+    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);
+}
+
+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_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
+        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
+{
+    VIOsPAPRDevice *sdev, *selected;
+    DeviceState *iter;
+
+    /*
+     * To avoid the console bouncing around we want one VTY to be
+     * the "default". We haven't really got anything to go on, so
+     * arbitrarily choose the one with the lowest reg value.
+     */
+
+    selected = NULL;
+    QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
+        /* Only look at VTY devices */
+        if (iter->info != &spapr_vty.qdev) {
+            continue;
+        }
+
+        sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
+
+        /* First VTY we've found, so it is selected for now */
+        if (!selected) {
+            selected = sdev;
+            continue;
+        }
+
+        /* Choose VTY with lowest reg value */
+        if (sdev->reg < selected->reg) {
+            selected = sdev;
+        }
+    }
+
+    return selected;
+}
+
+static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
+{
+    VIOsPAPRDevice *sdev;
+
+    sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    if (!sdev && reg == 0) {
+        /* Hack for kernel early debug, which always specifies reg==0.
+         * We search all VIO devices, and grab the vty with the lowest
+         * reg.  This attempts to mimic existing PowerVM behaviour
+         * (early debug does work there, despite having no vty with
+         * reg==0. */
+        return spapr_vty_get_default(spapr->vio_bus);
+    }
+
+    return sdev;
+}
+
+static void spapr_vty_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vty);
+}
+device_init(spapr_vty_register);
index 5b1e42dff3aa6999860da787618e0830f30662a7..23f9d41ff72cfaaa9a43f810f44028b5f882c8f6 100644 (file)
@@ -24,6 +24,7 @@
 #include "boards.h"
 #include "blockdev.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #undef REG_FMT
 #define REG_FMT                        "0x%02lx"
 
 typedef struct {
     SysBusDevice busdev;
-    NANDFlashState *nand;
+    MemoryRegion iomem;
+    DeviceState *nand;
     uint8_t ctl;
     uint8_t manf_id;
     uint8_t chip_id;
     ECCState ecc;
 } SLNANDState;
 
-static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t sl_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     SLNANDState *s = (SLNANDState *) opaque;
     int ryby;
@@ -85,6 +87,10 @@ static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
             return s->ctl;
 
     case FLASH_FLASHIO:
+        if (size == 4) {
+            return ecc_digest(&s->ecc, nand_getio(s->nand)) |
+                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
+        }
         return ecc_digest(&s->ecc, nand_getio(s->nand));
 
     default:
@@ -93,19 +99,8 @@ static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static uint32_t sl_readl(void *opaque, target_phys_addr_t addr)
-{
-    SLNANDState *s = (SLNANDState *) opaque;
-
-    if (addr == FLASH_FLASHIO)
-        return ecc_digest(&s->ecc, nand_getio(s->nand)) |
-                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
-
-    return sl_readb(opaque, addr);
-}
-
-static void sl_writeb(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+static void sl_write(void *opaque, target_phys_addr_t addr,
+                     uint64_t value, unsigned size)
 {
     SLNANDState *s = (SLNANDState *) opaque;
 
@@ -139,15 +134,10 @@ enum {
     FLASH_1024M,
 };
 
-static CPUReadMemoryFunc * const sl_readfn[] = {
-    sl_readb,
-    sl_readb,
-    sl_readl,
-};
-static CPUWriteMemoryFunc * const sl_writefn[] = {
-    sl_writeb,
-    sl_writeb,
-    sl_writeb,
+static const MemoryRegionOps sl_ops = {
+    .read = sl_read,
+    .write = sl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void sl_flash_register(PXA2xxState *cpu, int size)
@@ -167,18 +157,17 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
 }
 
 static int sl_nand_init(SysBusDevice *dev) {
-    int iomemtype;
     SLNANDState *s;
+    DriveInfo *nand;
 
     s = FROM_SYSBUS(SLNANDState, dev);
 
     s->ctl = 0;
-    s->nand = nand_init(s->manf_id, s->chip_id);
-
-    iomemtype = cpu_register_io_memory(sl_readfn,
-                    sl_writefn, s, DEVICE_NATIVE_ENDIAN);
+    nand = drive_get(IF_MTD, 0, 0);
+    s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
 
-    sysbus_init_mmio(dev, 0x40, iomemtype);
+    memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     return 0;
 }
@@ -393,7 +382,7 @@ static void spitz_keyboard_tick(void *opaque)
             s->fifopos = 0;
     }
 
-    qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) +
                    get_ticks_per_sec() / 32);
 }
 
@@ -485,7 +474,7 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
         qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
                 qdev_get_gpio_in(dev, i));
 
-    qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock));
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock));
 
     qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
 }
@@ -506,7 +495,7 @@ static int spitz_keyboard_init(SysBusDevice *dev)
 
     spitz_keyboard_pre_map(s);
 
-    s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
+    s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s);
     qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
     qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
 
@@ -706,17 +695,13 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
 static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
 {
     PCMCIACardState *md;
-    BlockDriverState *bs;
     DriveInfo *dinfo;
 
     dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo)
+    if (!dinfo || dinfo->media_cd)
         return;
-    bs = dinfo->bdrv;
-    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
-        md = dscm1xxxx_init(dinfo);
-        pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-    }
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
 }
 
 /* Wm8750 and Max7310 on I2C */
@@ -898,17 +883,20 @@ static void spitz_common_init(ram_addr_t ram_size,
 {
     PXA2xxState *cpu;
     DeviceState *scp0, *scp1 = NULL;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
 
     /* Setup CPU & memory */
-    cpu = pxa270_init(spitz_binfo.ram_size, cpu_model);
+    cpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model);
 
     sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
 
-    cpu_register_physical_memory(0, SPITZ_ROM,
-                    qemu_ram_alloc(NULL, "spitz.rom", SPITZ_ROM) | IO_MEM_ROM);
+    memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
 
     /* Setup peripherals */
     spitz_keyboard_register(cpu);
diff --git a/hw/srp.h b/hw/srp.h
new file mode 100644 (file)
index 0000000..3009bd5
--- /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];
+} QEMU_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];
+} QEMU_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 QEMU_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 QEMU_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];
+} QEMU_PACKED;
+
+#endif /* SCSI_SRP_H */
index 108c0683c8907c806434609d9eff7eae1d435c36..401fdf592a54259e65fa4bb0e7a271ebea3b6941 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 /* The controller can support a variety of different displays, but we only
@@ -93,7 +93,7 @@ static int ssd0303_send(i2c_slave *i2c, uint8_t data)
             DPRINTF("cmd 0x%02x\n", data);
             s->mode = SSD0303_IDLE;
             switch (data) {
-            case 0x00 ... 0x0f: /* Set lower colum address.  */
+            case 0x00 ... 0x0f: /* Set lower column address.  */
                 s->col = (s->col & 0xf0) | (data & 0xf);
                 break;
             case 0x10 ... 0x20: /* Set higher column address.  */
index 86439611449d4431c469bbdd06b55c7ced807086..1eb3823fed8eede134d699d3f8006d254700fe6d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 /* The controller can support a variety of different displays, but we only
index fb4b64927901f9c33757887090892e99ef218ceb..18dabd64a6295f2db934df003b8a3b0194b81ac9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007-2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 
 #include "blockdev.h"
index cfe7c072f1a3b1b330af07eb6e48d19a25d86a6d..9842fe74722964c863a1fb11c6638c95b057f77d 100644 (file)
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 
 #include "ssi.h"
@@ -25,8 +25,8 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
     SSIBus *bus;
 
     bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
-    if (QLIST_FIRST(&bus->qbus.children) != dev
-        || QLIST_NEXT(dev, sibling) != NULL) {
+    if (QTAILQ_FIRST(&bus->qbus.children) != dev
+        || QTAILQ_NEXT(dev, sibling) != NULL) {
         hw_error("Too many devices on SSI bus");
     }
 
@@ -61,7 +61,7 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
     DeviceState *dev;
     SSISlave *slave;
-    dev = QLIST_FIRST(&bus->qbus.children);
+    dev = QTAILQ_FIRST(&bus->qbus.children);
     if (!dev) {
         return 0;
     }
index b90327305ae601d3981bbd694b8deca3acd0fc99..2bf1c235dc657bc8b8ccd8cd0094166d95f6f9ed 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -14,8 +14,8 @@
 #include "qemu-timer.h"
 #include "i2c.h"
 #include "net.h"
-#include "sysemu.h"
 #include "boards.h"
+#include "exec-memory.h"
 
 #define GPIO_A 0
 #define GPIO_B 1
@@ -79,7 +79,7 @@ static void gptm_reload(gptm_state *s, int n, int reset)
 {
     int64_t tick;
     if (reset)
-        tick = qemu_get_clock(vm_clock);
+        tick = qemu_get_clock_ns(vm_clock);
     else
         tick = s->tick[n];
 
@@ -280,64 +280,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)
 {
@@ -353,10 +317,9 @@ static int stellaris_gptm_init(SysBusDevice *dev)
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     s->opaque[0] = s->opaque[1] = s;
-    s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]);
-    s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]);
-    register_savevm(&dev->qdev, "stellaris_gptm", -1, 1,
-                    gptm_save, gptm_load, 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]);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
     return 0;
 }
 
@@ -370,6 +333,7 @@ typedef struct {
     uint32_t int_mask;
     uint32_t resc;
     uint32_t rcc;
+    uint32_t rcc2;
     uint32_t rcgc[3];
     uint32_t scgc[3];
     uint32_t dcgc[3];
@@ -424,6 +388,32 @@ static uint32_t pllcfg_fury[16] = {
     0xb11c /* 8.192 Mhz */
 };
 
+#define DID0_VER_MASK        0x70000000
+#define DID0_VER_0           0x00000000
+#define DID0_VER_1           0x10000000
+
+#define DID0_CLASS_MASK      0x00FF0000
+#define DID0_CLASS_SANDSTORM 0x00000000
+#define DID0_CLASS_FURY      0x00010000
+
+static int ssys_board_class(const ssys_state *s)
+{
+    uint32_t did0 = s->board->did0;
+    switch (did0 & DID0_VER_MASK) {
+    case DID0_VER_0:
+        return DID0_CLASS_SANDSTORM;
+    case DID0_VER_1:
+        switch (did0 & DID0_CLASS_MASK) {
+        case DID0_CLASS_SANDSTORM:
+        case DID0_CLASS_FURY:
+            return did0 & DID0_CLASS_MASK;
+        }
+        /* for unknown classes, fall through */
+    default:
+        hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
+    }
+}
+
 static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
 {
     ssys_state *s = (ssys_state *)opaque;
@@ -467,12 +457,18 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
         {
             int xtal;
             xtal = (s->rcc >> 6) & 0xf;
-            if (s->board->did0 & (1 << 16)) {
+            switch (ssys_board_class(s)) {
+            case DID0_CLASS_FURY:
                 return pllcfg_fury[xtal];
-            } else {
+            case DID0_CLASS_SANDSTORM:
                 return pllcfg_sandstorm[xtal];
+            default:
+                hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
+                return 0;
             }
         }
+    case 0x070: /* RCC2 */
+        return s->rcc2;
     case 0x100: /* RCGC0 */
         return s->rcgc[0];
     case 0x104: /* RCGC1 */
@@ -505,9 +501,21 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
     }
 }
 
+static bool ssys_use_rcc2(ssys_state *s)
+{
+    return (s->rcc2 >> 31) & 0x1;
+}
+
+/*
+ * Caculate the sys. clock period in ms.
+ */
 static void ssys_calculate_system_clock(ssys_state *s)
 {
-    system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+    if (ssys_use_rcc2(s)) {
+        system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
+    } else {
+        system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+    }
 }
 
 static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
@@ -543,6 +551,18 @@ static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
         s->rcc = value;
         ssys_calculate_system_clock(s);
         break;
+    case 0x070: /* RCC2 */
+        if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
+            break;
+        }
+
+        if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
+            /* PLL enable.  */
+            s->int_status |= (1 << 6);
+        }
+        s->rcc2 = value;
+        ssys_calculate_system_clock(s);
+        break;
     case 0x100: /* RCGC0 */
         s->rcgc[0] = value;
         break;
@@ -600,63 +620,49 @@ static void ssys_reset(void *opaque)
 
     s->pborctl = 0x7ffd;
     s->rcc = 0x078e3ac0;
+
+    if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
+        s->rcc2 = 0;
+    } else {
+        s->rcc2 = 0x07802810;
+    }
     s->rcgc[0] = 1;
     s->scgc[0] = 1;
     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 = 2,
+    .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_V(rcc2, ssys_state, 2),
+        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)
@@ -664,7 +670,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
     int iomemtype;
     ssys_state *s;
 
-    s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
+    s = (ssys_state *)g_malloc0(sizeof(ssys_state));
     s->irq = irq;
     s->board = board;
     /* Most devices come preprogrammed with a MAC address in the user data. */
@@ -676,7 +682,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 +850,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 +883,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 +1121,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]);
+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()
     }
-    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);
-    }
-    s->noise = qemu_get_be32(f);
-
-    return 0;
-}
+};
 
 static int stellaris_adc_init(SysBusDevice *dev)
 {
@@ -1201,8 +1172,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 +1204,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 +1223,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;
 }
 
@@ -1300,6 +1261,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
         0x40024000, 0x40025000, 0x40026000};
     static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
 
+    MemoryRegion *address_space_mem = get_system_memory();
     qemu_irq *pic;
     DeviceState *gpio_dev[7];
     qemu_irq gpio_in[7][8];
@@ -1314,7 +1276,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
 
     flash_size = ((board->dc0 & 0xffff) + 1) << 1;
     sram_size = (board->dc0 >> 18) + 1;
-    pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
+    pic = armv7m_init(address_space_mem,
+                      flash_size, sram_size, kernel_filename, cpu_model);
 
     if (board->dc1 & (1 << 16)) {
         dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
@@ -1334,11 +1297,11 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
         }
     }
 
-    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
+    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
 
     for (i = 0; i < 7; i++) {
         if (board->dc4 & (1 << i)) {
-            gpio_dev[i] = sysbus_create_simple("pl061", gpio_addr[i],
+            gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
                                                pic[gpio_irq[i]]);
             for (j = 0; j < 8; j++) {
                 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
index 6a0583a256e60fe10e98c098685301fb0cbffc55..d5613ffffdce9c38c90a26ec15b6e2caa1cde1b2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 #include "sysbus.h"
 #include "net.h"
@@ -69,7 +69,7 @@ typedef struct {
     NICState *nic;
     NICConf conf;
     qemu_irq irq;
-    int mmio_index;
+    MemoryRegion mmio;
 } stellaris_enet_state;
 
 static void stellaris_enet_update(stellaris_enet_state *s)
@@ -130,7 +130,8 @@ static int stellaris_enet_can_receive(VLANClientState *nc)
     return (s->np < 31);
 }
 
-static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset)
+static uint64_t stellaris_enet_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
 {
     stellaris_enet_state *s = (stellaris_enet_state *)opaque;
     uint32_t val;
@@ -198,7 +199,7 @@ static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void stellaris_enet_write(void *opaque, target_phys_addr_t offset,
-                        uint32_t value)
+                                 uint64_t value, unsigned size)
 {
     stellaris_enet_state *s = (stellaris_enet_state *)opaque;
 
@@ -303,17 +304,12 @@ static void stellaris_enet_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const stellaris_enet_readfn[] = {
-   stellaris_enet_read,
-   stellaris_enet_read,
-   stellaris_enet_read
+static const MemoryRegionOps stellaris_enet_ops = {
+    .read = stellaris_enet_read,
+    .write = stellaris_enet_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const stellaris_enet_writefn[] = {
-   stellaris_enet_write,
-   stellaris_enet_write,
-   stellaris_enet_write
-};
 static void stellaris_enet_reset(stellaris_enet_state *s)
 {
     s->mdv = 0x80;
@@ -391,9 +387,9 @@ static void stellaris_enet_cleanup(VLANClientState *nc)
 
     unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
 
-    cpu_unregister_io_memory(s->mmio_index);
+    memory_region_destroy(&s->mmio);
 
-    qemu_free(s);
+    g_free(s);
 }
 
 static NetClientInfo net_stellaris_enet_info = {
@@ -408,10 +404,9 @@ static int stellaris_enet_init(SysBusDevice *dev)
 {
     stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
 
-    s->mmio_index = cpu_register_io_memory(stellaris_enet_readfn,
-                                           stellaris_enet_writefn, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, s->mmio_index);
+    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
+                          0x1000);
+    sysbus_init_mmio_region(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
index 16aae96f2f563b08b8d409bec29ecb093c267728..68c600c04c5d76230c46d0a532eac225eecfad03 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 #include "hw.h"
 #include "devices.h"
@@ -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)
@@ -78,14 +77,13 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
     gamepad_state *s;
     int i;
 
-    s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state));
-    s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button));
+    s = (gamepad_state *)g_malloc0(sizeof (gamepad_state));
+    s->buttons = (gamepad_button *)g_malloc0(n * sizeof (gamepad_button));
     for (i = 0; i < n; i++) {
         s->buttons[i].irq = irq[i];
         s->buttons[i].keycode = keycode[i];
     }
     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..a3d9080
--- /dev/null
@@ -0,0 +1,1561 @@
+/*
+ * 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;
+    MemoryRegion iomem;
+    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 uint64_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset,
+                                       unsigned size)
+{
+    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,
+                                    uint64_t value, unsigned size)
+{
+    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 const MemoryRegionOps strongarm_pic_ops = {
+    .read = strongarm_pic_mem_read,
+    .write = strongarm_pic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_pic_initfn(SysBusDevice *dev)
+{
+    StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
+    memory_region_init_io(&s->iomem, &strongarm_pic_ops, s, "pic", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    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;
+    MemoryRegion iomem;
+    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 uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    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,
+                                uint64_t value, unsigned size)
+{
+    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 const MemoryRegionOps strongarm_rtc_ops = {
+    .read = strongarm_rtc_read,
+    .write = strongarm_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_rtc_init(SysBusDevice *dev)
+{
+    StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
+    struct tm tm;
+
+    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);
+
+    memory_region_init_io(&s->iomem, &strongarm_rtc_ops, s, "rtc", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    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;
+    MemoryRegion iomem;
+    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 uint64_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
+{
+    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,
+                                 uint64_t value, unsigned size)
+{
+    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 const MemoryRegionOps strongarm_gpio_ops = {
+    .read = strongarm_gpio_read,
+    .write = strongarm_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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)
+{
+    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);
+
+    memory_region_init_io(&s->iomem, &strongarm_gpio_ops, s, "gpio", 0x1000);
+
+    sysbus_init_mmio_region(dev, &s->iomem);
+    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;
+    MemoryRegion iomem;
+    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 uint64_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
+{
+    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,
+                                uint64_t value, unsigned size)
+{
+    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 const MemoryRegionOps strongarm_ppc_ops = {
+    .read = strongarm_ppc_read,
+    .write = strongarm_ppc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_ppc_init(SysBusDevice *dev)
+{
+    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);
+
+    memory_region_init_io(&s->iomem, &strongarm_ppc_ops, s, "ppc", 0x1000);
+
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    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;
+    MemoryRegion iomem;
+    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_fe_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_fe_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 uint64_t strongarm_uart_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
+{
+    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,
+                                 uint64_t value, unsigned size)
+{
+    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 const MemoryRegionOps strongarm_uart_ops = {
+    .read = strongarm_uart_read,
+    .write = strongarm_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_uart_init(SysBusDevice *dev)
+{
+    StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
+
+    memory_region_init_io(&s->iomem, &strongarm_uart_ops, s, "uart", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    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;
+    MemoryRegion iomem;
+    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 uint64_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    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,
+                                uint64_t value, unsigned size)
+{
+    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__,
+                   (int)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 const MemoryRegionOps strongarm_ssp_ops = {
+    .read = strongarm_ssp_read,
+    .write = strongarm_ssp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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)
+{
+    StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &strongarm_ssp_ops, s, "ssp", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    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(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev)
+{
+    StrongARMState *s;
+    qemu_irq *pic;
+    int i;
+
+    s = g_malloc0(sizeof(StrongARMState));
+
+    if (!rev) {
+        rev = "sa1110-b5";
+    }
+
+    if (strncmp(rev, "sa1110", 6)) {
+        error_report("Machine requires a SA1110 processor.");
+        exit(1);
+    }
+
+    s->env = cpu_init(rev);
+
+    if (!s->env) {
+        error_report("Unable to find CPU definition");
+        exit(1);
+    }
+
+    memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size);
+    memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
+
+    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..684f61b
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _STRONGARM_H
+#define _STRONGARM_H
+
+#include "memory.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;
+    MemoryRegion sdram;
+    DeviceState *pic;
+    DeviceState *gpio;
+    DeviceState *ppc;
+    DeviceState *ssp;
+    SSIBus *ssp_bus;
+} StrongARMState;
+
+StrongARMState *sa1110_init(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev);
+
+#endif
index 30e8a21672da21405e6e5cc9697c3cdcba6dece3..314edc4d87357e6018353a9e72ea46cb818b43c5 100644 (file)
@@ -97,12 +97,12 @@ struct sun4m_hwdef {
         target_phys_addr_t reg_base, vram_base;
     } vsimm[MAX_VSIMMS];
     target_phys_addr_t ecc_base;
-    uint32_t ecc_version;
-    uint8_t nvram_machine_id;
-    uint16_t machine_id;
-    uint32_t iommu_version;
     uint64_t max_mem;
     const char * const default_cpu_model;
+    uint32_t ecc_version;
+    uint32_t iommu_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
 };
 
 #define MAX_IOUNITS 5
@@ -115,11 +115,11 @@ struct sun4d_hwdef {
     target_phys_addr_t ledma_base, le_base;
     target_phys_addr_t tcx_base;
     target_phys_addr_t sbi_base;
-    uint8_t nvram_machine_id;
-    uint16_t machine_id;
-    uint32_t iounit_version;
     uint64_t max_mem;
     const char * const default_cpu_model;
+    uint32_t iounit_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
 };
 
 struct sun4c_hwdef {
@@ -128,11 +128,11 @@ struct sun4c_hwdef {
     target_phys_addr_t serial_base, fd_base;
     target_phys_addr_t idreg_base, dma_base, esp_base, le_base;
     target_phys_addr_t tcx_base, aux1_base;
-    uint8_t nvram_machine_id;
-    uint16_t machine_id;
-    uint32_t iommu_version;
     uint64_t max_mem;
     const char * const default_cpu_model;
+    uint32_t iommu_version;
+    uint16_t machine_id;
+    uint8_t nvram_machine_id;
 };
 
 int DMA_get_channel_mode (int nchan)
@@ -216,13 +216,13 @@ static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
 
 static DeviceState *slavio_intctl;
 
-void pic_info(Monitor *mon)
+void sun4m_pic_info(Monitor *mon)
 {
     if (slavio_intctl)
         slavio_pic_info(mon, slavio_intctl);
 }
 
-void irq_info(Monitor *mon)
+void sun4m_irq_info(Monitor *mon)
 {
     if (slavio_intctl)
         slavio_irq_info(mon, slavio_intctl);
@@ -253,15 +253,21 @@ void cpu_check_irqs(CPUState *env)
     }
 }
 
+static void cpu_kick_irq(CPUState *env)
+{
+    env->halted = 0;
+    cpu_check_irqs(env);
+    qemu_cpu_kick(env);
+}
+
 static void cpu_set_irq(void *opaque, int irq, int level)
 {
     CPUState *env = opaque;
 
     if (level) {
         trace_sun4m_cpu_set_irq_raise(irq);
-        env->halted = 0;
         env->pil_in |= 1 << irq;
-        cpu_check_irqs(env);
+        cpu_kick_irq(env);
     } else {
         trace_sun4m_cpu_set_irq_lower(irq);
         env->pil_in &= ~(1 << irq);
@@ -587,19 +593,25 @@ static void idreg_init(target_phys_addr_t addr)
     cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data));
 }
 
+typedef struct IDRegState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} IDRegState;
+
 static int idreg_init1(SysBusDevice *dev)
 {
-    ram_addr_t idreg_offset;
+    IDRegState *s = FROM_SYSBUS(IDRegState, dev);
 
-    idreg_offset = qemu_ram_alloc(NULL, "sun4m.idreg", sizeof(idreg_data));
-    sysbus_init_mmio(dev, sizeof(idreg_data), idreg_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->mem, NULL, "sun4m.idreg", sizeof(idreg_data));
+    memory_region_set_readonly(&s->mem, true);
+    sysbus_init_mmio_region(dev, &s->mem);
     return 0;
 }
 
 static SysBusDeviceInfo idreg_info = {
     .init = idreg_init1,
     .qdev.name  = "macio_idreg",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(IDRegState),
 };
 
 static void idreg_register_devices(void)
@@ -609,6 +621,11 @@ static void idreg_register_devices(void)
 
 device_init(idreg_register_devices);
 
+typedef struct AFXState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} AFXState;
+
 /* SS-5 TCX AFX register */
 static void afx_init(target_phys_addr_t addr)
 {
@@ -624,17 +641,17 @@ static void afx_init(target_phys_addr_t addr)
 
 static int afx_init1(SysBusDevice *dev)
 {
-    ram_addr_t afx_offset;
+    AFXState *s = FROM_SYSBUS(AFXState, dev);
 
-    afx_offset = qemu_ram_alloc(NULL, "sun4m.afx", 4);
-    sysbus_init_mmio(dev, 4, afx_offset | IO_MEM_RAM);
+    memory_region_init_ram(&s->mem, NULL, "sun4m.afx", 4);
+    sysbus_init_mmio_region(dev, &s->mem);
     return 0;
 }
 
 static SysBusDeviceInfo afx_info = {
     .init = afx_init1,
     .qdev.name  = "tcx_afx",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(AFXState),
 };
 
 static void afx_register_devices(void)
@@ -644,6 +661,11 @@ static void afx_register_devices(void)
 
 device_init(afx_register_devices);
 
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
 /* Boot PROM (OpenBIOS) */
 static uint64_t translate_prom_address(void *opaque, uint64_t addr)
 {
@@ -675,7 +697,7 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
         if (ret < 0 || ret > PROM_SIZE_MAX) {
             ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
         }
-        qemu_free(filename);
+        g_free(filename);
     } else {
         ret = -1;
     }
@@ -687,17 +709,18 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
 
 static int prom_init1(SysBusDevice *dev)
 {
-    ram_addr_t prom_offset;
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
 
-    prom_offset = qemu_ram_alloc(NULL, "sun4m.prom", PROM_SIZE_MAX);
-    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->prom, NULL, "sun4m.prom", PROM_SIZE_MAX);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio_region(dev, &s->prom);
     return 0;
 }
 
 static SysBusDeviceInfo prom_info = {
     .init = prom_init1,
     .qdev.name  = "openprom",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(PROMState),
     .qdev.props = (Property[]) {
         {/* end of property list */}
     }
@@ -713,19 +736,17 @@ device_init(prom_register_devices);
 typedef struct RamDevice
 {
     SysBusDevice busdev;
+    MemoryRegion ram;
     uint64_t size;
 } RamDevice;
 
 /* System RAM */
 static int ram_init1(SysBusDevice *dev)
 {
-    ram_addr_t RAM_size, ram_offset;
     RamDevice *d = FROM_SYSBUS(RamDevice, dev);
 
-    RAM_size = d->size;
-
-    ram_offset = qemu_ram_alloc(NULL, "sun4m.ram", RAM_size);
-    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    memory_region_init_ram(&d->ram, NULL, "sun4m.ram", d->size);
+    sysbus_init_mmio_region(dev, &d->ram);
     return 0;
 }
 
index ce97ee5a79ad4b5c71a795a88683d78bdbcf0d76..504c3af41367cc40d7e09742fa544a238e875632 100644 (file)
@@ -30,6 +30,10 @@ void slavio_irq_info(Monitor *mon, DeviceState *dev);
 void sun4c_pic_info(Monitor *mon, void *opaque);
 void sun4c_irq_info(Monitor *mon, void *opaque);
 
+/* sun4m.c */
+void sun4m_pic_info(Monitor *mon);
+void sun4m_irq_info(Monitor *mon);
+
 /* sparc32_dma.c */
 #include "sparc32_dma.h"
 
index bba69eef924aa2472630e4884aef314d1e832db6..6eeadfa18438b9faa7c8e80004d4560a1055fc6d 100644 (file)
 #define IOPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
 #define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or
                                           Viking/MXCC) */
-#define IOPTE_WRITE         0x00000004 /* Writeable */
+#define IOPTE_WRITE         0x00000004 /* Writable */
 #define IOPTE_VALID         0x00000002 /* IOPTE is valid */
 #define IOPTE_WAZ           0x00000001 /* Write as zeros */
 
@@ -130,8 +130,8 @@ typedef struct IOMMUState {
     SysBusDevice busdev;
     uint32_t regs[IOMMU_NREGS];
     target_phys_addr_t iostart;
-    uint32_t version;
     qemu_irq irq;
+    uint32_t version;
 } IOMMUState;
 
 static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr)
index 90b1ce277067282ae4a400ef054d53b619b3df8d..eaaefe3c948560218984e3f897ceb3be154e78b4 100644 (file)
@@ -38,6 +38,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
@@ -91,6 +92,12 @@ struct hwdef {
     uint64_t console_serial_base;
 };
 
+typedef struct EbusState {
+    PCIDevice pci_dev;
+    MemoryRegion bar0;
+    MemoryRegion bar1;
+} EbusState;
+
 int DMA_get_channel_mode (int nchan)
 {
     return 0;
@@ -236,14 +243,6 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
     return kernel_size;
 }
 
-void pic_info(Monitor *mon)
-{
-}
-
-void irq_info(Monitor *mon)
-{
-}
-
 void cpu_check_irqs(CPUState *env)
 {
     uint32_t pil = env->pil_in |
@@ -255,7 +254,9 @@ void cpu_check_irqs(CPUState *env)
         pil |= 1 << 14;
     }
 
-    if (!pil) {
+    /* The bit corresponding to psrpil is (1<< psrpil), the next bit
+       is (2 << psrpil). */
+    if (pil < (2 << env->psrpil)){
         if (env->interrupt_request & CPU_INTERRUPT_HARD) {
             CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
                            env->interrupt_index);
@@ -287,10 +288,12 @@ void cpu_check_irqs(CPUState *env)
                 break;
             }
         }
-    } else {
+    } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
         CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
                        "current interrupt %x\n",
                        pil, env->pil_in, env->softint, env->interrupt_index);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -298,6 +301,7 @@ static void cpu_kick_irq(CPUState *env)
 {
     env->halted = 0;
     cpu_check_irqs(env);
+    qemu_cpu_kick(env);
 }
 
 static void cpu_set_irq(void *opaque, int irq, int level)
@@ -306,9 +310,8 @@ static void cpu_set_irq(void *opaque, int irq, int level)
 
     if (level) {
         CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
-        env->halted = 0;
         env->pil_in |= 1 << irq;
-        cpu_check_irqs(env);
+        cpu_kick_irq(env);
     } else {
         CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
         env->pil_in &= ~(1 << irq);
@@ -345,16 +348,16 @@ static CPUTimer* cpu_timer_create(const char* name, CPUState *env,
                                   QEMUBHFunc *cb, uint32_t frequency,
                                   uint64_t disabled_mask)
 {
-    CPUTimer *timer = qemu_mallocz(sizeof (CPUTimer));
+    CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
 
     timer->name = name;
     timer->frequency = frequency;
     timer->disabled_mask = disabled_mask;
 
     timer->disabled = 1;
-    timer->clock_offset = qemu_get_clock(vm_clock);
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
 
-    timer->qtimer = qemu_new_timer(vm_clock, cb, env);
+    timer->qtimer = qemu_new_timer_ns(vm_clock, cb, env);
 
     return timer;
 }
@@ -362,7 +365,7 @@ static CPUTimer* cpu_timer_create(const char* name, CPUState *env,
 static void cpu_timer_reset(CPUTimer *timer)
 {
     timer->disabled = 1;
-    timer->clock_offset = qemu_get_clock(vm_clock);
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
 
     qemu_del_timer(timer->qtimer);
 }
@@ -457,7 +460,7 @@ void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
     uint64_t real_count = count & ~timer->disabled_mask;
     uint64_t disabled_bit = count & timer->disabled_mask;
 
-    int64_t vm_clock_offset = qemu_get_clock(vm_clock) -
+    int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) -
                     cpu_to_timer_ticks(real_count, timer->frequency);
 
     TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
@@ -471,7 +474,7 @@ void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
 uint64_t cpu_tick_get_count(CPUTimer *timer)
 {
     uint64_t real_count = timer_to_cpu_ticks(
-                    qemu_get_clock(vm_clock) - timer->clock_offset,
+                    qemu_get_clock_ns(vm_clock) - timer->clock_offset,
                     timer->frequency);
 
     TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
@@ -486,7 +489,7 @@ uint64_t cpu_tick_get_count(CPUTimer *timer)
 
 void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
 {
-    int64_t now = qemu_get_clock(vm_clock);
+    int64_t now = qemu_get_clock_ns(vm_clock);
 
     uint64_t real_limit = limit & ~timer->disabled_mask;
     timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
@@ -518,21 +521,6 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
     }
 }
 
-static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
-                              pcibus_t addr, pcibus_t size, int type)
-{
-    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
-                 region_num, addr);
-    switch (region_num) {
-    case 0:
-        isa_mmio_init(addr, 0x1000000);
-        break;
-    case 1:
-        isa_mmio_init(addr, 0x800000);
-        break;
-    }
-}
-
 static void dummy_isa_irq_handler(void *opaque, int n, int level)
 {
 }
@@ -549,32 +537,34 @@ pci_ebus_init(PCIBus *bus, int devfn)
 }
 
 static int
-pci_ebus_init1(PCIDevice *s)
-{
-    isa_bus_new(&s->qdev);
-
-    pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(s->config, PCI_DEVICE_ID_SUN_EBUS);
-    s->config[0x04] = 0x06; // command = bus master, pci mem
-    s->config[0x05] = 0x00;
-    s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
-    s->config[0x07] = 0x03; // status = medium devsel
-    s->config[0x08] = 0x01; // revision
-    s->config[0x09] = 0x00; // programming i/f
-    pci_config_set_class(s->config, PCI_CLASS_BRIDGE_OTHER);
-    s->config[0x0D] = 0x0a; // latency_timer
-
-    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
-    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
+pci_ebus_init1(PCIDevice *pci_dev)
+{
+    EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
+
+    isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev));
+
+    pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
+    pci_dev->config[0x05] = 0x00;
+    pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+    pci_dev->config[0x07] = 0x03; // status = medium devsel
+    pci_dev->config[0x09] = 0x00; // programming i/f
+    pci_dev->config[0x0D] = 0x0a; // latency_timer
+
+    isa_mmio_setup(&s->bar0, 0x1000000);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
+    isa_mmio_setup(&s->bar1, 0x800000);
+    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
     return 0;
 }
 
 static PCIDeviceInfo ebus_info = {
     .qdev.name = "ebus",
-    .qdev.size = sizeof(PCIDevice),
+    .qdev.size = sizeof(EbusState),
     .init = pci_ebus_init1,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_EBUS,
+    .revision = 0x01,
+    .class_id = PCI_CLASS_BRIDGE_OTHER,
 };
 
 static void pci_ebus_register(void)
@@ -584,6 +574,11 @@ static void pci_ebus_register(void)
 
 device_init(pci_ebus_register);
 
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
 static uint64_t translate_prom_address(void *opaque, uint64_t addr)
 {
     target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque;
@@ -615,7 +610,7 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
         if (ret < 0 || ret > PROM_SIZE_MAX) {
             ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
         }
-        qemu_free(filename);
+        g_free(filename);
     } else {
         ret = -1;
     }
@@ -627,17 +622,18 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
 
 static int prom_init1(SysBusDevice *dev)
 {
-    ram_addr_t prom_offset;
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
 
-    prom_offset = qemu_ram_alloc(NULL, "sun4u.prom", PROM_SIZE_MAX);
-    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->prom, NULL, "sun4u.prom", PROM_SIZE_MAX);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio_region(dev, &s->prom);
     return 0;
 }
 
 static SysBusDeviceInfo prom_info = {
     .init = prom_init1,
     .qdev.name  = "openprom",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(PROMState),
     .qdev.props = (Property[]) {
         {/* end of property list */}
     }
@@ -654,19 +650,17 @@ device_init(prom_register_devices);
 typedef struct RamDevice
 {
     SysBusDevice busdev;
+    MemoryRegion ram;
     uint64_t size;
 } RamDevice;
 
 /* System RAM */
 static int ram_init1(SysBusDevice *dev)
 {
-    ram_addr_t RAM_size, ram_offset;
     RamDevice *d = FROM_SYSBUS(RamDevice, dev);
 
-    RAM_size = d->size;
-
-    ram_offset = qemu_ram_alloc(NULL, "sun4u.ram", RAM_size);
-    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    memory_region_init_ram(&d->ram, NULL, "sun4u.ram", d->size);
+    sysbus_init_mmio_region(dev, &d->ram);
     return 0;
 }
 
@@ -730,7 +724,7 @@ static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
     env->hstick = cpu_timer_create("hstick", env, hstick_irq,
                                     hstick_frequency, TICK_INT_DIS);
 
-    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info = g_malloc0(sizeof(ResetData));
     reset_info->env = env;
     reset_info->prom_addr = hwdef->prom_addr;
     qemu_register_reset(main_cpu_reset, reset_info);
@@ -738,7 +732,8 @@ static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
     return env;
 }
 
-static void sun4uv_init(ram_addr_t RAM_size,
+static void sun4uv_init(MemoryRegion *address_space_mem,
+                        ram_addr_t RAM_size,
                         const char *boot_devices,
                         const char *kernel_filename, const char *kernel_cmdline,
                         const char *initrd_filename, const char *cpu_model,
@@ -766,7 +761,6 @@ static void sun4uv_init(ram_addr_t RAM_size,
     irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
     pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
                            &pci_bus3);
-    isa_mem_base = APB_PCI_IO_BASE;
     pci_vga_init(pci_bus);
 
     // XXX Should be pci_bus3
@@ -774,8 +768,8 @@ static void sun4uv_init(ram_addr_t RAM_size,
 
     i = 0;
     if (hwdef->console_serial_base) {
-        serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
-                       serial_hds[i], 1, 1);
+        serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
+                       NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
         i++;
     }
     for(; i < MAX_SERIAL_PORTS; i++) {
@@ -793,14 +787,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);
 
@@ -886,7 +873,7 @@ static void sun4u_init(ram_addr_t RAM_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
 }
 
@@ -896,7 +883,7 @@ static void sun4v_init(ram_addr_t RAM_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
 }
 
@@ -906,7 +893,7 @@ static void niagara_init(ram_addr_t RAM_size,
                          const char *kernel_filename, const char *kernel_cmdline,
                          const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
 }
 
index 758c69a9cdb1ba5b4e59dd072d4714d82649dd8f..248de54c4e105694ed90cd7ab815b3588b817c6f 100644 (file)
@@ -25,8 +25,8 @@
 #include "sysbus.h"
 #include "boards.h"
 #include "arm-misc.h"
-#include "sysemu.h"
 #include "net.h"
+#include "exec-memory.h"
 
 static struct arm_boot_info syborg_binfo;
 
@@ -36,9 +36,10 @@ static void syborg_init(ram_addr_t ram_size,
                         const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     qemu_irq *cpu_pic;
     qemu_irq pic[64];
-    ram_addr_t ram_addr;
     DeviceState *dev;
     int i;
 
@@ -51,8 +52,8 @@ static void syborg_init(ram_addr_t ram_size,
     }
 
     /* RAM at address zero. */
-    ram_addr = qemu_ram_alloc(NULL, "syborg.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "syborg.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     cpu_pic = arm_pic_init_cpu(env);
     dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
index 7e373645400e34ac7ce02780900d74f16d0131ea..ae3e0ebc64c172bd80f2c73699fd2ae01c63af37 100644 (file)
@@ -217,15 +217,24 @@ static void syborg_fb_update_display(void *opaque)
     }
 
     if (s->rgb) {
-        bpp_offset = 18;
+        bpp_offset = 24;
     } else {
         bpp_offset = 0;
     }
     if (s->endian) {
+        bpp_offset += 8;
+    }
+    /* Our bpp constants mostly match the PL110/PL111 but
+     * not for the 16 bit case
+     */
+    switch (s->bpp) {
+    case BPP_SRC_16:
         bpp_offset += 6;
+        break;
+    default:
+        bpp_offset += s->bpp;
     }
-
-    fn = fntable[s->bpp + bpp_offset];
+    fn = fntable[bpp_offset];
 
     if (s->pitch) {
         src_width = s->pitch;
index 5217983f6c06cf9db5935df1013ba9c62c17960b..1b0f3bb9b512c16a5fd20b29b5512abbd2362e0c 100644 (file)
@@ -213,7 +213,7 @@ static int syborg_int_init(SysBusDevice *dev)
                                        syborg_int_writefn, s,
                                        DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
-    s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags));
+    s->flags = g_malloc0(s->num_irqs * sizeof(syborg_int_flags));
 
     register_savevm(&dev->qdev, "syborg_int", -1, 1, syborg_int_save,
                     syborg_int_load, s);
index d295e99ebdae7710794e68eb30ccffc44b56ddc3..82b9dc088e979853203245c434564ce6532f376f 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)
 {
@@ -217,12 +195,11 @@ static int syborg_keyboard_init(SysBusDevice *dev)
         fprintf(stderr, "syborg_keyboard: fifo too small\n");
         s->fifo_size = 16;
     }
-    s->key_fifo = qemu_mallocz(s->fifo_size * sizeof(s->key_fifo[0]));
+    s->key_fifo = g_malloc0(s->fifo_size * sizeof(s->key_fifo[0]));
 
     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..b91214daea410e365be9f64cf25959bf9c7445d8 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)
 {
@@ -214,13 +198,12 @@ static int syborg_pointer_init(SysBusDevice *dev)
         fprintf(stderr, "syborg_pointer: fifo too small\n");
         s->fifo_size = 16;
     }
-    s->event_fifo = qemu_mallocz(s->fifo_size * sizeof(s->event_fifo[0]));
+    s->event_fifo = g_malloc0(s->fifo_size * sizeof(s->event_fifo[0]));
 
     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 329aa42661baedea65ed4870f6c404714ef46cb1..69f6ccf29cc395db23bff7d267a0c65a25381dd2 100644 (file)
@@ -66,7 +66,7 @@ static void syborg_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t v
     offset &= 0xfff;
     switch (offset >> 2) {
     case RTC_LATCH:
-        now = qemu_get_clock(vm_clock);
+        now = qemu_get_clock_ns(vm_clock);
         if (value >= 4) {
             s->offset = s->data - now;
         } else {
@@ -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..c83f82c36e70306024f360dfc063edb9e456d242 100644 (file)
@@ -119,14 +119,14 @@ static void do_dma_tx(SyborgSerialState *s, uint32_t count)
         /* optimize later. Now, 1 byte per iteration */
         while (count--) {
             cpu_physical_memory_read(s->dma_tx_ptr, &ch, 1);
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
             s->dma_tx_ptr++;
         }
     } else {
         s->dma_tx_ptr += count;
     }
     /* QEMU char backends do not have a nonblocking mode, so we transmit all
-       the data imediately and the interrupt status will be unchanged.  */
+       the data immediately and the interrupt status will be unchanged.  */
 }
 
 /* Initiate RX DMA, and transfer data from the FIFO.  */
@@ -203,7 +203,7 @@ static void syborg_serial_write(void *opaque, target_phys_addr_t offset,
     case SERIAL_DATA:
         ch = value;
         if (s->chr)
-            qemu_chr_write(s->chr, &ch, 1);
+            qemu_chr_fe_write(s->chr, &ch, 1);
         break;
     case SERIAL_INT_ENABLE:
         s->int_enable = value;
@@ -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)
 {
@@ -334,10 +311,8 @@ static int syborg_serial_init(SysBusDevice *dev)
         fprintf(stderr, "syborg_serial: fifo too small\n");
         s->fifo_size = 16;
     }
-    s->read_fifo = qemu_mallocz(s->fifo_size * sizeof(s->read_fifo[0]));
+    s->read_fifo = g_malloc0(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..6de952c938235f3cb1ca615507a23cc92b3c40d7 100644 (file)
@@ -26,7 +26,6 @@
 #include "sysbus.h"
 #include "virtio.h"
 #include "virtio-net.h"
-#include "sysemu.h"
 
 //#define DEBUG_SYBORG_VIRTIO
 
@@ -132,9 +131,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
     }
     switch (offset >> 2) {
     case SYBORG_VIRTIO_GUEST_FEATURES:
-        if (vdev->set_features)
-            vdev->set_features(vdev, value);
-        vdev->guest_features = value;
+        virtio_set_features(vdev, value);
         break;
     case SYBORG_VIRTIO_QUEUE_BASE:
         if (value == 0)
@@ -147,7 +144,9 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
             vdev->queue_sel = value;
         break;
     case SYBORG_VIRTIO_QUEUE_NOTIFY:
-        virtio_queue_notify(vdev, value);
+        if (value < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, value);
+        }
         break;
     case SYBORG_VIRTIO_STATUS:
         virtio_set_status(vdev, value & 0xFF);
index 1583bd85895f528601acfdb4f8e2ce710ff8880e..fd2fc6a51df15568a8d2ac703d1a8c8757956a31 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #include "sysbus.h"
-#include "sysemu.h"
 #include "monitor.h"
+#include "exec-memory.h"
 
 static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *sysbus_get_fw_dev_path(DeviceState *dev);
@@ -50,11 +50,22 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
     }
     if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
         /* Unregister previous mapping.  */
-        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
-                                     IO_MEM_UNASSIGNED);
+        if (dev->mmio[n].memory) {
+            memory_region_del_subregion(get_system_memory(),
+                                        dev->mmio[n].memory);
+        } else if (dev->mmio[n].unmap) {
+            dev->mmio[n].unmap(dev, dev->mmio[n].addr);
+        } else {
+            cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+                                         IO_MEM_UNASSIGNED);
+        }
     }
     dev->mmio[n].addr = addr;
-    if (dev->mmio[n].cb) {
+    if (dev->mmio[n].memory) {
+        memory_region_add_subregion(get_system_memory(),
+                                    addr,
+                                    dev->mmio[n].memory);
+    } else if (dev->mmio[n].cb) {
         dev->mmio[n].cb(dev, addr);
     } else {
         cpu_register_physical_memory(addr, dev->mmio[n].size,
@@ -96,16 +107,33 @@ void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
     dev->mmio[n].iofunc = iofunc;
 }
 
-void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
-                         mmio_mapfunc cb)
+void sysbus_init_mmio_cb2(SysBusDevice *dev,
+                          mmio_mapfunc cb, mmio_mapfunc unmap)
 {
     int n;
 
     assert(dev->num_mmio < QDEV_MAX_MMIO);
     n = dev->num_mmio++;
     dev->mmio[n].addr = -1;
-    dev->mmio[n].size = size;
+    dev->mmio[n].size = 0;
     dev->mmio[n].cb = cb;
+    dev->mmio[n].unmap = unmap;
+}
+
+void sysbus_init_mmio_region(SysBusDevice *dev, MemoryRegion *memory)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].size = memory_region_size(memory);
+    dev->mmio[n].memory = memory;
+}
+
+MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
+{
+    return dev->mmio[n].memory;
 }
 
 void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
@@ -138,8 +166,8 @@ void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
 {
     SysBusDeviceInfo *info;
 
-    info = qemu_mallocz(sizeof(*info));
-    info->qdev.name = qemu_strdup(name);
+    info = g_malloc0(sizeof(*info));
+    info->qdev.name = g_strdup(name);
     info->qdev.size = size;
     info->init = init;
     sysbus_register_withprop(info);
@@ -170,6 +198,39 @@ DeviceState *sysbus_create_varargs(const char *name,
         sysbus_connect_irq(s, n, irq);
         n++;
     }
+    va_end(va);
+    return dev;
+}
+
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       target_phys_addr_t addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_try_create(NULL, name);
+    if (!dev) {
+        return NULL;
+    }
+    s = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    if (addr != (target_phys_addr_t)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    va_end(va);
     return dev;
 }
 
@@ -178,6 +239,7 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
     SysBusDevice *s = sysbus_from_qdev(dev);
     int i;
 
+    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
     for (i = 0; i < s->num_mmio; i++) {
         monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
                        indent, "", s->mmio[i].addr, s->mmio[i].size);
@@ -201,3 +263,32 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev)
 
     return strdup(path);
 }
+
+void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem)
+{
+    memory_region_add_subregion(get_system_memory(), addr, mem);
+}
+
+void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr,
+                               MemoryRegion *mem, unsigned priority)
+{
+    memory_region_add_subregion_overlap(get_system_memory(), addr, mem,
+                                        priority);
+}
+
+void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem)
+{
+    memory_region_del_subregion(get_system_memory(), mem);
+}
+
+void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem)
+{
+    memory_region_add_subregion(get_system_io(), addr, mem);
+}
+
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem)
+{
+    memory_region_del_subregion(get_system_io(), mem);
+}
index e9eb618a7260012bddaa81f75f4dec2ae115fdae..6c36537c24d80f702dd082e9cbd96f609aa9a4c6 100644 (file)
@@ -4,6 +4,7 @@
 /* Devices attached directly to the main system bus.  */
 
 #include "qdev.h"
+#include "memory.h"
 
 #define QDEV_MAX_MMIO 32
 #define QDEV_MAX_PIO 32
@@ -22,7 +23,9 @@ struct SysBusDevice {
         target_phys_addr_t addr;
         target_phys_addr_t size;
         mmio_mapfunc cb;
+        mmio_mapfunc unmap;
         ram_addr_t iofunc;
+        MemoryRegion *memory;
     } mmio[QDEV_MAX_MMIO];
     int num_pio;
     pio_addr_t pio[QDEV_MAX_PIO];
@@ -44,8 +47,10 @@ void sysbus_register_withprop(SysBusDeviceInfo *info);
 void *sysbus_new(void);
 void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
                       ram_addr_t iofunc);
-void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
-                            mmio_mapfunc cb);
+void sysbus_init_mmio_cb2(SysBusDevice *dev,
+                          mmio_mapfunc cb, mmio_mapfunc unmap);
+void sysbus_init_mmio_region(SysBusDevice *dev, MemoryRegion *memory);
+MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
 void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
 void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
@@ -53,10 +58,20 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem);
+void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr,
+                               MemoryRegion *mem, unsigned priority);
+void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem);
+void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
+                   MemoryRegion *mem);
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem);
 
 /* Legacy helper function for creating devices.  */
 DeviceState *sysbus_create_varargs(const char *name,
                                  target_phys_addr_t addr, ...);
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       target_phys_addr_t addr, ...);
 static inline DeviceState *sysbus_create_simple(const char *name,
                                               target_phys_addr_t addr,
                                               qemu_irq irq)
@@ -64,4 +79,11 @@ static inline DeviceState *sysbus_create_simple(const char *name,
     return sysbus_create_varargs(name, addr, irq, NULL);
 }
 
+static inline DeviceState *sysbus_try_create_simple(const char *name,
+                                                    target_phys_addr_t addr,
+                                                    qemu_irq irq)
+{
+    return sysbus_try_create_varargs(name, addr, irq, NULL);
+}
+
 #endif /* !HW_SYSBUS_H */
index 672a01c467be53199f1850828e73de61888da007..4ce80b18f3f6bc7fd618d64434673c52b1a9c825 100644 (file)
@@ -1,6 +1,5 @@
 #include "hw.h"
 #include "sh.h"
-#include "sysemu.h"
 #include "loader.h"
 
 #define CE1  0x0100
@@ -31,12 +30,8 @@ static void init_dev(tc58128_dev * dev, const char *filename)
     int ret, blocks;
 
     dev->state = WAIT;
-    dev->flash_contents = qemu_mallocz(FLASH_SIZE);
+    dev->flash_contents = g_malloc(FLASH_SIZE);
     memset(dev->flash_contents, 0xff, FLASH_SIZE);
-    if (!dev->flash_contents) {
-       fprintf(stderr, "could not alloc memory for flash\n");
-       exit(1);
-    }
     if (filename) {
        /* Load flash image skipping the first block */
        ret = load_image(filename, dev->flash_contents + 528 * 32);
index c3fbe4e205a6e9377fc88ea2787575c05bf4ad41..c144dcf5ff37e790b4c922e0e06b9318ebce5122 100644 (file)
@@ -8,11 +8,11 @@
  * This code is licensed under the GNU GPL v2.
  */
 #include "hw.h"
-#include "pxa.h"
 #include "devices.h"
 #include "flash.h"
 #include "console.h"
 #include "pixel_ops.h"
+#include "blockdev.h"
 
 #define IRQ_TC6393_NAND                0
 #define IRQ_TC6393_MMC         1
@@ -79,6 +79,7 @@
 #define NAND_MODE_ECC_RST   0x60
 
 struct TC6393xbState {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq *sub_irqs;
     struct {
@@ -118,11 +119,11 @@ struct TC6393xbState {
     } nand;
     int nand_enable;
     uint32_t nand_phys;
-    NANDFlashState *flash;
+    DeviceState *flash;
     ECCState ecc;
 
     DisplayState *ds;
-    ram_addr_t vram_addr;
+    MemoryRegion vram;
     uint16_t *vram_ptr;
     uint32_t scr_width, scr_height; /* in pixels */
     qemu_irq l3v;
@@ -381,7 +382,7 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, target_phys_addr_t addr, uint
         case NAND_DATA + 2:
         case NAND_DATA + 3:
             nand_setio(s->flash, value);
-            s->nand.isr &= 1;
+            s->nand.isr |= 1;
             tc6393xb_nand_irq(s);
             return;
         case NAND_MODE:
@@ -495,7 +496,9 @@ static void tc6393xb_update_display(void *opaque)
 }
 
 
-static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) {
+static uint64_t tc6393xb_readb(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
+{
     TC6393xbState *s = opaque;
 
     switch (addr >> 8) {
@@ -516,7 +519,8 @@ static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) {
     return 0;
 }
 
-static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) {
+static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size) {
     TC6393xbState *s = opaque;
 
     switch (addr >> 8) {
@@ -532,53 +536,24 @@ static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t valu
         tc6393xb_nand_writeb(s, addr & 0xff, value);
     else
         fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr)
-{
-    return (tc6393xb_readb(opaque, addr) & 0xff) |
-        (tc6393xb_readb(opaque, addr + 1) << 8);
-}
-
-static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr)
-{
-    return (tc6393xb_readb(opaque, addr) & 0xff) |
-        ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) |
-        ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) |
-        ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24);
+                (uint32_t) addr, (int)value & 0xff);
 }
 
-static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
+TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
 {
-    tc6393xb_writeb(opaque, addr, value);
-    tc6393xb_writeb(opaque, addr + 1, value >> 8);
-}
-
-static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    tc6393xb_writeb(opaque, addr, value);
-    tc6393xb_writeb(opaque, addr + 1, value >> 8);
-    tc6393xb_writeb(opaque, addr + 2, value >> 16);
-    tc6393xb_writeb(opaque, addr + 3, value >> 24);
-}
-
-TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
-{
-    int iomemtype;
     TC6393xbState *s;
-    CPUReadMemoryFunc * const tc6393xb_readfn[] = {
-        tc6393xb_readb,
-        tc6393xb_readw,
-        tc6393xb_readl,
-    };
-    CPUWriteMemoryFunc * const tc6393xb_writefn[] = {
-        tc6393xb_writeb,
-        tc6393xb_writew,
-        tc6393xb_writel,
+    DriveInfo *nand;
+    static const MemoryRegionOps tc6393xb_ops = {
+        .read = tc6393xb_readb,
+        .write = tc6393xb_writeb,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+        .impl = {
+            .min_access_size = 1,
+            .max_access_size = 1,
+        },
     };
 
-    s = (TC6393xbState *) qemu_mallocz(sizeof(TC6393xbState));
+    s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
     s->irq = irq;
     s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
 
@@ -587,15 +562,15 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
 
     s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
 
-    s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+    nand = drive_get(IF_MTD, 0, 0);
+    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
 
-    iomemtype = cpu_register_io_memory(tc6393xb_readfn,
-                    tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x10000, iomemtype);
+    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
-    s->vram_addr = qemu_ram_alloc(NULL, "tc6393xb.vram", 0x100000);
-    s->vram_ptr = qemu_get_ram_ptr(s->vram_addr);
-    cpu_register_physical_memory(base + 0x100000, 0x100000, s->vram_addr);
+    memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
     s->scr_width = 480;
     s->scr_height = 640;
     s->ds = graphic_console_init(tc6393xb_update_display,
index 0e32830a877754a49578e648e9d0c3e20503f227..cd24100e14719e1bd670bd1d2376760307925fd9 100644 (file)
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -40,11 +40,19 @@ typedef struct TCXState {
     DisplayState *ds;
     uint8_t *vram;
     uint32_t *vram24, *cplane;
-    ram_addr_t vram_offset, vram24_offset, cplane_offset;
+    MemoryRegion vram_mem;
+    MemoryRegion vram_8bit;
+    MemoryRegion vram_24bit;
+    MemoryRegion vram_cplane;
+    MemoryRegion dac;
+    MemoryRegion tec;
+    MemoryRegion thc24;
+    MemoryRegion thc8;
+    ram_addr_t vram24_offset, cplane_offset;
     uint32_t vram_size;
-    uint16_t width, height, depth;
-    uint8_t r[256], g[256], b[256];
     uint32_t palette[256];
+    uint8_t r[256], g[256], b[256];
+    uint16_t width, height, depth;
     uint8_t dac_index, dac_state;
 } TCXState;
 
@@ -56,7 +64,7 @@ static void tcx_set_dirty(TCXState *s)
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+        memory_region_set_dirty(&s->vram_mem, i);
     }
 }
 
@@ -65,8 +73,8 @@ static void tcx24_set_dirty(TCXState *s)
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram24_offset + i);
-        cpu_physical_memory_set_dirty(s->cplane_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
     }
 }
 
@@ -174,16 +182,18 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
     }
 }
 
-static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
+static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
                               ram_addr_t cpage)
 {
     int ret;
     unsigned int off;
 
-    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
-        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
-        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
+                                       DIRTY_MEMORY_VGA);
+        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
+                                       DIRTY_MEMORY_VGA);
     }
     return ret;
 }
@@ -192,16 +202,17 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
                                ram_addr_t page_max, ram_addr_t page24,
                               ram_addr_t cpage)
 {
-    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    page_min -= ts->vram_offset;
-    page_max -= ts->vram_offset;
-    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
-                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
-                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page_min, page_max + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page24 + page_min * 4,
+                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              cpage + page_min * 4,
+                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
 }
 
 /* Fixed line length 1024 allows us to do nice tricks not possible on
@@ -216,7 +227,7 @@ static void tcx_update_display(void *opaque)
 
     if (ds_get_bits_per_pixel(ts->ds) == 0)
         return;
-    page = ts->vram_offset;
+    page = 0;
     y_start = -1;
     page_min = -1;
     page_max = 0;
@@ -242,7 +253,7 @@ static void tcx_update_display(void *opaque)
     }
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
+        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -279,8 +290,9 @@ static void tcx_update_display(void *opaque)
     }
     /* reset modified pages */
     if (page_max >= page_min) {
-        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                        VGA_DIRTY_FLAG);
+        memory_region_reset_dirty(&ts->vram_mem,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
     }
 }
 
@@ -294,7 +306,7 @@ static void tcx24_update_display(void *opaque)
 
     if (ds_get_bits_per_pixel(ts->ds) != 32)
             return;
-    page = ts->vram_offset;
+    page = 0;
     page24 = ts->vram24_offset;
     cpage = ts->cplane_offset;
     y_start = -1;
@@ -309,7 +321,7 @@ static void tcx24_update_display(void *opaque)
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
-        if (check_dirty(page, page24, cpage)) {
+        if (check_dirty(ts, page, page24, cpage)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -421,18 +433,20 @@ static void tcx_reset(DeviceState *d)
     s->r[255] = s->g[255] = s->b[255] = 255;
     update_palette_entries(s, 0, 256);
     memset(s->vram, 0, MAXX*MAXY);
-    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
-                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
+                              DIRTY_MEMORY_VGA);
     s->dac_index = 0;
     s->dac_state = 0;
 }
 
-static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     return 0;
 }
 
-static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
+                           unsigned size)
 {
     TCXState *s = opaque;
 
@@ -468,77 +482,77 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     return;
 }
 
-static CPUReadMemoryFunc * const tcx_dac_read[3] = {
-    NULL,
-    NULL,
-    tcx_dac_readl,
+static const MemoryRegionOps tcx_dac_ops = {
+    .read = tcx_dac_readl,
+    .write = tcx_dac_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-static CPUWriteMemoryFunc * const tcx_dac_write[3] = {
-    NULL,
-    NULL,
-    tcx_dac_writel,
-};
-
-static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     return 0;
 }
 
-static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void dummy_writel(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const tcx_dummy_read[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_readl,
-};
-
-static CPUWriteMemoryFunc * const tcx_dummy_write[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_writel,
+static const MemoryRegionOps dummy_ops = {
+    .read = dummy_readl,
+    .write = dummy_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static int tcx_init1(SysBusDevice *dev)
 {
     TCXState *s = FROM_SYSBUS(TCXState, dev);
-    int io_memory, dummy_memory;
-    ram_addr_t vram_offset;
+    ram_addr_t vram_offset = 0;
     int size;
     uint8_t *vram_base;
 
-    vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4));
-    vram_base = qemu_get_ram_ptr(vram_offset);
-    s->vram_offset = vram_offset;
+    memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
+                           s->vram_size * (1 + 4 + 4));
+    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
 
     /* 8-bit plane */
     s->vram = vram_base;
     size = s->vram_size;
-    sysbus_init_mmio(dev, size, s->vram_offset);
+    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
+                             &s->vram_mem, vram_offset, size);
+    sysbus_init_mmio_region(dev, &s->vram_8bit);
     vram_offset += size;
     vram_base += size;
 
     /* DAC */
-    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
+    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
+    sysbus_init_mmio_region(dev, &s->dac);
 
     /* TEC (dummy) */
-    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
-                                          s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
+    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
+    sysbus_init_mmio_region(dev, &s->tec);
     /* THC: NetBSD writes here even with 8-bit display: dummy */
-    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
+    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
+                          TCX_THC_NREGS_24);
+    sysbus_init_mmio_region(dev, &s->thc24);
 
     if (s->depth == 24) {
         /* 24-bit plane */
         size = s->vram_size * 4;
         s->vram24 = (uint32_t *)vram_base;
         s->vram24_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_24bit);
         vram_offset += size;
         vram_base += size;
 
@@ -546,14 +560,18 @@ static int tcx_init1(SysBusDevice *dev)
         size = s->vram_size * 4;
         s->cplane = (uint32_t *)vram_base;
         s->cplane_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_cplane);
 
         s->ds = graphic_console_init(tcx24_update_display,
                                      tcx24_invalidate_display,
                                      tcx24_screen_dump, NULL, s);
     } else {
         /* THC 8 bit (dummy) */
-        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
+        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
+                              TCX_THC_NREGS_8);
+        sysbus_init_mmio_region(dev, &s->thc8);
 
         s->ds = graphic_console_init(tcx_update_display,
                                      tcx_invalidate_display,
index 0bfab1634a20643d3ca3c1c2b5e9bb0da8f34a92..b992b994c735d289fcb2b46f2ccbfdf6853aedcb 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"
 #include "ssi.h"
 #include "blockdev.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #define TOSA_RAM    0x04000000
 #define TOSA_ROM       0x00800000
 
+#define TOSA_GPIO_USB_IN               (5)
 #define TOSA_GPIO_nSD_DETECT   (9)
 #define TOSA_GPIO_ON_RESET             (19)
 #define TOSA_GPIO_CF_IRQ               (21)    /* CF slot0 Ready */
 static void tosa_microdrive_attach(PXA2xxState *cpu)
 {
     PCMCIACardState *md;
-    BlockDriverState *bs;
     DriveInfo *dinfo;
 
     dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo)
+    if (!dinfo || dinfo->media_cd)
         return;
-    bs = dinfo->bdrv;
-    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
-        md = dscm1xxxx_init(dinfo);
-        pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-    }
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
 }
 
 static void tosa_out_switch(void *opaque, int line, int level)
@@ -115,6 +112,9 @@ static void tosa_gpio_setup(PXA2xxState *cpu,
     qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
 
     qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
+
+    /* UDC Vbus */
+    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
 }
 
 static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
@@ -207,6 +207,7 @@ static void tosa_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     PXA2xxState *cpu;
     TC6393xbState *tmio;
     DeviceState *scp0, *scp1;
@@ -214,12 +215,12 @@ static void tosa_init(ram_addr_t ram_size,
     if (!cpu_model)
         cpu_model = "pxa255";
 
-    cpu = pxa255_init(tosa_binfo.ram_size);
+    cpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
 
     cpu_register_physical_memory(0, TOSA_ROM,
                     qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
 
-    tmio = tc6393xb_init(0x10000000,
+    tmio = tc6393xb_init(address_space_mem, 0x10000000,
             qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT));
 
     scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
index a55853c8530540bf6469d111a079be45c58d3eba..9a500ebb3d284824a84cf47108ad119ea755eab4 100644 (file)
@@ -290,7 +290,7 @@ static void tsc2005_pin_update(TSC2005State *s)
     s->precision = s->nextprecision;
     s->function = s->nextfunction;
     s->pdst = !s->pnd0;        /* Synchronised on internal clock */
-    expires = qemu_get_clock(vm_clock) + (get_ticks_per_sec() >> 7);
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 7);
     qemu_mod_timer(s->timer, expires);
 }
 
@@ -524,12 +524,12 @@ void *tsc2005_init(qemu_irq pintdav)
     TSC2005State *s;
 
     s = (TSC2005State *)
-            qemu_mallocz(sizeof(TSC2005State));
+            g_malloc0(sizeof(TSC2005State));
     s->x = 400;
     s->y = 240;
     s->pressure = 0;
     s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer(vm_clock, tsc2005_timer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, tsc2005_timer_tick, s);
     s->pint = pintdav;
     s->model = 0x2005;
 
index fca73f16f341139e4da7c4e330b74065c56c7a5e..3c448a6f0f5a30fabdc798d67234d4bcb3f06f6c 100644 (file)
@@ -503,9 +503,9 @@ static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
         l_ch = 1;
         r_ch = 1;
         if (s->softstep && !(s->dac_power & (1 << 10))) {
-            l_ch = (qemu_get_clock(vm_clock) >
+            l_ch = (qemu_get_clock_ns(vm_clock) >
                             s->volume_change + TSC_SOFTSTEP_DELAY);
-            r_ch = (qemu_get_clock(vm_clock) >
+            r_ch = (qemu_get_clock_ns(vm_clock) >
                             s->volume_change + TSC_SOFTSTEP_DELAY);
         }
 
@@ -514,7 +514,7 @@ static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
     case 0x05: /* Stereo DAC Power Control */
         return 0x2aa0 | s->dac_power |
                 (((s->dac_power & (1 << 10)) &&
-                  (qemu_get_clock(vm_clock) >
+                  (qemu_get_clock_ns(vm_clock) >
                    s->powerdown + TSC_POWEROFF_DELAY)) << 6);
 
     case 0x06: /* Audio Control 3 */
@@ -695,7 +695,7 @@ static void tsc2102_audio_register_write(
 
     case 0x02: /* DAC Volume Control */
         s->volume = value;
-        s->volume_change = qemu_get_clock(vm_clock);
+        s->volume_change = qemu_get_clock_ns(vm_clock);
         return;
 
     case 0x03:
@@ -717,7 +717,7 @@ static void tsc2102_audio_register_write(
 
     case 0x05: /* Stereo DAC Power Control */
         if ((value & ~s->dac_power) & (1 << 10))
-            s->powerdown = qemu_get_clock(vm_clock);
+            s->powerdown = qemu_get_clock_ns(vm_clock);
 
         s->dac_power = value & 0x9543;
 #ifdef TSC_VERBOSE
@@ -864,7 +864,7 @@ static void tsc210x_pin_update(TSC210xState *s)
     s->busy = 1;
     s->precision = s->nextprecision;
     s->function = s->nextfunction;
-    expires = qemu_get_clock(vm_clock) + (get_ticks_per_sec() >> 10);
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
     qemu_mod_timer(s->timer, expires);
 }
 
@@ -1005,7 +1005,7 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
 static void tsc210x_save(QEMUFile *f, void *opaque)
 {
     TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock(vm_clock);
+    int64_t now = qemu_get_clock_ns(vm_clock);
     int i;
 
     qemu_put_be16(f, s->x);
@@ -1051,7 +1051,7 @@ static void tsc210x_save(QEMUFile *f, void *opaque)
 static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
 {
     TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock(vm_clock);
+    int64_t now = qemu_get_clock_ns(vm_clock);
     int i;
 
     s->x = qemu_get_be16(f);
@@ -1105,13 +1105,13 @@ uWireSlave *tsc2102_init(qemu_irq pint)
     TSC210xState *s;
 
     s = (TSC210xState *)
-            qemu_mallocz(sizeof(TSC210xState));
+            g_malloc0(sizeof(TSC210xState));
     memset(s, 0, sizeof(TSC210xState));
     s->x = 160;
     s->y = 160;
     s->pressure = 0;
     s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
     s->pint = pint;
     s->model = 0x2102;
     s->name = "tsc2102";
@@ -1154,13 +1154,13 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
     TSC210xState *s;
 
     s = (TSC210xState *)
-            qemu_mallocz(sizeof(TSC210xState));
+            g_malloc0(sizeof(TSC210xState));
     memset(s, 0, sizeof(TSC210xState));
     s->x = 400;
     s->y = 240;
     s->pressure = 0;
     s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s);
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
     s->pint = penirq;
     s->kbint = kbirq;
     s->davint = dav;
index 0005e1cffb99f3a5d10eee642d44f7b6230d3b12..ce7c81f8f2e3cb9ed0f90f39beef25a64e94ffaf 100644 (file)
 #include "omap.h"
 #include "irq.h"
 #include "devices.h"
+#include "sysbus.h"
 
-struct TUSBState {
-    int iomemtype[2];
+typedef struct TUSBState {
+    SysBusDevice busdev;
+    MemoryRegion iomem[2];
     qemu_irq irq;
     MUSBState *musb;
     QEMUTimer *otg_timer;
@@ -59,7 +61,7 @@ struct TUSBState {
     uint32_t pullup[2];
     uint32_t control_config;
     uint32_t otg_timer_val;
-};
+} TUSBState;
 
 #define TUSB_DEVCLOCK                  60000000        /* 60 MHz */
 
@@ -234,16 +236,6 @@ struct TUSBState {
 #define TUSB_EP_CONFIG_XFR_SIZE(v)     ((v) & 0x7fffffff)
 #define TUSB_PROD_TEST_RESET_VAL       0xa596
 
-int tusb6010_sync_io(TUSBState *s)
-{
-    return s->iomemtype[0];
-}
-
-int tusb6010_async_io(TUSBState *s)
-{
-    return s->iomemtype[1];
-}
-
 static void tusb_intr_update(TUSBState *s)
 {
     if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
@@ -520,7 +512,7 @@ static void tusb_async_writew(void *opaque, target_phys_addr_t addr,
     case TUSB_DEV_OTG_TIMER:
         s->otg_timer_val = value;
         if (value & TUSB_DEV_OTG_TIMER_ENABLE)
-            qemu_mod_timer(s->otg_timer, qemu_get_clock(vm_clock) +
+            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
                             muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
                                      get_ticks_per_sec(), TUSB_DEVCLOCK));
         else
@@ -647,16 +639,12 @@ static void tusb_async_writew(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const tusb_async_readfn[] = {
-    tusb_async_readb,
-    tusb_async_readh,
-    tusb_async_readw,
-};
-
-static CPUWriteMemoryFunc * const tusb_async_writefn[] = {
-    tusb_async_writeb,
-    tusb_async_writeh,
-    tusb_async_writew,
+static const MemoryRegionOps tusb_async_ops = {
+    .old_mmio = {
+        .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
+        .write =  { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void tusb_otg_tick(void *opaque)
@@ -727,9 +715,33 @@ static void tusb_musb_core_intr(void *opaque, int source, int level)
     }
 }
 
-TUSBState *tusb6010_init(qemu_irq intr)
+static void tusb6010_power(TUSBState *s, int on)
 {
-    TUSBState *s = qemu_mallocz(sizeof(*s));
+    if (!on) {
+        s->power = 0;
+    } else if (!s->power && on) {
+        s->power = 1;
+        /* Pull the interrupt down after TUSB6010 comes up.  */
+        s->intr_ok = 0;
+        tusb_intr_update(s);
+        qemu_mod_timer(s->pwr_timer,
+                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
+    }
+}
+
+static void tusb6010_irq(void *opaque, int source, int level)
+{
+    if (source) {
+        tusb_musb_core_intr(opaque, source - 1, level);
+    } else {
+        tusb6010_power(opaque, level);
+    }
+}
+
+static void tusb6010_reset(DeviceState *dev)
+{
+    TUSBState *s = FROM_SYSBUS(TUSBState, sysbus_from_qdev(dev));
+    int i;
 
     s->test_reset = TUSB_PROD_TEST_RESET_VAL;
     s->host_mode = 0;
@@ -739,28 +751,54 @@ TUSBState *tusb6010_init(qemu_irq intr)
     s->mask = 0xffffffff;
     s->intr = 0x00000000;
     s->otg_timer_val = 0;
-    s->iomemtype[1] = cpu_register_io_memory(tusb_async_readfn,
-                    tusb_async_writefn, s, DEVICE_NATIVE_ENDIAN);
-    s->irq = intr;
-    s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s);
-    s->pwr_timer = qemu_new_timer(vm_clock, tusb_power_tick, s);
-    s->musb = musb_init(qemu_allocate_irqs(tusb_musb_core_intr, s,
-                            __musb_irq_max));
-
-    return s;
+    s->scratch = 0;
+    s->prcm_config = 0;
+    s->prcm_mngmt = 0;
+    s->intr_ok = 0;
+    s->usbip_intr = 0;
+    s->usbip_mask = 0;
+    s->gpio_intr = 0;
+    s->gpio_mask = 0;
+    s->gpio_config = 0;
+    s->dma_intr = 0;
+    s->dma_mask = 0;
+    s->dma_map = 0;
+    s->dma_config = 0;
+    s->ep0_config = 0;
+    s->wkup_mask = 0;
+    s->pullup[0] = s->pullup[1] = 0;
+    s->control_config = 0;
+    for (i = 0; i < 15; i++) {
+        s->rx_config[i] = s->tx_config[i] = 0;
+    }
+    musb_reset(s->musb);
 }
 
-void tusb6010_power(TUSBState *s, int on)
+static int tusb6010_init(SysBusDevice *dev)
 {
-    if (!on)
-        s->power = 0;
-    else if (!s->power && on) {
-        s->power = 1;
+    TUSBState *s = FROM_SYSBUS(TUSBState, dev);
+    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
+    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
+    memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
+                          UINT32_MAX);
+    sysbus_init_mmio_region(dev, &s->iomem[0]);
+    sysbus_init_mmio_region(dev, &s->iomem[1]);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
+    s->musb = musb_init(&dev->qdev, 1);
+    return 0;
+}
 
-        /* Pull the interrupt down after TUSB6010 comes up.  */
-        s->intr_ok = 0;
-        tusb_intr_update(s);
-        qemu_mod_timer(s->pwr_timer,
-                       qemu_get_clock(vm_clock) + get_ticks_per_sec() / 2);
-    }
+static SysBusDeviceInfo tusb6010_info = {
+    .init = tusb6010_init,
+    .qdev.name = "tusb6010",
+    .qdev.size = sizeof(TUSBState),
+    .qdev.reset = tusb6010_reset,
+};
+
+static void tusb6010_register_device(void)
+{
+    sysbus_register_withprop(&tusb6010_info);
 }
+
+device_init(tusb6010_register_device)
index e61f17f0adeaa68bf73465d7abfea91ca852a1d0..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
@@ -74,14 +73,14 @@ static inline void menelaus_update(MenelausState *s)
 
 static inline void menelaus_rtc_start(MenelausState *s)
 {
-    s->rtc.next += qemu_get_clock(rt_clock);
+    s->rtc.next += qemu_get_clock_ms(rt_clock);
     qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
 }
 
 static inline void menelaus_rtc_stop(MenelausState *s)
 {
     qemu_del_timer(s->rtc.hz_tm);
-    s->rtc.next -= qemu_get_clock(rt_clock);
+    s->rtc.next -= qemu_get_clock_ms(rt_clock);
     if (s->rtc.next < 1)
         s->rtc.next = 1;
 }
@@ -786,7 +785,7 @@ static void menelaus_pre_save(void *opaque)
 {
     MenelausState *s = opaque;
     /* Should be <= 1000 */
-    s->rtc_next_vmstate =  s->rtc.next - qemu_get_clock(rt_clock);
+    s->rtc_next_vmstate =  s->rtc.next - qemu_get_clock_ms(rt_clock);
 }
 
 static int menelaus_post_load(void *opaque, int version_id)
@@ -847,7 +846,7 @@ static int twl92230_init(i2c_slave *i2c)
 {
     MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
 
-    s->rtc.hz_tm = qemu_new_timer(rt_clock, menelaus_rtc_hz, s);
+    s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s);
     /* Three output pins plus one interrupt pin.  */
     qdev_init_gpio_out(&i2c->qdev, s->out, 4);
     qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 3);
index 5f150589e16b96a0874cbb1ecaa34d499272c4ef..4299052c5e6515f269b8fcf93c8eb5cef81919c7 100644 (file)
@@ -41,7 +41,8 @@ static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
 typedef struct UNINState {
     SysBusDevice busdev;
     PCIHostState host_state;
-    ReadWriteHandler data_handler;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
 } UNINState;
 
 static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -63,23 +64,6 @@ static void pci_unin_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[unin_irq_line[irq_num]], level);
 }
 
-static void pci_unin_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-
-    pci_device_save(d, f);
-}
-
-static int pci_unin_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    return pci_device_load(d, f);
-}
-
 static void pci_unin_reset(void *opaque)
 {
 }
@@ -117,72 +101,71 @@ static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
     return retval;
 }
 
-static void unin_data_write(ReadWriteHandler *handler,
-                            pcibus_t addr, uint32_t val, int len)
+static void unin_data_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned len)
 {
-    UNINState *s = container_of(handler, UNINState, data_handler);
-    UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    UNINState *s = opaque;
+    UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
+                 addr, len, val);
     pci_data_write(s->host_state.bus,
                    unin_get_config_reg(s->host_state.config_reg, addr),
                    val, len);
 }
 
-static uint32_t unin_data_read(ReadWriteHandler *handler,
-                               pcibus_t addr, int len)
+static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr,
+                               unsigned len)
 {
-    UNINState *s = container_of(handler, UNINState, data_handler);
+    UNINState *s = opaque;
     uint32_t val;
 
     val = pci_data_read(s->host_state.bus,
                         unin_get_config_reg(s->host_state.config_reg, addr),
                         len);
-    UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
+                 addr, len, val);
     return val;
 }
 
+static const MemoryRegionOps unin_data_ops = {
+    .read = unin_data_read,
+    .write = unin_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static int pci_unin_main_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Use values found on a real PowerMac */
     /* Uninorth main bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    s->data_handler.read = unin_data_read;
-    s->data_handler.write = unin_data_write;
-    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
-                                                 DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
-
-    register_savevm(&dev->qdev, "uninorth", 0, 1,
-                    pci_unin_save, pci_unin_load, &s->host_state);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
+
     qemu_register_reset(pci_unin_reset, &s->host_state);
     return 0;
 }
 
+
 static int pci_u3_agp_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth U3 AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    s->data_handler.read = unin_data_read;
-    s->data_handler.write = unin_data_write;
-    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
-                                                 DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
-
-    register_savevm(&dev->qdev, "uninorth", 0, 1,
-                    pci_unin_save, pci_unin_load, &s->host_state);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
+
     qemu_register_reset(pci_unin_reset, &s->host_state);
 
     return 0;
@@ -191,38 +174,38 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
 static int pci_unin_agp_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
-                                               DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
 static int pci_unin_internal_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth internal bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
-                                                 DEVICE_LITTLE_ENDIAN);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
-                                               DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
-PCIBus *pci_pmac_init(qemu_irq *pic)
+PCIBus *pci_pmac_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -234,9 +217,18 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(UNINState, s);
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x70000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
-                                         pic, PCI_DEVFN(11, 0), 4);
+                                         pic,
+                                         &d->pci_mmio,
+                                         address_space_io,
+                                         PCI_DEVFN(11, 0), 4);
 
 #if 0
     pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
@@ -273,7 +265,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
     return d->host_state.bus;
 }
 
-PCIBus *pci_pmac_u3_init(qemu_irq *pic)
+PCIBus *pci_pmac_u3_init(qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -286,9 +280,18 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic)
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(UNINState, s);
 
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x70000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
-                                         pic, PCI_DEVFN(11, 0), 4);
+                                         pic,
+                                         &d->pci_mmio,
+                                         address_space_io,
+                                         PCI_DEVFN(11, 0), 4);
 
     sysbus_mmio_map(s, 0, 0xf0800000);
     sysbus_mmio_map(s, 1, 0xf0c00000);
@@ -300,10 +303,6 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic)
 
 static int unin_main_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_PCI);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
@@ -312,10 +311,6 @@ static int unin_main_pci_host_init(PCIDevice *d)
 
 static int unin_agp_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_AGP);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     //    d->config[0x34] = 0x80; // capabilities_pointer
@@ -324,11 +319,6 @@ static int unin_agp_pci_host_init(PCIDevice *d)
 
 static int u3_agp_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP);
-    /* revision */
-    d->config[0x08] = 0x00;
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     /* cache line size */
     d->config[0x0C] = 0x08;
     /* latency timer */
@@ -338,10 +328,6 @@ static int u3_agp_pci_host_init(PCIDevice *d)
 
 static int unin_internal_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_I_PCI);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
@@ -352,24 +338,40 @@ static PCIDeviceInfo unin_main_pci_host_info = {
     .qdev.name = "uni-north",
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_main_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static PCIDeviceInfo u3_agp_pci_host_info = {
     .qdev.name = "u3-agp",
     .qdev.size = sizeof(PCIDevice),
     .init      = u3_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static PCIDeviceInfo unin_agp_pci_host_info = {
     .qdev.name = "uni-north-agp",
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static PCIDeviceInfo unin_internal_pci_host_info = {
     .qdev.name = "uni-north-pci",
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_internal_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
 static void unin_register_devices(void)
index 22e684504935231113cb9f5c247b6e1bf5758d36..f30eec1ea2db1a164c91b11aa955a873429ac1b7 100644 (file)
@@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0,
                 .bInterval             = 0x01,
             },
@@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x09,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x09,
                 .bInterval             = 0x01,
             },
@@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x11,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x11,
                 .bInterval             = 0x01,
             },
@@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x19,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x19,
                 .bInterval             = 0x01,
             },
@@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x21,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x21,
                 .bInterval             = 0x01,
             },
@@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
         .eps = (USBDescEndpoint[]) {
             {
                 .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x31,
                 .bInterval             = 0x01,
             },
             {
                 .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
-                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
                 .wMaxPacketSize        = 0x31,
                 .bInterval             = 0x01,
             },
@@ -294,9 +294,9 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
     if (likely(!fifo->len))
         return USB_RET_STALL;
 
-    len = MIN(p->len, fifo->fifo[fifo->start].len);
-    memcpy(p->data, fifo->fifo[fifo->start].data, len);
-    if (len == p->len) {
+    len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
+    usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
+    if (len == p->iov.size) {
         fifo->fifo[fifo->start].len -= len;
         fifo->fifo[fifo->start].data += len;
     } else {
@@ -319,20 +319,13 @@ static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
                 struct usb_hci_out_fifo_s *fifo,
                 void (*send)(struct HCIInfo *, const uint8_t *, int),
                 int (*complete)(const uint8_t *, int),
-                const uint8_t *data, int len)
+                USBPacket *p)
 {
-    if (fifo->len) {
-        memcpy(fifo->data + fifo->len, data, len);
-        fifo->len += len;
-        if (complete(fifo->data, fifo->len)) {
-            send(s->hci, fifo->data, fifo->len);
-            fifo->len = 0;
-        }
-    } else if (complete(data, len))
-        send(s->hci, data, len);
-    else {
-        memcpy(fifo->data, data, len);
-        fifo->len = len;
+    usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
+    fifo->len += p->iov.size;
+    if (complete(fifo->data, fifo->len)) {
+        send(s->hci, fifo->data, fifo->len);
+        fifo->len = 0;
     }
 
     /* TODO: do we need to loop? */
@@ -372,13 +365,13 @@ static void usb_bt_handle_reset(USBDevice *dev)
     s->altsetting = 0;
 }
 
-static int usb_bt_handle_control(USBDevice *dev, int request, int value,
-                int index, int length, uint8_t *data)
+static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     struct USBBtState *s = (struct USBBtState *) dev->opaque;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         switch (request) {
         case DeviceRequest | USB_REQ_GET_CONFIGURATION:
@@ -432,7 +425,7 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value,
     case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
         if (s->config)
             usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
-                            usb_bt_hci_cmd_complete, data, length);
+                            usb_bt_hci_cmd_complete, p);
         break;
     default:
     fail:
@@ -474,12 +467,12 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
         switch (p->devep & 0xf) {
         case USB_ACL_EP:
             usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
-                            usb_bt_hci_acl_complete, p->data, p->len);
+                            usb_bt_hci_acl_complete, p);
             break;
 
         case USB_SCO_EP:
             usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
-                            usb_bt_hci_sco_complete, p->data, p->len);
+                            usb_bt_hci_sco_complete, p);
             break;
 
         default:
@@ -535,6 +528,9 @@ USBDevice *usb_bt_init(HCIInfo *hci)
     if (!hci)
         return NULL;
     dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle");
+    if (!dev) {
+        return NULL;
+    }
     s = DO_UPCAST(struct USBBtState, dev, dev);
     s->dev.opaque = s;
 
@@ -548,10 +544,16 @@ USBDevice *usb_bt_init(HCIInfo *hci)
     return dev;
 }
 
+static const VMStateDescription vmstate_usb_bt = {
+    .name = "usb-bt",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo bt_info = {
     .product_desc   = "QEMU BT dongle",
     .qdev.name      = "usb-bt-dongle",
     .qdev.size      = sizeof(struct USBBtState),
+    .qdev.vmsd      = &vmstate_usb_bt,
     .usb_desc       = &desc_bluetooth,
     .init           = usb_bt_initfn,
     .handle_packet  = usb_generic_handle_packet,
index abc7e61a59ec1337476dc92c8d60ace15e4be150..8cafb76fff5d44a5e9ea150bd5084b7471eee7ad 100644 (file)
@@ -3,11 +3,13 @@
 #include "qdev.h"
 #include "sysemu.h"
 #include "monitor.h"
+#include "trace.h"
 
 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
 
 static char *usb_get_dev_path(DeviceState *dev);
 static char *usb_get_fw_dev_path(DeviceState *qdev);
+static int usb_qdev_exit(DeviceState *qdev);
 
 static struct BusInfo usb_bus_info = {
     .name      = "USB",
@@ -39,9 +41,10 @@ const VMStateDescription vmstate_usb_device = {
     }
 };
 
-void usb_bus_new(USBBus *bus, DeviceState *host)
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
 {
     qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
+    bus->ops = ops;
     bus->busnr = next_usb_bus++;
     bus->qbus.allow_hotplug = 1; /* Yes, we can */
     QTAILQ_INIT(&bus->free);
@@ -72,9 +75,24 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     dev->info = info;
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
+    rc = usb_claim_port(dev);
+    if (rc != 0) {
+        goto err;
+    }
     rc = dev->info->init(dev);
-    if (rc == 0 && dev->auto_attach)
-        usb_device_attach(dev);
+    if (rc != 0) {
+        goto err;
+    }
+    if (dev->auto_attach) {
+        rc = usb_device_attach(dev);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+    return 0;
+
+err:
+    usb_qdev_exit(qdev);
     return rc;
 }
 
@@ -82,10 +100,15 @@ static int usb_qdev_exit(DeviceState *qdev)
 {
     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
 
-    usb_device_detach(dev);
+    if (dev->attached) {
+        usb_device_detach(dev);
+    }
     if (dev->info->handle_destroy) {
         dev->info->handle_destroy(dev);
     }
+    if (dev->port) {
+        usb_release_port(dev);
+    }
     return 0;
 }
 
@@ -116,7 +139,7 @@ USBDevice *usb_create(USBBus *bus, const char *name)
         bus = usb_bus_find(-1);
         if (!bus)
             return NULL;
-        fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
+        error_report("%s: no bus specified, using \"%s\" for \"%s\"\n",
                 __FUNCTION__, bus->qbus.name, name);
     }
 #endif
@@ -128,26 +151,69 @@ USBDevice *usb_create(USBBus *bus, const char *name)
 USBDevice *usb_create_simple(USBBus *bus, const char *name)
 {
     USBDevice *dev = usb_create(bus, name);
+    int rc;
+
     if (!dev) {
-        hw_error("Failed to create USB device '%s'\n", name);
+        error_report("Failed to create USB device '%s'\n", name);
+        return NULL;
+    }
+    rc = qdev_init(&dev->qdev);
+    if (rc < 0) {
+        error_report("Failed to initialize USB device '%s'\n", name);
+        return NULL;
     }
-    qdev_init_nofail(&dev->qdev);
     return dev;
 }
 
-void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
-                       USBPortOps *ops, int speedmask)
+static void usb_fill_port(USBPort *port, void *opaque, int index,
+                          USBPortOps *ops, int speedmask)
 {
-    port->opaque = opaque;
-    port->index = index;
     port->opaque = opaque;
     port->index = index;
     port->ops = ops;
     port->speedmask = speedmask;
+    usb_port_location(port, NULL, index + 1);
+}
+
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+                       USBPortOps *ops, int speedmask)
+{
+    usb_fill_port(port, opaque, index, ops, speedmask);
     QTAILQ_INSERT_TAIL(&bus->free, port, next);
     bus->nfree++;
 }
 
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+                           uint32_t portcount, uint32_t firstport,
+                           void *opaque, USBPortOps *ops, int speedmask)
+{
+    USBBus *bus;
+    int i;
+
+    QTAILQ_FOREACH(bus, &busses, next) {
+        if (strcmp(bus->qbus.name, masterbus) == 0) {
+            break;
+        }
+    }
+
+    if (!bus || !bus->ops->register_companion) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+                      "an USB masterbus");
+        if (bus) {
+            error_printf_unless_qmp(
+                "USB bus '%s' does not allow companion controllers\n",
+                masterbus);
+        }
+        return -1;
+    }
+
+    for (i = 0; i < portcount; i++) {
+        usb_fill_port(ports[i], opaque, i, ops, speedmask);
+    }
+
+    return bus->ops->register_companion(bus, ports, portcount, firstport);
+}
+
 void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
 {
     if (upstream) {
@@ -166,16 +232,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port)
     bus->nfree--;
 }
 
-static void do_attach(USBDevice *dev)
+int usb_claim_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
     USBPort *port;
 
-    if (dev->attached) {
-        fprintf(stderr, "Warning: tried to attach usb device %s twice\n",
-                dev->product_desc);
-        return;
-    }
+    assert(dev->port == NULL);
+
     if (dev->port_path) {
         QTAILQ_FOREACH(port, &bus->free, next) {
             if (strcmp(port->path, dev->port_path) == 0) {
@@ -183,62 +246,86 @@ static void do_attach(USBDevice *dev)
             }
         }
         if (port == NULL) {
-            fprintf(stderr, "Warning: usb port %s (bus %s) not found\n",
-                    dev->port_path, bus->qbus.name);
-            return;
+            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
+                         dev->port_path, bus->qbus.name);
+            return -1;
         }
     } else {
+        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+            /* Create a new hub and chain it on */
+            usb_create_simple(bus, "usb-hub");
+        }
+        if (bus->nfree == 0) {
+            error_report("Error: tried to attach usb device %s to a bus "
+                         "with no free ports\n", dev->product_desc);
+            return -1;
+        }
         port = QTAILQ_FIRST(&bus->free);
     }
+    trace_usb_port_claim(bus->busnr, port->path);
 
-    dev->attached++;
     QTAILQ_REMOVE(&bus->free, port, next);
     bus->nfree--;
 
-    usb_attach(port, dev);
+    dev->port = port;
+    port->dev = dev;
 
     QTAILQ_INSERT_TAIL(&bus->used, port, next);
     bus->nused++;
+    return 0;
 }
 
-int usb_device_attach(USBDevice *dev)
+void usb_release_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    if (bus->nfree == 1 && dev->port_path == NULL) {
-        /* Create a new hub and chain it on
-           (unless a physical port location is specified). */
-        usb_create_simple(bus, "usb-hub");
-    }
-    do_attach(dev);
-    return 0;
+    assert(port != NULL);
+    trace_usb_port_release(bus->busnr, port->path);
+
+    QTAILQ_REMOVE(&bus->used, port, next);
+    bus->nused--;
+
+    dev->port = NULL;
+    port->dev = NULL;
+
+    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+    bus->nfree++;
 }
 
-int usb_device_detach(USBDevice *dev)
+int usb_device_attach(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
-    USBPort *port;
+    USBPort *port = dev->port;
 
-    if (!dev->attached) {
-        fprintf(stderr, "Warning: tried to detach unattached usb device %s\n",
-                dev->product_desc);
+    assert(port != NULL);
+    assert(!dev->attached);
+    trace_usb_port_attach(bus->busnr, port->path);
+
+    if (!(port->speedmask & dev->speedmask)) {
+        error_report("Warning: speed mismatch trying to attach "
+                     "usb device %s to bus %s\n",
+                     dev->product_desc, bus->qbus.name);
         return -1;
     }
-    dev->attached--;
 
-    QTAILQ_FOREACH(port, &bus->used, next) {
-        if (port->dev == dev)
-            break;
-    }
-    assert(port != NULL);
+    dev->attached++;
+    usb_attach(port);
 
-    QTAILQ_REMOVE(&bus->used, port, next);
-    bus->nused--;
+    return 0;
+}
+
+int usb_device_detach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    usb_attach(port, NULL);
+    assert(port != NULL);
+    assert(dev->attached);
+    trace_usb_port_detach(bus->busnr, port->path);
 
-    QTAILQ_INSERT_TAIL(&bus->free, port, next);
-    bus->nfree++;
+    usb_detach(port);
+    dev->attached--;
     return 0;
 }
 
@@ -270,6 +357,7 @@ static const char *usb_speed(unsigned int speed)
         [ USB_SPEED_LOW  ] = "1.5",
         [ USB_SPEED_FULL ] = "12",
         [ USB_SPEED_HIGH ] = "480",
+        [ USB_SPEED_SUPER ] = "5000",
     };
     if (speed >= ARRAY_SIZE(txt))
         return "?";
@@ -291,7 +379,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 static char *usb_get_dev_path(DeviceState *qdev)
 {
     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
-    return qemu_strdup(dev->port->path);
+    return g_strdup(dev->port->path);
 }
 
 static char *usb_get_fw_dev_path(DeviceState *qdev)
@@ -302,7 +390,7 @@ static char *usb_get_fw_dev_path(DeviceState *qdev)
     long nr;
 
     fw_len = 32 + strlen(dev->port->path) * 6;
-    fw_path = qemu_malloc(fw_len);
+    fw_path = g_malloc(fw_len);
     in = dev->port->path;
     while (fw_len - pos > 0) {
         nr = strtol(in, &in, 10);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
new file mode 100644 (file)
index 0000000..cd349f3
--- /dev/null
@@ -0,0 +1,1321 @@
+/*
+ * 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 "usb-desc.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 QEMU_PACKED CCID_Header {
+    uint8_t     bMessageType;
+    uint32_t    dwLength;
+    uint8_t     bSlot;
+    uint8_t     bSeq;
+} CCID_Header;
+
+typedef struct QEMU_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 QEMU_PACKED CCID_SlotStatus {
+    CCID_BULK_IN b;
+    uint8_t     bClockStatus;
+} CCID_SlotStatus;
+
+typedef struct QEMU_PACKED CCID_Parameter {
+    CCID_BULK_IN b;
+    uint8_t     bProtocolNum;
+    uint8_t     abProtocolDataStructure[0];
+} CCID_Parameter;
+
+typedef struct QEMU_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 QEMU_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 QEMU_PACKED CCID_IccPowerOn {
+    CCID_Header hdr;
+    uint8_t     bPowerSelect;
+    uint16_t    abRFU;
+} CCID_IccPowerOn;
+
+typedef struct QEMU_PACKED CCID_IccPowerOff {
+    CCID_Header hdr;
+    uint16_t    abRFU;
+} CCID_IccPowerOff;
+
+typedef struct QEMU_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 {
+    BusState qbus;
+} CCIDBus;
+
+#define MAX_PROTOCOL_SIZE   7
+
+/*
+ * powered - defaults to true, changed by PowerOn/PowerOff messages
+ */
+typedef 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;
+} USBCCIDState;
+
+/*
+ * 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_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; */
+};
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_INTERFACE,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]  = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]       = "QEMU USB CCID",
+    [STR_SERIALNUMBER]  = "1",
+    [STR_INTERFACE]     = "CCID Interface",
+};
+
+static const USBDescIface desc_iface0 = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = 0x0b,
+    .bInterfaceSubClass            = 0x00,
+    .bInterfaceProtocol            = 0x00,
+    .iInterface                    = STR_INTERFACE,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* smartcard descriptor */
+            .data = qemu_ccid_descriptor,
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | CCID_INT_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .bInterval             = 255,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | CCID_BULK_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | CCID_BULK_OUT_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
+};
+
+static const USBDescDevice desc_device = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0xa0,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0,
+        },
+    },
+};
+
+static const USBDesc desc_ccid = {
+    .id = {
+        .idVendor          = CCID_VENDOR_ID,
+        .idProduct         = CCID_PRODUCT_ID,
+        .bcdDevice         = CCID_DEVICE_VERSION,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
+};
+
+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, USBPacket *p, 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);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        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:
+        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;
+    usb_wakeup(&s->dev);
+}
+
+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->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+        return USB_RET_STALL;
+    }
+    ccid_header = (CCID_Header *)s->bulk_out_data;
+    usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
+    s->bulk_out_pos += p->iov.size;
+    if (p->iov.size == CCID_MAX_PACKET_SIZE) {
+        DPRINTF(s, D_VERBOSE,
+            "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
+            p->iov.size, 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, USBPacket *p)
+{
+    int ret = 0;
+
+    assert(p->iov.size > 0);
+    ccid_bulk_in_get(s);
+    if (s->current_bulk_in != NULL) {
+        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
+                  p->iov.size);
+        usb_packet_copy(p, 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: %zd/%d req/act to guest (BULK_IN)\n",
+                __func__, p->iov.size, ret);
+    }
+    if (ret != USB_RET_NAK && ret < p->iov.size) {
+        DPRINTF(s, 1,
+                "%s: returning short (EREMOTEIO) %d < %zd\n",
+                __func__, ret, p->iov.size);
+    }
+    return ret;
+}
+
+static int ccid_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+    int ret = 0;
+    uint8_t buf[2];
+
+    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 (!p->iov.size) {
+                ret = USB_RET_NAK;
+            } else {
+                ret = ccid_bulk_in_copy_to_guest(s, p);
+            }
+            break;
+        case CCID_INT_IN_EP:
+            if (s->notify_slot_change) {
+                /* page 56, RDR_to_PC_NotifySlotChange */
+                buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+                buf[1] = s->bmSlotICCState;
+                usb_packet_copy(p, buf, 2);
+                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 %zd\n",
+                        s->bmSlotICCState, p->iov.size);
+            }
+            break;
+        default:
+            DPRINTF(s, 1, "Bad endpoint\n");
+            ret = USB_RET_STALL;
+            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 struct BusInfo ccid_bus_info = {
+    .name = "ccid-bus",
+    .size = sizeof(CCIDBus),
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+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");
+        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);
+
+    usb_desc_init(dev);
+    qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+    s->bus.qbus.allow_hotplug = 1;
+    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->dev.speedmask = USB_SPEED_MASK_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,
+    .usb_desc       = &desc_ccid,
+    .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 62591f20aa45e323517fdf67cfd2c60f99834353..ae2d384bb3ded8242c24f374c7ddf8873ae4d191 100644 (file)
@@ -76,7 +76,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
 {
     uint8_t  bLength = 0x09;
     uint16_t wTotalLength = 0;
-    int i, rc, count;
+    int i, rc;
 
     if (len < bLength) {
         return -1;
@@ -91,8 +91,19 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
     dest[0x08] = conf->bMaxPower;
     wTotalLength += bLength;
 
-    count = conf->nif ? conf->nif : conf->bNumInterfaces;
-    for (i = 0; i < count; i++) {
+    /* handle grouped interfaces if any*/
+    for (i = 0; i < conf->nif_groups; i++) {
+        rc = usb_desc_iface_group(&(conf->if_groups[i]),
+                                  dest + wTotalLength,
+                                  len - wTotalLength);
+        if (rc < 0) {
+            return rc;
+        }
+        wTotalLength += rc;
+    }
+
+    /* handle normal (ungrouped / no IAD) interfaces if any */
+    for (i = 0; i < conf->nif; i++) {
         rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
         if (rc < 0) {
             return rc;
@@ -105,6 +116,41 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
     return wTotalLength;
 }
 
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
+                         size_t len)
+{
+    int pos = 0;
+    int i = 0;
+
+    /* handle interface association descriptor */
+    uint8_t bLength = 0x08;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_INTERFACE_ASSOC;
+    dest[0x02] = iad->bFirstInterface;
+    dest[0x03] = iad->bInterfaceCount;
+    dest[0x04] = iad->bFunctionClass;
+    dest[0x05] = iad->bFunctionSubClass;
+    dest[0x06] = iad->bFunctionProtocol;
+    dest[0x07] = iad->iFunction;
+    pos += bLength;
+
+    /* handle associated interfaces in this group */
+    for (i = 0; i < iad->nif; i++) {
+        int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
+        if (rc < 0) {
+            return rc;
+        }
+        pos += rc;
+    }
+
+    return pos;
+}
+
 int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x09;
@@ -196,7 +242,17 @@ static void usb_desc_setdefaults(USBDevice *dev)
 
 void usb_desc_init(USBDevice *dev)
 {
+    const USBDesc *desc = dev->info->usb_desc;
+
+    assert(desc != NULL);
     dev->speed = USB_SPEED_FULL;
+    dev->speedmask = 0;
+    if (desc->full) {
+        dev->speedmask |= USB_SPEED_MASK_FULL;
+    }
+    if (desc->high) {
+        dev->speedmask |= USB_SPEED_MASK_HIGH;
+    }
     usb_desc_setdefaults(dev);
 }
 
@@ -227,12 +283,12 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
         }
     }
     if (s == NULL) {
-        s = qemu_mallocz(sizeof(*s));
+        s = g_malloc0(sizeof(*s));
         s->index = index;
         QLIST_INSERT_HEAD(&dev->strings, s, next);
     }
-    qemu_free(s->str);
-    s->str = qemu_strdup(str);
+    g_free(s->str);
+    s->str = g_strdup(str);
 }
 
 const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
@@ -329,6 +385,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
         trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
         break;
 
+    case USB_DT_DEBUG:
+        /* ignore silently */
+        break;
+
     default:
         fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
                 dev->addr, type, len);
@@ -344,8 +404,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
     return ret;
 }
 
-int usb_desc_handle_control(USBDevice *dev, int request, int value,
-                            int index, int length, uint8_t *data)
+int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data)
 {
     const USBDesc *desc = dev->info->usb_desc;
     int i, ret = -1;
index ac734ab088b961cb8766f7385948df5cdda7216e..5c14e4abdc2b20f03df77631b86d069b3cf5c7c4 100644 (file)
@@ -30,6 +30,24 @@ struct USBDescConfig {
     uint8_t                   bmAttributes;
     uint8_t                   bMaxPower;
 
+    /* grouped interfaces */
+    uint8_t                   nif_groups;
+    const USBDescIfaceAssoc   *if_groups;
+
+    /* "normal" interfaces */
+    uint8_t                   nif;
+    const USBDescIface        *ifs;
+};
+
+/* conceptually an Interface Association Descriptor, and releated interfaces */
+struct USBDescIfaceAssoc {
+    uint8_t                   bFirstInterface;
+    uint8_t                   bInterfaceCount;
+    uint8_t                   bFunctionClass;
+    uint8_t                   bFunctionSubClass;
+    uint8_t                   bFunctionProtocol;
+    uint8_t                   iFunction;
+
     uint8_t                   nif;
     const USBDescIface        *ifs;
 };
@@ -57,7 +75,7 @@ struct USBDescEndpoint {
 
 struct USBDescOther {
     uint8_t                   length;
-    uint8_t                   *data;
+    const uint8_t             *data;
 };
 
 typedef const char *USBDescStrings[256];
@@ -75,6 +93,8 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
 int usb_desc_device_qualifier(const USBDescDevice *dev,
                               uint8_t *dest, size_t len);
 int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
+                         size_t len);
 int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
 int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
 int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
@@ -86,7 +106,7 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
 const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
 int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
 int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
-int usb_desc_handle_control(USBDevice *dev, int request, int value,
-                            int index, int length, uint8_t *data);
+int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data);
 
 #endif /* QEMU_HW_USB_DESC_H */
index a58ba0dd9dec99f5a6abcc2d74003d29b2c89070..a946e1d1fd875ce8421d8ba66bd7847e6b64f501 100644 (file)
@@ -3,6 +3,11 @@
  *
  * Copyright(c) 2008  Emutex Ltd. (address@hidden)
  *
+ * EHCI project was started by Mark Burkley, with contributions by
+ * Niels de Vos.  David S. Ahern continued working on it.  Kevin Wolf,
+ * Jan Kiszka and Vincent Palatin contributed bugfixes.
+ *
+ *
  * 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
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * TODO:
- *  o Downstream port handoff
+ * 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.h"
 #include "qemu-timer.h"
 #include "usb.h"
 #include "pci.h"
-#include "sysbus.h"
-#include "usb-ehci.h"
 #include "monitor.h"
+#include "trace.h"
+#include "dma.h"
 
 #define EHCI_DEBUG   0
-#define STATE_DEBUG  0       /* state transitions  */
 
-#if EHCI_DEBUG || STATE_DEBUG
+#if EHCI_DEBUG
 #define DPRINTF printf
 #else
 #define DPRINTF(...)
 #endif
 
-#if STATE_DEBUG
-#define DPRINTF_ST DPRINTF
-#else
-#define DPRINTF_ST(...)
-#endif
-
 /* internal processing - reset HC to try and recover */
 #define USB_RET_PROCERR   (-99)
 
 #define MMIO_SIZE        0x1000
 
 /* Capability Registers Base Address - section 2.2 */
-#define CAPREGBASE       0x0000        
+#define CAPREGBASE       0x0000
 #define CAPLENGTH        CAPREGBASE + 0x0000  // 1-byte, 0x0001 reserved
 #define HCIVERSION       CAPREGBASE + 0x0002  // 2-bytes, i/f version #
-#define HCSPARAMS        CAPREGBASE + 0x0004  // 4-bytes, structural params 
+#define HCSPARAMS        CAPREGBASE + 0x0004  // 4-bytes, structural params
 #define HCCPARAMS        CAPREGBASE + 0x0008  // 4-bytes, capability params
 #define EECP             HCCPARAMS + 1
 #define HCSPPORTROUTE1   CAPREGBASE + 0x000c
 #define PORTSC_BEGIN         PORTSC
 #define PORTSC_END           (PORTSC + 4 * NB_PORTS)
 /*
- * Bits that are reserverd or are read-only are masked out of values
+ * Bits that are reserved or are read-only are masked out of values
  * written to us by software
  */
-#define PORTSC_RO_MASK       0x007021c5
+#define PORTSC_RO_MASK       0x007001c0
 #define PORTSC_RWC_MASK      0x0000002a
 #define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
 #define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
 #define PORTSC_CSC           (1 << 1)     // Connect Status Change
 #define PORTSC_CONNECT       (1 << 0)     // Current Connect Status
 
-//#define EHCI_NOMICROFRAMES
-
-#ifdef EHCI_NOMICROFRAMES
 #define FRAME_TIMER_FREQ 1000
-#else
-#define FRAME_TIMER_FREQ 8000
-#endif
-#define FRAME_TIMER_USEC (1000000 / FRAME_TIMER_FREQ)
+#define FRAME_TIMER_NS   (1000000000 / FRAME_TIMER_FREQ)
 
 #define NB_MAXINTRATE    8        // Max rate at which controller issues ints
-#define NB_PORTS         4        // Number of downstream ports
+#define NB_PORTS         6        // Number of downstream ports
 #define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
 #define MAX_ITERATIONS   20       // Max number of QH before we break the loop
 #define MAX_QH           100      // Max allowable queue heads in a chain
@@ -161,6 +149,7 @@ typedef enum {
     EST_FETCHENTRY,
     EST_FETCHQH,
     EST_FETCHITD,
+    EST_FETCHSITD,
     EST_ADVANCEQUEUE,
     EST_FETCHQTD,
     EST_EXECUTE,
@@ -208,6 +197,7 @@ typedef struct EHCIitd {
 #define ITD_BUFPTR_MAXPKT_MASK   0x000007ff
 #define ITD_BUFPTR_MAXPKT_SH     0
 #define ITD_BUFPTR_MULT_MASK     0x00000003
+#define ITD_BUFPTR_MULT_SH       0
 } EHCIitd;
 
 /*  EHCI spec version 1.0 Section 3.4
@@ -281,6 +271,7 @@ typedef struct EHCIqtd {
 
     uint32_t bufptr[5];               // Standard buffer pointer
 #define QTD_BUFPTR_MASK               0xfffff000
+#define QTD_BUFPTR_SH                 12
 } EHCIqtd;
 
 /*  EHCI spec version 1.0 Section 3.6
@@ -344,11 +335,49 @@ typedef struct EHCIfstn {
     uint32_t backptr;                 // Standard next link pointer
 } EHCIfstn;
 
-typedef struct {
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+enum async_state {
+    EHCI_ASYNC_NONE = 0,
+    EHCI_ASYNC_INFLIGHT,
+    EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIQueue {
+    EHCIState *ehci;
+    QTAILQ_ENTRY(EHCIQueue) next;
+    bool async_schedule;
+    uint32_t seen;
+    uint64_t ts;
+
+    /* cached data from guest - needs to be flushed
+     * when guest removes an entry (doorbell, handshake sequence)
+     */
+    EHCIqh qh;             // copy of current QH (being worked on)
+    uint32_t qhaddr;       // address QH read from
+    EHCIqtd qtd;           // copy of current QTD (being worked on)
+    uint32_t qtdaddr;      // address QTD read from
+
+    USBPacket packet;
+    QEMUSGList sgl;
+    int pid;
+    uint32_t tbytes;
+    enum async_state async;
+    int usb_status;
+};
+
+struct EHCIState {
+    PCIDevice dev;
+    USBBus bus;
     qemu_irq irq;
-    target_phys_addr_t mem_base;
-    int mem;
-    int num_ports;
+    MemoryRegion mem;
+    int companion_count;
+
+    /* properties */
+    uint32_t freq;
+    uint32_t maxframes;
+
     /*
      *  EHCI spec version 1.0 Section 2.3
      *  Host Controller Operational Registers
@@ -369,6 +398,7 @@ typedef struct {
             uint32_t portsc[NB_PORTS];
         };
     };
+
     /*
      *  Internal states, shadow registers, etc
      */
@@ -378,35 +408,22 @@ typedef struct {
     int astate;                        // Current state in asynchronous schedule
     int pstate;                        // Current state in periodic schedule
     USBPort ports[NB_PORTS];
-    uint8_t buffer[BUFF_SIZE];
-
-    /* cached data from guest - needs to be flushed 
-     * when guest removes an entry (doorbell, handshake sequence)
-     */
-    EHCIqh qh;             // copy of current QH (being worked on)
-    uint32_t qhaddr;       // address QH read from
-
-    EHCIqtd qtd;           // copy of current QTD (being worked on)
-    uint32_t qtdaddr;      // address QTD read from
+    USBPort *companion_ports[NB_PORTS];
+    uint32_t usbsts_pending;
+    QTAILQ_HEAD(, EHCIQueue) queues;
 
-    uint32_t itdaddr;      // current ITD
+    uint32_t a_fetch_addr;   // which address to look at next
+    uint32_t p_fetch_addr;   // which address to look at next
 
-    uint32_t fetch_addr;   // which address to look at next
-
-    USBBus bus;
-    USBPacket usb_packet;
-    int async_port_in_progress;
-    int async_complete;
-    uint32_t tbytes;
-    int pid;
-    int exec_status;
+    USBPacket ipacket;
+    QEMUSGList isgl;
     int isoch_pause;
-    uint32_t last_run_usec;
-    uint32_t frame_end_usec;
-} EHCIState;
+
+    uint64_t last_run_ns;
+};
 
 #define SET_LAST_RUN_CLOCK(s) \
-    (s)->last_run_usec = qemu_get_clock(vm_clock) / 1000;
+    (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
 
 /* nifty macros from Arnon's EHCI version  */
 #define get_field(data, field) \
@@ -419,121 +436,412 @@ typedef struct {
     *data = val; \
     } while(0)
 
+static const char *ehci_state_names[] = {
+    [EST_INACTIVE]     = "INACTIVE",
+    [EST_ACTIVE]       = "ACTIVE",
+    [EST_EXECUTING]    = "EXECUTING",
+    [EST_SLEEPING]     = "SLEEPING",
+    [EST_WAITLISTHEAD] = "WAITLISTHEAD",
+    [EST_FETCHENTRY]   = "FETCH ENTRY",
+    [EST_FETCHQH]      = "FETCH QH",
+    [EST_FETCHITD]     = "FETCH ITD",
+    [EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
+    [EST_FETCHQTD]     = "FETCH QTD",
+    [EST_EXECUTE]      = "EXECUTE",
+    [EST_WRITEBACK]    = "WRITEBACK",
+    [EST_HORIZONTALQH] = "HORIZONTALQH",
+};
 
-#if EHCI_DEBUG
-static const char *addr2str(unsigned addr)
+static const char *ehci_mmio_names[] = {
+    [CAPLENGTH]         = "CAPLENGTH",
+    [HCIVERSION]        = "HCIVERSION",
+    [HCSPARAMS]         = "HCSPARAMS",
+    [HCCPARAMS]         = "HCCPARAMS",
+    [USBCMD]            = "USBCMD",
+    [USBSTS]            = "USBSTS",
+    [USBINTR]           = "USBINTR",
+    [FRINDEX]           = "FRINDEX",
+    [PERIODICLISTBASE]  = "P-LIST BASE",
+    [ASYNCLISTADDR]     = "A-LIST ADDR",
+    [PORTSC_BEGIN]      = "PORTSC #0",
+    [PORTSC_BEGIN + 4]  = "PORTSC #1",
+    [PORTSC_BEGIN + 8]  = "PORTSC #2",
+    [PORTSC_BEGIN + 12] = "PORTSC #3",
+    [PORTSC_BEGIN + 16] = "PORTSC #4",
+    [PORTSC_BEGIN + 20] = "PORTSC #5",
+    [CONFIGFLAG]        = "CONFIGFLAG",
+};
+
+static const char *nr2str(const char **n, size_t len, uint32_t nr)
 {
-    const char *r = "   unknown";
+    if (nr < len && n[nr] != NULL) {
+        return n[nr];
+    } else {
+        return "unknown";
+    }
+}
 
-    switch(addr) {
-        case CAPLENGTH:
-            r = " CAPLENGTH";
-            break;
+static const char *state2str(uint32_t state)
+{
+    return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
+}
 
-        case HCIVERSION:
-            r = "HCIVERSION";
-            break;
+static const char *addr2str(target_phys_addr_t addr)
+{
+    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+}
 
-        case HCSPARAMS:
-            r = " HCSPARAMS";
-            break;
+static void ehci_trace_usbsts(uint32_t mask, int state)
+{
+    /* interrupts */
+    if (mask & USBSTS_INT) {
+        trace_usb_ehci_usbsts("INT", state);
+    }
+    if (mask & USBSTS_ERRINT) {
+        trace_usb_ehci_usbsts("ERRINT", state);
+    }
+    if (mask & USBSTS_PCD) {
+        trace_usb_ehci_usbsts("PCD", state);
+    }
+    if (mask & USBSTS_FLR) {
+        trace_usb_ehci_usbsts("FLR", state);
+    }
+    if (mask & USBSTS_HSE) {
+        trace_usb_ehci_usbsts("HSE", state);
+    }
+    if (mask & USBSTS_IAA) {
+        trace_usb_ehci_usbsts("IAA", state);
+    }
 
-        case HCCPARAMS:
-            r = " HCCPARAMS";
-            break;
+    /* status */
+    if (mask & USBSTS_HALT) {
+        trace_usb_ehci_usbsts("HALT", state);
+    }
+    if (mask & USBSTS_REC) {
+        trace_usb_ehci_usbsts("REC", state);
+    }
+    if (mask & USBSTS_PSS) {
+        trace_usb_ehci_usbsts("PSS", state);
+    }
+    if (mask & USBSTS_ASS) {
+        trace_usb_ehci_usbsts("ASS", state);
+    }
+}
 
-        case USBCMD:
-            r = "   COMMAND";
-            break;
+static inline void ehci_set_usbsts(EHCIState *s, int mask)
+{
+    if ((s->usbsts & mask) == mask) {
+        return;
+    }
+    ehci_trace_usbsts(mask, 1);
+    s->usbsts |= mask;
+}
 
-        case USBSTS:
-            r = "    STATUS";
-            break;
+static inline void ehci_clear_usbsts(EHCIState *s, int mask)
+{
+    if ((s->usbsts & mask) == 0) {
+        return;
+    }
+    ehci_trace_usbsts(mask, 0);
+    s->usbsts &= ~mask;
+}
 
-        case USBINTR:
-            r = " INTERRUPT";
-            break;
+static inline void ehci_set_interrupt(EHCIState *s, int intr)
+{
+    int level = 0;
 
-        case FRINDEX:
-            r = " FRAME IDX";
-            break;
-    
-        case PERIODICLISTBASE:
-            r = "P-LIST BASE";
-            break;
-    
-        case ASYNCLISTADDR:
-            r = "A-LIST ADDR";
-            break;
+    // TODO honour interrupt threshold requests
 
-        case PORTSC_BEGIN ... PORTSC_END:
-            r = "PORT STATUS";
-            break;
+    ehci_set_usbsts(s, intr);
 
-        case CONFIGFLAG:
-            r = "CONFIG FLAG";
-            break;
+    if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
+        level = 1;
     }
 
-    return r;
+    qemu_set_irq(s->irq, level);
 }
-#endif
 
+static inline void ehci_record_interrupt(EHCIState *s, int intr)
+{
+    s->usbsts_pending |= intr;
+}
 
-static inline void ehci_set_interrupt(EHCIState *s, int intr)
+static inline void ehci_commit_interrupt(EHCIState *s)
 {
-    int level = 0;
+    if (!s->usbsts_pending) {
+        return;
+    }
+    ehci_set_interrupt(s, s->usbsts_pending);
+    s->usbsts_pending = 0;
+}
 
-    // TODO honour interrupt threshold requests
+static void ehci_set_state(EHCIState *s, int async, int state)
+{
+    if (async) {
+        trace_usb_ehci_state("async", state2str(state));
+        s->astate = state;
+    } else {
+        trace_usb_ehci_state("periodic", state2str(state));
+        s->pstate = state;
+    }
+}
 
-    s->usbsts |= intr;
+static int ehci_get_state(EHCIState *s, int async)
+{
+    return async ? s->astate : s->pstate;
+}
 
-    if ((s->usbsts & USBINTR_MASK) & s->usbintr)
-        level = 1;
+static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
+{
+    if (async) {
+        s->a_fetch_addr = addr;
+    } else {
+        s->p_fetch_addr = addr;
+    }
+}
 
-    qemu_set_irq(s->irq, level);
+static int ehci_get_fetch_addr(EHCIState *s, int async)
+{
+    return async ? s->a_fetch_addr : s->p_fetch_addr;
+}
+
+static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh)
+{
+    /* need three here due to argument count limits */
+    trace_usb_ehci_qh_ptrs(q, addr, qh->next,
+                           qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
+    trace_usb_ehci_qh_fields(addr,
+                             get_field(qh->epchar, QH_EPCHAR_RL),
+                             get_field(qh->epchar, QH_EPCHAR_MPLEN),
+                             get_field(qh->epchar, QH_EPCHAR_EPS),
+                             get_field(qh->epchar, QH_EPCHAR_EP),
+                             get_field(qh->epchar, QH_EPCHAR_DEVADDR));
+    trace_usb_ehci_qh_bits(addr,
+                           (bool)(qh->epchar & QH_EPCHAR_C),
+                           (bool)(qh->epchar & QH_EPCHAR_H),
+                           (bool)(qh->epchar & QH_EPCHAR_DTC),
+                           (bool)(qh->epchar & QH_EPCHAR_I));
+}
+
+static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
+{
+    /* need three here due to argument count limits */
+    trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
+    trace_usb_ehci_qtd_fields(addr,
+                              get_field(qtd->token, QTD_TOKEN_TBYTES),
+                              get_field(qtd->token, QTD_TOKEN_CPAGE),
+                              get_field(qtd->token, QTD_TOKEN_CERR),
+                              get_field(qtd->token, QTD_TOKEN_PID));
+    trace_usb_ehci_qtd_bits(addr,
+                            (bool)(qtd->token & QTD_TOKEN_IOC),
+                            (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+                            (bool)(qtd->token & QTD_TOKEN_HALT),
+                            (bool)(qtd->token & QTD_TOKEN_BABBLE),
+                            (bool)(qtd->token & QTD_TOKEN_XACTERR));
+}
+
+static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+{
+    trace_usb_ehci_itd(addr, itd->next,
+                       get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
+                       get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
+                       get_field(itd->bufptr[0], ITD_BUFPTR_EP),
+                       get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
+}
+
+static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
+                            EHCIsitd *sitd)
+{
+    trace_usb_ehci_sitd(addr, sitd->next,
+                        (bool)(sitd->results & SITD_RESULTS_ACTIVE));
+}
+
+/* queue management */
+
+static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+{
+    EHCIQueue *q;
+
+    q = g_malloc0(sizeof(*q));
+    q->ehci = ehci;
+    q->async_schedule = async;
+    QTAILQ_INSERT_HEAD(&ehci->queues, q, next);
+    trace_usb_ehci_queue_action(q, "alloc");
+    return q;
+}
+
+static void ehci_free_queue(EHCIQueue *q)
+{
+    trace_usb_ehci_queue_action(q, "free");
+    if (q->async == EHCI_ASYNC_INFLIGHT) {
+        usb_cancel_packet(&q->packet);
+    }
+    QTAILQ_REMOVE(&q->ehci->queues, q, next);
+    g_free(q);
+}
+
+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
+{
+    EHCIQueue *q;
+
+    QTAILQ_FOREACH(q, &ehci->queues, next) {
+        if (addr == q->qhaddr) {
+            return q;
+        }
+    }
+    return NULL;
+}
+
+static void ehci_queues_rip_unused(EHCIState *ehci)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        if (q->seen) {
+            q->seen = 0;
+            q->ts = ehci->last_run_ns;
+            continue;
+        }
+        if (ehci->last_run_ns < q->ts + 250000000) {
+            /* allow 0.25 sec idle */
+            continue;
+        }
+        ehci_free_queue(q);
+    }
+}
+
+static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        if (q->packet.owner != dev) {
+            continue;
+        }
+        ehci_free_queue(q);
+    }
+}
+
+static void ehci_queues_rip_all(EHCIState *ehci)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        ehci_free_queue(q);
+    }
 }
 
 /* Attach or detach a device on root hub */
 
-static void ehci_attach(USBPort *port, USBDevice *dev)
+static void ehci_attach(USBPort *port)
 {
     EHCIState *s = port->opaque;
     uint32_t *portsc = &s->portsc[port->index];
 
-    DPRINTF("ehci_attach invoked for index %d, portsc 0x%x, desc %s\n",
-           port->index, *portsc, dev ? dev->product_desc : "undefined");
+    trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
 
-    if (dev) {
-        if (port->dev) {
-            usb_attach(port, NULL);
-        }
+    if (*portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->dev = port->dev;
+        companion->ops->attach(companion);
+        return;
+    }
 
-        *portsc |= PORTSC_CONNECT;
+    *portsc |= PORTSC_CONNECT;
+    *portsc |= PORTSC_CSC;
 
-        usb_send_msg(dev, USB_MSG_ATTACH);
-        port->dev = dev;
-    } else {
-        *portsc &= ~PORTSC_CONNECT;
+    ehci_set_interrupt(s, USBSTS_PCD);
+}
 
-        if (port->dev) {
-            dev = port->dev;
-            usb_send_msg(dev, USB_MSG_DETACH);
-        }
+static void ehci_detach(USBPort *port)
+{
+    EHCIState *s = port->opaque;
+    uint32_t *portsc = &s->portsc[port->index];
 
-        port->dev = NULL;
+    trace_usb_ehci_port_detach(port->index);
+
+    if (*portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->detach(companion);
+        companion->dev = NULL;
+        return;
     }
 
+    ehci_queues_rip_device(s, port->dev);
+
+    *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
     *portsc |= PORTSC_CSC;
 
-    /*
-     *  If a high speed device is attached then we own this port(indicated
-     *  by zero in the PORTSC_POWNER bit field) so set the status bit
-     *  and set an interrupt if enabled.
-     */
-    if ( !(*portsc & PORTSC_POWNER)) {
-        ehci_set_interrupt(s, USBSTS_PCD);
+    ehci_set_interrupt(s, USBSTS_PCD);
+}
+
+static void ehci_child_detach(USBPort *port, USBDevice *child)
+{
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
+
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->child_detach(companion, child);
+        companion->dev = NULL;
+        return;
+    }
+
+    ehci_queues_rip_device(s, child);
+}
+
+static void ehci_wakeup(USBPort *port)
+{
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
+
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        if (companion->ops->wakeup) {
+            companion->ops->wakeup(companion);
+        }
+    }
+}
+
+static int ehci_register_companion(USBBus *bus, USBPort *ports[],
+                                   uint32_t portcount, uint32_t firstport)
+{
+    EHCIState *s = container_of(bus, EHCIState, bus);
+    uint32_t i;
+
+    if (firstport + portcount > NB_PORTS) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
+                      "firstport on masterbus");
+        error_printf_unless_qmp(
+            "firstport value of %u makes companion take ports %u - %u, which "
+            "is outside of the valid range of 0 - %u\n", firstport, firstport,
+            firstport + portcount - 1, NB_PORTS - 1);
+        return -1;
+    }
+
+    for (i = 0; i < portcount; i++) {
+        if (s->companion_ports[firstport + i]) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+                          "an USB masterbus");
+            error_printf_unless_qmp(
+                "port %u on masterbus %s already has a companion assigned\n",
+                firstport + i, bus->qbus.name);
+            return -1;
+        }
     }
+
+    for (i = 0; i < portcount; i++) {
+        s->companion_ports[firstport + i] = ports[i];
+        s->ports[firstport + i].speedmask |=
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
+        /* Ensure devs attached before the initial reset go to the companion */
+        s->portsc[firstport + i] = PORTSC_POWNER;
+    }
+
+    s->companion_count++;
+    s->mmio[0x05] = (s->companion_count << 4) | portcount;
+
+    return 0;
 }
 
 /* 4.1 host controller initialization */
@@ -541,6 +849,20 @@ static void ehci_reset(void *opaque)
 {
     EHCIState *s = opaque;
     int i;
+    USBDevice *devs[NB_PORTS];
+
+    trace_usb_ehci_reset();
+
+    /*
+     * Do the detach before touching portsc, so that it correctly gets send to
+     * us or to our companion based on PORTSC_POWNER before the reset.
+     */
+    for(i = 0; i < NB_PORTS; i++) {
+        devs[i] = s->ports[i].dev;
+        if (devs[i] && devs[i]->attached) {
+            usb_detach(&s->ports[i]);
+        }
+    }
 
     memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
 
@@ -549,17 +871,21 @@ static void ehci_reset(void *opaque)
 
     s->astate = EST_INACTIVE;
     s->pstate = EST_INACTIVE;
-    s->async_port_in_progress = -1;
-    s->async_complete = 0;
     s->isoch_pause = -1;
     s->attach_poll_counter = 0;
 
-    for (i = 0; i < NB_PORTS; i++) {
-        s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
-
-        if (s->ports[i].dev)
-            ehci_attach(&s->ports[i], s->ports[i].dev);
+    for(i = 0; i < NB_PORTS; i++) {
+        if (s->companion_ports[i]) {
+            s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
+        } else {
+            s->portsc[i] = PORTSC_PPOWER;
+        }
+        if (devs[i] && devs[i]->attached) {
+            usb_attach(&s->ports[i]);
+            usb_send_msg(devs[i], USB_MSG_RESET);
+        }
     }
+    ehci_queues_rip_all(s);
 }
 
 static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
@@ -590,6 +916,7 @@ static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
     val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
           (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
 
+    trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
     return val;
 }
 
@@ -605,108 +932,117 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
     exit(1);
 }
 
-static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
 {
-    uint32_t *portsc = &s->portsc[port];
-    int rwc;
     USBDevice *dev = s->ports[port].dev;
+    uint32_t *portsc = &s->portsc[port];
+    uint32_t orig;
 
-    DPRINTF("port_status_write: "
-            "PORTSC (port %d) curr %08X new %08X rw-clear %08X rw %08X\n",
-            port, *portsc, val, (val & PORTSC_RWC_MASK), val & PORTSC_RO_MASK);
+    if (s->companion_ports[port] == NULL)
+        return;
 
-    rwc = val & PORTSC_RWC_MASK;
-    val &= PORTSC_RO_MASK;
+    owner = owner & PORTSC_POWNER;
+    orig  = *portsc & PORTSC_POWNER;
 
-    // handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC);
+    if (!(owner ^ orig)) {
+        return;
+    }
 
-    *portsc &= ~rwc;
+    if (dev && dev->attached) {
+        usb_detach(&s->ports[port]);
+    }
 
-    if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
-        DPRINTF("port_status_write: USBTRAN Port %d reset begin\n", port);
+    *portsc &= ~PORTSC_POWNER;
+    *portsc |= owner;
+
+    if (dev && dev->attached) {
+        usb_attach(&s->ports[port]);
     }
+}
 
-    if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
-        DPRINTF("port_status_write: USBTRAN Port %d reset done\n", port);
-        ehci_attach(&s->ports[port], dev);
+static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+{
+    uint32_t *portsc = &s->portsc[port];
+    USBDevice *dev = s->ports[port].dev;
+
+    /* Clear rwc bits */
+    *portsc &= ~(val & PORTSC_RWC_MASK);
+    /* The guest may clear, but not set the PED bit */
+    *portsc &= val | ~PORTSC_PED;
+    /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
+    handle_port_owner_write(s, port, val);
+    /* And finally apply RO_MASK */
+    val &= PORTSC_RO_MASK;
 
-        // TODO how to handle reset of ports with no device
-        if (dev)
-            usb_send_msg(dev, USB_MSG_RESET);
+    if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
+        trace_usb_ehci_port_reset(port, 1);
+    }
 
-        if (s->ports[port].dev) {
-            DPRINTF("port_status_write: "
-                    "Device was connected before reset, clearing CSC bit\n");
+    if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
+        trace_usb_ehci_port_reset(port, 0);
+        if (dev && dev->attached) {
+            usb_reset(&s->ports[port]);
             *portsc &= ~PORTSC_CSC;
         }
 
-        /*  Table 2.16 Set the enable bit(and enable bit change) to indicate
+        /*
+         *  Table 2.16 Set the enable bit(and enable bit change) to indicate
          *  to SW that this port has a high speed device attached
-         *
-         *  TODO - when to disable?
          */
-        val |= PORTSC_PED;
-        val |= PORTSC_PEDC;
+        if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+            val |= PORTSC_PED;
+        }
     }
 
     *portsc &= ~PORTSC_RO_MASK;
     *portsc |= val;
-    DPRINTF("port_status_write: Port %d status set to 0x%08x\n", port, *portsc);
 }
 
 static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
 {
     EHCIState *s = ptr;
+    uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
+    uint32_t old = *mmio;
     int i;
-#if EHCI_DEBUG
-    const char *str;
-#endif
+
+    trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
 
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
         fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
-            TARGET_FMT_plx "\n", addr);
+                TARGET_FMT_plx "\n", addr);
         return;
     }
 
     if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
         handle_port_status_write(s, (addr-PORTSC)/4, val);
+        trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
         return;
     }
 
     if (addr < OPREGBASE) {
         fprintf(stderr, "usb-ehci: write attempt to read-only register"
-            TARGET_FMT_plx "\n", addr);
+                TARGET_FMT_plx "\n", addr);
         return;
     }
 
 
     /* Do any register specific pre-write processing here.  */
-#if EHCI_DEBUG
-    str = addr2str((unsigned) addr);
-#endif
-    switch(addr)
-    {
+    switch(addr) {
     case USBCMD:
-        DPRINTF("ehci_mem_writel: USBCMD val=0x%08X, current cmd=0x%08X\n",
-                val, s->usbcmd);
-
         if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
-            DPRINTF("ehci_mem_writel: %s run, clear halt\n", str);
-            qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
+            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
             SET_LAST_RUN_CLOCK(s);
-            s->usbsts &= ~USBSTS_HALT;
+            ehci_clear_usbsts(s, USBSTS_HALT);
         }
 
         if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
-            DPRINTF("                         ** STOP **\n");
             qemu_del_timer(s->frame_timer);
             // TODO - should finish out some stuff before setting halt
-            s->usbsts |= USBSTS_HALT;
+            ehci_set_usbsts(s, USBSTS_HALT);
         }
 
         if (val & USBCMD_HCRESET) {
-            DPRINTF("ehci_mem_writel: %s run, resetting\n", str);
             ehci_reset(s);
             val &= ~USBCMD_HCRESET;
         }
@@ -717,60 +1053,28 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
                     val & USBCMD_FLS);
             val &= ~USBCMD_FLS;
         }
-#if EHCI_DEBUG
-        if ((val & USBCMD_PSE) && !(s->usbcmd & USBCMD_PSE)) {
-            DPRINTF("periodic scheduling enabled\n");
-        }
-        if (!(val & USBCMD_PSE) && (s->usbcmd & USBCMD_PSE)) {
-            DPRINTF("periodic scheduling disabled\n");
-        }
-        if ((val & USBCMD_ASE) && !(s->usbcmd & USBCMD_ASE)) {
-            DPRINTF("asynchronous scheduling enabled\n");
-        }
-        if (!(val & USBCMD_ASE) && (s->usbcmd & USBCMD_ASE)) {
-            DPRINTF("asynchronous scheduling disabled\n");
-        }
-        if ((val & USBCMD_IAAD) && !(s->usbcmd & USBCMD_IAAD)) {
-            DPRINTF("doorbell request received\n");
-        }
-        if ((val & USBCMD_LHCR) && !(s->usbcmd & USBCMD_LHCR)) {
-            DPRINTF("light host controller reset received\n");
-        }
-        if ((val & USBCMD_ITC) != (s->usbcmd & USBCMD_ITC)) {
-            DPRINTF("interrupt threshold control set to %x\n",
-                    (val & USBCMD_ITC)>>USBCMD_ITC_SH);
-        }
-#endif
         break;
 
-
     case USBSTS:
         val &= USBSTS_RO_MASK;              // bits 6 thru 31 are RO
-        DPRINTF("ehci_mem_writel: %s RWC set to 0x%08X\n", str, val);
-
-        val = (s->usbsts &= ~val);         // bits 0 thru 5 are R/WC
-
-        DPRINTF("ehci_mem_writel: %s updating interrupt condition\n", str);
+        ehci_clear_usbsts(s, val);          // bits 0 thru 5 are R/WC
+        val = s->usbsts;
         ehci_set_interrupt(s, 0);
         break;
 
-
     case USBINTR:
         val &= USBINTR_MASK;
-        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         break;
 
     case FRINDEX:
         s->sofv = val >> 3;
-        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         break;
 
     case CONFIGFLAG:
-        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         val &= 0x1;
         if (val) {
-            for (i = 0; i < NB_PORTS; i++)
-                s->portsc[i] &= ~PORTSC_POWNER;
+            for(i = 0; i < NB_PORTS; i++)
+                handle_port_owner_write(s, i, 0);
         }
         break;
 
@@ -780,7 +1084,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
               "ehci: PERIODIC list base register set while periodic schedule\n"
               "      is enabled and HC is enabled\n");
         }
-        DPRINTF("ehci_mem_writel: P-LIST BASE set to 0x%08X\n", val);
         break;
 
     case ASYNCLISTADDR:
@@ -789,23 +1092,24 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
               "ehci: ASYNC list address register set while async schedule\n"
               "      is enabled and HC is enabled\n");
         }
-        DPRINTF("ehci_mem_writel: A-LIST ADDR set to 0x%08X\n", val);
         break;
     }
 
-    *(uint32_t *)(&s->mmio[addr]) = val;
+    *mmio = val;
+    trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
 }
 
 
 // TODO : Put in common header file, duplication from usb-ohci.c
 
 /* Get an array of dwords from main memory */
-static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int get_dwords(EHCIState *ehci, uint32_t addr,
+                             uint32_t *buf, int num)
 {
     int i;
 
     for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
-        cpu_physical_memory_rw(addr,(uint8_t *)buf, sizeof(*buf), 0);
+        pci_dma_read(&ehci->dev, addr, (uint8_t *)buf, sizeof(*buf));
         *buf = le32_to_cpu(*buf);
     }
 
@@ -813,13 +1117,14 @@ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
 }
 
 /* Put an array of dwords in to main memory */
-static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int put_dwords(EHCIState *ehci, uint32_t addr,
+                             uint32_t *buf, int num)
 {
     int i;
 
     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);
+        pci_dma_write(&ehci->dev, addr, (uint8_t *)&tmp, sizeof(tmp));
     }
 
     return 1;
@@ -827,7 +1132,7 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
 
 // 4.10.2
 
-static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
+static int ehci_qh_do_overlay(EHCIQueue *q)
 {
     int i;
     int dtoggle;
@@ -837,200 +1142,193 @@ static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
 
     // remember values in fields to preserve in qh after overlay
 
-    dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
-    ping    = qh->token & QTD_TOKEN_PING;
+    dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
+    ping    = q->qh.token & QTD_TOKEN_PING;
 
-    DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current_qtd,
-            ehci->qtdaddr);
-    qh->current_qtd = ehci->qtdaddr;
-    qh->next_qtd    = qtd->next;
-    qh->altnext_qtd = qtd->altnext;
-    qh->token       = qtd->token;
+    q->qh.current_qtd = q->qtdaddr;
+    q->qh.next_qtd    = q->qtd.next;
+    q->qh.altnext_qtd = q->qtd.altnext;
+    q->qh.token       = q->qtd.token;
 
 
-    eps = get_field(qh->epchar, QH_EPCHAR_EPS);
+    eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
     if (eps == EHCI_QH_EPS_HIGH) {
-        qh->token &= ~QTD_TOKEN_PING;
-        qh->token |= ping;
+        q->qh.token &= ~QTD_TOKEN_PING;
+        q->qh.token |= ping;
     }
 
-    reload = get_field(qh->epchar, QH_EPCHAR_RL);
-    set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+    set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
 
     for (i = 0; i < 5; i++) {
-        qh->bufptr[i] = qtd->bufptr[i];
+        q->qh.bufptr[i] = q->qtd.bufptr[i];
     }
 
-    if (!(qh->epchar & QH_EPCHAR_DTC)) {
+    if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
         // preserve QH DT bit
-        qh->token &= ~QTD_TOKEN_DTOGGLE;
-        qh->token |= dtoggle;
+        q->qh.token &= ~QTD_TOKEN_DTOGGLE;
+        q->qh.token |= dtoggle;
     }
 
-    qh->bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
-    qh->bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
+    q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
+    q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
 
-    put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+    put_dwords(q->ehci, NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh,
+               sizeof(EHCIqh) >> 2);
 
     return 0;
 }
 
-static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
+static int ehci_init_transfer(EHCIQueue *q)
 {
-    int bufpos = 0;
-    int cpage, offset;
-    uint32_t head;
-    uint32_t tail;
-
+    uint32_t cpage, offset, bytes, plen;
+    dma_addr_t page;
 
-    if (!bytes)
-        return 0;
+    cpage  = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+    bytes  = get_field(q->qh.token, QTD_TOKEN_TBYTES);
+    offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+    pci_dma_sglist_init(&q->sgl, &q->ehci->dev, 5);
 
-    cpage = get_field(qh->token, QTD_TOKEN_CPAGE);
-    if (cpage > 4) {
-        fprintf(stderr, "cpage out of range (%d)\n", cpage);
-        return USB_RET_PROCERR;
-    }
-
-    offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
-    DPRINTF("ehci_buffer_rw: %sing %d bytes %08x cpage %d offset %d\n",
-           rw ? "writ" : "read", bytes, qh->bufptr[0], cpage, offset);
-
-    do {
-        /* start and end of this page */
-        head = qh->bufptr[cpage] & QTD_BUFPTR_MASK;
-        tail = head + ~QTD_BUFPTR_MASK + 1;
-        /* add offset into page */
-        head |= offset;
-
-        if (bytes <= (tail - head)) {
-            tail = head + bytes;
+    while (bytes > 0) {
+        if (cpage > 4) {
+            fprintf(stderr, "cpage out of range (%d)\n", cpage);
+            return USB_RET_PROCERR;
         }
 
-        DPRINTF("DATA %s cpage:%d head:%08X tail:%08X target:%08X\n",
-                rw ? "WRITE" : "READ ", cpage, head, tail, bufpos);
-
-        cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
-
-        bufpos += (tail - head);
-        bytes -= (tail - head);
-
-        if (bytes > 0) {
-            cpage++;
+        page  = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
+        page += offset;
+        plen  = bytes;
+        if (plen > 4096 - offset) {
+            plen = 4096 - offset;
             offset = 0;
+            cpage++;
         }
-    } while (bytes > 0);
-
-    /* save cpage */
-    set_field(&qh->token, cpage, QTD_TOKEN_CPAGE);
-
-    /* save offset into cpage */
-    offset = tail - head;
-    qh->bufptr[0] &= ~QTD_BUFPTR_MASK;
-    qh->bufptr[0] |= offset;
 
+        qemu_sglist_add(&q->sgl, page, plen);
+        bytes -= plen;
+    }
     return 0;
 }
 
-static void ehci_async_complete_packet(USBPacket *packet, void *opaque)
+static void ehci_finish_transfer(EHCIQueue *q, int status)
 {
-    EHCIState *ehci = opaque;
+    uint32_t cpage, offset;
+
+    qemu_sglist_destroy(&q->sgl);
 
-    DPRINTF("Async packet complete\n");
-    ehci->async_complete = 1;
-    ehci->exec_status = packet->len;
+    if (status > 0) {
+        /* update cpage & offset */
+        cpage  = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+        offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+
+        offset += status;
+        cpage  += offset >> QTD_BUFPTR_SH;
+        offset &= ~QTD_BUFPTR_MASK;
+
+        set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+        q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+        q->qh.bufptr[0] |= offset;
+    }
 }
 
-static int ehci_execute_complete(EHCIState *ehci,
-                                  EHCIqh *qh,
-                                  int ret)
+static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
 {
-    int i, c_err, reload;
+    EHCIQueue *q;
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
 
-    if (ret == USB_RET_ASYNC && !ehci->async_complete) {
-        DPRINTF("not done yet\n");
-        return ret;
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->complete(companion, packet);
+        return;
     }
 
-    ehci->async_complete = 0;
-    i = ehci->async_port_in_progress;
-    ehci->async_port_in_progress = -1;
+    q = container_of(packet, EHCIQueue, packet);
+    trace_usb_ehci_queue_action(q, "wakeup");
+    assert(q->async == EHCI_ASYNC_INFLIGHT);
+    q->async = EHCI_ASYNC_FINISHED;
+    q->usb_status = packet->result;
+}
+
+static void ehci_execute_complete(EHCIQueue *q)
+{
+    int c_err, reload;
+
+    assert(q->async != EHCI_ASYNC_INFLIGHT);
+    q->async = EHCI_ASYNC_NONE;
 
     DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
-           ehci->qhaddr, qh->next, ehci->qtdaddr, ret);
+            q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
 
-    if (ret < 0) {
+    if (q->usb_status < 0) {
 err:
         /* TO-DO: put this is in a function that can be invoked below as well */
-        c_err = get_field(qh->token, QTD_TOKEN_CERR);
+        c_err = get_field(q->qh.token, QTD_TOKEN_CERR);
         c_err--;
-        set_field(&qh->token, c_err, QTD_TOKEN_CERR);
+        set_field(&q->qh.token, c_err, QTD_TOKEN_CERR);
 
-        switch(ret) {
+        switch(q->usb_status) {
         case USB_RET_NODEV:
-            fprintf(stderr, "USB no device\n");
+            q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
             break;
         case USB_RET_STALL:
-            fprintf(stderr, "USB stall\n");
-            qh->token |= QTD_TOKEN_HALT;
+            q->qh.token |= QTD_TOKEN_HALT;
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
             break;
         case USB_RET_NAK:
             /* 4.10.3 */
-            reload = get_field(qh->epchar, QH_EPCHAR_RL);
-            if ((ehci->pid == USB_TOKEN_IN) && reload) {
-                int nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+            reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+            if ((q->pid == USB_TOKEN_IN) && reload) {
+                int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
                 nakcnt--;
-                set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+                set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
             } else if (!reload) {
-                return USB_RET_NAK;
+                return;
             }
             break;
         case USB_RET_BABBLE:
-            fprintf(stderr, "USB babble TODO\n");
-            qh->token |= QTD_TOKEN_BABBLE;
+            q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
             break;
         default:
-            fprintf(stderr, "USB invalid response %d to handle\n", ret);
-            /* TO-DO: transaction error */
-            ret = USB_RET_PROCERR;
+            /* should not be triggerable */
+            fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status);
+            assert(0);
             break;
         }
     } else {
         // DPRINTF("Short packet condition\n");
         // TODO check 4.12 for splits
 
-        if ((ret > ehci->tbytes) && (ehci->pid == USB_TOKEN_IN)) {
-            ret = USB_RET_BABBLE;
+        if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
+            q->usb_status = USB_RET_BABBLE;
             goto err;
         }
 
-        if (ehci->tbytes && ehci->pid == USB_TOKEN_IN) {
-            if (ehci_buffer_rw(ehci->buffer, qh, ret, 1) != 0) {
-                return USB_RET_PROCERR;
-            }
-            ehci->tbytes -= ret;
+        if (q->tbytes && q->pid == USB_TOKEN_IN) {
+            q->tbytes -= q->usb_status;
         } else {
-            ehci->tbytes = 0;
+            q->tbytes = 0;
         }
 
-        DPRINTF("updating tbytes to %d\n", ehci->tbytes);
-        set_field(&qh->token, ehci->tbytes, QTD_TOKEN_TBYTES);
+        DPRINTF("updating tbytes to %d\n", q->tbytes);
+        set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
     }
+    ehci_finish_transfer(q, q->usb_status);
+    usb_packet_unmap(&q->packet);
 
-    qh->token ^= QTD_TOKEN_DTOGGLE;
-    qh->token &= ~QTD_TOKEN_ACTIVE;
+    q->qh.token ^= QTD_TOKEN_DTOGGLE;
+    q->qh.token &= ~QTD_TOKEN_ACTIVE;
 
-    if ((ret >= 0) && (qh->token & QTD_TOKEN_IOC)) {
-        // TODO should do this after writeback to memory
-        ehci_set_interrupt(ehci, USBSTS_INT);
+    if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) {
+        ehci_record_interrupt(q->ehci, USBSTS_INT);
     }
-
-    return ret;
 }
 
 // 4.10.3
 
-static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
+static int ehci_execute(EHCIQueue *q)
 {
     USBPort *port;
     USBDevice *dev;
@@ -1039,76 +1337,65 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
     int endp;
     int devadr;
 
-    if ( !(qh->token & QTD_TOKEN_ACTIVE)) {
+    if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) {
         fprintf(stderr, "Attempting to execute inactive QH\n");
         return USB_RET_PROCERR;
     }
 
-    ehci->tbytes = (qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
-    if (ehci->tbytes > BUFF_SIZE) {
+    q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+    if (q->tbytes > BUFF_SIZE) {
         fprintf(stderr, "Request for more bytes than allowed\n");
         return USB_RET_PROCERR;
     }
 
-    ehci->pid = (qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
-    switch(ehci->pid) {
-        case 0: ehci->pid = USB_TOKEN_OUT; break;
-        case 1: ehci->pid = USB_TOKEN_IN; break;
-        case 2: ehci->pid = USB_TOKEN_SETUP; break;
+    q->pid = (q->qh.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+    switch(q->pid) {
+        case 0: q->pid = USB_TOKEN_OUT; break;
+        case 1: q->pid = USB_TOKEN_IN; break;
+        case 2: q->pid = USB_TOKEN_SETUP; break;
         default: fprintf(stderr, "bad token\n"); break;
     }
 
-    if ((ehci->tbytes && ehci->pid != USB_TOKEN_IN) &&
-        (ehci_buffer_rw(ehci->buffer, qh, ehci->tbytes, 0) != 0)) {
+    if (ehci_init_transfer(q) != 0) {
         return USB_RET_PROCERR;
     }
 
-    endp = get_field(qh->epchar, QH_EPCHAR_EP);
-    devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
+    endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
+    devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
 
     ret = USB_RET_NODEV;
 
+    usb_packet_setup(&q->packet, q->pid, devadr, endp);
+    usb_packet_map(&q->packet, &q->sgl);
+
     // TO-DO: associating device with ehci port
-    for (i = 0; i < NB_PORTS; i++) {
-        port = &ehci->ports[i];
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &q->ehci->ports[i];
         dev = port->dev;
 
-        // TODO sometime we will also need to check if we are the port owner
-
-        if (!(ehci->portsc[i] &(PORTSC_CONNECT))) {
+        if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
             DPRINTF("Port %d, no exec, not connected(%08X)\n",
-                    i, ehci->portsc[i]);
+                    i, q->ehci->portsc[i]);
             continue;
         }
 
-        ehci->usb_packet.pid = ehci->pid;
-        ehci->usb_packet.devaddr = devadr;
-        ehci->usb_packet.devep = endp;
-        ehci->usb_packet.data = ehci->buffer;
-        ehci->usb_packet.len = ehci->tbytes;
-        ehci->usb_packet.complete_cb = ehci_async_complete_packet;
-        ehci->usb_packet.complete_opaque = ehci;
-
-        ret = dev->info->handle_packet(dev, &ehci->usb_packet);
+        ret = usb_handle_packet(dev, &q->packet);
 
-        DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
-                ehci->qhaddr, qh->next, ehci->qtdaddr, ehci->pid,
-                ehci->usb_packet.len, ehci->tbytes, endp, ret);
+        DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+                "(total %d) endp %x ret %d\n",
+                q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+                q->packet.iov.size, q->tbytes, endp, ret);
 
-        if (ret != USB_RET_NODEV)
+        if (ret != USB_RET_NODEV) {
             break;
+        }
     }
 
     if (ret > BUFF_SIZE) {
-        fprintf(stderr, "ret from handle packet > BUFF_SIZE\n");
+        fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
         return USB_RET_PROCERR;
     }
 
-    if (ret == USB_RET_ASYNC) {
-        ehci->async_port_in_progress = i;
-        ehci->async_complete = 0;
-    }
-
     return ret;
 }
 
@@ -1116,204 +1403,181 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
  */
 
 static int ehci_process_itd(EHCIState *ehci,
-                             EHCIitd *itd)
+                            EHCIitd *itd)
 {
     USBPort *port;
     USBDevice *dev;
     int ret;
-    int i, j;
-    int ptr;
-    int pid;
-    int pg;
-    int len;
-    int dir;
-    int devadr;
-    int endp;
-    int maxpkt;
+    uint32_t i, j, len, pid, dir, devaddr, endp;
+    uint32_t pg, off, ptr1, ptr2, max, mult;
 
     dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
-    devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+    devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
     endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
-    maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+    max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+    mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
 
-#ifdef EHCI_NOMICROFRAMES
     for(i = 0; i < 8; i++) {
-#else
-    i =(ehci->frindex & 7);
-#endif
-
-    if (itd->transact[i] & ITD_XACT_ACTIVE) {
-        DPRINTF("ISOCHRONOUS active for frame %d, interval %d\n",
-                ehci->frindex >> 3, i);
+        if (itd->transact[i] & ITD_XACT_ACTIVE) {
+            pg   = get_field(itd->transact[i], ITD_XACT_PGSEL);
+            off  = itd->transact[i] & ITD_XACT_OFFSET_MASK;
+            ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
+            ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
+            len  = get_field(itd->transact[i], ITD_XACT_LENGTH);
+
+            if (len > max * mult) {
+                len = max * mult;
+            }
 
-        pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
-        ptr = (itd->bufptr[pg] & ITD_BUFPTR_MASK) |
-                  (itd->transact[i] & ITD_XACT_OFFSET_MASK);
-        len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+            if (len > BUFF_SIZE) {
+                return USB_RET_PROCERR;
+            }
 
-        if (len > BUFF_SIZE) {
-            return USB_RET_PROCERR;
-        }
+            pci_dma_sglist_init(&ehci->isgl, &ehci->dev, 2);
+            if (off + len > 4096) {
+                /* transfer crosses page border */
+                uint32_t len2 = off + len - 4096;
+                uint32_t len1 = len - len2;
+                qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
+                qemu_sglist_add(&ehci->isgl, ptr2, len2);
+            } else {
+                qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
+            }
 
-        DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
+            pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
 
-        if (!dir) {
-            cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 0);
-            pid = USB_TOKEN_OUT;
-        } else
-            pid = USB_TOKEN_IN;
+            usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+            usb_packet_map(&ehci->ipacket, &ehci->isgl);
 
-        ret = USB_RET_NODEV;
+            ret = USB_RET_NODEV;
+            for (j = 0; j < NB_PORTS; j++) {
+                port = &ehci->ports[j];
+                dev = port->dev;
 
-        for(j = 0; j < NB_PORTS; j++) {
-            port = &ehci->ports[j];
-            dev = port->dev;
+                if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
+                    continue;
+                }
 
-            // TODO sometime we will also need to check if we are the port owner
+                ret = usb_handle_packet(dev, &ehci->ipacket);
 
-            if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
-                DPRINTF("Port %d, no exec, not connected(%08X)\n",
-                        j, ehci->portsc[j]);
-                continue;
+                if (ret != USB_RET_NODEV) {
+                    break;
+                }
             }
 
-            ehci->usb_packet.pid = ehci->pid;
-            ehci->usb_packet.devaddr = devadr;
-            ehci->usb_packet.devep = endp;
-            ehci->usb_packet.data = ehci->buffer;
-            ehci->usb_packet.len = len;
-            ehci->usb_packet.complete_cb = ehci_async_complete_packet;
-            ehci->usb_packet.complete_opaque = ehci;
-
-            DPRINTF("calling dev->info->handle_packet\n");
-            ret = dev->info->handle_packet(dev, &ehci->usb_packet);
-
-            if (ret != USB_RET_NODEV)
-                break;
-        }
+            usb_packet_unmap(&ehci->ipacket);
+            qemu_sglist_destroy(&ehci->isgl);
 
-        /*  In isoch, there is no facility to indicate a NAK so let's
-         *  instead just complete a zero-byte transaction.  Setting
-         *  DBERR seems too draconian.
-         */
+#if 0
+            /*  In isoch, there is no facility to indicate a NAK so let's
+             *  instead just complete a zero-byte transaction.  Setting
+             *  DBERR seems too draconian.
+             */
 
-        if (ret == USB_RET_NAK) {
-            if (ehci->isoch_pause > 0) {
-                DPRINTF("ISOCH: received a NAK but paused so returning\n");
-                ehci->isoch_pause--;
-                return 0;
-            } else if (ehci->isoch_pause == -1) {
-                DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
-                // Pause frindex for up to 50 msec waiting for data from
-                // remote
-                ehci->isoch_pause = 50;
-                return 0;
+            if (ret == USB_RET_NAK) {
+                if (ehci->isoch_pause > 0) {
+                    DPRINTF("ISOCH: received a NAK but paused so returning\n");
+                    ehci->isoch_pause--;
+                    return 0;
+                } else if (ehci->isoch_pause == -1) {
+                    DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
+                    // Pause frindex for up to 50 msec waiting for data from
+                    // remote
+                    ehci->isoch_pause = 50;
+                    return 0;
+                } else {
+                    DPRINTF("ISOCH: isoch pause timeout! return 0\n");
+                    ret = 0;
+                }
             } else {
-                DPRINTF("ISOCH: isoch pause timeout! return 0\n");
-                ret = 0;
+                DPRINTF("ISOCH: received ACK, clearing pause\n");
+                ehci->isoch_pause = -1;
             }
-        } else {
-            DPRINTF("ISOCH: received ACK, clearing pause\n");
-            ehci->isoch_pause = -1;
-        }
-
-        if (ret >= 0) {
-            itd->transact[i] &= ~ITD_XACT_ACTIVE;
-
-            if (itd->transact[i] & ITD_XACT_IOC) {
-                // TODO should do this after writeback to memory
-                ehci_set_interrupt(ehci, USBSTS_INT);
+#else
+            if (ret == USB_RET_NAK) {
+                ret = 0;
             }
-        }
-
-        if (ret >= 0 && dir) {
-            cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 1);
+#endif
 
-            if (ret != len) {
-                DPRINTF("ISOCH IN expected %d, got %d\n",
-                        len, ret);
-                set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+            if (ret >= 0) {
+                if (!dir) {
+                    /* OUT */
+                    set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
+                } else {
+                    /* IN */
+                    set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+                }
+
+                if (itd->transact[i] & ITD_XACT_IOC) {
+                    ehci_record_interrupt(ehci, USBSTS_INT);
+                }
             }
+            itd->transact[i] &= ~ITD_XACT_ACTIVE;
         }
     }
-
-#ifdef EHCI_NOMICROFRAMES
-    }
-#endif
     return 0;
 }
 
 /*  This state is the entry point for asynchronous schedule
  *  processing.  Entry here consitutes a EHCI start event state (4.8.5)
  */
-static int ehci_state_waitlisthead(EHCIState *ehci,  int async, int *state)
+static int ehci_state_waitlisthead(EHCIState *ehci,  int async)
 {
-    EHCIqh *qh = &ehci->qh;
+    EHCIqh qh;
     int i = 0;
     int again = 0;
     uint32_t entry = ehci->asynclistaddr;
 
     /* set reclamation flag at start event (4.8.6) */
     if (async) {
-        ehci->usbsts |= USBSTS_REC;
+        ehci_set_usbsts(ehci, USBSTS_REC);
     }
 
+    ehci_queues_rip_unused(ehci);
+
     /*  Find the head of the list (4.9.1.1) */
     for(i = 0; i < MAX_QH; i++) {
-        get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+        get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
+                   sizeof(EHCIqh) >> 2);
+        ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
 
-        if (qh->epchar & QH_EPCHAR_H) {
-            DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
-                       entry);
-            if (async)
+        if (qh.epchar & QH_EPCHAR_H) {
+            if (async) {
                 entry |= (NLPTR_TYPE_QH << 1);
+            }
 
-            ehci->fetch_addr = entry;
-            *state = EST_FETCHENTRY;
+            ehci_set_fetch_addr(ehci, async, entry);
+            ehci_set_state(ehci, async, EST_FETCHENTRY);
             again = 1;
             goto out;
         }
 
-        DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
-                   entry);
-        entry = qh->next;
+        entry = qh.next;
         if (entry == ehci->asynclistaddr) {
-            DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
             break;
         }
     }
 
     /* no head found for list. */
 
-    *state = EST_ACTIVE;
+    ehci_set_state(ehci, async, EST_ACTIVE);
 
 out:
     return again;
 }
 
 
-/*  This state is the entry point for periodic schedule processing as 
+/*  This state is the entry point for periodic schedule processing as
  *  well as being a continuation state for async processing.
  */
-static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchentry(EHCIState *ehci, int async)
 {
     int again = 0;
-    uint32_t entry = ehci->fetch_addr;
+    uint32_t entry = ehci_get_fetch_addr(ehci, async);
 
-#if EHCI_DEBUG == 0
-    if (qemu_get_clock(vm_clock) / 1000 >= ehci->frame_end_usec) {
-        if (async) {
-            DPRINTF("FETCHENTRY: FRAME timer elapsed, exit state machine\n");
-            goto out;
-        } else {
-            DPRINTF("FETCHENTRY: WARNING "
-                    "- frame timer elapsed during periodic\n");
-        }
-    }
-#endif
     if (entry < 0x1000) {
         DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
-        *state = EST_ACTIVE;
+        ehci_set_state(ehci, async, EST_ACTIVE);
         goto out;
     }
 
@@ -1325,21 +1589,22 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
 
     switch (NLPTR_TYPE_GET(entry)) {
     case NLPTR_TYPE_QH:
-        DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", entry);
-        *state = EST_FETCHQH;
-        ehci->qhaddr = entry;
+        ehci_set_state(ehci, async, EST_FETCHQH);
         again = 1;
         break;
 
     case NLPTR_TYPE_ITD:
-        DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", entry);
-        *state = EST_FETCHITD;
-        ehci->itdaddr = entry;
+        ehci_set_state(ehci, async, EST_FETCHITD);
+        again = 1;
+        break;
+
+    case NLPTR_TYPE_STITD:
+        ehci_set_state(ehci, async, EST_FETCHSITD);
         again = 1;
         break;
 
     default:
-        // TODO: handle siTD and FSTN types
+        /* TODO: handle FSTN type */
         fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
                 "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
         return -1;
@@ -1349,88 +1614,139 @@ out:
     return again;
 }
 
-static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
 {
-    EHCIqh *qh = &ehci->qh;
+    uint32_t entry;
+    EHCIQueue *q;
     int reload;
-    int again = 0;
 
-    get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+    entry = ehci_get_fetch_addr(ehci, async);
+    q = ehci_find_queue_by_qh(ehci, entry);
+    if (NULL == q) {
+        q = ehci_alloc_queue(ehci, async);
+    }
+    q->qhaddr = entry;
+    q->seen++;
 
-    if (async && (qh->epchar & QH_EPCHAR_H)) {
+    if (q->seen > 1) {
+        /* we are going in circles -- stop processing */
+        ehci_set_state(ehci, async, EST_ACTIVE);
+        q = NULL;
+        goto out;
+    }
+
+    get_dwords(ehci, NLPTR_GET(q->qhaddr),
+               (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+    ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
+
+    if (q->async == EHCI_ASYNC_INFLIGHT) {
+        /* I/O still in progress -- skip queue */
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
+        goto out;
+    }
+    if (q->async == EHCI_ASYNC_FINISHED) {
+        /* I/O finished -- continue processing queue */
+        trace_usb_ehci_queue_action(q, "resume");
+        ehci_set_state(ehci, async, EST_EXECUTING);
+        goto out;
+    }
+
+    if (async && (q->qh.epchar & QH_EPCHAR_H)) {
 
         /*  EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
         if (ehci->usbsts & USBSTS_REC) {
-            ehci->usbsts &= ~USBSTS_REC;
+            ehci_clear_usbsts(ehci, USBSTS_REC);
         } else {
             DPRINTF("FETCHQH:  QH 0x%08x. H-bit set, reclamation status reset"
-                       " - done processing\n", ehci->qhaddr);
-            *state = EST_ACTIVE;
+                       " - done processing\n", q->qhaddr);
+            ehci_set_state(ehci, async, EST_ACTIVE);
+            q = NULL;
             goto out;
         }
     }
 
 #if EHCI_DEBUG
-    if (ehci->qhaddr != qh->next) {
+    if (q->qhaddr != q->qh.next) {
     DPRINTF("FETCHQH:  QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
-               ehci->qhaddr, 
-               qh->epchar & QH_EPCHAR_H,
-               qh->token & QTD_TOKEN_HALT,
-               qh->token & QTD_TOKEN_ACTIVE,
-               qh->next);
+               q->qhaddr,
+               q->qh.epchar & QH_EPCHAR_H,
+               q->qh.token & QTD_TOKEN_HALT,
+               q->qh.token & QTD_TOKEN_ACTIVE,
+               q->qh.next);
     }
 #endif
 
-    reload = get_field(qh->epchar, QH_EPCHAR_RL);
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
     if (reload) {
-        DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
-        set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+        set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
     }
 
-    if (qh->token & QTD_TOKEN_HALT) {
-        DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
-        *state = EST_HORIZONTALQH;
-        again = 1;
+    if (q->qh.token & QTD_TOKEN_HALT) {
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
 
-    } else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
-        DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
-        ehci->qtdaddr = qh->current_qtd;
-        *state = EST_FETCHQTD;
-        again = 1;
+    } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) {
+        q->qtdaddr = q->qh.current_qtd;
+        ehci_set_state(ehci, async, EST_FETCHQTD);
 
     } else {
         /*  EHCI spec version 1.0 Section 4.10.2 */
-        DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
-        *state = EST_ADVANCEQUEUE;
-        again = 1;
+        ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
     }
 
 out:
-    return again;
+    return q;
 }
 
-static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchitd(EHCIState *ehci, int async)
 {
+    uint32_t entry;
     EHCIitd itd;
 
-    get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
+    assert(!async);
+    entry = ehci_get_fetch_addr(ehci, async);
+
+    get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
                sizeof(EHCIitd) >> 2);
-    DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
-               ehci->itdaddr, itd.next);
+    ehci_trace_itd(ehci, entry, &itd);
 
-    if (ehci_process_itd(ehci, &itd) != 0)
+    if (ehci_process_itd(ehci, &itd) != 0) {
         return -1;
+    }
 
-    put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
-                sizeof(EHCIitd) >> 2);
-    ehci->itdaddr = itd.next;
-    *state = EST_FETCHITD;
+    put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
+               sizeof(EHCIitd) >> 2);
+    ehci_set_fetch_addr(ehci, async, itd.next);
+    ehci_set_state(ehci, async, EST_FETCHENTRY);
 
     return 1;
 }
 
+static int ehci_state_fetchsitd(EHCIState *ehci, int async)
+{
+    uint32_t entry;
+    EHCIsitd sitd;
+
+    assert(!async);
+    entry = ehci_get_fetch_addr(ehci, async);
+
+    get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
+               sizeof(EHCIsitd) >> 2);
+    ehci_trace_sitd(ehci, entry, &sitd);
+
+    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
+        /* siTD is not active, nothing to do */;
+    } else {
+        /* TODO: split transfers are not implemented */
+        fprintf(stderr, "WARNING: Skipping active siTD\n");
+    }
+
+    ehci_set_fetch_addr(ehci, async, sitd.next);
+    ehci_set_state(ehci, async, EST_FETCHENTRY);
+    return 1;
+}
+
 /* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+static int ehci_state_advqueue(EHCIQueue *q, int async)
 {
 #if 0
     /* TO-DO: 4.10.2 - paragraph 2
@@ -1438,315 +1754,308 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
      * go to horizontal QH
      */
     if (I-bit set) {
-        *state = EST_HORIZONTALQH;
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
         goto out;
     }
 #endif
 
-    /* 
+    /*
      * want data and alt-next qTD is valid
      */
-    if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
-        (ehci->qh.altnext_qtd > 0x1000) &&
-        (NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
-        DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
-                   "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
-                   ehci->qh.current_qtd, ehci->qh.altnext_qtd,
-                   ehci->qh.next_qtd, ehci->qh.next);
-        ehci->qtdaddr = ehci->qh.altnext_qtd;
-        *state = EST_FETCHQTD;
+    if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+        (q->qh.altnext_qtd > 0x1000) &&
+        (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
+        q->qtdaddr = q->qh.altnext_qtd;
+        ehci_set_state(q->ehci, async, EST_FETCHQTD);
 
     /*
      *  next qTD is valid
      */
-    } else if ((ehci->qh.next_qtd > 0x1000) &&
-               (NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
-        DPRINTF_ST("ADVQUEUE: next qTD. "
-                   "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
-                   ehci->qh.current_qtd, ehci->qh.altnext_qtd, 
-                   ehci->qh.next_qtd, ehci->qh.next);
-        ehci->qtdaddr = ehci->qh.next_qtd;
-        *state = EST_FETCHQTD;
+    } else if ((q->qh.next_qtd > 0x1000) &&
+               (NLPTR_TBIT(q->qh.next_qtd) == 0)) {
+        q->qtdaddr = q->qh.next_qtd;
+        ehci_set_state(q->ehci, async, EST_FETCHQTD);
 
     /*
      *  no valid qTD, try next QH
      */
     } else {
-        DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
-        *state = EST_HORIZONTALQH;
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
     }
 
     return 1;
 }
 
 /* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqtd(EHCIQueue *q, int async)
 {
-    EHCIqtd *qtd = &ehci->qtd;
     int again = 0;
 
-    get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+    get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qtd,
+               sizeof(EHCIqtd) >> 2);
+    ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd);
 
-    if (qtd->token & QTD_TOKEN_ACTIVE) {
-        *state = EST_EXECUTE;
+    if (q->qtd.token & QTD_TOKEN_ACTIVE) {
+        ehci_set_state(q->ehci, async, EST_EXECUTE);
         again = 1;
     } else {
-        *state = EST_HORIZONTALQH;
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
         again = 1;
     }
 
     return again;
 }
 
-static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_horizqh(EHCIQueue *q, int async)
 {
     int again = 0;
 
-    if (ehci->fetch_addr != ehci->qh.next) {
-        ehci->fetch_addr = ehci->qh.next;
-        *state = EST_FETCHENTRY;
+    if (ehci_get_fetch_addr(q->ehci, async) != q->qh.next) {
+        ehci_set_fetch_addr(q->ehci, async, q->qh.next);
+        ehci_set_state(q->ehci, async, EST_FETCHENTRY);
         again = 1;
     } else {
-        *state = EST_ACTIVE;
+        ehci_set_state(q->ehci, async, EST_ACTIVE);
     }
 
     return again;
 }
 
-static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+/*
+ *  Write the qh back to guest physical memory.  This step isn't
+ *  in the EHCI spec but we need to do it since we don't share
+ *  physical memory with our guest VM.
+ *
+ *  The first three dwords are read-only for the EHCI, so skip them
+ *  when writing back the qh.
+ */
+static void ehci_flush_qh(EHCIQueue *q)
+{
+    uint32_t *qh = (uint32_t *) &q->qh;
+    uint32_t dwords = sizeof(EHCIqh) >> 2;
+    uint32_t addr = NLPTR_GET(q->qhaddr);
+
+    put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
+}
+
+static int ehci_state_execute(EHCIQueue *q, int async)
 {
-    EHCIqh *qh = &ehci->qh;
-    EHCIqtd *qtd = &ehci->qtd;
     int again = 0;
     int reload, nakcnt;
     int smask;
 
-    if (async) {
-        DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
-                  ehci->qhaddr, ehci->qtdaddr);
-    } else {
-        DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
-    }
-
-    if (ehci_qh_do_overlay(ehci, qh, qtd) != 0)
+    if (ehci_qh_do_overlay(q) != 0) {
         return -1;
-
-    smask = get_field(qh->epcap, QH_EPCAP_SMASK);
-#ifndef EHCI_NOMICROFRAMES
-    if (smask && (smask & (1 << (ehci->frindex & 7))) == 0) {
-        DPRINTF_ST("PERIODIC active not interval: mask %x, frindex %d,%d\n",
-                   smask, (ehci->frindex >> 3),(ehci->frindex & 7));
-
-        *state = EST_HORIZONTALQH;
-        again = 1;
-        goto out;
     }
-#endif
+
+    smask = get_field(q->qh.epcap, QH_EPCAP_SMASK);
 
     if (!smask) {
-        reload = get_field(qh->epchar, QH_EPCHAR_RL);
-        nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+        reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
         if (reload && !nakcnt) {
-            DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
-            *state = EST_HORIZONTALQH;
+            ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
             again = 1;
             goto out;
         }
     }
 
     // TODO verify enough time remains in the uframe as in 4.4.1.1
-
     // TODO write back ptr to async list when done or out of time
-
     // TODO Windows does not seem to ever set the MULT field
 
-
-    if (!async)
-    {
-        int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+    if (!async) {
+        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
         if (!transactCtr) {
-            DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
-            *state = EST_HORIZONTALQH;
+            ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
             again = 1;
             goto out;
         }
     }
 
+    if (async) {
+        ehci_set_usbsts(q->ehci, USBSTS_REC);
+    }
 
-    if (async)
-        ehci->usbsts |= USBSTS_REC;
-
-    ehci->exec_status = ehci_execute(ehci, qh);
-    if (ehci->exec_status == USB_RET_PROCERR) {
+    q->usb_status = ehci_execute(q);
+    if (q->usb_status == USB_RET_PROCERR) {
         again = -1;
         goto out;
     }
-    *state = EST_EXECUTING;
-
-    if (ehci->exec_status != USB_RET_ASYNC)
+    if (q->usb_status == USB_RET_ASYNC) {
+        ehci_flush_qh(q);
+        trace_usb_ehci_queue_action(q, "suspend");
+        q->async = EHCI_ASYNC_INFLIGHT;
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
         again = 1;
+        goto out;
+    }
+
+    ehci_set_state(q->ehci, async, EST_EXECUTING);
+    again = 1;
 
 out:
     return again;
 }
 
-static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+static int ehci_state_executing(EHCIQueue *q, int async)
 {
-    EHCIqh *qh = &ehci->qh;
     int again = 0;
     int reload, nakcnt;
 
-    ehci->exec_status = ehci_execute_complete(ehci, qh, ehci->exec_status);
-    if (ehci->exec_status == USB_RET_ASYNC) {
+    ehci_execute_complete(q);
+    if (q->usb_status == USB_RET_ASYNC) {
         goto out;
     }
-    if (ehci->exec_status == USB_RET_PROCERR) {
+    if (q->usb_status == USB_RET_PROCERR) {
         again = -1;
         goto out;
     }
 
     // 4.10.3
     if (!async) {
-        int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
         transactCtr--;
-        set_field(&qh->epcap, transactCtr, QH_EPCAP_MULT);
+        set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
         // 4.10.3, bottom of page 82, should exit this state when transaction
         // counter decrements to 0
     }
 
-
-    reload = get_field(qh->epchar, QH_EPCHAR_RL);
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
     if (reload) {
-        nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
-        if (ehci->exec_status == USB_RET_NAK) {
+        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+        if (q->usb_status == USB_RET_NAK) {
             if (nakcnt) {
                 nakcnt--;
             }
-            DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
-                    nakcnt);
         } else {
             nakcnt = reload;
-            DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
-                       nakcnt);
         }
-        set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+        set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
     }
 
-    /*
-     *  Write the qh back to guest physical memory.  This step isn't
-     *  in the EHCI spec but we need to do it since we don't share
-     *  physical memory with our guest VM.
-     */
-
-    DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
-              ehci->qhaddr, qh->next);
-    put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
-
     /* 4.10.5 */
-    if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
-        *state = EST_HORIZONTALQH;
+    if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
     } else {
-        *state = EST_WRITEBACK;
+        ehci_set_state(q->ehci, async, EST_WRITEBACK);
     }
 
     again = 1;
 
 out:
+    ehci_flush_qh(q);
     return again;
 }
 
 
-static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+static int ehci_state_writeback(EHCIQueue *q, int async)
 {
-    EHCIqh *qh = &ehci->qh;
     int again = 0;
 
     /*  Write back the QTD from the QH area */
-    DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
-    put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
-                sizeof(EHCIqtd) >> 2);
+    ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
+    put_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qh.next_qtd,
+               sizeof(EHCIqtd) >> 2);
 
-    /* TODO confirm next state.  For now, keep going if async
-     * but stop after one qtd if periodic
+    /*
+     * EHCI specs say go horizontal here.
+     *
+     * We can also advance the queue here for performance reasons.  We
+     * need to take care to only take that shortcut in case we've
+     * processed the qtd just written back without errors, i.e. halt
+     * bit is clear.
      */
-    //if (async) {
-        *state = EST_ADVANCEQUEUE;
+    if (q->qh.token & QTD_TOKEN_HALT) {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
         again = 1;
-    //} else {
-    //    *state = EST_ACTIVE;
-    //}
+    } else {
+        ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
+        again = 1;
+    }
     return again;
 }
 
-/* 
- * This is the state machine that is common to both async and periodic 
+/*
+ * This is the state machine that is common to both async and periodic
  */
 
-static int ehci_advance_state(EHCIState *ehci,
-                                int async,
-                                int state)
+static void ehci_advance_state(EHCIState *ehci,
+                               int async)
 {
+    EHCIQueue *q = NULL;
     int again;
     int iter = 0;
 
     do {
-        if (state == EST_FETCHQH) {
+        if (ehci_get_state(ehci, async) == EST_FETCHQH) {
             iter++;
             /* if we are roaming a lot of QH without executing a qTD
              * something is wrong with the linked list. TO-DO: why is
              * this hack needed?
              */
+            assert(iter < MAX_ITERATIONS);
+#if 0
             if (iter > MAX_ITERATIONS) {
                 DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
-                state = EST_ACTIVE;
+                ehci_set_state(ehci, async, EST_ACTIVE);
                 break;
             }
+#endif
         }
-        switch(state) {
+        switch(ehci_get_state(ehci, async)) {
         case EST_WAITLISTHEAD:
-            again = ehci_state_waitlisthead(ehci, async, &state);
+            again = ehci_state_waitlisthead(ehci, async);
             break;
 
         case EST_FETCHENTRY:
-            again = ehci_state_fetchentry(ehci, async, &state);
+            again = ehci_state_fetchentry(ehci, async);
             break;
 
         case EST_FETCHQH:
-            again = ehci_state_fetchqh(ehci, async, &state);
+            q = ehci_state_fetchqh(ehci, async);
+            again = q ? 1 : 0;
             break;
 
         case EST_FETCHITD:
-            again = ehci_state_fetchitd(ehci, async, &state);
+            again = ehci_state_fetchitd(ehci, async);
+            break;
+
+        case EST_FETCHSITD:
+            again = ehci_state_fetchsitd(ehci, async);
             break;
 
         case EST_ADVANCEQUEUE:
-            again = ehci_state_advqueue(ehci, async, &state);
+            again = ehci_state_advqueue(q, async);
             break;
 
         case EST_FETCHQTD:
-            again = ehci_state_fetchqtd(ehci, async, &state);
+            again = ehci_state_fetchqtd(q, async);
             break;
 
         case EST_HORIZONTALQH:
-            again = ehci_state_horizqh(ehci, async, &state);
+            again = ehci_state_horizqh(q, async);
             break;
 
         case EST_EXECUTE:
             iter = 0;
-            again = ehci_state_execute(ehci, async, &state);
+            again = ehci_state_execute(q, async);
             break;
 
         case EST_EXECUTING:
-            again = ehci_state_executing(ehci, async, &state);
+            assert(q != NULL);
+            again = ehci_state_executing(q, async);
             break;
 
         case EST_WRITEBACK:
-            again = ehci_state_writeback(ehci, async, &state);
+            assert(q != NULL);
+            again = ehci_state_writeback(q, async);
             break;
 
         default:
             fprintf(stderr, "Bad state!\n");
             again = -1;
+            assert(0);
             break;
         }
 
@@ -1754,31 +2063,31 @@ static int ehci_advance_state(EHCIState *ehci,
             fprintf(stderr, "processing error - resetting ehci HC\n");
             ehci_reset(ehci);
             again = 0;
+            assert(0);
         }
     }
     while (again);
 
-    return state;
+    ehci_commit_interrupt(ehci);
 }
 
 static void ehci_advance_async_state(EHCIState *ehci)
 {
-    EHCIqh qh;
-    int state = ehci->astate;
+    int async = 1;
 
-    switch(state) {
+    switch(ehci_get_state(ehci, async)) {
     case EST_INACTIVE:
         if (!(ehci->usbcmd & USBCMD_ASE)) {
             break;
         }
-        ehci->usbsts |= USBSTS_ASS;
-        ehci->astate = EST_ACTIVE;
+        ehci_set_usbsts(ehci, USBSTS_ASS);
+        ehci_set_state(ehci, async, EST_ACTIVE);
         // No break, fall through to ACTIVE
 
     case EST_ACTIVE:
         if ( !(ehci->usbcmd & USBCMD_ASE)) {
-            ehci->usbsts &= ~USBSTS_ASS;
-            ehci->astate = EST_INACTIVE;
+            ehci_clear_usbsts(ehci, USBSTS_ASS);
+            ehci_set_state(ehci, async, EST_INACTIVE);
             break;
         }
 
@@ -1800,30 +2109,20 @@ static void ehci_advance_async_state(EHCIState *ehci)
             break;
         }
 
-        DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
-                ehci->asynclistaddr);
         /* check that address register has been set */
         if (ehci->asynclistaddr == 0) {
             break;
         }
 
-        state = EST_WAITLISTHEAD;
-        /* fall through */
-
-    case EST_FETCHENTRY:
-        /* fall through */
-
-    case EST_EXECUTING:
-        get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
-                   sizeof(EHCIqh) >> 2);
-        ehci->astate = ehci_advance_state(ehci, 1, state);
+        ehci_set_state(ehci, async, EST_WAITLISTHEAD);
+        ehci_advance_state(ehci, async);
         break;
 
     default:
         /* this should only be due to a developer mistake */
         fprintf(stderr, "ehci: Bad asynchronous state %d. "
                 "Resetting to active\n", ehci->astate);
-        ehci->astate = EST_ACTIVE;
+        assert(0);
     }
 }
 
@@ -1831,24 +2130,23 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
 {
     uint32_t entry;
     uint32_t list;
+    int async = 0;
 
     // 4.6
 
-    switch(ehci->pstate) {
+    switch(ehci_get_state(ehci, async)) {
     case EST_INACTIVE:
         if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
-            DPRINTF("PERIODIC going active\n");
-            ehci->usbsts |= USBSTS_PSS;
-            ehci->pstate = EST_ACTIVE;
+            ehci_set_usbsts(ehci, USBSTS_PSS);
+            ehci_set_state(ehci, async, EST_ACTIVE);
             // No break, fall through to ACTIVE
         } else
             break;
 
     case EST_ACTIVE:
         if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
-            DPRINTF("PERIODIC going inactive\n");
-            ehci->usbsts &= ~USBSTS_PSS;
-            ehci->pstate = EST_INACTIVE;
+            ehci_clear_usbsts(ehci, USBSTS_PSS);
+            ehci_set_state(ehci, async, EST_INACTIVE);
             break;
         }
 
@@ -1859,25 +2157,21 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
         }
         list |= ((ehci->frindex & 0x1ff8) >> 1);
 
-        cpu_physical_memory_rw(list, (uint8_t *) &entry, sizeof entry, 0);
+        pci_dma_read(&ehci->dev, list, (uint8_t *) &entry, sizeof entry);
         entry = le32_to_cpu(entry);
 
         DPRINTF("PERIODIC state adv fr=%d.  [%08X] -> %08X\n",
                 ehci->frindex / 8, list, entry);
-        ehci->fetch_addr = entry;
-        ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
-        break;
-
-    case EST_EXECUTING:
-        DPRINTF("PERIODIC state adv for executing\n");
-        ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
+        ehci_set_fetch_addr(ehci, async,entry);
+        ehci_set_state(ehci, async, EST_FETCHENTRY);
+        ehci_advance_state(ehci, async);
         break;
 
     default:
         /* this should only be due to a developer mistake */
         fprintf(stderr, "ehci: Bad periodic state %d. "
                 "Resetting to active\n", ehci->pstate);
-        ehci->pstate = EST_ACTIVE;
+        assert(0);
     }
 }
 
@@ -1885,31 +2179,21 @@ static void ehci_frame_timer(void *opaque)
 {
     EHCIState *ehci = opaque;
     int64_t expire_time, t_now;
-    int usec_elapsed;
+    uint64_t ns_elapsed;
     int frames;
-    int usec_now;
     int i;
     int skipped_frames = 0;
 
+    t_now = qemu_get_clock_ns(vm_clock);
+    expire_time = t_now + (get_ticks_per_sec() / ehci->freq);
 
-    t_now = qemu_get_clock(vm_clock);
-    expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ);
-    if (expire_time == t_now)
-        expire_time++;
+    ns_elapsed = t_now - ehci->last_run_ns;
+    frames = ns_elapsed / FRAME_TIMER_NS;
 
-    usec_now = t_now / 1000;
-    usec_elapsed = usec_now - ehci->last_run_usec;
-    frames = usec_elapsed / FRAME_TIMER_USEC;
-    ehci->frame_end_usec = usec_now + FRAME_TIMER_USEC - 10;
-
-    for(i = 0; i < frames; i++) {
+    for (i = 0; i < frames; i++) {
         if ( !(ehci->usbsts & USBSTS_HALT)) {
             if (ehci->isoch_pause <= 0) {
-#ifdef EHCI_NOMICROFRAMES
                 ehci->frindex += 8;
-#else
-                ehci->frindex++;
-#endif
             }
 
             if (ehci->frindex > 0x00001fff) {
@@ -1921,170 +2205,108 @@ static void ehci_frame_timer(void *opaque)
             ehci->sofv &= 0x000003ff;
         }
 
-        if (frames - i > 10)
+        if (frames - i > ehci->maxframes) {
             skipped_frames++;
-        else {
-            // TODO could this cause periodic frames to get skipped if async
-            // active?
-            if (ehci->astate != EST_EXECUTING)
-                ehci_advance_periodic_state(ehci);
+        } else {
+            ehci_advance_periodic_state(ehci);
         }
 
-        ehci->last_run_usec += FRAME_TIMER_USEC;
+        ehci->last_run_ns += FRAME_TIMER_NS;
     }
 
 #if 0
-    if (skipped_frames)
+    if (skipped_frames) {
         DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames);
+    }
 #endif
 
     /*  Async is not inside loop since it executes everything it can once
      *  called
      */
-    if (ehci->pstate != EST_EXECUTING)
-        ehci_advance_async_state(ehci);
+    ehci_advance_async_state(ehci);
 
     qemu_mod_timer(ehci->frame_timer, expire_time);
 }
 
-static CPUReadMemoryFunc *ehci_readfn[3]={
-    ehci_mem_readb,
-    ehci_mem_readw,
-    ehci_mem_readl
-};
 
-static CPUWriteMemoryFunc *ehci_writefn[3]={
-    ehci_mem_writeb,
-    ehci_mem_writew,
-    ehci_mem_writel
+static const MemoryRegionOps ehci_mem_ops = {
+    .old_mmio = {
+        .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
+        .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void usb_ehci_save(QEMUFile *f, void *opaque)
-{
-    USBPort   *ports = (USBPort *)opaque;
-    EHCIState *port_info;
-    uint32_t  portsc;
-    int i;
-
-    for (i = 0; i < NB_PORTS; i++) {
-        port_info = ports[i].opaque;
-        portsc    = port_info->portsc[ports[i].index];
-        if (portsc & PORTSC_CONNECT) {
-            hw_error("usb-ehci: some device is attached to usb-port. "
-                     "SaveVM is not possible\n");
-        }
-    }
-}
-
-static int usb_ehci_load(QEMUFile *f, void *opaque, int version_id)
-{
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static void usb_ehci_init(EHCIState *s, DeviceState *dev, qemu_irq irq)
-{
-    int i;
-
-    fprintf(stderr, "\n\n*** EHCI support is under development *** \n\n");
-    s->irq = irq;
-
-    // 2.2 host controller interface version
-    s->mmio[0x00] = (uint8_t) OPREGBASE;
-    s->mmio[0x01] = 0x00;
-    s->mmio[0x02] = 0x00;
-    s->mmio[0x03] = 0x01;        // HC version
-    s->mmio[0x04] = NB_PORTS;    // Number of downstream ports
-    s->mmio[0x05] = 0x00;        // No companion ports at present
-    s->mmio[0x06] = 0x00;
-    s->mmio[0x07] = 0x00;
-    s->mmio[0x08] = 0x80;        // We can cache whole frame, not 64-bit capable
-    s->mmio[0x09] = 0x68;        // EECP
-    s->mmio[0x0a] = 0x00;
-    s->mmio[0x0b] = 0x00;
-
-    // TODO - port registration is going to need an overhaul since ports
-    // can be low, full or high speed and are not tied to UHCI or EHCI.
-    // This works for now since we register last so are top of the free
-    // list but really all ports need to be owned by EHCI and it should
-    // hand off to companion controllers if device is full or low speed.
-
-    DPRINTF("ehci_init : registering USB ports with no device attached\n");
-
-    // TODO come up with a better port allocation scheme
-    // added ehci->bus, need to find ehci->DeviceState
-    usb_bus_new(&s->bus, dev);
-    for (i = 0; i < NB_PORTS; i++) {
-        usb_register_port(&s->bus, &s->ports[i], s, i, ehci_attach, 
-                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-        s->ports[i].dev = 0;
-    }
-
-    s->frame_timer = qemu_new_timer(vm_clock, ehci_frame_timer, s);
-
-    DPRINTF("ehci_init: calling ehci_reset\n");
-    qemu_register_reset(ehci_reset, s);
-
-    s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s, DEVICE_NATIVE_ENDIAN);
+static int usb_ehci_initfn(PCIDevice *dev);
 
-    register_savevm(dev, "usb-ehci", -1, 1,
-                    usb_ehci_save, usb_ehci_load, s->ports);
-}
-
-typedef struct {
-    PCIDevice dev;
-    EHCIState state;
-} EHCIPCIState;
+static USBPortOps ehci_port_ops = {
+    .attach = ehci_attach,
+    .detach = ehci_detach,
+    .child_detach = ehci_child_detach,
+    .wakeup = ehci_wakeup,
+    .complete = ehci_async_complete_packet,
+};
 
-static void ehci_map(PCIDevice *pci_dev, int region_num,
-                     pcibus_t addr, pcibus_t size, int type)
-{
-    EHCIPCIState *s = (EHCIPCIState *)pci_dev;
+static USBBusOps ehci_bus_ops = {
+    .register_companion = ehci_register_companion,
+};
 
-    DPRINTF("ehci_map: region %d, addr %08llX, size %lld, s->mem %08X\n",
-            region_num, addr, size, s->state.mem);
-    s->state.mem_base = addr;
-    cpu_register_physical_memory(addr, size, s->state.mem);
-}
+static const VMStateDescription vmstate_ehci = {
+    .name = "ehci",
+    .unmigratable = 1,
+};
 
-static int usb_ehci_initfn_pci(PCIDevice *dev);
+static Property ehci_properties[] = {
+    DEFINE_PROP_UINT32("freq",      EHCIState, freq, FRAME_TIMER_FREQ),
+    DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
+    DEFINE_PROP_END_OF_LIST(),
+};
 
 static PCIDeviceInfo ehci_info[] = {
     {
-        .qdev.name    = "pci-ehci",
-        .qdev.size    = sizeof(EHCIPCIState),
-        .init         = usb_ehci_initfn_pci,
+        .qdev.name    = "usb-ehci",
+        .qdev.size    = sizeof(EHCIState),
+        .qdev.vmsd    = &vmstate_ehci,
+        .init         = usb_ehci_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
+        .revision     = 0x10,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = ehci_properties,
+    },{
+        .qdev.name    = "ich9-usb-ehci1",
+        .qdev.size    = sizeof(EHCIState),
+        .qdev.vmsd    = &vmstate_ehci,
+        .init         = usb_ehci_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = ehci_properties,
     },{
         /* end of list */
     }
 };
 
-static int usb_ehci_initfn_pci(PCIDevice *dev)
+static int usb_ehci_initfn(PCIDevice *dev)
 {
-    EHCIPCIState *s = DO_UPCAST(EHCIPCIState, dev, dev);
+    EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
+    int i;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82801D);
-    pci_set_byte(&pci_conf[PCI_REVISION_ID], 0x10);
     pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-    pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
-    pci_set_byte(&pci_conf[PCI_HEADER_TYPE], PCI_HEADER_TYPE_NORMAL);
 
     /* capabilities pointer */
     pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
     //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
 
-    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3
+    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
     pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
     pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
 
     // pci_conf[0x50] = 0x01; // power management caps
 
-    pci_set_byte(&pci_conf[0x60], 0x20);  // spec release number (2.1.4)
+    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
     pci_set_byte(&pci_conf[0x61], 0x20);  // frame length adjustment (2.1.5)
     pci_set_word(&pci_conf[0x62], 0x00);  // port wake up capability (2.1.6)
 
@@ -2101,26 +2323,38 @@ static int usb_ehci_initfn_pci(PCIDevice *dev)
     pci_conf[0x6e] = 0x00;
     pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS
 
-    usb_ehci_init(&s->state, &dev->qdev, s->dev.irq[3]);
+    // 2.2 host controller interface version
+    s->mmio[0x00] = (uint8_t) OPREGBASE;
+    s->mmio[0x01] = 0x00;
+    s->mmio[0x02] = 0x00;
+    s->mmio[0x03] = 0x01;        // HC version
+    s->mmio[0x04] = NB_PORTS;    // Number of downstream ports
+    s->mmio[0x05] = 0x00;        // No companion ports at present
+    s->mmio[0x06] = 0x00;
+    s->mmio[0x07] = 0x00;
+    s->mmio[0x08] = 0x80;        // We can cache whole frame, not 64-bit capable
+    s->mmio[0x09] = 0x68;        // EECP
+    s->mmio[0x0a] = 0x00;
+    s->mmio[0x0b] = 0x00;
 
-    DPRINTF("ehci_init: registering MMIO size %d\n", MMIO_SIZE);
-    pci_register_bar(&s->dev, 0, MMIO_SIZE,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, ehci_map);
-    return 0;
-}
+    s->irq = s->dev.irq[3];
 
-typedef struct {
-    SysBusDevice busdev;
-    EHCIState state;
-} EHCISysBusState;
+    usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
+    for(i = 0; i < NB_PORTS; i++) {
+        usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
+                          USB_SPEED_MASK_HIGH);
+        s->ports[i].dev = 0;
+    }
 
-static int usb_ehci_initfn_sysbus(SysBusDevice *dev)
-{
-    EHCISysBusState *s = FROM_SYSBUS(EHCISysBusState, dev);
+    s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
+    QTAILQ_INIT(&s->queues);
+
+    qemu_register_reset(ehci_reset, s);
+
+    memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
 
-    sysbus_init_irq(dev, &s->state.irq);
-    usb_ehci_init(&s->state, &dev->qdev, s->state.irq);
-    sysbus_init_mmio(dev, 0x1000, s->state.mem);
+    fprintf(stderr, "*** EHCI support is under development ***\n");
 
     return 0;
 }
@@ -2128,16 +2362,9 @@ static int usb_ehci_initfn_sysbus(SysBusDevice *dev)
 static void ehci_register(void)
 {
     pci_qdev_register_many(ehci_info);
-    sysbus_register_dev("usb-ehci", sizeof(EHCISysBusState),
-                        usb_ehci_initfn_sysbus);
 }
 device_init(ehci_register);
 
-void usb_ehci_init_pci(PCIBus *bus, int devfn)
-{
-    pci_create_simple(bus, devfn, "pci-ehci");
-}
-
 /*
  * vim: expandtab ts=4
  */
index b559c50be6ed1e95d862900a97fd55e2760a7603..4d1a5d62c6db4313bea32812f193f6bcb98a30a5 100644 (file)
 #include "console.h"
 #include "usb.h"
 #include "usb-desc.h"
-#include "sysemu.h"
+#include "qemu-timer.h"
+#include "hid.h"
+
+#ifdef CONFIG_MARU
+#include "../tizen/src/mloop_event.h"
+#endif
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define USB_MOUSE     1
-#define USB_TABLET    2
-#define USB_KEYBOARD  3
-
-typedef struct USBPointerEvent {
-    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
-    int32_t dz, buttons_state;
-} USBPointerEvent;
-
-#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
-#define QUEUE_MASK      (QUEUE_LENGTH-1u)
-#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
-
-typedef struct USBMouseState {
-    USBPointerEvent queue[QUEUE_LENGTH];
-    int mouse_grabbed;
-    QEMUPutMouseEntry *eh_entry;
-} USBMouseState;
-
-typedef struct USBKeyboardState {
-    uint32_t keycodes[QUEUE_LENGTH];
-    uint16_t modifiers;
-    uint8_t leds;
-    uint8_t key[16];
-    int32_t keys;
-} USBKeyboardState;
-
 typedef struct USBHIDState {
     USBDevice dev;
-    union {
-        USBMouseState ptr;
-        USBKeyboardState kbd;
-    };
-    uint32_t head; /* index into circular queue */
-    uint32_t n;
-    int kind;
-    int32_t protocol;
-    uint8_t idle;
-    int64_t next_idle_clock;
-    int changed;
-    void *datain_opaque;
-    void (*datain)(void *);
+    HIDState hid;
 } USBHIDState;
 
 enum {
@@ -142,7 +108,6 @@ static const USBDescIface desc_iface_tablet = {
     .bInterfaceNumber              = 0,
     .bNumEndpoints                 = 1,
     .bInterfaceClass               = USB_CLASS_HID,
-    .bInterfaceSubClass            = 0x01, /* boot */
     .bInterfaceProtocol            = 0x02,
     .ndesc                         = 1,
     .descs = (USBDescOther[]) {
@@ -211,6 +176,7 @@ static const USBDescDevice desc_device_mouse = {
             .iConfiguration        = STR_CONFIG_MOUSE,
             .bmAttributes          = 0xa0,
             .bMaxPower             = 50,
+            .nif = 1,
             .ifs = &desc_iface_mouse,
         },
     },
@@ -227,6 +193,7 @@ static const USBDescDevice desc_device_tablet = {
             .iConfiguration        = STR_CONFIG_TABLET,
             .bmAttributes          = 0xa0,
             .bMaxPower             = 50,
+            .nif = 1,
             .ifs = &desc_iface_tablet,
         },
     },
@@ -243,6 +210,7 @@ static const USBDescDevice desc_device_keyboard = {
             .iConfiguration        = STR_CONFIG_KEYBOARD,
             .bmAttributes          = 0xa0,
             .bMaxPower             = 50,
+            .nif = 1,
             .ifs = &desc_iface_keyboard,
         },
     },
@@ -392,351 +360,34 @@ static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
     0xc0,              /* End Collection */
 };
 
-#define USB_HID_USAGE_ERROR_ROLLOVER   0x01
-#define USB_HID_USAGE_POSTFAIL         0x02
-#define USB_HID_USAGE_ERROR_UNDEFINED  0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
-static const uint8_t usb_hid_usage_keys[0x100] = {
-    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
-    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
-    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
-    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
-    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
-    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
-    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
-    0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
-    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
-    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
-    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
-    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
-    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
-    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
-    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
-    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static void usb_hid_changed(USBHIDState *hs)
-{
-    hs->changed = 1;
-
-    if (hs->datain)
-        hs->datain(hs->datain_opaque);
-
-    usb_wakeup(&hs->dev);
-}
-
-static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
-    e->xdx = e->ydy = e->dz = 0;
-    e->buttons_state = buttons;
-}
-
-static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
-                                      int x1, int y1, int z1) {
-    if (xyrel) {
-        e->xdx += x1;
-        e->ydy += y1;
-    } else {
-        e->xdx = x1;
-        e->ydy = y1;
-    }
-    e->dz += z1;
-}
-
-static void usb_pointer_event(void *opaque,
-                              int x1, int y1, int z1, int buttons_state)
+static void usb_hid_changed(HIDState *hs)
 {
-    USBHIDState *hs = opaque;
-    USBMouseState *s = &hs->ptr;
-    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
-    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
-
-    /* We combine events where feasible to keep the queue small.  We shouldn't
-     * combine anything with the first event of a particular button state, as
-     * that would change the location of the button state change.  When the
-     * queue is empty, a second event is needed because we don't know if
-     * the first event changed the button state.  */
-    if (hs->n == QUEUE_LENGTH) {
-        /* Queue full.  Discard old button state, combine motion normally.  */
-        s->queue[use_slot].buttons_state = buttons_state;
-    } else if (hs->n < 2 ||
-               s->queue[use_slot].buttons_state != buttons_state ||
-               s->queue[previous_slot].buttons_state != s->queue[use_slot].buttons_state) {
-        /* Cannot or should not combine, so add an empty item to the queue.  */
-        QUEUE_INCR(use_slot);
-        hs->n++;
-        usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
-    }
-    usb_pointer_event_combine(&s->queue[use_slot],
-                              hs->kind == USB_MOUSE,
-                              x1, y1, z1);
-    usb_hid_changed(hs);
-}
+    USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-static void usb_keyboard_event(void *opaque, int keycode)
-{
-    USBHIDState *hs = opaque;
-    USBKeyboardState *s = &hs->kbd;
-    int slot;
-
-    if (hs->n == QUEUE_LENGTH) {
-        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
-        return;
-    }
-    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    s->keycodes[slot] = keycode;
-    usb_hid_changed(hs);
+    usb_wakeup(&us->dev);
 }
 
-static void usb_keyboard_process_keycode(USBHIDState *hs)
+static void usb_hid_handle_reset(USBDevice *dev)
 {
-    USBKeyboardState *s = &hs->kbd;
-    uint8_t hid_code, key;
-    int i, keycode, slot;
-
-    if (hs->n == 0) {
-        return;
-    }
-    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = s->keycodes[slot];
-
-    key = keycode & 0x7f;
-    hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
-    s->modifiers &= ~(1 << 8);
-
-    switch (hid_code) {
-    case 0x00:
-        return;
-
-    case 0xe0:
-        if (s->modifiers & (1 << 9)) {
-            s->modifiers ^= 3 << 8;
-            usb_hid_changed(hs);
-            return;
-        }
-    case 0xe1 ... 0xe7:
-        if (keycode & (1 << 7)) {
-            s->modifiers &= ~(1 << (hid_code & 0x0f));
-            usb_hid_changed(hs);
-            return;
-        }
-    case 0xe8 ... 0xef:
-        s->modifiers |= 1 << (hid_code & 0x0f);
-        usb_hid_changed(hs);
-        return;
-    }
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    if (keycode & (1 << 7)) {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code) {
-                s->key[i] = s->key[-- s->keys];
-                s->key[s->keys] = 0x00;
-                break;
-            }
-        if (i < 0)
-            return;
-    } else {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code)
-                break;
-        if (i < 0) {
-            if (s->keys < sizeof(s->key))
-                s->key[s->keys ++] = hid_code;
-        } else
-            return;
-    }
+    hid_reset(&us->hid);
 }
 
-static inline int int_clamp(int val, int vmin, int vmax)
+static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
-    if (val < vmin)
-        return vmin;
-    else if (val > vmax)
-        return vmax;
-    else
-        return val;
-}
-
-static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
-{
-    int dx, dy, dz, b, l;
-    int index;
-    USBMouseState *s = &hs->ptr;
-    USBPointerEvent *e;
-
-    if (!s->mouse_grabbed) {
-        qemu_activate_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 1;
-    }
-
-    /* When the buffer is empty, return the last event.  Relative
-       movements will all be zero.  */
-    index = (hs->n ? hs->head : hs->head - 1);
-    e = &s->queue[index & QUEUE_MASK];
-
-    if (hs->kind == USB_MOUSE) {
-        dx = int_clamp(e->xdx, -127, 127);
-        dy = int_clamp(e->ydy, -127, 127);
-        e->xdx -= dx;
-        e->ydy -= dy;
-    } else {
-        dx = e->xdx;
-        dy = e->ydy;
-    }
-    dz = int_clamp(e->dz, -127, 127);
-    e->dz -= dz;
-
-    b = 0;
-    if (e->buttons_state & MOUSE_EVENT_LBUTTON)
-        b |= 0x01;
-    if (e->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
-    if (e->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
-
-    if (hs->n &&
-        !e->dz &&
-        (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
-        /* that deals with this event */
-        QUEUE_INCR(hs->head);
-        hs->n--;
-    }
-
-    /* Appears we have to invert the wheel direction */
-    dz = 0 - dz;
-    l = 0;
-    switch (hs->kind) {
-    case USB_MOUSE:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx;
-        if (len > l)
-            buf[l++] = dy;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    case USB_TABLET:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx & 0xff;
-        if (len > l)
-            buf[l++] = dx >> 8;
-        if (len > l)
-            buf[l++] = dy & 0xff;
-        if (len > l)
-            buf[l++] = dy >> 8;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    default:
-        abort();
-    }
-
-    return l;
-}
-
-static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
-{
-    USBKeyboardState *s = &hs->kbd;
-    if (len < 2)
-        return 0;
-
-    usb_keyboard_process_keycode(hs);
-
-    buf[0] = s->modifiers & 0xff;
-    buf[1] = 0;
-    if (s->keys > 6)
-        memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    else
-        memcpy(buf + 2, s->key, MIN(8, len) - 2);
-
-    return MIN(8, len);
-}
-
-static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
-{
-    if (len > 0) {
-        int ledstate = 0;
-        /* 0x01: Num Lock LED
-         * 0x02: Caps Lock LED
-         * 0x04: Scroll Lock LED
-         * 0x08: Compose LED
-         * 0x10: Kana LED */
-        s->leds = buf[0];
-        if (s->leds & 0x04)
-            ledstate |= QEMU_SCROLL_LOCK_LED;
-        if (s->leds & 0x01)
-            ledstate |= QEMU_NUM_LOCK_LED;
-        if (s->leds & 0x02)
-            ledstate |= QEMU_CAPS_LOCK_LED;
-        kbd_put_ledstate(ledstate);
-    }
-    return 0;
-}
-
-static void usb_mouse_handle_reset(USBDevice *dev)
-{
-    USBHIDState *s = (USBHIDState *)dev;
-
-    memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
-    s->head = 0;
-    s->n = 0;
-    s->protocol = 1;
-}
-
-static void usb_keyboard_handle_reset(USBDevice *dev)
-{
-    USBHIDState *s = (USBHIDState *)dev;
-
-    qemu_add_kbd_event_handler(usb_keyboard_event, s);
-    memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
-    s->head = 0;
-    s->n = 0;
-    memset(s->kbd.key, 0, sizeof (s->kbd.key));
-    s->kbd.keys = 0;
-    s->protocol = 1;
-}
-
-static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
-{
-    s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
-}
-
-static int usb_hid_handle_control(USBDevice *dev, int request, int value,
-                                  int index, int length, uint8_t *data)
-{
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
 
     ret = 0;
-    switch(request) {
+    switch (request) {
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -746,17 +397,17 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
         break;
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch(value >> 8) {
+        switch (value >> 8) {
         case 0x22:
-           if (s->kind == USB_MOUSE) {
+            if (hs->kind == HID_MOUSE) {
                memcpy(data, qemu_mouse_hid_report_descriptor,
                       sizeof(qemu_mouse_hid_report_descriptor));
                ret = sizeof(qemu_mouse_hid_report_descriptor);
-           } else if (s->kind == USB_TABLET) {
-               memcpy(data, qemu_tablet_hid_report_descriptor,
+            } else if (hs->kind == HID_TABLET) {
+                memcpy(data, qemu_tablet_hid_report_descriptor,
                       sizeof(qemu_tablet_hid_report_descriptor));
                ret = sizeof(qemu_tablet_hid_report_descriptor);
-            } else if (s->kind == USB_KEYBOARD) {
+            } else if (hs->kind == HID_KEYBOARD) {
                 memcpy(data, qemu_keyboard_hid_report_descriptor,
                        sizeof(qemu_keyboard_hid_report_descriptor));
                 ret = sizeof(qemu_keyboard_hid_report_descriptor);
@@ -767,36 +418,43 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
         }
         break;
     case GET_REPORT:
-        if (s->kind == USB_MOUSE || s->kind == USB_TABLET)
-            ret = usb_pointer_poll(s, data, length);
-        else if (s->kind == USB_KEYBOARD)
-            ret = usb_keyboard_poll(s, data, length);
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            ret = hid_pointer_poll(hs, data, length);
+        } else if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_poll(hs, data, length);
+        }
         break;
     case SET_REPORT:
-        if (s->kind == USB_KEYBOARD)
-            ret = usb_keyboard_write(&s->kbd, data, length);
-        else
+        if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_write(hs, data, length);
+        } else {
             goto fail;
+        }
         break;
     case GET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 1;
-        data[0] = s->protocol;
+        data[0] = hs->protocol;
         break;
     case SET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 0;
-        s->protocol = value;
+        hs->protocol = value;
         break;
     case GET_IDLE:
         ret = 1;
-        data[0] = s->idle;
+        data[0] = hs->idle;
         break;
     case SET_IDLE:
-        s->idle = (uint8_t) (value >> 8);
-        usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
+        hs->idle = (uint8_t) (value >> 8);
+        hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            hid_pointer_activate(hs);
+        }
         ret = 0;
         break;
     default:
@@ -809,23 +467,26 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
 
 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
+    uint8_t buf[p->iov.size];
     int ret = 0;
 
-    switch(p->pid) {
+    switch (p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
-            int64_t curtime = qemu_get_clock(vm_clock);
-            if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
+            int64_t curtime = qemu_get_clock_ns(vm_clock);
+            if (!hid_has_events(hs) &&
+                (!hs->idle || hs->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
-            usb_hid_set_next_idle(s, curtime);
-            if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
-                ret = usb_pointer_poll(s, p->data, p->len);
             }
-            else if (s->kind == USB_KEYBOARD) {
-                ret = usb_keyboard_poll(s, p->data, p->len);
+            hid_set_next_idle(hs, curtime);
+            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+                ret = hid_pointer_poll(hs, buf, p->iov.size);
+            } else if (hs->kind == HID_KEYBOARD) {
+                ret = hid_keyboard_poll(hs, buf, p->iov.size);
             }
-            s->changed = s->n > 0;
+            usb_packet_copy(p, buf, ret);
         } else {
             goto fail;
         }
@@ -841,95 +502,62 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 
 static void usb_hid_handle_destroy(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    switch(s->kind) {
-    case USB_KEYBOARD:
-        qemu_remove_kbd_event_handler();
-        break;
-    default:
-        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+#ifdef CONFIG_MARU
+    if (us->hid.kind == HID_KEYBOARD) {
+        mloop_evcmd_set_usbkbd(NULL);
     }
+#endif
+
+    hid_free(&us->hid);
 }
 
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
-    USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
     usb_desc_init(dev);
-    s->kind = kind;
-
-    if (s->kind == USB_MOUSE) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       0, "QEMU USB Mouse");
-    } else if (s->kind == USB_TABLET) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       1, "QEMU USB Tablet");
-    }
-
-    /* Force poll routine to be run and grab input the first time.  */
-    s->changed = 1;
+    hid_init(&us->hid, kind, usb_hid_changed);
     return 0;
 }
 
 static int usb_tablet_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_TABLET);
+    return usb_hid_initfn(dev, HID_TABLET);
 }
 
 static int usb_mouse_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_MOUSE);
+    return usb_hid_initfn(dev, HID_MOUSE);
 }
 
 static int usb_keyboard_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_KEYBOARD);
+#ifdef CONFIG_MARU
+    mloop_evcmd_set_usbkbd(dev);
+#endif
+    return usb_hid_initfn(dev, HID_KEYBOARD);
 }
 
-void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
-{
-    USBHIDState *s = (USBHIDState *)dev;
-
-    s->datain_opaque = opaque;
-    s->datain = datain;
-}
-
-static int usb_hid_post_load(void *opaque, int version_id)
+static int usb_ptr_post_load(void *opaque, int version_id)
 {
     USBHIDState *s = opaque;
 
-    if (s->idle) {
-        usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
+    if (s->dev.remote_wakeup) {
+        hid_pointer_activate(&s->hid);
     }
     return 0;
 }
 
-static const VMStateDescription vmstate_usb_ptr_queue = {
-    .name = "usb-ptr-queue",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_INT32(xdx, USBPointerEvent),
-        VMSTATE_INT32(ydy, USBPointerEvent),
-        VMSTATE_INT32(dz, USBPointerEvent),
-        VMSTATE_INT32(buttons_state, USBPointerEvent),
-        VMSTATE_END_OF_LIST()
-    }
-};
 static const VMStateDescription vmstate_usb_ptr = {
     .name = "usb-ptr",
     .version_id = 1,
     .minimum_version_id = 1,
-    .post_load = usb_hid_post_load,
+    .post_load = usb_ptr_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_STRUCT_ARRAY(ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
-                             vmstate_usb_ptr_queue, USBPointerEvent),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -938,18 +566,9 @@ static const VMStateDescription vmstate_usb_kbd = {
     .name = "usb-kbd",
     .version_id = 1,
     .minimum_version_id = 1,
-    .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_UINT32_ARRAY(kbd.keycodes, USBHIDState, QUEUE_LENGTH),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
-        VMSTATE_UINT16(kbd.modifiers, USBHIDState),
-        VMSTATE_UINT8(kbd.leds, USBHIDState),
-        VMSTATE_UINT8_ARRAY(kbd.key, USBHIDState, 16),
-        VMSTATE_INT32(kbd.keys, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -964,7 +583,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_tablet,
         .init           = usb_tablet_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -977,7 +596,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_mouse,
         .init           = usb_mouse_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -990,7 +609,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_keyboard,
         .init           = usb_keyboard_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_keyboard_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
index 3dd31ba31f5b574c301464b16edeae04fc83f3e6..e1959372e7629f1b4a619f00c450d4ca351d6d7a 100644 (file)
@@ -119,6 +119,7 @@ static const USBDescDevice desc_device_hub = {
             .bNumInterfaces        = 1,
             .bConfigurationValue   = 1,
             .bmAttributes          = 0xe0,
+            .nif = 1,
             .ifs = &desc_iface_hub,
         },
     },
@@ -126,8 +127,8 @@ static const USBDescDevice desc_device_hub = {
 
 static const USBDesc desc_hub = {
     .id = {
-        .idVendor          = 0,
-        .idProduct         = 0,
+        .idVendor          = 0x0409,
+        .idProduct         = 0x55aa,
         .bcdDevice         = 0x0101,
         .iManufacturer     = STR_MANUFACTURER,
         .iProduct          = STR_PRODUCT,
@@ -137,74 +138,6 @@ static const USBDesc desc_hub = {
     .str  = desc_strings,
 };
 
-static const uint8_t qemu_hub_dev_descriptor[] = {
-       0x12,       /*  u8 bLength; */
-       0x01,       /*  u8 bDescriptorType; Device */
-       0x10, 0x01, /*  u16 bcdUSB; v1.1 */
-
-       0x09,       /*  u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,       /*  u8  bDeviceSubClass; */
-       0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
-       0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
-
-       0x00, 0x00, /*  u16 idVendor; */
-       0x00, 0x00, /*  u16 idProduct; */
-       0x01, 0x01, /*  u16 bcdDevice */
-
-       0x03,       /*  u8  iManufacturer; */
-       0x02,       /*  u8  iProduct; */
-       0x01,       /*  u8  iSerialNumber; */
-       0x01        /*  u8  bNumConfigurations; */
-};
-
-/* XXX: patch interrupt size */
-static const uint8_t qemu_hub_config_descriptor[] = {
-
-       /* one configuration */
-       0x09,       /*  u8  bLength; */
-       0x02,       /*  u8  bDescriptorType; Configuration */
-       0x19, 0x00, /*  u16 wTotalLength; */
-       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 */
-       0x00,       /*  u8  MaxPower; */
-
-       /* USB 1.1:
-        * USB 2.0, single TT organization (mandatory):
-        *      one interface, protocol 0
-        *
-        * USB 2.0, multiple TT organization (optional):
-        *      two interfaces, protocols 1 (like single TT)
-        *      and 2 (multiple TT mode) ... config is
-        *      sometimes settable
-        *      NOT IMPLEMENTED
-        */
-
-       /* one interface */
-       0x09,       /*  u8  if_bLength; */
-       0x04,       /*  u8  if_bDescriptorType; Interface */
-       0x00,       /*  u8  if_bInterfaceNumber; */
-       0x00,       /*  u8  if_bAlternateSetting; */
-       0x01,       /*  u8  if_bNumEndpoints; */
-       0x09,       /*  u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,       /*  u8  if_bInterfaceSubClass; */
-       0x00,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
-       0x00,       /*  u8  if_iInterface; */
-
-       /* one endpoint (status change endpoint) */
-       0x07,       /*  u8  ep_bLength; */
-       0x05,       /*  u8  ep_bDescriptorType; Endpoint */
-       0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,       /*  u8  ep_bmAttributes; Interrupt */
-       0x02, 0x00, /*  u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
-       0xff        /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
-};
-
 static const uint8_t qemu_hub_hub_descriptor[] =
 {
        0x00,                   /*  u8  bLength; patched in later */
@@ -230,6 +163,7 @@ static void usb_hub_attach(USBPort *port1)
     } else {
         port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
     }
+    usb_wakeup(&s->dev);
 }
 
 static void usb_hub_detach(USBPort *port1)
@@ -237,6 +171,11 @@ static void usb_hub_detach(USBPort *port1)
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
+    usb_wakeup(&s->dev);
+
+    /* Let upstream know the device on this port is gone */
+    s->dev.port->ops->child_detach(s->dev.port, port1->dev);
+
     port->wPortStatus &= ~PORT_STAT_CONNECTION;
     port->wPortChange |= PORT_STAT_C_CONNECTION;
     if (port->wPortStatus & PORT_STAT_ENABLE) {
@@ -245,10 +184,18 @@ static void usb_hub_detach(USBPort *port1)
     }
 }
 
-static void usb_hub_wakeup(USBDevice *dev)
+static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
+{
+    USBHubState *s = port1->opaque;
+
+    /* Pass along upstream */
+    s->dev.port->ops->child_detach(s->dev.port, child);
+}
+
+static void usb_hub_wakeup(USBPort *port1)
 {
-    USBHubState *s = dev->port->opaque;
-    USBHubPort *port = &s->ports[dev->port->index];
+    USBHubState *s = port1->opaque;
+    USBHubPort *port = &s->ports[port1->index];
 
     if (port->wPortStatus & PORT_STAT_SUSPEND) {
         port->wPortChange |= PORT_STAT_C_SUSPEND;
@@ -256,28 +203,50 @@ static void usb_hub_wakeup(USBDevice *dev)
     }
 }
 
-static void usb_hub_handle_attach(USBDevice *dev)
+static void usb_hub_complete(USBPort *port, USBPacket *packet)
+{
+    USBHubState *s = port->opaque;
+
+    /*
+     * Just pass it along upstream for now.
+     *
+     * If we ever implement usb 2.0 split transactions this will
+     * become a little more complicated ...
+     *
+     * Can't use usb_packet_complete() here because packet->owner is
+     * cleared already, go call the ->complete() callback directly
+     * instead.
+     */
+    s->dev.port->ops->complete(s->dev.port, packet);
+}
+
+static void usb_hub_handle_reset(USBDevice *dev)
 {
     USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+    USBHubPort *port;
     int i;
 
     for (i = 0; i < NUM_PORTS; i++) {
-        usb_port_location(&s->ports[i].port, dev->port, i+1);
+        port = s->ports + i;
+        port->wPortStatus = PORT_STAT_POWER;
+        port->wPortChange = 0;
+        if (port->port.dev && port->port.dev->attached) {
+            port->wPortStatus |= PORT_STAT_CONNECTION;
+            port->wPortChange |= PORT_STAT_C_CONNECTION;
+            if (port->port.dev->speed == USB_SPEED_LOW) {
+                port->wPortStatus |= PORT_STAT_LOW_SPEED;
+            }
+        }
     }
 }
 
-static void usb_hub_handle_reset(USBDevice *dev)
-{
-    /* XXX: do it */
-}
-
-static int usb_hub_handle_control(USBDevice *dev, int request, int value,
-                                  int index, int length, uint8_t *data)
+static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     USBHubState *s = (USBHubState *)dev;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
@@ -342,7 +311,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
                 port->wPortStatus |= PORT_STAT_SUSPEND;
                 break;
             case PORT_RESET:
-                if (dev) {
+                if (dev && dev->attached) {
                     usb_send_msg(dev, USB_MSG_RESET);
                     port->wPortChange |= PORT_STAT_C_RESET;
                     /* set enable bit */
@@ -437,11 +406,12 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
         if (p->devep == 1) {
             USBHubPort *port;
             unsigned int status;
+            uint8_t buf[4];
             int i, n;
             n = (NUM_PORTS + 1 + 7) / 8;
-            if (p->len == 1) { /* FreeBSD workaround */
+            if (p->iov.size == 1) { /* FreeBSD workaround */
                 n = 1;
-            } else if (n > p->len) {
+            } else if (n > p->iov.size) {
                 return USB_RET_BABBLE;
             }
             status = 0;
@@ -452,8 +422,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
             }
             if (status != 0) {
                 for(i = 0; i < n; i++) {
-                    p->data[i] = status >> (8 * i);
+                    buf[i] = status >> (8 * i);
                 }
+                usb_packet_copy(p, buf, n);
                 ret = n;
             } else {
                 ret = USB_RET_NAK; /* usb11 11.13.1 */
@@ -480,8 +451,8 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
     for(i = 0; i < NUM_PORTS; i++) {
         port = &s->ports[i];
         dev = port->port.dev;
-        if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
-            ret = dev->info->handle_packet(dev, p);
+        if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) {
+            ret = usb_handle_packet(dev, p);
             if (ret != USB_RET_NODEV) {
                 return ret;
             }
@@ -523,7 +494,9 @@ static void usb_hub_handle_destroy(USBDevice *dev)
 static USBPortOps usb_hub_port_ops = {
     .attach = usb_hub_attach,
     .detach = usb_hub_detach,
+    .child_detach = usb_hub_child_detach,
     .wakeup = usb_hub_wakeup,
+    .complete = usb_hub_complete,
 };
 
 static int usb_hub_initfn(USBDevice *dev)
@@ -538,9 +511,9 @@ static int usb_hub_initfn(USBDevice *dev)
         usb_register_port(usb_bus_from_device(dev),
                           &port->port, s, i, &usb_hub_port_ops,
                           USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-        port->wPortStatus = PORT_STAT_POWER;
-        port->wPortChange = 0;
+        usb_port_location(&port->port, dev->port, i+1);
     }
+    usb_hub_handle_reset(dev);
     return 0;
 }
 
@@ -576,7 +549,6 @@ static struct USBDeviceInfo hub_info = {
     .usb_desc       = &desc_hub,
     .init           = usb_hub_initfn,
     .handle_packet  = usb_hub_handle_packet,
-    .handle_attach  = usb_hub_handle_attach,
     .handle_reset   = usb_hub_handle_reset,
     .handle_control = usb_hub_handle_control,
     .handle_data    = usb_hub_handle_data,
diff --git a/hw/usb-libhw.c b/hw/usb-libhw.c
new file mode 100644 (file)
index 0000000..162b42b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * QEMU USB emulation, libhw bits.
+ *
+ * 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 "cpu-common.h"
+#include "usb.h"
+#include "dma.h"
+
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
+{
+    int is_write = (p->pid == USB_TOKEN_IN);
+    target_phys_addr_t len;
+    void *mem;
+    int i;
+
+    for (i = 0; i < sgl->nsg; i++) {
+        len = sgl->sg[i].len;
+        mem = cpu_physical_memory_map(sgl->sg[i].base, &len,
+                                      is_write);
+        if (!mem) {
+            goto err;
+        }
+        qemu_iovec_add(&p->iov, mem, len);
+        if (len != sgl->sg[i].len) {
+            goto err;
+        }
+    }
+    return 0;
+
+err:
+    usb_packet_unmap(p);
+    return -1;
+}
+
+void usb_packet_unmap(USBPacket *p)
+{
+    int is_write = (p->pid == USB_TOKEN_IN);
+    int i;
+
+    for (i = 0; i < p->iov.niov; i++) {
+        cpu_physical_memory_unmap(p->iov.iov[i].iov_base,
+                                  p->iov.iov[i].iov_len, is_write,
+                                  p->iov.iov[i].iov_len);
+    }
+}
index 76f5b027b2d277517ef2f5ec8d8f7b0a117efd31..8162ded7c9c00c7c0e2a06d3240b19dfc576cf1f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 #include "qemu-common.h"
 #include "sysemu.h"
 #include "blockdev.h"
 
+#ifdef CONFIG_MARU
+#include "../tizen/src/mloop_event.h"
+#endif
+
 //#define DEBUG_MSD
 
 #ifdef DEBUG_MSD
@@ -33,26 +37,32 @@ 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.  */
 };
 
+struct usb_msd_csw {
+    uint32_t sig;
+    uint32_t tag;
+    uint32_t residue;
+    uint8_t status;
+};
+
 typedef struct {
     USBDevice dev;
     enum USBMSDMode mode;
     uint32_t scsi_len;
     uint8_t *scsi_buf;
-    uint32_t usb_len;
-    uint8_t *usb_buf;
     uint32_t data_len;
     uint32_t residue;
-    uint32_t tag;
+    struct usb_msd_csw csw;
+    SCSIRequest *req;
     SCSIBus bus;
     BlockConf conf;
+    char *serial;
     SCSIDevice *scsi_dev;
     uint32_t removable;
-    int result;
     /* For async completion.  */
     USBPacket *packet;
 } MSDState;
@@ -67,13 +77,6 @@ struct usb_msd_cbw {
     uint8_t cmd[16];
 };
 
-struct usb_msd_csw {
-    uint32_t sig;
-    uint32_t tag;
-    uint32_t residue;
-    uint8_t status;
-};
-
 enum {
     STR_MANUFACTURER = 1,
     STR_PRODUCT,
@@ -119,6 +122,7 @@ static const USBDescDevice desc_device_full = {
             .bConfigurationValue   = 1,
             .iConfiguration        = STR_CONFIG_FULL,
             .bmAttributes          = 0xc0,
+            .nif = 1,
             .ifs = &desc_iface_full,
         },
     },
@@ -153,6 +157,7 @@ static const USBDescDevice desc_device_high = {
             .bConfigurationValue   = 1,
             .iConfiguration        = STR_CONFIG_HIGH,
             .bmAttributes          = 0xc0,
+            .nif = 1,
             .ifs = &desc_iface_high,
         },
     },
@@ -160,8 +165,8 @@ static const USBDescDevice desc_device_high = {
 
 static const USBDesc desc = {
     .id = {
-        .idVendor          = 0,
-        .idProduct         = 0,
+        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
+        .idProduct         = 0x0001,
         .bcdDevice         = 0,
         .iManufacturer     = STR_MANUFACTURER,
         .iProduct          = STR_PRODUCT,
@@ -172,93 +177,103 @@ static const USBDesc desc = {
     .str  = desc_strings,
 };
 
-static void usb_msd_copy_data(MSDState *s)
+static void usb_msd_copy_data(MSDState *s, USBPacket *p)
 {
     uint32_t len;
-    len = s->usb_len;
+    len = p->iov.size - p->result;
     if (len > s->scsi_len)
         len = s->scsi_len;
-    if (s->mode == USB_MSDM_DATAIN) {
-        memcpy(s->usb_buf, s->scsi_buf, len);
-    } else {
-        memcpy(s->scsi_buf, s->usb_buf, len);
-    }
-    s->usb_len -= len;
+    usb_packet_copy(p, s->scsi_buf, len);
     s->scsi_len -= len;
-    s->usb_buf += len;
     s->scsi_buf += len;
     s->data_len -= len;
     if (s->scsi_len == 0 || s->data_len == 0) {
-        if (s->mode == USB_MSDM_DATAIN) {
-            s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
-        } else if (s->mode == USB_MSDM_DATAOUT) {
-            s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
-        }
+        scsi_req_continue(s->req);
     }
 }
 
 static void usb_msd_send_status(MSDState *s, USBPacket *p)
 {
-    struct usb_msd_csw csw;
     int len;
 
-    csw.sig = cpu_to_le32(0x53425355);
-    csw.tag = cpu_to_le32(s->tag);
-    csw.residue = s->residue;
-    csw.status = s->result;
+    DPRINTF("Command status %d tag 0x%x, len %zd\n",
+            s->csw.status, s->csw.tag, p->iov.size);
 
-    len = MIN(sizeof(csw), p->len);
-    memcpy(p->data, &csw, len);
+    assert(s->csw.sig == 0x53425355);
+    len = MIN(sizeof(s->csw), p->iov.size);
+    usb_packet_copy(p, &s->csw, len);
+    memset(&s->csw, 0, sizeof(s->csw));
 }
 
-static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
-                                     uint32_t arg)
+static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
 {
-    MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent);
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
     USBPacket *p = s->packet;
 
-    if (tag != s->tag) {
-        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag);
-    }
-    if (reason == SCSI_REASON_DONE) {
-        DPRINTF("Command complete %d\n", arg);
-        s->residue = s->data_len;
-        s->result = arg != 0;
-        if (s->packet) {
-            if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
-                /* A deferred packet with no write data remaining must be
-                   the status read packet.  */
-                usb_msd_send_status(s, p);
-                s->mode = USB_MSDM_CBW;
-            } else {
-                if (s->data_len) {
-                    s->data_len -= s->usb_len;
-                    if (s->mode == USB_MSDM_DATAIN)
-                        memset(s->usb_buf, 0, s->usb_len);
-                    s->usb_len = 0;
-                }
-                if (s->data_len == 0)
-                    s->mode = USB_MSDM_CSW;
-            }
-            s->packet = NULL;
-            usb_packet_complete(p);
-        } else if (s->data_len == 0) {
-            s->mode = USB_MSDM_CSW;
-        }
-        return;
-    }
-    s->scsi_len = arg;
-    s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag);
+    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
+    s->scsi_len = len;
+    s->scsi_buf = scsi_req_get_buf(req);
     if (p) {
-        usb_msd_copy_data(s);
-        if (s->usb_len == 0) {
+        usb_msd_copy_data(s, p);
+        p = s->packet;
+        if (p && p->result == p->iov.size) {
             /* 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;
-            usb_packet_complete(p);
+            usb_packet_complete(&s->dev, p);
+        }
+    }
+}
+
+static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+    USBPacket *p = s->packet;
+
+    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
+    s->residue = s->data_len;
+
+    s->csw.sig = cpu_to_le32(0x53425355);
+    s->csw.tag = cpu_to_le32(req->tag);
+    s->csw.residue = s->residue;
+    s->csw.status = status != 0;
+
+    if (s->packet) {
+        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
+            /* A deferred packet with no write data remaining must be
+               the status read packet.  */
+            usb_msd_send_status(s, p);
+            s->mode = USB_MSDM_CBW;
+        } else {
+            if (s->data_len) {
+                int len = (p->iov.size - p->result);
+                usb_packet_skip(p, len);
+                s->data_len -= len;
+            }
+            if (s->data_len == 0) {
+                s->mode = USB_MSDM_CSW;
+            }
         }
+        s->packet = NULL;
+        usb_packet_complete(&s->dev, p);
+    } else if (s->data_len == 0) {
+        s->mode = USB_MSDM_CSW;
+    }
+    scsi_req_unref(req);
+    s->req = NULL;
+}
+
+static void usb_msd_request_cancelled(SCSIRequest *req)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+
+    if (req == s->req) {
+        scsi_req_unref(s->req);
+        s->req = NULL;
+        s->packet = NULL;
+        s->scsi_len = 0;
     }
 }
 
@@ -267,16 +282,28 @@ static void usb_msd_handle_reset(USBDevice *dev)
     MSDState *s = (MSDState *)dev;
 
     DPRINTF("Reset\n");
+    if (s->req) {
+        scsi_req_cancel(s->req);
+    }
+    assert(s->req == NULL);
+
+    if (s->packet) {
+        USBPacket *p = s->packet;
+        s->packet = NULL;
+        p->result = USB_RET_STALL;
+        usb_packet_complete(dev, p);
+    }
+
     s->mode = USB_MSDM_CBW;
 }
 
-static int usb_msd_handle_control(USBDevice *dev, int request, int value,
-                                  int index, int length, uint8_t *data)
+static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     MSDState *s = (MSDState *)dev;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
@@ -313,22 +340,22 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
     return ret;
 }
 
-static void usb_msd_cancel_io(USBPacket *p, void *opaque)
+static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
 {
-    MSDState *s = opaque;
-    s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag);
-    s->packet = NULL;
-    s->scsi_len = 0;
+    MSDState *s = DO_UPCAST(MSDState, dev, dev);
+
+    if (s->req) {
+        scsi_req_cancel(s->req);
+    }
 }
 
 static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 {
     MSDState *s = (MSDState *)dev;
+    uint32_t tag;
     int ret = 0;
     struct usb_msd_cbw cbw;
     uint8_t devep = p->devep;
-    uint8_t *data = p->data;
-    int len = p->len;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
@@ -337,11 +364,11 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 
         switch (s->mode) {
         case USB_MSDM_CBW:
-            if (len != 31) {
+            if (p->iov.size != 31) {
                 fprintf(stderr, "usb-msd: Bad CBW size");
                 goto fail;
             }
-            memcpy(&cbw, data, 31);
+            usb_packet_copy(p, &cbw, 31);
             if (le32_to_cpu(cbw.sig) != 0x43425355) {
                 fprintf(stderr, "usb-msd: Bad signature %08x\n",
                         le32_to_cpu(cbw.sig));
@@ -352,7 +379,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
                 goto fail;
             }
-            s->tag = le32_to_cpu(cbw.tag);
+            tag = le32_to_cpu(cbw.tag);
             s->data_len = le32_to_cpu(cbw.data_len);
             if (s->data_len == 0) {
                 s->mode = USB_MSDM_CSW;
@@ -362,49 +389,47 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 s->mode = USB_MSDM_DATAOUT;
             }
             DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
-                    s->tag, cbw.flags, cbw.cmd_len, s->data_len);
+                    tag, cbw.flags, cbw.cmd_len, s->data_len);
             s->residue = 0;
-            s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
-            /* ??? Should check that USB and SCSI data transfer
-               directions match.  */
-            if (s->residue == 0) {
-                if (s->mode == USB_MSDM_DATAIN) {
-                    s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
-                } else if (s->mode == USB_MSDM_DATAOUT) {
-                    s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
-                }
+            s->scsi_len = 0;
+            s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
+            scsi_req_enqueue(s->req);
+            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
+                scsi_req_continue(s->req);
             }
-            ret = len;
+            ret = p->result;
             break;
 
         case USB_MSDM_DATAOUT:
-            DPRINTF("Data out %d/%d\n", len, s->data_len);
-            if (len > s->data_len)
+            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
+            if (p->iov.size > s->data_len) {
                 goto fail;
+            }
 
-            s->usb_buf = data;
-            s->usb_len = len;
             if (s->scsi_len) {
-                usb_msd_copy_data(s);
+                usb_msd_copy_data(s, p);
             }
-            if (s->residue && s->usb_len) {
-                s->data_len -= s->usb_len;
-                if (s->data_len == 0)
-                    s->mode = USB_MSDM_CSW;
-                s->usb_len = 0;
+            if (s->residue) {
+                int len = p->iov.size - p->result;
+                if (len) {
+                    usb_packet_skip(p, len);
+                    s->data_len -= len;
+                    if (s->data_len == 0) {
+                        s->mode = USB_MSDM_CSW;
+                    }
+                }
             }
-            if (s->usb_len) {
+            if (p->result < p->iov.size) {
                 DPRINTF("Deferring packet %p\n", p);
-                usb_defer_packet(p, usb_msd_cancel_io, s);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
-                ret = len;
+                ret = p->result;
             }
             break;
 
         default:
-            DPRINTF("Unexpected write (len %d)\n", len);
+            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
             goto fail;
         }
         break;
@@ -415,53 +440,57 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 
         switch (s->mode) {
         case USB_MSDM_DATAOUT:
-            if (s->data_len != 0 || len < 13)
+            if (s->data_len != 0 || p->iov.size < 13) {
                 goto fail;
+            }
             /* Waiting for SCSI write to complete.  */
-            usb_defer_packet(p, usb_msd_cancel_io, s);
             s->packet = p;
             ret = USB_RET_ASYNC;
             break;
 
         case USB_MSDM_CSW:
-            DPRINTF("Command status %d tag 0x%x, len %d\n",
-                    s->result, s->tag, len);
-            if (len < 13)
+            if (p->iov.size < 13) {
                 goto fail;
+            }
 
-            usb_msd_send_status(s, p);
-            s->mode = USB_MSDM_CBW;
-            ret = 13;
+            if (s->req) {
+                /* still in flight */
+                s->packet = p;
+                ret = USB_RET_ASYNC;
+            } else {
+                usb_msd_send_status(s, p);
+                s->mode = USB_MSDM_CBW;
+                ret = 13;
+            }
             break;
 
         case USB_MSDM_DATAIN:
-            DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
-            if (len > s->data_len)
-                len = s->data_len;
-            s->usb_buf = data;
-            s->usb_len = len;
+            DPRINTF("Data in %zd/%d, scsi_len %d\n",
+                    p->iov.size, s->data_len, s->scsi_len);
             if (s->scsi_len) {
-                usb_msd_copy_data(s);
+                usb_msd_copy_data(s, p);
             }
-            if (s->residue && s->usb_len) {
-                s->data_len -= s->usb_len;
-                memset(s->usb_buf, 0, s->usb_len);
-                if (s->data_len == 0)
-                    s->mode = USB_MSDM_CSW;
-                s->usb_len = 0;
+            if (s->residue) {
+                int len = p->iov.size - p->result;
+                if (len) {
+                    usb_packet_skip(p, len);
+                    s->data_len -= len;
+                    if (s->data_len == 0) {
+                        s->mode = USB_MSDM_CSW;
+                    }
+                }
             }
-            if (s->usb_len) {
+            if (p->result < p->iov.size) {
                 DPRINTF("Deferring packet %p\n", p);
-                usb_defer_packet(p, usb_msd_cancel_io, s);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
-                ret = len;
+                ret = p->result;
             }
             break;
 
         default:
-            DPRINTF("Unexpected read (len %d)\n", len);
+            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
             goto fail;
         }
         break;
@@ -476,16 +505,34 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
+#ifdef CONFIG_MARU
+static void usb_msd_handle_destroy(USBDevice *dev)
+{
+    mloop_evcmd_set_usbdisk(NULL);
+}
+#endif
+
 static void usb_msd_password_cb(void *opaque, int err)
 {
     MSDState *s = opaque;
 
     if (!err)
-        usb_device_attach(&s->dev);
-    else
+        err = usb_device_attach(&s->dev);
+
+    if (err)
         qdev_unplug(&s->dev.qdev);
 }
 
+static const struct SCSIBusInfo usb_msd_scsi_info = {
+    .tcq = false,
+    .max_target = 0,
+    .max_lun = 0,
+
+    .transfer_data = usb_msd_transfer_data,
+    .complete = usb_msd_command_complete,
+    .cancel = usb_msd_request_cancelled
+};
+
 static int usb_msd_initfn(USBDevice *dev)
 {
     MSDState *s = DO_UPCAST(MSDState, dev, dev);
@@ -506,17 +553,24 @@ static int usb_msd_initfn(USBDevice *dev)
      *
      * The hack is probably a bad idea.
      */
-    bdrv_detach(bs, &s->dev.qdev);
+    bdrv_detach_dev(bs, &s->dev.qdev);
     s->conf.bs = NULL;
 
-    dinfo = drive_get_by_blockdev(bs);
-    if (dinfo && dinfo->serial) {
-        usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial);
+    if (!s->serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(bs);
+        if (*dinfo->serial) {
+            s->serial = strdup(dinfo->serial);
+        }
+    }
+    if (s->serial) {
+        usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
     }
 
     usb_desc_init(dev);
-    scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
-    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
+    scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
+    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
+                                            s->conf.bootindex);
     if (!s->scsi_dev) {
         return -1;
     }
@@ -532,7 +586,6 @@ static int usb_msd_initfn(USBDevice *dev)
         }
     }
 
-    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk@0,0");
     return 0;
 }
 
@@ -590,25 +643,46 @@ static USBDevice *usb_msd_init(const char *filename)
     if (qdev_init(&dev->qdev) < 0)
         return NULL;
 
+#ifdef CONFIG_MARU
+    mloop_evcmd_set_usbdisk(dev);
+#endif
+
     return dev;
 }
 
+static const VMStateDescription vmstate_usb_msd = {
+    .name = "usb-storage",
+    .unmigratable = 1, /* FIXME: handle transactions which are in flight */
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_USB_DEVICE(dev, MSDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static struct USBDeviceInfo msd_info = {
     .product_desc   = "QEMU USB MSD",
     .qdev.name      = "usb-storage",
     .qdev.fw_name      = "storage",
     .qdev.size      = sizeof(MSDState),
+    .qdev.vmsd      = &vmstate_usb_msd,
     .usb_desc       = &desc,
     .init           = usb_msd_initfn,
     .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usb_msd_cancel_io,
     .handle_attach  = usb_desc_attach,
     .handle_reset   = usb_msd_handle_reset,
     .handle_control = usb_msd_handle_control,
     .handle_data    = usb_msd_handle_data,
+#ifdef CONFIG_MARU
+    .handle_destroy = usb_msd_handle_destroy,
+#endif
     .usbdevice_name = "disk",
     .usbdevice_init = usb_msd_init,
     .qdev.props     = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+        DEFINE_PROP_STRING("serial", MSDState, serial),
         DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
         DEFINE_PROP_END_OF_LIST(),
     },
index 782cfa22821f65b2635018658584ac04a0c18972..01e2e7c389e136e130d0368dbfdec12305e2fffe 100644 (file)
 
 static void musb_attach(USBPort *port);
 static void musb_detach(USBPort *port);
+static void musb_child_detach(USBPort *port, USBDevice *child);
+static void musb_schedule_cb(USBPort *port, USBPacket *p);
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
 
 static USBPortOps musb_port_ops = {
     .attach = musb_attach,
     .detach = musb_detach,
+    .child_detach = musb_child_detach,
+    .complete = musb_schedule_cb,
 };
 
-typedef struct {
+static USBBusOps musb_bus_ops = {
+};
+
+typedef struct MUSBPacket MUSBPacket;
+typedef struct MUSBEndPoint MUSBEndPoint;
+
+struct MUSBPacket {
+    USBPacket p;
+    MUSBEndPoint *ep;
+    int dir;
+};
+
+struct MUSBEndPoint {
     uint16_t faddr[2];
     uint8_t haddr[2];
     uint8_t hport[2];
@@ -284,7 +301,7 @@ typedef struct {
     int fifolen[2];
     int fifostart[2];
     int fifoaddr[2];
-    USBPacket packey[2];
+    MUSBPacket packey[2];
     int status[2];
     int ext_size[2];
 
@@ -294,10 +311,10 @@ typedef struct {
     MUSBState *musb;
     USBCallback *delayed_cb[2];
     QEMUTimer *intv_timer[2];
-} MUSBEndPoint;
+};
 
 struct MUSBState {
-    qemu_irq *irqs;
+    qemu_irq irqs[musb_irq_max];
     USBBus bus;
     USBPort port;
 
@@ -321,14 +338,14 @@ struct MUSBState {
         /* Duplicating the world since 2008!...  probably we should have 32
          * logical, single endpoints instead.  */
     MUSBEndPoint ep[16];
-} *musb_init(qemu_irq *irqs)
+};
+
+void musb_reset(MUSBState *s)
 {
-    MUSBState *s = qemu_mallocz(sizeof(*s));
     int i;
 
-    s->irqs = irqs;
-
     s->faddr = 0x00;
+    s->devctl = 0;
     s->power = MGC_M_POWER_HSENAB;
     s->tx_intr = 0x0000;
     s->rx_intr = 0x0000;
@@ -338,6 +355,10 @@ struct MUSBState {
     s->mask = 0x06;
     s->idx = 0;
 
+    s->setup_len = 0;
+    s->session = 0;
+    memset(s->buf, 0, sizeof(s->buf));
+
     /* TODO: _DW */
     s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
     for (i = 0; i < 16; i ++) {
@@ -346,12 +367,25 @@ struct MUSBState {
         s->ep[i].maxp[1] = 0x40;
         s->ep[i].musb = s;
         s->ep[i].epnum = i;
+        usb_packet_init(&s->ep[i].packey[0].p);
+        usb_packet_init(&s->ep[i].packey[1].p);
     }
+}
 
-    usb_bus_new(&s->bus, NULL /* FIXME */);
+struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
+{
+    MUSBState *s = g_malloc0(sizeof(*s));
+    int i;
+
+    for (i = 0; i < musb_irq_max; i++) {
+        s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
+    }
+
+    musb_reset(s);
+
+    usb_bus_new(&s->bus, &musb_bus_ops, parent_device);
     usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
                       USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-    usb_port_location(&s->port, NULL, 1);
 
     return s;
 }
@@ -480,29 +514,40 @@ static void musb_detach(USBPort *port)
 {
     MUSBState *s = (MUSBState *) port->opaque;
 
+    musb_async_cancel_device(s, port->dev);
+
     musb_intr_set(s, musb_irq_disconnect, 1);
     musb_session_update(s, 1, s->session);
 }
 
-static inline void musb_cb_tick0(void *opaque)
+static void musb_child_detach(USBPort *port, USBDevice *child)
+{
+    MUSBState *s = (MUSBState *) port->opaque;
+
+    musb_async_cancel_device(s, child);
+}
+
+static void musb_cb_tick0(void *opaque)
 {
     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
 
-    ep->delayed_cb[0](&ep->packey[0], opaque);
+    ep->delayed_cb[0](&ep->packey[0].p, opaque);
 }
 
-static inline void musb_cb_tick1(void *opaque)
+static void musb_cb_tick1(void *opaque)
 {
     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
 
-    ep->delayed_cb[1](&ep->packey[1], opaque);
+    ep->delayed_cb[1](&ep->packey[1].p, opaque);
 }
 
 #define musb_cb_tick   (dir ? musb_cb_tick1 : musb_cb_tick0)
 
-static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
+static void musb_schedule_cb(USBPort *port, USBPacket *packey)
 {
-    MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+    MUSBPacket *p = container_of(packey, MUSBPacket, p);
+    MUSBEndPoint *ep = p->ep;
+    int dir = p->dir;
     int timeout = 0;
 
     if (ep->status[dir] == USB_RET_NAK)
@@ -510,25 +555,15 @@ static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
     else if (ep->interrupt[dir])
         timeout = 8;
     else
-        return musb_cb_tick(opaque);
+        return musb_cb_tick(ep);
 
     if (!ep->intv_timer[dir])
-        ep->intv_timer[dir] = qemu_new_timer(vm_clock, musb_cb_tick, opaque);
+        ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep);
 
-    qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock(vm_clock) +
+    qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) +
                    muldiv64(timeout, get_ticks_per_sec(), 8000));
 }
 
-static void musb_schedule0_cb(USBPacket *packey, void *opaque)
-{
-    return musb_schedule_cb(packey, opaque, 0);
-}
-
-static void musb_schedule1_cb(USBPacket *packey, void *opaque)
-{
-    return musb_schedule_cb(packey, opaque, 1);
-}
-
 static int musb_timeout(int ttype, int speed, int val)
 {
 #if 1
@@ -567,7 +602,7 @@ static int musb_timeout(int ttype, int speed, int val)
     hw_error("bad interval\n");
 }
 
-static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
+static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
                 int epnum, int pid, int len, USBCallback cb, int dir)
 {
     int ret;
@@ -585,19 +620,16 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
                     ep->type[idx] >> 6, ep->interval[idx]);
     ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
     ep->delayed_cb[dir] = cb;
-    cb = dir ? musb_schedule1_cb : musb_schedule0_cb;
 
-    ep->packey[dir].pid = pid;
     /* A wild guess on the FADDR semantics... */
-    ep->packey[dir].devaddr = ep->faddr[idx];
-    ep->packey[dir].devep = ep->type[idx] & 0xf;
-    ep->packey[dir].data = (void *) ep->buf[idx];
-    ep->packey[dir].len = len;
-    ep->packey[dir].complete_cb = cb;
-    ep->packey[dir].complete_opaque = ep;
+    usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
+                     ep->type[idx] & 0xf);
+    usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
+    ep->packey[dir].ep = ep;
+    ep->packey[dir].dir = dir;
 
     if (s->port.dev)
-        ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir]);
+        ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
     else
         ret = USB_RET_NODEV;
 
@@ -607,7 +639,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     }
 
     ep->status[dir] = ret;
-    usb_packet_complete(&ep->packey[dir]);
+    musb_schedule_cb(&s->port, &ep->packey[dir].p);
 }
 
 static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
@@ -720,7 +752,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
 
     if (ep->status[1] == USB_RET_STALL) {
         ep->status[1] = 0;
-        packey->len = 0;
+        packey->result = 0;
 
         ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
         if (!epnum)
@@ -734,7 +766,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
          * Data-errors in Isochronous.  */
         if (ep->interrupt[1])
             return musb_packet(s, ep, epnum, USB_TOKEN_IN,
-                            packey->len, musb_rx_packet_complete, 1);
+                            packey->iov.size, musb_rx_packet_complete, 1);
 
         ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
         if (!epnum)
@@ -759,14 +791,14 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
     /* TODO: check len for over/underruns of an OUT packet?  */
     /* TODO: perhaps make use of e->ext_size[1] here.  */
 
-    packey->len = ep->status[1];
+    packey->result = ep->status[1];
 
     if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
         if (!epnum)
             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
 
-        ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+        ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
         /* In DMA mode: assert DMA request for this EP */
     }
 
@@ -774,6 +806,21 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
     musb_rx_intr_set(s, epnum, 1);
 }
 
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
+{
+    int ep, dir;
+
+    for (ep = 0; ep < 16; ep++) {
+        for (dir = 0; dir < 2; dir++) {
+            if (s->ep[ep].packey[dir].p.owner != dev) {
+                continue;
+            }
+            usb_cancel_packet(&s->ep[ep].packey[dir].p);
+            /* status updates needed here? */
+        }
+    }
+}
+
 static void musb_tx_rdy(MUSBState *s, int epnum)
 {
     MUSBEndPoint *ep = s->ep + epnum;
@@ -821,14 +868,14 @@ static void musb_rx_req(MUSBState *s, int epnum)
 
     /* If we already have a packet, which didn't fit into the
      * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
-    if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
+    if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
                     (ep->fifostart[1]) + ep->rxcount <
-                    ep->packey[1].len) {
+                    ep->packey[1].p.iov.size) {
         TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
         ep->fifostart[1] += ep->rxcount;
         ep->fifolen[1] = 0;
 
-        ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]),
+        ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
                         ep->maxp[1]);
 
         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
@@ -866,10 +913,11 @@ static void musb_rx_req(MUSBState *s, int epnum)
 #ifdef SETUPLEN_HACK
     /* Why should *we* do that instead of Linux?  */
     if (!epnum) {
-        if (ep->packey[0].devaddr == 2)
+        if (ep->packey[0].p.devaddr == 2) {
             total = MIN(s->setup_len, 8);
-        else
+        } else {
             total = MIN(s->setup_len, 64);
+        }
         s->setup_len -= total;
     }
 #endif
index bf51bb38909ded4f9def280cd0663eccec62b6ee..a8b7c8dd76953b10594612b50ba7693ed170ee29 100644 (file)
@@ -29,6 +29,7 @@
 #include "net.h"
 #include "qemu-queue.h"
 #include "sysemu.h"
+#include "iov.h"
 
 /*#define TRAFFIC_DEBUG*/
 /* Thanks to NetChip Technologies for donating this product ID.
@@ -843,7 +844,7 @@ static int rndis_get_response(USBNetState *s, uint8_t *buf)
     QTAILQ_REMOVE(&s->rndis_resp, r, entries);
     ret = r->length;
     memcpy(buf, r->buf, r->length);
-    qemu_free(r);
+    g_free(r);
 
     return ret;
 }
@@ -851,7 +852,7 @@ static int rndis_get_response(USBNetState *s, uint8_t *buf)
 static void *rndis_queue_response(USBNetState *s, unsigned int length)
 {
     struct rndis_response *r =
-            qemu_mallocz(sizeof(struct rndis_response) + length);
+            g_malloc0(sizeof(struct rndis_response) + length);
 
     QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
     r->length = length;
@@ -865,7 +866,7 @@ static void rndis_clear_responsequeue(USBNetState *s)
 
     while ((r = s->rndis_resp.tqh_first)) {
         QTAILQ_REMOVE(&s->rndis_resp, r, entries);
-        qemu_free(r);
+        g_free(r);
     }
 }
 
@@ -1042,13 +1043,13 @@ static void usb_net_handle_reset(USBDevice *dev)
 {
 }
 
-static int usb_net_handle_control(USBDevice *dev, int request, int value,
-                int index, int length, uint8_t *data)
+static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     USBNetState *s = (USBNetState *) dev;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
@@ -1121,28 +1122,23 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
 
 static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
 {
+    le32 buf[2];
     int ret = 8;
 
-    if (p->len < 8)
+    if (p->iov.size < 8) {
         return USB_RET_STALL;
+    }
 
-    ((le32 *) p->data)[0] = cpu_to_le32(1);
-    ((le32 *) p->data)[1] = cpu_to_le32(0);
+    buf[0] = cpu_to_le32(1);
+    buf[1] = cpu_to_le32(0);
+    usb_packet_copy(p, buf, 8);
     if (!s->rndis_resp.tqh_first)
         ret = USB_RET_NAK;
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < ret; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
+            p->iov.size, ret);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
 #endif
 
     return ret;
@@ -1162,9 +1158,10 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
         return ret;
     }
     ret = s->in_len - s->in_ptr;
-    if (ret > p->len)
-        ret = p->len;
-    memcpy(p->data, &s->in_buf[s->in_ptr], ret);
+    if (ret > p->iov.size) {
+        ret = p->iov.size;
+    }
+    usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
     s->in_ptr += ret;
     if (s->in_ptr >= s->in_len &&
                     (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
@@ -1173,17 +1170,8 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
     }
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < ret; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
 #endif
 
     return ret;
@@ -1191,29 +1179,20 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
 
 static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
 {
-    int ret = p->len;
+    int ret = p->iov.size;
     int sz = sizeof(s->out_buf) - s->out_ptr;
     struct rndis_packet_msg_type *msg =
             (struct rndis_packet_msg_type *) s->out_buf;
     uint32_t len;
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: data out len %u\n", p->len);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < p->len; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
 #endif
 
     if (sz > ret)
         sz = ret;
-    memcpy(&s->out_buf[s->out_ptr], p->data, sz);
+    usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
     s->out_ptr += sz;
 
     if (!is_rndis(s)) {
@@ -1277,8 +1256,8 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
     }
     if (ret == USB_RET_STALL)
         fprintf(stderr, "usbnet: failed data transaction: "
-                        "pid 0x%x ep 0x%x len 0x%x\n",
-                        p->pid, p->devep, p->len);
+                        "pid 0x%x ep 0x%x len 0x%zx\n",
+                        p->pid, p->devep, p->iov.size);
     return ret;
 }
 
@@ -1414,11 +1393,17 @@ static USBDevice *usb_net_init(const char *cmdline)
     return dev;
 }
 
+static const VMStateDescription vmstate_usb_net = {
+    .name = "usb-net",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo net_info = {
     .product_desc   = "QEMU USB Network Interface",
     .qdev.name      = "usb-net",
     .qdev.fw_name    = "network",
     .qdev.size      = sizeof(USBNetState),
+    .qdev.vmsd      = &vmstate_usb_net,
     .usb_desc       = &desc_net,
     .init           = usb_net_initfn,
     .handle_packet  = usb_generic_handle_packet,
index 09ea0b6260f02a5b96ebc8337574c5886642572b..c27014a88f41b89bdc86554848893e760eb2b438 100644 (file)
@@ -62,7 +62,7 @@ typedef struct OHCIPort {
 typedef struct {
     USBBus bus;
     qemu_irq irq;
-    int mem;
+    MemoryRegion mem;
     int num_ports;
     const char *name;
 
@@ -124,6 +124,7 @@ struct ohci_hcca {
 };
 
 static void ohci_bus_stop(OHCIState *ohci);
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
 
 /* Bitfields for the first word of an Endpoint Desciptor.  */
 #define OHCI_ED_FA_SHIFT  0
@@ -149,7 +150,7 @@ static void ohci_bus_stop(OHCIState *ohci);
 #define OHCI_TD_DI_SHIFT  21
 #define OHCI_TD_DI_MASK   (7<<OHCI_TD_DI_SHIFT)
 #define OHCI_TD_T0        (1<<24)
-#define OHCI_TD_T1        (1<<24)
+#define OHCI_TD_T1        (1<<25)
 #define OHCI_TD_EC_SHIFT  26
 #define OHCI_TD_EC_MASK   (3<<OHCI_TD_EC_SHIFT)
 #define OHCI_TD_CC_SHIFT  28
@@ -326,6 +327,7 @@ static void ohci_attach(USBPort *port1)
 {
     OHCIState *s = port1->opaque;
     OHCIPort *port = &s->rhport[port1->index];
+    uint32_t old_state = port->ctrl;
 
     /* set connect status */
     port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
@@ -343,6 +345,10 @@ static void ohci_attach(USBPort *port1)
     }
 
     DPRINTF("usb-ohci: Attached port %d\n", port1->index);
+
+    if (old_state != port->ctrl) {
+        ohci_set_interrupt(s, OHCI_INTR_RHSC);
+    }
 }
 
 static void ohci_detach(USBPort *port1)
@@ -351,6 +357,8 @@ static void ohci_detach(USBPort *port1)
     OHCIPort *port = &s->rhport[port1->index];
     uint32_t old_state = port->ctrl;
 
+    ohci_async_cancel_device(s, port1->dev);
+
     /* set connect status */
     if (port->ctrl & OHCI_PORT_CCS) {
         port->ctrl &= ~OHCI_PORT_CCS;
@@ -363,8 +371,41 @@ static void ohci_detach(USBPort *port1)
     }
     DPRINTF("usb-ohci: Detached port %d\n", port1->index);
 
-    if (old_state != port->ctrl)
+    if (old_state != port->ctrl) {
         ohci_set_interrupt(s, OHCI_INTR_RHSC);
+    }
+}
+
+static void ohci_wakeup(USBPort *port1)
+{
+    OHCIState *s = port1->opaque;
+    OHCIPort *port = &s->rhport[port1->index];
+    uint32_t intr = 0;
+    if (port->ctrl & OHCI_PORT_PSS) {
+        DPRINTF("usb-ohci: port %d: wakeup\n", port1->index);
+        port->ctrl |= OHCI_PORT_PSSC;
+        port->ctrl &= ~OHCI_PORT_PSS;
+        intr = OHCI_INTR_RHSC;
+    }
+    /* Note that the controller can be suspended even if this port is not */
+    if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+        DPRINTF("usb-ohci: remote-wakeup: SUSPEND->RESUME\n");
+        /* This is the one state transition the controller can do by itself */
+        s->ctl &= ~OHCI_CTL_HCFS;
+        s->ctl |= OHCI_USB_RESUME;
+        /* In suspend mode only ResumeDetected is possible, not RHSC:
+         * see the OHCI spec 5.1.2.3.
+         */
+        intr = OHCI_INTR_RD;
+    }
+    ohci_set_interrupt(s, intr);
+}
+
+static void ohci_child_detach(USBPort *port1, USBDevice *child)
+{
+    OHCIState *s = port1->opaque;
+
+    ohci_async_cancel_device(s, child);
 }
 
 /* Reset the controller */
@@ -407,8 +448,8 @@ static void ohci_reset(void *opaque)
       {
         port = &ohci->rhport[i];
         port->ctrl = 0;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_reset(&port->port);
         }
       }
     if (ohci->async_td) {
@@ -427,7 +468,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 +485,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 +500,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 +517,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 +545,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 +571,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;
 }
 
@@ -577,9 +616,9 @@ static void ohci_copy_iso_td(OHCIState *ohci,
 
 static void ohci_process_lists(OHCIState *ohci, int completion);
 
-static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
+static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
 {
-    OHCIState *ohci = opaque;
+    OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
 #ifdef DEBUG_PACKET
     DPRINTF("Async packet complete\n");
 #endif
@@ -738,21 +777,18 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     }
 
     if (completion) {
-        ret = ohci->usb_packet.len;
+        ret = ohci->usb_packet.result;
     } else {
         ret = USB_RET_NODEV;
         for (i = 0; i < ohci->num_ports; i++) {
             dev = ohci->rhport[i].port.dev;
             if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
                 continue;
-            ohci->usb_packet.pid = pid;
-            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
-            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
-            ohci->usb_packet.data = ohci->usb_buf;
-            ohci->usb_packet.len = len;
-            ohci->usb_packet.complete_cb = ohci_async_complete_packet;
-            ohci->usb_packet.complete_opaque = ohci;
-            ret = dev->info->handle_packet(dev, &ohci->usb_packet);
+            usb_packet_setup(&ohci->usb_packet, pid,
+                             OHCI_BM(ed->flags, ED_FA),
+                             OHCI_BM(ed->flags, ED_EN));
+            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
+            ret = usb_handle_packet(dev, &ohci->usb_packet);
             if (ret != USB_RET_NODEV)
                 break;
         }
@@ -836,7 +872,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
 static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
 {
     int dir;
-    size_t len = 0;
+    size_t len = 0, pktlen = 0;
 #ifdef DEBUG_PACKET
     const char *str = NULL;
 #endif
@@ -904,25 +940,35 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
             len = (td.be - td.cbp) + 1;
         }
 
-        if (len && dir != OHCI_TD_DIR_IN && !completion) {
-            ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
+        pktlen = len;
+        if (len && dir != OHCI_TD_DIR_IN) {
+            /* The endpoint may not allow us to transfer it all now */
+            pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
+            if (pktlen > len) {
+                pktlen = len;
+            }
+            if (!completion) {
+                ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 0);
+            }
         }
     }
 
     flag_r = (td.flags & OHCI_TD_R) != 0;
 #ifdef DEBUG_PACKET
-    DPRINTF(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
-            addr, (int64_t)len, str, flag_r, td.cbp, td.be);
+    DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64
+            " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
+            addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be);
 
-    if (len > 0 && dir != OHCI_TD_DIR_IN) {
+    if (pktlen > 0 && dir != OHCI_TD_DIR_IN) {
         DPRINTF("  data:");
-        for (i = 0; i < len; i++)
+        for (i = 0; i < pktlen; i++) {
             printf(" %.2x", ohci->usb_buf[i]);
+        }
         DPRINTF("\n");
     }
 #endif
     if (completion) {
-        ret = ohci->usb_packet.len;
+        ret = ohci->usb_packet.result;
         ohci->async_td = 0;
         ohci->async_complete = 0;
     } else {
@@ -943,14 +989,11 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
 #endif
                 return 1;
             }
-            ohci->usb_packet.pid = pid;
-            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
-            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
-            ohci->usb_packet.data = ohci->usb_buf;
-            ohci->usb_packet.len = len;
-            ohci->usb_packet.complete_cb = ohci_async_complete_packet;
-            ohci->usb_packet.complete_opaque = ohci;
-            ret = dev->info->handle_packet(dev, &ohci->usb_packet);
+            usb_packet_setup(&ohci->usb_packet, pid,
+                             OHCI_BM(ed->flags, ED_FA),
+                             OHCI_BM(ed->flags, ED_EN));
+            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
+            ret = usb_handle_packet(dev, &ohci->usb_packet);
             if (ret != USB_RET_NODEV)
                 break;
         }
@@ -972,20 +1015,20 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
             DPRINTF("\n");
 #endif
         } else {
-            ret = len;
+            ret = pktlen;
         }
     }
 
     /* Writeback */
-    if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
+    if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
         /* Transmission succeeded.  */
         if (ret == len) {
             td.cbp = 0;
         } else {
-            td.cbp += ret;
             if ((td.cbp & 0xfff) + ret > 0xfff) {
-                td.cbp &= 0xfff;
-                td.cbp |= td.be & ~0xfff;
+                td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
+            } else {
+                td.cbp += ret;
             }
         }
         td.flags |= OHCI_TD_T1;
@@ -993,6 +1036,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
         OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
         OHCI_SET_BM(td.flags, TD_EC, 0);
 
+        if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
+            /* Partial packet transfer: TD not ready to retire yet */
+            goto exit_no_retire;
+        }
+
+        /* Setting ED_C is part of the TD retirement process */
         ed->head &= ~OHCI_ED_C;
         if (td.flags & OHCI_TD_T0)
             ed->head |= OHCI_ED_C;
@@ -1033,6 +1082,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
     i = OHCI_BM(td.flags, TD_DI);
     if (i < ohci->done_count)
         ohci->done_count = i;
+exit_no_retire:
     ohci_put_td(ohci, addr, &td);
     return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
 }
@@ -1101,7 +1151,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
 /* Generate a SOF event, and set a timer for EOF */
 static void ohci_sof(OHCIState *ohci)
 {
-    ohci->sof_time = qemu_get_clock(vm_clock);
+    ohci->sof_time = qemu_get_clock_ns(vm_clock);
     qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time);
     ohci_set_interrupt(ohci, OHCI_INTR_SF);
 }
@@ -1186,12 +1236,12 @@ static void ohci_frame_boundary(void *opaque)
  */
 static int ohci_bus_start(OHCIState *ohci)
 {
-    ohci->eof_timer = qemu_new_timer(vm_clock,
+    ohci->eof_timer = qemu_new_timer_ns(vm_clock,
                     ohci_frame_boundary,
                     ohci);
 
     if (ohci->eof_timer == NULL) {
-        fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", ohci->name);
+        fprintf(stderr, "usb-ohci: %s: qemu_new_timer_ns failed\n", ohci->name);
         /* TODO: Signal unrecoverable error */
         return 0;
     }
@@ -1311,7 +1361,7 @@ static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
     /* Being in USB operational state guarnatees sof_time was
      * set already.
      */
-    tks = qemu_get_clock(vm_clock) - ohci->sof_time;
+    tks = qemu_get_clock_ns(vm_clock) - ohci->sof_time;
 
     /* avoid muldiv if possible */
     if (tks >= usb_frame_time)
@@ -1405,13 +1455,13 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
     return;
 }
 
-static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
+static uint64_t ohci_mem_read(void *opaque,
+                              target_phys_addr_t addr,
+                              unsigned size)
 {
-    OHCIState *ohci = ptr;
+    OHCIState *ohci = opaque;
     uint32_t retval;
 
-    addr &= 0xff;
-
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
         fprintf(stderr, "usb-ohci: Mis-aligned read\n");
@@ -1528,11 +1578,12 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
     return retval;
 }
 
-static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
+static void ohci_mem_write(void *opaque,
+                           target_phys_addr_t addr,
+                           uint64_t val,
+                           unsigned size)
 {
-    OHCIState *ohci = ptr;
-
-    addr &= 0xff;
+    OHCIState *ohci = opaque;
 
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
@@ -1581,6 +1632,10 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
         ohci->hcca = val & OHCI_HCCA_MASK;
         break;
 
+    case 7: /* HcPeriodCurrentED */
+        /* Ignore writes to this read-only register, Linux does them */
+        break;
+
     case 8: /* HcControlHeadED */
         ohci->ctrl_head = val & OHCI_EDPTR_MASK;
         break;
@@ -1650,27 +1705,34 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-/* Only dword reads are defined on OHCI register space */
-static CPUReadMemoryFunc * const ohci_readfn[3]={
-    ohci_mem_read,
-    ohci_mem_read,
-    ohci_mem_read
-};
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
+{
+    if (ohci->async_td && ohci->usb_packet.owner == dev) {
+        usb_cancel_packet(&ohci->usb_packet);
+        ohci->async_td = 0;
+    }
+}
 
-/* Only dword writes are defined on OHCI register space */
-static CPUWriteMemoryFunc * const ohci_writefn[3]={
-    ohci_mem_write,
-    ohci_mem_write,
-    ohci_mem_write
+static const MemoryRegionOps ohci_mem_ops = {
+    .read = ohci_mem_read,
+    .write = ohci_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static USBPortOps ohci_port_ops = {
     .attach = ohci_attach,
     .detach = ohci_detach,
+    .child_detach = ohci_child_detach,
+    .wakeup = ohci_wakeup,
+    .complete = ohci_async_complete_packet,
+};
+
+static USBBusOps ohci_bus_ops = {
 };
 
-static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
-                          int num_ports, uint32_t localmem_base)
+static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
+                         int num_ports, uint32_t localmem_base,
+                         char *masterbus, uint32_t firstport)
 {
     int i;
 
@@ -1690,55 +1752,61 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
                 usb_frame_time, usb_bit_time);
     }
 
-    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
-                                       DEVICE_LITTLE_ENDIAN);
+    ohci->num_ports = num_ports;
+    if (masterbus) {
+        USBPort *ports[OHCI_MAX_PORTS];
+        for(i = 0; i < num_ports; i++) {
+            ports[i] = &ohci->rhport[i].port;
+        }
+        if (usb_register_companion(masterbus, ports, num_ports,
+                firstport, ohci, &ohci_port_ops,
+                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+            return -1;
+        }
+    } else {
+        usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
+        for (i = 0; i < num_ports; i++) {
+            usb_register_port(&ohci->bus, &ohci->rhport[i].port,
+                              ohci, i, &ohci_port_ops,
+                              USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        }
+    }
+
+    memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256);
     ohci->localmem_base = localmem_base;
 
     ohci->name = dev->info->name;
-
-    usb_bus_new(&ohci->bus, dev);
-    ohci->num_ports = num_ports;
-    for (i = 0; i < num_ports; i++) {
-        usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
-                          USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-        usb_port_location(&ohci->rhport[i].port, NULL, i+1);
-    }
+    usb_packet_init(&ohci->usb_packet);
 
     ohci->async_td = 0;
     qemu_register_reset(ohci_reset, ohci);
+
+    return 0;
 }
 
 typedef struct {
     PCIDevice pci_dev;
     OHCIState state;
+    char *masterbus;
+    uint32_t num_ports;
+    uint32_t firstport;
 } OHCIPCIState;
 
-static void ohci_mapfunc(PCIDevice *pci_dev, int i,
-            pcibus_t addr, pcibus_t size, int type)
-{
-    OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, pci_dev);
-    cpu_register_physical_memory(addr, size, ohci->state.mem);
-}
-
 static int usb_ohci_initfn_pci(struct PCIDevice *dev)
 {
     OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
-    int num_ports = 3;
 
-    pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(ohci->pci_dev.config,
-                             PCI_DEVICE_ID_APPLE_IPID_USB);
     ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
-    pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
-    /* TODO: RST# value should be 0. */
-    ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+    ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
 
-    usb_ohci_init(&ohci->state, &dev->qdev, num_ports, 0);
+    if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
+                      ohci->masterbus, ohci->firstport) != 0) {
+        return -1;
+    }
     ohci->state.irq = ohci->pci_dev.irq[0];
 
     /* TODO: avoid cast below by using dev */
-    pci_register_bar(&ohci->pci_dev, 0, 256,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
+    pci_register_bar(&ohci->pci_dev, 0, 0, &ohci->state.mem);
     return 0;
 }
 
@@ -1758,9 +1826,10 @@ static int ohci_init_pxa(SysBusDevice *dev)
 {
     OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev);
 
-    usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset);
+    /* Cannot fail as we pass NULL for masterbus */
+    usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0);
     sysbus_init_irq(dev, &s->ohci.irq);
-    sysbus_init_mmio(dev, 0x1000, s->ohci.mem);
+    sysbus_init_mmio_region(dev, &s->ohci.mem);
 
     return 0;
 }
@@ -1770,6 +1839,15 @@ static PCIDeviceInfo ohci_pci_info = {
     .qdev.desc    = "Apple USB Controller",
     .qdev.size    = sizeof(OHCIPCIState),
     .init         = usb_ohci_initfn_pci,
+    .vendor_id    = PCI_VENDOR_ID_APPLE,
+    .device_id    = PCI_DEVICE_ID_APPLE_IPID_USB,
+    .class_id     = PCI_CLASS_SERIAL_USB,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+        DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+        DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
 };
 
 static SysBusDeviceInfo ohci_sysbus_info = {
index 6763d520405df5f0154ef1a7f91ab74b4b02dbae..7dbf6dfc6d635b50949c1c0c598de4061ccf1c98 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
  * Written by Paul Brook, reused for FTDI by Samuel Thibault
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 #include "qemu-common.h"
@@ -146,6 +146,7 @@ static const USBDescDevice desc_device = {
             .bConfigurationValue   = 1,
             .bmAttributes          = 0x80,
             .bMaxPower             = 50,
+            .nif = 1,
             .ifs = &desc_iface0,
         },
     },
@@ -202,7 +203,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
     int flags;
     uint8_t ret;
 
-    if (qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
+    if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
         return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
 
     ret = 0;
@@ -218,14 +219,14 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
     return ret;
 }
 
-static int usb_serial_handle_control(USBDevice *dev, int request, int value,
-                                  int index, int length, uint8_t *data)
+static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     USBSerialState *s = (USBSerialState *)dev;
     int ret;
 
     DPRINTF("got control %x, value %x\n",request, value);
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
@@ -262,7 +263,7 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
     case DeviceOutVendor | FTDI_SET_MDM_CTRL:
     {
         static int flags;
-        qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
         if (value & FTDI_SET_RTS) {
             if (value & FTDI_RTS)
                 flags |= CHR_TIOCM_RTS;
@@ -275,7 +276,7 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
             else
                 flags &= ~CHR_TIOCM_DTR;
         }
-        qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
         break;
     }
     case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
@@ -294,7 +295,7 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
             divisor = 1;
 
         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
-        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         break;
     }
     case DeviceOutVendor | FTDI_SET_DATA:
@@ -323,7 +324,7 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
                 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
                 goto fail;
         }
-        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         /* TODO: TX ON/OFF */
         break;
     case DeviceInVendor | FTDI_GET_MDM_ST:
@@ -358,37 +359,42 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
 static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBSerialState *s = (USBSerialState *)dev;
-    int ret = 0;
+    int i, ret = 0;
     uint8_t devep = p->devep;
-    uint8_t *data = p->data;
-    int len = p->len;
-    int first_len;
+    struct iovec *iov;
+    uint8_t header[2];
+    int first_len, len;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
             goto fail;
-        qemu_chr_write(s->cs, data, len);
+        for (i = 0; i < p->iov.niov; i++) {
+            iov = p->iov.iov + i;
+            qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
+        }
         break;
 
     case USB_TOKEN_IN:
         if (devep != 1)
             goto fail;
         first_len = RECV_BUF - s->recv_ptr;
+        len = p->iov.size;
         if (len <= 2) {
             ret = USB_RET_NAK;
             break;
         }
-        *data++ = usb_get_modem_lines(s) | 1;
+        header[0] = usb_get_modem_lines(s) | 1;
         /* We do not have the uart details */
         /* handle serial break */
         if (s->event_trigger && s->event_trigger & FTDI_BI) {
             s->event_trigger &= ~FTDI_BI;
-            *data = FTDI_BI;
+            header[1] = FTDI_BI;
+            usb_packet_copy(p, header, 2);
             ret = 2;
             break;
         } else {
-            *data++ = 0;
+            header[1] = 0;
         }
         len -= 2;
         if (len > s->recv_used)
@@ -399,9 +405,10 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
         }
         if (first_len > len)
             first_len = len;
-        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        usb_packet_copy(p, header, 2);
+        usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
         if (len > first_len)
-            memcpy(data + first_len, s->recv_buf, len - first_len);
+            usb_packet_copy(p, s->recv_buf, len - first_len);
         s->recv_used -= len;
         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
         ret = len + 2;
@@ -421,7 +428,7 @@ static void usb_serial_handle_destroy(USBDevice *dev)
 {
     USBSerialState *s = (USBSerialState *)dev;
 
-    qemu_chr_close(s->cs);
+    qemu_chr_delete(s->cs);
 }
 
 static int usb_serial_can_read(void *opaque)
@@ -531,7 +538,7 @@ static USBDevice *usb_serial_init(const char *filename)
     filename++;
 
     snprintf(label, sizeof(label), "usbserial%d", index++);
-    cdrv = qemu_chr_open(label, filename, NULL);
+    cdrv = qemu_chr_new(label, filename, NULL);
     if (!cdrv)
         return NULL;
 
@@ -554,7 +561,7 @@ static USBDevice *usb_braille_init(const char *unused)
     USBDevice *dev;
     CharDriverState *cdrv;
 
-    cdrv = qemu_chr_open("braille", "braille", NULL);
+    cdrv = qemu_chr_new("braille", "braille", NULL);
     if (!cdrv)
         return NULL;
 
@@ -565,10 +572,16 @@ static USBDevice *usb_braille_init(const char *unused)
     return dev;
 }
 
+static const VMStateDescription vmstate_usb_serial = {
+    .name = "usb-serial",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo serial_info = {
     .product_desc   = "QEMU USB Serial",
     .qdev.name      = "usb-serial",
     .qdev.size      = sizeof(USBSerialState),
+    .qdev.vmsd      = &vmstate_usb_serial,
     .usb_desc       = &desc_serial,
     .init           = usb_serial_initfn,
     .handle_packet  = usb_generic_handle_packet,
@@ -588,6 +601,7 @@ static struct USBDeviceInfo braille_info = {
     .product_desc   = "QEMU USB Braille",
     .qdev.name      = "usb-braille",
     .qdev.size      = sizeof(USBSerialState),
+    .qdev.vmsd      = &vmstate_usb_serial,
     .usb_desc       = &desc_braille,
     .init           = usb_serial_initfn,
     .handle_packet  = usb_generic_handle_packet,
index b384e1ddec203dfc8b709c981054d7d0312f7719..660c7338cf7722c5b3d9b2b4c8643de91e2f0a1e 100644 (file)
 #include "pci.h"
 #include "qemu-timer.h"
 #include "usb-uhci.h"
+#include "iov.h"
+#include "dma.h"
+
+#ifdef CONFIG_MARU
+#include "kvm.h"
+#include "hax.h"
+#endif
 
 //#define DEBUG
 //#define DEBUG_DUMP_DATA
@@ -70,7 +77,6 @@
 #define UHCI_PORT_WRITE_CLEAR  (UHCI_PORT_CSC | UHCI_PORT_ENC)
 
 #define FRAME_TIMER_FREQ 1000
-
 #define FRAME_MAX_LOOPS  100
 
 #define NB_PORTS 2
@@ -93,19 +99,16 @@ static const char *pid2str(int pid)
 #endif
 
 #ifdef DEBUG_DUMP_DATA
-static void dump_data(const uint8_t *data, int len)
+static void dump_data(USBPacket *p, int ret)
 {
-    int i;
-
-    printf("uhci: data: ");
-    for(i = 0; i < len; i++)
-        printf(" %02x", data[i]);
-    printf("\n");
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
 }
 #else
-static void dump_data(const uint8_t *data, int len) {}
+static void dump_data(USBPacket *p, int ret) {}
 #endif
 
+typedef struct UHCIState UHCIState;
+
 /* 
  * Pending async transaction.
  * 'packet' must be the first field because completion
@@ -113,13 +116,14 @@ static void dump_data(const uint8_t *data, int len) {}
  */
 typedef struct UHCIAsync {
     USBPacket packet;
-    struct UHCIAsync *next;
+    QEMUSGList sgl;
+    UHCIState *uhci;
+    QTAILQ_ENTRY(UHCIAsync) next;
     uint32_t  td;
     uint32_t  token;
     int8_t    valid;
     uint8_t   isoc;
     uint8_t   done;
-    uint8_t   buffer[2048];
 } UHCIAsync;
 
 typedef struct UHCIPort {
@@ -127,9 +131,10 @@ typedef struct UHCIPort {
     uint16_t ctrl;
 } UHCIPort;
 
-typedef struct UHCIState {
+struct UHCIState {
     PCIDevice dev;
-    USBBus bus;
+    MemoryRegion io_bar;
+    USBBus bus; /* Note unused when we're a companion controller */
     uint16_t cmd; /* cmd register */
     uint16_t status;
     uint16_t intr; /* interrupt enable register */
@@ -145,10 +150,13 @@ typedef struct UHCIState {
     uint32_t pending_int_mask;
 
     /* Active packets */
-    UHCIAsync *async_pending;
-    UHCIAsync *async_pool;
+    QTAILQ_HEAD(,UHCIAsync) async_pending;
     uint8_t num_ports_vmstate;
-} UHCIState;
+
+    /* Properties */
+    char *masterbus;
+    uint32_t firstport;
+};
 
 typedef struct UHCI_TD {
     uint32_t link;
@@ -164,44 +172,36 @@ typedef struct UHCI_QH {
 
 static UHCIAsync *uhci_async_alloc(UHCIState *s)
 {
-    UHCIAsync *async = qemu_malloc(sizeof(UHCIAsync));
+    UHCIAsync *async = g_malloc(sizeof(UHCIAsync));
 
     memset(&async->packet, 0, sizeof(async->packet));
+    async->uhci  = s;
     async->valid = 0;
     async->td    = 0;
     async->token = 0;
     async->done  = 0;
     async->isoc  = 0;
-    async->next  = NULL;
+    usb_packet_init(&async->packet);
+    pci_dma_sglist_init(&async->sgl, &s->dev, 1);
 
     return async;
 }
 
 static void uhci_async_free(UHCIState *s, UHCIAsync *async)
 {
-    qemu_free(async);
+    usb_packet_cleanup(&async->packet);
+    qemu_sglist_destroy(&async->sgl);
+    g_free(async);
 }
 
 static void uhci_async_link(UHCIState *s, UHCIAsync *async)
 {
-    async->next = s->async_pending;
-    s->async_pending = async;
+    QTAILQ_INSERT_HEAD(&s->async_pending, async, next);
 }
 
 static void uhci_async_unlink(UHCIState *s, UHCIAsync *async)
 {
-    UHCIAsync *curr = s->async_pending;
-    UHCIAsync **prev = &s->async_pending;
-
-    while (curr) {
-       if (curr == async) {
-            *prev = curr->next;
-            return;
-        }
-
-        prev = &curr->next;
-        curr = curr->next;
-    }
+    QTAILQ_REMOVE(&s->async_pending, async, next);
 }
 
 static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
@@ -220,11 +220,10 @@ static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
  */
 static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
 {
-    UHCIAsync *async = s->async_pending;
+    UHCIAsync *async;
 
-    while (async) {
+    QTAILQ_FOREACH(async, &s->async_pending, next) {
         async->valid--;
-        async = async->next;
     }
     return NULL;
 }
@@ -234,47 +233,43 @@ static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
  */
 static void uhci_async_validate_end(UHCIState *s)
 {
-    UHCIAsync *curr = s->async_pending;
-    UHCIAsync **prev = &s->async_pending;
-    UHCIAsync *next;
+    UHCIAsync *curr, *n;
 
-    while (curr) {
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
         if (curr->valid > 0) {
-            prev = &curr->next;
-            curr = curr->next;
             continue;
         }
+        uhci_async_unlink(s, curr);
+        uhci_async_cancel(s, curr);
+    }
+}
 
-        next = curr->next;
-
-        /* Unlink */
-        *prev = next;
+static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
+{
+    UHCIAsync *curr, *n;
 
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+        if (curr->packet.owner != dev) {
+            continue;
+        }
+        uhci_async_unlink(s, curr);
         uhci_async_cancel(s, curr);
-
-        curr = next;
     }
 }
 
 static void uhci_async_cancel_all(UHCIState *s)
 {
-    UHCIAsync *curr = s->async_pending;
-    UHCIAsync *next;
-
-    while (curr) {
-        next = curr->next;
+    UHCIAsync *curr, *n;
 
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+        uhci_async_unlink(s, curr);
         uhci_async_cancel(s, curr);
-
-        curr = next;
     }
-
-    s->async_pending = NULL;
 }
 
 static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token)
 {
-    UHCIAsync *async = s->async_pending;
+    UHCIAsync *async;
     UHCIAsync *match = NULL;
     int count = 0;
 
@@ -291,7 +286,7 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
      * If we ever do we'd want to optimize this algorithm.
      */
 
-    while (async) {
+    QTAILQ_FOREACH(async, &s->async_pending, next) {
         if (async->token == token) {
             /* Good match */
             match = async;
@@ -301,8 +296,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
                 break;
             }
         }
-
-        async = async->next;
         count++;
     }
 
@@ -351,8 +344,8 @@ static void uhci_reset(void *opaque)
     for(i = 0; i < NB_PORTS; i++) {
         port = &s->ports[i];
         port->ctrl = 0x0080;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_reset(&port->port);
         }
     }
 
@@ -441,7 +434,19 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
     case 0x00:
         if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
             /* start frame processing */
-            qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
+#ifdef CONFIG_MARU
+            if (kvm_enabled() || hax_enabled()) { //kvm or haxm machine
+                s->expire_time = qemu_get_clock_ns(vm_clock) +
+                    (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+            } else {
+                s->expire_time = qemu_get_clock_ns(vm_clock) +
+                    (get_ticks_per_sec() / (FRAME_TIMER_FREQ / 2));
+            }
+#else
+            s->expire_time = qemu_get_clock_ns(vm_clock) +
+                (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+#endif
+            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
             s->status &= ~UHCI_STS_HCHALTED;
         } else if (!(val & UHCI_CMD_RS)) {
             s->status |= UHCI_STS_HCHALTED;
@@ -455,7 +460,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
             for(i = 0; i < NB_PORTS; i++) {
                 port = &s->ports[i];
                 dev = port->port.dev;
-                if (dev) {
+                if (dev && dev->attached) {
                     usb_send_msg(dev, USB_MSG_RESET);
                 }
             }
@@ -495,7 +500,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
                 return;
             port = &s->ports[n];
             dev = port->port.dev;
-            if (dev) {
+            if (dev && dev->attached) {
                 /* port reset */
                 if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
@@ -621,6 +626,8 @@ static void uhci_detach(USBPort *port1)
     UHCIState *s = port1->opaque;
     UHCIPort *port = &s->ports[port1->index];
 
+    uhci_async_cancel_device(s, port1->dev);
+
     /* set connect status */
     if (port->ctrl & UHCI_PORT_CCS) {
         port->ctrl &= ~UHCI_PORT_CCS;
@@ -635,11 +642,17 @@ static void uhci_detach(USBPort *port1)
     uhci_resume(s);
 }
 
-static void uhci_wakeup(USBDevice *dev)
+static void uhci_child_detach(USBPort *port1, USBDevice *child)
 {
-    USBBus *bus = usb_bus_from_device(dev);
-    UHCIState *s = container_of(bus, UHCIState, bus);
-    UHCIPort *port = s->ports + dev->port->index;
+    UHCIState *s = port1->opaque;
+
+    uhci_async_cancel_device(s, child);
+}
+
+static void uhci_wakeup(USBPort *port1)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
 
     if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
         port->ctrl |= UHCI_PORT_RD;
@@ -651,28 +664,29 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
 {
     int i, ret;
 
-    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n",
-           pid2str(p->pid), p->devaddr, p->devep, p->len);
+    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
+           pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
     if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
-        dump_data(p->data, p->len);
+        dump_data(p, 0);
 
     ret = USB_RET_NODEV;
     for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
         UHCIPort *port = &s->ports[i];
         USBDevice *dev = port->port.dev;
 
-        if (dev && (port->ctrl & UHCI_PORT_EN))
-            ret = dev->info->handle_packet(dev, p);
+        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
+            ret = usb_handle_packet(dev, p);
+        }
     }
 
-    DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+    DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
     if (p->pid == USB_TOKEN_IN && ret > 0)
-        dump_data(p->data, ret);
+        dump_data(p, ret);
 
     return ret;
 }
 
-static void uhci_async_complete(USBPacket * packet, void *opaque);
+static void uhci_async_complete(USBPort *port, USBPacket *packet);
 static void uhci_process_frame(UHCIState *s);
 
 /* return -1 if fatal error (frame must be stopped)
@@ -687,7 +701,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    ret = async->packet.len;
+    ret = async->packet.result;
 
     if (td->ctrl & TD_CTRL_IOS)
         td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -695,7 +709,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     if (ret < 0)
         goto out;
 
-    len = async->packet.len;
+    len = async->packet.result;
     td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
 
     /* The NAK bit may have been set by a previous frame, so clear it
@@ -711,11 +725,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
             goto out;
         }
 
-        if (len > 0) {
-            /* write the data back */
-            cpu_physical_memory_write(td->buffer, async->buffer, len);
-        }
-
         if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
             *int_mask |= 0x02;
             /* short packet: do not update QH */
@@ -732,11 +741,21 @@ out:
     case USB_RET_STALL:
         td->ctrl |= TD_CTRL_STALL;
         td->ctrl &= ~TD_CTRL_ACTIVE;
+        s->status |= UHCI_STS_USBERR;
+        if (td->ctrl & TD_CTRL_IOC) {
+            *int_mask |= 0x01;
+        }
+        uhci_update_irq(s);
         return 1;
 
     case USB_RET_BABBLE:
         td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
         td->ctrl &= ~TD_CTRL_ACTIVE;
+        s->status |= UHCI_STS_USBERR;
+        if (td->ctrl & TD_CTRL_IOC) {
+            *int_mask |= 0x01;
+        }
+        uhci_update_irq(s);
         /* frame interrupted */
         return -1;
 
@@ -820,18 +839,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    async->packet.pid     = pid;
-    async->packet.devaddr = (td->token >> 8) & 0x7f;
-    async->packet.devep   = (td->token >> 15) & 0xf;
-    async->packet.data    = async->buffer;
-    async->packet.len     = max_len;
-    async->packet.complete_cb     = uhci_async_complete;
-    async->packet.complete_opaque = s;
+    usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
+                     (td->token >> 15) & 0xf);
+    qemu_sglist_add(&async->sgl, td->buffer, max_len);
+    usb_packet_map(&async->packet, &async->sgl);
 
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        cpu_physical_memory_read(td->buffer, async->buffer, max_len);
         len = uhci_broadcast_packet(s, &async->packet);
         if (len >= 0)
             len = max_len;
@@ -854,18 +869,19 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
         return 2;
     }
 
-    async->packet.len = len;
+    async->packet.result = len;
 
 done:
     len = uhci_complete_td(s, td, async, int_mask);
+    usb_packet_unmap(&async->packet);
     uhci_async_free(s, async);
     return len;
 }
 
-static void uhci_async_complete(USBPacket *packet, void *opaque)
+static void uhci_async_complete(USBPort *port, USBPacket *packet)
 {
-    UHCIState *s = opaque;
-    UHCIAsync *async = (UHCIAsync *) packet;
+    UHCIAsync *async = container_of(packet, UHCIAsync, packet);
+    UHCIState *s = async->uhci;
 
     DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
 
@@ -874,7 +890,7 @@ static void uhci_async_complete(USBPacket *packet, void *opaque)
         uint32_t link = async->td;
         uint32_t int_mask = 0, val;
 
-        cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td));
+        pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td));
         le32_to_cpus(&td.link);
         le32_to_cpus(&td.ctrl);
         le32_to_cpus(&td.token);
@@ -886,8 +902,8 @@ static void uhci_async_complete(USBPacket *packet, void *opaque)
 
         /* update the status bits of the TD */
         val = cpu_to_le32(td.ctrl);
-        cpu_physical_memory_write((link & ~0xf) + 4,
-                                  (const uint8_t *)&val, sizeof(val));
+        pci_dma_write(&s->dev, (link & ~0xf) + 4,
+                      (const uint8_t *)&val, sizeof(val));
         uhci_async_free(s, async);
     } else {
         async->done = 1;
@@ -950,7 +966,7 @@ static void uhci_process_frame(UHCIState *s)
 
     DPRINTF("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr);
 
-    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
+    pci_dma_read(&s->dev, frame_addr, (uint8_t *)&link, 4);
     le32_to_cpus(&link);
 
     int_mask = 0;
@@ -974,7 +990,7 @@ static void uhci_process_frame(UHCIState *s)
                 break;
             }
 
-            cpu_physical_memory_read(link & ~0xf, (uint8_t *) &qh, sizeof(qh));
+            pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &qh, sizeof(qh));
             le32_to_cpus(&qh.link);
             le32_to_cpus(&qh.el_link);
 
@@ -994,7 +1010,7 @@ static void uhci_process_frame(UHCIState *s)
         }
 
         /* TD */
-        cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td));
+        pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td));
         le32_to_cpus(&td.link);
         le32_to_cpus(&td.ctrl);
         le32_to_cpus(&td.token);
@@ -1008,8 +1024,8 @@ static void uhci_process_frame(UHCIState *s)
         if (old_td_ctrl != td.ctrl) {
             /* update the status bits of the TD */
             val = cpu_to_le32(td.ctrl);
-            cpu_physical_memory_write((link & ~0xf) + 4,
-                                      (const uint8_t *)&val, sizeof(val));
+            pci_dma_write(&s->dev, (link & ~0xf) + 4,
+                          (const uint8_t *)&val, sizeof(val));
         }
 
         if (ret < 0) {
@@ -1037,8 +1053,8 @@ static void uhci_process_frame(UHCIState *s)
            /* update QH element link */
             qh.el_link = link;
             val = cpu_to_le32(qh.el_link);
-            cpu_physical_memory_write((curr_qh & ~0xf) + 4,
-                                          (const uint8_t *)&val, sizeof(val));
+            pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4,
+                          (const uint8_t *)&val, sizeof(val));
 
             if (!depth_first(link)) {
                /* done with this QH */
@@ -1062,7 +1078,15 @@ static void uhci_frame_timer(void *opaque)
     UHCIState *s = opaque;
 
     /* prepare the timer for the next frame */
+#ifdef CONFIG_MARU
+    if (kvm_enabled() || hax_enabled()) { //kvm or haxm machine
+        s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+    } else {
+        s->expire_time += (get_ticks_per_sec() / (FRAME_TIMER_FREQ / 2));
+    }
+#else
     s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+#endif
 
     if (!(s->cmd & UHCI_CMD_RS)) {
         /* Full stop */
@@ -1096,86 +1120,78 @@ static void uhci_frame_timer(void *opaque)
     qemu_mod_timer(s->frame_timer, s->expire_time);
 }
 
-static void uhci_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    UHCIState *s = (UHCIState *)pci_dev;
-
-    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
-    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
-    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
-    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
-    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
-    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
-}
+static const MemoryRegionPortio uhci_portio[] = {
+    { 0, 32, 2, .write = uhci_ioport_writew, },
+    { 0, 32, 2, .read = uhci_ioport_readw, },
+    { 0, 32, 4, .write = uhci_ioport_writel, },
+    { 0, 32, 4, .read = uhci_ioport_readl, },
+    { 0, 32, 1, .write = uhci_ioport_writeb, },
+    { 0, 32, 1, .read = uhci_ioport_readb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps uhci_ioport_ops = {
+    .old_portio = uhci_portio,
+};
 
 static USBPortOps uhci_port_ops = {
     .attach = uhci_attach,
     .detach = uhci_detach,
+    .child_detach = uhci_child_detach,
     .wakeup = uhci_wakeup,
+    .complete = uhci_async_complete,
 };
 
-static int usb_uhci_common_initfn(UHCIState *s)
+static USBBusOps uhci_bus_ops = {
+};
+
+static int usb_uhci_common_initfn(PCIDevice *dev)
 {
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     int i;
 
-    pci_conf[PCI_REVISION_ID] = 0x01; // revision number
     pci_conf[PCI_CLASS_PROG] = 0x00;
-    pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
     /* TODO: reset value should be 0. */
-    pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
-    pci_conf[0x60] = 0x10; // release number
+    pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
+    pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
 
-    usb_bus_new(&s->bus, &s->dev.qdev);
-    for(i = 0; i < NB_PORTS; i++) {
-        usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
-                          USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-        usb_port_location(&s->ports[i].port, NULL, i+1);
+    if (s->masterbus) {
+        USBPort *ports[NB_PORTS];
+        for(i = 0; i < NB_PORTS; i++) {
+            ports[i] = &s->ports[i].port;
+        }
+        if (usb_register_companion(s->masterbus, ports, NB_PORTS,
+                s->firstport, s, &uhci_port_ops,
+                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+            return -1;
+        }
+    } else {
+        usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
+        for (i = 0; i < NB_PORTS; i++) {
+            usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
+                              USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        }
     }
-    s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
-    s->expire_time = qemu_get_clock(vm_clock) +
-        (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
     s->num_ports_vmstate = NB_PORTS;
+    QTAILQ_INIT(&s->async_pending);
 
     qemu_register_reset(uhci_reset, s);
 
+    memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20);
     /* Use region 4 for consistency with real hardware.  BSD guests seem
        to rely on this.  */
-    pci_register_bar(&s->dev, 4, 0x20,
-                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
+    pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
     return 0;
 }
 
-static int usb_uhci_piix3_initfn(PCIDevice *dev)
-{
-    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_2);
-    return usb_uhci_common_initfn(s);
-}
-
-static int usb_uhci_piix4_initfn(PCIDevice *dev)
-{
-    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
-    uint8_t *pci_conf = s->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_2);
-    return usb_uhci_common_initfn(s);
-}
-
 static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
 {
     UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_UHCI);
-
     /* USB misc control 1/2 */
     pci_set_long(pci_conf + 0x40,0x00001000);
     /* PM capability */
@@ -1183,25 +1199,87 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
     /* USB legacy support  */
     pci_set_long(pci_conf + 0xc0,0x00002000);
 
-    return usb_uhci_common_initfn(s);
+    return usb_uhci_common_initfn(dev);
+}
+
+static int usb_uhci_exit(PCIDevice *dev)
+{
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+
+    memory_region_destroy(&s->io_bar);
+    return 0;
 }
 
+static Property uhci_properties[] = {
+    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
+    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static PCIDeviceInfo uhci_info[] = {
     {
         .qdev.name    = "piix3-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_piix3_initfn,
+        .init         = usb_uhci_common_initfn,
+        .exit         = usb_uhci_exit,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
     },{
         .qdev.name    = "piix4-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_piix4_initfn,
+        .init         = usb_uhci_common_initfn,
+        .exit         = usb_uhci_exit,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
     },{
         .qdev.name    = "vt82c686b-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .init         = usb_uhci_vt82c686b_initfn,
+        .exit         = usb_uhci_exit,
+        .vendor_id    = PCI_VENDOR_ID_VIA,
+        .device_id    = PCI_DEVICE_ID_VIA_UHCI,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci1",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci2",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci3",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
     },{
         /* end of list */
     }
index 53978942baa04bab2210a8abc39cca536f2114a9..25580067f2e24ae6be54229e39ab5c4351f75020 100644 (file)
 #define HID_SET_IDLE           0x210a
 #define HID_SET_PROTOCOL       0x210b
 
-enum {
-    WACOM_MODE_HID = 1,
-    WACOM_MODE_WACOM = 2,
-} ;
-
 typedef struct USBWacomState {
     USBDevice dev;
     QEMUPutMouseEntry *eh_entry;
-    int32_t dx, dy, dz, buttons_state;
-    int32_t x, y;
-    int32_t mouse_grabbed;
-    uint8_t mode;
+    int dx, dy, dz, buttons_state;
+    int x, y;
+    int mouse_grabbed;
+    enum {
+        WACOM_MODE_HID = 1,
+        WACOM_MODE_WACOM = 2,
+    } mode;
     uint8_t idle;
-    int32_t changed;
+    int changed;
 } USBWacomState;
 
 enum {
@@ -110,6 +108,7 @@ static const USBDescDevice desc_device_wacom = {
             .bConfigurationValue   = 1,
             .bmAttributes          = 0x80,
             .bMaxPower             = 40,
+            .nif = 1,
             .ifs = &desc_iface_wacom,
         },
     },
@@ -251,13 +250,13 @@ static void usb_wacom_handle_reset(USBDevice *dev)
     s->mode = WACOM_MODE_HID;
 }
 
-static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
-                                    int index, int length, uint8_t *data)
+static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
     USBWacomState *s = (USBWacomState *) dev;
     int ret;
 
-    ret = usb_desc_handle_control(dev, request, value, index, length, data);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
     }
@@ -275,8 +274,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
         if (s->mouse_grabbed) {
             qemu_remove_mouse_event_handler(s->eh_entry);
             s->mouse_grabbed = 0;
-            s->changed = 1;
-            dev->setup_index=0;
         }
         s->mode = data[0];
         ret = 0;
@@ -311,6 +308,7 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
 static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBWacomState *s = (USBWacomState *) dev;
+    uint8_t buf[p->iov.size];
     int ret = 0;
 
     switch (p->pid) {
@@ -320,9 +318,10 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
                 return USB_RET_NAK;
             s->changed = 0;
             if (s->mode == WACOM_MODE_HID)
-                ret = usb_mouse_poll(s, p->data, p->len);
+                ret = usb_mouse_poll(s, buf, p->iov.size);
             else if (s->mode == WACOM_MODE_WACOM)
-                ret = usb_wacom_poll(s, p->data, p->len);
+                ret = usb_wacom_poll(s, buf, p->iov.size);
+            usb_packet_copy(p, buf, ret);
             break;
         }
         /* Fall through.  */
@@ -352,70 +351,9 @@ static int usb_wacom_initfn(USBDevice *dev)
     return 0;
 }
 
-/* Remove mouse handlers before loading.  */
-static int wacom_pre_load(void *opaque)
-{
-    USBWacomState *s = (USBWacomState *)opaque;
-
-    if (s->eh_entry) {
-        qemu_remove_mouse_event_handler(s->eh_entry);
-       }
-
-       return 0;
-}
-
-static int wacom_post_load(void *opaque, int version_id)
-{
-    USBWacomState *s = (USBWacomState *)opaque;
-
-    s->changed = 1;
-       if (s->mouse_grabbed && s->mode == WACOM_MODE_WACOM) {
-        s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
-                        "QEMU PenPartner tablet");
-       } else if (s->mouse_grabbed && s->mode == WACOM_MODE_HID) {
-        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
-                        "QEMU PenPartner tablet");
-       }
-       if (s->mouse_grabbed) {
-        qemu_activate_mouse_event_handler(s->eh_entry);
-       }
-
-       return 0;
-}
-
-static VMStateDescription vmsd_usbdevice = {
-       .name = "wacom-tablet_usbdevice",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT8(addr, USBDevice),
-           VMSTATE_INT32(state, USBDevice),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static VMStateDescription vmsd = {
-       .name = "wacom-tablet",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-       .pre_load = wacom_pre_load,
-       .post_load = wacom_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_STRUCT(dev, USBWacomState, 1, vmsd_usbdevice, USBDevice),
-        VMSTATE_INT32(dx, USBWacomState),
-        VMSTATE_INT32(dy, USBWacomState),
-        VMSTATE_INT32(dz, USBWacomState),
-        VMSTATE_INT32(buttons_state, USBWacomState),
-        VMSTATE_INT32(x, USBWacomState),
-        VMSTATE_INT32(y, USBWacomState),
-        VMSTATE_INT32(mouse_grabbed, USBWacomState),
-        VMSTATE_UINT8(mode, USBWacomState),
-        VMSTATE_UINT8(idle, USBWacomState),
-        VMSTATE_INT32(changed, USBWacomState),
-        VMSTATE_END_OF_LIST()
-    }
+static const VMStateDescription vmstate_usb_wacom = {
+    .name = "usb-wacom",
+    .unmigratable = 1,
 };
 
 static struct USBDeviceInfo wacom_info = {
@@ -425,7 +363,7 @@ static struct USBDeviceInfo wacom_info = {
     .usbdevice_name = "wacom-tablet",
     .usb_desc       = &desc_wacom,
     .qdev.size      = sizeof(USBWacomState),
-    .qdev.vmsd      = &vmsd,
+    .qdev.vmsd      = &vmstate_usb_wacom,
     .init           = usb_wacom_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_wacom_handle_reset,
index 82a6217a0b5f94b3d7f83ccc5c43c9608eb8bd1e..2216efe077a1f84075005d51ef75cc62261d75e3 100644 (file)
--- a/hw/usb.c
+++ b/hw/usb.c
  */
 #include "qemu-common.h"
 #include "usb.h"
+#include "iov.h"
 
-void usb_attach(USBPort *port, USBDevice *dev)
+void usb_attach(USBPort *port)
 {
-    if (dev != NULL) {
-        /* attach */
-        if (port->dev) {
-            usb_attach(port, NULL);
-        }
-        dev->port = port;
-        port->dev = dev;
-        port->ops->attach(port);
-        usb_send_msg(dev, USB_MSG_ATTACH);
-    } else {
-        /* detach */
-        dev = port->dev;
-        port->ops->detach(port);
-        if (dev) {
-            usb_send_msg(dev, USB_MSG_DETACH);
-            dev->port = NULL;
-            port->dev = NULL;
-        }
-    }
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    assert(dev->attached);
+    assert(dev->state == USB_STATE_NOTATTACHED);
+    port->ops->attach(port);
+    usb_send_msg(dev, USB_MSG_ATTACH);
+}
+
+void usb_detach(USBPort *port)
+{
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    assert(dev->state != USB_STATE_NOTATTACHED);
+    port->ops->detach(port);
+    usb_send_msg(dev, USB_MSG_DETACH);
+}
+
+void usb_reset(USBPort *port)
+{
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    usb_detach(port);
+    usb_attach(port);
+    usb_send_msg(dev, USB_MSG_RESET);
 }
 
 void usb_wakeup(USBDevice *dev)
 {
     if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
-        dev->port->ops->wakeup(dev);
+        dev->port->ops->wakeup(dev->port);
     }
 }
 
@@ -63,29 +72,35 @@ void usb_wakeup(USBDevice *dev)
    protocol)
 */
 
-#define SETUP_STATE_IDLE 0
-#define SETUP_STATE_DATA 1
-#define SETUP_STATE_ACK  2
+#define SETUP_STATE_IDLE  0
+#define SETUP_STATE_SETUP 1
+#define SETUP_STATE_DATA  2
+#define SETUP_STATE_ACK   3
 
 static int do_token_setup(USBDevice *s, USBPacket *p)
 {
     int request, value, index;
     int ret = 0;
 
-    if (p->len != 8)
+    if (p->iov.size != 8) {
         return USB_RET_STALL;
-    memcpy(s->setup_buf, p->data, 8);
+    }
+
+    usb_packet_copy(p, s->setup_buf, p->iov.size);
     s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
     s->setup_index = 0;
 
     request = (s->setup_buf[0] << 8) | s->setup_buf[1];
     value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
     index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
+
     if (s->setup_buf[0] & USB_DIR_IN) {
-        ret = s->info->handle_control(s, request, value, index, 
+        ret = s->info->handle_control(s, p, request, value, index,
                                       s->setup_len, s->data_buf);
+        if (ret == USB_RET_ASYNC) {
+             s->setup_state = SETUP_STATE_SETUP;
+             return USB_RET_ASYNC;
+        }
         if (ret < 0)
             return ret;
 
@@ -93,6 +108,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
             s->setup_len = ret;
         s->setup_state = SETUP_STATE_DATA;
     } else {
+        if (s->setup_len > sizeof(s->data_buf)) {
+            fprintf(stderr,
+                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
+                s->setup_len, sizeof(s->data_buf));
+            return USB_RET_STALL;
+        }
         if (s->setup_len == 0)
             s->setup_state = SETUP_STATE_ACK;
         else
@@ -117,9 +138,12 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
         if (!(s->setup_buf[0] & USB_DIR_IN)) {
-            s->setup_state = SETUP_STATE_IDLE;
-            ret = s->info->handle_control(s, request, value, index,
+            ret = s->info->handle_control(s, p, request, value, index,
                                           s->setup_len, s->data_buf);
+            if (ret == USB_RET_ASYNC) {
+                return USB_RET_ASYNC;
+            }
+            s->setup_state = SETUP_STATE_IDLE;
             if (ret > 0)
                 return 0;
             return ret;
@@ -131,9 +155,10 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     case SETUP_STATE_DATA:
         if (s->setup_buf[0] & USB_DIR_IN) {
             int len = s->setup_len - s->setup_index;
-            if (len > p->len)
-                len = p->len;
-            memcpy(p->data, s->data_buf + s->setup_index, len);
+            if (len > p->iov.size) {
+                len = p->iov.size;
+            }
+            usb_packet_copy(p, s->data_buf + s->setup_index, len);
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
@@ -166,9 +191,10 @@ static int do_token_out(USBDevice *s, USBPacket *p)
     case SETUP_STATE_DATA:
         if (!(s->setup_buf[0] & USB_DIR_IN)) {
             int len = s->setup_len - s->setup_index;
-            if (len > p->len)
-                len = p->len;
-            memcpy(s->data_buf + s->setup_index, p->data, len);
+            if (len > p->iov.size) {
+                len = p->iov.size;
+            }
+            usb_packet_copy(p, s->data_buf + s->setup_index, len);
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
@@ -232,6 +258,36 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
     }
 }
 
+/* ctrl complete function for devices which use usb_generic_handle_packet and
+   may return USB_RET_ASYNC from their handle_control callback. Device code
+   which does this *must* call this function instead of the normal
+   usb_packet_complete to complete their async control packets. */
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
+{
+    if (p->result < 0) {
+        s->setup_state = SETUP_STATE_IDLE;
+    }
+
+    switch (s->setup_state) {
+    case SETUP_STATE_SETUP:
+        if (p->result < s->setup_len) {
+            s->setup_len = p->result;
+        }
+        s->setup_state = SETUP_STATE_DATA;
+        p->result = 8;
+        break;
+
+    case SETUP_STATE_ACK:
+        s->setup_state = SETUP_STATE_IDLE;
+        p->result = 0;
+        break;
+
+    default:
+        break;
+    }
+    usb_packet_complete(s, p);
+}
+
 /* XXX: fix overflow */
 int set_usb_string(uint8_t *buf, const char *str)
 {
@@ -253,9 +309,108 @@ int set_usb_string(uint8_t *buf, const char *str)
 void usb_send_msg(USBDevice *dev, int msg)
 {
     USBPacket p;
+    int ret;
+
     memset(&p, 0, sizeof(p));
     p.pid = msg;
-    dev->info->handle_packet(dev, &p);
-
+    ret = usb_handle_packet(dev, &p);
     /* This _must_ be synchronous */
+    assert(ret != USB_RET_ASYNC);
+}
+
+/* Hand over a packet to a device for processing.  Return value
+   USB_RET_ASYNC indicates the processing isn't finished yet, the
+   driver will call usb_packet_complete() when done processing it. */
+int usb_handle_packet(USBDevice *dev, USBPacket *p)
+{
+    int ret;
+
+    assert(p->owner == NULL);
+    ret = dev->info->handle_packet(dev, p);
+    if (ret == USB_RET_ASYNC) {
+        if (p->owner == NULL) {
+            p->owner = dev;
+        } else {
+            /* We'll end up here when usb_handle_packet is called
+             * recursively due to a hub being in the chain.  Nothing
+             * to do.  Leave p->owner pointing to the device, not the
+             * hub. */;
+        }
+    }
+    return ret;
+}
+
+/* Notify the controller that an async packet is complete.  This should only
+   be called for packets previously deferred by returning USB_RET_ASYNC from
+   handle_packet. */
+void usb_packet_complete(USBDevice *dev, USBPacket *p)
+{
+    /* Note: p->owner != dev is possible in case dev is a hub */
+    assert(p->owner != NULL);
+    p->owner = NULL;
+    dev->port->ops->complete(dev->port, p);
+}
+
+/* Cancel an active packet.  The packed must have been deferred by
+   returning USB_RET_ASYNC from handle_packet, and not yet
+   completed.  */
+void usb_cancel_packet(USBPacket * p)
+{
+    assert(p->owner != NULL);
+    p->owner->info->cancel_packet(p->owner, p);
+    p->owner = NULL;
+}
+
+
+void usb_packet_init(USBPacket *p)
+{
+    qemu_iovec_init(&p->iov, 1);
+}
+
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+{
+    p->pid = pid;
+    p->devaddr = addr;
+    p->devep = ep;
+    p->result = 0;
+    qemu_iovec_reset(&p->iov);
+}
+
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
+{
+    qemu_iovec_add(&p->iov, ptr, len);
+}
+
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
+{
+    assert(p->result >= 0);
+    assert(p->result + bytes <= p->iov.size);
+    switch (p->pid) {
+    case USB_TOKEN_SETUP:
+    case USB_TOKEN_OUT:
+        iov_to_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+        break;
+    case USB_TOKEN_IN:
+        iov_from_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+        break;
+    default:
+        fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
+        abort();
+    }
+    p->result += bytes;
+}
+
+void usb_packet_skip(USBPacket *p, size_t bytes)
+{
+    assert(p->result >= 0);
+    assert(p->result + bytes <= p->iov.size);
+    if (p->pid == USB_TOKEN_IN) {
+        iov_clear(p->iov.iov, p->iov.niov, p->result, bytes);
+    }
+    p->result += bytes;
+}
+
+void usb_packet_cleanup(USBPacket *p)
+{
+    qemu_iovec_destroy(&p->iov);
 }
index d3d755db7bfa82890ef1fecda2d24e81321e1904..c6e1870e59acf70b0844e4495f68aa63a69320a6 100644 (file)
--- a/hw/usb.h
+++ b/hw/usb.h
 #include "qdev.h"
 #include "qemu-queue.h"
 
+/* Constants related to the USB / PCI interaction */
+#define USB_SBRN    0x60 /* Serial Bus Release Number Register */
+#define USB_RELEASE_1  0x10 /* USB 1.0 */
+#define USB_RELEASE_2  0x20 /* USB 2.0 */
+#define USB_RELEASE_3  0x30 /* USB 3.0 */
+
 #define USB_TOKEN_SETUP 0x2d
 #define USB_TOKEN_IN    0x69 /* device -> host */
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
 #define USB_DT_ENDPOINT                        0x05
 #define USB_DT_DEVICE_QUALIFIER         0x06
 #define USB_DT_OTHER_SPEED_CONFIG       0x07
+#define USB_DT_DEBUG                    0x0A
+#define USB_DT_INTERFACE_ASSOC          0x0B
 
 #define USB_ENDPOINT_XFER_CONTROL      0
 #define USB_ENDPOINT_XFER_ISOC         1
 #define USB_ENDPOINT_XFER_INT          3
 
 typedef struct USBBus USBBus;
+typedef struct USBBusOps USBBusOps;
 typedef struct USBPort USBPort;
 typedef struct USBDevice USBDevice;
 typedef struct USBDeviceInfo USBDeviceInfo;
@@ -140,6 +149,7 @@ typedef struct USBDesc USBDesc;
 typedef struct USBDescID USBDescID;
 typedef struct USBDescDevice USBDescDevice;
 typedef struct USBDescConfig USBDescConfig;
+typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
 typedef struct USBDescIface USBDescIface;
 typedef struct USBDescEndpoint USBDescEndpoint;
 typedef struct USBDescOther USBDescOther;
@@ -159,7 +169,10 @@ struct USBDevice {
     char *port_path;
     void *opaque;
 
+    /* Actual connected speed */
     int speed;
+    /* Supported speeds, not in info because it may be variable (hostdevs) */
+    int speedmask;
     uint8_t addr;
     char product_desc[32];
     int auto_attach;
@@ -167,7 +180,7 @@ struct USBDevice {
 
     int32_t state;
     uint8_t setup_buf[8];
-    uint8_t data_buf[1024];
+    uint8_t data_buf[4096];
     int32_t remote_wakeup;
     int32_t setup_state;
     int32_t setup_len;
@@ -191,6 +204,11 @@ struct USBDeviceInfo {
      */
     int (*handle_packet)(USBDevice *dev, USBPacket *p);
 
+    /*
+     * Called when a packet is canceled.
+     */
+    void (*cancel_packet)(USBDevice *dev, USBPacket *p);
+
     /*
      * Called when device is destroyed.
      */
@@ -212,7 +230,7 @@ struct USBDeviceInfo {
      *
      * Returns length or one of the USB_RET_ codes.
      */
-    int (*handle_control)(USBDevice *dev, int request, int value,
+    int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
                           int index, int length, uint8_t *data);
 
     /*
@@ -234,7 +252,18 @@ struct USBDeviceInfo {
 typedef struct USBPortOps {
     void (*attach)(USBPort *port);
     void (*detach)(USBPort *port);
-    void (*wakeup)(USBDevice *dev);
+    /*
+     * This gets called when a device downstream from the device attached to
+     * the port (iow attached through a hub) gets detached.
+     */
+    void (*child_detach)(USBPort *port, USBDevice *child);
+    void (*wakeup)(USBPort *port);
+    /*
+     * Note that port->dev will be different then the device from which
+     * the packet originated when a hub is involved, if you want the orginating
+     * device use p->owner
+     */
+    void (*complete)(USBPort *port, USBPacket *p);
 } USBPortOps;
 
 /* USB port on which a device can be connected */
@@ -256,43 +285,31 @@ struct USBPacket {
     int pid;
     uint8_t devaddr;
     uint8_t devep;
-    uint8_t *data;
-    int len;
+    QEMUIOVector iov;
+    int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
-    USBCallback *complete_cb;
-    void *complete_opaque;
-    USBCallback *cancel_cb;
-    void *cancel_opaque;
+    USBDevice *owner;
 };
 
-/* Defer completion of a USB packet.  The hadle_packet routine should then
-   return USB_RET_ASYNC.  Packets that complete immediately (before
-   handle_packet returns) should not call this method.  */
-static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel,
-                                    void * opaque)
-{
-    p->cancel_cb = cancel;
-    p->cancel_opaque = opaque;
-}
-
-/* Notify the controller that an async packet is complete.  This should only
-   be called for packets previously deferred with usb_defer_packet, and
-   should never be called from within handle_packet.  */
-static inline void usb_packet_complete(USBPacket *p)
-{
-    p->complete_cb(p, p->complete_opaque);
-}
-
-/* Cancel an active packet.  The packed must have been deferred with
-   usb_defer_packet,  and not yet completed.  */
-static inline void usb_cancel_packet(USBPacket * p)
-{
-    p->cancel_cb(p, p->cancel_opaque);
-}
-
-void usb_attach(USBPort *port, USBDevice *dev);
+void usb_packet_init(USBPacket *p);
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
+void usb_packet_unmap(USBPacket *p);
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
+void usb_packet_skip(USBPacket *p, size_t bytes);
+void usb_packet_cleanup(USBPacket *p);
+
+int usb_handle_packet(USBDevice *dev, USBPacket *p);
+void usb_packet_complete(USBDevice *dev, USBPacket *p);
+void usb_cancel_packet(USBPacket * p);
+
+void usb_attach(USBPort *port);
+void usb_detach(USBPort *port);
+void usb_reset(USBPort *port);
 void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 void usb_send_msg(USBDevice *dev, int msg);
 
@@ -301,9 +318,6 @@ USBDevice *usb_host_device_open(const char *devname);
 int usb_host_device_close(const char *devname);
 void usb_host_info(Monitor *mon);
 
-/* usb-hid.c */
-void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
-
 /* usb-bt.c */
 USBDevice *usb_bt_init(HCIInfo *hci);
 
@@ -325,11 +339,13 @@ enum musb_irq_source_e {
     musb_irq_tx,
     musb_set_vbus,
     musb_set_session,
-    __musb_irq_max,
+    /* Add new interrupts here */
+    musb_irq_max, /* total number of interrupts defined */
 };
 
 typedef struct MUSBState MUSBState;
-MUSBState *musb_init(qemu_irq *irqs);
+MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
+void musb_reset(MUSBState *s);
 uint32_t musb_core_intr_get(MUSBState *s);
 void musb_core_intr_clear(MUSBState *s, uint32_t mask);
 void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
@@ -338,6 +354,7 @@ void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
 
 struct USBBus {
     BusState qbus;
+    USBBusOps *ops;
     int busnr;
     int nfree;
     int nused;
@@ -346,7 +363,12 @@ struct USBBus {
     QTAILQ_ENTRY(USBBus) next;
 };
 
-void usb_bus_new(USBBus *bus, DeviceState *host);
+struct USBBusOps {
+    int (*register_companion)(USBBus *bus, USBPort *ports[],
+                              uint32_t portcount, uint32_t firstport);
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
 USBBus *usb_bus_find(int busnr);
 void usb_qdev_register(USBDeviceInfo *info);
 void usb_qdev_register_many(USBDeviceInfo *info);
@@ -355,8 +377,13 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name);
 USBDevice *usbdevice_create(const char *cmdline);
 void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
                        USBPortOps *ops, int speedmask);
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+                           uint32_t portcount, uint32_t firstport,
+                           void *opaque, USBPortOps *ops, int speedmask);
 void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
 void usb_unregister_port(USBBus *bus, USBPort *port);
+int usb_claim_port(USBDevice *dev);
+void usb_release_port(USBDevice *dev);
 int usb_device_attach(USBDevice *dev);
 int usb_device_detach(USBDevice *dev);
 int usb_device_delete_addr(int busnr, int addr);
index 2fed8a00fde9317a05c6b4371218ac331ca36511..8a88696f2c13d19e45ca281288618d15dbd6a3eb 100644 (file)
@@ -4,18 +4,21 @@
  * Copyright (c) 2006-2009 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
  */
 
 #include "sysbus.h"
 #include "pci.h"
 #include "pci_host.h"
+#include "exec-memory.h"
 
 typedef struct {
     SysBusDevice busdev;
     qemu_irq irq[4];
     int realview;
-    int mem_config;
+    MemoryRegion mem_config;
+    MemoryRegion mem_config2;
+    MemoryRegion isa;
 } PCIVPBState;
 
 static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
@@ -23,55 +26,24 @@ static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
     return addr & 0xffffff;
 }
 
-static void pci_vpb_config_write(void *opaque, target_phys_addr_t addr,
-                                   uint32_t val)
+static void pci_vpb_config_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t val, unsigned size)
 {
-    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
+    pci_data_write(opaque, vpb_pci_config_addr(addr), val, size);
 }
 
-static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
-                                   uint32_t val)
-{
-    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
-}
-
-static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
-                                   uint32_t val)
-{
-    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
-}
-
-static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
-    return val;
-}
-
-static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
-    return val;
-}
-
-static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t pci_vpb_config_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
 {
     uint32_t val;
-    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
+    val = pci_data_read(opaque, vpb_pci_config_addr(addr), size);
     return val;
 }
 
-static CPUWriteMemoryFunc * const pci_vpb_config_write[] = {
-    &pci_vpb_config_writeb,
-    &pci_vpb_config_writew,
-    &pci_vpb_config_writel,
-};
-
-static CPUReadMemoryFunc * const pci_vpb_config_read[] = {
-    &pci_vpb_config_readb,
-    &pci_vpb_config_readw,
-    &pci_vpb_config_readl,
+static const MemoryRegionOps pci_vpb_config_ops = {
+    .read = pci_vpb_config_read,
+    .write = pci_vpb_config_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
@@ -86,20 +58,6 @@ static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[irq_num], level);
 }
 
-static void pci_vpb_map(SysBusDevice *dev, target_phys_addr_t base)
-{
-    PCIVPBState *s = (PCIVPBState *)dev;
-    /* Selfconfig area.  */
-    cpu_register_physical_memory(base + 0x01000000, 0x1000000, s->mem_config);
-    /* Normal config area.  */
-    cpu_register_physical_memory(base + 0x02000000, 0x1000000, s->mem_config);
-
-    if (s->realview) {
-        /* IO memory area.  */
-        isa_mmio_init(base + 0x03000000, 0x00100000);
-    }
-}
-
 static int pci_vpb_init(SysBusDevice *dev)
 {
     PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
@@ -111,14 +69,26 @@ static int pci_vpb_init(SysBusDevice *dev)
     }
     bus = pci_register_bus(&dev->qdev, "pci",
                            pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
+                           get_system_memory(), get_system_io(),
                            PCI_DEVFN(11, 0), 4);
 
     /* ??? Register memory space.  */
 
-    s->mem_config = cpu_register_io_memory(pci_vpb_config_read,
-                                           pci_vpb_config_write, bus,
-                                           DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio_cb(dev, 0x04000000, pci_vpb_map);
+    /* Our memory regions are:
+     * 0 : PCI self config window
+     * 1 : PCI config window
+     * 2 : PCI IO window (realview_pci only)
+     */
+    memory_region_init_io(&s->mem_config, &pci_vpb_config_ops, bus,
+                          "pci-vpb-selfconfig", 0x1000000);
+    sysbus_init_mmio_region(dev, &s->mem_config);
+    memory_region_init_io(&s->mem_config2, &pci_vpb_config_ops, bus,
+                          "pci-vpb-config", 0x1000000);
+    sysbus_init_mmio_region(dev, &s->mem_config2);
+    if (s->realview) {
+        isa_mmio_setup(&s->isa, 0x0100000);
+        sysbus_init_mmio_region(dev, &s->isa);
+    }
 
     pci_create_simple(bus, -1, "versatile_pci_host");
     return 0;
@@ -133,12 +103,8 @@ static int pci_realview_init(SysBusDevice *dev)
 
 static int versatile_pci_host_init(PCIDevice *d)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX);
-    /* Both boards have the same device ID.  Oh well.  */
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30);
     pci_set_word(d->config + PCI_STATUS,
                 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO);
     pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
     return 0;
 }
@@ -147,6 +113,10 @@ static PCIDeviceInfo versatile_pci_host_info = {
     .qdev.name = "versatile_pci_host",
     .qdev.size = sizeof(PCIDevice),
     .init      = versatile_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_XILINX,
+    /* Both boards have the same device ID.  Oh well.  */
+    .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
+    .class_id  = PCI_CLASS_PROCESSOR_CO,
 };
 
 static void versatile_pci_register_devices(void)
index 9f1bfcf94143762f66b39747cdb96491767c9882..6370600bb3dbfa008be2ff6450ff3aa4482ade7d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005-2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #include "sysbus.h"
@@ -180,7 +180,9 @@ static void versatile_init(ram_addr_t ram_size,
     qemu_irq *cpu_pic;
     qemu_irq pic[32];
     qemu_irq sic[32];
-    DeviceState *dev;
+    DeviceState *dev, *sysctl;
+    SysBusDevice *busdev;
+    DeviceState *pl041;
     PCIBus *pci_bus;
     NICInfo *nd;
     int n;
@@ -198,7 +200,12 @@ static void versatile_init(ram_addr_t ram_size,
     /* SDRAM at address zero.  */
     cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
 
-    arm_sysctl_init(0x10000000, 0x41007004, 0x02000000);
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
+    qdev_init_nofail(sysctl);
+    qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
+    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+
     cpu_pic = arm_pic_init_cpu(env);
     dev = sysbus_create_varargs("pl190", 0x10140000,
                                 cpu_pic[0], cpu_pic[1], NULL);
@@ -214,8 +221,15 @@ static void versatile_init(ram_addr_t ram_size,
     sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
     sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
 
-    dev = sysbus_create_varargs("versatile_pci", 0x40000000,
-                                sic[27], sic[28], sic[29], sic[30], NULL);
+    dev = qdev_create(NULL, "versatile_pci");
+    busdev = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */
+    sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */
+    sysbus_connect_irq(busdev, 0, sic[27]);
+    sysbus_connect_irq(busdev, 1, sic[28]);
+    sysbus_connect_irq(busdev, 2, sic[29]);
+    sysbus_connect_irq(busdev, 3, sic[30]);
     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
 
     /* The Versatile PCI bridge does not provide access to PCI IO space,
@@ -223,7 +237,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 {
@@ -250,7 +264,9 @@ static void versatile_init(ram_addr_t ram_size,
 
     /* The versatile/PB actually has a modified Color LCD controller
        that includes hardware cursor support from the PL111.  */
-    sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
+    dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
+    /* Wire up the mux control signals from the SYS_CLCD register */
+    qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
 
     sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
     sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
@@ -258,6 +274,13 @@ static void versatile_init(ram_addr_t ram_size,
     /* Add PL031 Real Time Clock. */
     sysbus_create_simple("pl031", 0x101e8000, pic[10]);
 
+    /* Add PL041 AACI Interface to the LM4549 codec */
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, sic[24]);
+
     /* Memory map for Versatile/PB:  */
     /* 0x10000000 System registers.  */
     /* 0x10001000 PCI controller config registers.  */
diff --git a/hw/vexpress.c b/hw/vexpress.c
new file mode 100644 (file)
index 0000000..0940a26
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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, *pl041;
+    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 */
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[11]);
+
+    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("pl111", 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);
index 4954bb18be633bc4bb21a14b1bba3e9f498fa146..f8984c62cb3f55f93a5d4c44d478944a11fc9d1f 100644 (file)
@@ -79,50 +79,61 @@ static void vga_mm_writel (void *opaque,
     vga_ioport_write(&s->vga, addr >> s->it_shift, value);
 }
 
-static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
-    &vga_mm_readb,
-    &vga_mm_readw,
-    &vga_mm_readl,
-};
-
-static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
-    &vga_mm_writeb,
-    &vga_mm_writew,
-    &vga_mm_writel,
+static const MemoryRegionOps vga_mm_ctrl_ops = {
+    .old_mmio = {
+        .read = {
+            vga_mm_readb,
+            vga_mm_readw,
+            vga_mm_readl,
+        },
+        .write = {
+            vga_mm_writeb,
+            vga_mm_writew,
+            vga_mm_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base,
-                        target_phys_addr_t ctrl_base, int it_shift)
+                        target_phys_addr_t ctrl_base, int it_shift,
+                        MemoryRegion *address_space)
 {
-    int s_ioport_ctrl, vga_io_memory;
+    MemoryRegion *s_ioport_ctrl, *vga_io_memory;
 
     s->it_shift = it_shift;
-    s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
-                                           DEVICE_NATIVE_ENDIAN);
+    s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl));
+    memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s,
+                          "vga-mm-ctrl", 0x100000);
+
+    vga_io_memory = g_malloc(sizeof(*vga_io_memory));
+    /* XXX: endianness? */
+    memory_region_init_io(vga_io_memory, &vga_mem_ops, &s->vga,
+                          "vga-mem", 0x20000);
 
     vmstate_register(NULL, 0, &vmstate_vga_common, s);
 
-    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
+    memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl);
     s->vga.bank_offset = 0;
-    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
-    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
+    memory_region_add_subregion(address_space,
+                                vram_base + 0x000a0000, vga_io_memory);
+    memory_region_set_coalescing(vga_io_memory);
 }
 
 int isa_vga_mm_init(target_phys_addr_t vram_base,
-                    target_phys_addr_t ctrl_base, int it_shift)
+                    target_phys_addr_t ctrl_base, int it_shift,
+                    MemoryRegion *address_space)
 {
     ISAVGAMMState *s;
 
-    s = qemu_mallocz(sizeof(*s));
+    s = g_malloc0(sizeof(*s));
 
     vga_common_init(&s->vga, VGA_RAM_SIZE);
-    vga_mm_init(s, vram_base, ctrl_base, it_shift);
+    vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
 
     s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
                                      s->vga.screen_dump, s->vga.text_update, s);
 
-    vga_init_vbe(&s->vga);
+    vga_init_vbe(&s->vga, address_space);
     return 0;
 }
index 304605493a6ec0036b784e67ecb9bc35aae3a807..4825313f675ef7ecafb9b2c1e186b7d5a8918a58 100644 (file)
 #include "qemu-timer.h"
 #include "loader.h"
 
-int isa_vga_init(void)
+typedef struct ISAVGAState {
+    ISADevice dev;
+    struct VGACommonState state;
+} ISAVGAState;
+
+static void vga_reset_isa(DeviceState *dev)
 {
-    VGACommonState *s;
+    ISAVGAState *d = container_of(dev, ISAVGAState, dev.qdev);
+    VGACommonState *s = &d->state;
 
-    s = qemu_mallocz(sizeof(*s));
+    vga_common_reset(s);
+}
 
-    vga_common_init(s, VGA_RAM_SIZE);
-    vga_init(s);
-    vmstate_register(NULL, 0, &vmstate_vga_common, s);
+static int vga_initfn(ISADevice *dev)
+{
+    ISAVGAState *d = DO_UPCAST(ISAVGAState, dev, dev);
+    VGACommonState *s = &d->state;
+    MemoryRegion *vga_io_memory;
+    const MemoryRegionPortio *vga_ports, *vbe_ports;
 
+    vga_common_init(s, VGA_RAM_SIZE);
+    s->legacy_address_space = isa_address_space(dev);
+    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+    isa_register_portio_list(dev, 0x3b0, vga_ports, s, "vga");
+    if (vbe_ports) {
+        isa_register_portio_list(dev, 0x1ce, vbe_ports, s, "vbe");
+    }
+    memory_region_add_subregion_overlap(isa_address_space(dev),
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory, 1);
+    memory_region_set_coalescing(vga_io_memory);
     s->ds = graphic_console_init(s->update, s->invalidate,
                                  s->screen_dump, s->text_update, s);
 
-    vga_init_vbe(s);
+    vga_init_vbe(s, isa_address_space(dev));
     /* ROM BIOS */
     rom_add_vga(VGABIOS_FILENAME);
     return 0;
 }
+
+static ISADeviceInfo vga_info = {
+    .qdev.name     = "isa-vga",
+    .qdev.size     = sizeof(ISAVGAState),
+    .qdev.vmsd     = &vmstate_vga_common,
+    .qdev.reset     = vga_reset_isa,
+    .init          = vga_initfn,
+};
+
+static void vga_register(void)
+{
+    isa_qdev_register(&vga_info);
+}
+device_init(vga_register)
index 098733cf94d0d14e6511c5959705f4386c5a8ef1..6dbde6c02974e6983201489074f19c59ebd52cc8 100644 (file)
 #include "pixel_ops.h"
 #include "qemu-timer.h"
 #include "loader.h"
+#ifdef CONFIG_MARU
+#include "../tizen/src/hw/maru_pci_ids.h"
+#include "../tizen/src/hw/maru_vga_int.h"
+#endif
 
 typedef struct PCIVGAState {
     PCIDevice dev;
     VGACommonState vga;
 } PCIVGAState;
 
+int pci_vga_init(PCIBus *bus)
+{
+    pci_create_simple(bus, -1, "VGA");
+    return 0;
+}
+
 static const VMStateDescription vmstate_vga_pci = {
     .name = "vga",
     .version_id = 2,
@@ -47,95 +57,95 @@ static const VMStateDescription vmstate_vga_pci = {
     }
 };
 
-static void vga_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIVGAState *d = (PCIVGAState *)pci_dev;
-    VGACommonState *s = &d->vga;
-
-    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
-    s->map_addr = addr;
-    s->map_end = addr + s->vram_size;
-    vga_dirty_log_start(s);
-}
-
-static void pci_vga_write_config(PCIDevice *d,
-                                 uint32_t address, uint32_t val, int len)
-{
-    PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
-    VGACommonState *s = &pvs->vga;
-
-    pci_default_write_config(d, address, val, len);
-    if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
-        s->map_addr = 0;
-}
-
 static int pci_vga_initfn(PCIDevice *dev)
 {
      PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
      VGACommonState *s = &d->vga;
-     uint8_t *pci_conf = d->dev.config;
 
      // vga + console init
      vga_common_init(s, VGA_RAM_SIZE);
-     vga_init(s);
+     vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true);
 
      s->ds = graphic_console_init(s->update, s->invalidate,
                                   s->screen_dump, s->text_update, s);
 
-     // dummy VGA (same as Bochs ID)
-     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
-     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
-     pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
-
      /* XXX: VGA_RAM_SIZE must be a power of two */
-     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
 
      if (!dev->rom_bar) {
          /* compatibility with pc-0.13 and older */
-         vga_init_vbe(s);
+         vga_init_vbe(s, pci_address_space(dev));
      }
 
      return 0;
 }
 
-int pci_vga_init(PCIBus *bus)
-{
-    pci_create_simple(bus, -1, "VGA");
-    return 0;
-}
-
 static PCIDeviceInfo vga_info = {
     .qdev.name    = "VGA",
     .qdev.size    = sizeof(PCIVGAState),
     .qdev.vmsd    = &vmstate_vga_pci,
     .no_hotplug   = 1,
     .init         = pci_vga_initfn,
-    .config_write = pci_vga_write_config,
     .romfile      = "vgabios-stdvga.bin",
+
+    /* dummy VGA (same as Bochs ID) */
+    .vendor_id    = PCI_VENDOR_ID_QEMU,
+    .device_id    = PCI_DEVICE_ID_QEMU_VGA,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
 };
 
-int pci_tizen_vga_init(PCIBus *bus)
+#ifdef CONFIG_MARU
+
+int pci_maru_vga_init(PCIBus *bus)
 {
-    pci_create_simple(bus, -1, "TIZEN_VGA");
+    pci_create_simple(bus, -1, "MARU_VGA");
     return 0;
 }
 
-static PCIDeviceInfo tizen_vga_info = {
-    .qdev.name    = "TIZEN_VGA",
+static int maru_pci_vga_initfn(PCIDevice *dev)
+{
+     PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
+     VGACommonState *s = &d->vga;
+
+     // vga + console init
+     maru_vga_common_init(s, VGA_RAM_SIZE);
+     vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true);
+
+     s->ds = graphic_console_init(s->update, s->invalidate,
+                                  s->screen_dump, s->text_update, s);
+
+     /* XXX: VGA_RAM_SIZE must be a power of two */
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+
+     if (!dev->rom_bar) {
+         /* compatibility with pc-0.13 and older */
+         vga_init_vbe(s, pci_address_space(dev));
+     }
+
+     return 0;
+}
+
+static PCIDeviceInfo maru_vga_info = {
+    .qdev.name    = "MARU_VGA",
     .qdev.size    = sizeof(PCIVGAState),
     .qdev.vmsd    = &vmstate_vga_pci,
     .no_hotplug   = 1,
-    .init         = pci_vga_initfn,
-    .config_write = pci_vga_write_config,
-    .romfile      = "vgabios-tizenvga.bin",
+    .init         = maru_pci_vga_initfn,
+    .romfile      = "vgabios-maruvga.bin",
+
+    /* dummy VGA (same as Bochs ID) */
+    .vendor_id    = PCI_VENDOR_ID_QEMU,
+    .device_id    = PCI_DEVICE_ID_QEMU_VGA,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
 };
 
+#endif // CONFIG_MARU
+
 static void vga_register(void)
 {
     pci_qdev_register(&vga_info);
-// by caramis...
-    pci_qdev_register(&tizen_vga_info);
+#ifdef CONFIG_MARU
+    pci_qdev_register(&maru_vga_info);
+#endif
 }
 device_init(vga_register);
old mode 100755 (executable)
new mode 100644 (file)
index a7649ec..ca79aa1
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -28,7 +28,6 @@
 #include "vga_int.h"
 #include "pixel_ops.h"
 #include "qemu-timer.h"
-#include "kvm.h"
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
@@ -150,9 +149,53 @@ static uint16_t expand2[256];
 static uint8_t expand4to8[16];
 
 static void vga_screen_dump(void *opaque, const char *filename);
-static char *screen_dump_filename;
+static const char *screen_dump_filename;
 static DisplayChangeListener *screen_dump_dcl;
 
+static void vga_update_memory_access(VGACommonState *s)
+{
+    MemoryRegion *region, *old_region = s->chain4_alias;
+    target_phys_addr_t base, offset, size;
+
+    s->chain4_alias = NULL;
+
+    if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
+        offset = 0;
+        switch ((s->gr[6] >> 2) & 3) {
+        case 0:
+            base = 0xa0000;
+            size = 0x20000;
+            break;
+        case 1:
+            base = 0xa0000;
+            size = 0x10000;
+            offset = s->bank_offset;
+            break;
+        case 2:
+            base = 0xb0000;
+            size = 0x8000;
+            break;
+        case 3:
+        default:
+            base = 0xb8000;
+            size = 0x8000;
+            break;
+        }
+        base += isa_mem_base;
+        region = g_malloc(sizeof(*region));
+        memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
+        memory_region_add_subregion_overlap(s->legacy_address_space, base,
+                                            region, 2);
+        s->chain4_alias = region;
+    }
+    if (old_region) {
+        memory_region_del_subregion(s->legacy_address_space, old_region);
+        memory_region_destroy(old_region);
+        g_free(old_region);
+        s->plane_updated = 0xf;
+    }
+}
+
 static void vga_dumb_update_retrace_info(VGACommonState *s)
 {
     (void) s;
@@ -261,7 +304,7 @@ static uint8_t vga_precise_retrace(VGACommonState *s)
         int cur_line, cur_line_char, cur_char;
         int64_t cur_tick;
 
-        cur_tick = qemu_get_clock(vm_clock);
+        cur_tick = qemu_get_clock_ns(vm_clock);
 
         cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
         cur_line = cur_char / r->htotal;
@@ -446,6 +489,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
         s->sr[s->sr_index] = val & sr_mask[s->sr_index];
         if (s->sr_index == 1) s->update_retrace_info(s);
+        vga_update_memory_access(s);
         break;
     case 0x3c7:
         s->dac_read_index = val;
@@ -473,6 +517,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
 #endif
         s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+        vga_update_memory_access(s);
         break;
     case 0x3b4:
     case 0x3d4:
@@ -606,6 +651,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
             }
             s->vbe_regs[s->vbe_index] = val;
             s->bank_offset = (val << 16);
+            vga_update_memory_access(s);
             break;
         case VBE_DISPI_INDEX_ENABLE:
             if ((val & VBE_DISPI_ENABLED) &&
@@ -665,6 +711,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
             }
             s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
             s->vbe_regs[s->vbe_index] = val;
+            vga_update_memory_access(s);
             break;
         case VBE_DISPI_INDEX_VIRT_WIDTH:
             {
@@ -708,9 +755,8 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
 #endif
 
 /* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
+uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
 {
-    VGACommonState *s = opaque;
     int memory_map_mode, plane;
     uint32_t ret;
 
@@ -764,28 +810,9 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-    v = vga_mem_readb(opaque, addr);
-    v |= vga_mem_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-    v = vga_mem_readb(opaque, addr);
-    v |= vga_mem_readb(opaque, addr + 1) << 8;
-    v |= vga_mem_readb(opaque, addr + 2) << 16;
-    v |= vga_mem_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
 /* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
 {
-    VGACommonState *s = opaque;
     int memory_map_mode, plane, write_mode, b, func_select, mask;
     uint32_t write_mask, bit_mask, set_mask;
 
@@ -826,7 +853,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+            memory_region_set_dirty(&s->vram, addr);
         }
     } else if (s->gr[5] & 0x10) {
         /* odd/even mode (aka text mode mapping) */
@@ -839,7 +866,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+            memory_region_set_dirty(&s->vram, addr);
         }
     } else {
         /* standard VGA latched access */
@@ -913,24 +940,10 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
                addr * 4, write_mask, val);
 #endif
-        cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
+        memory_region_set_dirty(&s->vram, addr << 2);
     }
 }
 
-static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    vga_mem_writeb(opaque, addr, val & 0xff);
-    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    vga_mem_writeb(opaque, addr, val & 0xff);
-    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
                              const uint8_t *font_ptr, int h,
                              uint32_t fgcol, uint32_t bgcol);
@@ -1273,7 +1286,7 @@ static void vga_draw_text(VGACommonState *s, int full_update)
         s->font_offsets[1] = offset;
         full_update = 1;
     }
-    if (s->plane_updated & (1 << 2)) {
+    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
         /* if the plane 2 was modified since the last display, it
            indicates the font may have been modified */
         s->plane_updated = 0;
@@ -1554,89 +1567,22 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
 
 static void vga_sync_dirty_bitmap(VGACommonState *s)
 {
-    if (s->map_addr)
-        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
-
-    if (s->lfb_vram_mapped) {
-        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
-        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (s->vbe_mapped) {
-        cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                       VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
-    }
-#endif
-
+    memory_region_sync_dirty_bitmap(&s->vram);
 }
 
 void vga_dirty_log_start(VGACommonState *s)
 {
-    if (kvm_enabled() && s->map_addr)
-        kvm_log_start(s->map_addr, s->map_end - s->map_addr);
-
-    if (kvm_enabled() && s->lfb_vram_mapped) {
-        kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
-        kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (kvm_enabled() && s->vbe_mapped) {
-        kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
-    }
-#endif
+    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
 }
 
 void vga_dirty_log_stop(VGACommonState *s)
 {
-    if (kvm_enabled() && s->map_addr)
-       kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
-
-    if (kvm_enabled() && s->lfb_vram_mapped) {
-       kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
-       kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (kvm_enabled() && s->vbe_mapped) {
-       kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
-    }
-#endif
-}
-
-void vga_dirty_log_restart(VGACommonState *s)
-{
-    vga_dirty_log_stop(s);
-    vga_dirty_log_start(s);
+    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
 }
 
 /*
-* graphic modes
-*/
-#if defined (TARGET_I386)
-extern uint8_t overlay0_power;
-extern uint16_t overlay0_left;
-extern uint16_t overlay0_top;
-extern uint16_t overlay0_width;
-extern uint16_t overlay0_height;
-       
-extern uint8_t overlay1_power;
-extern uint16_t overlay1_left;
-extern uint16_t overlay1_top;
-extern uint16_t overlay1_width;
-extern uint16_t overlay1_height;
-       
-extern uint8_t* overlay_ptr;   // pointer in qemu space
-
-/* brightness level :              0,   1,   2,   3,   4,   5,   6,   7,   8,   9 */
-//static const uint8_t brightness_tbl[] = {20, 100, 120, 140, 160, 180, 200, 220, 230, 240};
-static const uint8_t brightness_tbl[] = {20, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120,
-                                                                               130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240};
-extern uint32_t brightness_level;
-extern uint32_t brightness_off;
-#endif
-
+ * graphic modes
+ */
 static void vga_draw_graphic(VGACommonState *s, int full_update)
 {
     int y1, y, update, linesize, y_start, double_scan, mask, depth;
@@ -1693,7 +1639,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         if (depth == 32) {
 #endif
             qemu_free_displaysurface(s->ds);
-            s->ds->surface = qemu_create_displaysurface(s->ds, disp_width, height);
+            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
+                    s->line_offset,
+                    s->vram_ptr + (s->start_addr * 4));
 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
             s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
 #endif
@@ -1793,21 +1741,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         if (!(s->cr[0x17] & 2)) {
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
         }
-        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
-        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
+        page0 = addr & TARGET_PAGE_MASK;
+        page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
         update = full_update |
-            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
-            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+            memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
+            memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
         if ((page1 - page0) > TARGET_PAGE_SIZE) {
             /* if wide line, can use another page */
-            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
-                                                    VGA_DIRTY_FLAG);
+            update |= memory_region_get_dirty(&s->vram,
+                                              page0 + TARGET_PAGE_SIZE,
+                                              DIRTY_MEMORY_VGA);
         }
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
-#if defined (TARGET_I386)
-        update |= 1;   // sucking architecture causes low performance. sorry.
-#endif
         if (update) {
             if (y_start < 0)
                 y_start = y;
@@ -1817,76 +1763,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
                 page_max = page1;
             if (!(is_buffer_shared(s->ds->surface))) {
                 vga_draw_line(s, d, s->vram_ptr + addr, width);
-           }
-#if defined (TARGET_I386)
-           int i;
-           uint8_t *fb_sub;
-           uint8_t *over_sub;
-           uint8_t *dst_sub;
-           uint8_t alpha, c_alpha;
-           uint32_t *dst;
-           uint16_t overlay_bottom;
-
-            if (overlay0_power) {
-                overlay_bottom = overlay0_top + overlay0_height;
-
-                if (overlay0_top <= y && y < overlay_bottom) {
-                    fb_sub = s->vram_ptr + addr + overlay0_left * 4;
-                    over_sub = overlay_ptr + (y - overlay0_top) * overlay0_width * 4;
-                    dst = (uint32_t*)(s->ds->surface->data + addr + overlay0_left * 4);
-    
-                    for (i = 0; i < overlay0_width; i++, fb_sub += 4, over_sub += 4, dst++) {
-                        //alpha = 0x80;
-                        alpha = fb_sub[3];
-                        c_alpha = 0xff - alpha;
-                        //fprintf(stderr, "alpha = %d\n", alpha);
-                        
-                        *dst = ((c_alpha * over_sub[0] + alpha * fb_sub[0]) >> 8) |
-                               ((c_alpha * over_sub[1] + alpha * fb_sub[1]) & 0xFF00) |
-                               (((c_alpha * over_sub[2] + alpha * fb_sub[2]) & 0xFF00) << 8);
-                    }
-                }
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
             }
-
-            if (overlay1_power) {
-                overlay_bottom = overlay1_top + overlay1_height;
-
-                if (overlay1_top <= y && y < overlay_bottom) {
-                    fb_sub = s->vram_ptr + addr + overlay1_left * 4;
-                    over_sub = overlay_ptr + (y - overlay1_top) * overlay1_width * 4 + 0x00400000;
-                    dst = (uint32_t*)(s->ds->surface->data + addr + overlay1_left * 4);
-    
-                    for (i = 0; i < overlay1_width; i++, fb_sub += 4, over_sub += 4, dst++) {
-                        //alpha = 0x80;
-                        alpha = fb_sub[3];
-                        c_alpha = 0xff - alpha;
-                        //fprintf(stderr, "alpha = %d\n", alpha);
-                        
-                        *dst = ((c_alpha * over_sub[0] + alpha * fb_sub[0]) >> 8) |
-                               ((c_alpha * over_sub[1] + alpha * fb_sub[1]) & 0xFF00) |
-                               (((c_alpha * over_sub[2] + alpha * fb_sub[2]) & 0xFF00) << 8);
-                    }
-                }
-            }
-            
-            if( brightness_off ) {
-               alpha = 0x00;
-            }else if (brightness_level < 24) {
-                       alpha = brightness_tbl[brightness_level];
-            }
-
-            if ( brightness_off || brightness_level < 24 ) {
-                dst_sub = s->ds->surface->data + addr;
-                dst = (uint32_t*)(s->ds->surface->data + addr);
-
-                for (i=0; i < disp_width; i++, dst_sub += 4, dst++) {
-                       *dst = ((alpha * dst_sub[0]) >> 8) |
-                                       ((alpha * dst_sub[1]) & 0xFF00) |
-                                       (((alpha * dst_sub[2]) & 0xFF00) << 8);
-                }
-            }
-#endif /* TARGET_I386 */
-
         } else {
             if (y_start >= 0) {
                 /* flush to display */
@@ -1916,8 +1795,10 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     }
     /* reset modified pages */
     if (page_max >= page_min) {
-        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                        VGA_DIRTY_FLAG);
+        memory_region_reset_dirty(&s->vram,
+                                  page_min,
+                                  page_max + TARGET_PAGE_SIZE - page_min,
+                                  DIRTY_MEMORY_VGA);
     }
     memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
 }
@@ -1957,6 +1838,8 @@ static void vga_update_display(void *opaque)
     VGACommonState *s = opaque;
     int full_update, graphic_mode;
 
+    qemu_flush_coalesced_mmio_buffer();
+
     if (ds_get_bits_per_pixel(s->ds) == 0) {
         /* nothing to do */
     } else {
@@ -1996,11 +1879,6 @@ static void vga_invalidate_display(void *opaque)
 
 void vga_common_reset(VGACommonState *s)
 {
-    s->lfb_addr = 0;
-    s->lfb_end = 0;
-    s->map_addr = 0;
-    s->map_end = 0;
-    s->lfb_vram_mapped = 0;
     s->sr_index = 0;
     memset(s->sr, '\0', sizeof(s->sr));
     s->gr_index = 0;
@@ -2057,6 +1935,7 @@ void vga_common_reset(VGACommonState *s)
         memset(&s->retrace_info, 0, sizeof (s->retrace_info));
         break;
     }
+    vga_update_memory_access(s);
 }
 
 static void vga_reset(void *opaque)
@@ -2081,6 +1960,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     char msg_buffer[80];
     int full_update = 0;
 
+    qemu_flush_coalesced_mmio_buffer();
+
     if (!(s->ar_index & 0x20)) {
         graphic_mode = GMODE_BLANK;
     } else {
@@ -2231,16 +2112,30 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     dpy_update(s->ds, 0, 0, s->last_width, height);
 }
 
-CPUReadMemoryFunc * const vga_mem_read[3] = {
-    vga_mem_readb,
-    vga_mem_readw,
-    vga_mem_readl,
-};
+static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_readb(s, addr);
+}
 
-CPUWriteMemoryFunc * const vga_mem_write[3] = {
-    vga_mem_writeb,
-    vga_mem_writew,
-    vga_mem_writel,
+static void vga_mem_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t data, unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_writeb(s, addr, data);
+}
+
+const MemoryRegionOps vga_mem_ops = {
+    .read = vga_mem_read,
+    .write = vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 static int vga_common_post_load(void *opaque, int version_id)
@@ -2326,8 +2221,8 @@ void vga_common_init(VGACommonState *s, int vga_ram_size)
 #else
     s->is_vbe_vmstate = 0;
 #endif
-    s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
-    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
+    memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
     s->vram_size = vga_ram_size;
     s->get_bpp = vga_get_bpp;
     s->get_offsets = vga_get_offsets;
@@ -2347,59 +2242,87 @@ void vga_common_init(VGACommonState *s, int vga_ram_size)
         s->update_retrace_info = vga_precise_update_retrace_info;
         break;
     }
+    vga_dirty_log_start(s);
 }
 
-/* used by both ISA and PCI */
-void vga_init(VGACommonState *s)
-{
-    int vga_io_memory;
+static const MemoryRegionPortio vga_portio_list[] = {
+    { 0x04,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
 
-    qemu_register_reset(vga_reset, s);
+#ifdef CONFIG_BOCHS_VBE
+static const MemoryRegionPortio vbe_portio_list[] = {
+    { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
+# ifdef TARGET_I386
+    { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# else
+    { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# endif
+    PORTIO_END_OF_LIST(),
+};
+#endif /* CONFIG_BOCHS_VBE */
 
-    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
+/* Used by both ISA and PCI */
+MemoryRegion *vga_init_io(VGACommonState *s,
+                          const MemoryRegionPortio **vga_ports,
+                          const MemoryRegionPortio **vbe_ports)
+{
+    MemoryRegion *vga_mem;
 
-    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
-    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
-    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
-    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
+    *vga_ports = vga_portio_list;
+    *vbe_ports = NULL;
+#ifdef CONFIG_BOCHS_VBE
+    *vbe_ports = vbe_portio_list;
+#endif
 
-    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
+    vga_mem = g_malloc(sizeof(*vga_mem));
+    memory_region_init_io(vga_mem, &vga_mem_ops, s,
+                          "vga-lowmem", 0x20000);
 
-    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
-    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
-    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
-    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
-    s->bank_offset = 0;
+    return vga_mem;
+}
 
-#ifdef CONFIG_BOCHS_VBE
-#if defined (TARGET_I386)
-    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
-    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+              MemoryRegion *address_space_io, bool init_vga_ports)
+{
+    MemoryRegion *vga_io_memory;
+    const MemoryRegionPortio *vga_ports, *vbe_ports;
+    PortioList *vga_port_list = g_new(PortioList, 1);
+    PortioList *vbe_port_list = g_new(PortioList, 1);
 
-    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
-    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
-#else
-    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
-    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
+    qemu_register_reset(vga_reset, s);
 
-    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
-    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
-#endif
-#endif /* CONFIG_BOCHS_VBE */
+    s->bank_offset = 0;
 
-    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
-                                           DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 vga_io_memory);
-    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    s->legacy_address_space = address_space;
+
+    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+    memory_region_add_subregion_overlap(address_space,
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory,
+                                        1);
+    memory_region_set_coalescing(vga_io_memory);
+    if (init_vga_ports) {
+        portio_list_init(vga_port_list, vga_ports, s, "vga");
+        portio_list_add(vga_port_list, address_space_io, 0x3b0);
+    }
+    if (vbe_ports) {
+        portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
+        portio_list_add(vbe_port_list, address_space_io, 0x1ce);
+    }
 }
 
-void vga_init_vbe(VGACommonState *s)
+void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
 {
 #ifdef CONFIG_BOCHS_VBE
     /* XXX: use optimized standard vga accesses */
-    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                 VGA_RAM_SIZE, s->vram_offset);
+    memory_region_add_subregion(system_memory,
+                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                &s->vram);
     s->vbe_mapped = 1;
 #endif 
 }
@@ -2411,7 +2334,6 @@ static void vga_save_dpy_update(DisplayState *ds,
 {
     if (screen_dump_filename) {
         ppm_save(screen_dump_filename, ds->surface);
-        screen_dump_filename = NULL;
     }
 }
 
@@ -2430,15 +2352,19 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
     uint32_t v;
     int y, x;
     uint8_t r, g, b;
+    int ret;
+    char *linebuf, *pbuf;
 
     f = fopen(filename, "wb");
     if (!f)
         return -1;
     fprintf(f, "P6\n%d %d\n%d\n",
             ds->width, ds->height, 255);
+    linebuf = g_malloc(ds->width * 3);
     d1 = ds->data;
     for(y = 0; y < ds->height; y++) {
         d = d1;
+        pbuf = linebuf;
         for(x = 0; x < ds->width; x++) {
             if (ds->pf.bits_per_pixel == 32)
                 v = *(uint32_t *)d;
@@ -2450,13 +2376,16 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
                 (ds->pf.gmax + 1);
             b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
                 (ds->pf.bmax + 1);
-            fputc(r, f);
-            fputc(g, f);
-            fputc(b, f);
+            *pbuf++ = r;
+            *pbuf++ = g;
+            *pbuf++ = b;
             d += ds->pf.bytes_per_pixel;
         }
         d1 += ds->linesize;
+        ret = fwrite(linebuf, 1, pbuf - linebuf, f);
+        (void)ret;
     }
+    g_free(linebuf);
     fclose(f);
     return 0;
 }
@@ -2465,7 +2394,7 @@ static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
 {
     DisplayChangeListener *dcl;
 
-    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
     dcl->dpy_update = vga_save_dpy_update;
     dcl->dpy_resize = vga_save_dpy_resize;
     dcl->dpy_refresh = vga_save_dpy_refresh;
@@ -2482,8 +2411,8 @@ static void vga_screen_dump(void *opaque, const char *filename)
     if (!screen_dump_dcl)
         screen_dump_dcl = vga_screen_dump_init(s->ds);
 
-    screen_dump_filename = (char *)filename;
+    screen_dump_filename = filename;
     vga_invalidate_display(s);
     vga_hw_update();
+    screen_dump_filename = NULL;
 }
-
index 9d91ba6e0ae50e8f27d7e59eac3832e770bf9974..4e8568dfd5f035312911f1347c78aa441f878d3a 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <hw/hw.h>
+#include "memory.h"
 
 #define MSR_COLOR_EMULATION 0x01
 #define MSR_PAGE_SELECT     0x20
 #define CONFIG_BOCHS_VBE
 
 #define VBE_DISPI_MAX_XRES              1600
+#if CONFIG_MARU
 #define VBE_DISPI_MAX_YRES              1600
+#else
+#define VBE_DISPI_MAX_YRES              1200
+#endif
 #define VBE_DISPI_MAX_BPP               32
 
 #define VBE_DISPI_INDEX_ID              0x0
@@ -104,15 +109,12 @@ typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
 typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
 
 typedef struct VGACommonState {
+    MemoryRegion *legacy_address_space;
     uint8_t *vram_ptr;
-    ram_addr_t vram_offset;
+    MemoryRegion vram;
     uint32_t vram_size;
-    uint32_t lfb_addr;
-    uint32_t lfb_end;
-    uint32_t map_addr;
-    uint32_t map_end;
-    uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
     uint32_t latch;
+    MemoryRegion *chain4_alias;
     uint8_t sr_index;
     uint8_t sr[256];
     uint8_t gr_index;
@@ -134,7 +136,6 @@ typedef struct VGACommonState {
     int dac_8bit;
     uint8_t palette[768];
     int32_t bank_offset;
-    int vga_io_memory;
     int (*get_bpp)(struct VGACommonState *s);
     void (*get_offsets)(struct VGACommonState *s,
                         uint32_t *pline_offset,
@@ -190,18 +191,21 @@ static inline int c6_to_8(int v)
 }
 
 void vga_common_init(VGACommonState *s, int vga_ram_size);
-void vga_init(VGACommonState *s);
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+              MemoryRegion *address_space_io, bool init_vga_ports);
+MemoryRegion *vga_init_io(VGACommonState *s,
+                          const MemoryRegionPortio **vga_ports,
+                          const MemoryRegionPortio **vbe_ports);
 void vga_common_reset(VGACommonState *s);
 
 void vga_dirty_log_start(VGACommonState *s);
 void vga_dirty_log_stop(VGACommonState *s);
-void vga_dirty_log_restart(VGACommonState *s);
 
 extern const VMStateDescription vmstate_vga_common;
 uint32_t vga_ioport_read(void *opaque, uint32_t addr);
 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
+uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr);
+void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
 int ppm_save(const char *filename, struct DisplaySurface *ds);
 
@@ -219,7 +223,7 @@ void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
                              unsigned int color_xor);
 
 int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
-void vga_init_vbe(VGACommonState *s);
+void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
 
 extern const uint8_t sr_mask[8];
 extern const uint8_t gr_mask[16];
@@ -228,5 +232,4 @@ extern const uint8_t gr_mask[16];
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
 
-extern CPUReadMemoryFunc * const vga_mem_read[3];
-extern CPUWriteMemoryFunc * const vga_mem_write[3];
+extern const MemoryRegionOps vga_mem_ops;
index 6c194f0f810093daf6f0d3de85e82da3343bdbb5..0870cb7d8590db00fdc5ec880386665adc4b1a9e 100644 (file)
@@ -120,7 +120,6 @@ static void vhost_dev_unassign_memory(struct vhost_dev *dev,
         if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
             --dev->mem->nregions;
             --to;
-            assert(to >= 0);
             ++overlap_middle;
             continue;
         }
@@ -253,7 +252,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
     uint64_t log_base;
     int r;
     if (size) {
-        log = qemu_mallocz(size * sizeof *log);
+        log = g_malloc0(size * sizeof *log);
     } else {
         log = NULL;
     }
@@ -263,7 +262,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
     vhost_client_sync_dirty_bitmap(&dev->client, 0,
                                    (target_phys_addr_t)~0x0ull);
     if (dev->log) {
-        qemu_free(dev->log);
+        g_free(dev->log);
     }
     dev->log = log;
     dev->log_size = size;
@@ -297,10 +296,50 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
     return 0;
 }
 
+static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
+                                                     uint64_t start_addr,
+                                                     uint64_t size)
+{
+    int i, n = dev->mem->nregions;
+    for (i = 0; i < n; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+                           start_addr, size)) {
+            return reg;
+        }
+    }
+    return NULL;
+}
+
+static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
+                                 uint64_t start_addr,
+                                 uint64_t size,
+                                 uint64_t uaddr)
+{
+    struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
+    uint64_t reglast;
+    uint64_t memlast;
+
+    if (!reg) {
+        return true;
+    }
+
+    reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+    memlast = range_get_last(start_addr, size);
+
+    /* Need to extend region? */
+    if (start_addr < reg->guest_phys_addr || memlast > reglast) {
+        return true;
+    }
+    /* userspace_addr changed? */
+    return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
+}
+
 static void vhost_client_set_memory(CPUPhysMemoryClient *client,
                                     target_phys_addr_t start_addr,
                                     ram_addr_t size,
-                                    ram_addr_t phys_offset)
+                                    ram_addr_t phys_offset,
+                                    bool log_dirty)
 {
     struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
     ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
@@ -308,10 +347,29 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client,
         (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
     uint64_t log_size;
     int r;
-    dev->mem = qemu_realloc(dev->mem, s);
+
+    dev->mem = g_realloc(dev->mem, s);
+
+    if (log_dirty) {
+        flags = IO_MEM_UNASSIGNED;
+    }
 
     assert(size);
 
+    /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
+    if (flags == IO_MEM_RAM) {
+        if (!vhost_dev_cmp_memory(dev, start_addr, size,
+                                  (uintptr_t)qemu_get_ram_ptr(phys_offset))) {
+            /* Region exists with same address. Nothing to do. */
+            return;
+        }
+    } else {
+        if (!vhost_dev_find_reg(dev, start_addr, size)) {
+            /* Removing region that we don't access. Nothing to do. */
+            return;
+        }
+    }
+
     vhost_dev_unassign_memory(dev, start_addr, size);
     if (flags == IO_MEM_RAM) {
         /* Add given mapping, merging adjacent regions if any */
@@ -427,7 +485,7 @@ static int vhost_client_migration_log(CPUPhysMemoryClient *client,
             return r;
         }
         if (dev->log) {
-            qemu_free(dev->log);
+            g_free(dev->log);
         }
         dev->log = NULL;
         dev->log_size = 0;
@@ -457,11 +515,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
     };
     struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
 
-    if (!vdev->binding->set_host_notifier) {
-        fprintf(stderr, "binding does not support host notifiers\n");
-        return -ENOSYS;
-    }
-
     vq->num = state.num = virtio_queue_get_num(vdev, idx);
     r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
     if (r) {
@@ -509,12 +562,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
         r = -errno;
         goto fail_alloc;
     }
-    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
-    if (r < 0) {
-        fprintf(stderr, "Error binding host notifier: %d\n", -r);
-        goto fail_host_notifier;
-    }
-
     file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
     if (r) {
@@ -533,8 +580,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
 
 fail_call:
 fail_kick:
-    vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
-fail_host_notifier:
 fail_alloc:
     cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
                               0, 0);
@@ -560,12 +605,6 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
         .index = idx,
     };
     int r;
-    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
-    if (r < 0) {
-        fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
-        fflush(stderr);
-    }
-    assert (r >= 0);
     r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
     if (r < 0) {
         fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
@@ -609,7 +648,9 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
     hdev->client.set_memory = vhost_client_set_memory;
     hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap;
     hdev->client.migration_log = vhost_client_migration_log;
-    hdev->mem = qemu_mallocz(offsetof(struct vhost_memory, regions));
+    hdev->client.log_start = NULL;
+    hdev->client.log_stop = NULL;
+    hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
     hdev->log = NULL;
     hdev->log_size = 0;
     hdev->log_enabled = false;
@@ -626,7 +667,7 @@ fail:
 void vhost_dev_cleanup(struct vhost_dev *hdev)
 {
     cpu_unregister_phys_memory_client(&hdev->client);
-    qemu_free(hdev->mem);
+    g_free(hdev->mem);
     close(hdev->control);
 }
 
@@ -637,6 +678,60 @@ bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
         hdev->force;
 }
 
+/* Stop processing guest IO notifications in qemu.
+ * Start processing them in vhost in kernel.
+ */
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+    if (!vdev->binding->set_host_notifier) {
+        fprintf(stderr, "binding does not support host notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, true);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
+            goto fail_vq;
+        }
+    }
+
+    return 0;
+fail_vq:
+    while (--i >= 0) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+fail:
+    return r;
+}
+
+/* Stop processing guest IO notifications in vhost.
+ * Start processing them in qemu.
+ * This might actually run the qemu handlers right away,
+ * so virtio in qemu must be completely setup when this is called.
+ */
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+}
+
+/* Host notifiers must be enabled at this point. */
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
@@ -674,7 +769,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
     if (hdev->log_enabled) {
         hdev->log_size = vhost_get_log_size(hdev);
         hdev->log = hdev->log_size ?
-            qemu_mallocz(hdev->log_size * sizeof *hdev->log) : NULL;
+            g_malloc0(hdev->log_size * sizeof *hdev->log) : NULL;
         r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
                   (uint64_t)(unsigned long)hdev->log);
         if (r < 0) {
@@ -702,6 +797,7 @@ fail:
     return r;
 }
 
+/* Host notifiers must be enabled at this point. */
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
@@ -722,6 +818,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
     assert (r >= 0);
 
     hdev->started = false;
-    qemu_free(hdev->log);
+    g_free(hdev->log);
+    hdev->log = NULL;
     hdev->log_size = 0;
 }
index c8c595a147d48f36b67795d4f33d735005d5a7ca..c9452f073297f96725635d1cf5fa244e56a3a417 100644 (file)
@@ -46,5 +46,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev);
 bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
 
 #endif
index 420e05f112882ade2aab69c3a1ae5facffa02ebb..950a6b8d990389702164e7ceb7b0565d93f1a2c6 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "virtio-net.h"
 #include "vhost_net.h"
+#include "qemu-error.h"
 
 #include "config.h"
 
@@ -50,6 +51,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
     if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
         features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
+    }
     if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
         features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
     }
@@ -65,6 +69,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
     if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
         net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
+    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
+    }
     if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
     }
@@ -85,7 +92,7 @@ struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
                                  bool force)
 {
     int r;
-    struct vhost_net *net = qemu_malloc(sizeof *net);
+    struct vhost_net *net = g_malloc(sizeof *net);
     if (!backend) {
         fprintf(stderr, "vhost-net requires backend to be setup\n");
         goto fail;
@@ -118,7 +125,7 @@ struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
     vhost_net_ack_features(net, 0);
     return net;
 fail:
-    qemu_free(net);
+    g_free(net);
     return NULL;
 }
 
@@ -132,16 +139,22 @@ int vhost_net_start(struct vhost_net *net,
 {
     struct vhost_vring_file file = { };
     int r;
+
+    net->dev.nvqs = 2;
+    net->dev.vqs = net->vqs;
+
+    r = vhost_dev_enable_notifiers(&net->dev, dev);
+    if (r < 0) {
+        goto fail_notifiers;
+    }
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc,
                              sizeof(struct virtio_net_hdr_mrg_rxbuf));
     }
 
-    net->dev.nvqs = 2;
-    net->dev.vqs = net->vqs;
     r = vhost_dev_start(&net->dev, dev);
     if (r < 0) {
-        return r;
+        goto fail_start;
     }
 
     net->vc->info->poll(net->vc, false);
@@ -166,6 +179,9 @@ fail:
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
     }
+fail_start:
+    vhost_dev_disable_notifiers(&net->dev, dev);
+fail_notifiers:
     return r;
 }
 
@@ -183,6 +199,7 @@ void vhost_net_stop(struct vhost_net *net,
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
     }
+    vhost_dev_disable_notifiers(&net->dev, dev);
 }
 
 void vhost_net_cleanup(struct vhost_net *net)
@@ -191,12 +208,13 @@ void vhost_net_cleanup(struct vhost_net *net)
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
     }
-    qemu_free(net);
+    g_free(net);
 }
 #else
 struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
                                  bool force)
 {
+    error_report("vhost-net support is not compiled in");
     return NULL;
 }
 
index fa605158e7564cd5b9be3b7a27b3a90e9c4705c7..5ea0e60e419e8843e33c65ae5a237d77ed542d52 100644 (file)
@@ -34,6 +34,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "qemu-log.h"
+#include "exec-memory.h"
 
 #include "ppc.h"
 #include "ppc4xx.h"
@@ -60,7 +61,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
                                      target_ulong va,
                                      target_phys_addr_t pa)
 {
-    ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
 
     tlb->attr = 0;
     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
@@ -69,7 +70,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
     tlb->RPN = pa & TARGET_PAGE_MASK;
     tlb->PID = 0;
 
-    tlb = &env->tlb[1].tlbe;
+    tlb = &env->tlb.tlbe[1];
     tlb->attr = 0;
     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
     tlb->size = 1 << 31; /* up to 0xffffffff  */
@@ -81,7 +82,6 @@ static void mmubooke_create_initial_mapping(CPUState *env,
 static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
                                     int do_init,
                                     const char *cpu_model,
-                                    clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
                                     uint32_t sysclk)
 {
     CPUState *env;
@@ -93,16 +93,12 @@ static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
         exit(1);
     }
 
-    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
-    cpu_clk->opaque = env;
-    /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
-    tb_clk->opaque = env;
+    ppc_booke_timers_init(env, sysclk, 0/* no flags */);
 
     ppc_dcr_init(env, NULL, NULL);
 
     /* interrupt controller */
-    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
     irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
     ppcuic_init(env, irqs, 0x0C0, 0, 1);
@@ -154,7 +150,7 @@ static int xilinx_load_device_tree(target_phys_addr_t addr,
         path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
         if (path) {
             fdt = load_device_tree(path, &fdt_size);
-            qemu_free(path);
+            g_free(path);
         }
         if (!fdt) {
             return 0;
@@ -173,7 +169,7 @@ static int xilinx_load_device_tree(target_phys_addr_t addr,
         path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
         if (path) {
             fdt_size = load_image_targphys(path, addr, 0x10000);
-            qemu_free(path);
+            g_free(path);
         }
     }
 
@@ -191,14 +187,13 @@ static void virtex_init(ram_addr_t ram_size,
                         const char *kernel_cmdline,
                         const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     DeviceState *dev;
     CPUState *env;
     target_phys_addr_t ram_base = 0;
     DriveInfo *dinfo;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
-    clk_setup_t clk_setup[7];
     int kernel_size;
     int i;
 
@@ -207,17 +202,14 @@ static void virtex_init(ram_addr_t ram_size,
         cpu_model = "440-Xilinx";
     }
 
-    memset(clk_setup, 0, sizeof(clk_setup));
-    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
-                             &clk_setup[1], 400000000);
+    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
     qemu_register_reset(main_cpu_reset, env);
 
     phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
     cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE);
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(0xfc000000, phys_flash,
+    pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                           FLASH_SIZE >> 16,
                           1, 0x89, 0x18, 0x0000, 0x0, 1);
@@ -228,7 +220,8 @@ static void virtex_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+    serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
+                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 62 Mhz.  */
     xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
index 8adddeaa5335e9801b2157c0286ef31a357fa17f..e24a2bf1f36e74722e1f07f65ad8560cc9900354 100644 (file)
@@ -1,7 +1,9 @@
 /*
- * Virtio Block Device
+ * Virtio Balloon Device
  *
  * Copyright IBM, Corp. 2008
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
  *
  * Authors:
  *  Anthony Liguori   <aliguori@us.ibm.com>
 #include "qemu-common.h"
 #include "virtio.h"
 #include "pc.h"
-#include "sysemu.h"
 #include "cpu.h"
-#include "monitor.h"
 #include "balloon.h"
 #include "virtio-balloon.h"
 #include "kvm.h"
-#include "qlist.h"
-#include "qint.h"
-#include "qstring.h"
 
 #if defined(__linux__)
 #include <sys/mman.h>
 #endif
 
-/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
-#define ENABLE_GUEST_STATS   0
-
-
 typedef struct VirtIOBalloon
 {
     VirtIODevice vdev;
@@ -42,8 +35,7 @@ typedef struct VirtIOBalloon
     uint64_t stats[VIRTIO_BALLOON_S_NR];
     VirtQueueElement stats_vq_elem;
     size_t stats_vq_offset;
-    MonitorCompletion *stats_callback;
-    void *stats_opaque_callback_data;
+    DeviceState *qdev;
 } VirtIOBalloon;
 
 static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
@@ -74,31 +66,6 @@ static inline void reset_stats(VirtIOBalloon *dev)
     for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
 }
 
-static void stat_put(QDict *dict, const char *label, uint64_t val)
-{
-    if (val != -1)
-        qdict_put(dict, label, qint_from_int(val));
-}
-
-static QObject *get_stats_qobject(VirtIOBalloon *dev)
-{
-    QDict *dict = qdict_new();
-    uint64_t actual = ram_size - ((uint64_t) dev->actual <<
-                                  VIRTIO_BALLOON_PFN_SHIFT);
-
-    stat_put(dict, "actual", actual);
-#if ENABLE_GUEST_STATS
-    stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
-    stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
-    stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
-    stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
-    stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
-    stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
-#endif
-
-    return QOBJECT(dict);
-}
-
 static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOBalloon *s = to_virtio_balloon(vdev);
@@ -129,20 +96,6 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     }
 }
 
-static void complete_stats_request(VirtIOBalloon *vb)
-{
-    QObject *stats;
-
-    if (!vb->stats_opaque_callback_data)
-        return;
-
-    stats = get_stats_qobject(vb);
-    vb->stats_callback(vb->stats_opaque_callback_data, stats);
-    qobject_decref(stats);
-    vb->stats_opaque_callback_data = NULL;
-    vb->stats_callback = NULL;
-}
-
 static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
@@ -170,8 +123,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
             s->stats[tag] = val;
     }
     s->stats_vq_offset = offset;
-
-    complete_stats_request(s);
 }
 
 static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
@@ -191,7 +142,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)
@@ -200,36 +151,45 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
     return f;
 }
 
-static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
-                                     MonitorCompletion cb, void *cb_data)
+static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
 {
     VirtIOBalloon *dev = opaque;
 
-    if (target > ram_size)
-        target = ram_size;
+#if 0
+    /* Disable guest-provided stats for now. For more details please check:
+     * https://bugzilla.redhat.com/show_bug.cgi?id=623903
+     *
+     * If you do enable it (which is probably not going to happen as we
+     * need a new command for it), remember that you also need to fill the
+     * appropriate members of the BalloonInfo structure so that the stats
+     * are returned to the client.
+     */
+    if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
+        virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
+        virtio_notify(&dev->vdev, dev->svq);
+        return;
+    }
+#endif
+
+    /* Stats are not supported.  Clear out any stale values that might
+     * have been set by a more featureful guest kernel.
+     */
+    reset_stats(dev);
+
+    info->actual = ram_size - ((uint64_t) dev->actual <<
+                               VIRTIO_BALLOON_PFN_SHIFT);
+}
 
+static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
+{
+    VirtIOBalloon *dev = opaque;
+
+    if (target > ram_size) {
+        target = ram_size;
+    }
     if (target) {
         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
         virtio_notify_config(&dev->vdev);
-    } else {
-        /* For now, only allow one request at a time.  This restriction can be
-         * removed later by queueing callback and data pairs.
-         */
-        if (dev->stats_callback != NULL) {
-            return;
-        }
-        dev->stats_callback = cb;
-        dev->stats_opaque_callback_data = cb_data; 
-        if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
-            virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
-            virtio_notify(&dev->vdev, dev->svq);
-        } else {
-            /* Stats are not supported.  Clear out any stale values that might
-             * have been set by a more featureful guest kernel.
-             */
-            reset_stats(dev);
-            complete_stats_request(dev);
-        }
     }
 }
 
@@ -260,6 +220,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
 VirtIODevice *virtio_balloon_init(DeviceState *dev)
 {
     VirtIOBalloon *s;
+    int ret;
 
     s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
                                             VIRTIO_ID_BALLOON,
@@ -269,15 +230,31 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
     s->vdev.set_config = virtio_balloon_set_config;
     s->vdev.get_features = virtio_balloon_get_features;
 
+    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
+                                   virtio_balloon_stat, s);
+    if (ret < 0) {
+        virtio_cleanup(&s->vdev);
+        return NULL;
+    }
+
     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
     s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
 
     reset_stats(s);
-    qemu_add_balloon_handler(virtio_balloon_to_target, s);
 
+    s->qdev = dev;
     register_savevm(dev, "virtio-balloon", -1, 1,
                     virtio_balloon_save, virtio_balloon_load, s);
 
     return &s->vdev;
 }
+
+void virtio_balloon_exit(VirtIODevice *vdev)
+{
+    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+
+    qemu_remove_balloon_handler(s);
+    unregister_savevm(s->qdev, "virtio-balloon", s);
+    virtio_cleanup(vdev);
+}
index e20cf6bc0dbb53aff1b1f7f75a6d3f3cc482ce1e..73300ddc864a31e1b197bc540259f3cb23ab0c35 100644 (file)
@@ -50,6 +50,6 @@ struct virtio_balloon_config
 typedef struct VirtIOBalloonStat {
     uint16_t tag;
     uint64_t val;
-} __attribute__((packed)) VirtIOBalloonStat;
+} QEMU_PACKED VirtIOBalloonStat;
 
 #endif
index 114c63888f999a14cca8de0c9cb5893f73e589df..d6d1f87cda6348414b55d9fe5fe8266a37b07acf 100644 (file)
  *
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "qemu-error.h"
 #include "trace.h"
 #include "blockdev.h"
 #include "virtio-blk.h"
+#include "scsi-defs.h"
 #ifdef __linux__
 # include <scsi/sg.h>
 #endif
@@ -28,8 +29,8 @@ typedef struct VirtIOBlock
     void *rq;
     QEMUBH *bh;
     BlockConf *conf;
+    char *serial;
     unsigned short sector_mask;
-    char sn[BLOCK_SERIAL_STRLEN];
     DeviceState *qdev;
 } VirtIOBlock;
 
@@ -47,6 +48,7 @@ typedef struct VirtIOBlockReq
     struct virtio_scsi_inhdr *scsi;
     QEMUIOVector qiov;
     struct VirtIOBlockReq *next;
+    BlockAcctCookie acct;
 } VirtIOBlockReq;
 
 static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
@@ -58,8 +60,6 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
     stb_p(&req->in->status, status);
     virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
     virtio_notify(&s->vdev, s->vq);
-
-    qemu_free(req);
 }
 
 static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
@@ -78,9 +78,12 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
         req->next = s->rq;
         s->rq = req;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(0);
+        vm_stop(RUN_STATE_IO_ERROR);
+        bdrv_iostatus_set_err(s->bs, error);
     } else {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        bdrv_acct_done(s->bs, &req->acct);
+        g_free(req);
         bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
     }
 
@@ -100,6 +103,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
     }
 
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+    bdrv_acct_done(req->dev->bs, &req->acct);
+    g_free(req);
 }
 
 static void virtio_blk_flush_complete(void *opaque, int ret)
@@ -113,11 +118,13 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
     }
 
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+    bdrv_acct_done(req->dev->bs, &req->acct);
+    g_free(req);
 }
 
 static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
 {
-    VirtIOBlockReq *req = qemu_malloc(sizeof(*req));
+    VirtIOBlockReq *req = g_malloc(sizeof(*req));
     req->dev = s;
     req->qiov.size = 0;
     req->next = NULL;
@@ -130,7 +137,7 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
 
     if (req != NULL) {
         if (!virtqueue_pop(s->vq, &req->elem)) {
-            qemu_free(req);
+            g_free(req);
             return NULL;
         }
     }
@@ -155,6 +162,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
      */
     if (req->elem.out_num < 2 || req->elem.in_num < 3) {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        g_free(req);
         return;
     }
 
@@ -163,6 +171,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
      */
     if (req->elem.out_num > 2 && req->elem.in_num > 3) {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+        g_free(req);
         return;
     }
 
@@ -223,17 +232,32 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
         status = VIRTIO_BLK_S_OK;
     }
 
-    stl_p(&req->scsi->errors, hdr.status);
+    /*
+     * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
+     * clear the masked_status field [hence status gets cleared too, see
+     * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
+     * status has occurred.  However they do set DRIVER_SENSE in driver_status
+     * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
+     */
+    if (hdr.status == 0 && hdr.sb_len_wr > 0) {
+        hdr.status = CHECK_CONDITION;
+    }
+
+    stl_p(&req->scsi->errors,
+          hdr.status | (hdr.msg_status << 8) |
+          (hdr.host_status << 16) | (hdr.driver_status << 24));
     stl_p(&req->scsi->residual, hdr.resid);
     stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
     stl_p(&req->scsi->data_len, hdr.dxfer_len);
 
     virtio_blk_req_complete(req, status);
+    g_free(req);
 }
 #else
 static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 {
     virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+    g_free(req);
 }
 #endif /* __linux__ */
 
@@ -266,6 +290,8 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
 {
     BlockDriverAIOCB *acb;
 
+    bdrv_acct_start(req->dev->bs, &req->acct, 0, BDRV_ACCT_FLUSH);
+
     /*
      * Make sure all outstanding writes are posted to the backing device.
      */
@@ -284,6 +310,8 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
 
     sector = ldq_p(&req->out->sector);
 
+    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
+
     trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
 
     if (sector & req->dev->sector_mask) {
@@ -317,6 +345,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
 
     sector = ldq_p(&req->out->sector);
 
+    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
+
     if (sector & req->dev->sector_mask) {
         virtio_blk_rw_complete(req, -EIO);
         return;
@@ -362,9 +392,15 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
     } else if (type & VIRTIO_BLK_T_GET_ID) {
         VirtIOBlock *s = req->dev;
 
-        memcpy(req->elem.in_sg[0].iov_base, s->sn,
-               MIN(req->elem.in_sg[0].iov_len, sizeof(s->sn)));
+        /*
+         * NB: per existing s/n string convention the string is
+         * terminated by '\0' only when shorter than buffer.
+         */
+        strncpy(req->elem.in_sg[0].iov_base,
+                s->serial ? s->serial : "",
+                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+        g_free(req);
     } else if (type & VIRTIO_BLK_T_OUT) {
         qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
                                  req->elem.out_num - 1);
@@ -418,7 +454,8 @@ static void virtio_blk_dma_restart_bh(void *opaque)
     virtio_submit_multiwrite(s->bs, &mrb);
 }
 
-static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
+static void virtio_blk_dma_restart_cb(void *opaque, int running,
+                                      RunState state)
 {
     VirtIOBlock *s = opaque;
 
@@ -448,6 +485,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
     struct virtio_blk_config blkcfg;
     uint64_t capacity;
     int cylinders, heads, secs;
+    int blk_size = s->conf->logical_block_size;
 
     bdrv_get_geometry(s->bs, &capacity);
     bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
@@ -455,14 +493,14 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
     stq_raw(&blkcfg.capacity, capacity);
     stl_raw(&blkcfg.seg_max, 128 - 2);
     stw_raw(&blkcfg.cylinders, cylinders);
+    stl_raw(&blkcfg.blk_size, blk_size);
+    stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
+    stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
     blkcfg.heads = heads;
     blkcfg.sectors = secs & ~s->sector_mask;
-    blkcfg.blk_size = s->conf->logical_block_size;
     blkcfg.size_max = 0;
     blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
     blkcfg.alignment_offset = 0;
-    blkcfg.min_io_size = s->conf->min_io_size / blkcfg.blk_size;
-    blkcfg.opt_io_size = s->conf->opt_io_size / blkcfg.blk_size;
     memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
 }
 
@@ -522,16 +560,19 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void virtio_blk_change_cb(void *opaque, int reason)
+static void virtio_blk_resize(void *opaque)
 {
     VirtIOBlock *s = opaque;
 
-    if (reason & CHANGE_SIZE) {
-        virtio_notify_config(&s->vdev);
-    }
+    virtio_notify_config(&s->vdev);
 }
 
-VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
+static const BlockDevOps virtio_block_ops = {
+    .resize_cb = virtio_blk_resize,
+};
+
+VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
+                              char **serial)
 {
     VirtIOBlock *s;
     int cylinders, heads, secs;
@@ -547,6 +588,14 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
         return NULL;
     }
 
+    if (!*serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(conf->bs);
+        if (*dinfo->serial) {
+            *serial = strdup(dinfo->serial);
+        }
+    }
+
     s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
                                           sizeof(struct virtio_blk_config),
                                           sizeof(VirtIOBlock));
@@ -556,26 +605,21 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
     s->vdev.reset = virtio_blk_reset;
     s->bs = conf->bs;
     s->conf = conf;
+    s->serial = *serial;
     s->rq = NULL;
     s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
     bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
 
-    /* NB: per existing s/n string convention the string is terminated
-     * by '\0' only when less than sizeof (s->sn)
-     */
-    dinfo = drive_get_by_blockdev(s->bs);
-    strncpy(s->sn, dinfo->serial, sizeof (s->sn));
-
     s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
 
     qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
     s->qdev = dev;
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
-    bdrv_set_removable(s->bs, 0);
-    bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
-    s->bs->buffer_alignment = conf->logical_block_size;
+    bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
+    bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
 
+    bdrv_iostatus_enable(s->bs);
     add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
 
     return &s->vdev;
@@ -585,4 +629,5 @@ void virtio_blk_exit(VirtIODevice *vdev)
 {
     VirtIOBlock *s = to_virtio_blk(vdev);
     unregister_savevm(s->qdev, "virtio-blk", s);
+    virtio_cleanup(vdev);
 }
index fff46da7db680f44cbc8917406347a6ce4ebb873..244dce45aa31b9f6f85d3135c0d4e6cab3bf9475 100644 (file)
@@ -34,6 +34,8 @@
 #define VIRTIO_BLK_F_WCACHE     9       /* write cache enabled */
 #define VIRTIO_BLK_F_TOPOLOGY   10      /* Topology information is available */
 
+#define VIRTIO_BLK_ID_BYTES     20      /* ID string length */
+
 struct virtio_blk_config
 {
     uint64_t capacity;
@@ -47,7 +49,7 @@ struct virtio_blk_config
     uint8_t alignment_offset;
     uint16_t min_io_size;
     uint32_t opt_io_size;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /* These two define direction. */
 #define VIRTIO_BLK_T_IN         0
index 62624ec7802ee843df47fbe605c6ee6cd328d514..d3351c83ffdf952b5dcbdc72b2c70ecbda070313 100644 (file)
@@ -11,6 +11,8 @@
  */
 
 #include "qemu-char.h"
+#include "qemu-error.h"
+#include "trace.h"
 #include "virtio-serial.h"
 
 typedef struct VirtConsole {
@@ -23,8 +25,42 @@ typedef struct VirtConsole {
 static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
 {
     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    ssize_t ret;
+
+    ret = qemu_chr_fe_write(vcon->chr, buf, len);
+    trace_virtio_console_flush_buf(port->id, len, ret);
+
+    if (ret < 0) {
+        /*
+         * Ideally we'd get a better error code than just -1, but
+         * that's what the chardev interface gives us right now.  If
+         * we had a finer-grained message, like -EPIPE, we could close
+         * this connection.  Absent such error messages, the most we
+         * can do is to return 0 here.
+         *
+         * This will prevent stray -1 values to go to
+         * virtio-serial-bus.c and cause abort()s in
+         * do_flush_queued_data().
+         */
+        ret = 0;
+    }
+    return ret;
+}
 
-    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_fe_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_fe_close(vcon->chr);
 }
 
 /* Readiness of the guest to accept data on a port */
@@ -40,6 +76,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 {
     VirtConsole *vcon = opaque;
 
+    trace_virtio_console_chr_read(vcon->port.id, size);
     virtio_serial_write(&vcon->port, buf, size);
 }
 
@@ -47,6 +84,7 @@ static void chr_event(void *opaque, int event)
 {
     VirtConsole *vcon = opaque;
 
+    trace_virtio_console_chr_event(vcon->port.id, event);
     switch (event) {
     case CHR_EVENT_OPENED:
         virtio_serial_open(&vcon->port);
@@ -57,36 +95,38 @@ static void chr_event(void *opaque, int event)
     }
 }
 
-static int generic_port_init(VirtConsole *vcon, VirtIOSerialDevice *dev)
+static int virtconsole_initfn(VirtIOSerialPort *port)
 {
-    vcon->port.info = dev->info;
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
+                                           vcon->port.dev.info);
+
+    if (port->id == 0 && !info->is_console) {
+        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
+        return -1;
+    }
 
     if (vcon->chr) {
         qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
                               vcon);
-        vcon->port.info->have_data = flush_buf;
+        info->have_data = flush_buf;
+        info->guest_open = guest_open;
+        info->guest_close = guest_close;
     }
-    return 0;
-}
-
-/* Virtio Console Ports */
-static int virtconsole_initfn(VirtIOSerialDevice *dev)
-{
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
 
-    port->is_console = true;
-    return generic_port_init(vcon, dev);
+    return 0;
 }
 
-static int virtconsole_exitfn(VirtIOSerialDevice *dev)
+static int virtconsole_exitfn(VirtIOSerialPort *port)
 {
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
 
     if (vcon->chr) {
-        port->info->have_data = NULL;
-        qemu_chr_close(vcon->chr);
+       /*
+        * Instead of closing the chardev, free it so it can be used
+        * for other purposes.
+        */
+       qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL);
     }
 
     return 0;
@@ -95,13 +135,11 @@ static int virtconsole_exitfn(VirtIOSerialDevice *dev)
 static VirtIOSerialPortInfo virtconsole_info = {
     .qdev.name     = "virtconsole",
     .qdev.size     = sizeof(VirtConsole),
+    .is_console    = true,
     .init          = virtconsole_initfn,
     .exit          = virtconsole_exitfn,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
-        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-        DEFINE_PROP_STRING("name", VirtConsole, port.name),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
@@ -112,24 +150,13 @@ static void virtconsole_register(void)
 }
 device_init(virtconsole_register)
 
-/* Generic Virtio Serial Ports */
-static int virtserialport_initfn(VirtIOSerialDevice *dev)
-{
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-
-    return generic_port_init(vcon, dev);
-}
-
 static VirtIOSerialPortInfo virtserialport_info = {
     .qdev.name     = "virtserialport",
     .qdev.size     = sizeof(VirtConsole),
-    .init          = virtserialport_initfn,
+    .init          = virtconsole_initfn,
     .exit          = virtconsole_exitfn,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-        DEFINE_PROP_STRING("name", VirtConsole, port.name),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
index e9775a6e737c73a87c0762f58c7dd68ee3d454fc..8c2f4601470c5727b43ba82f12ccf1bd0bdca20f 100644 (file)
@@ -115,7 +115,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
     if (!tap_get_vhost_net(n->nic->nc.peer)) {
         return;
     }
-    if (!!n->vhost_started == virtio_net_started(n, status)) {
+    if (!!n->vhost_started == virtio_net_started(n, status) &&
+                              !n->nic->nc.peer->link_down) {
         return;
     }
     if (!n->vhost_started) {
@@ -149,7 +150,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
     if (virtio_net_started(n, status) && !n->vhost_started) {
         if (n->tx_timer) {
             qemu_mod_timer(n->tx_timer,
-                           qemu_get_clock(vm_clock) + n->tx_timeout);
+                           qemu_get_clock_ns(vm_clock) + n->tx_timeout);
         } else {
             qemu_bh_schedule(n->tx_bh);
         }
@@ -656,7 +657,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         /* copy in packet.  ugh */
         len = iov_from_buf(sg, elem.in_num,
-                           buf + offset, size - offset);
+                           buf + offset, 0, size - offset);
         total += len;
         offset += len;
         /* If buffers can't be merged, at this point we
@@ -784,7 +785,7 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
         virtio_net_flush_tx(n, vq);
     } else {
         qemu_mod_timer(n->tx_timer,
-                       qemu_get_clock(vm_clock) + n->tx_timeout);
+                       qemu_get_clock_ns(vm_clock) + n->tx_timeout);
         n->tx_waiting = 1;
         virtio_queue_set_notification(vq, 0);
     }
@@ -1018,7 +1019,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
 
     if (net->tx && !strcmp(net->tx, "timer")) {
         n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_timer);
-        n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
+        n->tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, n);
         n->tx_timeout = net->txtimer;
     } else {
         n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh);
@@ -1038,9 +1039,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
     n->mergeable_rx_bufs = 0;
     n->promisc = 1; /* for compatibility */
 
-    n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
+    n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
 
-    n->vlans = qemu_mallocz(MAX_VLAN >> 3);
+    n->vlans = g_malloc0(MAX_VLAN >> 3);
 
     n->qdev = dev;
     register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
@@ -1062,8 +1063,8 @@ void virtio_net_exit(VirtIODevice *vdev)
 
     unregister_savevm(n->qdev, "virtio-net", n);
 
-    qemu_free(n->mac_table.macs);
-    qemu_free(n->vlans);
+    g_free(n->mac_table.macs);
+    g_free(n->vlans);
 
     if (n->tx_timer) {
         qemu_del_timer(n->tx_timer);
@@ -1072,6 +1073,6 @@ void virtio_net_exit(VirtIODevice *vdev)
         qemu_bh_delete(n->tx_bh);
     }
 
-    virtio_cleanup(&n->vdev);
     qemu_del_vlan_client(&n->nic->nc);
+    virtio_cleanup(&n->vdev);
 }
index 8af9a1ce55fd8d8814d02cd8906e7c7c6d76c194..44687414c95cb5ac8f283cb9b839af95dc9af971 100644 (file)
@@ -72,7 +72,7 @@ struct virtio_net_config
     uint8_t mac[ETH_ALEN];
     /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
     uint16_t status;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /* This is the first element of the scatter-gather list.  If you don't
  * specify GSO or CSUM features, you can simply ignore the header. */
index 5a3acdec83b181bf5870a54aa25382e38f63272e..8fb8b9f1d2809c9a1ce4279869fd6d4973797f0d 100644 (file)
@@ -18,6 +18,7 @@
 #include "virtio.h"
 #include "virtio-blk.h"
 #include "virtio-net.h"
+#include "virtio-serial.h"
 #include "pci.h"
 #include "qemu-error.h"
 #include "msix.h"
@@ -25,6 +26,8 @@
 #include "loader.h"
 #include "kvm.h"
 #include "blockdev.h"
+#include "virtio-pci.h"
+#include "range.h"
 
 /* from Linux's linux/virtio_pci.h */
 
 #define VIRTIO_PCI_CONFIG_NOMSI         20
 #define VIRTIO_PCI_CONFIG_MSI           24
 #define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
-VIRTIO_PCI_CONFIG_MSI : \
-               VIRTIO_PCI_CONFIG_NOMSI)
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
 
 /* The remaining space is defined by each driver as the per-driver
  * configuration space */
 #define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
-               VIRTIO_PCI_CONFIG_MSI : \
-               VIRTIO_PCI_CONFIG_NOMSI)
-
-/* Virtio ABI version, if we increment this, we break the guest driver. */
-#define VIRTIO_PCI_ABI_VERSION          0
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
 
 /* How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size. */
@@ -83,885 +83,826 @@ VIRTIO_PCI_CONFIG_MSI : \
 /* Flags track per-device state like workarounds for quirks in older guests. */
 #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
 
-/* Performance improves when virtqueue kick processing is decoupled from the
- * vcpu thread using ioeventfd for some devices. */
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
-
 /* QEMU doesn't strictly need write barriers since everything runs in
  * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
  * KVM or if kqemu gets SMP support.
  */
 #define wmb() do { } while (0)
 
-/* PCI bindings.  */
-
-typedef struct {
-       PCIDevice pci_dev;
-       VirtIODevice *vdev;
-       uint32_t flags;
-       uint32_t addr;
-       uint32_t class_code;
-       uint32_t nvectors;
-       BlockConf block;
-       NICConf nic;
-       uint32_t host_features;
-#ifdef CONFIG_LINUX
-       V9fsConf fsconf;
-#endif
-       /* Max. number of ports we can have for a the virtio-serial device */
-       uint32_t max_virtserial_ports;
-       virtio_net_conf net;
-       bool ioeventfd_disabled;
-       bool ioeventfd_started;
-} VirtIOPCIProxy;
-
 /* virtio device */
 
 static void virtio_pci_notify(void *opaque, uint16_t vector)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       if (msix_enabled(&proxy->pci_dev))
-               msix_notify(&proxy->pci_dev, vector);
-       else
-               qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
+    VirtIOPCIProxy *proxy = opaque;
+    if (msix_enabled(&proxy->pci_dev))
+        msix_notify(&proxy->pci_dev, vector);
+    else
+        qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
 }
 
 static void virtio_pci_save_config(void * opaque, QEMUFile *f)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       pci_device_save(&proxy->pci_dev, f);
-       msix_save(&proxy->pci_dev, f);
-       if (msix_present(&proxy->pci_dev))
-               qemu_put_be16(f, proxy->vdev->config_vector);
+    VirtIOPCIProxy *proxy = opaque;
+    pci_device_save(&proxy->pci_dev, f);
+    msix_save(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, proxy->vdev->config_vector);
 }
 
 static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       if (msix_present(&proxy->pci_dev))
-               qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
+    VirtIOPCIProxy *proxy = opaque;
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
 }
 
 static int virtio_pci_load_config(void * opaque, QEMUFile *f)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       int ret;
-       ret = pci_device_load(&proxy->pci_dev, f);
-       if (ret) {
-               return ret;
-       }
-       msix_load(&proxy->pci_dev, f);
-       if (msix_present(&proxy->pci_dev)) {
-               qemu_get_be16s(f, &proxy->vdev->config_vector);
-       } else {
-               proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
-       }
-       if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
-               return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
-       }
-       return 0;
+    VirtIOPCIProxy *proxy = opaque;
+    int ret;
+    ret = pci_device_load(&proxy->pci_dev, f);
+    if (ret) {
+        return ret;
+    }
+    msix_load(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &proxy->vdev->config_vector);
+    } else {
+        proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
+    }
+    if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
+    }
+    return 0;
 }
 
 static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint16_t vector;
-       if (msix_present(&proxy->pci_dev)) {
-               qemu_get_be16s(f, &vector);
-       } else {
-               vector = VIRTIO_NO_VECTOR;
-       }
-       virtio_queue_set_vector(proxy->vdev, n, vector);
-       if (vector != VIRTIO_NO_VECTOR) {
-               return msix_vector_use(&proxy->pci_dev, vector);
-       }
-       return 0;
+    VirtIOPCIProxy *proxy = opaque;
+    uint16_t vector;
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &vector);
+    } else {
+        vector = VIRTIO_NO_VECTOR;
+    }
+    virtio_queue_set_vector(proxy->vdev, n, vector);
+    if (vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, vector);
+    }
+    return 0;
 }
 
 static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
-               int n, bool assign)
-{
-       VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
-       EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
-       int r;
-       if (assign) {
-               r = event_notifier_init(notifier, 1);
-               if (r < 0) {
-                       error_report("%s: unable to init event notifier: %d",
-                                       __func__, r);
-                       return r;
-               }
-               r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
-                               proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
-                               n, assign);
-               if (r < 0) {
-                       error_report("%s: unable to map ioeventfd: %d",
-                                       __func__, r);
-                       event_notifier_cleanup(notifier);
-               }
-       } else {
-               r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
-                               proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
-                               n, assign);
-               if (r < 0) {
-                       error_report("%s: unable to unmap ioeventfd: %d",
-                                       __func__, r);
-                       return r;
-               }
-
-               /* Handle the race condition where the guest kicked and we deassigned
-                * before we got around to handling the kick.
-                */
-               if (event_notifier_test_and_clear(notifier)) {
-                       virtio_queue_notify_vq(vq);
-               }
-
-               event_notifier_cleanup(notifier);
-       }
-       return r;
+                                                 int n, bool assign)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+    int r = 0;
+
+    if (assign) {
+        r = event_notifier_init(notifier, 1);
+        if (r < 0) {
+            error_report("%s: unable to init event notifier: %d",
+                         __func__, r);
+            return r;
+        }
+        memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, event_notifier_get_fd(notifier));
+    } else {
+        memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, event_notifier_get_fd(notifier));
+        /* Handle the race condition where the guest kicked and we deassigned
+         * before we got around to handling the kick.
+         */
+        if (event_notifier_test_and_clear(notifier)) {
+            virtio_queue_notify_vq(vq);
+        }
+
+        event_notifier_cleanup(notifier);
+    }
+    return r;
 }
 
 static void virtio_pci_host_notifier_read(void *opaque)
 {
-       VirtQueue *vq = opaque;
-       EventNotifier *n = virtio_queue_get_host_notifier(vq);
-       if (event_notifier_test_and_clear(n)) {
-               virtio_queue_notify_vq(vq);
-       }
+    VirtQueue *vq = opaque;
+    EventNotifier *n = virtio_queue_get_host_notifier(vq);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_queue_notify_vq(vq);
+    }
 }
 
 static void virtio_pci_set_host_notifier_fd_handler(VirtIOPCIProxy *proxy,
-               int n, bool assign)
-{
-       VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
-       EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
-       if (assign) {
-               qemu_set_fd_handler(event_notifier_get_fd(notifier),
-                               virtio_pci_host_notifier_read, NULL, vq);
-       } else {
-               qemu_set_fd_handler(event_notifier_get_fd(notifier),
-                               NULL, NULL, NULL);
-       }
+                                                    int n, bool assign)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+    if (assign) {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            virtio_pci_host_notifier_read, NULL, vq);
+    } else {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            NULL, NULL, NULL);
+    }
 }
 
 static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
 {
-       int n, r;
+    int n, r;
 
-       if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
-                       proxy->ioeventfd_disabled ||
-                       proxy->ioeventfd_started) {
-               return;
-       }
+    if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
+        proxy->ioeventfd_disabled ||
+        proxy->ioeventfd_started) {
+        return;
+    }
 
-       for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
-               if (!virtio_queue_get_num(proxy->vdev, n)) {
-                       continue;
-               }
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
 
-               r = virtio_pci_set_host_notifier_internal(proxy, n, true);
-               if (r < 0) {
-                       goto assign_error;
-               }
+        r = virtio_pci_set_host_notifier_internal(proxy, n, true);
+        if (r < 0) {
+            goto assign_error;
+        }
 
-               virtio_pci_set_host_notifier_fd_handler(proxy, n, true);
-       }
-       proxy->ioeventfd_started = true;
-       return;
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, true);
+    }
+    proxy->ioeventfd_started = true;
+    return;
 
 assign_error:
-       while (--n >= 0) {
-               if (!virtio_queue_get_num(proxy->vdev, n)) {
-                       continue;
-               }
-
-               virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
-               r = virtio_pci_set_host_notifier_internal(proxy, n, false);
-               assert(r >= 0);
-       }
-       proxy->ioeventfd_started = false;
-       error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+    while (--n >= 0) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
+    error_report("%s: failed. Fallback to a userspace (slower).", __func__);
 }
 
 static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
 {
-       int r;
-       int n;
+    int r;
+    int n;
 
-       if (!proxy->ioeventfd_started) {
-               return;
-       }
+    if (!proxy->ioeventfd_started) {
+        return;
+    }
 
-       for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
-               if (!virtio_queue_get_num(proxy->vdev, n)) {
-                       continue;
-               }
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
 
-               virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
-               r = virtio_pci_set_host_notifier_internal(proxy, n, false);
-               assert(r >= 0);
-       }
-       proxy->ioeventfd_started = false;
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
 }
 
-static void virtio_pci_reset(DeviceState *d)
+void virtio_pci_reset(DeviceState *d)
 {
-       VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
-       virtio_pci_stop_ioeventfd(proxy);
-       virtio_reset(proxy->vdev);
-       msix_reset(&proxy->pci_dev);
-       proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+    VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_reset(proxy->vdev);
+    msix_reset(&proxy->pci_dev);
+    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
 }
 
 static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       VirtIODevice *vdev = proxy->vdev;
-       target_phys_addr_t pa;
-
-       switch (addr) {
-               case VIRTIO_PCI_GUEST_FEATURES:
-                       /* Guest does not negotiate properly?  We have to assume nothing. */
-                       if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
-                               if (vdev->bad_features)
-                                       val = proxy->host_features & vdev->bad_features(vdev);
-                               else
-                                       val = 0;
-                       }
-                       if (vdev->set_features)
-                               vdev->set_features(vdev, val);
-                       vdev->guest_features = val;
-                       break;
-               case VIRTIO_PCI_QUEUE_PFN:
-                       pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
-                       if (pa == 0) {
-                               virtio_pci_stop_ioeventfd(proxy);
-                               virtio_reset(proxy->vdev);
-                               msix_unuse_all_vectors(&proxy->pci_dev);
-                       }
-                       else
-                               virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
-                       break;
-               case VIRTIO_PCI_QUEUE_SEL:
-                       if (val < VIRTIO_PCI_QUEUE_MAX)
-                               vdev->queue_sel = val;
-                       break;
-               case VIRTIO_PCI_QUEUE_NOTIFY:
-                       virtio_queue_notify(vdev, val);
-                       break;
-               case VIRTIO_PCI_STATUS:
-                       if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
-                               virtio_pci_stop_ioeventfd(proxy);
-                       }
-
-                       virtio_set_status(vdev, val & 0xFF);
-
-                       if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
-                               virtio_pci_start_ioeventfd(proxy);
-                       }
-
-                       if (vdev->status == 0) {
-                               virtio_reset(proxy->vdev);
-                               msix_unuse_all_vectors(&proxy->pci_dev);
-                       }
-
-                       /* Linux before 2.6.34 sets the device as OK without enabling
-                          the PCI device bus master bit. In this case we need to disable
-                          some safety checks. */
-                       if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
-                                       !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-                               proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-                       }
-                       break;
-               case VIRTIO_MSI_CONFIG_VECTOR:
-                       msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
-                       /* Make it possible for guest to discover an error took place. */
-                       if (msix_vector_use(&proxy->pci_dev, val) < 0)
-                               val = VIRTIO_NO_VECTOR;
-                       vdev->config_vector = val;
-                       break;
-               case VIRTIO_MSI_QUEUE_VECTOR:
-                       msix_vector_unuse(&proxy->pci_dev,
-                                       virtio_queue_vector(vdev, vdev->queue_sel));
-                       /* Make it possible for guest to discover an error took place. */
-                       if (msix_vector_use(&proxy->pci_dev, val) < 0)
-                               val = VIRTIO_NO_VECTOR;
-                       virtio_queue_set_vector(vdev, vdev->queue_sel, val);
-                       break;
-               default:
-                       error_report("%s: unexpected address 0x%x value 0x%x",
-                                       __func__, addr, val);
-                       break;
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    target_phys_addr_t pa;
+
+    switch (addr) {
+    case VIRTIO_PCI_GUEST_FEATURES:
+       /* Guest does not negotiate properly?  We have to assume nothing. */
+       if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
+            val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
        }
+        virtio_set_features(vdev, val);
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        if (pa == 0) {
+            virtio_pci_stop_ioeventfd(proxy);
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+        else
+            virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        if (val < VIRTIO_PCI_QUEUE_MAX)
+            vdev->queue_sel = val;
+        break;
+    case VIRTIO_PCI_QUEUE_NOTIFY:
+        if (val < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, val);
+        }
+        break;
+    case VIRTIO_PCI_STATUS:
+        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+            virtio_pci_stop_ioeventfd(proxy);
+        }
+
+        virtio_set_status(vdev, val & 0xFF);
+
+        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
+            virtio_pci_start_ioeventfd(proxy);
+        }
+
+        if (vdev->status == 0) {
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+
+        /* Linux before 2.6.34 sets the device as OK without enabling
+           the PCI device bus master bit. In this case we need to disable
+           some safety checks. */
+        if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        vdev->config_vector = val;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev,
+                          virtio_queue_vector(vdev, vdev->queue_sel));
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        virtio_queue_set_vector(vdev, vdev->queue_sel, val);
+        break;
+    default:
+        error_report("%s: unexpected address 0x%x value 0x%x",
+                     __func__, addr, val);
+        break;
+    }
 }
 
 static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
 {
-       VirtIODevice *vdev = proxy->vdev;
-       uint32_t ret = 0xFFFFFFFF;
-
-       switch (addr) {
-               case VIRTIO_PCI_HOST_FEATURES:
-                       ret = proxy->host_features;
-                       break;
-               case VIRTIO_PCI_GUEST_FEATURES:
-                       ret = vdev->guest_features;
-                       break;
-               case VIRTIO_PCI_QUEUE_PFN:
-                       ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
-                               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
-                       break;
-               case VIRTIO_PCI_QUEUE_NUM:
-                       ret = virtio_queue_get_num(vdev, vdev->queue_sel);
-                       break;
-               case VIRTIO_PCI_QUEUE_SEL:
-                       ret = vdev->queue_sel;
-                       break;
-               case VIRTIO_PCI_STATUS:
-                       ret = vdev->status;
-                       break;
-               case VIRTIO_PCI_ISR:
-                       /* reading from the ISR also clears it. */
-                       ret = vdev->isr;
-                       vdev->isr = 0;
-                       qemu_set_irq(proxy->pci_dev.irq[0], 0);
-                       break;
-               case VIRTIO_MSI_CONFIG_VECTOR:
-                       ret = vdev->config_vector;
-                       break;
-               case VIRTIO_MSI_QUEUE_VECTOR:
-                       ret = virtio_queue_vector(vdev, vdev->queue_sel);
-                       break;
-               default:
-                       break;
-       }
-
-       return ret;
+    VirtIODevice *vdev = proxy->vdev;
+    uint32_t ret = 0xFFFFFFFF;
+
+    switch (addr) {
+    case VIRTIO_PCI_HOST_FEATURES:
+        ret = proxy->host_features;
+        break;
+    case VIRTIO_PCI_GUEST_FEATURES:
+        ret = vdev->guest_features;
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
+              >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        break;
+    case VIRTIO_PCI_QUEUE_NUM:
+        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        ret = vdev->queue_sel;
+        break;
+    case VIRTIO_PCI_STATUS:
+        ret = vdev->status;
+        break;
+    case VIRTIO_PCI_ISR:
+        /* reading from the ISR also clears it. */
+        ret = vdev->isr;
+        vdev->isr = 0;
+        qemu_set_irq(proxy->pci_dev.irq[0], 0);
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        ret = vdev->config_vector;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        ret = virtio_queue_vector(vdev, vdev->queue_sel);
+        break;
+    default:
+        break;
+    }
+
+    return ret;
 }
 
 static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config)
-               return virtio_ioport_read(proxy, addr);
-       addr -= config;
-       return virtio_config_readb(proxy->vdev, addr);
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readb(proxy->vdev, addr);
 }
 
 static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config)
-               return virtio_ioport_read(proxy, addr);
-       addr -= config;
-       return virtio_config_readw(proxy->vdev, addr);
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readw(proxy->vdev, addr);
 }
 
 static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config)
-               return virtio_ioport_read(proxy, addr);
-       addr -= config;
-       return virtio_config_readl(proxy->vdev, addr);
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readl(proxy->vdev, addr);
 }
 
 static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config) {
-               virtio_ioport_write(proxy, addr, val);
-               return;
-       }
-       addr -= config;
-       virtio_config_writeb(proxy->vdev, addr, val);
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writeb(proxy->vdev, addr, val);
 }
 
 static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config) {
-               virtio_ioport_write(proxy, addr, val);
-               return;
-       }
-       addr -= config;
-       virtio_config_writew(proxy->vdev, addr, val);
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writew(proxy->vdev, addr, val);
 }
 
 static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-       addr -= proxy->addr;
-       if (addr < config) {
-               virtio_ioport_write(proxy, addr, val);
-               return;
-       }
-       addr -= config;
-       virtio_config_writel(proxy->vdev, addr, val);
-}
-
-static void virtio_map(PCIDevice *pci_dev, int region_num,
-               pcibus_t addr, pcibus_t size, int type)
-{
-       VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
-       VirtIODevice *vdev = proxy->vdev;
-       unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writel(proxy->vdev, addr, val);
+}
+
+const MemoryRegionPortio virtio_portio[] = {
+    { 0, 0x10000, 1, .write = virtio_pci_config_writeb, },
+    { 0, 0x10000, 2, .write = virtio_pci_config_writew, },
+    { 0, 0x10000, 4, .write = virtio_pci_config_writel, },
+    { 0, 0x10000, 1, .read = virtio_pci_config_readb, },
+    { 0, 0x10000, 2, .read = virtio_pci_config_readw, },
+    { 0, 0x10000, 4, .read = virtio_pci_config_readl, },
+    PORTIO_END_OF_LIST()
+};
 
-       proxy->addr = addr;
+static const MemoryRegionOps virtio_pci_config_ops = {
+    .old_portio = virtio_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
-       register_ioport_write(addr, config_len, 1, virtio_pci_config_writeb, proxy);
-       register_ioport_write(addr, config_len, 2, virtio_pci_config_writew, proxy);
-       register_ioport_write(addr, config_len, 4, virtio_pci_config_writel, proxy);
-       register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
-       register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
-       register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
+static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
+                                uint32_t val, int len)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-       if (vdev->config_len)
-               vdev->get_config(vdev, vdev->config);
-}
+    pci_default_write_config(pci_dev, address, val, len);
 
-static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
-               uint32_t val, int len)
-{
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-       if (PCI_COMMAND == address) {
-               if (!(val & PCI_COMMAND_MASTER)) {
-                       if (!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
-                               virtio_pci_stop_ioeventfd(proxy);
-                               virtio_set_status(proxy->vdev,
-                                               proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
-                       }
-               }
-       }
+    if (range_covers_byte(address, len, PCI_COMMAND) &&
+        !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
+        !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
+        virtio_pci_stop_ioeventfd(proxy);
+        virtio_set_status(proxy->vdev,
+                          proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
+    }
 
-       pci_default_write_config(pci_dev, address, val, len);
-       msix_write_config(pci_dev, address, val, len);
+    msix_write_config(pci_dev, address, val, len);
 }
 
 static unsigned virtio_pci_get_features(void *opaque)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       return proxy->host_features;
+    VirtIOPCIProxy *proxy = opaque;
+    return proxy->host_features;
 }
 
 static void virtio_pci_guest_notifier_read(void *opaque)
 {
-       VirtQueue *vq = opaque;
-       EventNotifier *n = virtio_queue_get_guest_notifier(vq);
-       if (event_notifier_test_and_clear(n)) {
-               virtio_irq(vq);
-       }
+    VirtQueue *vq = opaque;
+    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_irq(vq);
+    }
 }
 
 static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
-       EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
-       if (assign) {
-               int r = event_notifier_init(notifier, 0);
-               if (r < 0) {
-                       return r;
-               }
-               qemu_set_fd_handler(event_notifier_get_fd(notifier),
-                               virtio_pci_guest_notifier_read, NULL, vq);
-       } else {
-               qemu_set_fd_handler(event_notifier_get_fd(notifier),
-                               NULL, NULL, NULL);
-               event_notifier_cleanup(notifier);
-       }
+    VirtIOPCIProxy *proxy = opaque;
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+
+    if (assign) {
+        int r = event_notifier_init(notifier, 0);
+        if (r < 0) {
+            return r;
+        }
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            virtio_pci_guest_notifier_read, NULL, vq);
+    } else {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            NULL, NULL, NULL);
+        event_notifier_cleanup(notifier);
+    }
 
-       return 0;
+    return 0;
 }
 
 static bool virtio_pci_query_guest_notifiers(void *opaque)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       return msix_enabled(&proxy->pci_dev);
+    VirtIOPCIProxy *proxy = opaque;
+    return msix_enabled(&proxy->pci_dev);
 }
 
 static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
 {
-       VirtIOPCIProxy *proxy = opaque;
-       VirtIODevice *vdev = proxy->vdev;
-       int r, n;
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    int r, n;
 
-       for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
-               if (!virtio_queue_get_num(vdev, n)) {
-                       break;
-               }
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(vdev, n)) {
+            break;
+        }
 
-               r = virtio_pci_set_guest_notifier(opaque, n, assign);
-               if (r < 0) {
-                       goto assign_error;
-               }
-       }
+        r = virtio_pci_set_guest_notifier(opaque, n, assign);
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
 
-       return 0;
+    return 0;
 
 assign_error:
-       /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
-       while (--n >= 0) {
-               virtio_pci_set_guest_notifier(opaque, n, !assign);
-       }
-       return r;
+    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+    while (--n >= 0) {
+        virtio_pci_set_guest_notifier(opaque, n, !assign);
+    }
+    return r;
 }
 
 static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
 {
-       VirtIOPCIProxy *proxy = opaque;
+    VirtIOPCIProxy *proxy = opaque;
 
-       /* Stop using ioeventfd for virtqueue kick if the device starts using host
-        * notifiers.  This makes it easy to avoid stepping on each others' toes.
-        */
-       proxy->ioeventfd_disabled = assign;
-       if (assign) {
-               virtio_pci_stop_ioeventfd(proxy);
-       }
-       /* We don't need to start here: it's not needed because backend
-        * currently only stops on status change away from ok,
-        * reset, vmstop and such. If we do add code to start here,
-        * need to check vmstate, device state etc. */
-       return virtio_pci_set_host_notifier_internal(proxy, n, assign);
+    /* Stop using ioeventfd for virtqueue kick if the device starts using host
+     * notifiers.  This makes it easy to avoid stepping on each others' toes.
+     */
+    proxy->ioeventfd_disabled = assign;
+    if (assign) {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
+    /* We don't need to start here: it's not needed because backend
+     * currently only stops on status change away from ok,
+     * reset, vmstop and such. If we do add code to start here,
+     * need to check vmstate, device state etc. */
+    return virtio_pci_set_host_notifier_internal(proxy, n, assign);
 }
 
 static void virtio_pci_vmstate_change(void *opaque, bool running)
 {
-       VirtIOPCIProxy *proxy = opaque;
-
-       if (running) {
-               /* Try to find out if the guest has bus master disabled, but is
-                  in ready state. Then we have a buggy guest OS. */
-               if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
-                               !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-                       proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-               }
-               virtio_pci_start_ioeventfd(proxy);
-       } else {
-               virtio_pci_stop_ioeventfd(proxy);
-       }
+    VirtIOPCIProxy *proxy = opaque;
+
+    if (running) {
+        /* Try to find out if the guest has bus master disabled, but is
+           in ready state. Then we have a buggy guest OS. */
+        if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        virtio_pci_start_ioeventfd(proxy);
+    } else {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
 }
 
 static const VirtIOBindings virtio_pci_bindings = {
-       .notify = virtio_pci_notify,
-       .save_config = virtio_pci_save_config,
-       .load_config = virtio_pci_load_config,
-       .save_queue = virtio_pci_save_queue,
-       .load_queue = virtio_pci_load_queue,
-       .get_features = virtio_pci_get_features,
-       .query_guest_notifiers = virtio_pci_query_guest_notifiers,
-       .set_host_notifier = virtio_pci_set_host_notifier,
-       .set_guest_notifiers = virtio_pci_set_guest_notifiers,
-       .vmstate_change = virtio_pci_vmstate_change,
+    .notify = virtio_pci_notify,
+    .save_config = virtio_pci_save_config,
+    .load_config = virtio_pci_load_config,
+    .save_queue = virtio_pci_save_queue,
+    .load_queue = virtio_pci_load_queue,
+    .get_features = virtio_pci_get_features,
+    .query_guest_notifiers = virtio_pci_query_guest_notifiers,
+    .set_host_notifier = virtio_pci_set_host_notifier,
+    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
+    .vmstate_change = virtio_pci_vmstate_change,
 };
 
-static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
-               uint16_t vendor, uint16_t device,
-               uint16_t class_code, uint8_t pif)
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
 {
-       uint8_t *config;
-       uint32_t size;
-
-       proxy->vdev = vdev;
-
-       config = proxy->pci_dev.config;
-       pci_config_set_vendor_id(config, vendor);
-       pci_config_set_device_id(config, device);
+    uint8_t *config;
+    uint32_t size;
 
-       config[0x08] = VIRTIO_PCI_ABI_VERSION;
+    proxy->vdev = vdev;
 
-       config[0x09] = pif;
-       pci_config_set_class(config, class_code);
+    config = proxy->pci_dev.config;
 
-       config[0x2c] = vendor & 0xFF;
-       config[0x2d] = (vendor >> 8) & 0xFF;
-       config[0x2e] = vdev->device_id & 0xFF;
-       config[0x2f] = (vdev->device_id >> 8) & 0xFF;
+    if (proxy->class_code) {
+        pci_config_set_class(config, proxy->class_code);
+    }
+    pci_set_word(config + 0x2c, pci_get_word(config + PCI_VENDOR_ID));
+    pci_set_word(config + 0x2e, vdev->device_id);
+    config[0x3d] = 1;
 
-       config[0x3d] = 1;
+    memory_region_init(&proxy->msix_bar, "virtio-msix", 4096);
+    if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors,
+                                     &proxy->msix_bar, 1, 0)) {
+        pci_register_bar(&proxy->pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         &proxy->msix_bar);
+    } else
+        vdev->nvectors = 0;
 
-       if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
-               pci_register_bar(&proxy->pci_dev, 1,
-                               msix_bar_size(&proxy->pci_dev),
-                               PCI_BASE_ADDRESS_SPACE_MEMORY,
-                               msix_mmio_map);
-       } else
-               vdev->nvectors = 0;
+    proxy->pci_dev.config_write = virtio_write_config;
 
-       proxy->pci_dev.config_write = virtio_write_config;
+    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
+    if (size & (size-1))
+        size = 1 << qemu_fls(size);
 
-       size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
-       if (size & (size-1))
-               size = 1 << qemu_fls(size);
+    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
+                          "virtio-pci", size);
+    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                     &proxy->bar);
 
-       pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
-                       virtio_map);
+    if (!kvm_has_many_ioeventfds()) {
+        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
+    }
 
-       if (!kvm_has_many_ioeventfds()) {
-               proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
-       }
-
-       virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
-       proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
-       proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
-       proxy->host_features = vdev->get_features(vdev, proxy->host_features);
+    virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
+    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
+    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
 }
 
 static int virtio_blk_init_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
 
-       if (proxy->class_code != PCI_CLASS_STORAGE_SCSI &&
-                       proxy->class_code != PCI_CLASS_STORAGE_OTHER)
-               proxy->class_code = PCI_CLASS_STORAGE_SCSI;
+    if (proxy->class_code != PCI_CLASS_STORAGE_SCSI &&
+        proxy->class_code != PCI_CLASS_STORAGE_OTHER)
+        proxy->class_code = PCI_CLASS_STORAGE_SCSI;
 
-       vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
-       if (!vdev) {
-               return -1;
-       }
-       vdev->nvectors = proxy->nvectors;
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       PCI_DEVICE_ID_VIRTIO_BLOCK,
-                       proxy->class_code, 0x00);
-       /* make the actual value visible */
-       proxy->nvectors = vdev->nvectors;
-       return 0;
+    vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block,
+                           &proxy->block_serial);
+    if (!vdev) {
+        return -1;
+    }
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
 }
 
 static int virtio_exit_pci(PCIDevice *pci_dev)
 {
-       return msix_uninit(pci_dev);
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    int r;
+
+    memory_region_destroy(&proxy->bar);
+    r = msix_uninit(pci_dev, &proxy->msix_bar);
+    memory_region_destroy(&proxy->msix_bar);
+    return r;
 }
 
 static int virtio_blk_exit_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-       virtio_pci_stop_ioeventfd(proxy);
-       virtio_blk_exit(proxy->vdev);
-       blockdev_mark_auto_del(proxy->block.bs);
-       return virtio_exit_pci(pci_dev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_blk_exit(proxy->vdev);
+    blockdev_mark_auto_del(proxy->block.bs);
+    return virtio_exit_pci(pci_dev);
 }
 
 static int virtio_serial_init_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
 
-       if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
-                       proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
-                       proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
-               proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
+    if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
+        proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
+        proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
+        proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
 
-       vdev = virtio_serial_init(&pci_dev->qdev, proxy->max_virtserial_ports);
-       if (!vdev) {
-               return -1;
-       }
-       vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
-               ? proxy->max_virtserial_ports + 1
-               : proxy->nvectors;
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       PCI_DEVICE_ID_VIRTIO_CONSOLE,
-                       proxy->class_code, 0x00);
-       proxy->nvectors = vdev->nvectors;
-       return 0;
+    vdev = virtio_serial_init(&pci_dev->qdev, &proxy->serial);
+    if (!vdev) {
+        return -1;
+    }
+    vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
+                                        ? proxy->serial.max_virtserial_ports + 1
+                                        : proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    proxy->nvectors = vdev->nvectors;
+    return 0;
 }
 
 static int virtio_serial_exit_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-       virtio_serial_exit(proxy->vdev);
-       return virtio_exit_pci(pci_dev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_serial_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
 }
 
 static int virtio_net_init_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
 
-       vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
+    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
 
-       vdev->nvectors = proxy->nvectors;
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       PCI_DEVICE_ID_VIRTIO_NET,
-                       PCI_CLASS_NETWORK_ETHERNET,
-                       0x00);
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
 
-       /* make the actual value visible */
-       proxy->nvectors = vdev->nvectors;
-       return 0;
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
 }
 
 static int virtio_net_exit_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-       virtio_pci_stop_ioeventfd(proxy);
-       virtio_net_exit(proxy->vdev);
-       return virtio_exit_pci(pci_dev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_net_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
 }
 
 static int virtio_balloon_init_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
 
-       vdev = virtio_balloon_init(&pci_dev->qdev);
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       PCI_DEVICE_ID_VIRTIO_BALLOON,
-                       PCI_CLASS_MEMORY_RAM,
-                       0x00);
-       return 0;
+    vdev = virtio_balloon_init(&pci_dev->qdev);
+    if (!vdev) {
+        return -1;
+    }
+    virtio_init_pci(proxy, vdev);
+    return 0;
 }
 
-static int virtio_gpi_init_pci(PCIDevice *pci_dev)
+static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-       vdev = virtio_gpi_init(&pci_dev->qdev);
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       PCI_DEVICE_ID_VIRTIO_EXAMPLE,
-                       PCI_CLASS_MEMORY_RAM,
-                       0x00);
-       return 0;
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_balloon_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
 }
 
-#ifdef CONFIG_VIRTFS
-static int virtio_9p_init_pci(PCIDevice *pci_dev)
+#ifndef _WIN32\r
+extern VirtIODevice *virtio_gl_init(DeviceState *dev);
+static int virtio_gl_init_pci(PCIDevice *pci_dev)
 {
-       VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-       VirtIODevice *vdev;
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
 
-       vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
-       vdev->nvectors = proxy->nvectors;
-       virtio_init_pci(proxy, vdev,
-                       PCI_VENDOR_ID_REDHAT_QUMRANET,
-                       0x1009,
-                       0x2,
-                       0x00);
-       /* make the actual value visible */
-       proxy->nvectors = vdev->nvectors;
-       return 0;
+    vdev = virtio_gl_init(&pci_dev->qdev);
+    if (!vdev) {
+        return -1;
+    }
+    virtio_init_pci(proxy, vdev);
+    return 0;
 }
-#endif
+#endif\r
 
 static PCIDeviceInfo virtio_info[] = {
-       {
-               .qdev.name = "virtio-blk-pci",
-               .qdev.alias = "virtio-blk",
+    {
+        .qdev.name = "virtio-blk-pci",
+        .qdev.alias = "virtio-blk",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_blk_init_pci,
+        .exit      = virtio_blk_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_STORAGE_SCSI,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+            DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+            DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+            DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .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.rom",
+        .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id  = PCI_DEVICE_ID_VIRTIO_NET,
+        .revision   = VIRTIO_PCI_ABI_VERSION,
+        .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+            DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+            DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
+                               net.txtimer, TX_TIMER_INTERVAL),
+            DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
+                              net.txburst, TX_BURST),
+            DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+        .qdev.name = "virtio-serial-pci",
+        .qdev.alias = "virtio-serial",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_serial_init_pci,
+        .exit      = virtio_serial_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_COMMUNICATION_OTHER,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                               DEV_NVECTORS_UNSPECIFIED),
+            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy,
+                               serial.max_virtserial_ports, 31),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .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_balloon_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_MEMORY_RAM,
+        .qdev.props = (Property[]) {
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+#ifndef _WIN32\r
+               .qdev.name = "virtio-gl-pci",
+        .qdev.alias = "virtio-gl",
                .qdev.size = sizeof(VirtIOPCIProxy),
-               .init      = virtio_blk_init_pci,
-               .exit      = virtio_blk_exit_pci,
-               .qdev.props = (Property[]) {
-                       DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-                       DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
-                       DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                                       VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-                       DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-                       DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
-                       DEFINE_PROP_END_OF_LIST(),
-               },
-               .qdev.reset = virtio_pci_reset,
-       },{
-               .qdev.name  = "virtio-net-pci",
-               .qdev.size  = sizeof(VirtIOPCIProxy),
-               .init       = virtio_net_init_pci,
-               .exit       = virtio_net_exit_pci,
-               .romfile    = "pxe-virtio.bin",
+               .init      = virtio_gl_init_pci,
+               .exit      = virtio_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_GL,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_OTHERS,
                .qdev.props = (Property[]) {
-                       DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                                       VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
-                       DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
-                       DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
-                       DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
-                       DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
-                                       net.txtimer, TX_TIMER_INTERVAL),
-                       DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
-                                       net.txburst, TX_BURST),
-                       DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
                        DEFINE_PROP_END_OF_LIST(),
                },
                .qdev.reset = virtio_pci_reset,
        },{
-               .qdev.name = "virtio-serial-pci",
-                       .qdev.alias = "virtio-serial",
-                       .qdev.size = sizeof(VirtIOPCIProxy),
-                       .init      = virtio_serial_init_pci,
-                       .exit      = virtio_serial_exit_pci,
-                       .qdev.props = (Property[]) {
-                               DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
-                                               DEV_NVECTORS_UNSPECIFIED),
-                               DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-                               DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-                               DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
-                                               31),
-                               DEFINE_PROP_END_OF_LIST(),
-                       },
-                       .qdev.reset = virtio_pci_reset,
-       },{
-               .qdev.name = "virtio-balloon-pci",
-                       .qdev.size = sizeof(VirtIOPCIProxy),
-                       .init      = virtio_balloon_init_pci,
-                       .exit      = virtio_exit_pci,
-                       .qdev.props = (Property[]) {
-                               DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-                               DEFINE_PROP_END_OF_LIST(),
-                       },
-                       .qdev.reset = virtio_pci_reset,
-       },{
-               .qdev.name = "virtio-gpi-pci",
-                       .qdev.alias = "virtio-gpi",
-                       .qdev.size = sizeof(VirtIOPCIProxy),
-                       .init      = virtio_gpi_init_pci,
-                       .exit      = virtio_exit_pci,
-                       .qdev.props = (Property[]) {
-                               DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-                               DEFINE_PROP_END_OF_LIST(),
-                       },
-                       .qdev.reset = virtio_pci_reset,
-       },{
-#ifdef CONFIG_VIRTFS
-               .qdev.name = "virtio-9p-pci",
-                       .qdev.size = sizeof(VirtIOPCIProxy),
-                       .init      = virtio_9p_init_pci,
-                       .qdev.props = (Property[]) {
-                               DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-                               DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-                               DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
-                               DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
-                               DEFINE_PROP_END_OF_LIST(),
-                       },
-       }, {
-#endif
-               /* end of list */
-       }
+#endif\r
+        /* end of list */
+    }
 };
 
 static void virtio_pci_register_devices(void)
 {
-       pci_qdev_register_many(virtio_info);
+    pci_qdev_register_many(virtio_info);
 }
 
 device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
new file mode 100644 (file)
index 0000000..344c22b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Paul Brook        <paul@codesourcery.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_PCI_H
+#define QEMU_VIRTIO_PCI_H
+
+#include "virtio-net.h"
+#include "virtio-serial.h"
+
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
+
+typedef struct {
+    PCIDevice pci_dev;
+    VirtIODevice *vdev;
+    MemoryRegion bar;
+    MemoryRegion msix_bar;
+    uint32_t flags;
+    uint32_t class_code;
+    uint32_t nvectors;
+    BlockConf block;
+    char *block_serial;
+    NICConf nic;
+    uint32_t host_features;
+#ifdef CONFIG_LINUX
+    V9fsConf fsconf;
+#endif
+    virtio_serial_conf serial;
+    virtio_net_conf net;
+    bool ioeventfd_disabled;
+    bool ioeventfd_started;
+} VirtIOPCIProxy;
+
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
+void virtio_pci_reset(DeviceState *d);
+
+/* Virtio ABI version, if we increment this, we break the guest driver. */
+#define VIRTIO_PCI_ABI_VERSION          0
+
+#endif
index e05ab5e609691f0b04b55f061d16a5302455dfe3..a4825b9eebd4275fb09f6557ff5af528b8ed1d9f 100644 (file)
@@ -19,6 +19,7 @@
 #include "monitor.h"
 #include "qemu-queue.h"
 #include "sysbus.h"
+#include "trace.h"
 #include "virtio-serial.h"
 
 /* The virtio-serial bus on top of which the ports will ride as devices */
@@ -39,7 +40,7 @@ struct VirtIOSerial {
     /* Arrays of ivqs and ovqs: one per port */
     VirtQueue **ivqs, **ovqs;
 
-    VirtIOSerialBus *bus;
+    VirtIOSerialBus bus;
 
     DeviceState *qdev;
 
@@ -103,7 +104,7 @@ static size_t write_to_port(VirtIOSerialPort *port,
         }
 
         len = iov_from_buf(elem.in_sg, elem.in_num,
-                           buf + offset, size - offset);
+                           buf + offset, 0, size - offset);
         offset += len;
 
         virtqueue_push(vq, &elem, len);
@@ -129,9 +130,13 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
 static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                  VirtIODevice *vdev)
 {
+    VirtIOSerialPortInfo *info;
+
     assert(port);
     assert(virtio_queue_ready(vq));
 
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+
     while (!port->throttled) {
         unsigned int i;
 
@@ -149,10 +154,10 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
             ssize_t ret;
 
             buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
-            ret = port->info->have_data(port,
-                                        port->elem.out_sg[i].iov_base
-                                          + port->iov_offset,
-                                        buf_size);
+            ret = info->have_data(port,
+                                  port->elem.out_sg[i].iov_base
+                                  + port->iov_offset,
+                                  buf_size);
             if (ret < 0 && ret != -EAGAIN) {
                 /* We don't handle any other type of errors here */
                 abort();
@@ -217,6 +222,7 @@ static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
     stw_p(&cpkt.event, event);
     stw_p(&cpkt.value, value);
 
+    trace_virtio_serial_send_control_event(port->id, event, value);
     return send_control_msg(port, &cpkt, sizeof(cpkt));
 }
 
@@ -285,24 +291,32 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
     return 0;
 }
 
+static void flush_queued_data_bh(void *opaque)
+{
+    VirtIOSerialPort *port = opaque;
+
+    flush_queued_data(port);
+}
+
 void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
 {
     if (!port) {
         return;
     }
 
+    trace_virtio_serial_throttle_port(port->id, throttle);
     port->throttled = throttle;
     if (throttle) {
         return;
     }
-
-    flush_queued_data(port);
+    qemu_bh_schedule(port->bh);
 }
 
 /* Guest wants to notify us of some event */
 static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
 {
     struct VirtIOSerialPort *port;
+    struct VirtIOSerialPortInfo *info;
     struct virtio_console_control cpkt, *gcpkt;
     uint8_t *buffer;
     size_t buffer_len;
@@ -317,16 +331,13 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
     cpkt.event = lduw_p(&gcpkt->event);
     cpkt.value = lduw_p(&gcpkt->value);
 
-    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
-    if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
-        return;
+    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
 
-    switch(cpkt.event) {
-    case VIRTIO_CONSOLE_DEVICE_READY:
+    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
         if (!cpkt.value) {
-            error_report("virtio-serial-bus: Guest failure in adding device %s\n",
-                         vser->bus->qbus.name);
-            break;
+            error_report("virtio-serial-bus: Guest failure in adding device %s",
+                         vser->bus.qbus.name);
+            return;
         }
         /*
          * The device is up, we can now tell the device about all the
@@ -335,12 +346,25 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
         QTAILQ_FOREACH(port, &vser->ports, next) {
             send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
         }
-        break;
+        return;
+    }
+
+    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+    if (!port) {
+        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
+                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
+        return;
+    }
+
+    trace_virtio_serial_handle_control_message_port(port->id);
 
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+
+    switch(cpkt.event) {
     case VIRTIO_CONSOLE_PORT_READY:
         if (!cpkt.value) {
-            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
-                         port->id, vser->bus->qbus.name);
+            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
+                         port->id, vser->bus.qbus.name);
             break;
         }
         /*
@@ -350,7 +374,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
          * this port is a console port so that the guest can hook it
          * up to hvc.
          */
-        if (port->is_console) {
+        if (info->is_console) {
             send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
         }
 
@@ -359,14 +383,14 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
             stw_p(&cpkt.value, 1);
 
             buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
-            buffer = qemu_malloc(buffer_len);
+            buffer = g_malloc(buffer_len);
 
             memcpy(buffer, &cpkt, sizeof(cpkt));
             memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
             buffer[buffer_len - 1] = 0;
 
             send_control_msg(port, buffer, buffer_len);
-            qemu_free(buffer);
+            g_free(buffer);
         }
 
         if (port->host_connected) {
@@ -379,21 +403,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
          * initialised. If some app is interested in knowing about
          * this event, let it know.
          */
-        if (port->info->guest_ready) {
-            port->info->guest_ready(port);
+        if (info->guest_ready) {
+            info->guest_ready(port);
         }
         break;
 
     case VIRTIO_CONSOLE_PORT_OPEN:
         port->guest_connected = cpkt.value;
-        if (cpkt.value && port->info->guest_open) {
+        if (cpkt.value && info->guest_open) {
             /* Send the guest opened notification if an app is interested */
-            port->info->guest_open(port);
+            info->guest_open(port);
         }
 
-        if (!cpkt.value && port->info->guest_close) {
+        if (!cpkt.value && info->guest_close) {
             /* Send the guest closed notification if an app is interested */
-            port->info->guest_close(port);
+            info->guest_close(port);
         }
         break;
     }
@@ -423,9 +447,9 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
          * if the size of the buf differs
          */
         if (cur_len > len) {
-            qemu_free(buf);
+            g_free(buf);
 
-            buf = qemu_malloc(cur_len);
+            buf = g_malloc(cur_len);
             len = cur_len;
         }
         copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
@@ -433,7 +457,7 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
         handle_control_message(vser, buf, copied);
         virtqueue_push(vq, &elem, 0);
     }
-    qemu_free(buf);
+    g_free(buf);
     virtio_notify(vdev, vq);
 }
 
@@ -442,25 +466,21 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOSerial *vser;
     VirtIOSerialPort *port;
-    bool discard;
+    VirtIOSerialPortInfo *info;
 
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
     port = find_port_by_vq(vser, vq);
+    info = port ? DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info) : NULL;
 
-    discard = false;
-    if (!port || !port->host_connected || !port->info->have_data) {
-        discard = true;
-    }
-
-    if (discard) {
+    if (!port || !port->host_connected || !info->have_data) {
         discard_vq_data(vq, vdev);
         return;
     }
-    if (port->throttled) {
+
+    if (!port->throttled) {
+        do_flush_queued_data(port, vq, vdev);
         return;
     }
-
-    do_flush_queued_data(port, vq, vdev);
 }
 
 static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
@@ -473,7 +493,7 @@ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
 
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
 
-    if (vser->bus->max_nr_ports > 1) {
+    if (vser->bus.max_nr_ports > 1) {
         features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
     }
     return features;
@@ -500,7 +520,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);
@@ -512,8 +532,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]);
     }
 
@@ -574,7 +594,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;
     }
@@ -600,6 +621,9 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 
         id = qemu_get_be32(f);
         port = find_port_by_id(s, id);
+        if (!port) {
+            return -EINVAL;
+        }
 
         port->guest_connected = qemu_get_byte(f);
         host_connected = qemu_get_byte(f);
@@ -644,39 +668,31 @@ static struct BusInfo virtser_bus_info = {
     .name      = "virtio-serial-bus",
     .size      = sizeof(VirtIOSerialBus),
     .print_dev = virtser_bus_dev_print,
+    .props      = (Property[]) {
+        DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
+        DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
+        DEFINE_PROP_END_OF_LIST()
+    }
 };
 
-static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
-{
-    VirtIOSerialBus *bus;
-
-    bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
-    bus->qbus.allow_hotplug = 1;
-
-    return bus;
-}
-
 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 {
-    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
 
-    monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
-                   indent, "", port->id);
-    monitor_printf(mon, "%*s dev-prop-int: guest_connected: %d\n",
-                   indent, "", port->guest_connected);
-    monitor_printf(mon, "%*s dev-prop-int: host_connected: %d\n",
-                   indent, "", port->host_connected);
-    monitor_printf(mon, "%*s dev-prop-int: throttled: %d\n",
-                   indent, "", port->throttled);
+    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
+                   indent, "", port->id,
+                   port->guest_connected ? "on" : "off",
+                   port->host_connected ? "on" : "off",
+                   port->throttled ? "on" : "off");
 }
 
 /* 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];
@@ -721,24 +737,24 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
 
 static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
-    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
     VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
-    int ret;
+    int ret, max_nr_ports;
     bool plugging_port0;
 
     port->vser = bus->vser;
+    port->bh = qemu_bh_new(flush_queued_data_bh, port);
 
     /*
      * Is the first console port we're seeing? If so, put it up at
      * location 0. This is done for backward compatibility (old
      * kernel, new qemu).
      */
-    plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
+    plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
 
     if (find_port_by_id(port->vser, port->id)) {
-        error_report("virtio-serial-bus: A port already exists at id %u\n",
+        error_report("virtio-serial-bus: A port already exists at id %u",
                      port->id);
         return -1;
     }
@@ -749,20 +765,20 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
         } else {
             port->id = find_free_port_id(port->vser);
             if (port->id == VIRTIO_CONSOLE_BAD_ID) {
-                error_report("virtio-serial-bus: Maximum port limit for this device reached\n");
+                error_report("virtio-serial-bus: Maximum port limit for this device reached");
                 return -1;
             }
         }
     }
 
-    if (port->id >= port->vser->config.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 = 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",
+                     max_nr_ports - 1);
         return -1;
     }
 
-    dev->info = info;
-    ret = info->init(dev);
+    ret = info->init(port);
     if (ret) {
         return ret;
     }
@@ -791,17 +807,19 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
 
 static int virtser_port_qdev_exit(DeviceState *qdev)
 {
-    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
+                                           port->dev.info);
     VirtIOSerial *vser = port->vser;
 
+    qemu_bh_delete(port->bh);
     remove_port(port->vser, port->id);
 
     QTAILQ_REMOVE(&vser->ports, port, next);
 
-    if (port->info->exit)
-        port->info->exit(dev);
-
+    if (info->exit) {
+        info->exit(port);
+    }
     return 0;
 }
 
@@ -814,19 +832,19 @@ void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
     qdev_register(&info->qdev);
 }
 
-VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
 {
     VirtIOSerial *vser;
     VirtIODevice *vdev;
     uint32_t i, max_supported_ports;
 
-    if (!max_nr_ports)
+    if (!conf->max_virtserial_ports)
         return NULL;
 
     /* Each port takes 2 queues, and one pair is for the control queue */
     max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
 
-    if (max_nr_ports > max_supported_ports) {
+    if (conf->max_virtserial_ports > max_supported_ports) {
         error_report("maximum ports supported: %u", max_supported_ports);
         return NULL;
     }
@@ -838,13 +856,14 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
 
     /* Spawn a new virtio-serial bus on which the ports will ride as devices */
-    vser->bus = virtser_bus_new(dev);
-    vser->bus->vser = vser;
+    qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
+    vser->bus.qbus.allow_hotplug = 1;
+    vser->bus.vser = vser;
     QTAILQ_INIT(&vser->ports);
 
-    vser->bus->max_nr_ports = max_nr_ports;
-    vser->ivqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
-    vser->ovqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
+    vser->bus.max_nr_ports = conf->max_virtserial_ports;
+    vser->ivqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
+    vser->ovqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
 
     /* Add a queue for host to guest transfers for port 0 (backward compat) */
     vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
@@ -862,15 +881,15 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
     /* control queue: guest to host */
     vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
 
-    for (i = 1; i < vser->bus->max_nr_ports; i++) {
+    for (i = 1; i < vser->bus.max_nr_ports; i++) {
         /* Add a per-port queue for host to guest transfers */
         vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
         /* Add a per-per queue for guest to host transfers */
         vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
     }
 
-    vser->config.max_nr_ports = max_nr_ports;
-    vser->ports_map = qemu_mallocz(((max_nr_ports + 31) / 32)
+    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
+    vser->ports_map = g_malloc0(((conf->max_virtserial_ports + 31) / 32)
         * sizeof(vser->ports_map[0]));
     /*
      * Reserve location 0 for a console port for backward compat
@@ -900,9 +919,9 @@ void virtio_serial_exit(VirtIODevice *vdev)
 
     unregister_savevm(vser->qdev, "virtio-console", vser);
 
-    qemu_free(vser->ivqs);
-    qemu_free(vser->ovqs);
-    qemu_free(vser->ports_map);
+    g_free(vser->ivqs);
+    g_free(vser->ovqs);
+    g_free(vser->ports_map);
 
     virtio_cleanup(vdev);
 }
index a308196786dad1da1aa2f006f828b554abe52fec..ab138038c0edf7f48af363a5032dcf5a7669da6f 100644 (file)
@@ -37,7 +37,7 @@ struct virtio_console_config {
     uint16_t rows;
 
     uint32_t max_nr_ports;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 struct virtio_console_control {
     uint32_t id;               /* Port number */
@@ -45,6 +45,11 @@ struct virtio_console_control {
     uint16_t value;            /* Extra information for the key */
 };
 
+struct virtio_serial_conf {
+    /* Max. number of ports we can have for a virtio-serial device */
+    uint32_t max_virtserial_ports;
+};
+
 /* Some events for the internal messages (control packets) */
 #define VIRTIO_CONSOLE_DEVICE_READY    0
 #define VIRTIO_CONSOLE_PORT_ADD                1
@@ -62,11 +67,6 @@ typedef struct VirtIOSerialBus VirtIOSerialBus;
 typedef struct VirtIOSerialPort VirtIOSerialPort;
 typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
 
-typedef struct VirtIOSerialDevice {
-    DeviceState qdev;
-    VirtIOSerialPortInfo *info;
-} VirtIOSerialDevice;
-
 /*
  * This is the state that's shared between all the ports.  Some of the
  * state is configurable via command-line options. Some of it can be
@@ -75,7 +75,6 @@ typedef struct VirtIOSerialDevice {
  */
 struct VirtIOSerialPort {
     DeviceState dev;
-    VirtIOSerialPortInfo *info;
 
     QTAILQ_ENTRY(VirtIOSerialPort) next;
 
@@ -119,8 +118,10 @@ struct VirtIOSerialPort {
     uint32_t iov_idx;
     uint64_t iov_offset;
 
-    /* Identify if this is a port that binds with hvc in the guest */
-    uint8_t is_console;
+    /*
+     * When unthrottling we use a bottom-half to call flush_queued_data.
+     */
+    QEMUBH *bh;
 
     /* Is the corresponding guest device open? */
     bool guest_connected;
@@ -132,16 +133,20 @@ struct VirtIOSerialPort {
 
 struct VirtIOSerialPortInfo {
     DeviceInfo qdev;
+
+    /* Is this a device that binds with hvc in the guest? */
+    bool is_console;
+
     /*
      * The per-port (or per-app) init function that's called when a
      * new device is found on the bus.
      */
-    int (*init)(VirtIOSerialDevice *dev);
+    int (*init)(VirtIOSerialPort *port);
     /*
      * Per-port exit function that's called when a port gets
      * hot-unplugged or removed.
      */
-    int (*exit)(VirtIOSerialDevice *dev);
+    int (*exit)(VirtIOSerialPort *port);
 
     /* Callbacks for guest events */
         /* Guest opened device. */
index 31bd9e32dc5abd890fea27ecb23c9616df027311..81ecc40b310d0d02dc1c8fbf8592de948be3b6d2 100644 (file)
 #include "trace.h"
 #include "qemu-error.h"
 #include "virtio.h"
-#include "sysemu.h"
+#include "qemu-barrier.h"
 
 /* The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. */
 #define VIRTIO_PCI_VRING_ALIGN         4096
 
-/* QEMU doesn't strictly need write barriers since everything runs in
- * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
- * KVM or if kqemu gets SMP support.
- * In any case, we must prevent the compiler from reordering the code.
- * TODO: we likely need some rmb()/mb() as well.
- */
-
-#define wmb() __asm__ __volatile__("": : :"memory")
-
 typedef struct VRingDesc
 {
     uint64_t addr;
@@ -72,7 +63,17 @@ struct VirtQueue
     VRing vring;
     target_phys_addr_t pa;
     uint16_t last_avail_idx;
+    /* Last used index value we have signalled on */
+    uint16_t signalled_used;
+
+    /* Last used index value we have signalled on */
+    bool signalled_used_valid;
+
+    /* Notification enabled? */
+    bool notification;
+
     int inuse;
+
     uint16_t vector;
     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
     VirtIODevice *vdev;
@@ -141,6 +142,11 @@ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
     return lduw_phys(pa);
 }
 
+static inline uint16_t vring_used_event(VirtQueue *vq)
+{
+    return vring_avail_ring(vq, vq->vring.num);
+}
+
 static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
 {
     target_phys_addr_t pa;
@@ -162,11 +168,11 @@ static uint16_t vring_used_idx(VirtQueue *vq)
     return lduw_phys(pa);
 }
 
-static inline void vring_used_idx_increment(VirtQueue *vq, uint16_t val)
+static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
 {
     target_phys_addr_t pa;
     pa = vq->vring.used + offsetof(VRingUsed, idx);
-    stw_phys(pa, vring_used_idx(vq) + val);
+    stw_phys(pa, val);
 }
 
 static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
@@ -183,12 +189,26 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
     stw_phys(pa, lduw_phys(pa) & ~mask);
 }
 
+static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
+{
+    target_phys_addr_t pa;
+    if (!vq->notification) {
+        return;
+    }
+    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
+    stw_phys(pa, val);
+}
+
 void virtio_queue_set_notification(VirtQueue *vq, int enable)
 {
-    if (enable)
+    vq->notification = enable;
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    } else if (enable) {
         vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
-    else
+    } else {
         vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
+    }
 }
 
 int virtio_queue_ready(VirtQueue *vq)
@@ -234,11 +254,16 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
 
 void virtqueue_flush(VirtQueue *vq, unsigned int count)
 {
+    uint16_t old, new;
     /* Make sure buffer is written before we update index. */
-    wmb();
+    smp_wmb();
     trace_virtqueue_flush(vq, count);
-    vring_used_idx_increment(vq, count);
+    old = vring_used_idx(vq);
+    new = old + count;
+    vring_used_idx_set(vq, new);
     vq->inuse -= count;
+    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
+        vq->signalled_used_valid = false;
 }
 
 void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
@@ -291,7 +316,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
     /* Check they're not leading us off end of descriptors. */
     next = vring_desc_next(desc_pa, i);
     /* Make sure compiler knows to grab that: we don't want it changing! */
-    wmb();
+    smp_wmb();
 
     if (next >= max) {
         error_report("Desc next is %u", next);
@@ -395,6 +420,9 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
     max = vq->vring.num;
 
     i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    }
 
     if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
         if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
@@ -413,9 +441,17 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
         struct iovec *sg;
 
         if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
+                error_report("Too many write descriptors in indirect table");
+                exit(1);
+            }
             elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
             sg = &elem->in_sg[elem->in_num++];
         } else {
+            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
+                error_report("Too many read descriptors in indirect table");
+                exit(1);
+            }
             elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
             sg = &elem->out_sg[elem->out_num++];
         }
@@ -454,6 +490,16 @@ void virtio_update_irq(VirtIODevice *vdev)
     virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
 }
 
+void virtio_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    trace_virtio_set_status(vdev, val);
+
+    if (vdev->set_status) {
+        vdev->set_status(vdev, val);
+    }
+    vdev->status = val;
+}
+
 void virtio_reset(void *opaque)
 {
     VirtIODevice *vdev = opaque;
@@ -478,6 +524,9 @@ void virtio_reset(void *opaque)
         vdev->vq[i].last_avail_idx = 0;
         vdev->vq[i].pa = 0;
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].signalled_used = 0;
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
     }
 }
 
@@ -586,9 +635,7 @@ void virtio_queue_notify_vq(VirtQueue *vq)
 
 void virtio_queue_notify(VirtIODevice *vdev, int n)
 {
-    if (n < VIRTIO_PCI_QUEUE_MAX) {
-        virtio_queue_notify_vq(&vdev->vq[n]);
-    }
+    virtio_queue_notify_vq(&vdev->vq[n]);
 }
 
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
@@ -629,13 +676,45 @@ void virtio_irq(VirtQueue *vq)
     virtio_notify_vector(vq->vdev, vq->vector);
 }
 
-void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
+{
+       /* Note: Xen has similar logic for notification hold-off
+        * in include/xen/interface/io/ring.h with req_event and req_prod
+        * corresponding to event_idx + 1 and new respectively.
+        * Note also that req_event and req_prod in Xen start at 1,
+        * event indexes in virtio start at 0. */
+       return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
+}
+
+static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
 {
+    uint16_t old, new;
+    bool v;
     /* Always notify when queue is empty (when feature acknowledge) */
-    if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) &&
-        (!(vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
-         (vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
+    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
+         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
+        return true;
+    }
+
+    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
+    }
+
+    v = vq->signalled_used_valid;
+    vq->signalled_used_valid = true;
+    old = vq->signalled_used;
+    new = vq->signalled_used = vring_used_idx(vq);
+    return !v || vring_need_event(vring_used_event(vq), new, old);
+}
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    if (!vring_notify(vdev, vq)) {
         return;
+    }
 
     trace_virtio_notify(vdev, vq);
     vdev->isr |= 0x01;
@@ -684,12 +763,25 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
     }
 }
 
+int virtio_set_features(VirtIODevice *vdev, uint32_t val)
+{
+    uint32_t supported_features =
+        vdev->binding->get_features(vdev->binding_opaque);
+    bool bad = (val & ~supported_features) != 0;
+
+    val &= supported_features;
+    if (vdev->set_features) {
+        vdev->set_features(vdev, val);
+    }
+    vdev->guest_features = val;
+    return bad ? -1 : 0;
+}
+
 int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 {
     int num, i, ret;
     uint32_t features;
-    uint32_t supported_features =
-        vdev->binding->get_features(vdev->binding_opaque);
+    uint32_t supported_features;
 
     if (vdev->binding->load_config) {
         ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -701,14 +793,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
     qemu_get_8s(f, &vdev->isr);
     qemu_get_be16s(f, &vdev->queue_sel);
     qemu_get_be32s(f, &features);
-    if (features & ~supported_features) {
+
+    if (virtio_set_features(vdev, features) < 0) {
+        supported_features = vdev->binding->get_features(vdev->binding_opaque);
         error_report("Features 0x%x unsupported. Allowed features: 0x%x",
                      features, supported_features);
         return -1;
     }
-    if (vdev->set_features)
-        vdev->set_features(vdev, features);
-    vdev->guest_features = features;
     vdev->config_len = qemu_get_be32(f);
     qemu_get_buffer(f, vdev->config, vdev->config_len);
 
@@ -718,6 +809,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
         vdev->vq[i].vring.num = qemu_get_be32(f);
         vdev->vq[i].pa = qemu_get_be64(f);
         qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
 
         if (vdev->vq[i].pa) {
             uint16_t nheads;
@@ -726,7 +819,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
             /* Check it isn't doing very strange things with descriptor numbers. */
             if (nheads > vdev->vq[i].vring.num) {
                 error_report("VQ %d size 0x%x Guest index 0x%x "
-                             "inconsistent with Host index 0x%x: delta 0x%x\n",
+                             "inconsistent with Host index 0x%x: delta 0x%x",
                              i, vdev->vq[i].vring.num,
                              vring_avail_idx(&vdev->vq[i]),
                              vdev->vq[i].last_avail_idx, nheads);
@@ -734,7 +827,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
             }
         } else if (vdev->vq[i].last_avail_idx) {
             error_report("VQ %d address 0x0 "
-                         "inconsistent with Host index 0x%x\n",
+                         "inconsistent with Host index 0x%x",
                          i, vdev->vq[i].last_avail_idx);
                 return -1;
        }
@@ -753,11 +846,12 @@ void virtio_cleanup(VirtIODevice *vdev)
 {
     qemu_del_vm_change_state_handler(vdev->vmstate);
     if (vdev->config)
-        qemu_free(vdev->config);
-    qemu_free(vdev->vq);
+        g_free(vdev->config);
+    g_free(vdev->vq);
+    g_free(vdev);
 }
 
-static void virtio_vmstate_change(void *opaque, int running, int reason)
+static void virtio_vmstate_change(void *opaque, int running, RunState state)
 {
     VirtIODevice *vdev = opaque;
     bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
@@ -782,14 +876,15 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
     VirtIODevice *vdev;
     int i;
 
-    vdev = qemu_mallocz(struct_size);
+    vdev = g_malloc0(struct_size);
 
     vdev->device_id = device_id;
     vdev->status = 0;
     vdev->isr = 0;
     vdev->queue_sel = 0;
     vdev->config_vector = VIRTIO_NO_VECTOR;
-    vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+    vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+    vdev->vm_running = runstate_is_running();
     for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
         vdev->vq[i].vdev = vdev;
@@ -798,7 +893,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
     vdev->name = name;
     vdev->config_len = config_size;
     if (vdev->config_len)
-        vdev->config = qemu_mallocz(config_size);
+        vdev->config = g_malloc0(config_size);
     else
         vdev->config = NULL;
 
index 4ceb52ee07c6a7fd0cd66f5d588029c700586bca..470e3adb1f8ce2badd57820780f77752bb4bccc7 100644 (file)
 #include "net.h"
 #include "qdev.h"
 #include "sysemu.h"
-#include "block_int.h"
+#include "block.h"
 #include "event_notifier.h"
 #ifdef CONFIG_LINUX
 #include "9p.h"
 #endif
+#define VIRTIO_ID_GL 6
 
 /* from Linux's linux/virtio_config.h */
 
 #define VIRTIO_F_NOTIFY_ON_EMPTY        24
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC     28
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX         29
 /* A guest should never accept this.  It implies negotiation is broken. */
 #define VIRTIO_F_BAD_FEATURE           30
 
@@ -130,14 +136,6 @@ struct VirtIODevice
     VMChangeStateEntry *vmstate;
 };
 
-static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val)
-{
-    if (vdev->set_status) {
-        vdev->set_status(vdev, val);
-    }
-    vdev->status = val;
-}
-
 VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                             void (*handle_output)(VirtIODevice *,
                                                   VirtQueue *));
@@ -185,32 +183,38 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n);
 void virtio_queue_notify(VirtIODevice *vdev, int n);
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
 void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
+void virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_update_irq(VirtIODevice *vdev);
+int virtio_set_features(VirtIODevice *vdev, uint32_t val);
 
 void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
                         void *opaque);
 
 /* Base devices.  */
-VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
+VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
+                              char **serial);
 struct virtio_net_conf;
 VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
                               struct virtio_net_conf *net);
-VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
+typedef struct virtio_serial_conf virtio_serial_conf;
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
 #ifdef CONFIG_LINUX
 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
 #endif
-VirtIODevice *virtio_gpi_init(DeviceState *dev);
 
 
 void virtio_net_exit(VirtIODevice *vdev);
 void virtio_blk_exit(VirtIODevice *vdev);
 void virtio_serial_exit(VirtIODevice *vdev);
+void virtio_balloon_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
        DEFINE_PROP_BIT("indirect_desc", _state, _field, \
-                       VIRTIO_RING_F_INDIRECT_DESC, true)
+                       VIRTIO_RING_F_INDIRECT_DESC, true), \
+       DEFINE_PROP_BIT("event_idx", _state, _field, \
+                       VIRTIO_RING_F_EVENT_IDX, true)
 
 target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
index 209711942fa4ad4474d69e701a6ddded23af2334..1113f33d6894cdc82422bbadf6bff1c7774f7606 100644 (file)
@@ -25,6 +25,7 @@
 #include "console.h"
 #include "ps2.h"
 #include "pc.h"
+#include "qdev.h"
 
 /* debug only vmmouse */
 //#define DEBUG_VMMOUSE
@@ -52,6 +53,7 @@
 
 typedef struct _VMMouseState
 {
+    ISADevice dev;
     uint32_t queue[VMMOUSE_QUEUE_SIZE];
     int32_t queue_size;
     uint16_t nb_queue;
@@ -176,30 +178,6 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
         memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
 }
 
-static void vmmouse_get_data(uint32_t *data)
-{
-    CPUState *env = cpu_single_env;
-
-    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
-    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
-    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
-
-    DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n",
-            data[0], data[1], data[2], data[3], data[4], data[5]);
-}
-
-static void vmmouse_set_data(const uint32_t *data)
-{
-    CPUState *env = cpu_single_env;
-
-    DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n",
-            data[0], data[1], data[2], data[3], data[4], data[5]);
-
-    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
-    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
-    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
-}
-
 static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
 {
     VMMouseState *s = opaque;
@@ -270,22 +248,42 @@ static const VMStateDescription vmstate_vmmouse = {
     }
 };
 
-void *vmmouse_init(void *m)
+static void vmmouse_reset(DeviceState *d)
 {
-    VMMouseState *s = NULL;
-
-    DPRINTF("vmmouse_init\n");
-
-    s = qemu_mallocz(sizeof(VMMouseState));
+    VMMouseState *s = container_of(d, VMMouseState, dev.qdev);
 
     s->status = 0xffff;
-    s->ps2_mouse = m;
     s->queue_size = VMMOUSE_QUEUE_SIZE;
+}
+
+static int vmmouse_initfn(ISADevice *dev)
+{
+    VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev);
+
+    DPRINTF("vmmouse_init\n");
 
     vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
     vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
     vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
-    vmstate_register(NULL, 0, &vmstate_vmmouse, s);
 
-    return s;
+    return 0;
+}
+
+static ISADeviceInfo vmmouse_info = {
+    .init          = vmmouse_initfn,
+    .qdev.name     = "vmmouse",
+    .qdev.size     = sizeof(VMMouseState),
+    .qdev.vmsd     = &vmstate_vmmouse,
+    .qdev.no_user  = 1,
+    .qdev.reset    = vmmouse_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void vmmouse_dev_register(void)
+{
+    isa_qdev_register(&vmmouse_info);
 }
+device_init(vmmouse_dev_register)
index 6c9d7c9651a0a05ad3d38bc76536719fc3e17109..b5c6fa19cd696692ed299ee73e52ba69c6a7d173 100644 (file)
@@ -24,8 +24,8 @@
 #include "hw.h"
 #include "isa.h"
 #include "pc.h"
-#include "sysemu.h"
 #include "kvm.h"
+#include "qdev.h"
 
 //#define VMPORT_DEBUG
 
 
 typedef struct _VMPortState
 {
+    ISADevice dev;
+    MemoryRegion io;
     IOPortReadFunc *func[VMPORT_ENTRIES];
     void *opaque[VMPORT_ENTRIES];
 } VMPortState;
 
-static VMPortState port_state;
+static VMPortState *port_state;
 
 void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque)
 {
     if (command >= VMPORT_ENTRIES)
         return;
 
-    port_state.func[command] = func;
-    port_state.opaque[command] = opaque;
+    port_state->func[command] = func;
+    port_state->opaque[command] = opaque;
 }
 
 static uint32_t vmport_ioport_read(void *opaque, uint32_t addr)
@@ -100,12 +102,57 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
     return ram_size;
 }
 
-void vmport_init(void)
+/* vmmouse helpers */
+void vmmouse_get_data(uint32_t *data)
 {
-    register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state);
-    register_ioport_write(0x5658, 1, 4, vmport_ioport_write, &port_state);
+    CPUState *env = cpu_single_env;
+
+    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+}
+
+void vmmouse_set_data(const uint32_t *data)
+{
+    CPUState *env = cpu_single_env;
+
+    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
+static const MemoryRegionPortio vmport_portio[] = {
+    {0, 1, 4, .read = vmport_ioport_read, .write = vmport_ioport_write },
+    PORTIO_END_OF_LIST(),
+};
 
+static const MemoryRegionOps vmport_ops = {
+    .old_portio = vmport_portio
+};
+
+static int vmport_initfn(ISADevice *dev)
+{
+    VMPortState *s = DO_UPCAST(VMPortState, dev, dev);
+
+    memory_region_init_io(&s->io, &vmport_ops, s, "vmport", 1);
+    isa_register_ioport(dev, &s->io, 0x5658);
+
+    port_state = s;
     /* Register some generic port commands */
     vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
     vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
+    return 0;
+}
+
+static ISADeviceInfo vmport_info = {
+    .qdev.name     = "vmport",
+    .qdev.size     = sizeof(VMPortState),
+    .qdev.no_user  = 1,
+    .init          = vmport_initfn,
+};
+
+static void vmport_dev_register(void)
+{
+    isa_qdev_register(&vmport_info);
 }
+device_init(vmport_dev_register)
index 6c590533081b4469ddfc95aefb2d4fe0e18783cd..af70bdee094a0035f4e6797b1e5583bff38e506f 100644 (file)
@@ -27,8 +27,7 @@
 #include "pci.h"
 #include "vmware_vga.h"
 
-#define VERBOSE
-#undef DIRECT_VRAM
+#undef VERBOSE
 #define HW_RECT_ACCEL
 #define HW_FILL_ACCEL
 #define HW_MOUSE_ACCEL
@@ -52,8 +51,6 @@ struct vmsvga_state_s {
         int on;
     } cursor;
 
-    target_phys_addr_t vram_base;
-
     int index;
     int scratch_size;
     uint32_t *scratch;
@@ -67,14 +64,13 @@ struct vmsvga_state_s {
     int syncing;
     int fb_size;
 
-    ram_addr_t fifo_offset;
+    MemoryRegion fifo_ram;
     uint8_t *fifo_ptr;
     unsigned int fifo_size;
-    target_phys_addr_t fifo_base;
 
     union {
         uint32_t *fifo;
-        struct __attribute__((__packed__)) {
+        struct QEMU_PACKED {
             uint32_t min;
             uint32_t max;
             uint32_t next_cmd;
@@ -94,6 +90,7 @@ struct vmsvga_state_s {
 struct pci_vmsvga_state_s {
     PCIDevice card;
     struct vmsvga_state_s chip;
+    MemoryRegion io_bar;
 };
 
 #define SVGA_MAGIC             0x900000UL
@@ -294,7 +291,6 @@ enum {
 static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
                 int x, int y, int w, int h)
 {
-#ifndef DIRECT_VRAM
     int line;
     int bypl;
     int width;
@@ -325,23 +321,17 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
 
     for (; line > 0; line --, src += bypl, dst += bypl)
         memcpy(dst, src, width);
-#endif
 
     dpy_update(s->vga.ds, x, y, w, h);
 }
 
 static inline void vmsvga_update_screen(struct vmsvga_state_s *s)
 {
-#ifndef DIRECT_VRAM
-    memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, s->bypp * s->width * s->height);
-#endif
-
+    memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr,
+           s->bypp * s->width * s->height);
     dpy_update(s->vga.ds, 0, 0, s->width, s->height);
 }
 
-#ifdef DIRECT_VRAM
-# define vmsvga_update_rect_delayed    vmsvga_update_rect
-#else
 static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
                 int x, int y, int w, int h)
 {
@@ -352,7 +342,6 @@ static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
     rect->w = w;
     rect->h = h;
 }
-#endif
 
 static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
 {
@@ -374,32 +363,23 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
 static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
                 int x0, int y0, int x1, int y1, int w, int h)
 {
-# ifdef DIRECT_VRAM
-    uint8_t *vram = ds_get_data(s->ds);
-# else
     uint8_t *vram = s->vga.vram_ptr;
-# endif
     int bypl = s->bypp * s->width;
     int width = s->bypp * w;
     int line = h;
     uint8_t *ptr[2];
 
-# ifdef DIRECT_VRAM
-    if (s->ds->dpy_copy)
-        qemu_console_copy(s->ds, x0, y0, x1, y1, w, h);
-    else
-# endif
-    {
-        if (y1 > y0) {
-            ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1);
-            ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1);
-            for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl)
-                memmove(ptr[1], ptr[0], width);
-        } else {
-            ptr[0] = vram + s->bypp * x0 + bypl * y0;
-            ptr[1] = vram + s->bypp * x1 + bypl * y1;
-            for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl)
-                memmove(ptr[1], ptr[0], width);
+    if (y1 > y0) {
+        ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1);
+        ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1);
+        for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) {
+            memmove(ptr[1], ptr[0], width);
+        }
+    } else {
+        ptr[0] = vram + s->bypp * x0 + bypl * y0;
+        ptr[1] = vram + s->bypp * x1 + bypl * y1;
+        for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) {
+            memmove(ptr[1], ptr[0], width);
         }
     }
 
@@ -411,11 +391,7 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
 static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
                 uint32_t c, int x, int y, int w, int h)
 {
-# ifdef DIRECT_VRAM
-    uint8_t *vram = ds_get_data(s->ds);
-# else
     uint8_t *vram = s->vga.vram_ptr;
-# endif
     int bypp = s->bypp;
     int bypl = bypp * s->width;
     int width = bypp * w;
@@ -426,31 +402,25 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
     uint8_t *src;
     uint8_t col[4];
 
-# ifdef DIRECT_VRAM
-    if (s->ds->dpy_fill)
-        s->ds->dpy_fill(s->ds, x, y, w, h, c);
-    else
-# endif
-    {
-        col[0] = c;
-        col[1] = c >> 8;
-        col[2] = c >> 16;
-        col[3] = c >> 24;
-
-        if (line --) {
-            dst = fst;
-            src = col;
-            for (column = width; column > 0; column --) {
-                *(dst ++) = *(src ++);
-                if (src - col == bypp)
-                    src = col;
-            }
-            dst = fst;
-            for (; line > 0; line --) {
-                dst += bypl;
-                memcpy(dst, fst, width);
+    col[0] = c;
+    col[1] = c >> 8;
+    col[2] = c >> 16;
+    col[3] = c >> 24;
+
+    if (line--) {
+        dst = fst;
+        src = col;
+        for (column = width; column > 0; column--) {
+            *(dst++) = *(src++);
+            if (src - col == bypp) {
+                src = col;
             }
         }
+        dst = fst;
+        for (; line > 0; line--) {
+            dst += bypl;
+            memcpy(dst, fst, width);
+        }
     }
 
     vmsvga_update_rect_delayed(s, x, y, w, h);
@@ -761,8 +731,11 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
     case SVGA_REG_BYTES_PER_LINE:
         return ((s->depth + 7) >> 3) * s->new_width;
 
-    case SVGA_REG_FB_START:
-        return s->vram_base;
+    case SVGA_REG_FB_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 1);
+    }
 
     case SVGA_REG_FB_OFFSET:
         return 0x0;
@@ -788,8 +761,11 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
 #endif
         return caps;
 
-    case SVGA_REG_MEM_START:
-        return s->fifo_base;
+    case SVGA_REG_MEM_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 2);
+    }
 
     case SVGA_REG_MEM_SIZE:
         return s->fifo_size;
@@ -994,46 +970,21 @@ static void vmsvga_update_display(void *opaque)
     }
 }
 
-static void vmsvga_reset(struct vmsvga_state_s *s)
+static void vmsvga_reset(DeviceState *dev)
 {
+    struct pci_vmsvga_state_s *pci =
+        DO_UPCAST(struct pci_vmsvga_state_s, card.qdev, dev);
+    struct vmsvga_state_s *s = &pci->chip;
+
     s->index = 0;
     s->enable = 0;
     s->config = 0;
     s->width = -1;
     s->height = -1;
     s->svgaid = SVGA_ID;
-    s->depth = ds_get_bits_per_pixel(s->vga.ds);
-    s->bypp = ds_get_bytes_per_pixel(s->vga.ds);
     s->cursor.on = 0;
     s->redraw_fifo_first = 0;
     s->redraw_fifo_last = 0;
-    switch (s->depth) {
-    case 8:
-        s->wred   = 0x00000007;
-        s->wgreen = 0x00000038;
-        s->wblue  = 0x000000c0;
-        break;
-    case 15:
-        s->wred   = 0x0000001f;
-        s->wgreen = 0x000003e0;
-        s->wblue  = 0x00007c00;
-        break;
-    case 16:
-        s->wred   = 0x0000001f;
-        s->wgreen = 0x000007e0;
-        s->wblue  = 0x0000f800;
-        break;
-    case 24:
-        s->wred   = 0x00ff0000;
-        s->wgreen = 0x0000ff00;
-        s->wblue  = 0x000000ff;
-        break;
-    case 32:
-        s->wred   = 0x00ff0000;
-        s->wgreen = 0x0000ff00;
-        s->wblue  = 0x000000ff;
-        break;
-    }
     s->syncing = 0;
 
     vga_dirty_log_start(&s->vga);
@@ -1064,7 +1015,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename)
         DisplaySurface *ds = qemu_create_displaysurface_from(s->width,
                 s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr);
         ppm_save(filename, ds);
-        qemu_free(ds);
+        g_free(ds);
     }
 }
 
@@ -1076,77 +1027,6 @@ static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
         s->vga.text_update(&s->vga, chardata);
 }
 
-#ifdef DIRECT_VRAM
-static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        return *(uint8_t *) (ds_get_data(s->ds) + addr);
-    else
-        return *(uint8_t *) (s->vram_ptr + addr);
-}
-
-static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        return *(uint16_t *) (ds_get_data(s->ds) + addr);
-    else
-        return *(uint16_t *) (s->vram_ptr + addr);
-}
-
-static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        return *(uint32_t *) (ds_get_data(s->ds) + addr);
-    else
-        return *(uint32_t *) (s->vram_ptr + addr);
-}
-
-static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        *(uint8_t *) (ds_get_data(s->ds) + addr) = value;
-    else
-        *(uint8_t *) (s->vram_ptr + addr) = value;
-}
-
-static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        *(uint16_t *) (ds_get_data(s->ds) + addr) = value;
-    else
-        *(uint16_t *) (s->vram_ptr + addr) = value;
-}
-
-static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (addr < s->fb_size)
-        *(uint32_t *) (ds_get_data(s->ds) + addr) = value;
-    else
-        *(uint32_t *) (s->vram_ptr + addr) = value;
-}
-
-static CPUReadMemoryFunc * const vmsvga_vram_read[] = {
-    vmsvga_vram_readb,
-    vmsvga_vram_readw,
-    vmsvga_vram_readl,
-};
-
-static CPUWriteMemoryFunc * const vmsvga_vram_write[] = {
-    vmsvga_vram_writeb,
-    vmsvga_vram_writew,
-    vmsvga_vram_writel,
-};
-#endif
-
 static int vmsvga_post_load(void *opaque, int version_id)
 {
     struct vmsvga_state_s *s = opaque;
@@ -1198,10 +1078,11 @@ static const VMStateDescription vmstate_vmware_vga = {
     }
 };
 
-static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
+static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size,
+                        MemoryRegion *address_space, MemoryRegion *io)
 {
     s->scratch_size = SVGA_SCRATCH_SIZE;
-    s->scratch = qemu_malloc(s->scratch_size * 4);
+    s->scratch = g_malloc(s->scratch_size * 4);
 
     s->vga.ds = graphic_console_init(vmsvga_update_display,
                                      vmsvga_invalidate_display,
@@ -1210,117 +1091,127 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
 
 
     s->fifo_size = SVGA_FIFO_SIZE;
-    s->fifo_offset = qemu_ram_alloc(NULL, "vmsvga.fifo", s->fifo_size);
-    s->fifo_ptr = qemu_get_ram_ptr(s->fifo_offset);
+    memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
+    s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
 
     vga_common_init(&s->vga, vga_ram_size);
-    vga_init(&s->vga);
+    vga_init(&s->vga, address_space, io, true);
     vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
 
-    vmsvga_reset(s);
+    s->depth = ds_get_bits_per_pixel(s->vga.ds);
+    s->bypp = ds_get_bytes_per_pixel(s->vga.ds);
+    switch (s->depth) {
+    case 8:
+        s->wred   = 0x00000007;
+        s->wgreen = 0x00000038;
+        s->wblue  = 0x000000c0;
+        break;
+    case 15:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000003e0;
+        s->wblue  = 0x00007c00;
+        break;
+    case 16:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000007e0;
+        s->wblue  = 0x0000f800;
+        break;
+    case 24:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    case 32:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    }
 }
 
-static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+static uint64_t vmsvga_io_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_write, s);
+    struct vmsvga_state_s *s = opaque;
+
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT: return vmsvga_index_read(s, addr);
+    case SVGA_IO_MUL * SVGA_VALUE_PORT: return vmsvga_value_read(s, addr);
+    case SVGA_IO_MUL * SVGA_BIOS_PORT: return vmsvga_bios_read(s, addr);
+    default: return -1u;
+    }
 }
 
-static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+static void vmsvga_io_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t data, unsigned size)
 {
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
-
-    s->vram_base = addr;
-#ifdef DIRECT_VRAM
-    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
-                    vmsvga_vram_write, s, DEVICE_NATIVE_ENDIAN);
-#else
-    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
-#endif
-    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
-                    iomemtype);
+    struct vmsvga_state_s *s = opaque;
 
-    s->vga.map_addr = addr;
-    s->vga.map_end = addr + s->vga.vram_size;
-    vga_dirty_log_restart(&s->vga);
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT:
+        return vmsvga_index_write(s, addr, data);
+    case SVGA_IO_MUL * SVGA_VALUE_PORT:
+        return vmsvga_value_write(s, addr, data);
+    case SVGA_IO_MUL * SVGA_BIOS_PORT:
+        return vmsvga_bios_write(s, addr, data);
+    }
 }
 
-static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
-
-    s->fifo_base = addr;
-    iomemtype = s->fifo_offset | IO_MEM_RAM;
-    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
-                    iomemtype);
-}
+static const MemoryRegionOps vmsvga_io_ops = {
+    .read = vmsvga_io_read,
+    .write = vmsvga_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
 
 static int pci_vmsvga_initfn(PCIDevice *dev)
 {
     struct pci_vmsvga_state_s *s =
         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+    MemoryRegion *iomem;
+
+    iomem = &s->chip.vga.vram;
 
-    pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
-    pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
-    pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
     s->card.config[PCI_CACHE_LINE_SIZE]        = 0x08;         /* Cache line size */
     s->card.config[PCI_LATENCY_TIMER] = 0x40;          /* Latency timer */
-    s->card.config[PCI_SUBSYSTEM_VENDOR_ID] = PCI_VENDOR_ID_VMWARE & 0xff;
-    s->card.config[PCI_SUBSYSTEM_VENDOR_ID + 1]        = PCI_VENDOR_ID_VMWARE >> 8;
-    s->card.config[PCI_SUBSYSTEM_ID] = SVGA_PCI_DEVICE_ID & 0xff;
-    s->card.config[PCI_SUBSYSTEM_ID + 1] = SVGA_PCI_DEVICE_ID >> 8;
     s->card.config[PCI_INTERRUPT_LINE] = 0xff;         /* End */
 
-    pci_register_bar(&s->card, 0, 0x10,
-                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
-    pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
-                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
+    memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
+                          "vmsvga-io", 0x10);
+    pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
-    pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
-                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
+    vmsvga_init(&s->chip, VGA_RAM_SIZE, pci_address_space(dev),
+                pci_address_space_io(dev));
 
-    vmsvga_init(&s->chip, VGA_RAM_SIZE);
+    pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, iomem);
+    pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &s->chip.fifo_ram);
 
     if (!dev->rom_bar) {
         /* compatibility with pc-0.13 and older */
-        vga_init_vbe(&s->chip.vga);
+        vga_init_vbe(&s->chip.vga, pci_address_space(dev));
     }
 
     return 0;
 }
 
-void pci_vmsvga_init(PCIBus *bus)
-{
-    pci_create_simple(bus, -1, "vmware-svga");
-}
-
 static PCIDeviceInfo vmsvga_info = {
     .qdev.name    = "vmware-svga",
     .qdev.size    = sizeof(struct pci_vmsvga_state_s),
     .qdev.vmsd    = &vmstate_vmware_vga,
+    .qdev.reset   = vmsvga_reset,
     .no_hotplug   = 1,
     .init         = pci_vmsvga_initfn,
     .romfile      = "vgabios-vmware.bin",
+
+    .vendor_id    =  PCI_VENDOR_ID_VMWARE,
+    .device_id    = SVGA_PCI_DEVICE_ID,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+    .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
+    .subsystem_id = SVGA_PCI_DEVICE_ID,
 };
 
 static void vmsvga_register(void)
index 2e0813c81b814c02af0869724623b88bdd7c256b..5132573a56f3ad239642201cf568c19e24629110 100644 (file)
@@ -4,6 +4,16 @@
 #include "qemu-common.h"
 
 /* vmware_vga.c */
-void pci_vmsvga_init(PCIBus *bus);
+static inline bool pci_vmsvga_init(PCIBus *bus)
+{
+    PCIDevice *dev;
+
+    dev = pci_try_create(bus, -1, "vmware-svga");
+    if (!dev || qdev_init(&dev->qdev) < 0) {
+        return false;
+    } else {
+        return true;
+    }
+}
 
 #endif
index cacc21767b3ee68c822855f5bbbefc5a0f7ec590..284595905dc52ddf980dfe4b638a3c66cf9f6894 100644 (file)
@@ -49,7 +49,7 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
     int can_write;
     SuperIOConfig *superio_conf = opaque;
 
-    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x  \n", addr, data);
+    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x\n", addr, data);
     if (addr == 0x3f0) {
         superio_conf->index = data & 0xff;
     } else {
@@ -73,12 +73,12 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
                 switch (superio_conf->index) {
                 case 0xe7:
                     if ((data & 0xff) != 0xfe) {
-                        DPRINTF("chage uart 1 base. unsupported yet \n");
+                        DPRINTF("chage uart 1 base. unsupported yet\n");
                     }
                     break;
                 case 0xe8:
                     if ((data & 0xff) != 0xbe) {
-                        DPRINTF("chage uart 2 base. unsupported yet \n");
+                        DPRINTF("chage uart 2 base. unsupported yet\n");
                     }
                     break;
 
@@ -95,7 +95,7 @@ static uint32_t superio_ioport_readb(void *opaque, uint32_t addr)
 {
     SuperIOConfig *superio_conf = opaque;
 
-    DPRINTF("superio_ioport_readb  address 0x%x   \n", addr);
+    DPRINTF("superio_ioport_readb  address 0x%x\n", addr);
     return (superio_conf->config[superio_conf->index]);
 }
 
@@ -133,7 +133,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
 {
     VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d);
 
-    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x \n",
+    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x\n",
            address, val, len);
 
     pci_default_write_config(d, address, val, len);
@@ -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(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(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(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;
@@ -340,7 +285,7 @@ static void pm_io_space_update(VT686PMState *s)
 static void pm_write_config(PCIDevice *d,
                             uint32_t address, uint32_t val, int len)
 {
-    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x \n",
+    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x\n",
            address, val, len);
     pci_default_write_config(d, address, val, len);
 }
@@ -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()
     }
 };
@@ -381,11 +326,6 @@ static int vt82c686b_ac97_initfn(PCIDevice *dev)
     VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
     uint8_t *pci_conf = s->dev.config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_AC97);
-    pci_config_set_class(pci_conf, PCI_CLASS_MULTIMEDIA_AUDIO);
-    pci_config_set_revision(pci_conf, 0x50);
-
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
                  PCI_COMMAND_PARITY);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
@@ -408,6 +348,10 @@ static PCIDeviceInfo via_ac97_info = {
     .qdev.desc          = "AC97",
     .qdev.size          = sizeof(VT686AC97State),
     .init               = vt82c686b_ac97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_AC97,
+    .revision           = 0x50,
+    .class_id           = PCI_CLASS_MULTIMEDIA_AUDIO,
 };
 
 static void vt82c686b_ac97_register(void)
@@ -422,11 +366,6 @@ static int vt82c686b_mc97_initfn(PCIDevice *dev)
     VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
     uint8_t *pci_conf = s->dev.config;
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_MC97);
-    pci_config_set_class(pci_conf, PCI_CLASS_COMMUNICATION_OTHER);
-    pci_config_set_revision(pci_conf, 0x30);
-
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
                  PCI_COMMAND_VGA_PALETTE);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
@@ -448,6 +387,10 @@ static PCIDeviceInfo via_mc97_info = {
     .qdev.desc          = "MC97",
     .qdev.size          = sizeof(VT686MC97State),
     .init               = vt82c686b_mc97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_MC97,
+    .class_id           = PCI_CLASS_COMMUNICATION_OTHER,
+    .revision           = 0x30,
 };
 
 static void vt82c686b_mc97_register(void)
@@ -464,11 +407,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
     uint8_t *pci_conf;
 
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ACPI);
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
-    pci_config_set_revision(pci_conf, 0x40);
-
     pci_set_word(pci_conf + PCI_COMMAND, 0);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
                  PCI_STATUS_DEVSEL_MEDIUM);
@@ -486,7 +424,8 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
 
     apm_init(&s->apm, NULL, s);
 
-    s->tmr_timer = qemu_new_timer(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);
 
@@ -516,6 +455,10 @@ static PCIDeviceInfo via_pm_info = {
     .qdev.vmsd          = &vmstate_acpi,
     .init               = vt82c686b_pm_initfn,
     .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_ACPI,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
+    .revision           = 0x40,
     .qdev.props         = (Property[]) {
         DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
         DEFINE_PROP_END_OF_LIST(),
@@ -547,14 +490,10 @@ static int vt82c686b_initfn(PCIDevice *d)
     uint8_t *wmask;
     int i;
 
-    isa_bus_new(&d->qdev);
+    isa_bus_new(&d->qdev, pci_address_space_io(d));
 
     pci_conf = d->config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ISA_BRIDGE);
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
     pci_config_set_prog_interface(pci_conf, 0x0);
-    pci_config_set_revision(pci_conf,0x40); /* Revision 4.0 */
 
     wmask = d->wmask;
     for (i = 0x00; i < 0xff; i++) {
@@ -585,6 +524,10 @@ static PCIDeviceInfo via_info = {
     .qdev.no_user = 1,
     .init         = vt82c686b_initfn,
     .config_write = vt82c686b_write_config,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
+    .class_id     = PCI_CLASS_BRIDGE_ISA,
+    .revision     = 0x40,
 };
 
 static void vt82c686b_register(void)
index e9dd56e229e4ef1a68c3b5cf91ab7fdfdae987b3..4c189656540c4b9ad1348495fbd47458538304d9 100644 (file)
@@ -132,7 +132,7 @@ void watchdog_perform_action(void)
 
     case WDT_PAUSE:             /* same as 'stop' command in monitor */
         watchdog_mon_event("pause");
-        vm_stop(0);
+        vm_stop(RUN_STATE_WATCHDOG);
         break;
 
     case WDT_DEBUG:
index 90bf5f65a73b5dbfadd2b3ceb61deb519c211d32..20d86731865b20d9c663a5b8c0b95b041848eb7d 100644 (file)
@@ -66,6 +66,7 @@
 /* Device state. */
 struct I6300State {
     PCIDevice dev;
+    MemoryRegion io_mem;
 
     int reboot_enabled;         /* "Reboot" on timer expiry.  The real action
                                  * performed depends on the -watchdog-action
@@ -129,7 +130,7 @@ static void i6300esb_restart_timer(I6300State *d, int stage)
 
     i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
 
-    qemu_mod_timer(d->timer, qemu_get_clock(vm_clock) + timeout);
+    qemu_mod_timer(d->timer, qemu_get_clock_ns(vm_clock) + timeout);
 }
 
 /* This is called when the guest disables the watchdog. */
@@ -355,30 +356,21 @@ static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static void i6300esb_map(PCIDevice *dev, int region_num,
-                         pcibus_t addr, pcibus_t size, int type)
-{
-    static CPUReadMemoryFunc * const mem_read[3] = {
-        i6300esb_mem_readb,
-        i6300esb_mem_readw,
-        i6300esb_mem_readl,
-    };
-    static CPUWriteMemoryFunc * const mem_write[3] = {
-        i6300esb_mem_writeb,
-        i6300esb_mem_writew,
-        i6300esb_mem_writel,
-    };
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    int io_mem;
-
-    i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
-                   addr, size, type);
-
-    io_mem = cpu_register_io_memory(mem_read, mem_write, d,
-                                    DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory (addr, 0x10, io_mem);
-    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
-}
+static const MemoryRegionOps i6300esb_ops = {
+    .old_mmio = {
+        .read = {
+            i6300esb_mem_readb,
+            i6300esb_mem_readw,
+            i6300esb_mem_readl,
+        },
+        .write = {
+            i6300esb_mem_writeb,
+            i6300esb_mem_writew,
+            i6300esb_mem_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
 
 static const VMStateDescription vmstate_i6300esb = {
     .name = "i6300esb_wdt",
@@ -406,20 +398,24 @@ static const VMStateDescription vmstate_i6300esb = {
 static int i6300esb_init(PCIDevice *dev)
 {
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    uint8_t *pci_conf;
 
     i6300esb_debug("I6300State = %p\n", d);
 
-    d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d);
+    d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
     d->previous_reboot_flag = 0;
 
-    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_ESB_9);
-    pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
+    memory_region_init_io(&d->io_mem, &i6300esb_ops, d, "i6300esb", 0x10);
+    pci_register_bar(&d->dev, 0, 0, &d->io_mem);
+    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
+
+    return 0;
+}
+
+static int i6300esb_exit(PCIDevice *dev)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
 
-    pci_register_bar(&d->dev, 0, 0x10,
-                            PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
+    memory_region_destroy(&d->io_mem);
 
     return 0;
 }
@@ -437,6 +433,10 @@ static PCIDeviceInfo i6300esb_info = {
     .config_read  = i6300esb_config_read,
     .config_write = i6300esb_config_write,
     .init         = i6300esb_init,
+    .exit         = i6300esb_exit,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_ESB_9,
+    .class_id     = PCI_CLASS_SYSTEM_OTHER,
 };
 
 static void i6300esb_register_devices(void)
index 1248464ff5f319519d51d392ff81229923d06804..81f22d026114f1e79f6da4e6b455b2e632d28b16 100644 (file)
@@ -58,7 +58,7 @@ static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
     ib700_debug("addr = %x, data = %x\n", addr, data);
 
     timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec();
-    qemu_mod_timer(s->timer, qemu_get_clock (vm_clock) + timeout);
+    qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout);
 }
 
 /* A write (of any value) to this register disables the timer. */
@@ -99,7 +99,7 @@ static int wdt_ib700_init(ISADevice *dev)
 
     ib700_debug("watchdog init\n");
 
-    s->timer = qemu_new_timer(vm_clock, ib700_timer_expired, s);
+    s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s);
     register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s);
     register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s);
 
index c9c674451b4c5664ffa037237d2ebd8f154cea3b..39383f43e564e2f79fd9317b331cf60a4478404e 100644 (file)
@@ -625,7 +625,7 @@ static void wm8750_fini(i2c_slave *i2c)
     WM8750State *s = (WM8750State *) i2c;
     wm8750_reset(&s->i2c);
     AUD_remove_card(&s->card);
-    qemu_free(s);
+    g_free(s);
 }
 #endif
 
index 780dcf713af6526e53cd7fcc2f884fc37d0a6895..21621115e48624ef8a0c0f351cbdb7e9e8c9aafa 100644 (file)
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -8,6 +8,8 @@
  */
 #include <inttypes.h>
 
+#include "qemu-common.h"
+
 /* xen-machine.c */
 enum xen_mode {
     XEN_EMULATE = 0,  // xen emulation, using xenner (default)
@@ -18,4 +20,35 @@ enum xen_mode {
 extern uint32_t xen_domid;
 extern enum xen_mode xen_mode;
 
+extern int xen_allowed;
+
+static inline int xen_enabled(void)
+{
+#if defined(CONFIG_XEN_BACKEND) && !defined(CONFIG_NO_XEN)
+    return xen_allowed;
+#else
+    return 0;
+#endif
+}
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
+void xen_piix3_set_irq(void *opaque, int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
+
+qemu_irq *xen_interrupt_controller_init(void);
+
+int xen_init(void);
+int xen_hvm_init(void);
+void xen_vcpu_init(void);
+void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
+
+#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size);
+#endif
+
+#if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+#  define HVM_MAX_VCPUS 32
+#endif
+
 #endif /* QEMU_HW_XEN_H */
index a2e408fa0e58bf6a8c329d04290a65b998c0c00a..d876cabb128abbd0edf181efbede9a1e76be0812 100644 (file)
@@ -43,7 +43,8 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-int xen_xc;
+XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
+XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE;
 struct xs_handle *xenstore = NULL;
 const char *xen_protocol;
 
@@ -58,8 +59,9 @@ int xenstore_write_str(const char *base, const char *node, const char *val)
     char abspath[XEN_BUFSIZE];
 
     snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
-       return -1;
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
+        return -1;
+    }
     return 0;
 }
 
@@ -73,8 +75,8 @@ char *xenstore_read_str(const char *base, const char *node)
     str = xs_read(xenstore, 0, abspath, &len);
     if (str != NULL) {
         /* move to qemu-allocated memory to make sure
-         * callers can savely qemu_free() stuff. */
-        ret = qemu_strdup(str);
+         * callers can savely g_free() stuff. */
+        ret = g_strdup(str);
         free(str);
     }
     return ret;
@@ -94,9 +96,10 @@ int xenstore_read_int(const char *base, const char *node, int *ival)
     int rc = -1;
 
     val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%d", ival))
-       rc = 0;
-    qemu_free(val);
+    if (val && 1 == sscanf(val, "%d", ival)) {
+        rc = 0;
+    }
+    g_free(val);
     return rc;
 }
 
@@ -134,16 +137,16 @@ int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
 
 const char *xenbus_strstate(enum xenbus_state state)
 {
-       static const char *const name[] = {
-               [ XenbusStateUnknown      ] = "Unknown",
-               [ XenbusStateInitialising ] = "Initialising",
-               [ XenbusStateInitWait     ] = "InitWait",
-               [ XenbusStateInitialised  ] = "Initialised",
-               [ XenbusStateConnected    ] = "Connected",
-               [ XenbusStateClosing      ] = "Closing",
-               [ XenbusStateClosed       ] = "Closed",
-       };
-       return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+    static const char *const name[] = {
+        [ XenbusStateUnknown      ] = "Unknown",
+        [ XenbusStateInitialising ] = "Initialising",
+        [ XenbusStateInitWait     ] = "InitWait",
+        [ XenbusStateInitialised  ] = "Initialised",
+        [ XenbusStateConnected    ] = "Connected",
+        [ XenbusStateClosing      ] = "Closing",
+        [ XenbusStateClosed       ] = "Closed",
+    };
+    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
 }
 
 int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
@@ -151,10 +154,11 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
     int rc;
 
     rc = xenstore_write_be_int(xendev, "state", state);
-    if (rc < 0)
-       return rc;
+    if (rc < 0) {
+        return rc;
+    }
     xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
-                 xenbus_strstate(xendev->be_state), xenbus_strstate(state));
+                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
     xendev->be_state = state;
     return 0;
 }
@@ -166,13 +170,16 @@ struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
     struct XenDevice *xendev;
 
     QTAILQ_FOREACH(xendev, &xendevs, next) {
-       if (xendev->dom != dom)
-           continue;
-       if (xendev->dev != dev)
-           continue;
-       if (strcmp(xendev->type, type) != 0)
-           continue;
-       return xendev;
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev) {
+            continue;
+        }
+        if (strcmp(xendev->type, type) != 0) {
+            continue;
+        }
+        return xendev;
     }
     return NULL;
 }
@@ -187,11 +194,12 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
     char *dom0;
 
     xendev = xen_be_find_xendev(type, dom, dev);
-    if (xendev)
-       return xendev;
+    if (xendev) {
+        return xendev;
+    }
 
     /* init new xendev */
-    xendev = qemu_mallocz(ops->size);
+    xendev = g_malloc0(ops->size);
     xendev->type  = type;
     xendev->dom   = dom;
     xendev->dev   = dev;
@@ -199,38 +207,39 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
 
     dom0 = xs_get_domain_path(xenstore, 0);
     snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
-            dom0, xendev->type, xendev->dom, xendev->dev);
+             dom0, xendev->type, xendev->dom, xendev->dev);
     snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
-            xendev->type, xendev->dev);
+             xendev->type, xendev->dev);
     free(dom0);
 
     xendev->debug      = debug;
     xendev->local_port = -1;
 
-    xendev->evtchndev = xc_evtchn_open();
-    if (xendev->evtchndev < 0) {
-       xen_be_printf(NULL, 0, "can't open evtchn device\n");
-       qemu_free(xendev);
-       return NULL;
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
     }
     fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
 
     if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-       xendev->gnttabdev = xc_gnttab_open();
-       if (xendev->gnttabdev < 0) {
-           xen_be_printf(NULL, 0, "can't open gnttab device\n");
-           xc_evtchn_close(xendev->evtchndev);
-           qemu_free(xendev);
-           return NULL;
-       }
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
     } else {
-       xendev->gnttabdev = -1;
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
     }
 
     QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
 
-    if (xendev->ops->alloc)
-       xendev->ops->alloc(xendev);
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
 
     return xendev;
 }
@@ -251,28 +260,33 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev)
         xendev = xnext;
         xnext = xendev->next.tqe_next;
 
-       if (xendev->dom != dom)
-           continue;
-       if (xendev->dev != dev && dev != -1)
-           continue;
-
-       if (xendev->ops->free)
-           xendev->ops->free(xendev);
-
-       if (xendev->fe) {
-           char token[XEN_BUFSIZE];
-           snprintf(token, sizeof(token), "fe:%p", xendev);
-           xs_unwatch(xenstore, xendev->fe, token);
-           qemu_free(xendev->fe);
-       }
-
-       if (xendev->evtchndev >= 0)
-           xc_evtchn_close(xendev->evtchndev);
-       if (xendev->gnttabdev >= 0)
-           xc_gnttab_close(xendev->gnttabdev);
-
-       QTAILQ_REMOVE(&xendevs, xendev, next);
-       qemu_free(xendev);
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev && dev != -1) {
+            continue;
+        }
+
+        if (xendev->ops->free) {
+            xendev->ops->free(xendev);
+        }
+
+        if (xendev->fe) {
+            char token[XEN_BUFSIZE];
+            snprintf(token, sizeof(token), "fe:%p", xendev);
+            xs_unwatch(xenstore, xendev->fe, token);
+            g_free(xendev->fe);
+        }
+
+        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
+            xc_evtchn_close(xendev->evtchndev);
+        }
+        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
+            xc_gnttab_close(xendev->gnttabdev);
+        }
+
+        QTAILQ_REMOVE(&xendevs, xendev, next);
+        g_free(xendev);
     }
     return NULL;
 }
@@ -285,14 +299,16 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev)
 static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
 {
     if (node == NULL  ||  strcmp(node, "online") == 0) {
-       if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
-           xendev->online = 0;
+        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
+            xendev->online = 0;
+        }
     }
 
     if (node) {
-       xen_be_printf(xendev, 2, "backend update: %s\n", node);
-       if (xendev->ops->backend_changed)
-           xendev->ops->backend_changed(xendev, node);
+        xen_be_printf(xendev, 2, "backend update: %s\n", node);
+        if (xendev->ops->backend_changed) {
+            xendev->ops->backend_changed(xendev, node);
+        }
     }
 }
 
@@ -301,25 +317,29 @@ static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
     int fe_state;
 
     if (node == NULL  ||  strcmp(node, "state") == 0) {
-       if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1)
-           fe_state = XenbusStateUnknown;
-       if (xendev->fe_state != fe_state)
-           xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
-                         xenbus_strstate(xendev->fe_state),
-                         xenbus_strstate(fe_state));
-       xendev->fe_state = fe_state;
+        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+            fe_state = XenbusStateUnknown;
+        }
+        if (xendev->fe_state != fe_state) {
+            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+                          xenbus_strstate(xendev->fe_state),
+                          xenbus_strstate(fe_state));
+        }
+        xendev->fe_state = fe_state;
     }
     if (node == NULL  ||  strcmp(node, "protocol") == 0) {
-       qemu_free(xendev->protocol);
-       xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
-       if (xendev->protocol)
-           xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+        g_free(xendev->protocol);
+        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+        if (xendev->protocol) {
+            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+        }
     }
 
     if (node) {
-       xen_be_printf(xendev, 2, "frontend update: %s\n", node);
-       if (xendev->ops->frontend_changed)
-           xendev->ops->frontend_changed(xendev, node);
+        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+        if (xendev->ops->frontend_changed) {
+            xendev->ops->frontend_changed(xendev, node);
+        }
     }
 }
 
@@ -340,28 +360,28 @@ static int xen_be_try_setup(struct XenDevice *xendev)
     int be_state;
 
     if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
-       xen_be_printf(xendev, 0, "reading backend state failed\n");
-       return -1;
+        xen_be_printf(xendev, 0, "reading backend state failed\n");
+        return -1;
     }
 
     if (be_state != XenbusStateInitialising) {
-       xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
-                     xenbus_strstate(be_state));
-       return -1;
+        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
+                      xenbus_strstate(be_state));
+        return -1;
     }
 
     xendev->fe = xenstore_read_be_str(xendev, "frontend");
     if (xendev->fe == NULL) {
-       xen_be_printf(xendev, 0, "reading frontend path failed\n");
-       return -1;
+        xen_be_printf(xendev, 0, "reading frontend path failed\n");
+        return -1;
     }
 
     /* setup frontend watch */
     snprintf(token, sizeof(token), "fe:%p", xendev);
     if (!xs_watch(xenstore, xendev->fe, token)) {
-       xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
-                     xendev->fe);
-       return -1;
+        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
+                      xendev->fe);
+        return -1;
     }
     xen_be_set_state(xendev, XenbusStateInitialising);
 
@@ -383,15 +403,16 @@ static int xen_be_try_init(struct XenDevice *xendev)
     int rc = 0;
 
     if (!xendev->online) {
-       xen_be_printf(xendev, 1, "not online\n");
-       return -1;
+        xen_be_printf(xendev, 1, "not online\n");
+        return -1;
     }
 
-    if (xendev->ops->init)
-       rc = xendev->ops->init(xendev);
+    if (xendev->ops->init) {
+        rc = xendev->ops->init(xendev);
+    }
     if (rc != 0) {
-       xen_be_printf(xendev, 1, "init() failed\n");
-       return rc;
+        xen_be_printf(xendev, 1, "init() failed\n");
+        return rc;
     }
 
     xenstore_write_be_str(xendev, "hotplug-status", "connected");
@@ -400,37 +421,61 @@ static int xen_be_try_init(struct XenDevice *xendev)
 }
 
 /*
- * Try to connect xendev.  Depends on the frontend being ready
+ * Try to initialise xendev.  Depends on the frontend being ready
  * for it (shared ring and evtchn info in xenstore, state being
  * Initialised or Connected).
  *
  * Goes to Connected on success.
  */
-static int xen_be_try_connect(struct XenDevice *xendev)
+static int xen_be_try_initialise(struct XenDevice *xendev)
 {
     int rc = 0;
 
     if (xendev->fe_state != XenbusStateInitialised  &&
-       xendev->fe_state != XenbusStateConnected) {
-       if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
-           xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
-       } else {
-           xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
-           return -1;
-       }
+        xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return -1;
+        }
     }
 
-    if (xendev->ops->connect)
-       rc = xendev->ops->connect(xendev);
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
+    }
     if (rc != 0) {
-       xen_be_printf(xendev, 0, "connect() failed\n");
-       return rc;
+        xen_be_printf(xendev, 0, "initialise() failed\n");
+        return rc;
     }
 
     xen_be_set_state(xendev, XenbusStateConnected);
     return 0;
 }
 
+/*
+ * Try to let xendev know that it is connected.  Depends on the
+ * frontend being Connected.  Note that this may be called more
+ * than once since the backend state is not modified.
+ */
+static void xen_be_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
 /*
  * Teardown connection.
  *
@@ -440,10 +485,12 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
 {
     if (xendev->be_state != XenbusStateClosing &&
         xendev->be_state != XenbusStateClosed  &&
-        xendev->ops->disconnect)
-       xendev->ops->disconnect(xendev);
-    if (xendev->be_state != state)
+        xendev->ops->disconnect) {
+        xendev->ops->disconnect(xendev);
+    }
+    if (xendev->be_state != state) {
         xen_be_set_state(xendev, state);
+    }
 }
 
 /*
@@ -451,8 +498,9 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
  */
 static int xen_be_try_reset(struct XenDevice *xendev)
 {
-    if (xendev->fe_state != XenbusStateInitialising)
+    if (xendev->fe_state != XenbusStateInitialising) {
         return -1;
+    }
 
     xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
     xen_be_set_state(xendev, XenbusStateInitialising);
@@ -468,31 +516,37 @@ void xen_be_check_state(struct XenDevice *xendev)
 
     /* frontend may request shutdown from almost anywhere */
     if (xendev->fe_state == XenbusStateClosing ||
-       xendev->fe_state == XenbusStateClosed) {
-       xen_be_disconnect(xendev, xendev->fe_state);
-       return;
+        xendev->fe_state == XenbusStateClosed) {
+        xen_be_disconnect(xendev, xendev->fe_state);
+        return;
     }
 
     /* check for possible backend state transitions */
     for (;;) {
-       switch (xendev->be_state) {
-       case XenbusStateUnknown:
-           rc = xen_be_try_setup(xendev);
-           break;
-       case XenbusStateInitialising:
-           rc = xen_be_try_init(xendev);
-           break;
-       case XenbusStateInitWait:
-           rc = xen_be_try_connect(xendev);
-           break;
+        switch (xendev->be_state) {
+        case XenbusStateUnknown:
+            rc = xen_be_try_setup(xendev);
+            break;
+        case XenbusStateInitialising:
+            rc = xen_be_try_init(xendev);
+            break;
+        case XenbusStateInitWait:
+            rc = xen_be_try_initialise(xendev);
+            break;
+        case XenbusStateConnected:
+            /* xendev->be_state doesn't change */
+            xen_be_try_connected(xendev);
+            rc = -1;
+            break;
         case XenbusStateClosed:
             rc = xen_be_try_reset(xendev);
             break;
-       default:
-           rc = -1;
-       }
-       if (rc != 0)
-           break;
+        default:
+            rc = -1;
+        }
+        if (rc != 0) {
+            break;
+        }
     }
 }
 
@@ -511,26 +565,28 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
     snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
     free(dom0);
     if (!xs_watch(xenstore, path, token)) {
-       xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
-       return -1;
+        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
+        return -1;
     }
 
     /* look for backends */
     dev = xs_directory(xenstore, 0, path, &cdev);
-    if (!dev)
-       return 0;
+    if (!dev) {
+        return 0;
+    }
     for (j = 0; j < cdev; j++) {
-       xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
-       if (xendev == NULL)
-           continue;
-       xen_be_check_state(xendev);
+        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
+        if (xendev == NULL) {
+            continue;
+        }
+        xen_be_check_state(xendev);
     }
     free(dev);
     return 0;
 }
 
 static void xenstore_update_be(char *watch, char *type, int dom,
-                              struct XenDevOps *ops)
+                               struct XenDevOps *ops)
 {
     struct XenDevice *xendev;
     char path[XEN_BUFSIZE], *dom0;
@@ -539,25 +595,28 @@ static void xenstore_update_be(char *watch, char *type, int dom,
     dom0 = xs_get_domain_path(xenstore, 0);
     len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
     free(dom0);
-    if (strncmp(path, watch, len) != 0)
-       return;
+    if (strncmp(path, watch, len) != 0) {
+        return;
+    }
     if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
-       strcpy(path, "");
-       if (sscanf(watch+len, "/%u", &dev) != 1)
-           dev = -1;
+        strcpy(path, "");
+        if (sscanf(watch+len, "/%u", &dev) != 1) {
+            dev = -1;
+        }
+    }
+    if (dev == -1) {
+        return;
     }
-    if (dev == -1)
-       return;
 
     if (0) {
-       /* FIXME: detect devices being deleted from xenstore ... */
-       xen_be_del_xendev(dom, dev);
+        /* FIXME: detect devices being deleted from xenstore ... */
+        xen_be_del_xendev(dom, dev);
     }
 
     xendev = xen_be_get_xendev(type, dom, dev, ops);
     if (xendev != NULL) {
-       xen_be_backend_changed(xendev, path);
-       xen_be_check_state(xendev);
+        xen_be_backend_changed(xendev, path);
+        xen_be_check_state(xendev);
     }
 }
 
@@ -567,10 +626,12 @@ static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
     unsigned int len;
 
     len = strlen(xendev->fe);
-    if (strncmp(xendev->fe, watch, len) != 0)
-       return;
-    if (watch[len] != '/')
-       return;
+    if (strncmp(xendev->fe, watch, len) != 0) {
+        return;
+    }
+    if (watch[len] != '/') {
+        return;
+    }
     node = watch + len + 1;
 
     xen_be_frontend_changed(xendev, node);
@@ -584,14 +645,17 @@ static void xenstore_update(void *unused)
     unsigned int dom, count;
 
     vec = xs_read_watch(xenstore, &count);
-    if (vec == NULL)
-       goto cleanup;
+    if (vec == NULL) {
+        goto cleanup;
+    }
 
     if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
-               &type, &dom, &ops) == 3)
-       xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
-    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1)
-       xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+               &type, &dom, &ops) == 3) {
+        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
+    }
+    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
+        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+    }
 
 cleanup:
     free(vec);
@@ -604,14 +668,15 @@ static void xen_be_evtchn_event(void *opaque)
 
     port = xc_evtchn_pending(xendev->evtchndev);
     if (port != xendev->local_port) {
-       xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
-                     port, xendev->local_port);
-       return;
+        xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
+                      port, xendev->local_port);
+        return;
     }
     xc_evtchn_unmask(xendev->evtchndev, port);
 
-    if (xendev->ops->event)
-       xendev->ops->event(xendev);
+    if (xendev->ops->event) {
+        xendev->ops->event(xendev);
+    }
 }
 
 /* -------------------------------------------------------------------- */
@@ -620,17 +685,17 @@ int xen_be_init(void)
 {
     xenstore = xs_daemon_open();
     if (!xenstore) {
-       xen_be_printf(NULL, 0, "can't connect to xenstored\n");
-       return -1;
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
     }
 
-    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
-       goto err;
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
+        goto err;
+    }
 
-    xen_xc = xc_interface_open();
-    if (xen_xc == -1) {
-       xen_be_printf(NULL, 0, "can't open xen interface\n");
-       goto err;
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+        /* Check if xen_init() have been called */
+        goto err;
     }
     return 0;
 
@@ -649,24 +714,26 @@ int xen_be_register(const char *type, struct XenDevOps *ops)
 
 int xen_be_bind_evtchn(struct XenDevice *xendev)
 {
-    if (xendev->local_port != -1)
-       return 0;
+    if (xendev->local_port != -1) {
+        return 0;
+    }
     xendev->local_port = xc_evtchn_bind_interdomain
-       (xendev->evtchndev, xendev->dom, xendev->remote_port);
+        (xendev->evtchndev, xendev->dom, xendev->remote_port);
     if (xendev->local_port == -1) {
-       xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
-       return -1;
+        xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+        return -1;
     }
     xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
     qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
-                       xen_be_evtchn_event, NULL, xendev);
+                        xen_be_evtchn_event, NULL, xendev);
     return 0;
 }
 
 void xen_be_unbind_evtchn(struct XenDevice *xendev)
 {
-    if (xendev->local_port == -1)
-       return;
+    if (xendev->local_port == -1) {
+        return;
+    }
     qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
     xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
     xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
@@ -690,17 +757,21 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...
     va_list args;
 
     if (xendev) {
-        if (msg_level > xendev->debug)
+        if (msg_level > xendev->debug) {
             return;
+        }
         qemu_log("xen be: %s: ", xendev->name);
-        if (msg_level == 0)
+        if (msg_level == 0) {
             fprintf(stderr, "xen be: %s: ", xendev->name);
+        }
     } else {
-        if (msg_level > debug)
+        if (msg_level > debug) {
             return;
+        }
         qemu_log("xen be core: ");
-        if (msg_level == 0)
+        if (msg_level == 0) {
             fprintf(stderr, "xen be core: ");
+        }
     }
     va_start(args, fmt);
     qemu_log_vprintf(fmt, args);
index 1b428e3bf407dd1b65aa8f1cbfef06fce43b568e..330563090349075c5d3fd4b27193482727de301e 100644 (file)
@@ -21,7 +21,8 @@ struct XenDevOps {
     uint32_t  flags;
     void      (*alloc)(struct XenDevice *xendev);
     int       (*init)(struct XenDevice *xendev);
-    int       (*connect)(struct XenDevice *xendev);
+    int       (*initialise)(struct XenDevice *xendev);
+    void      (*connected)(struct XenDevice *xendev);
     void      (*event)(struct XenDevice *xendev);
     void      (*disconnect)(struct XenDevice *xendev);
     int       (*free)(struct XenDevice *xendev);
@@ -45,8 +46,8 @@ struct XenDevice {
     int                remote_port;
     int                local_port;
 
-    int                evtchndev;
-    int                gnttabdev;
+    XenEvtchn          evtchndev;
+    XenGnttab          gnttabdev;
 
     struct XenDevOps   *ops;
     QTAILQ_ENTRY(XenDevice) next;
@@ -55,7 +56,7 @@ struct XenDevice {
 /* ------------------------------------------------------------- */
 
 /* variables */
-extern int xen_xc;
+extern XenXC xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 
index 8a55b44f0bdc24e2f1ed369c466e4f5247d9acb2..0409ac79713b128a1f229421028889b651d93103 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef QEMU_HW_XEN_COMMON_H
 #define QEMU_HW_XEN_COMMON_H 1
 
+#include "config-host.h"
+
 #include <stddef.h>
 #include <inttypes.h>
 
 #include "qemu-queue.h"
 
 /*
- * tweaks needed to build with different xen versions
- *  0x00030205 -> 3.1.0
- *  0x00030207 -> 3.2.0
- *  0x00030208 -> unstable
+ * We don't support Xen prior to 3.3.0.
  */
-#include <xen/xen-compat.h>
-#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030205
-# define evtchn_port_or_error_t int
-#endif
-#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030207
-# define xc_map_foreign_pages xc_map_foreign_batch
+
+/* Xen before 4.0 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+static inline void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
+                                        xen_pfn_t *arr, int *err,
+                                        unsigned int num)
+{
+    return xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
+}
 #endif
-#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030208
-# define xen_mb()  mb()
-# define xen_rmb() rmb()
-# define xen_wmb() wmb()
+
+
+/* Xen before 4.1 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 410
+
+typedef int XenXC;
+typedef int XenEvtchn;
+typedef int XenGnttab;
+
+#  define XC_INTERFACE_FMT "%i"
+#  define XC_HANDLER_INITIAL_VALUE    -1
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open();
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open();
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open();
+}
+
+static inline int xc_fd(int xen_xc)
+{
+    return xen_xc;
+}
+
+
+static inline int xc_domain_populate_physmap_exact
+    (XenXC xc_handle, uint32_t domid, unsigned long nr_extents,
+     unsigned int extent_order, unsigned int mem_flags, xen_pfn_t *extent_start)
+{
+    return xc_domain_memory_populate_physmap
+        (xc_handle, domid, nr_extents, extent_order, mem_flags, extent_start);
+}
+
+static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
+                                           unsigned int space, unsigned long idx,
+                                           xen_pfn_t gpfn)
+{
+    struct xen_add_to_physmap xatp = {
+        .domid = domid,
+        .space = space,
+        .idx = idx,
+        .gpfn = gpfn,
+    };
+
+    return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
+}
+
+static inline struct xs_handle *xs_open(unsigned long flags)
+{
+    return xs_daemon_open();
+}
+
+static inline void xs_close(struct xs_handle *xsh)
+{
+    if (xsh != NULL) {
+        xs_daemon_close(xsh);
+    }
+}
+
+
+/* Xen 4.1 */
+#else
+
+typedef xc_interface *XenXC;
+typedef xc_evtchn *XenEvtchn;
+typedef xc_gnttab *XenGnttab;
+
+#  define XC_INTERFACE_FMT "%p"
+#  define XC_HANDLER_INITIAL_VALUE    NULL
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open(logger, open_flags);
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open(logger, open_flags);
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open(logger, dombuild_logger, open_flags);
+}
+
+/* FIXME There is now way to have the xen fd */
+static inline int xc_fd(xc_interface *xen_xc)
+{
+    return -1;
+}
 #endif
 
+void destroy_hvm_domain(void);
+
 #endif /* QEMU_HW_XEN_COMMON_H */
index d2261f4139252e0f56f4f71f18874e78f2057840..edcb31ce6629c0a74e7a9ae911dec5b57fa50a5c 100644 (file)
@@ -33,7 +33,6 @@
 #include <xenctrl.h>
 
 #include "hw.h"
-#include "sysemu.h"
 #include "qemu-char.h"
 #include "xen_backend.h"
 
@@ -71,7 +70,7 @@ static void buffer_append(struct XenConsole *con)
 
     if ((buffer->capacity - buffer->size) < size) {
        buffer->capacity += (size + 1024);
-       buffer->data = qemu_realloc(buffer->data, buffer->capacity);
+       buffer->data = g_realloc(buffer->data, buffer->capacity);
     }
 
     while (cons != prod)
@@ -90,7 +89,7 @@ static void buffer_append(struct XenConsole *con)
        uint8_t *maxpos = buffer->data + buffer->max_capacity;
 
        memmove(maxpos - over, maxpos, over);
-       buffer->data = qemu_realloc(buffer->data, buffer->max_capacity);
+       buffer->data = g_realloc(buffer->data, buffer->max_capacity);
        buffer->size = buffer->capacity = buffer->max_capacity;
 
        if (buffer->consumed > buffer->max_capacity - over)
@@ -157,7 +156,7 @@ static void xencons_send(struct XenConsole *con)
 
     size = con->buffer.size - con->buffer.consumed;
     if (con->chr)
-        len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+        len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed,
                              size);
     else
         len = size;
@@ -180,7 +179,9 @@ static void xencons_send(struct XenConsole *con)
 static int con_init(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-    char *type, *dom;
+    char *type, *dom, label[32];
+    int ret = 0;
+    const char *output;
 
     /* setup */
     dom = xs_get_domain_path(xenstore, con->xendev.dom);
@@ -190,19 +191,28 @@ static int con_init(struct XenDevice *xendev)
     type = xenstore_read_str(con->console, "type");
     if (!type || strcmp(type, "ioemu") != 0) {
        xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
-       return -1;
+        ret = -1;
+        goto out;
     }
 
-    if (!serial_hds[con->xendev.dev])
-       xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
-                      con->xendev.dev);
-    else
+    output = xenstore_read_str(con->console, "output");
+
+    /* no Xen override, use qemu output device */
+    if (output == NULL) {
         con->chr = serial_hds[con->xendev.dev];
+    } else {
+        snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
+        con->chr = qemu_chr_new(label, output, NULL);
+    }
 
-    return 0;
+    xenstore_store_pv_console_info(con->xendev.dev, con->chr);
+
+out:
+    g_free(type);
+    return ret;
 }
 
-static int con_connect(struct XenDevice *xendev)
+static int con_initialise(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
     int limit;
@@ -263,7 +273,7 @@ struct XenDevOps xen_console_ops = {
     .size       = sizeof(struct XenConsole),
     .flags      = DEVOPS_FLAG_IGNORE_STATE,
     .init       = con_init,
-    .connect    = con_connect,
+    .initialise = con_initialise,
     .event      = con_event,
     .disconnect = con_disconnect,
 };
index 8d50216c0486e74b0686a9736adfdd0a4dc8ac79..41accbbfa9a473b052f8d6d744446549544f38b6 100644 (file)
@@ -14,7 +14,7 @@ static void xen_config_cleanup_dir(char *dir)
 {
     struct xs_dirs *d;
 
-    d = qemu_malloc(sizeof(*d));
+    d = g_malloc(sizeof(*d));
     d->xs_dir = dir;
     QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
 }
@@ -43,7 +43,7 @@ static int xen_config_dev_mkdir(char *dev, int p)
        xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
        return -1;
     }
-    xen_config_cleanup_dir(qemu_strdup(dev));
+    xen_config_cleanup_dir(g_strdup(dev));
 
     if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
        xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
@@ -96,7 +96,7 @@ int xen_config_dev_blk(DriveInfo *disk)
 {
     char fe[256], be[256];
     int vdev = 202 * 256 + 16 * disk->unit;
-    int cdrom = disk->bdrv->type == BDRV_TYPE_CDROM;
+    int cdrom = disk->media_cd;
     const char *devtype = cdrom ? "cdrom" : "disk";
     const char *mode    = cdrom ? "r"     : "w";
 
@@ -126,8 +126,8 @@ int xen_config_dev_nic(NICInfo *nic)
     char mac[20];
 
     snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
-            nic->macaddr[0], nic->macaddr[1], nic->macaddr[2],
-            nic->macaddr[3], nic->macaddr[4], nic->macaddr[5]);
+             nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
+             nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
     xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", nic->vlan->id, mac);
     xen_config_dev_dirs("vif", "qnic", nic->vlan->id, fe, be, sizeof(fe));
 
index ed9e5eb4d7ac56d6021390808ef16c3d932ffca4..286bbac54a198d3b22377c77451b432e06ae76cb 100644 (file)
@@ -79,6 +79,7 @@ struct ioreq {
 
     struct XenBlkDev    *blkdev;
     QLIST_ENTRY(ioreq)   list;
+    BlockAcctCookie     acct;
 };
 
 struct XenBlkDev {
@@ -120,17 +121,18 @@ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
     struct ioreq *ioreq = NULL;
 
     if (QLIST_EMPTY(&blkdev->freelist)) {
-       if (blkdev->requests_total >= max_requests)
-           goto out;
-       /* allocate new struct */
-       ioreq = qemu_mallocz(sizeof(*ioreq));
-       ioreq->blkdev = blkdev;
-       blkdev->requests_total++;
+        if (blkdev->requests_total >= max_requests) {
+            goto out;
+        }
+        /* allocate new struct */
+        ioreq = g_malloc0(sizeof(*ioreq));
+        ioreq->blkdev = blkdev;
+        blkdev->requests_total++;
         qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
     } else {
-       /* get one from freelist */
-       ioreq = QLIST_FIRST(&blkdev->freelist);
-       QLIST_REMOVE(ioreq, list);
+        /* get one from freelist */
+        ioreq = QLIST_FIRST(&blkdev->freelist);
+        QLIST_REMOVE(ioreq, list);
         qemu_iovec_reset(&ioreq->v);
     }
     QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
@@ -173,30 +175,32 @@ static int ioreq_parse(struct ioreq *ioreq)
     int i;
 
     xen_be_printf(&blkdev->xendev, 3,
-                 "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
-                 ioreq->req.operation, ioreq->req.nr_segments,
-                 ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
+                  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
+                  ioreq->req.operation, ioreq->req.nr_segments,
+                  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
     switch (ioreq->req.operation) {
     case BLKIF_OP_READ:
-       ioreq->prot = PROT_WRITE; /* to memory */
-       break;
+        ioreq->prot = PROT_WRITE; /* to memory */
+        break;
     case BLKIF_OP_WRITE_BARRIER:
         if (!ioreq->req.nr_segments) {
             ioreq->presync = 1;
             return 0;
         }
-       if (!syncwrite)
-           ioreq->presync = ioreq->postsync = 1;
-       /* fall through */
+        if (!syncwrite) {
+            ioreq->presync = ioreq->postsync = 1;
+        }
+        /* fall through */
     case BLKIF_OP_WRITE:
-       ioreq->prot = PROT_READ; /* from memory */
-       if (syncwrite)
-           ioreq->postsync = 1;
-       break;
+        ioreq->prot = PROT_READ; /* from memory */
+        if (syncwrite) {
+            ioreq->postsync = 1;
+        }
+        break;
     default:
-       xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
-                     ioreq->req.operation);
-       goto err;
+        xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+                      ioreq->req.operation);
+        goto err;
     };
 
     if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
@@ -206,29 +210,29 @@ static int ioreq_parse(struct ioreq *ioreq)
 
     ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
     for (i = 0; i < ioreq->req.nr_segments; i++) {
-       if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
-           xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
-           goto err;
-       }
-       if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
-           xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
-           goto err;
-       }
-       if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
-           xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
-           goto err;
-       }
-
-       ioreq->domids[i] = blkdev->xendev.dom;
-       ioreq->refs[i]   = ioreq->req.seg[i].gref;
-
-       mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
-       len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+        if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+            xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+            xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+            xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
+            goto err;
+        }
+
+        ioreq->domids[i] = blkdev->xendev.dom;
+        ioreq->refs[i]   = ioreq->req.seg[i].gref;
+
+        mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
+        len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
         qemu_iovec_add(&ioreq->v, (void*)mem, len);
     }
     if (ioreq->start + ioreq->v.size > blkdev->file_size) {
-       xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
-       goto err;
+        xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+        goto err;
     }
     return 0;
 
@@ -239,66 +243,73 @@ err:
 
 static void ioreq_unmap(struct ioreq *ioreq)
 {
-    int gnt = ioreq->blkdev->xendev.gnttabdev;
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
     int i;
 
-    if (ioreq->v.niov == 0)
+    if (ioreq->v.niov == 0) {
         return;
+    }
     if (batch_maps) {
-       if (!ioreq->pages)
-           return;
-       if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0)
-           xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
-                         strerror(errno));
-       ioreq->blkdev->cnt_map -= ioreq->v.niov;
-       ioreq->pages = NULL;
+        if (!ioreq->pages) {
+            return;
+        }
+        if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                          strerror(errno));
+        }
+        ioreq->blkdev->cnt_map -= ioreq->v.niov;
+        ioreq->pages = NULL;
     } else {
-       for (i = 0; i < ioreq->v.niov; i++) {
-           if (!ioreq->page[i])
-               continue;
-           if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0)
-               xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
-                             strerror(errno));
-           ioreq->blkdev->cnt_map--;
-           ioreq->page[i] = NULL;
-       }
+        for (i = 0; i < ioreq->v.niov; i++) {
+            if (!ioreq->page[i]) {
+                continue;
+            }
+            if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                              strerror(errno));
+            }
+            ioreq->blkdev->cnt_map--;
+            ioreq->page[i] = NULL;
+        }
     }
 }
 
 static int ioreq_map(struct ioreq *ioreq)
 {
-    int gnt = ioreq->blkdev->xendev.gnttabdev;
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
     int i;
 
-    if (ioreq->v.niov == 0)
+    if (ioreq->v.niov == 0) {
         return 0;
+    }
     if (batch_maps) {
-       ioreq->pages = xc_gnttab_map_grant_refs
-           (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
-       if (ioreq->pages == NULL) {
-           xen_be_printf(&ioreq->blkdev->xendev, 0,
-                         "can't map %d grant refs (%s, %d maps)\n",
-                         ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map);
-           return -1;
-       }
-       for (i = 0; i < ioreq->v.niov; i++)
-           ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE +
-               (uintptr_t)ioreq->v.iov[i].iov_base;
-       ioreq->blkdev->cnt_map += ioreq->v.niov;
+        ioreq->pages = xc_gnttab_map_grant_refs
+            (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+        if (ioreq->pages == NULL) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0,
+                          "can't map %d grant refs (%s, %d maps)\n",
+                          ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map);
+            return -1;
+        }
+        for (i = 0; i < ioreq->v.niov; i++) {
+            ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE +
+                (uintptr_t)ioreq->v.iov[i].iov_base;
+        }
+        ioreq->blkdev->cnt_map += ioreq->v.niov;
     } else  {
-       for (i = 0; i < ioreq->v.niov; i++) {
-           ioreq->page[i] = xc_gnttab_map_grant_ref
-               (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
-           if (ioreq->page[i] == NULL) {
-               xen_be_printf(&ioreq->blkdev->xendev, 0,
-                             "can't map grant ref %d (%s, %d maps)\n",
-                             ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map);
-               ioreq_unmap(ioreq);
-               return -1;
-           }
-           ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base;
-           ioreq->blkdev->cnt_map++;
-       }
+        for (i = 0; i < ioreq->v.niov; i++) {
+            ioreq->page[i] = xc_gnttab_map_grant_ref
+                (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+            if (ioreq->page[i] == NULL) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0,
+                              "can't map grant ref %d (%s, %d maps)\n",
+                              ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+                ioreq_unmap(ioreq);
+                return -1;
+            }
+            ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base;
+            ioreq->blkdev->cnt_map++;
+        }
     }
     return 0;
 }
@@ -306,57 +317,59 @@ static int ioreq_map(struct ioreq *ioreq)
 static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
 {
     struct XenBlkDev *blkdev = ioreq->blkdev;
-    int i, rc, len = 0;
+    int i, rc;
     off_t pos;
 
-    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
-       goto err;
-    if (ioreq->presync)
-       bdrv_flush(blkdev->bs);
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+        goto err_no_map;
+    }
+    if (ioreq->presync) {
+        bdrv_flush(blkdev->bs);
+    }
 
     switch (ioreq->req.operation) {
     case BLKIF_OP_READ:
-       pos = ioreq->start;
-       for (i = 0; i < ioreq->v.niov; i++) {
-           rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE,
-                          ioreq->v.iov[i].iov_base,
-                          ioreq->v.iov[i].iov_len / BLOCK_SIZE);
-           if (rc != 0) {
-               xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n",
-                             ioreq->v.iov[i].iov_base,
-                             ioreq->v.iov[i].iov_len);
-               goto err;
-           }
-           len += ioreq->v.iov[i].iov_len;
-           pos += ioreq->v.iov[i].iov_len;
-       }
-       break;
+        pos = ioreq->start;
+        for (i = 0; i < ioreq->v.niov; i++) {
+            rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE,
+                           ioreq->v.iov[i].iov_base,
+                           ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+            if (rc != 0) {
+                xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n",
+                              ioreq->v.iov[i].iov_base,
+                              ioreq->v.iov[i].iov_len);
+                goto err;
+            }
+            pos += ioreq->v.iov[i].iov_len;
+        }
+        break;
     case BLKIF_OP_WRITE:
     case BLKIF_OP_WRITE_BARRIER:
-        if (!ioreq->req.nr_segments)
+        if (!ioreq->req.nr_segments) {
             break;
-       pos = ioreq->start;
-       for (i = 0; i < ioreq->v.niov; i++) {
-           rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
-                           ioreq->v.iov[i].iov_base,
-                           ioreq->v.iov[i].iov_len / BLOCK_SIZE);
-           if (rc != 0) {
-               xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n",
-                             ioreq->v.iov[i].iov_base,
-                             ioreq->v.iov[i].iov_len);
-               goto err;
-           }
-           len += ioreq->v.iov[i].iov_len;
-           pos += ioreq->v.iov[i].iov_len;
-       }
-       break;
+        }
+        pos = ioreq->start;
+        for (i = 0; i < ioreq->v.niov; i++) {
+            rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
+                            ioreq->v.iov[i].iov_base,
+                            ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+            if (rc != 0) {
+                xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n",
+                              ioreq->v.iov[i].iov_base,
+                              ioreq->v.iov[i].iov_len);
+                goto err;
+            }
+            pos += ioreq->v.iov[i].iov_len;
+        }
+        break;
     default:
-       /* unknown operation (shouldn't happen -- parse catches this) */
-       goto err;
+        /* unknown operation (shouldn't happen -- parse catches this) */
+        goto err;
     }
 
-    if (ioreq->postsync)
-       bdrv_flush(blkdev->bs);
+    if (ioreq->postsync) {
+        bdrv_flush(blkdev->bs);
+    }
     ioreq->status = BLKIF_RSP_OKAY;
 
     ioreq_unmap(ioreq);
@@ -364,6 +377,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;
 }
@@ -379,12 +395,14 @@ static void qemu_aio_complete(void *opaque, int ret)
     }
 
     ioreq->aio_inflight--;
-    if (ioreq->aio_inflight > 0)
+    if (ioreq->aio_inflight > 0) {
         return;
+    }
 
     ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
     ioreq_unmap(ioreq);
     ioreq_finish(ioreq);
+    bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
     qemu_bh_schedule(ioreq->blkdev->bh);
 }
 
@@ -392,41 +410,51 @@ 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;
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+        goto err_no_map;
+    }
 
     ioreq->aio_inflight++;
-    if (ioreq->presync)
-       bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    if (ioreq->presync) {
+        bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    }
 
     switch (ioreq->req.operation) {
     case BLKIF_OP_READ:
+        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_READ);
         ioreq->aio_inflight++;
         bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
                        &ioreq->v, ioreq->v.size / BLOCK_SIZE,
                        qemu_aio_complete, ioreq);
-       break;
+        break;
     case BLKIF_OP_WRITE:
     case BLKIF_OP_WRITE_BARRIER:
-        ioreq->aio_inflight++;
-        if (!ioreq->req.nr_segments)
+        if (!ioreq->req.nr_segments) {
             break;
+        }
+
+        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_WRITE);
+        ioreq->aio_inflight++;
         bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
                         &ioreq->v, ioreq->v.size / BLOCK_SIZE,
                         qemu_aio_complete, ioreq);
-       break;
+        break;
     default:
-       /* unknown operation (shouldn't happen -- parse catches this) */
-       goto err;
+        /* unknown operation (shouldn't happen -- parse catches this) */
+        goto err;
     }
 
-    if (ioreq->postsync)
-       bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    if (ioreq->postsync) {
+        bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    }
     qemu_aio_complete(ioreq, 0);
 
     return 0;
 
 err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
     ioreq->status = BLKIF_RSP_ERROR;
     return -1;
 }
@@ -446,36 +474,37 @@ static int blk_send_response_one(struct ioreq *ioreq)
     /* Place on the response ring for the relevant domain. */
     switch (blkdev->protocol) {
     case BLKIF_PROTOCOL_NATIVE:
-       dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
-       break;
+        dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
+        break;
     case BLKIF_PROTOCOL_X86_32:
         dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
                                 blkdev->rings.x86_32_part.rsp_prod_pvt);
-       break;
+        break;
     case BLKIF_PROTOCOL_X86_64:
         dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
                                 blkdev->rings.x86_64_part.rsp_prod_pvt);
-       break;
+        break;
     default:
-       dst = NULL;
+        dst = NULL;
     }
     memcpy(dst, &resp, sizeof(resp));
     blkdev->rings.common.rsp_prod_pvt++;
 
     RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
     if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
-       /*
-        * Tail check for pending requests. Allows frontend to avoid
-        * notifications if requests are already in flight (lower
-        * overheads and promotes batching).
-        */
-       RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
+        /*
+         * Tail check for pending requests. Allows frontend to avoid
+         * notifications if requests are already in flight (lower
+         * overheads and promotes batching).
+         */
+        RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
     } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
-       have_requests = 1;
+        have_requests = 1;
     }
 
-    if (have_requests)
-       blkdev->more_work++;
+    if (have_requests) {
+        blkdev->more_work++;
+    }
     return send_notify;
 }
 
@@ -487,28 +516,29 @@ static void blk_send_response_all(struct XenBlkDev *blkdev)
 
     while (!QLIST_EMPTY(&blkdev->finished)) {
         ioreq = QLIST_FIRST(&blkdev->finished);
-       send_notify += blk_send_response_one(ioreq);
-       ioreq_release(ioreq);
+        send_notify += blk_send_response_one(ioreq);
+        ioreq_release(ioreq);
+    }
+    if (send_notify) {
+        xen_be_send_notify(&blkdev->xendev);
     }
-    if (send_notify)
-       xen_be_send_notify(&blkdev->xendev);
 }
 
 static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
 {
     switch (blkdev->protocol) {
     case BLKIF_PROTOCOL_NATIVE:
-       memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
-              sizeof(ioreq->req));
-       break;
+        memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
+               sizeof(ioreq->req));
+        break;
     case BLKIF_PROTOCOL_X86_32:
         blkif_get_x86_32_req(&ioreq->req,
                              RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
-       break;
+        break;
     case BLKIF_PROTOCOL_X86_64:
         blkif_get_x86_64_req(&ioreq->req,
                              RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
-       break;
+        break;
     }
     return 0;
 }
@@ -524,12 +554,14 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
     rp = blkdev->rings.common.sring->req_prod;
     xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
 
-    if (use_aio)
+    if (use_aio) {
         blk_send_response_all(blkdev);
+    }
     while (rc != rp) {
         /* pull request from ring */
-        if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc))
+        if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
             break;
+        }
         ioreq = ioreq_start(blkdev);
         if (ioreq == NULL) {
             blkdev->more_work++;
@@ -540,8 +572,9 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
 
         /* parse them */
         if (ioreq_parse(ioreq) != 0) {
-            if (blk_send_response_one(ioreq))
+            if (blk_send_response_one(ioreq)) {
                 xen_be_send_notify(&blkdev->xendev);
+            }
             ioreq_release(ioreq);
             continue;
         }
@@ -554,11 +587,13 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
             ioreq_runio_qemu_sync(ioreq);
         }
     }
-    if (!use_aio)
+    if (!use_aio) {
         blk_send_response_all(blkdev);
+    }
 
-    if (blkdev->more_work && blkdev->requests_inflight < max_requests)
+    if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
         qemu_bh_schedule(blkdev->bh);
+    }
 }
 
 /* ------------------------------------------------------------- */
@@ -577,56 +612,68 @@ static void blk_alloc(struct XenDevice *xendev)
     QLIST_INIT(&blkdev->finished);
     QLIST_INIT(&blkdev->freelist);
     blkdev->bh = qemu_bh_new(blk_bh, blkdev);
-    if (xen_mode != XEN_EMULATE)
+    if (xen_mode != XEN_EMULATE) {
         batch_maps = 1;
+    }
 }
 
 static int blk_init(struct XenDevice *xendev)
 {
     struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    int index, qflags, have_barriers, info = 0;
-    char *h;
+    int index, qflags, info = 0;
 
     /* read xenstore entries */
     if (blkdev->params == NULL) {
-       blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
-        h = strchr(blkdev->params, ':');
-       if (h != NULL) {
-           blkdev->fileproto = blkdev->params;
-           blkdev->filename  = h+1;
-           *h = 0;
-       } else {
-           blkdev->fileproto = "<unset>";
-           blkdev->filename  = blkdev->params;
-       }
-    }
-    if (blkdev->mode == NULL)
-       blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
-    if (blkdev->type == NULL)
-       blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
-    if (blkdev->dev == NULL)
-       blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
-    if (blkdev->devtype == NULL)
-       blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+        char *h = NULL;
+        blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+        if (blkdev->params != NULL) {
+            h = strchr(blkdev->params, ':');
+        }
+        if (h != NULL) {
+            blkdev->fileproto = blkdev->params;
+            blkdev->filename  = h+1;
+            *h = 0;
+        } else {
+            blkdev->fileproto = "<unset>";
+            blkdev->filename  = blkdev->params;
+        }
+    }
+    if (!strcmp("aio", blkdev->fileproto)) {
+        blkdev->fileproto = "raw";
+    }
+    if (blkdev->mode == NULL) {
+        blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+    }
+    if (blkdev->type == NULL) {
+        blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+    }
+    if (blkdev->dev == NULL) {
+        blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
+    }
+    if (blkdev->devtype == NULL) {
+        blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+    }
 
     /* do we have all we need? */
     if (blkdev->params == NULL ||
-       blkdev->mode == NULL   ||
-       blkdev->type == NULL   ||
-       blkdev->dev == NULL)
-       return -1;
+        blkdev->mode == NULL   ||
+        blkdev->type == NULL   ||
+        blkdev->dev == NULL) {
+        goto out_error;
+    }
 
     /* read-only ? */
     if (strcmp(blkdev->mode, "w") == 0) {
-       qflags = BDRV_O_RDWR;
+        qflags = BDRV_O_RDWR;
     } else {
-       qflags = 0;
-       info  |= VDISK_READONLY;
+        qflags = 0;
+        info  |= VDISK_READONLY;
     }
 
     /* cdrom ? */
-    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom"))
-       info  |= VDISK_CDROM;
+    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
+        info  |= VDISK_CDROM;
+    }
 
     /* init qemu block driver */
     index = (blkdev->xendev.dev - 202 * 256) / 16;
@@ -635,95 +682,118 @@ static int blk_init(struct XenDevice *xendev)
         /* setup via xenbus -> create new block driver instance */
         xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
         blkdev->bs = bdrv_new(blkdev->dev);
-        if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
-                      bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
-            bdrv_delete(blkdev->bs);
-            return -1;
+        if (blkdev->bs) {
+            if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
+                        bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
+                bdrv_delete(blkdev->bs);
+                blkdev->bs = NULL;
+            }
+        }
+        if (!blkdev->bs) {
+            goto out_error;
         }
     } else {
         /* setup via qemu cmdline -> already setup for us */
         xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
-       blkdev->bs = blkdev->dinfo->bdrv;
+        blkdev->bs = blkdev->dinfo->bdrv;
     }
+    bdrv_attach_dev_nofail(blkdev->bs, blkdev);
     blkdev->file_blk  = BLOCK_SIZE;
     blkdev->file_size = bdrv_getlength(blkdev->bs);
     if (blkdev->file_size < 0) {
         xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
                       (int)blkdev->file_size, strerror(-blkdev->file_size),
                       blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
-       blkdev->file_size = 0;
+        blkdev->file_size = 0;
     }
-    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
 
     xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
-                 " size %" PRId64 " (%" PRId64 " MB)\n",
-                 blkdev->type, blkdev->fileproto, blkdev->filename,
-                 blkdev->file_size, blkdev->file_size >> 20);
+                  " size %" PRId64 " (%" PRId64 " MB)\n",
+                  blkdev->type, blkdev->fileproto, blkdev->filename,
+                  blkdev->file_size, blkdev->file_size >> 20);
 
     /* fill info */
-    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1);
     xenstore_write_be_int(&blkdev->xendev, "info",            info);
     xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
     xenstore_write_be_int(&blkdev->xendev, "sectors",
-                         blkdev->file_size / blkdev->file_blk);
+                          blkdev->file_size / blkdev->file_blk);
     return 0;
+
+out_error:
+    g_free(blkdev->params);
+    blkdev->params = NULL;
+    g_free(blkdev->mode);
+    blkdev->mode = NULL;
+    g_free(blkdev->type);
+    blkdev->type = NULL;
+    g_free(blkdev->dev);
+    blkdev->dev = NULL;
+    g_free(blkdev->devtype);
+    blkdev->devtype = NULL;
+    return -1;
 }
 
 static int blk_connect(struct XenDevice *xendev)
 {
     struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
 
-    if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1)
-       return -1;
+    if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
+        return -1;
+    }
     if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
-                             &blkdev->xendev.remote_port) == -1)
-       return -1;
+                             &blkdev->xendev.remote_port) == -1) {
+        return -1;
+    }
 
     blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
     if (blkdev->xendev.protocol) {
-        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0)
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
             blkdev->protocol = BLKIF_PROTOCOL_X86_32;
-        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0)
+        }
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
             blkdev->protocol = BLKIF_PROTOCOL_X86_64;
+        }
     }
 
     blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
-                                           blkdev->xendev.dom,
-                                           blkdev->ring_ref,
-                                           PROT_READ | PROT_WRITE);
-    if (!blkdev->sring)
-       return -1;
+                                            blkdev->xendev.dom,
+                                            blkdev->ring_ref,
+                                            PROT_READ | PROT_WRITE);
+    if (!blkdev->sring) {
+        return -1;
+    }
     blkdev->cnt_map++;
 
     switch (blkdev->protocol) {
     case BLKIF_PROTOCOL_NATIVE:
     {
-       blkif_sring_t *sring_native = blkdev->sring;
-       BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
-       break;
+        blkif_sring_t *sring_native = blkdev->sring;
+        BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
+        break;
     }
     case BLKIF_PROTOCOL_X86_32:
     {
-       blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+        blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
 
         BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
-       break;
+        break;
     }
     case BLKIF_PROTOCOL_X86_64:
     {
-       blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+        blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
 
         BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
-       break;
+        break;
     }
     }
 
     xen_be_bind_evtchn(&blkdev->xendev);
 
     xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
-                 "remote port %d, local port %d\n",
-                 blkdev->xendev.protocol, blkdev->ring_ref,
-                 blkdev->xendev.remote_port, blkdev->xendev.local_port);
+                  "remote port %d, local port %d\n",
+                  blkdev->xendev.protocol, blkdev->ring_ref,
+                  blkdev->xendev.remote_port, blkdev->xendev.local_port);
     return 0;
 }
 
@@ -737,14 +807,14 @@ static void blk_disconnect(struct XenDevice *xendev)
             bdrv_close(blkdev->bs);
             bdrv_delete(blkdev->bs);
         }
-       blkdev->bs = NULL;
+        blkdev->bs = NULL;
     }
     xen_be_unbind_evtchn(&blkdev->xendev);
 
     if (blkdev->sring) {
-       xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
-       blkdev->cnt_map--;
-       blkdev->sring = NULL;
+        xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+        blkdev->cnt_map--;
+        blkdev->sring = NULL;
     }
 }
 
@@ -754,17 +824,17 @@ static int blk_free(struct XenDevice *xendev)
     struct ioreq *ioreq;
 
     while (!QLIST_EMPTY(&blkdev->freelist)) {
-       ioreq = QLIST_FIRST(&blkdev->freelist);
+        ioreq = QLIST_FIRST(&blkdev->freelist);
         QLIST_REMOVE(ioreq, list);
         qemu_iovec_destroy(&ioreq->v);
-       qemu_free(ioreq);
+        g_free(ioreq);
     }
 
-    qemu_free(blkdev->params);
-    qemu_free(blkdev->mode);
-    qemu_free(blkdev->type);
-    qemu_free(blkdev->dev);
-    qemu_free(blkdev->devtype);
+    g_free(blkdev->params);
+    g_free(blkdev->mode);
+    g_free(blkdev->type);
+    g_free(blkdev->dev);
+    g_free(blkdev->devtype);
     qemu_bh_delete(blkdev->bh);
     return 0;
 }
@@ -781,7 +851,7 @@ struct XenDevOps xen_blkdev_ops = {
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .alloc      = blk_alloc,
     .init       = blk_init,
-    .connect    = blk_connect,
+    .initialise    = blk_connect,
     .disconnect = blk_disconnect,
     .event      = blk_event,
     .free       = blk_free,
index 7f1fd66eafca072070c1e87e309e4be7ea422a11..a6a12e5930dd194fe1830fd1d0a342846d3b6c99 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"
 
@@ -149,7 +148,7 @@ static void xen_domain_poll(void *opaque)
         goto quit;
     }
 
-    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
     return;
 
 quit:
@@ -176,8 +175,9 @@ static int xen_domain_watcher(void)
     for (i = 3; i < n; i++) {
         if (i == fd[0])
             continue;
-        if (i == xen_xc)
+        if (i == xc_fd(xen_xc)) {
             continue;
+        }
         close(i);
     }
 
@@ -291,8 +291,8 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk,
         goto err;
     }
 
-    xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
-    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL);
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
     return 0;
 
 err:
index 77a34bf111dffedc9c95823b3c694e27d316bdee..7985d11d5ad40167a5de89dc1aa4f4c6e3ba5a38 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"
@@ -114,6 +113,7 @@ static QEMUMachine xenpv_machine = {
     .desc = "Xen Para-virtualized PC",
     .init = xen_init_pv,
     .max_cpus = 1,
+    .default_machine_opts = "accel=xen",
 };
 
 static void xenpv_machine_init(void)
index 08055b83ffeec207c2c869916c58bcaaf70f68db..ef2a2d6997d9f6fca47f7298df2d4b05da28a76a 100644 (file)
@@ -25,7 +25,6 @@
 #include <inttypes.h>
 #include <fcntl.h>
 #include <errno.h>
-#include <pthread.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
@@ -74,20 +73,23 @@ static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, i
     resp->status = st;
 
 #if 0
-    if (txp->flags & NETTXF_extra_info)
-       RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+    if (txp->flags & NETTXF_extra_info) {
+        RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+    }
 #endif
 
     netdev->tx_ring.rsp_prod_pvt = ++i;
     RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
-    if (notify)
-       xen_be_send_notify(&netdev->xendev);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
 
     if (i == netdev->tx_ring.req_cons) {
-       int more_to_do;
-       RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
-       if (more_to_do)
-           netdev->tx_work++;
+        int more_to_do;
+        RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
+        if (more_to_do) {
+            netdev->tx_work++;
+        }
     }
 }
 
@@ -101,10 +103,11 @@ static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING
     RING_IDX cons = netdev->tx_ring.req_cons;
 
     do {
-       make_tx_response(netif, txp, NETIF_RSP_ERROR);
-       if (cons >= end)
-           break;
-       txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
+        make_tx_response(netif, txp, NETIF_RSP_ERROR);
+        if (cons >= end) {
+            break;
+        }
+        txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
     } while (1);
     netdev->tx_ring.req_cons = cons;
     netif_schedule_work(netif);
@@ -122,85 +125,88 @@ static void net_tx_packets(struct XenNetDev *netdev)
     void *tmpbuf = NULL;
 
     for (;;) {
-       rc = netdev->tx_ring.req_cons;
-       rp = netdev->tx_ring.sring->req_prod;
-       xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+        rc = netdev->tx_ring.req_cons;
+        rp = netdev->tx_ring.sring->req_prod;
+        xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
 
-       while ((rc != rp)) {
-           if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc))
-               break;
-           memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
-           netdev->tx_ring.req_cons = ++rc;
+        while ((rc != rp)) {
+            if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) {
+                break;
+            }
+            memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
+            netdev->tx_ring.req_cons = ++rc;
 
 #if 1
-           /* should not happen in theory, we don't announce the *
-            * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
-           if (txreq.flags & NETTXF_extra_info) {
-               xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
-               net_tx_error(netdev, &txreq, rc);
-               continue;
-           }
-           if (txreq.flags & NETTXF_more_data) {
-               xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
-               net_tx_error(netdev, &txreq, rc);
-               continue;
-           }
+            /* should not happen in theory, we don't announce the *
+             * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
+            if (txreq.flags & NETTXF_extra_info) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_more_data) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
 #endif
 
-           if (txreq.size < 14) {
-               xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
-               net_tx_error(netdev, &txreq, rc);
-               continue;
-           }
-
-           if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
-               xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
-               net_tx_error(netdev, &txreq, rc);
-               continue;
-           }
-
-           xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
-                         txreq.gref, txreq.offset, txreq.size, txreq.flags,
-                         (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
-                         (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
-                         (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
-                         (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
-
-           page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                          netdev->xendev.dom,
-                                          txreq.gref, PROT_READ);
-           if (page == NULL) {
-               xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
+            if (txreq.size < 14) {
+                xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
+                xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
+                          txreq.gref, txreq.offset, txreq.size, txreq.flags,
+                          (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
+                          (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+                          (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
+                          (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
+
+            page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                           netdev->xendev.dom,
+                                           txreq.gref, PROT_READ);
+            if (page == NULL) {
+                xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
                               txreq.gref);
-               net_tx_error(netdev, &txreq, rc);
-               continue;
-           }
-           if (txreq.flags & NETTXF_csum_blank) {
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_csum_blank) {
                 /* have read-only mapping -> can't fill checksum in-place */
-                if (!tmpbuf)
-                    tmpbuf = qemu_malloc(XC_PAGE_SIZE);
+                if (!tmpbuf) {
+                    tmpbuf = g_malloc(XC_PAGE_SIZE);
+                }
                 memcpy(tmpbuf, page + txreq.offset, txreq.size);
-               net_checksum_calculate(tmpbuf, txreq.size);
+                net_checksum_calculate(tmpbuf, txreq.size);
                 qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size);
             } else {
                 qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size);
             }
-           xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
-           net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
-       }
-       if (!netdev->tx_work)
-           break;
-       netdev->tx_work = 0;
+            xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+            net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
+        }
+        if (!netdev->tx_work) {
+            break;
+        }
+        netdev->tx_work = 0;
     }
-    qemu_free(tmpbuf);
+    g_free(tmpbuf);
 }
 
 /* ------------------------------------------------------------- */
 
 static void net_rx_response(struct XenNetDev *netdev,
-                           netif_rx_request_t *req, int8_t st,
-                           uint16_t offset, uint16_t size,
-                           uint16_t flags)
+                            netif_rx_request_t *req, int8_t st,
+                            uint16_t offset, uint16_t size,
+                            uint16_t flags)
 {
     RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
     netif_rx_response_t *resp;
@@ -211,16 +217,18 @@ static void net_rx_response(struct XenNetDev *netdev,
     resp->flags      = flags;
     resp->id         = req->id;
     resp->status     = (int16_t)size;
-    if (st < 0)
-       resp->status = (int16_t)st;
+    if (st < 0) {
+        resp->status = (int16_t)st;
+    }
 
     xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
-                 i, resp->status, resp->flags);
+                  i, resp->status, resp->flags);
 
     netdev->rx_ring.rsp_prod_pvt = ++i;
     RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
-    if (notify)
-       xen_be_send_notify(&netdev->xendev);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
 }
 
 #define NET_IP_ALIGN 2
@@ -230,17 +238,18 @@ static int net_rx_ok(VLANClientState *nc)
     struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque;
     RING_IDX rc, rp;
 
-    if (netdev->xendev.be_state != XenbusStateConnected)
-       return 0;
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return 0;
+    }
 
     rc = netdev->rx_ring.req_cons;
     rp = netdev->rx_ring.sring->req_prod;
     xen_rmb();
 
     if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
-       xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
-                     __FUNCTION__, rc, rp);
-       return 0;
+        xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
+                      __FUNCTION__, rc, rp);
+        return 0;
     }
     return 1;
 }
@@ -252,34 +261,35 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
     RING_IDX rc, rp;
     void *page;
 
-    if (netdev->xendev.be_state != XenbusStateConnected)
-       return -1;
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return -1;
+    }
 
     rc = netdev->rx_ring.req_cons;
     rp = netdev->rx_ring.sring->req_prod;
     xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
 
     if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
-       xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
-       return -1;
+        xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
+        return -1;
     }
     if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
-       xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
-                     (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
-       return -1;
+        xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
+                      (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
+        return -1;
     }
 
     memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
     netdev->rx_ring.req_cons = ++rc;
 
     page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                  netdev->xendev.dom,
-                                  rxreq.gref, PROT_WRITE);
+                                   netdev->xendev.dom,
+                                   rxreq.gref, PROT_WRITE);
     if (page == NULL) {
-       xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
+        xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
                       rxreq.gref);
-       net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
-       return -1;
+        net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
+        return -1;
     }
     memcpy(page + NET_IP_ALIGN, buf, size);
     xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
@@ -302,15 +312,18 @@ static int net_init(struct XenDevice *xendev)
     struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
 
     /* read xenstore entries */
-    if (netdev->mac == NULL)
-       netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+    if (netdev->mac == NULL) {
+        netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+    }
 
     /* do we have all we need? */
-    if (netdev->mac == NULL)
-       return -1;
+    if (netdev->mac == NULL) {
+        return -1;
+    }
 
-    if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0)
+    if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
         return -1;
+    }
 
     netdev->conf.vlan = qemu_find_vlan(netdev->xendev.dev, 1);
     netdev->conf.peer = NULL;
@@ -334,41 +347,46 @@ static int net_connect(struct XenDevice *xendev)
     int rx_copy;
 
     if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
-                                  &netdev->tx_ring_ref) == -1)
-       return -1;
+                             &netdev->tx_ring_ref) == -1) {
+        return -1;
+    }
     if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
-                                  &netdev->rx_ring_ref) == -1)
-       return 1;
+                             &netdev->rx_ring_ref) == -1) {
+        return 1;
+    }
     if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
-                                  &netdev->xendev.remote_port) == -1)
-       return -1;
+                             &netdev->xendev.remote_port) == -1) {
+        return -1;
+    }
 
-    if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1)
-       rx_copy = 0;
+    if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
+        rx_copy = 0;
+    }
     if (rx_copy == 0) {
-       xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
-       return -1;
+        xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
+        return -1;
     }
 
     netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                         netdev->xendev.dom,
-                                         netdev->tx_ring_ref,
-                                         PROT_READ | PROT_WRITE);
+                                          netdev->xendev.dom,
+                                          netdev->tx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
     netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                         netdev->xendev.dom,
-                                         netdev->rx_ring_ref,
-                                         PROT_READ | PROT_WRITE);
-    if (!netdev->txs || !netdev->rxs)
-       return -1;
+                                          netdev->xendev.dom,
+                                          netdev->rx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
+    if (!netdev->txs || !netdev->rxs) {
+        return -1;
+    }
     BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
     BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
 
     xen_be_bind_evtchn(&netdev->xendev);
 
     xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
-                 "remote port %d, local port %d\n",
-                 netdev->tx_ring_ref, netdev->rx_ring_ref,
-                 netdev->xendev.remote_port, netdev->xendev.local_port);
+                  "remote port %d, local port %d\n",
+                  netdev->tx_ring_ref, netdev->rx_ring_ref,
+                  netdev->xendev.remote_port, netdev->xendev.local_port);
 
     net_tx_packets(netdev);
     return 0;
@@ -381,12 +399,12 @@ static void net_disconnect(struct XenDevice *xendev)
     xen_be_unbind_evtchn(&netdev->xendev);
 
     if (netdev->txs) {
-       xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
-       netdev->txs = NULL;
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+        netdev->txs = NULL;
     }
     if (netdev->rxs) {
-       xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
-       netdev->rxs = NULL;
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+        netdev->rxs = NULL;
     }
     if (netdev->nic) {
         qemu_del_vlan_client(&netdev->nic->nc);
@@ -404,7 +422,7 @@ static int net_free(struct XenDevice *xendev)
 {
     struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
 
-    qemu_free(netdev->mac);
+    g_free(netdev->mac);
     return 0;
 }
 
@@ -414,7 +432,7 @@ struct XenDevOps xen_netdev_ops = {
     .size       = sizeof(struct XenNetDev),
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .init       = net_init,
-    .connect    = net_connect,
+    .initialise    = net_connect,
     .event      = net_event,
     .disconnect = net_disconnect,
     .free       = net_free,
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
new file mode 100644 (file)
index 0000000..5e792f5
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * XEN platform pci device, formerly known as the event channel device
+ *
+ * Copyright (c) 2003-2004 Intel Corp.
+ * Copyright (c) 2006 XenSource
+ *
+ * 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 <assert.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "irq.h"
+#include "xen_common.h"
+#include "net.h"
+#include "xen_backend.h"
+#include "trace.h"
+#include "exec-memory.h"
+
+#include <xenguest.h>
+
+//#define DEBUG_PLATFORM
+
+#ifdef DEBUG_PLATFORM
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState {
+    PCIDevice  pci_dev;
+    MemoryRegion fixed_io;
+    MemoryRegion bar;
+    MemoryRegion mmio_bar;
+    uint8_t flags; /* used only for version_id == 2 */
+    int drivers_blacklisted;
+    uint16_t driver_product_version;
+
+    /* Log from guest drivers */
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* Send bytes to syslog */
+static void log_writeb(PCIXenPlatformState *s, char val)
+{
+    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+        /* Flush buffer */
+        s->log_buffer[s->log_buffer_off] = 0;
+        trace_xen_platform_log(s->log_buffer);
+        s->log_buffer_off = 0;
+    } else {
+        s->log_buffer[s->log_buffer_off++] = val;
+    }
+}
+
+/* Xen Platform, Fixed IOPort */
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void unplug_nic(PCIBus *b, PCIDevice *d)
+{
+    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+            PCI_CLASS_NETWORK_ETHERNET) {
+        qdev_unplug(&(d->qdev));
+    }
+}
+
+static void pci_unplug_nics(PCIBus *bus)
+{
+    pci_for_each_device(bus, 0, unplug_nic);
+}
+
+static void unplug_disks(PCIBus *b, PCIDevice *d)
+{
+    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+            PCI_CLASS_STORAGE_IDE) {
+        qdev_unplug(&(d->qdev));
+    }
+}
+
+static void pci_unplug_disks(PCIBus *bus)
+{
+    pci_for_each_device(bus, 0, unplug_disks);
+}
+
+static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        /* Unplug devices.  Value is a bitmask of which devices to
+           unplug, with bit 0 the IDE devices, bit 1 the network
+           devices, and bit 2 the non-primary-master IDE devices. */
+        if (val & UNPLUG_ALL_IDE_DISKS) {
+            DPRINTF("unplug disks\n");
+            qemu_aio_flush();
+            bdrv_flush_all();
+            pci_unplug_disks(s->pci_dev.bus);
+        }
+        if (val & UNPLUG_ALL_NICS) {
+            DPRINTF("unplug nics\n");
+            pci_unplug_nics(s->pci_dev.bus);
+        }
+        if (val & UNPLUG_AUX_IDE_DISKS) {
+            DPRINTF("unplug auxiliary disks not supported\n");
+        }
+        break;
+    case 2:
+        switch (val) {
+        case 1:
+            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            DPRINTF("Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            DPRINTF("Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        s->driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0: /* Platform flags */ {
+        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
+            HVMMEM_ram_ro : HVMMEM_ram_rw;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
+            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
+        } else {
+            s->flags = val & PFFLAG_ROM_LOCK;
+            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
+                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
+        }
+        break;
+    }
+    case 2:
+        log_writeb(s, val);
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        if (s->drivers_blacklisted) {
+            /* The drivers will recognise this magic number and refuse
+             * to do anything. */
+            return 0xd249;
+        } else {
+            /* Magic value so that you can identify the interface. */
+            return 0x49d2;
+        }
+    default:
+        return 0xffff;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        /* Platform flags */
+        return s->flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_reset(void *opaque)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, 0, 0);
+}
+
+const MemoryRegionPortio xen_platform_ioport[] = {
+    { 0, 16, 4, .write = platform_fixed_ioport_writel, },
+    { 0, 16, 2, .write = platform_fixed_ioport_writew, },
+    { 0, 16, 1, .write = platform_fixed_ioport_writeb, },
+    { 0, 16, 2, .read = platform_fixed_ioport_readw, },
+    { 0, 16, 1, .read = platform_fixed_ioport_readb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps platform_fixed_io_ops = {
+    .old_portio = xen_platform_ioport,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void platform_fixed_ioport_init(PCIXenPlatformState* s)
+{
+    memory_region_init_io(&s->fixed_io, &platform_fixed_io_ops, s,
+                          "xen-fixed", 16);
+    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
+                                &s->fixed_io);
+}
+
+/* Xen Platform PCI Device */
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+    if (addr == 0) {
+        return platform_fixed_ioport_readb(opaque, 0);
+    } else {
+        return ~0u;
+    }
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_writeb(opaque, 0, val);
+        break;
+    case 8:
+        log_writeb(s, val);
+        break;
+    default:
+        break;
+    }
+}
+
+static MemoryRegionPortio xen_pci_portio[] = {
+    { 0, 0x100, 1, .read = xen_platform_ioport_readb, },
+    { 0, 0x100, 1, .write = xen_platform_ioport_writeb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps xen_pci_io_ops = {
+    .old_portio = xen_pci_portio,
+};
+
+static void platform_ioport_bar_setup(PCIXenPlatformState *d)
+{
+    memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100);
+}
+
+static uint64_t platform_mmio_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    DPRINTF("Warning: attempted read from physical address "
+            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+
+    return 0;
+}
+
+static void platform_mmio_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned size)
+{
+    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
+            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+            val, addr);
+}
+
+static const MemoryRegionOps platform_mmio_handler = {
+    .read = &platform_mmio_read,
+    .write = &platform_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void platform_mmio_setup(PCIXenPlatformState *d)
+{
+    memory_region_init_io(&d->mmio_bar, &platform_mmio_handler, d,
+                          "xen-mmio", 0x1000000);
+}
+
+static int xen_platform_post_load(void *opaque, int version_id)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, 0, s->flags);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xen_platform = {
+    .name = "platform",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = xen_platform_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+        VMSTATE_UINT8(flags, PCIXenPlatformState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int xen_platform_initfn(PCIDevice *dev)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = d->pci_dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    pci_config_set_prog_interface(pci_conf, 0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    platform_ioport_bar_setup(d);
+    pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
+
+    /* reserve 16MB mmio address for share memory*/
+    platform_mmio_setup(d);
+    pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &d->mmio_bar);
+
+    platform_fixed_ioport_init(d);
+
+    return 0;
+}
+
+static void platform_reset(DeviceState *dev)
+{
+    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+
+    platform_fixed_ioport_reset(s);
+}
+
+static PCIDeviceInfo xen_platform_info = {
+    .init = xen_platform_initfn,
+    .qdev.name = "xen-platform",
+    .qdev.desc = "XEN platform pci device",
+    .qdev.size = sizeof(PCIXenPlatformState),
+    .qdev.vmsd = &vmstate_xen_platform,
+    .qdev.reset = platform_reset,
+
+    .vendor_id    =  PCI_VENDOR_ID_XEN,
+    .device_id    = PCI_DEVICE_ID_XEN_PLATFORM,
+    .class_id     = PCI_CLASS_OTHERS << 8 | 0x80,
+    .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
+    .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
+    .revision = 1,
+};
+
+static void xen_platform_register(void)
+{
+    pci_qdev_register(&xen_platform_info);
+}
+
+device_init(xen_platform_register);
index da5297b4989952d188ee0c6f8359bdb9a5619a9d..1bcf171b014af6f7f7116bba52b413e436b6f17b 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"
@@ -348,35 +347,50 @@ static void xenfb_mouse_event(void *opaque,
 
 static int input_init(struct XenDevice *xendev)
 {
-    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
-    if (!in->c.ds) {
-        xen_be_printf(xendev, 1, "ds not set (yet)\n");
-       return -1;
-    }
-
     xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
     return 0;
 }
 
-static int input_connect(struct XenDevice *xendev)
+static int input_initialise(struct XenDevice *xendev)
 {
     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
     int rc;
 
-    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
-                             &in->abs_pointer_wanted) == -1)
-       in->abs_pointer_wanted = 0;
+    if (!in->c.ds) {
+        char *vfb = xenstore_read_str(NULL, "device/vfb");
+        if (vfb == NULL) {
+            /* there is no vfb, run vkbd on its own */
+            in->c.ds = get_displaystate();
+        } else {
+            g_free(vfb);
+            xen_be_printf(xendev, 1, "ds not set (yet)\n");
+            return -1;
+        }
+    }
 
     rc = common_bind(&in->c);
     if (rc != 0)
        return rc;
 
     qemu_add_kbd_event_handler(xenfb_key_event, in);
+    return 0;
+}
+
+static void input_connected(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+                             &in->abs_pointer_wanted) == -1) {
+        in->abs_pointer_wanted = 0;
+    }
+
+    if (in->qmouse) {
+        qemu_remove_mouse_event_handler(in->qmouse);
+    }
     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
                                              in->abs_pointer_wanted,
                                              "Xen PVFB Mouse");
-    return 0;
 }
 
 static void input_disconnect(struct XenDevice *xendev)
@@ -479,8 +493,8 @@ static int xenfb_map_fb(struct XenFB *xenfb)
     n_fbdirs = xenfb->fbpages * mode / 8;
     n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
 
-    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
-    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
 
     xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
     map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
@@ -498,8 +512,8 @@ static int xenfb_map_fb(struct XenFB *xenfb)
     ret = 0; /* all is fine */
 
 out:
-    qemu_free(pgmfns);
-    qemu_free(fbmfns);
+    g_free(pgmfns);
+    g_free(fbmfns);
     return ret;
 }
 
@@ -861,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
     return 0;
 }
 
-static int fb_connect(struct XenDevice *xendev)
+static int fb_initialise(struct XenDevice *xendev)
 {
     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
     struct xenfb_page *fb_page;
@@ -955,7 +969,8 @@ static void fb_event(struct XenDevice *xendev)
 struct XenDevOps xen_kbdmouse_ops = {
     .size       = sizeof(struct XenInput),
     .init       = input_init,
-    .connect    = input_connect,
+    .initialise = input_initialise,
+    .connected  = input_connected,
     .disconnect = input_disconnect,
     .event      = input_event,
 };
@@ -963,7 +978,7 @@ struct XenDevOps xen_kbdmouse_ops = {
 struct XenDevOps xen_framebuffer_ops = {
     .size       = sizeof(struct XenFB),
     .init       = fb_init,
-    .connect    = fb_connect,
+    .initialise = fb_initialise,
     .disconnect = fb_disconnect,
     .event      = fb_event,
     .frontend_changed = fb_frontend_changed,
diff --git a/hw/xics.c b/hw/xics.c
new file mode 100644 (file)
index 0000000..1c5eaa4
--- /dev/null
+++ b/hw/xics.c
@@ -0,0 +1,493 @@
+/*
+ * 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"
+
+/*
+ * 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 srcno, int val)
+{
+    struct ics_state *ics = (struct ics_state *)opaque;
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if (val) {
+        if (irq->priority == 0xff) {
+            irq->masked_pending = 1;
+            /* masked pending */ ;
+        } else  {
+            icp_irq(ics->icp, irq->server, srcno + 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 - ics->offset;
+
+    irq->server = server;
+    irq->priority = priority;
+
+    if (!irq->masked_pending || (priority == 0xff)) {
+        return;
+    }
+
+    irq->masked_pending = 0;
+    icp_irq(ics->icp, server, nr, 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, 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, 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, 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 = g_malloc0(sizeof(*icp));
+    icp->nr_servers = max_server_num + 1;
+    icp->ss = g_malloc0(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 = g_malloc0(sizeof(*ics));
+    ics->nr_irqs = nr_irqs;
+    ics->offset = 16;
+    ics->irqs = g_malloc0(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 705ff5b84b344bd52a9528565ebb529abd576154..35f35bd7fc1f957086dad04af7f8578d85f51b69 100644 (file)
@@ -1,6 +1,5 @@
-
-/* OPB Interrupt Controller.  */
-qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+#include "qemu-common.h"
+#include "net.h"
 
 static inline DeviceState *
 xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr)
@@ -48,3 +47,42 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
     sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
     return dev;
 }
+
+static inline DeviceState *
+xilinx_axiethernet_create(void *dmach,
+                          NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+                          int txmem, int rxmem)
+{
+    DeviceState *dev;
+    qemu_check_nic_model(nd, "xilinx-axienet");
+
+    dev = qdev_create(NULL, "xilinx,axienet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "c_rxmem", rxmem);
+    qdev_prop_set_uint32(dev, "c_txmem", txmem);
+    qdev_prop_set_ptr(dev, "dmach", dmach);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+static inline DeviceState *
+xilinx_axiethernetdma_create(void *dmach,
+                             target_phys_addr_t base, qemu_irq irq,
+                             qemu_irq irq2, int freqhz)
+{
+    DeviceState *dev = NULL;
+
+    dev = qdev_create(NULL, "xilinx,axidma");
+    qdev_prop_set_uint32(dev, "freqhz", freqhz);
+    qdev_prop_set_ptr(dev, "dmach", dmach);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq2);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq);
+
+    return dev;
+}
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
new file mode 100644 (file)
index 0000000..571a5b0
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * QEMU model of Xilinx AXI-DMA block.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+#include "qemu-log.h"
+#include "qdev-addr.h"
+
+#include "xilinx_axidma.h"
+
+#define D(x)
+
+#define R_DMACR             (0x00 / 4)
+#define R_DMASR             (0x04 / 4)
+#define R_CURDESC           (0x08 / 4)
+#define R_TAILDESC          (0x10 / 4)
+#define R_MAX               (0x30 / 4)
+
+enum {
+    DMACR_RUNSTOP = 1,
+    DMACR_TAILPTR_MODE = 2,
+    DMACR_RESET = 4
+};
+
+enum {
+    DMASR_HALTED = 1,
+    DMASR_IDLE  = 2,
+    DMASR_IOC_IRQ  = 1 << 12,
+    DMASR_DLY_IRQ  = 1 << 13,
+
+    DMASR_IRQ_MASK = 7 << 12
+};
+
+struct SDesc {
+    uint64_t nxtdesc;
+    uint64_t buffer_address;
+    uint64_t reserved;
+    uint32_t control;
+    uint32_t status;
+    uint32_t app[6];
+};
+
+enum {
+    SDESC_CTRL_EOF = (1 << 26),
+    SDESC_CTRL_SOF = (1 << 27),
+
+    SDESC_CTRL_LEN_MASK = (1 << 23) - 1
+};
+
+enum {
+    SDESC_STATUS_EOF = (1 << 26),
+    SDESC_STATUS_SOF_BIT = 27,
+    SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
+    SDESC_STATUS_COMPLETE = (1 << 31)
+};
+
+struct AXIStream {
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+    qemu_irq irq;
+
+    int nr;
+
+    struct SDesc desc;
+    int pos;
+    unsigned int complete_cnt;
+    uint32_t regs[R_MAX];
+};
+
+struct XilinxAXIDMA {
+    SysBusDevice busdev;
+    uint32_t freqhz;
+    void *dmach;
+
+    struct AXIStream streams[2];
+};
+
+/*
+ * Helper calls to extract info from desriptors and other trivial
+ * state from regs.
+ */
+static inline int stream_desc_sof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_SOF;
+}
+
+static inline int stream_desc_eof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_EOF;
+}
+
+static inline int stream_resetting(struct AXIStream *s)
+{
+    return !!(s->regs[R_DMACR] & DMACR_RESET);
+}
+
+static inline int stream_running(struct AXIStream *s)
+{
+    return s->regs[R_DMACR] & DMACR_RUNSTOP;
+}
+
+static inline int stream_halted(struct AXIStream *s)
+{
+    return s->regs[R_DMASR] & DMASR_HALTED;
+}
+
+static inline int stream_idle(struct AXIStream *s)
+{
+    return !!(s->regs[R_DMASR] & DMASR_IDLE);
+}
+
+static void stream_reset(struct AXIStream *s)
+{
+    s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
+    s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
+}
+
+/* Map an offset addr into a channel index.  */
+static inline int streamid_from_addr(target_phys_addr_t addr)
+{
+    int sid;
+
+    sid = addr / (0x30);
+    sid &= 1;
+    return sid;
+}
+
+#ifdef DEBUG_ENET
+static void stream_desc_show(struct SDesc *d)
+{
+    qemu_log("buffer_addr  = " PRIx64 "\n", d->buffer_address);
+    qemu_log("nxtdesc      = " PRIx64 "\n", d->nxtdesc);
+    qemu_log("control      = %x\n", d->control);
+    qemu_log("status       = %x\n", d->status);
+}
+#endif
+
+static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    cpu_physical_memory_read(addr, (void *) d, sizeof *d);
+
+    /* Convert from LE into host endianness.  */
+    d->buffer_address = le64_to_cpu(d->buffer_address);
+    d->nxtdesc = le64_to_cpu(d->nxtdesc);
+    d->control = le32_to_cpu(d->control);
+    d->status = le32_to_cpu(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = le32_to_cpu(d->app[i]);
+    }
+}
+
+static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    /* Convert from host endianness into LE.  */
+    d->buffer_address = cpu_to_le64(d->buffer_address);
+    d->nxtdesc = cpu_to_le64(d->nxtdesc);
+    d->control = cpu_to_le32(d->control);
+    d->status = cpu_to_le32(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = cpu_to_le32(d->app[i]);
+    }
+    cpu_physical_memory_write(addr, (void *) d, sizeof *d);
+}
+
+static void stream_update_irq(struct AXIStream *s)
+{
+    unsigned int pending, mask, irq;
+
+    pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
+    mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
+
+    irq = pending & mask;
+
+    qemu_set_irq(s->irq, !!irq);
+}
+
+static void stream_reload_complete_cnt(struct AXIStream *s)
+{
+    unsigned int comp_th;
+    comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
+    s->complete_cnt = comp_th;
+}
+
+static void timer_hit(void *opaque)
+{
+    struct AXIStream *s = opaque;
+
+    stream_reload_complete_cnt(s);
+    s->regs[R_DMASR] |= DMASR_DLY_IRQ;
+    stream_update_irq(s);
+}
+
+static void stream_complete(struct AXIStream *s)
+{
+    unsigned int comp_delay;
+
+    /* Start the delayed timer.  */
+    comp_delay = s->regs[R_DMACR] >> 24;
+    if (comp_delay) {
+        ptimer_stop(s->ptimer);
+        ptimer_set_count(s->ptimer, comp_delay);
+        ptimer_run(s->ptimer, 1);
+    }
+
+    s->complete_cnt--;
+    if (s->complete_cnt == 0) {
+        /* Raise the IOC irq.  */
+        s->regs[R_DMASR] |= DMASR_IOC_IRQ;
+        stream_reload_complete_cnt(s);
+    }
+}
+
+static void stream_process_mem2s(struct AXIStream *s,
+                                 struct XilinxDMAConnection *dmach)
+{
+    uint32_t prev_d;
+    unsigned char txbuf[16 * 1024];
+    unsigned int txlen;
+    uint32_t app[6];
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (1) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        if (stream_desc_sof(&s->desc)) {
+            s->pos = 0;
+            memcpy(app, s->desc.app, sizeof app);
+        }
+
+        txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if ((txlen + s->pos) > sizeof txbuf) {
+            hw_error("%s: too small internal txbuf! %d\n", __func__,
+                     txlen + s->pos);
+        }
+
+        cpu_physical_memory_read(s->desc.buffer_address,
+                                 txbuf + s->pos, txlen);
+        s->pos += txlen;
+
+        if (stream_desc_eof(&s->desc)) {
+            xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+            s->pos = 0;
+            stream_complete(s);
+        }
+
+        /* Update the descriptor.  */
+        s->desc.status = txlen | SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static void stream_process_s2mem(struct AXIStream *s,
+                                 unsigned char *buf, size_t len, uint32_t *app)
+{
+    uint32_t prev_d;
+    unsigned int rxlen;
+    int pos = 0;
+    int sof = 1;
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (len) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if (rxlen > len) {
+            /* It fits.  */
+            rxlen = len;
+        }
+
+        cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
+        len -= rxlen;
+        pos += rxlen;
+
+        /* Update the descriptor.  */
+        if (!len) {
+            int i;
+
+            stream_complete(s);
+            for (i = 0; i < 5; i++) {
+                s->desc.app[i] = app[i];
+            }
+            s->desc.status |= SDESC_STATUS_EOF;
+        }
+
+        s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
+        s->desc.status |= SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+        sof = 0;
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static
+void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s = &d->streams[1];
+
+    if (!app) {
+        hw_error("No stream app data!\n");
+    }
+    stream_process_s2mem(s, buf, len, app);
+    stream_update_irq(s);
+}
+
+static uint32_t axidma_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s;
+    uint32_t r = 0;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Simulate one cycles reset delay.  */
+            s->regs[addr] &= ~DMACR_RESET;
+            r = s->regs[addr];
+            break;
+        case R_DMASR:
+            s->regs[addr] &= 0xffff;
+            s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
+            s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
+            r = s->regs[addr];
+            break;
+        default:
+            r = s->regs[addr];
+            D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, sid, addr * 4, r));
+            break;
+    }
+    return r;
+
+}
+
+static void
+axidma_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Tailptr mode is always on.  */
+            value |= DMACR_TAILPTR_MODE;
+            /* Remember our previous reset state.  */
+            value |= (s->regs[addr] & DMACR_RESET);
+            s->regs[addr] = value;
+
+            if (value & DMACR_RESET) {
+                stream_reset(s);
+            }
+
+            if ((value & 1) && !stream_resetting(s)) {
+                /* Start processing.  */
+                s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
+            }
+            stream_reload_complete_cnt(s);
+            break;
+
+        case R_DMASR:
+            /* Mask away write to clear irq lines.  */
+            value &= ~(value & DMASR_IRQ_MASK);
+            s->regs[addr] = value;
+            break;
+
+        case R_TAILDESC:
+            s->regs[addr] = value;
+            s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
+            if (!sid) {
+                stream_process_mem2s(s, d->dmach);
+            }
+            break;
+        default:
+            D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                  __func__, sid, addr * 4, value));
+            s->regs[addr] = value;
+            break;
+    }
+    stream_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const axidma_read[] = {
+    &axidma_readl,
+    &axidma_readl,
+    &axidma_readl,
+};
+
+static CPUWriteMemoryFunc * const axidma_write[] = {
+    &axidma_writel,
+    &axidma_writel,
+    &axidma_writel,
+};
+
+static int xilinx_axidma_init(SysBusDevice *dev)
+{
+    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev);
+    int axidma_regs;
+    int i;
+
+    sysbus_init_irq(dev, &s->streams[1].irq);
+    sysbus_init_irq(dev, &s->streams[0].irq);
+
+    if (!s->dmach) {
+        hw_error("Unconnected DMA channel.\n");
+    }
+
+    xlx_dma_connect_dma(s->dmach, s, axidma_push);
+
+    axidma_regs = cpu_register_io_memory(axidma_read, axidma_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4 * 2, axidma_regs);
+
+    for (i = 0; i < 2; i++) {
+        stream_reset(&s->streams[i]);
+        s->streams[i].nr = i;
+        s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
+        s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
+        ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
+    }
+    return 0;
+}
+
+static SysBusDeviceInfo axidma_info = {
+    .init = xilinx_axidma_init,
+    .qdev.name  = "xilinx,axidma",
+    .qdev.size  = sizeof(struct XilinxAXIDMA),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+        DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xilinx_axidma_register(void)
+{
+    sysbus_register_withprop(&axidma_info);
+}
+
+device_init(xilinx_axidma_register)
diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h
new file mode 100644 (file)
index 0000000..37cb6f0
--- /dev/null
@@ -0,0 +1,39 @@
+/* AXI DMA connection. Used until qdev provides a generic way.  */
+typedef void (*DMAPushFn)(void *opaque,
+                            unsigned char *buf, size_t len, uint32_t *app);
+
+struct XilinxDMAConnection {
+    void *dma;
+    void *client;
+
+    DMAPushFn to_dma;
+    DMAPushFn to_client;
+};
+
+static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
+                                          void *c, DMAPushFn f)
+{
+    dmach->client = c;
+    dmach->to_client = f;
+}
+
+static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
+                                       void *d, DMAPushFn f)
+{
+    dmach->dma = d;
+    dmach->to_dma = f;
+}
+
+static inline
+void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
+                         uint8_t *buf, size_t len, uint32_t *app)
+{
+    dmach->to_dma(dmach->dma, buf, len, app);
+}
+static inline
+void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
+                            uint8_t *buf, size_t len, uint32_t *app)
+{
+    dmach->to_client(dmach->client, buf, len, app);
+}
+
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
new file mode 100644 (file)
index 0000000..b875aad
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * QEMU model of Xilinx AXI-Ethernet.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#include "xilinx_axidma.h"
+
+#define DPHY(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+struct PHY {
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct PHY *phy, unsigned int req);
+    void (*write)(struct PHY *phy, unsigned int req,
+                  unsigned int data);
+};
+
+static unsigned int tdk_read(struct PHY *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+        case 1:
+            if (!phy->link) {
+                break;
+            }
+            /* MR1.  */
+            /* Speeds and modes.  */
+            r |= (1 << 13) | (1 << 14);
+            r |= (1 << 11) | (1 << 12);
+            r |= (1 << 5); /* Autoneg complete.  */
+            r |= (1 << 3); /* Autoneg able.  */
+            r |= (1 << 2); /* link.  */
+            r |= (1 << 1); /* link.  */
+            break;
+        case 5:
+            /* Link partner ability.
+               We are kind; always agree with whatever best mode
+               the guest advertises.  */
+            r = 1 << 14; /* Success.  */
+            /* Copy advertised modes.  */
+            r |= phy->regs[4] & (15 << 5);
+            /* Autoneg support.  */
+            r |= 1;
+            break;
+        case 17:
+            /* Marvel PHY on many xilinx boards.  */
+            r = 0x8000; /* 1000Mb  */
+            break;
+        case 18:
+            {
+                /* Diagnostics reg.  */
+                int duplex = 0;
+                int speed_100 = 0;
+
+                if (!phy->link) {
+                    break;
+                }
+
+                /* Are we advertising 100 half or 100 duplex ? */
+                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+                /* Are we advertising 10 duplex or 100 duplex ? */
+                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+                r = (speed_100 << 10) | (duplex << 11);
+            }
+            break;
+
+        default:
+            r = phy->regs[regnum];
+            break;
+    }
+    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void
+tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+        default:
+            phy->regs[regnum] = data;
+            break;
+    }
+}
+
+static void
+tdk_init(struct PHY *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id.  */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg.  */
+    phy->regs[4] = 0x01E1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+struct MDIOBus {
+    /* bus.  */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct PHY *devs[32];
+};
+
+static void
+mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void
+mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
+                  unsigned int reg)
+{
+    struct PHY *phy;
+    uint16_t data;
+
+    phy = bus->devs[addr];
+    if (phy && phy->read) {
+        data = phy->read(phy, reg);
+    } else {
+        data = 0xffff;
+    }
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    return data;
+}
+
+static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
+               unsigned int reg, uint16_t data)
+{
+    struct PHY *phy;
+
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    phy = bus->devs[addr];
+    if (phy && phy->write) {
+        phy->write(phy, reg, data);
+    }
+}
+
+#define DENET(x)
+
+#define R_RAF      (0x000 / 4)
+enum {
+    RAF_MCAST_REJ = (1 << 1),
+    RAF_BCAST_REJ = (1 << 2),
+    RAF_EMCF_EN = (1 << 12),
+    RAF_NEWFUNC_EN = (1 << 11)
+};
+
+#define R_IS       (0x00C / 4)
+enum {
+    IS_HARD_ACCESS_COMPLETE = 1,
+    IS_AUTONEG = (1 << 1),
+    IS_RX_COMPLETE = (1 << 2),
+    IS_RX_REJECT = (1 << 3),
+    IS_TX_COMPLETE = (1 << 5),
+    IS_RX_DCM_LOCK = (1 << 6),
+    IS_MGM_RDY = (1 << 7),
+    IS_PHY_RST_DONE = (1 << 8),
+};
+
+#define R_IP       (0x010 / 4)
+#define R_IE       (0x014 / 4)
+#define R_UAWL     (0x020 / 4)
+#define R_UAWU     (0x024 / 4)
+#define R_PPST     (0x030 / 4)
+enum {
+    PPST_LINKSTATUS = (1 << 0),
+    PPST_PHY_LINKSTATUS = (1 << 7),
+};
+
+#define R_STATS_RX_BYTESL (0x200 / 4)
+#define R_STATS_RX_BYTESH (0x204 / 4)
+#define R_STATS_TX_BYTESL (0x208 / 4)
+#define R_STATS_TX_BYTESH (0x20C / 4)
+#define R_STATS_RXL       (0x290 / 4)
+#define R_STATS_RXH       (0x294 / 4)
+#define R_STATS_RX_BCASTL (0x2a0 / 4)
+#define R_STATS_RX_BCASTH (0x2a4 / 4)
+#define R_STATS_RX_MCASTL (0x2a8 / 4)
+#define R_STATS_RX_MCASTH (0x2ac / 4)
+
+#define R_RCW0     (0x400 / 4)
+#define R_RCW1     (0x404 / 4)
+enum {
+    RCW1_VLAN = (1 << 27),
+    RCW1_RX   = (1 << 28),
+    RCW1_FCS  = (1 << 29),
+    RCW1_JUM  = (1 << 30),
+    RCW1_RST  = (1 << 31),
+};
+
+#define R_TC       (0x408 / 4)
+enum {
+    TC_VLAN = (1 << 27),
+    TC_TX   = (1 << 28),
+    TC_FCS  = (1 << 29),
+    TC_JUM  = (1 << 30),
+    TC_RST  = (1 << 31),
+};
+
+#define R_EMMC     (0x410 / 4)
+enum {
+    EMMC_LINKSPEED_10MB = (0 << 30),
+    EMMC_LINKSPEED_100MB = (1 << 30),
+    EMMC_LINKSPEED_1000MB = (2 << 30),
+};
+
+#define R_PHYC     (0x414 / 4)
+
+#define R_MC       (0x500 / 4)
+#define MC_EN      (1 << 6)
+
+#define R_MCR      (0x504 / 4)
+#define R_MWD      (0x508 / 4)
+#define R_MRD      (0x50c / 4)
+#define R_MIS      (0x600 / 4)
+#define R_MIP      (0x620 / 4)
+#define R_MIE      (0x640 / 4)
+#define R_MIC      (0x640 / 4)
+
+#define R_UAW0     (0x700 / 4)
+#define R_UAW1     (0x704 / 4)
+#define R_FMI      (0x708 / 4)
+#define R_AF0      (0x710 / 4)
+#define R_AF1      (0x714 / 4)
+#define R_MAX      (0x34 / 4)
+
+/* Indirect registers.  */
+struct TEMAC  {
+    struct MDIOBus mdio_bus;
+    struct PHY phy;
+
+    void *parent;
+};
+
+struct XilinxAXIEnet {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    void *dmach;
+    NICState *nic;
+    NICConf conf;
+
+
+    uint32_t c_rxmem;
+    uint32_t c_txmem;
+    uint32_t c_phyaddr;
+
+    struct TEMAC TEMAC;
+
+    /* MII regs.  */
+    union {
+        uint32_t regs[4];
+        struct {
+            uint32_t mc;
+            uint32_t mcr;
+            uint32_t mwd;
+            uint32_t mrd;
+        };
+    } mii;
+
+    struct {
+        uint64_t rx_bytes;
+        uint64_t tx_bytes;
+
+        uint64_t rx;
+        uint64_t rx_bcast;
+        uint64_t rx_mcast;
+    } stats;
+
+    /* Receive configuration words.  */
+    uint32_t rcw[2];
+    /* Transmit config.  */
+    uint32_t tc;
+    uint32_t emmc;
+    uint32_t phyc;
+
+    /* Unicast Address Word.  */
+    uint32_t uaw[2];
+    /* Unicast address filter used with extended mcast.  */
+    uint32_t ext_uaw[2];
+    uint32_t fmi;
+
+    uint32_t regs[R_MAX];
+
+    /* Multicast filter addrs.  */
+    uint32_t maddr[4][2];
+    /* 32K x 1 lookup filter.  */
+    uint32_t ext_mtable[1024];
+
+
+    uint8_t *rxmem;
+};
+
+static void axienet_rx_reset(struct XilinxAXIEnet *s)
+{
+    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
+}
+
+static void axienet_tx_reset(struct XilinxAXIEnet *s)
+{
+    s->tc = TC_JUM | TC_TX | TC_VLAN;
+}
+
+static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RST;
+}
+
+static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RX;
+}
+
+static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
+}
+
+static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
+}
+
+static void axienet_reset(struct XilinxAXIEnet *s)
+{
+    axienet_rx_reset(s);
+    axienet_tx_reset(s);
+
+    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
+    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
+
+    s->emmc = EMMC_LINKSPEED_100MB;
+}
+
+static void enet_update_irq(struct XilinxAXIEnet *s)
+{
+    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
+    qemu_set_irq(s->irq, !!s->regs[R_IP]);
+}
+
+static uint32_t enet_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct XilinxAXIEnet *s = opaque;
+    uint32_t r = 0;
+    addr >>= 2;
+
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            r = s->rcw[addr & 1];
+            break;
+
+        case R_TC:
+            r = s->tc;
+            break;
+
+        case R_EMMC:
+            r = s->emmc;
+            break;
+
+        case R_PHYC:
+            r = s->phyc;
+            break;
+
+        case R_MCR:
+            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
+            break;
+
+        case R_STATS_RX_BYTESL:
+        case R_STATS_RX_BYTESH:
+            r = s->stats.rx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_TX_BYTESL:
+        case R_STATS_TX_BYTESH:
+            r = s->stats.tx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_RXL:
+        case R_STATS_RXH:
+            r = s->stats.rx >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_BCASTL:
+        case R_STATS_RX_BCASTH:
+            r = s->stats.rx_bcast >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_MCASTL:
+        case R_STATS_RX_MCASTH:
+            r = s->stats.rx_mcast >> (32 * (addr & 1));
+            break;
+
+        case R_MC:
+        case R_MWD:
+        case R_MRD:
+            r = s->mii.regs[addr & 3];
+            break;
+
+        case R_UAW0:
+        case R_UAW1:
+            r = s->uaw[addr & 1];
+            break;
+
+        case R_UAWU:
+        case R_UAWL:
+            r = s->ext_uaw[addr & 1];
+            break;
+
+        case R_FMI:
+            r = s->fmi;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            r = s->maddr[s->fmi & 3][addr & 1];
+            break;
+
+        case 0x8000 ... 0x83ff:
+            r = s->ext_mtable[addr - 0x8000];
+            break;
+
+        default:
+            if (addr < ARRAY_SIZE(s->regs)) {
+                r = s->regs[addr];
+            }
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                            __func__, addr * 4, r));
+            break;
+    }
+    return r;
+}
+
+static void
+enet_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct XilinxAXIEnet *s = opaque;
+    struct TEMAC *t = &s->TEMAC;
+
+    addr >>= 2;
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            s->rcw[addr & 1] = value;
+            if ((addr & 1) && value & RCW1_RST) {
+                axienet_rx_reset(s);
+            }
+            break;
+
+        case R_TC:
+            s->tc = value;
+            if (value & TC_RST) {
+                axienet_tx_reset(s);
+            }
+            break;
+
+        case R_EMMC:
+            s->emmc = value;
+            break;
+
+        case R_PHYC:
+            s->phyc = value;
+            break;
+
+        case R_MC:
+             value &= ((1 < 7) - 1);
+
+             /* Enable the MII.  */
+             if (value & MC_EN) {
+                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
+                 if (!miiclkdiv) {
+                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
+                 }
+             }
+             s->mii.mc = value;
+             break;
+
+        case R_MCR: {
+             unsigned int phyaddr = (value >> 24) & 0x1f;
+             unsigned int regaddr = (value >> 16) & 0x1f;
+             unsigned int op = (value >> 14) & 3;
+             unsigned int initiate = (value >> 11) & 1;
+
+             if (initiate) {
+                 if (op == 1) {
+                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
+                 } else if (op == 2) {
+                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
+                 } else {
+                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
+                 }
+             }
+             s->mii.mcr = value;
+             break;
+        }
+
+        case R_MWD:
+        case R_MRD:
+             s->mii.regs[addr & 3] = value;
+             break;
+
+
+        case R_UAW0:
+        case R_UAW1:
+            s->uaw[addr & 1] = value;
+            break;
+
+        case R_UAWL:
+        case R_UAWU:
+            s->ext_uaw[addr & 1] = value;
+            break;
+
+        case R_FMI:
+            s->fmi = value;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            s->maddr[s->fmi & 3][addr & 1] = value;
+            break;
+
+        case 0x8000 ... 0x83ff:
+            s->ext_mtable[addr - 0x8000] = value;
+            break;
+
+        default:
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, addr * 4, value));
+            if (addr < ARRAY_SIZE(s->regs)) {
+                s->regs[addr] = value;
+            }
+            break;
+    }
+    enet_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const enet_read[] = {
+    &enet_readl,
+    &enet_readl,
+    &enet_readl,
+};
+
+static CPUWriteMemoryFunc * const enet_write[] = {
+    &enet_writel,
+    &enet_writel,
+    &enet_writel,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    /* RX enabled?  */
+    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
+}
+
+static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
+{
+    int match = 1;
+
+    if (memcmp(buf, &f0, 4)) {
+        match = 0;
+    }
+
+    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
+        match = 0;
+    }
+
+    return match;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+                                              0xff, 0xff, 0xff};
+    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
+    uint32_t app[6] = {0};
+    int promisc = s->fmi & (1 << 31);
+    int unicast, broadcast, multicast, ip_multicast = 0;
+    uint32_t csum32;
+    uint16_t csum16;
+    int i;
+
+    s = s;
+    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
+
+    unicast = ~buf[0] & 0x1;
+    broadcast = memcmp(buf, sa_bcast, 6) == 0;
+    multicast = !unicast && !broadcast;
+    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
+        ip_multicast = 1;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->rcw[1] & RCW1_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
+            return size;
+        }
+    }
+
+    /* Basic Address filters.  If you want to use the extended filters
+       you'll generally have to place the ethernet mac into promiscuous mode
+       to avoid the basic filtering from dropping most frames.  */
+    if (!promisc) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast.  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int drop = 1;
+
+                /* Multicast.  */
+                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
+                    return size;
+                }
+
+                for (i = 0; i < 4; i++) {
+                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
+                        drop = 0;
+                        break;
+                    }
+                }
+
+                if (drop) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    /* Extended mcast filtering enabled?  */
+    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast. ???  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int idx, bit;
+
+                /* Multicast.  */
+                if (!memcmp(buf, sa_ipmcast, 3)) {
+                    return size;
+                }
+
+                idx  = (buf[4] & 0x7f) << 8;
+                idx |= buf[5];
+
+                bit = 1 << (idx & 0x1f);
+                idx >>= 5;
+
+                if (!(s->ext_mtable[idx] & bit)) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    if (size < 12) {
+        s->regs[R_IS] |= IS_RX_REJECT;
+        enet_update_irq(s);
+        return -1;
+    }
+
+    if (size > (s->c_rxmem - 4)) {
+        size = s->c_rxmem - 4;
+    }
+
+    memcpy(s->rxmem, buf, size);
+    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
+
+    if (s->rcw[1] & RCW1_FCS) {
+        size += 4; /* fcs is inband.  */
+    }
+
+    app[0] = 5 << 28;
+    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
+    /* Fold it once.  */
+    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
+    /* And twice to get rid of possible carries.  */
+    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
+    app[3] = csum16;
+    app[4] = size & 0xffff;
+
+    s->stats.rx_bytes += size;
+    s->stats.rx++;
+    if (multicast) {
+        s->stats.rx_mcast++;
+        app[2] |= 1 | (ip_multicast << 1);
+    } else if (broadcast) {
+        s->stats.rx_bcast++;
+        app[2] |= 1 << 3;
+    }
+
+    /* Good frame.  */
+    app[2] |= 1 << 6;
+
+    xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+
+    s->regs[R_IS] |= IS_RX_COMPLETE;
+    enet_update_irq(s);
+    return size;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+    /* FIXME.  */
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    g_free(s->rxmem);
+    g_free(s);
+}
+
+static void
+axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+{
+    struct XilinxAXIEnet *s = opaque;
+
+    /* TX enable ?  */
+    if (!(s->tc & TC_TX)) {
+        return;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->tc & TC_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
+            return;
+        }
+    }
+
+    if (hdr[0] & 1) {
+        unsigned int start_off = hdr[1] >> 16;
+        unsigned int write_off = hdr[1] & 0xffff;
+        uint32_t tmp_csum;
+        uint16_t csum;
+
+        tmp_csum = net_checksum_add(size - start_off,
+                                    (uint8_t *)buf + start_off);
+        /* Accumulate the seed.  */
+        tmp_csum += hdr[2] & 0xffff;
+
+        /* Fold the 32bit partial checksum.  */
+        csum = net_checksum_finish(tmp_csum);
+
+        /* Writeback.  */
+        buf[write_off] = csum >> 8;
+        buf[write_off + 1] = csum & 0xff;
+    }
+
+    qemu_send_packet(&s->nic->nc, buf, size);
+
+    s->stats.tx_bytes += size;
+    s->regs[R_IS] |= IS_TX_COMPLETE;
+    enet_update_irq(s);
+}
+
+static NetClientInfo net_xilinx_enet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_enet_init(SysBusDevice *dev)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
+    int enet_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    if (!s->dmach) {
+        hw_error("Unconnected Xilinx Ethernet MAC.\n");
+    }
+
+    xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
+
+    enet_regs = cpu_register_io_memory(enet_read, enet_write, s,
+                                       DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x40000, enet_regs);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    tdk_init(&s->TEMAC.phy);
+    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
+
+    s->TEMAC.parent = s;
+
+    s->rxmem = g_malloc(s->c_rxmem);
+    axienet_reset(s);
+
+    return 0;
+}
+
+static SysBusDeviceInfo xilinx_enet_info = {
+    .init = xilinx_enet_init,
+    .qdev.name  = "xilinx,axienet",
+    .qdev.size  = sizeof(struct XilinxAXIEnet),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+        DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+        DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+        DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
+        DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+static void xilinx_enet_register(void)
+{
+    sysbus_register_withprop(&xilinx_enet_info);
+}
+
+device_init(xilinx_enet_register)
index 54b57d774f47b857ab2f7ee35cf040249f345a7e..6f44c8466eeb8b1610a44940b9085fe0e53cd857 100644 (file)
@@ -50,6 +50,7 @@
 struct xlx_ethlite
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     NICState *nic;
     NICConf conf;
@@ -70,7 +71,8 @@ static inline void eth_pulse_irq(struct xlx_ethlite *s)
     }
 }
 
-static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+eth_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_ethlite *s = opaque;
     uint32_t r = 0;
@@ -90,23 +92,20 @@ static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
             D(qemu_log("%s %x=%x\n", __func__, addr * 4, r));
             break;
 
-        /* Rx packet data is endian fixed at the way into the rx rams. This
-         * speeds things up because the ethlite MAC does not have a len
-         * register. That means the CPU will issue MMIO reads for the entire
-         * 2k rx buffer even for small packets.
-         */
         default:
-            r = s->regs[addr];
+            r = tswap32(s->regs[addr]);
             break;
     }
     return r;
 }
 
 static void
-eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+eth_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct xlx_ethlite *s = opaque;
     unsigned int base = 0;
+    uint32_t value = val64;
 
     addr >>= 2;
     switch (addr) 
@@ -145,19 +144,20 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
             s->regs[addr] = value;
             break;
 
-        /* Packet data, make sure it stays BE.  */
         default:
-            s->regs[addr] = cpu_to_be32(value);
+            s->regs[addr] = tswap32(value);
             break;
     }
 }
 
-static CPUReadMemoryFunc * const eth_read[] = {
-    NULL, NULL, &eth_readl,
-};
-
-static CPUWriteMemoryFunc * const eth_write[] = {
-    NULL, NULL, &eth_writel,
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static int eth_can_rx(VLANClientState *nc)
@@ -172,7 +172,6 @@ static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
 {
     struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque;
     unsigned int rxbase = s->rxbuf * (0x800 / 4);
-    int i;
 
     /* DA filter.  */
     if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
@@ -186,12 +185,6 @@ static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
     D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase));
     memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
 
-    /* Bring it into host endianess.  */
-    for (i = 0; i < ((size + 3) / 4); i++) {
-       uint32_t d = s->regs[rxbase + R_RX_BUF0 + i];
-       s->regs[rxbase + R_RX_BUF0 + i] = be32_to_cpu(d);
-    }
-
     s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
     if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
         eth_pulse_irq(s);
@@ -219,13 +212,12 @@ static NetClientInfo net_xilinx_ethlite_info = {
 static int xilinx_ethlite_init(SysBusDevice *dev)
 {
     struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
-    int regs;
 
     sysbus_init_irq(dev, &s->irq);
     s->rxbuf = 0;
 
-    regs = cpu_register_io_memory(eth_read, eth_write, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, regs);
+    memory_region_init_io(&s->mmio, &eth_ops, s, "xilinx-ethlite", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
index cb72d5a14e6adf47904247e6e31b17e8450d863a..58b73d95cc6f35a22fe95bf2dde5f432f208c69a 100644 (file)
@@ -40,6 +40,7 @@
 struct xlx_pic
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq parent_irq;
 
     /* Configuration reg chosen at synthesis-time. QEMU populates
@@ -72,7 +73,8 @@ static void update_irq(struct xlx_pic *p)
     }
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+pic_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_pic *p = opaque;
     uint32_t r = 0;
@@ -91,9 +93,11 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
 }
 
 static void
-pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+pic_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct xlx_pic *p = opaque;
+    uint32_t value = val64;
 
     addr >>= 2;
     D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
@@ -116,14 +120,14 @@ pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     update_irq(p);
 }
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    NULL, NULL,
-    &pic_readl,
-};
-
-static CPUWriteMemoryFunc * const pic_write[] = {
-    NULL, NULL,
-    &pic_writel,
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void irq_handler(void *opaque, int irq, int level)
@@ -148,13 +152,12 @@ static void irq_handler(void *opaque, int irq, int level)
 static int xilinx_intc_init(SysBusDevice *dev)
 {
     struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
-    int pic_regs;
 
     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
     sysbus_init_irq(dev, &p->parent_irq);
 
-    pic_regs = cpu_register_io_memory(pic_read, pic_write, p, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
+    memory_region_init_io(&p->mmio, &pic_ops, p, "xilinx-pic", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &p->mmio);
     return 0;
 }
 
index 30827b03cd0e869eb3d62a7ae2e6782cb7398fff..8779c56f0bac85252491df0178c2c1e2cc50030a 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "sysbus.h"
-#include "sysemu.h"
 #include "qemu-timer.h"
 
 #define D(x)
@@ -60,6 +59,7 @@ struct xlx_timer
 struct timerblock
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     uint32_t nr_timers;
     uint32_t freq_hz;
@@ -86,7 +86,8 @@ static void timer_update_irq(struct timerblock *t)
     qemu_set_irq(t->irq, !!irq);
 }
 
-static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct timerblock *t = opaque;
     struct xlx_timer *xt;
@@ -135,11 +136,13 @@ static void timer_enable(struct xlx_timer *xt)
 }
 
 static void
-timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+timer_write(void *opaque, target_phys_addr_t addr,
+            uint64_t val64, unsigned int size)
 {
     struct timerblock *t = opaque;
     struct xlx_timer *xt;
     unsigned int timer;
+    uint32_t value = val64;
 
     addr >>= 2;
     timer = timer_from_addr(addr);
@@ -167,14 +170,14 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     timer_update_irq(t);
 }
 
-static CPUReadMemoryFunc * const timer_read[] = {
-    NULL, NULL,
-    &timer_readl,
-};
-
-static CPUWriteMemoryFunc * const timer_write[] = {
-    NULL, NULL,
-    &timer_writel,
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void timer_hit(void *opaque)
@@ -193,13 +196,12 @@ static int xilinx_timer_init(SysBusDevice *dev)
 {
     struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
     unsigned int i;
-    int timer_regs;
 
     /* All timers share a single irq line.  */
     sysbus_init_irq(dev, &t->irq);
 
     /* Init all the ptimers.  */
-    t->timers = qemu_mallocz(sizeof t->timers[0] * t->nr_timers);
+    t->timers = g_malloc0(sizeof t->timers[0] * t->nr_timers);
     for (i = 0; i < t->nr_timers; i++) {
         struct xlx_timer *xt = &t->timers[i];
 
@@ -210,9 +212,9 @@ static int xilinx_timer_init(SysBusDevice *dev)
         ptimer_set_freq(xt->ptimer, t->freq_hz);
     }
 
-    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
-                                        DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
+    memory_region_init_io(&t->mmio, &timer_ops, t, "xilinx-timer",
+                          R_MAX * 4 * t->nr_timers);
+    sysbus_init_mmio_region(dev, &t->mmio);
     return 0;
 }
 
index 9b94e98fe3880fb5a94b472fb954182bd950ee01..ceb7b4d9ed19f1a35426e790c4b8d4a7fff9da15 100644 (file)
@@ -49,6 +49,7 @@
 struct xlx_uartlite
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -82,7 +83,8 @@ static void uart_update_status(struct xlx_uartlite *s)
     s->regs[R_STATUS] = r;
 }
 
-static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+uart_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_uartlite *s = opaque;
     uint32_t r = 0;
@@ -107,9 +109,11 @@ static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
 }
 
 static void
-uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+uart_write(void *opaque, target_phys_addr_t addr,
+           uint64_t val64, unsigned int size)
 {
     struct xlx_uartlite *s = opaque;
+    uint32_t value = val64;
     unsigned char ch = value;
 
     addr >>= 2;
@@ -129,7 +133,7 @@ uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 
         case R_TX:
             if (s->chr)
-                qemu_chr_write(s->chr, &ch, 1);
+                qemu_chr_fe_write(s->chr, &ch, 1);
 
             s->regs[addr] = value;
 
@@ -147,16 +151,14 @@ uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     uart_update_irq(s);
 }
 
-static CPUReadMemoryFunc * const uart_read[] = {
-    &uart_readl,
-    &uart_readl,
-    &uart_readl,
-};
-
-static CPUWriteMemoryFunc * const uart_write[] = {
-    &uart_writel,
-    &uart_writel,
-    &uart_writel,
+static const MemoryRegionOps uart_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4
+    }
 };
 
 static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@ -196,14 +198,12 @@ static void uart_event(void *opaque, int event)
 static int xilinx_uartlite_init(SysBusDevice *dev)
 {
     struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
-    int uart_regs;
 
     sysbus_init_irq(dev, &s->irq);
 
     uart_update_status(s);
-    uart_regs = cpu_register_io_memory(uart_read, uart_write, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+    memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr)
index 5aa6a6b149bfe135f8098827046c0832fa3c5956..d3c387d6cb3a0e27d357a0d443a2a3e43e259839 100644 (file)
@@ -69,9 +69,6 @@ static int xio3130_downstream_initfn(PCIDevice *d)
     }
 
     pcie_port_init_reg(d);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130D);
-    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
 
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
@@ -182,6 +179,9 @@ static PCIDeviceInfo xio3130_downstream_info = {
     .config_write = xio3130_downstream_write_config,
     .init = xio3130_downstream_initfn,
     .exit = xio3130_downstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130D,
+    .revision = XIO3130_REVISION,
 
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
index a7640f518a1fa6b4070055c9c56b914ab4820b5b..82836958a40fb165f9b011b937b0b04594724e70 100644 (file)
@@ -65,9 +65,6 @@ static int xio3130_upstream_initfn(PCIDevice *d)
     }
 
     pcie_port_init_reg(d);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130U);
-    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
 
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
@@ -159,6 +156,9 @@ static PCIDeviceInfo xio3130_upstream_info = {
     .config_write = xio3130_upstream_write_config,
     .init = xio3130_upstream_initfn,
     .exit = xio3130_upstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130U,
+    .revision = XIO3130_REVISION,
 
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
diff --git a/hw/xtensa_bootparam.h b/hw/xtensa_bootparam.h
new file mode 100644 (file)
index 0000000..38ef32b
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef HW_XTENSA_BOOTPARAM
+#define HW_XTENSA_BOOTPARAM
+
+typedef struct BpTag {
+    uint16_t tag;
+    uint16_t size;
+} BpTag;
+
+static inline ram_addr_t put_tag(ram_addr_t addr, uint16_t tag,
+        size_t size, const void *data)
+{
+    BpTag bp_tag = {
+        .tag = tswap16(tag),
+        .size = tswap16((size + 3) & ~3),
+    };
+
+    cpu_physical_memory_write(addr, &bp_tag, sizeof(bp_tag));
+    addr += sizeof(bp_tag);
+    cpu_physical_memory_write(addr, data, size);
+    addr += (size + 3) & ~3;
+
+    return addr;
+}
+
+#endif
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
new file mode 100644 (file)
index 0000000..8947157
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+#include "pc.h"
+#include "sysbus.h"
+#include "flash.h"
+#include "xtensa_bootparam.h"
+
+typedef struct LxBoardDesc {
+    size_t flash_size;
+    size_t flash_sector_size;
+    size_t sram_size;
+} LxBoardDesc;
+
+typedef struct Lx60FpgaState {
+    MemoryRegion iomem;
+    uint32_t leds;
+    uint32_t switches;
+} Lx60FpgaState;
+
+static void lx60_fpga_reset(void *opaque)
+{
+    Lx60FpgaState *s = opaque;
+
+    s->leds = 0;
+    s->switches = 0;
+}
+
+static uint64_t lx60_fpga_read(void *opaque, target_phys_addr_t addr,
+        unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x0: /*build date code*/
+        return 0x09272011;
+
+    case 0x4: /*processor clock frequency, Hz*/
+        return 10000000;
+
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        return s->leds;
+
+    case 0xc: /*DIP switches (off = 0, on = 1)*/
+        return s->switches;
+    }
+    return 0;
+}
+
+static void lx60_fpga_write(void *opaque, target_phys_addr_t addr,
+        uint64_t val, unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        s->leds = val;
+        break;
+
+    case 0x10: /*board reset*/
+        if (val == 0xdead) {
+            qemu_system_reset_request();
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps lx60_fpga_ops = {
+    .read = lx60_fpga_read,
+    .write = lx60_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
+        target_phys_addr_t base)
+{
+    Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
+
+    memory_region_init_io(&s->iomem, &lx60_fpga_ops, s,
+            "lx60.fpga", 0x10000);
+    memory_region_add_subregion(address_space, base, &s->iomem);
+    lx60_fpga_reset(s);
+    qemu_register_reset(lx60_fpga_reset, s);
+    return s;
+}
+
+static void lx60_net_init(MemoryRegion *address_space,
+        target_phys_addr_t base,
+        target_phys_addr_t descriptors,
+        target_phys_addr_t buffers,
+        qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    MemoryRegion *ram;
+
+    dev = qdev_create(NULL, "open_eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(address_space, base,
+            sysbus_mmio_get_region(s, 0));
+    memory_region_add_subregion(address_space, descriptors,
+            sysbus_mmio_get_region(s, 1));
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "open_eth.ram", 16384);
+    memory_region_add_subregion(address_space, buffers, ram);
+}
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void lx60_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void lx_init(const LxBoardDesc *board,
+        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)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    int be = 1;
+#else
+    int be = 0;
+#endif
+    MemoryRegion *system_memory = get_system_memory();
+    CPUState *env = NULL;
+    MemoryRegion *ram, *rom, *system_io;
+    DriveInfo *dinfo;
+    pflash_t *flash = NULL;
+    int n;
+
+    if (!cpu_model) {
+        cpu_model = "dc232b";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env->sregs[PRID] = n;
+        qemu_register_reset(lx60_reset, env);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        cpu_reset(env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "lx60.dram", ram_size);
+    memory_region_add_subregion(system_memory, 0, ram);
+
+    system_io = g_malloc(sizeof(*system_io));
+    memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024);
+    memory_region_add_subregion(system_memory, 0xf0000000, system_io);
+    lx60_fpga_init(system_io, 0x0d020000);
+    if (nd_table[0].vlan) {
+        lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
+                xtensa_get_extint(env, 1), nd_table);
+    }
+
+    if (!serial_hds[0]) {
+        serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
+    }
+
+    serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
+            115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        flash = pflash_cfi01_register(0xf8000000,
+                NULL, "lx60.io.flash", board->flash_size,
+                dinfo->bdrv, board->flash_sector_size,
+                board->flash_size / board->flash_sector_size,
+                4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+        if (flash == NULL) {
+            fprintf(stderr, "Unable to mount pflash\n");
+            exit(1);
+        }
+    }
+
+    /* Use presence of kernel file name as 'boot from SRAM' switch. */
+    if (kernel_filename) {
+        rom = g_malloc(sizeof(*rom));
+        memory_region_init_ram(rom, NULL, "lx60.sram", board->sram_size);
+        memory_region_add_subregion(system_memory, 0xfe000000, rom);
+
+        /* Put kernel bootparameters to the end of that SRAM */
+        if (kernel_cmdline) {
+            size_t cmdline_size = strlen(kernel_cmdline) + 1;
+            size_t bp_size = sizeof(BpTag[4]) + cmdline_size;
+            uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff;
+
+            env->regs[2] = tagptr;
+
+            tagptr = put_tag(tagptr, 0x7b0b, 0, NULL);
+            if (cmdline_size > 1) {
+                tagptr = put_tag(tagptr, 0x1001,
+                        cmdline_size, kernel_cmdline);
+            }
+            tagptr = put_tag(tagptr, 0x7e0b, 0, NULL);
+        }
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    } else {
+        if (flash) {
+            MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash);
+            MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
+
+            memory_region_init_alias(flash_io, "lx60.flash",
+                    flash_mr, 0, board->flash_size);
+            memory_region_add_subregion(system_memory, 0xfe000000,
+                    flash_io);
+        }
+    }
+}
+
+static void xtensa_lx60_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)
+{
+    static const LxBoardDesc lx60_board = {
+        .flash_size = 0x400000,
+        .flash_sector_size = 0x10000,
+        .sram_size = 0x20000,
+    };
+    lx_init(&lx60_board, ram_size, boot_device,
+            kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static void xtensa_lx200_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)
+{
+    static const LxBoardDesc lx200_board = {
+        .flash_size = 0x1000000,
+        .flash_sector_size = 0x20000,
+        .sram_size = 0x2000000,
+    };
+    lx_init(&lx200_board, ram_size, boot_device,
+            kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_lx60_machine = {
+    .name = "lx60",
+    .desc = "lx60 EVB (dc232b)",
+    .init = xtensa_lx60_init,
+    .max_cpus = 4,
+};
+
+static QEMUMachine xtensa_lx200_machine = {
+    .name = "lx200",
+    .desc = "lx200 EVB (dc232b)",
+    .init = xtensa_lx200_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_lx_machines_init(void)
+{
+    qemu_register_machine(&xtensa_lx60_machine);
+    qemu_register_machine(&xtensa_lx200_machine);
+}
+
+machine_init(xtensa_lx_machines_init);
diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
new file mode 100644 (file)
index 0000000..71d5fc8
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw.h"
+#include "qemu-log.h"
+#include "qemu-timer.h"
+
+void xtensa_advance_ccount(CPUState *env, uint32_t d)
+{
+    uint32_t old_ccount = env->sregs[CCOUNT];
+
+    env->sregs[CCOUNT] += d;
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
+                xtensa_timer_irq(env, i, 1);
+            }
+        }
+    }
+}
+
+void check_interrupts(CPUState *env)
+{
+    int minlevel = xtensa_get_cintlevel(env);
+    uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
+    int level;
+
+    /* If the CPU is halted advance CCOUNT according to the vm_clock time
+     * elapsed since the moment when it was advanced last time.
+     */
+    if (env->halted) {
+        int64_t now = qemu_get_clock_ns(vm_clock);
+
+        xtensa_advance_ccount(env,
+                muldiv64(now - env->halt_clock,
+                    env->config->clock_freq_khz, 1000000));
+        env->halt_clock = now;
+    }
+    for (level = env->config->nlevel; level > minlevel; --level) {
+        if (env->config->level_mask[level] & int_set_enabled) {
+            env->pending_irq_level = level;
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            qemu_log_mask(CPU_LOG_INT,
+                    "%s level = %d, cintlevel = %d, "
+                    "pc = %08x, a0 = %08x, ps = %08x, "
+                    "intset = %08x, intenable = %08x, "
+                    "ccount = %08x\n",
+                    __func__, level, xtensa_get_cintlevel(env),
+                    env->pc, env->regs[0], env->sregs[PS],
+                    env->sregs[INTSET], env->sregs[INTENABLE],
+                    env->sregs[CCOUNT]);
+            return;
+        }
+    }
+    env->pending_irq_level = 0;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void xtensa_set_irq(void *opaque, int irq, int active)
+{
+    CPUState *env = opaque;
+
+    if (irq >= env->config->ninterrupt) {
+        qemu_log("%s: bad IRQ %d\n", __func__, irq);
+    } else {
+        uint32_t irq_bit = 1 << irq;
+
+        if (active) {
+            env->sregs[INTSET] |= irq_bit;
+        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+            env->sregs[INTSET] &= ~irq_bit;
+        }
+
+        check_interrupts(env);
+    }
+}
+
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active)
+{
+    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+}
+
+void xtensa_rearm_ccompare_timer(CPUState *env)
+{
+    int i;
+    uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
+
+    for (i = 0; i < env->config->nccompare; ++i) {
+        if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
+                wake_ccount - env->sregs[CCOUNT]) {
+            wake_ccount = env->sregs[CCOMPARE + i];
+        }
+    }
+    env->wake_ccount = wake_ccount;
+    qemu_mod_timer(env->ccompare_timer, env->halt_clock +
+            muldiv64(wake_ccount - env->sregs[CCOUNT],
+                1000000, env->config->clock_freq_khz));
+}
+
+static void xtensa_ccompare_cb(void *opaque)
+{
+    CPUState *env = opaque;
+
+    if (env->halted) {
+        env->halt_clock = qemu_get_clock_ns(vm_clock);
+        xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
+        if (!cpu_has_work(env)) {
+            env->sregs[CCOUNT] = env->wake_ccount + 1;
+            xtensa_rearm_ccompare_timer(env);
+        }
+    }
+}
+
+void xtensa_irq_init(CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(
+            xtensa_set_irq, env, env->config->ninterrupt);
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+            env->config->nccompare > 0) {
+        env->ccompare_timer =
+            qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env);
+    }
+}
+
+void *xtensa_get_extint(CPUState *env, unsigned extint)
+{
+    if (extint < env->config->nextint) {
+        unsigned irq = env->config->extint[extint];
+        return env->irq_inputs[irq];
+    } else {
+        qemu_log("%s: trying to acquire invalid external interrupt %d\n",
+                __func__, extint);
+        return NULL;
+    }
+}
diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c
new file mode 100644 (file)
index 0000000..a94e4e5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void sim_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void sim_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;
+    MemoryRegion *ram, *rom;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env->sregs[PRID] = n;
+        qemu_register_reset(sim_reset, env);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        sim_reset(env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    rom = g_malloc(sizeof(*rom));
+    memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
+    memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_sim_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)
+{
+    if (!cpu_model) {
+        cpu_model = "dc232b";
+    }
+    sim_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_sim_machine = {
+    .name = "sim",
+    .desc = "sim machine (dc232b)",
+    .init = xtensa_sim_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_sim_machine_init(void)
+{
+    qemu_register_machine(&xtensa_sim_machine);
+}
+
+machine_init(xtensa_sim_machine_init);
diff --git a/hw/z2.c b/hw/z2.c
new file mode 100644 (file)
index 0000000..a03bb33
--- /dev/null
+++ b/hw/z2.c
@@ -0,0 +1,360 @@
+/*
+ * PXA270-based Zipit Z2 device
+ *
+ * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Code is based on mainstone platform.
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "boards.h"
+#include "sysemu.h"
+#include "flash.h"
+#include "blockdev.h"
+#include "console.h"
+#include "audio/audio.h"
+#include "exec-memory.h"
+
+#ifdef DEBUG_Z2
+#define DPRINTF(fmt, ...) \
+        printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static struct keymap map[0x100] = {
+    [0 ... 0xff] = { -1, -1 },
+    [0x3b] = {0, 0}, /* Option = F1 */
+    [0xc8] = {0, 1}, /* Up */
+    [0xd0] = {0, 2}, /* Down */
+    [0xcb] = {0, 3}, /* Left */
+    [0xcd] = {0, 4}, /* Right */
+    [0xcf] = {0, 5}, /* End */
+    [0x0d] = {0, 6}, /* KPPLUS */
+    [0xc7] = {1, 0}, /* Home */
+    [0x10] = {1, 1}, /* Q */
+    [0x17] = {1, 2}, /* I */
+    [0x22] = {1, 3}, /* G */
+    [0x2d] = {1, 4}, /* X */
+    [0x1c] = {1, 5}, /* Enter */
+    [0x0c] = {1, 6}, /* KPMINUS */
+    [0xc9] = {2, 0}, /* PageUp */
+    [0x11] = {2, 1}, /* W */
+    [0x18] = {2, 2}, /* O */
+    [0x23] = {2, 3}, /* H */
+    [0x2e] = {2, 4}, /* C */
+    [0x38] = {2, 5}, /* LeftAlt */
+    [0xd1] = {3, 0}, /* PageDown */
+    [0x12] = {3, 1}, /* E */
+    [0x19] = {3, 2}, /* P */
+    [0x24] = {3, 3}, /* J */
+    [0x2f] = {3, 4}, /* V */
+    [0x2a] = {3, 5}, /* LeftShift */
+    [0x01] = {4, 0}, /* Esc */
+    [0x13] = {4, 1}, /* R */
+    [0x1e] = {4, 2}, /* A */
+    [0x25] = {4, 3}, /* K */
+    [0x30] = {4, 4}, /* B */
+    [0x1d] = {4, 5}, /* LeftCtrl */
+    [0x0f] = {5, 0}, /* Tab */
+    [0x14] = {5, 1}, /* T */
+    [0x1f] = {5, 2}, /* S */
+    [0x26] = {5, 3}, /* L */
+    [0x31] = {5, 4}, /* N */
+    [0x39] = {5, 5}, /* Space */
+    [0x3c] = {6, 0}, /* Stop = F2 */
+    [0x15] = {6, 1}, /* Y */
+    [0x20] = {6, 2}, /* D */
+    [0x0e] = {6, 3}, /* Backspace */
+    [0x32] = {6, 4}, /* M */
+    [0x33] = {6, 5}, /* Comma */
+    [0x3d] = {7, 0}, /* Play = F3 */
+    [0x16] = {7, 1}, /* U */
+    [0x21] = {7, 2}, /* F */
+    [0x2c] = {7, 3}, /* Z */
+    [0x27] = {7, 4}, /* Semicolon */
+    [0x34] = {7, 5}, /* Dot */
+};
+
+#define Z2_RAM_SIZE     0x02000000
+#define Z2_FLASH_BASE   0x00000000
+#define Z2_FLASH_SIZE   0x00800000
+
+static struct arm_boot_info z2_binfo = {
+    .loader_start   = PXA2XX_SDRAM_BASE,
+    .ram_size       = Z2_RAM_SIZE,
+};
+
+#define Z2_GPIO_SD_DETECT   96
+#define Z2_GPIO_AC_IN       0
+#define Z2_GPIO_KEY_ON      1
+#define Z2_GPIO_LCD_CS      88
+
+typedef struct {
+    SSISlave ssidev;
+    int32_t selected;
+    int32_t enabled;
+    uint8_t buf[3];
+    uint32_t cur_reg;
+    int pos;
+} ZipitLCD;
+
+static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
+{
+    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+    uint16_t val;
+    if (z->selected) {
+        z->buf[z->pos] = value & 0xff;
+        z->pos++;
+    }
+    if (z->pos == 3) {
+        switch (z->buf[0]) {
+        case 0x74:
+            DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
+            z->cur_reg = z->buf[2];
+            break;
+        case 0x76:
+            val = z->buf[1] << 8 | z->buf[2];
+            DPRINTF("%s: value: 0x%.4x\n", __func__, val);
+            if (z->cur_reg == 0x22 && val == 0x0000) {
+                z->enabled = 1;
+                printf("%s: LCD enabled\n", __func__);
+            } else if (z->cur_reg == 0x10 && val == 0x0000) {
+                z->enabled = 0;
+                printf("%s: LCD disabled\n", __func__);
+            }
+            break;
+        default:
+            DPRINTF("%s: unknown command!\n", __func__);
+            break;
+        }
+        z->pos = 0;
+    }
+    return 0;
+}
+
+static void z2_lcd_cs(void *opaque, int line, int level)
+{
+    ZipitLCD *z2_lcd = opaque;
+    z2_lcd->selected = !level;
+}
+
+static int zipit_lcd_init(SSISlave *dev)
+{
+    ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+    z->selected = 0;
+    z->enabled = 0;
+    z->pos = 0;
+
+    return 0;
+}
+
+static VMStateDescription vmstate_zipit_lcd_state = {
+    .name = "zipit-lcd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(selected, ZipitLCD),
+        VMSTATE_INT32(enabled, ZipitLCD),
+        VMSTATE_BUFFER(buf, ZipitLCD),
+        VMSTATE_UINT32(cur_reg, ZipitLCD),
+        VMSTATE_INT32(pos, ZipitLCD),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static SSISlaveInfo zipit_lcd_info = {
+    .qdev.name = "zipit-lcd",
+    .qdev.size = sizeof(ZipitLCD),
+    .qdev.vmsd = &vmstate_zipit_lcd_state,
+    .init = zipit_lcd_init,
+    .transfer = zipit_lcd_transfer
+};
+
+typedef struct {
+    i2c_slave i2c;
+    int len;
+    uint8_t buf[3];
+} AER915State;
+
+static int aer915_send(i2c_slave *i2c, uint8_t data)
+{
+    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+    s->buf[s->len] = data;
+    if (s->len++ > 2) {
+        DPRINTF("%s: message too long (%i bytes)\n",
+            __func__, s->len);
+        return 1;
+    }
+
+    if (s->len == 2) {
+        DPRINTF("%s: reg %d value 0x%02x\n", __func__,
+                s->buf[0], s->buf[1]);
+    }
+
+    return 0;
+}
+
+static void aer915_event(i2c_slave *i2c, enum i2c_event event)
+{
+    AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+    switch (event) {
+    case I2C_START_SEND:
+        s->len = 0;
+        break;
+    case I2C_START_RECV:
+        if (s->len != 1) {
+            DPRINTF("%s: short message!?\n", __func__);
+        }
+        break;
+    case I2C_FINISH:
+        break;
+    default:
+        break;
+    }
+}
+
+static int aer915_recv(i2c_slave *slave)
+{
+    int retval = 0x00;
+    AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
+
+    switch (s->buf[0]) {
+    /* Return hardcoded battery voltage,
+     * 0xf0 means ~4.1V
+     */
+    case 0x02:
+        retval = 0xf0;
+        break;
+    /* Return 0x00 for other regs,
+     * we don't know what they are for,
+     * anyway they return 0x00 on real hardware.
+     */
+    default:
+        break;
+    }
+
+    return retval;
+}
+
+static int aer915_init(i2c_slave *i2c)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+static VMStateDescription vmstate_aer915_state = {
+    .name = "aer915",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(len, AER915State),
+        VMSTATE_BUFFER(buf, AER915State),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static I2CSlaveInfo aer915_info = {
+    .qdev.name = "aer915",
+    .qdev.size = sizeof(AER915State),
+    .qdev.vmsd = &vmstate_aer915_state,
+    .init = aer915_init,
+    .event = aer915_event,
+    .recv = aer915_recv,
+    .send = aer915_send
+};
+
+static void z2_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)
+{
+    MemoryRegion *address_space_mem = get_system_memory();
+    uint32_t sector_len = 0x10000;
+    PXA2xxState *cpu;
+    DriveInfo *dinfo;
+    int be;
+    void *z2_lcd;
+    i2c_bus *bus;
+    DeviceState *wm;
+
+    if (!cpu_model) {
+        cpu_model = "pxa270-c5";
+    }
+
+    /* Setup CPU & memory */
+    cpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "Flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+    if (!pflash_cfi01_register(Z2_FLASH_BASE,
+                               NULL, "z2.flash0", Z2_FLASH_SIZE,
+                               dinfo->bdrv, sector_len,
+                               Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
+                               be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* setup keypad */
+    pxa27x_register_keypad(cpu->kp, map, 0x100);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc,
+        NULL,
+        qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT));
+
+    ssi_register_slave(&zipit_lcd_info);
+    i2c_register_slave(&aer915_info);
+    z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
+    bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+    i2c_create_slave(bus, "aer915", 0x55);
+    wm = i2c_create_slave(bus, "wm8750", 0x1b);
+    cpu->i2s->opaque = wm;
+    cpu->i2s->codec_out = wm8750_dac_dat;
+    cpu->i2s->codec_in = wm8750_adc_dat;
+    wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
+
+    qdev_connect_gpio_out(cpu->gpio, Z2_GPIO_LCD_CS,
+        qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]);
+
+    if (kernel_filename) {
+        z2_binfo.kernel_filename = kernel_filename;
+        z2_binfo.kernel_cmdline = kernel_cmdline;
+        z2_binfo.initrd_filename = initrd_filename;
+        z2_binfo.board_id = 0x6dd;
+        arm_load_kernel(cpu->env, &z2_binfo);
+    }
+}
+
+static QEMUMachine z2_machine = {
+    .name = "z2",
+    .desc = "Zipit Z2 (PXA27x)",
+    .init = z2_init,
+};
+
+static void z2_machine_init(void)
+{
+    qemu_register_machine(&z2_machine);
+}
+
+machine_init(z2_machine_init);
index fca11a53337852828d2a45087b4b302df4f8dfcc..0eeacf7cb3fb82aec031ac5750adfcf9d4929e9f 100644 (file)
@@ -16,7 +16,6 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "hw.h"
-#include "pxa.h"
 #include "sharpsl.h"
 #include "sysbus.h"
 
@@ -181,17 +180,34 @@ static int scoop_init(SysBusDevice *dev)
     return 0;
 }
 
+static int scoop_post_load(void *opaque, int version_id)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+    int i;
+    uint32_t level;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (i = 0; i < 16; i++) {
+        qemu_set_irq(s->handler[i], (level >> i) & 1);
+    }
+
+    s->prev_level = level;
+
+    return 0;
+}
+
 static bool is_version_0 (void *opaque, int version_id)
 {
     return version_id == 0;
 }
 
-
 static const VMStateDescription vmstate_scoop_regs = {
     .name = "scoop",
     .version_id = 1,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
+    .post_load = scoop_post_load,
     .fields = (VMStateField []) {
         VMSTATE_UINT16(status, ScoopInfo),
         VMSTATE_UINT16(power, ScoopInfo),
@@ -230,7 +246,7 @@ device_init(scoop_register);
 
 #define MAGIC_CHG(a, b, c, d)  ((d << 24) | (c << 16) | (b << 8) | a)
 
-static struct __attribute__ ((__packed__)) sl_param_info {
+static struct QEMU_PACKED sl_param_info {
     uint32_t comadj_keyword;
     int32_t comadj;
 
diff --git a/i386.ld b/i386.ld
index f8df7bf8dd66fffb768e14f9aa14397f5177b522..cc3f160af07c21ceeb0fe62bf3772ad7b314ac41 100644 (file)
--- a/i386.ld
+++ b/i386.ld
@@ -42,16 +42,16 @@ SECTIONS
   .rel.plt      :
   {
     *(.rel.plt)
-    PROVIDE_HIDDEN (__rel_iplt_start = .);
+    PROVIDE (__rel_iplt_start = .);
     *(.rel.iplt)
-    PROVIDE_HIDDEN (__rel_iplt_end = .);
+    PROVIDE (__rel_iplt_end = .);
   }
   .rela.plt       :
   {
     *(.rela.plt)
-    PROVIDE_HIDDEN (__rela_iplt_start = .);
+    PROVIDE (__rela_iplt_start = .);
     *(.rela.iplt)
-    PROVIDE_HIDDEN (__rela_iplt_end = .);
+    PROVIDE (__rela_iplt_end = .);
   }
   .init          : { *(.init)  } =0x47ff041f
   .text      :
index 2886df361443c920a99fb7c80937302add8acbd3..2a103e6b5cbfa6a71381ce39ab2f79449a05391b 100644 (file)
@@ -781,6 +781,9 @@ ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
   return 0;
 }
 
+/* glib.h defines ABS so we must undefine it to avoid a clash */
+#undef ABS
+
 #define CST    IA64_OPND_CLASS_CST
 #define REG    IA64_OPND_CLASS_REG
 #define IND    IA64_OPND_CLASS_IND
diff --git a/input.c b/input.c
index 7e5fa1ac502e381efc0c7c86b98ae42281b7a8d7..37c88c78951f2847147043889253ab0d18a8877d 100644 (file)
--- a/input.c
+++ b/input.c
 #include "net.h"
 #include "monitor.h"
 #include "console.h"
-#include "qjson.h"
+#include "error.h"
+#include "qmp-commands.h"
 
 static QEMUPutKBDEvent *qemu_put_kbd_event;
 static void *qemu_put_kbd_event_opaque;
+#ifdef CONFIG_MARU
 static QEMUPutKBDEvent *qemu_put_ps2kbd_event;
 static void *qemu_put_ps2kbd_event_opaque;
+#endif
 static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
 static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
     QTAILQ_HEAD_INITIALIZER(mouse_handlers);
@@ -50,9 +53,10 @@ void qemu_remove_kbd_event_handler(void)
     qemu_put_kbd_event = NULL;
 }
 
+#ifdef CONFIG_MARU
+
 void qemu_add_ps2kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
 {
-    qemu_add_kbd_event_handler(func,opaque); // temporary code for compatibility with Xserver
     qemu_put_ps2kbd_event_opaque = opaque;
     qemu_put_ps2kbd_event = func;
 }
@@ -63,6 +67,15 @@ void qemu_remove_ps2kbd_event_handler(void)
     qemu_put_ps2kbd_event = NULL;
 }
 
+void ps2kbd_put_keycode(int keycode)
+{
+    if (qemu_put_ps2kbd_event) {
+        qemu_put_ps2kbd_event(qemu_put_ps2kbd_event_opaque, keycode);
+    }
+}
+
+#endif
+
 static void check_mode_change(void)
 {
     static int current_is_absolute, current_has_absolute;
@@ -74,7 +87,7 @@ static void check_mode_change(void)
 
     if (is_absolute != current_is_absolute ||
         has_absolute != current_has_absolute) {
-        notifier_list_notify(&mouse_mode_notifiers);
+        notifier_list_notify(&mouse_mode_notifiers, NULL);
     }
 
     current_is_absolute = is_absolute;
@@ -88,12 +101,12 @@ QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
     QEMUPutMouseEntry *s;
     static int mouse_index = 0;
 
-    s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
+    s = g_malloc0(sizeof(QEMUPutMouseEntry));
 
     s->qemu_put_mouse_event = func;
     s->qemu_put_mouse_event_opaque = opaque;
     s->qemu_put_mouse_event_absolute = absolute;
-    s->qemu_put_mouse_event_name = qemu_strdup(name);
+    s->qemu_put_mouse_event_name = g_strdup(name);
     s->index = mouse_index++;
 
     QTAILQ_INSERT_TAIL(&mouse_handlers, s, node);
@@ -115,8 +128,8 @@ void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
 {
     QTAILQ_REMOVE(&mouse_handlers, entry, node);
 
-    qemu_free(entry->qemu_put_mouse_event_name);
-    qemu_free(entry);
+    g_free(entry->qemu_put_mouse_event_name);
+    g_free(entry);
 
     check_mode_change();
 }
@@ -126,7 +139,7 @@ QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
 {
     QEMUPutLEDEntry *s;
 
-    s = qemu_mallocz(sizeof(QEMUPutLEDEntry));
+    s = g_malloc0(sizeof(QEMUPutLEDEntry));
 
     s->put_led = func;
     s->opaque = opaque;
@@ -139,7 +152,7 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
     if (entry == NULL)
         return;
     QTAILQ_REMOVE(&led_handlers, entry, next);
-    qemu_free(entry);
+    g_free(entry);
 }
 
 void kbd_put_keycode(int keycode)
@@ -149,13 +162,6 @@ void kbd_put_keycode(int keycode)
     }
 }
 
-void ps2kbd_put_keycode(int keycode)
-{
-    if (qemu_put_ps2kbd_event) {
-        qemu_put_ps2kbd_event(qemu_put_ps2kbd_event_opaque, keycode);
-    }
-}
-
 void kbd_put_ledstate(int ledstate)
 {
     QEMUPutLEDEntry *cursor;
@@ -170,7 +176,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     QEMUPutMouseEntry *entry;
     QEMUPutMouseEvent *mouse_event;
     void *mouse_event_opaque;
-    int width;
+    int width, height;
 
     if (QTAILQ_EMPTY(&mouse_handlers)) {
         return;
@@ -182,16 +188,32 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
 
     if (mouse_event) {
-        if (graphic_rotate) {
-            if (entry->qemu_put_mouse_event_absolute)
-                width = 0x7fff;
-            else
-                width = graphic_width - 1;
+        if (entry->qemu_put_mouse_event_absolute) {
+            width = 0x7fff;
+            height = 0x7fff;
+        } else {
+            width = graphic_width - 1;
+            height = graphic_height - 1;
+        }
+
+        switch (graphic_rotate) {
+        case 0:
+            mouse_event(mouse_event_opaque,
+                        dx, dy, dz, buttons_state);
+            break;
+        case 90:
             mouse_event(mouse_event_opaque,
                         width - dy, dx, dz, buttons_state);
-        } else
+            break;
+        case 180:
             mouse_event(mouse_event_opaque,
-                        dx, dy, dz, buttons_state);
+                        width - dx, height - dy, dz, buttons_state);
+            break;
+        case 270:
+            mouse_event(mouse_event_opaque,
+                        dy, height - dx, dz, buttons_state);
+            break;
+        }
     }
 }
 
@@ -217,60 +239,27 @@ int kbd_mouse_has_absolute(void)
     return 0;
 }
 
-static void info_mice_iter(QObject *data, void *opaque)
-{
-    QDict *mouse;
-    Monitor *mon = opaque;
-
-    mouse = qobject_to_qdict(data);
-    monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
-                  (qdict_get_bool(mouse, "current") ? '*' : ' '),
-                   qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
-                   qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
-}
-
-void do_info_mice_print(Monitor *mon, const QObject *data)
-{
-    QList *mice_list;
-
-    mice_list = qobject_to_qlist(data);
-    if (qlist_empty(mice_list)) {
-        monitor_printf(mon, "No mouse devices connected\n");
-        return;
-    }
-
-    qlist_iter(mice_list, info_mice_iter, mon);
-}
-
-void do_info_mice(Monitor *mon, QObject **ret_data)
+MouseInfoList *qmp_query_mice(Error **errp)
 {
+    MouseInfoList *mice_list = NULL;
     QEMUPutMouseEntry *cursor;
-    QList *mice_list;
-    int current;
+    bool current = true;
 
-    mice_list = qlist_new();
-
-    if (QTAILQ_EMPTY(&mouse_handlers)) {
-        goto out;
-    }
+    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
+        MouseInfoList *info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
+        info->value->index = cursor->index;
+        info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
+        info->value->current = current;
 
-    current = QTAILQ_FIRST(&mouse_handlers)->index;
+        current = false;
 
-    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
-        QObject *obj;
-        obj = qobject_from_jsonf("{ 'name': %s,"
-                                 "  'index': %d,"
-                                 "  'current': %i,"
-                                 "  'absolute': %i }",
-                                 cursor->qemu_put_mouse_event_name,
-                                 cursor->index,
-                                 cursor->index == current,
-                                 !!cursor->qemu_put_mouse_event_absolute);
-        qlist_append_obj(mice_list, obj);
+        info->next = mice_list;
+        mice_list = info;
     }
 
-out:
-    *ret_data = QOBJECT(mice_list);
+    return mice_list;
 }
 
 void do_mouse_set(Monitor *mon, const QDict *qdict)
diff --git a/int128.h b/int128.h
new file mode 100644 (file)
index 0000000..b3864b6
--- /dev/null
+++ b/int128.h
@@ -0,0 +1,116 @@
+#ifndef INT128_H
+#define INT128_H
+
+typedef struct Int128 Int128;
+
+struct Int128 {
+    uint64_t lo;
+    int64_t hi;
+};
+
+static inline Int128 int128_make64(uint64_t a)
+{
+    return (Int128) { a, 0 };
+}
+
+static inline uint64_t int128_get64(Int128 a)
+{
+    assert(!a.hi);
+    return a.lo;
+}
+
+static inline Int128 int128_zero(void)
+{
+    return int128_make64(0);
+}
+
+static inline Int128 int128_one(void)
+{
+    return int128_make64(1);
+}
+
+static inline Int128 int128_2_64(void)
+{
+    return (Int128) { 0, 1 };
+}
+
+static inline Int128 int128_add(Int128 a, Int128 b)
+{
+    Int128 r = { a.lo + b.lo, a.hi + b.hi };
+    r.hi += (r.lo < a.lo) || (r.lo < b.lo);
+    return r;
+}
+
+static inline Int128 int128_neg(Int128 a)
+{
+    a.lo = ~a.lo;
+    a.hi = ~a.hi;
+    return int128_add(a, int128_one());
+}
+
+static inline Int128 int128_sub(Int128 a, Int128 b)
+{
+    return int128_add(a, int128_neg(b));
+}
+
+static inline bool int128_nonneg(Int128 a)
+{
+    return a.hi >= 0;
+}
+
+static inline bool int128_eq(Int128 a, Int128 b)
+{
+    return a.lo == b.lo && a.hi == b.hi;
+}
+
+static inline bool int128_ne(Int128 a, Int128 b)
+{
+    return !int128_eq(a, b);
+}
+
+static inline bool int128_ge(Int128 a, Int128 b)
+{
+    return int128_nonneg(int128_sub(a, b));
+}
+
+static inline bool int128_lt(Int128 a, Int128 b)
+{
+    return !int128_ge(a, b);
+}
+
+static inline bool int128_le(Int128 a, Int128 b)
+{
+    return int128_ge(b, a);
+}
+
+static inline bool int128_gt(Int128 a, Int128 b)
+{
+    return !int128_le(a, b);
+}
+
+static inline bool int128_nz(Int128 a)
+{
+    return a.lo || a.hi;
+}
+
+static inline Int128 int128_min(Int128 a, Int128 b)
+{
+    return int128_le(a, b) ? a : b;
+}
+
+static inline Int128 int128_max(Int128 a, Int128 b)
+{
+    return int128_ge(a, b) ? a : b;
+}
+
+static inline void int128_addto(Int128 *a, Int128 b)
+{
+    *a = int128_add(*a, b);
+}
+
+static inline void int128_subfrom(Int128 *a, Int128 b)
+{
+    *a = int128_sub(*a, b);
+}
+
+#endif
diff --git a/iohandler.c b/iohandler.c
new file mode 100644 (file)
index 0000000..5640d49
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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"
+#include "main-loop.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 = g_malloc0(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);
+                g_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);
+            g_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 = g_malloc0(sizeof(ChildProcessRecord));
+    rec->pid = pid;
+    QLIST_INSERT_HEAD(&child_watches, rec, next);
+    return 0;
+}
+#endif
index aa4188a40f195c721009a328e24e43bfde91f6a4..36fa3a477ebde72de4745bf4e13ad5146f4686fd 100644 (file)
--- a/ioport.c
+++ b/ioport.c
@@ -27,6 +27,7 @@
 
 #include "ioport.h"
 #include "trace.h"
+#include "memory.h"
 
 /***********************************************************/
 /* IO Port */
@@ -146,10 +147,11 @@ int register_ioport_read(pio_addr_t start, int length, int size,
         hw_error("register_ioport_read: invalid size");
         return -1;
     }
-    for(i = start; i < start + length; i += size) {
+    for(i = start; i < start + length; ++i) {
         ioport_read_table[bsize][i] = func;
         if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
-            hw_error("register_ioport_read: invalid opaque");
+            hw_error("register_ioport_read: invalid opaque for address 0x%x",
+                     i);
         ioport_opaque[i] = opaque;
     }
     return 0;
@@ -165,10 +167,11 @@ int register_ioport_write(pio_addr_t start, int length, int size,
         hw_error("register_ioport_write: invalid size");
         return -1;
     }
-    for(i = start; i < start + length; i += size) {
+    for(i = start; i < start + length; ++i) {
         ioport_write_table[bsize][i] = func;
         if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
-            hw_error("register_ioport_write: invalid opaque");
+            hw_error("register_ioport_write: invalid opaque for address 0x%x",
+                     i);
         ioport_opaque[i] = opaque;
     }
     return 0;
@@ -243,18 +246,25 @@ void isa_unassign_ioport(pio_addr_t start, int length)
     int i;
 
     for(i = start; i < start + length; i++) {
-        ioport_read_table[0][i] = default_ioport_readb;
-        ioport_read_table[1][i] = default_ioport_readw;
-        ioport_read_table[2][i] = default_ioport_readl;
+        ioport_read_table[0][i] = NULL;
+        ioport_read_table[1][i] = NULL;
+        ioport_read_table[2][i] = NULL;
 
-        ioport_write_table[0][i] = default_ioport_writeb;
-        ioport_write_table[1][i] = default_ioport_writew;
-        ioport_write_table[2][i] = default_ioport_writel;
+        ioport_write_table[0][i] = NULL;
+        ioport_write_table[1][i] = NULL;
+        ioport_write_table[2][i] = NULL;
 
         ioport_opaque[i] = NULL;
     }
 }
 
+bool isa_is_ioport_assigned(pio_addr_t start)
+{
+    return (ioport_read_table[0][start] || ioport_write_table[0][start] ||
+           ioport_read_table[1][start] || ioport_write_table[1][start] ||
+           ioport_read_table[2][start] || ioport_write_table[2][start]);
+}
+
 /***********************************************************/
 
 void cpu_outb(pio_addr_t addr, uint8_t val)
@@ -304,3 +314,110 @@ uint32_t cpu_inl(pio_addr_t addr)
     LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
     return val;
 }
+
+void portio_list_init(PortioList *piolist,
+                      const MemoryRegionPortio *callbacks,
+                      void *opaque, const char *name)
+{
+    unsigned n = 0;
+
+    while (callbacks[n].size) {
+        ++n;
+    }
+
+    piolist->ports = callbacks;
+    piolist->nr = 0;
+    piolist->regions = g_new0(MemoryRegion *, n);
+    piolist->address_space = NULL;
+    piolist->opaque = opaque;
+    piolist->name = name;
+}
+
+void portio_list_destroy(PortioList *piolist)
+{
+    g_free(piolist->regions);
+}
+
+static void portio_list_add_1(PortioList *piolist,
+                              const MemoryRegionPortio *pio_init,
+                              unsigned count, unsigned start,
+                              unsigned off_low, unsigned off_high)
+{
+    MemoryRegionPortio *pio;
+    MemoryRegionOps *ops;
+    MemoryRegion *region;
+    unsigned i;
+
+    /* Copy the sub-list and null-terminate it.  */
+    pio = g_new(MemoryRegionPortio, count + 1);
+    memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count);
+    memset(pio + count, 0, sizeof(MemoryRegionPortio));
+
+    /* Adjust the offsets to all be zero-based for the region.  */
+    for (i = 0; i < count; ++i) {
+        pio[i].offset -= off_low;
+    }
+
+    ops = g_new0(MemoryRegionOps, 1);
+    ops->old_portio = pio;
+
+    region = g_new(MemoryRegion, 1);
+    memory_region_init_io(region, ops, piolist->opaque, piolist->name,
+                          off_high - off_low);
+    memory_region_set_offset(region, start + off_low);
+    memory_region_add_subregion(piolist->address_space,
+                                start + off_low, region);
+    piolist->regions[piolist->nr++] = region;
+}
+
+void portio_list_add(PortioList *piolist,
+                     MemoryRegion *address_space,
+                     uint32_t start)
+{
+    const MemoryRegionPortio *pio, *pio_start = piolist->ports;
+    unsigned int off_low, off_high, off_last, count;
+
+    piolist->address_space = address_space;
+
+    /* Handle the first entry specially.  */
+    off_last = off_low = pio_start->offset;
+    off_high = off_low + pio_start->len;
+    count = 1;
+
+    for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
+        /* All entries must be sorted by offset.  */
+        assert(pio->offset >= off_last);
+        off_last = pio->offset;
+
+        /* If we see a hole, break the region.  */
+        if (off_last > off_high) {
+            portio_list_add_1(piolist, pio_start, count, start, off_low,
+                              off_high);
+            /* ... and start collecting anew.  */
+            pio_start = pio;
+            off_low = off_last;
+            off_high = off_low + pio->len;
+            count = 0;
+        } else if (off_last + pio->len > off_high) {
+            off_high = off_last + pio->len;
+        }
+    }
+
+    /* There will always be an open sub-list.  */
+    portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
+}
+
+void portio_list_del(PortioList *piolist)
+{
+    MemoryRegion *mr;
+    unsigned i;
+
+    for (i = 0; i < piolist->nr; ++i) {
+        mr = piolist->regions[i];
+        memory_region_del_subregion(piolist->address_space, mr);
+        memory_region_destroy(mr);
+        g_free((MemoryRegionOps *)mr->ops);
+        g_free(mr);
+        piolist->regions[i] = NULL;
+    }
+}
index 5ae62a3a2c712b9b322d8011d7052fb7cdc94380..ae3e9da0b5487e68a16f28c459889496160e8e16 100644 (file)
--- a/ioport.h
+++ b/ioport.h
@@ -43,7 +43,7 @@ int register_ioport_read(pio_addr_t start, int length, int size,
 int register_ioport_write(pio_addr_t start, int length, int size,
                           IOPortWriteFunc *func, void *opaque);
 void isa_unassign_ioport(pio_addr_t start, int length);
-
+bool isa_is_ioport_assigned(pio_addr_t start);
 
 void cpu_outb(pio_addr_t addr, uint8_t val);
 void cpu_outw(pio_addr_t addr, uint16_t val);
@@ -52,4 +52,25 @@ uint8_t cpu_inb(pio_addr_t addr);
 uint16_t cpu_inw(pio_addr_t addr);
 uint32_t cpu_inl(pio_addr_t addr);
 
+struct MemoryRegion;
+struct MemoryRegionPortio;
+
+typedef struct PortioList {
+    const struct MemoryRegionPortio *ports;
+    struct MemoryRegion *address_space;
+    unsigned nr;
+    struct MemoryRegion **regions;
+    void *opaque;
+    const char *name;
+} PortioList;
+
+void portio_list_init(PortioList *piolist,
+                      const struct MemoryRegionPortio *callbacks,
+                      void *opaque, const char *name);
+void portio_list_destroy(PortioList *piolist);
+void portio_list_add(PortioList *piolist,
+                     struct MemoryRegion *address_space,
+                     uint32_t addr);
+void portio_list_del(PortioList *piolist);
+
 #endif /* IOPORT_H */
diff --git a/iov.c b/iov.c
index 588cd042881b5af2b808094a793f868f2a01bf6e..e7385c41f4ecc55f0234ba1cafd78f2fa1df0bbb 100644 (file)
--- a/iov.c
+++ b/iov.c
 
 #include "iov.h"
 
-size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
-                    const void *buf, size_t size)
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size)
 {
-    size_t offset;
+    size_t iovec_off, buf_off;
     unsigned int i;
 
-    offset = 0;
-    for (i = 0; offset < size && i < iovcnt; i++) {
-        size_t len;
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off, size);
 
-        len = MIN(iov[i].iov_len, size - offset);
+            memcpy(iov[i].iov_base + (iov_off - iovec_off), buf + buf_off, len);
 
-        memcpy(iov[i].iov_base, buf + offset, len);
-        offset += len;
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
     }
-    return offset;
+    return buf_off;
 }
 
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
-                  void *buf, size_t offset, size_t size)
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size)
 {
     uint8_t *ptr;
-    size_t iov_off, buf_off;
+    size_t iovec_off, buf_off;
     unsigned int i;
 
     ptr = buf;
-    iov_off = 0;
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
+
+            memcpy(ptr + buf_off, iov[i].iov_base + (iov_off - iovec_off), len);
+
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
+    }
+    return buf_off;
+}
+
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+                 size_t iov_off, size_t size)
+{
+    size_t iovec_off, buf_off;
+    unsigned int i;
+
+    iovec_off = 0;
     buf_off = 0;
-    for (i = 0; i < iovcnt && size; i++) {
-        if (offset < (iov_off + iov[i].iov_len)) {
-            size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
 
-            memcpy(ptr + buf_off, iov[i].iov_base + (offset - iov_off), len);
+            memset(iov[i].iov_base + (iov_off - iovec_off), 0, len);
 
             buf_off += len;
-            offset += len;
+            iov_off += len;
             size -= len;
         }
-        iov_off += iov[i].iov_len;
+        iovec_off += iov[i].iov_len;
     }
     return buf_off;
 }
 
-size_t iov_size(const struct iovec *iov, const unsigned int iovcnt)
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
 {
     size_t len;
     unsigned int i;
 
     len = 0;
-    for (i = 0; i < iovcnt; i++) {
+    for (i = 0; i < iov_cnt; i++) {
         len += iov[i].iov_len;
     }
     return len;
 }
+
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+                 FILE *fp, const char *prefix, size_t limit)
+{
+    unsigned int i, v, b;
+    uint8_t *c;
+
+    c = iov[0].iov_base;
+    for (i = 0, v = 0, b = 0; b < limit; i++, b++) {
+        if (i == iov[v].iov_len) {
+            i = 0; v++;
+            if (v == iov_cnt) {
+                break;
+            }
+            c = iov[v].iov_base;
+        }
+        if ((b % 16) == 0) {
+            fprintf(fp, "%s: %04x:", prefix, b);
+        }
+        if ((b % 4) == 0) {
+            fprintf(fp, " ");
+        }
+        fprintf(fp, " %02x", c[i]);
+        if ((b % 16) == 15) {
+            fprintf(fp, "\n");
+        }
+    }
+    if ((b % 16) != 0) {
+        fprintf(fp, "\n");
+    }
+}
diff --git a/iov.h b/iov.h
index 60a85470bd7336f932fbd52bdf7fc87183c9420c..94d2f7828433890d133d37fff8d2b1122450d267 100644 (file)
--- a/iov.h
+++ b/iov.h
 
 #include "qemu-common.h"
 
-size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
-                    const void *buf, size_t size);
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
-                  void *buf, size_t offset, size_t size);
-size_t iov_size(const struct iovec *iov, const unsigned int iovcnt);
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size);
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size);
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+                 size_t iov_off, size_t size);
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+                 FILE *fp, const char *prefix, size_t limit);
index c736f42900e9484a33327cf79ac094ef99e86a66..c21338f66db75814e504ca86bf29c7b7487c3903 100644 (file)
@@ -18,6 +18,8 @@
 #include "qemu-common.h"
 #include "json-lexer.h"
 
+#define MAX_TOKEN_SIZE (64ULL << 20)
+
 /*
  * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
  * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
@@ -28,7 +30,7 @@
  */
 
 enum json_lexer_state {
-    ERROR = 0,
+    IN_ERROR = 0,
     IN_DQ_UCODE3,
     IN_DQ_UCODE2,
     IN_DQ_UCODE1,
@@ -103,7 +105,8 @@ static const uint8_t json_lexer[][256] =  {
         ['u'] = IN_DQ_UCODE0,
     },
     [IN_DQ_STRING] = {
-        [1 ... 0xFF] = IN_DQ_STRING,
+        [1 ... 0xBF] = IN_DQ_STRING,
+        [0xC2 ... 0xF4] = IN_DQ_STRING,
         ['\\'] = IN_DQ_STRING_ESCAPE,
         ['"'] = JSON_STRING,
     },
@@ -142,7 +145,8 @@ static const uint8_t json_lexer[][256] =  {
         ['u'] = IN_SQ_UCODE0,
     },
     [IN_SQ_STRING] = {
-        [1 ... 0xFF] = IN_SQ_STRING,
+        [1 ... 0xBF] = IN_SQ_STRING,
+        [0xC2 ... 0xF4] = IN_SQ_STRING,
         ['\\'] = IN_SQ_STRING_ESCAPE,
         ['\''] = JSON_STRING,
     },
@@ -150,7 +154,7 @@ static const uint8_t json_lexer[][256] =  {
     /* Zero */
     [IN_ZERO] = {
         TERMINAL(JSON_INTEGER),
-        ['0' ... '9'] = ERROR,
+        ['0' ... '9'] = IN_ERROR,
         ['.'] = IN_MANTISSA,
     },
 
@@ -272,7 +276,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
     lexer->x = lexer->y = 0;
 }
 
-static int json_lexer_feed_char(JSONLexer *lexer, char ch)
+static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
 {
     int char_consumed, new_state;
 
@@ -302,13 +306,42 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
             lexer->token = qstring_new();
             new_state = IN_START;
             break;
-        case ERROR:
-            return -EINVAL;
+        case IN_ERROR:
+            /* XXX: To avoid having previous bad input leaving the parser in an
+             * unresponsive state where we consume unpredictable amounts of
+             * subsequent "good" input, percolate this error state up to the
+             * tokenizer/parser by forcing a NULL object to be emitted, then
+             * reset state.
+             *
+             * Also note that this handling is required for reliable channel
+             * negotiation between QMP and the guest agent, since chr(0xFF)
+             * is placed at the beginning of certain events to ensure proper
+             * delivery when the channel is in an unknown state. chr(0xFF) is
+             * never a valid ASCII/UTF-8 sequence, so this should reliably
+             * induce an error/flush state.
+             */
+            lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
+            QDECREF(lexer->token);
+            lexer->token = qstring_new();
+            new_state = IN_START;
+            lexer->state = new_state;
+            return 0;
         default:
             break;
         }
         lexer->state = new_state;
-    } while (!char_consumed);
+    } while (!char_consumed && !flush);
+
+    /* Do not let a single token grow to an arbitrarily large size,
+     * this is a security consideration.
+     */
+    if (lexer->token->length > MAX_TOKEN_SIZE) {
+        lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
+        QDECREF(lexer->token);
+        lexer->token = qstring_new();
+        lexer->state = IN_START;
+    }
+
     return 0;
 }
 
@@ -319,7 +352,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
     for (i = 0; i < size; i++) {
         int err;
 
-        err = json_lexer_feed_char(lexer, buffer[i]);
+        err = json_lexer_feed_char(lexer, buffer[i], false);
         if (err < 0) {
             return err;
         }
@@ -330,7 +363,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
 
 int json_lexer_flush(JSONLexer *lexer)
 {
-    return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0);
+    return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
 }
 
 void json_lexer_destroy(JSONLexer *lexer)
index 3b50c4634b31c4931d67dafbf28603f5e6b22832..10bc0a77984df5e607b3382c9b455907fa4edbc2 100644 (file)
@@ -25,6 +25,7 @@ typedef enum json_token_type {
     JSON_STRING,
     JSON_ESCAPE,
     JSON_SKIP,
+    JSON_ERROR,
 } JSONTokenType;
 
 typedef struct JSONLexer JSONLexer;
index 6c06ef91a623ce4dd90dc59435beefcea7242cee..849e2156da4e7a3fad8f890370236cb6da9be716 100644 (file)
 #include "qbool.h"
 #include "json-parser.h"
 #include "json-lexer.h"
+#include "qerror.h"
 
 typedef struct JSONParserContext
 {
+    Error *err;
 } JSONParserContext;
 
 #define BUG_ON(cond) assert(!(cond))
@@ -95,11 +97,15 @@ static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
                                            QObject *token, const char *msg, ...)
 {
     va_list ap;
+    char message[1024];
     va_start(ap, msg);
-    fprintf(stderr, "parse error: ");
-    vfprintf(stderr, msg, ap);
-    fprintf(stderr, "\n");
+    vsnprintf(message, sizeof(message), msg, ap);
     va_end(ap);
+    if (ctxt->err) {
+        error_free(ctxt->err);
+        ctxt->err = NULL;
+    }
+    error_set(&ctxt->err, QERR_JSON_PARSE_ERROR, message);
 }
 
 /**
@@ -269,10 +275,15 @@ out:
  */
 static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
 {
-    QObject *key, *token = NULL, *value, *peek;
+    QObject *key = NULL, *token = NULL, *value, *peek;
     QList *working = qlist_copy(*tokens);
 
     peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
     key = parse_value(ctxt, &working, ap);
     if (!key || qobject_type(key) != QTYPE_QSTRING) {
         parse_error(ctxt, peek, "key is not a string in object");
@@ -280,6 +291,11 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
     }
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
     if (!token_is_operator(token, ':')) {
         parse_error(ctxt, token, "missing : in object pair");
         goto out;
@@ -315,6 +331,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
     QList *working = qlist_copy(*tokens);
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
     if (!token_is_operator(token, '{')) {
         goto out;
     }
@@ -324,12 +344,22 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
     dict = qdict_new();
 
     peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
     if (!token_is_operator(peek, '}')) {
         if (parse_pair(ctxt, dict, &working, ap) == -1) {
             goto out;
         }
 
         token = qlist_pop(working);
+        if (token == NULL) {
+            parse_error(ctxt, NULL, "premature EOI");
+            goto out;
+        }
+
         while (!token_is_operator(token, '}')) {
             if (!token_is_operator(token, ',')) {
                 parse_error(ctxt, token, "expected separator in dict");
@@ -343,6 +373,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
             }
 
             token = qlist_pop(working);
+            if (token == NULL) {
+                parse_error(ctxt, NULL, "premature EOI");
+                goto out;
+            }
         }
         qobject_decref(token);
         token = NULL;
@@ -371,6 +405,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
     QList *working = qlist_copy(*tokens);
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
     if (!token_is_operator(token, '[')) {
         goto out;
     }
@@ -380,6 +418,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
     list = qlist_new();
 
     peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
     if (!token_is_operator(peek, ']')) {
         QObject *obj;
 
@@ -392,6 +435,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
         qlist_append_obj(list, obj);
 
         token = qlist_pop(working);
+        if (token == NULL) {
+            parse_error(ctxt, NULL, "premature EOI");
+            goto out;
+        }
+
         while (!token_is_operator(token, ']')) {
             if (!token_is_operator(token, ',')) {
                 parse_error(ctxt, token, "expected separator in list");
@@ -410,6 +458,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
             qlist_append_obj(list, obj);
 
             token = qlist_pop(working);
+            if (token == NULL) {
+                parse_error(ctxt, NULL, "premature EOI");
+                goto out;
+            }
         }
 
         qobject_decref(token);
@@ -438,6 +490,9 @@ static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
     QList *working = qlist_copy(*tokens);
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
 
     if (token_get_type(token) != JSON_KEYWORD) {
         goto out;
@@ -475,6 +530,9 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
     }
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
 
     if (token_is_escape(token, "%p")) {
         obj = va_arg(*ap, QObject *);
@@ -514,6 +572,10 @@ static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
     QList *working = qlist_copy(*tokens);
 
     token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
     switch (token_get_type(token)) {
     case JSON_STRING:
         obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
@@ -564,14 +626,25 @@ static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap
 }
 
 QObject *json_parser_parse(QList *tokens, va_list *ap)
+{
+    return json_parser_parse_err(tokens, ap, NULL);
+}
+
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
 {
     JSONParserContext ctxt = {};
-    QList *working = qlist_copy(tokens);
+    QList *working;
     QObject *result;
 
+    if (!tokens) {
+        return NULL;
+    }
+    working = qlist_copy(tokens);
     result = parse_value(&ctxt, &working, ap);
 
     QDECREF(working);
 
+    error_propagate(errp, ctxt.err);
+
     return result;
 }
index 97f43f67d44422829e7ad7d9db09b413395a7648..8f2b5ec4bcb43e4ed012d5621d5c82958b06ec25 100644 (file)
@@ -16,7 +16,9 @@
 
 #include "qemu-common.h"
 #include "qlist.h"
+#include "error.h"
 
 QObject *json_parser_parse(QList *tokens, va_list *ap);
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp);
 
 #endif
index f7e7a68d409f05731a47ef8e338b1f95c1b90682..c255c7818f3af4c6cd9dfca71ee55e8dd63bbb7c 100644 (file)
@@ -18,6 +18,9 @@
 #include "json-lexer.h"
 #include "json-streamer.h"
 
+#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_NESTING (1ULL << 10)
+
 static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
 {
     JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
@@ -49,14 +52,44 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
     qdict_put(dict, "x", qint_from_int(x));
     qdict_put(dict, "y", qint_from_int(y));
 
+    parser->token_size += token->length;
+
     qlist_append(parser->tokens, dict);
 
-    if (parser->brace_count == 0 &&
-        parser->bracket_count == 0) {
-        parser->emit(parser, parser->tokens);
+    if (type == JSON_ERROR) {
+        goto out_emit_bad;
+    } else if (parser->brace_count < 0 ||
+        parser->bracket_count < 0 ||
+        (parser->brace_count == 0 &&
+         parser->bracket_count == 0)) {
+        goto out_emit;
+    } else if (parser->token_size > MAX_TOKEN_SIZE ||
+               parser->bracket_count > MAX_NESTING ||
+               parser->brace_count > MAX_NESTING) {
+        /* Security consideration, we limit total memory allocated per object
+         * and the maximum recursion depth that a message can force.
+         */
+        goto out_emit;
+    }
+
+    return;
+
+out_emit_bad:
+    /* clear out token list and tell the parser to emit and error
+     * indication by passing it a NULL list
+     */
+    QDECREF(parser->tokens);
+    parser->tokens = NULL;
+out_emit:
+    /* send current list of tokens to parser and reset tokenizer */
+    parser->brace_count = 0;
+    parser->bracket_count = 0;
+    parser->emit(parser, parser->tokens);
+    if (parser->tokens) {
         QDECREF(parser->tokens);
-        parser->tokens = qlist_new();
     }
+    parser->tokens = qlist_new();
+    parser->token_size = 0;
 }
 
 void json_message_parser_init(JSONMessageParser *parser,
@@ -66,6 +99,7 @@ void json_message_parser_init(JSONMessageParser *parser,
     parser->brace_count = 0;
     parser->bracket_count = 0;
     parser->tokens = qlist_new();
+    parser->token_size = 0;
 
     json_lexer_init(&parser->lexer, json_message_process_token);
 }
index 09f3bd70e498c942a2a54e5f50b5f28fc6647285..f09bc4daec98aae800d86820d728e11336672f91 100644 (file)
@@ -24,6 +24,7 @@ typedef struct JSONMessageParser
     int brace_count;
     int bracket_count;
     QList *tokens;
+    uint64_t token_size;
 } JSONMessageParser;
 
 void json_message_parser_init(JSONMessageParser *parser,
index 91518313b7f511c5a08da51abcc6286f9ab03094..4c466d6aba4cacfe927b5a442e55cc111bdb106e 100644 (file)
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -19,7 +19,6 @@
 #include <stdarg.h>
 
 #include <linux/kvm.h>
-#include <asm/processor-flags.h>
 
 #include "qemu-common.h"
 #include "qemu-barrier.h"
 
 #ifdef DEBUG_KVM
 #define DPRINTF(fmt, ...) \
-       do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
 #else
 #define DPRINTF(fmt, ...) \
-       do { } while (0)
+    do { } while (0)
 #endif
 
-extern void show_message(const char *szTitle, const char *szMessage);
-
 typedef struct KVMSlot
 {
-       target_phys_addr_t start_addr;
-       ram_addr_t memory_size;
-       ram_addr_t phys_offset;
-       int slot;
-       int flags;
+    target_phys_addr_t start_addr;
+    ram_addr_t memory_size;
+    ram_addr_t phys_offset;
+    int slot;
+    int flags;
 } KVMSlot;
 
 typedef struct kvm_dirty_log KVMDirtyLog;
 
 struct KVMState
 {
-       KVMSlot slots[32];
-       int fd;
-       int vmfd;
-       int coalesced_mmio;
-       struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
-       int broken_set_mem_region;
-       int migration_log;
-       int vcpu_events;
-       int robust_singlestep;
-       int debugregs;
+    KVMSlot slots[32];
+    int fd;
+    int vmfd;
+    int coalesced_mmio;
+    struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+    bool coalesced_flush_in_progress;
+    int broken_set_mem_region;
+    int migration_log;
+    int vcpu_events;
+    int robust_singlestep;
+    int debugregs;
 #ifdef KVM_CAP_SET_GUEST_DEBUG
-       struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
+    struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
-       int irqchip_in_kernel;
-       int pit_in_kernel;
-       int xsave, xcrs;
-       int many_ioeventfds;
+    int irqchip_in_kernel;
+    int pit_in_kernel;
+    int xsave, xcrs;
+    int many_ioeventfds;
 };
 
-static KVMState *kvm_state;
+KVMState *kvm_state;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
-       KVM_CAP_INFO(USER_MEMORY),
-       KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
-       KVM_CAP_LAST_INFO
+    KVM_CAP_INFO(USER_MEMORY),
+    KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
+    KVM_CAP_LAST_INFO
 };
 
 static KVMSlot *kvm_alloc_slot(KVMState *s)
 {
-       int i;
+    int i;
 
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               /* KVM private memory slots */
-               if (i >= 8 && i < 12) {
-                       continue;
-               }
-               if (s->slots[i].memory_size == 0) {
-                       return &s->slots[i];
-               }
-       }
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        if (s->slots[i].memory_size == 0) {
+            return &s->slots[i];
+        }
+    }
 
-       fprintf(stderr, "%s: no free slot available\n", __func__);
-       abort();
+    fprintf(stderr, "%s: no free slot available\n", __func__);
+    abort();
 }
 
 static KVMSlot *kvm_lookup_matching_slot(KVMState *s,
-               target_phys_addr_t start_addr,
-               target_phys_addr_t end_addr)
+                                         target_phys_addr_t start_addr,
+                                         target_phys_addr_t end_addr)
 {
-       int i;
+    int i;
 
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               KVMSlot *mem = &s->slots[i];
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
 
-               if (start_addr == mem->start_addr &&
-                               end_addr == mem->start_addr + mem->memory_size) {
-                       return mem;
-               }
-       }
+        if (start_addr == mem->start_addr &&
+            end_addr == mem->start_addr + mem->memory_size) {
+            return mem;
+        }
+    }
 
-       return NULL;
+    return NULL;
 }
 
 /*
  * Find overlapping slot with lowest start address
  */
 static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
-               target_phys_addr_t start_addr,
-               target_phys_addr_t end_addr)
+                                            target_phys_addr_t start_addr,
+                                            target_phys_addr_t end_addr)
 {
-       KVMSlot *found = NULL;
-       int i;
+    KVMSlot *found = NULL;
+    int i;
 
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               KVMSlot *mem = &s->slots[i];
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
 
-               if (mem->memory_size == 0 ||
-                               (found && found->start_addr < mem->start_addr)) {
-                       continue;
-               }
+        if (mem->memory_size == 0 ||
+            (found && found->start_addr < mem->start_addr)) {
+            continue;
+        }
 
-               if (end_addr > mem->start_addr &&
-                               start_addr < mem->start_addr + mem->memory_size) {
-                       found = mem;
-               }
-       }
+        if (end_addr > mem->start_addr &&
+            start_addr < mem->start_addr + mem->memory_size) {
+            found = mem;
+        }
+    }
 
-       return found;
+    return found;
 }
 
 int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
-               target_phys_addr_t *phys_addr)
+                                      target_phys_addr_t *phys_addr)
 {
-       int i;
+    int i;
 
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               KVMSlot *mem = &s->slots[i];
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
 
-               if (ram_addr >= mem->phys_offset &&
-                               ram_addr < mem->phys_offset + mem->memory_size) {
-                       *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
-                       return 1;
-               }
-       }
+        if (ram_addr >= mem->phys_offset &&
+            ram_addr < mem->phys_offset + mem->memory_size) {
+            *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
+            return 1;
+        }
+    }
 
-       return 0;
+    return 0;
 }
 
 static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
 {
-       struct kvm_userspace_memory_region mem;
-
-       mem.slot = slot->slot;
-       mem.guest_phys_addr = slot->start_addr;
-       mem.memory_size = slot->memory_size;
-       mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset);
-       mem.flags = slot->flags;
-       if (s->migration_log) {
-               mem.flags |= KVM_MEM_LOG_DIRTY_PAGES;
-       }
-       return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+    struct kvm_userspace_memory_region mem;
+
+    mem.slot = slot->slot;
+    mem.guest_phys_addr = slot->start_addr;
+    mem.memory_size = slot->memory_size;
+    mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset);
+    mem.flags = slot->flags;
+    if (s->migration_log) {
+        mem.flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+    return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
 }
 
 static void kvm_reset_vcpu(void *opaque)
 {
-       CPUState *env = opaque;
+    CPUState *env = opaque;
 
-       kvm_arch_reset_vcpu(env);
+    kvm_arch_reset_vcpu(env);
 }
 
 int kvm_irqchip_in_kernel(void)
 {
-       return kvm_state->irqchip_in_kernel;
+    return kvm_state->irqchip_in_kernel;
 }
 
 int kvm_pit_in_kernel(void)
 {
-       return kvm_state->pit_in_kernel;
+    return kvm_state->pit_in_kernel;
 }
 
 int kvm_init_vcpu(CPUState *env)
 {
-       KVMState *s = kvm_state;
-       long mmap_size;
-       int ret;
-
-       DPRINTF("kvm_init_vcpu\n");
-
-       ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index);
-       if (ret < 0) {
-               DPRINTF("kvm_create_vcpu failed\n");
-               goto err;
-       }
-
-       env->kvm_fd = ret;
-       env->kvm_state = s;
-
-       mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
-       if (mmap_size < 0) {
-               DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
-               goto err;
-       }
-
-       env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
-                       env->kvm_fd, 0);
-       if (env->kvm_run == MAP_FAILED) {
-               ret = -errno;
-               DPRINTF("mmap'ing vcpu state failed\n");
-               goto err;
-       }
-
-       if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
-               s->coalesced_mmio_ring =
-                       (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
-       }
-
-       ret = kvm_arch_init_vcpu(env);
-       if (ret == 0) {
-               qemu_register_reset(kvm_reset_vcpu, env);
-               kvm_arch_reset_vcpu(env);
-       }
+    KVMState *s = kvm_state;
+    long mmap_size;
+    int ret;
+
+    DPRINTF("kvm_init_vcpu\n");
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index);
+    if (ret < 0) {
+        DPRINTF("kvm_create_vcpu failed\n");
+        goto err;
+    }
+
+    env->kvm_fd = ret;
+    env->kvm_state = s;
+    env->kvm_vcpu_dirty = 1;
+
+    mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
+    if (mmap_size < 0) {
+        ret = mmap_size;
+        DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
+        goto err;
+    }
+
+    env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        env->kvm_fd, 0);
+    if (env->kvm_run == MAP_FAILED) {
+        ret = -errno;
+        DPRINTF("mmap'ing vcpu state failed\n");
+        goto err;
+    }
+
+    if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
+        s->coalesced_mmio_ring =
+            (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
+    }
+
+    ret = kvm_arch_init_vcpu(env);
+    if (ret == 0) {
+        qemu_register_reset(kvm_reset_vcpu, env);
+        kvm_arch_reset_vcpu(env);
+    }
 err:
-       return ret;
+    return ret;
 }
 
 /*
  * dirty pages logging control
  */
-static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
-               ram_addr_t size, int flags, int mask)
+
+static int kvm_mem_flags(KVMState *s, bool log_dirty)
 {
-       KVMState *s = kvm_state;
-       KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
-       int old_flags;
+    return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0;
+}
+
+static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    int flags, mask = KVM_MEM_LOG_DIRTY_PAGES;
+    int old_flags;
+
+    old_flags = mem->flags;
 
-       if (mem == NULL)  {
-               fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
-                               TARGET_FMT_plx "\n", __func__, phys_addr,
-                               (target_phys_addr_t)(phys_addr + size - 1));
-               return -EINVAL;
-       }
+    flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty);
+    mem->flags = flags;
 
-       old_flags = mem->flags;
+    /* If nothing changed effectively, no need to issue ioctl */
+    if (s->migration_log) {
+        flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
 
-       flags = (mem->flags & ~mask) | flags;
-       mem->flags = flags;
+    if (flags == old_flags) {
+        return 0;
+    }
 
-       /* If nothing changed effectively, no need to issue ioctl */
-       if (s->migration_log) {
-               flags |= KVM_MEM_LOG_DIRTY_PAGES;
-       }
-       if (flags == old_flags) {
-               return 0;
-       }
+    return kvm_set_user_memory_region(s, mem);
+}
 
-       return kvm_set_user_memory_region(s, mem);
+static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
+                                      ram_addr_t size, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
+
+    if (mem == NULL)  {
+        fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
+                TARGET_FMT_plx "\n", __func__, phys_addr,
+                (target_phys_addr_t)(phys_addr + size - 1));
+        return -EINVAL;
+    }
+    return kvm_slot_dirty_pages_log_change(mem, log_dirty);
 }
 
-int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size)
+static int kvm_log_start(CPUPhysMemoryClient *client,
+                         target_phys_addr_t phys_addr, ram_addr_t size)
 {
-       return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES,
-                       KVM_MEM_LOG_DIRTY_PAGES);
+    return kvm_dirty_pages_log_change(phys_addr, size, true);
 }
 
-int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
+static int kvm_log_stop(CPUPhysMemoryClient *client,
+                        target_phys_addr_t phys_addr, ram_addr_t size)
 {
-       return kvm_dirty_pages_log_change(phys_addr, size, 0,
-                       KVM_MEM_LOG_DIRTY_PAGES);
+    return kvm_dirty_pages_log_change(phys_addr, size, false);
 }
 
 static int kvm_set_migration_log(int enable)
 {
-       KVMState *s = kvm_state;
-       KVMSlot *mem;
-       int i, err;
-
-       s->migration_log = enable;
-
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               mem = &s->slots[i];
-
-               if (!mem->memory_size) {
-                       continue;
-               }
-               if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) {
-                       continue;
-               }
-               err = kvm_set_user_memory_region(s, mem);
-               if (err) {
-                       return err;
-               }
-       }
-       return 0;
+    KVMState *s = kvm_state;
+    KVMSlot *mem;
+    int i, err;
+
+    s->migration_log = enable;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        mem = &s->slots[i];
+
+        if (!mem->memory_size) {
+            continue;
+        }
+        if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) {
+            continue;
+        }
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
 }
 
 /* get kvm's dirty pages bitmap and update qemu's */
 static int kvm_get_dirty_pages_log_range(unsigned long start_addr,
-               unsigned long *bitmap,
-               unsigned long offset,
-               unsigned long mem_size)
-{
-       unsigned int i, j;
-       unsigned long page_number, addr, addr1, c;
-       ram_addr_t ram_addr;
-       unsigned int len = ((mem_size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) /
-               HOST_LONG_BITS;
-
-       /*
-        * bitmap-traveling is faster than memory-traveling (for addr...)
-        * especially when most of the memory is not dirty.
-        */
-       for (i = 0; i < len; i++) {
-               if (bitmap[i] != 0) {
-                       c = leul_to_cpu(bitmap[i]);
-                       do {
-                               j = ffsl(c) - 1;
-                               c &= ~(1ul << j);
-                               page_number = i * HOST_LONG_BITS + j;
-                               addr1 = page_number * TARGET_PAGE_SIZE;
-                               addr = offset + addr1;
-                               ram_addr = cpu_get_physical_page_desc(addr);
-                               cpu_physical_memory_set_dirty(ram_addr);
-                       } while (c != 0);
-               }
-       }
-       return 0;
+                                         unsigned long *bitmap,
+                                         unsigned long offset,
+                                         unsigned long mem_size)
+{
+    unsigned int i, j;
+    unsigned long page_number, addr, addr1, c;
+    ram_addr_t ram_addr;
+    unsigned int len = ((mem_size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) /
+        HOST_LONG_BITS;
+
+    /*
+     * bitmap-traveling is faster than memory-traveling (for addr...)
+     * especially when most of the memory is not dirty.
+     */
+    for (i = 0; i < len; i++) {
+        if (bitmap[i] != 0) {
+            c = leul_to_cpu(bitmap[i]);
+            do {
+                j = ffsl(c) - 1;
+                c &= ~(1ul << j);
+                page_number = i * HOST_LONG_BITS + j;
+                addr1 = page_number * TARGET_PAGE_SIZE;
+                addr = offset + addr1;
+                ram_addr = cpu_get_physical_page_desc(addr);
+                cpu_physical_memory_set_dirty(ram_addr);
+            } while (c != 0);
+        }
+    }
+    return 0;
 }
 
 #define ALIGN(x, y)  (((x)+(y)-1) & ~((y)-1))
@@ -361,943 +371,946 @@ static int kvm_get_dirty_pages_log_range(unsigned long start_addr,
  * @end_addr: end of logged region.
  */
 static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
-               target_phys_addr_t end_addr)
-{
-       KVMState *s = kvm_state;
-       unsigned long size, allocated_size = 0;
-       KVMDirtyLog d;
-       KVMSlot *mem;
-       int ret = 0;
-
-       d.dirty_bitmap = NULL;
-       while (start_addr < end_addr) {
-               mem = kvm_lookup_overlapping_slot(s, start_addr, end_addr);
-               if (mem == NULL) {
-                       break;
-               }
-
-               size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), HOST_LONG_BITS) / 8;
-               if (!d.dirty_bitmap) {
-                       d.dirty_bitmap = qemu_malloc(size);
-               } else if (size > allocated_size) {
-                       d.dirty_bitmap = qemu_realloc(d.dirty_bitmap, size);
-               }
-               allocated_size = size;
-               memset(d.dirty_bitmap, 0, allocated_size);
-
-               d.slot = mem->slot;
-
-               if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
-                       DPRINTF("ioctl failed %d\n", errno);
-                       ret = -1;
-                       break;
-               }
-
-               kvm_get_dirty_pages_log_range(mem->start_addr, d.dirty_bitmap,
-                               mem->start_addr, mem->memory_size);
-               start_addr = mem->start_addr + mem->memory_size;
-       }
-       qemu_free(d.dirty_bitmap);
-
-       return ret;
+                                          target_phys_addr_t end_addr)
+{
+    KVMState *s = kvm_state;
+    unsigned long size, allocated_size = 0;
+    KVMDirtyLog d;
+    KVMSlot *mem;
+    int ret = 0;
+
+    d.dirty_bitmap = NULL;
+    while (start_addr < end_addr) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, end_addr);
+        if (mem == NULL) {
+            break;
+        }
+
+        /* 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 = g_malloc(size);
+        } else if (size > allocated_size) {
+            d.dirty_bitmap = g_realloc(d.dirty_bitmap, size);
+        }
+        allocated_size = size;
+        memset(d.dirty_bitmap, 0, allocated_size);
+
+        d.slot = mem->slot;
+
+        if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
+            DPRINTF("ioctl failed %d\n", errno);
+            ret = -1;
+            break;
+        }
+
+        kvm_get_dirty_pages_log_range(mem->start_addr, d.dirty_bitmap,
+                                      mem->start_addr, mem->memory_size);
+        start_addr = mem->start_addr + mem->memory_size;
+    }
+    g_free(d.dirty_bitmap);
+
+    return ret;
 }
 
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
 {
-       int ret = -ENOSYS;
-       KVMState *s = kvm_state;
+    int ret = -ENOSYS;
+    KVMState *s = kvm_state;
 
-       if (s->coalesced_mmio) {
-               struct kvm_coalesced_mmio_zone zone;
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
 
-               zone.addr = start;
-               zone.size = size;
+        zone.addr = start;
+        zone.size = size;
 
-               ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
-       }
+        ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
+    }
 
-       return ret;
+    return ret;
 }
 
 int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
 {
-       int ret = -ENOSYS;
-       KVMState *s = kvm_state;
+    int ret = -ENOSYS;
+    KVMState *s = kvm_state;
 
-       if (s->coalesced_mmio) {
-               struct kvm_coalesced_mmio_zone zone;
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
 
-               zone.addr = start;
-               zone.size = size;
+        zone.addr = start;
+        zone.size = size;
 
-               ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
-       }
+        ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+    }
 
-       return ret;
+    return ret;
 }
 
 int kvm_check_extension(KVMState *s, unsigned int extension)
 {
-       int ret;
+    int ret;
 
-       ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
-       if (ret < 0) {
-               ret = 0;
-       }
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
+    if (ret < 0) {
+        ret = 0;
+    }
 
-       return ret;
+    return ret;
 }
 
 static int kvm_check_many_ioeventfds(void)
 {
-       /* Userspace can use ioeventfd for io notification.  This requires a host
-        * that supports eventfd(2) and an I/O thread; since eventfd does not
-        * support SIGIO it cannot interrupt the vcpu.
-        *
-        * Older kernels have a 6 device limit on the KVM io bus.  Find out so we
-        * can avoid creating too many ioeventfds.
-        */
-#if defined(CONFIG_EVENTFD) && defined(CONFIG_IOTHREAD)
-       int ioeventfds[7];
-       int i, ret = 0;
-       for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
-               ioeventfds[i] = eventfd(0, EFD_CLOEXEC);
-               if (ioeventfds[i] < 0) {
-                       break;
-               }
-               ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true);
-               if (ret < 0) {
-                       close(ioeventfds[i]);
-                       break;
-               }
-       }
-
-       /* Decide whether many devices are supported or not */
-       ret = i == ARRAY_SIZE(ioeventfds);
-
-       while (i-- > 0) {
-               kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false);
-               close(ioeventfds[i]);
-       }
-       return ret;
+    /* Userspace can use ioeventfd for io notification.  This requires a host
+     * that supports eventfd(2) and an I/O thread; since eventfd does not
+     * support SIGIO it cannot interrupt the vcpu.
+     *
+     * Older kernels have a 6 device limit on the KVM io bus.  Find out so we
+     * can avoid creating too many ioeventfds.
+     */
+#if defined(CONFIG_EVENTFD)
+    int ioeventfds[7];
+    int i, ret = 0;
+    for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
+        ioeventfds[i] = eventfd(0, EFD_CLOEXEC);
+        if (ioeventfds[i] < 0) {
+            break;
+        }
+        ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true);
+        if (ret < 0) {
+            close(ioeventfds[i]);
+            break;
+        }
+    }
+
+    /* Decide whether many devices are supported or not */
+    ret = i == ARRAY_SIZE(ioeventfds);
+
+    while (i-- > 0) {
+        kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false);
+        close(ioeventfds[i]);
+    }
+    return ret;
 #else
-       return 0;
+    return 0;
 #endif
 }
 
-       static const KVMCapabilityInfo *
+static const KVMCapabilityInfo *
 kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
 {
-       while (list->name) {
-               if (!kvm_check_extension(s, list->value)) {
-                       return list;
-               }
-               list++;
-       }
-       return NULL;
+    while (list->name) {
+        if (!kvm_check_extension(s, list->value)) {
+            return list;
+        }
+        list++;
+    }
+    return NULL;
 }
 
 static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
-               ram_addr_t phys_offset)
-{
-       KVMState *s = kvm_state;
-       ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
-       KVMSlot *mem, old;
-       int err;
-
-       /* kvm works in page size chunks, but the function may be called
-          with sub-page size and unaligned start address. */
-       size = TARGET_PAGE_ALIGN(size);
-       start_addr = TARGET_PAGE_ALIGN(start_addr);
-
-       /* KVM does not support read-only slots */
-       phys_offset &= ~IO_MEM_ROM;
-
-       while (1) {
-               mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
-               if (!mem) {
-                       break;
-               }
-
-               if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
-                               (start_addr + size <= mem->start_addr + mem->memory_size) &&
-                               (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
-                       /* The new slot fits into the existing one and comes with
-                        * identical parameters - nothing to be done. */
-                       return;
-               }
-
-               old = *mem;
-
-               /* unregister the overlapping slot */
-               mem->memory_size = 0;
-               err = kvm_set_user_memory_region(s, mem);
-               if (err) {
-                       fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
-                                       __func__, strerror(-err));
-                       abort();
-               }
-
-               /* Workaround for older KVM versions: we can't join slots, even not by
-                * unregistering the previous ones and then registering the larger
-                * slot. We have to maintain the existing fragmentation. Sigh.
-                *
-                * This workaround assumes that the new slot starts at the same
-                * address as the first existing one. If not or if some overlapping
-                * slot comes around later, we will fail (not seen in practice so far)
-                * - and actually require a recent KVM version. */
-               if (s->broken_set_mem_region &&
-                               old.start_addr == start_addr && old.memory_size < size &&
-                               flags < IO_MEM_UNASSIGNED) {
-                       mem = kvm_alloc_slot(s);
-                       mem->memory_size = old.memory_size;
-                       mem->start_addr = old.start_addr;
-                       mem->phys_offset = old.phys_offset;
-                       mem->flags = 0;
-
-                       err = kvm_set_user_memory_region(s, mem);
-                       if (err) {
-                               fprintf(stderr, "%s: error updating slot: %s\n", __func__,
-                                               strerror(-err));
-                               abort();
-                       }
-
-                       start_addr += old.memory_size;
-                       phys_offset += old.memory_size;
-                       size -= old.memory_size;
-                       continue;
-               }
-
-               /* register prefix slot */
-               if (old.start_addr < start_addr) {
-                       mem = kvm_alloc_slot(s);
-                       mem->memory_size = start_addr - old.start_addr;
-                       mem->start_addr = old.start_addr;
-                       mem->phys_offset = old.phys_offset;
-                       mem->flags = 0;
-
-                       err = kvm_set_user_memory_region(s, mem);
-                       if (err) {
-                               fprintf(stderr, "%s: error registering prefix slot: %s\n",
-                                               __func__, strerror(-err));
-                               abort();
-                       }
-               }
-
-               /* register suffix slot */
-               if (old.start_addr + old.memory_size > start_addr + size) {
-                       ram_addr_t size_delta;
-
-                       mem = kvm_alloc_slot(s);
-                       mem->start_addr = start_addr + size;
-                       size_delta = mem->start_addr - old.start_addr;
-                       mem->memory_size = old.memory_size - size_delta;
-                       mem->phys_offset = old.phys_offset + size_delta;
-                       mem->flags = 0;
-
-                       err = kvm_set_user_memory_region(s, mem);
-                       if (err) {
-                               fprintf(stderr, "%s: error registering suffix slot: %s\n",
-                                               __func__, strerror(-err));
-                               abort();
-                       }
-               }
-       }
-
-       /* in case the KVM bug workaround already "consumed" the new slot */
-       if (!size) {
-               return;
-       }
-       /* KVM does not need to know about this memory */
-       if (flags >= IO_MEM_UNASSIGNED) {
-               return;
-       }
-       mem = kvm_alloc_slot(s);
-       mem->memory_size = size;
-       mem->start_addr = start_addr;
-       mem->phys_offset = phys_offset;
-       mem->flags = 0;
-
-       err = kvm_set_user_memory_region(s, mem);
-       if (err) {
-               fprintf(stderr, "%s: error registering slot: %s\n", __func__,
-                               strerror(-err));
-               abort();
-       }
+                             ram_addr_t phys_offset, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    KVMSlot *mem, old;
+    int err;
+
+    /* kvm works in page size chunks, but the function may be called
+       with sub-page size and unaligned start address. */
+    size = TARGET_PAGE_ALIGN(size);
+    start_addr = TARGET_PAGE_ALIGN(start_addr);
+
+    /* KVM does not support read-only slots */
+    phys_offset &= ~IO_MEM_ROM;
+
+    while (1) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
+        if (!mem) {
+            break;
+        }
+
+        if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
+            (start_addr + size <= mem->start_addr + mem->memory_size) &&
+            (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
+            /* The new slot fits into the existing one and comes with
+             * identical parameters - update flags and done. */
+            kvm_slot_dirty_pages_log_change(mem, log_dirty);
+            return;
+        }
+
+        old = *mem;
+
+        /* unregister the overlapping slot */
+        mem->memory_size = 0;
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
+                    __func__, strerror(-err));
+            abort();
+        }
+
+        /* Workaround for older KVM versions: we can't join slots, even not by
+         * unregistering the previous ones and then registering the larger
+         * slot. We have to maintain the existing fragmentation. Sigh.
+         *
+         * This workaround assumes that the new slot starts at the same
+         * address as the first existing one. If not or if some overlapping
+         * slot comes around later, we will fail (not seen in practice so far)
+         * - and actually require a recent KVM version. */
+        if (s->broken_set_mem_region &&
+            old.start_addr == start_addr && old.memory_size < size &&
+            flags < IO_MEM_UNASSIGNED) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = old.memory_size;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags = kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error updating slot: %s\n", __func__,
+                        strerror(-err));
+                abort();
+            }
+
+            start_addr += old.memory_size;
+            phys_offset += old.memory_size;
+            size -= old.memory_size;
+            continue;
+        }
+
+        /* register prefix slot */
+        if (old.start_addr < start_addr) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = start_addr - old.start_addr;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags =  kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering prefix slot: %s\n",
+                        __func__, strerror(-err));
+#ifdef TARGET_PPC
+                fprintf(stderr, "%s: This is probably because your kernel's " \
+                                "PAGE_SIZE is too big. Please try to use 4k " \
+                                "PAGE_SIZE!\n", __func__);
+#endif
+                abort();
+            }
+        }
+
+        /* register suffix slot */
+        if (old.start_addr + old.memory_size > start_addr + size) {
+            ram_addr_t size_delta;
+
+            mem = kvm_alloc_slot(s);
+            mem->start_addr = start_addr + size;
+            size_delta = mem->start_addr - old.start_addr;
+            mem->memory_size = old.memory_size - size_delta;
+            mem->phys_offset = old.phys_offset + size_delta;
+            mem->flags = kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering suffix slot: %s\n",
+                        __func__, strerror(-err));
+                abort();
+            }
+        }
+    }
+
+    /* in case the KVM bug workaround already "consumed" the new slot */
+    if (!size) {
+        return;
+    }
+    /* KVM does not need to know about this memory */
+    if (flags >= IO_MEM_UNASSIGNED) {
+        return;
+    }
+    mem = kvm_alloc_slot(s);
+    mem->memory_size = size;
+    mem->start_addr = start_addr;
+    mem->phys_offset = phys_offset;
+    mem->flags = kvm_mem_flags(s, log_dirty);
+
+    err = kvm_set_user_memory_region(s, mem);
+    if (err) {
+        fprintf(stderr, "%s: error registering slot: %s\n", __func__,
+                strerror(-err));
+        abort();
+    }
 }
 
 static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
-               target_phys_addr_t start_addr,
-               ram_addr_t size, ram_addr_t phys_offset)
+                                  target_phys_addr_t start_addr,
+                                  ram_addr_t size, ram_addr_t phys_offset,
+                                  bool log_dirty)
 {
-       kvm_set_phys_mem(start_addr, size, phys_offset);
+    kvm_set_phys_mem(start_addr, size, phys_offset, log_dirty);
 }
 
 static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
-               target_phys_addr_t start_addr,
-               target_phys_addr_t end_addr)
+                                        target_phys_addr_t start_addr,
+                                        target_phys_addr_t end_addr)
 {
-       return kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
+    return kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
 }
 
 static int kvm_client_migration_log(struct CPUPhysMemoryClient *client,
-               int enable)
+                                    int enable)
 {
-       return kvm_set_migration_log(enable);
+    return kvm_set_migration_log(enable);
 }
 
 static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
-       .set_memory = kvm_client_set_memory,
-       .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap,
-       .migration_log = kvm_client_migration_log,
+    .set_memory = kvm_client_set_memory,
+    .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap,
+    .migration_log = kvm_client_migration_log,
+    .log_start = kvm_log_start,
+    .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[] =
-               "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
-               "(see http://sourceforge.net/projects/kvm).\n";
-       KVMState *s;
-       const KVMCapabilityInfo *missing_cap;
-       int ret;
-       int i;
+    static const char upgrade_note[] =
+        "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
+        "(see http://sourceforge.net/projects/kvm).\n";
+    KVMState *s;
+    const KVMCapabilityInfo *missing_cap;
+    int ret;
+    int i;
 
-       s = qemu_mallocz(sizeof(KVMState));
+    s = g_malloc0(sizeof(KVMState));
 
 #ifdef KVM_CAP_SET_GUEST_DEBUG
-       QTAILQ_INIT(&s->kvm_sw_breakpoints);
+    QTAILQ_INIT(&s->kvm_sw_breakpoints);
 #endif
-       for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
-               s->slots[i].slot = i;
-       }
-       s->vmfd = -1;
-       s->fd = qemu_open("/dev/kvm", O_RDWR);
-       if (s->fd == -1) {
-               fprintf(stderr, "Could not access KVM kernel module: %m\n");
-
-               show_message("Error", "Could not access KVM kernel module: Permission denied\n"
-                               "You can add the login user to the KVM group by following command \n"
-                               " - $sudo addgroup `whoami` kvm");
-               exit(0);
-
-               ret = -errno;
-               goto err;
-       }
-
-       ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
-       if (ret < KVM_API_VERSION) {
-               if (ret > 0) {
-                       ret = -EINVAL;
-               }
-               fprintf(stderr, "kvm version too old\n");
-               show_message("Error", "KVM version too old \n");
-               goto err;
-       }
-
-       if (ret > KVM_API_VERSION) {
-               ret = -EINVAL;
-               fprintf(stderr, "kvm version not supported\n");
-               show_message("Error", "KVM version not supported \n");
-               goto err;
-       }
-
-       s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
-       if (s->vmfd < 0) {
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        s->slots[i].slot = i;
+    }
+    s->vmfd = -1;
+    s->fd = qemu_open("/dev/kvm", O_RDWR);
+    if (s->fd == -1) {
+        fprintf(stderr, "Could not access KVM kernel module: %m\n");
+        ret = -errno;
+        goto err;
+    }
+
+    ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
+    if (ret < KVM_API_VERSION) {
+        if (ret > 0) {
+            ret = -EINVAL;
+        }
+        fprintf(stderr, "kvm version too old\n");
+        goto err;
+    }
+
+    if (ret > KVM_API_VERSION) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm version not supported\n");
+        goto err;
+    }
+
+    s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
+    if (s->vmfd < 0) {
 #ifdef TARGET_S390X
-               fprintf(stderr, "Please add the 'switch_amode' kernel parameter to "
-                               "your host kernel command line\n");
-#endif
-               goto err;
-       }
-
-       missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
-       if (!missing_cap) {
-               missing_cap =
-                       kvm_check_extension_list(s, kvm_arch_required_capabilities);
-       }
-       if (missing_cap) {
-               ret = -EINVAL;
-               fprintf(stderr, "kvm does not support %s\n%s",
-                               missing_cap->name, upgrade_note);
-               goto err;
-       }
-
-       s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
-
-       s->broken_set_mem_region = 1;
-#ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS
-       ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
-       if (ret > 0) {
-               s->broken_set_mem_region = 0;
-       }
+        fprintf(stderr, "Please add the 'switch_amode' kernel parameter to "
+                        "your host kernel command line\n");
 #endif
+        ret = s->vmfd;
+        goto err;
+    }
+
+    missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
+    if (!missing_cap) {
+        missing_cap =
+            kvm_check_extension_list(s, kvm_arch_required_capabilities);
+    }
+    if (missing_cap) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm does not support %s\n%s",
+                missing_cap->name, upgrade_note);
+        goto err;
+    }
+
+    s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
+
+    s->broken_set_mem_region = 1;
+    ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
+    if (ret > 0) {
+        s->broken_set_mem_region = 0;
+    }
 
-       s->vcpu_events = 0;
 #ifdef KVM_CAP_VCPU_EVENTS
-       s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
+    s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
 #endif
 
-       s->robust_singlestep = 0;
-#ifdef KVM_CAP_X86_ROBUST_SINGLESTEP
-       s->robust_singlestep =
-               kvm_check_extension(s, KVM_CAP_X86_ROBUST_SINGLESTEP);
-#endif
+    s->robust_singlestep =
+        kvm_check_extension(s, KVM_CAP_X86_ROBUST_SINGLESTEP);
 
-       s->debugregs = 0;
 #ifdef KVM_CAP_DEBUGREGS
-       s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS);
+    s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS);
 #endif
 
-       s->xsave = 0;
 #ifdef KVM_CAP_XSAVE
-       s->xsave = kvm_check_extension(s, KVM_CAP_XSAVE);
+    s->xsave = kvm_check_extension(s, KVM_CAP_XSAVE);
 #endif
 
-       s->xcrs = 0;
 #ifdef KVM_CAP_XCRS
-       s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
+    s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
 #endif
 
-       ret = kvm_arch_init(s);
-       if (ret < 0) {
-               goto err;
-       }
+    ret = kvm_arch_init(s);
+    if (ret < 0) {
+        goto err;
+    }
+
+    kvm_state = s;
+    cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
 
-       kvm_state = s;
-       cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
+    s->many_ioeventfds = kvm_check_many_ioeventfds();
 
-       s->many_ioeventfds = kvm_check_many_ioeventfds();
+    cpu_interrupt_handler = kvm_handle_interrupt;
 
-       return 0;
+    return 0;
 
 err:
-       if (s) {
-               if (s->vmfd != -1) {
-                       close(s->vmfd);
-               }
-               if (s->fd != -1) {
-                       close(s->fd);
-               }
-       }
-       qemu_free(s);
-
-       return ret;
+    if (s) {
+        if (s->vmfd >= 0) {
+            close(s->vmfd);
+        }
+        if (s->fd != -1) {
+            close(s->fd);
+        }
+    }
+    g_free(s);
+
+    return ret;
 }
 
-static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
-               uint32_t count)
-{
-       int i;
-       uint8_t *ptr = data;
-
-       for (i = 0; i < count; i++) {
-               if (direction == KVM_EXIT_IO_IN) {
-                       switch (size) {
-                               case 1:
-                                       stb_p(ptr, cpu_inb(port));
-                                       break;
-                               case 2:
-                                       stw_p(ptr, cpu_inw(port));
-                                       break;
-                               case 4:
-                                       stl_p(ptr, cpu_inl(port));
-                                       break;
-                       }
-               } else {
-                       switch (size) {
-                               case 1:
-                                       cpu_outb(port, ldub_p(ptr));
-                                       break;
-                               case 2:
-                                       cpu_outw(port, lduw_p(ptr));
-                                       break;
-                               case 4:
-                                       cpu_outl(port, ldl_p(ptr));
-                                       break;
-                       }
-               }
-
-               ptr += size;
-       }
-
-       return 1;
+static void kvm_handle_io(uint16_t port, void *data, int direction, int size,
+                          uint32_t count)
+{
+    int i;
+    uint8_t *ptr = data;
+
+    for (i = 0; i < count; i++) {
+        if (direction == KVM_EXIT_IO_IN) {
+            switch (size) {
+            case 1:
+                stb_p(ptr, cpu_inb(port));
+                break;
+            case 2:
+                stw_p(ptr, cpu_inw(port));
+                break;
+            case 4:
+                stl_p(ptr, cpu_inl(port));
+                break;
+            }
+        } else {
+            switch (size) {
+            case 1:
+                cpu_outb(port, ldub_p(ptr));
+                break;
+            case 2:
+                cpu_outw(port, lduw_p(ptr));
+                break;
+            case 4:
+                cpu_outl(port, ldl_p(ptr));
+                break;
+            }
+        }
+
+        ptr += size;
+    }
 }
 
-#ifdef KVM_CAP_INTERNAL_ERROR_DATA
 static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
 {
-       fprintf(stderr, "KVM internal error.");
-       if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
-               int i;
-
-               fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
-               for (i = 0; i < run->internal.ndata; ++i) {
-                       fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
-                                       i, (uint64_t)run->internal.data[i]);
-               }
-       } else {
-               fprintf(stderr, "\n");
-       }
-       if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
-               fprintf(stderr, "emulation failure\n");
-               if (!kvm_arch_stop_on_emulation_error(env)) {
-                       cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
-                       return 0;
-               }
-       }
-       /* FIXME: Should trigger a qmp message to let management know
-        * something went wrong.
-        */
-       return -1;
+    fprintf(stderr, "KVM internal error.");
+    if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
+        int i;
+
+        fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
+        for (i = 0; i < run->internal.ndata; ++i) {
+            fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
+                    i, (uint64_t)run->internal.data[i]);
+        }
+    } else {
+        fprintf(stderr, "\n");
+    }
+    if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
+        fprintf(stderr, "emulation failure\n");
+        if (!kvm_arch_stop_on_emulation_error(env)) {
+            cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
+            return EXCP_INTERRUPT;
+        }
+    }
+    /* FIXME: Should trigger a qmp message to let management know
+     * something went wrong.
+     */
+    return -1;
 }
-#endif
 
 void kvm_flush_coalesced_mmio_buffer(void)
 {
-       KVMState *s = kvm_state;
-       if (s->coalesced_mmio_ring) {
-               struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
-               while (ring->first != ring->last) {
-                       struct kvm_coalesced_mmio *ent;
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_flush_in_progress) {
+        return;
+    }
+
+    s->coalesced_flush_in_progress = true;
+
+    if (s->coalesced_mmio_ring) {
+        struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
+        while (ring->first != ring->last) {
+            struct kvm_coalesced_mmio *ent;
+
+            ent = &ring->coalesced_mmio[ring->first];
 
-                       ent = &ring->coalesced_mmio[ring->first];
+            cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
+            smp_wmb();
+            ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+        }
+    }
 
-                       cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
-                       smp_wmb();
-                       ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
-               }
-       }
+    s->coalesced_flush_in_progress = false;
 }
 
 static void do_kvm_cpu_synchronize_state(void *_env)
 {
-       CPUState *env = _env;
+    CPUState *env = _env;
 
-       if (!env->kvm_vcpu_dirty) {
-               kvm_arch_get_registers(env);
-               env->kvm_vcpu_dirty = 1;
-       }
+    if (!env->kvm_vcpu_dirty) {
+        kvm_arch_get_registers(env);
+        env->kvm_vcpu_dirty = 1;
+    }
 }
 
 void kvm_cpu_synchronize_state(CPUState *env)
 {
-       if (!env->kvm_vcpu_dirty) {
-               run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
-       }
+    if (!env->kvm_vcpu_dirty) {
+        run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
+    }
 }
 
 void kvm_cpu_synchronize_post_reset(CPUState *env)
 {
-       kvm_arch_put_registers(env, KVM_PUT_RESET_STATE);
-       env->kvm_vcpu_dirty = 0;
+    kvm_arch_put_registers(env, KVM_PUT_RESET_STATE);
+    env->kvm_vcpu_dirty = 0;
 }
 
 void kvm_cpu_synchronize_post_init(CPUState *env)
 {
-       kvm_arch_put_registers(env, KVM_PUT_FULL_STATE);
-       env->kvm_vcpu_dirty = 0;
+    kvm_arch_put_registers(env, KVM_PUT_FULL_STATE);
+    env->kvm_vcpu_dirty = 0;
 }
 
 int kvm_cpu_exec(CPUState *env)
 {
-       struct kvm_run *run = env->kvm_run;
-       int ret;
-
-       DPRINTF("kvm_cpu_exec()\n");
-
-       do {
-#ifndef CONFIG_IOTHREAD
-               if (env->exit_request) {
-                       DPRINTF("interrupt exit requested\n");
-                       ret = 0;
-                       break;
-               }
-#endif
-
-               if (kvm_arch_process_irqchip_events(env)) {
-                       ret = 0;
-                       break;
-               }
-
-               if (env->kvm_vcpu_dirty) {
-                       kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
-                       env->kvm_vcpu_dirty = 0;
-               }
-
-               kvm_arch_pre_run(env, run);
-               cpu_single_env = NULL;
-               qemu_mutex_unlock_iothread();
-               ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
-               qemu_mutex_lock_iothread();
-               cpu_single_env = env;
-               kvm_arch_post_run(env, run);
-
-               kvm_flush_coalesced_mmio_buffer();
-
-               if (ret == -EINTR || ret == -EAGAIN) {
-                       cpu_exit(env);
-                       DPRINTF("io window exit\n");
-                       ret = 0;
-                       break;
-               }
-
-               if (ret < 0) {
-                       DPRINTF("kvm run failed %s\n", strerror(-ret));
-                       abort();
-               }
-
-               ret = 0; /* exit loop */
-               switch (run->exit_reason) {
-                       case KVM_EXIT_IO:
-                               DPRINTF("handle_io\n");
-                               ret = kvm_handle_io(run->io.port,
-                                               (uint8_t *)run + run->io.data_offset,
-                                               run->io.direction,
-                                               run->io.size,
-                                               run->io.count);
-                               break;
-                       case KVM_EXIT_MMIO:
-                               DPRINTF("handle_mmio\n");
-                               cpu_physical_memory_rw(run->mmio.phys_addr,
-                                               run->mmio.data,
-                                               run->mmio.len,
-                                               run->mmio.is_write);
-                               ret = 1;
-                               break;
-                       case KVM_EXIT_IRQ_WINDOW_OPEN:
-                               DPRINTF("irq_window_open\n");
-                               break;
-                       case KVM_EXIT_SHUTDOWN:
-                               DPRINTF("shutdown\n");
-                               qemu_system_reset_request();
-                               ret = 1;
-                               break;
-                       case KVM_EXIT_UNKNOWN:
-                               fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
-                                               (uint64_t)run->hw.hardware_exit_reason);
-                               ret = -1;
-                               break;
-#ifdef KVM_CAP_INTERNAL_ERROR_DATA
-                       case KVM_EXIT_INTERNAL_ERROR:
-                               ret = kvm_handle_internal_error(env, run);
-                               break;
-#endif
-                       case KVM_EXIT_DEBUG:
-                               DPRINTF("kvm_exit_debug\n");
-#ifdef KVM_CAP_SET_GUEST_DEBUG
-                               if (kvm_arch_debug(&run->debug.arch)) {
-                                       env->exception_index = EXCP_DEBUG;
-                                       return 0;
-                               }
-                               /* re-enter, this exception was guest-internal */
-                               ret = 1;
-#endif /* KVM_CAP_SET_GUEST_DEBUG */
-                               break;
-                       default:
-                               DPRINTF("kvm_arch_handle_exit\n");
-                               ret = kvm_arch_handle_exit(env, run);
-                               break;
-               }
-       } while (ret > 0);
-
-       if (ret < 0) {
-
-               show_message("Error", "Emulator can't operate in VMX root mode(KVM) \n"
-                               "Please disable the VT-x kernel extension(Ex: Virtualbox)");
-
-               cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
-               vm_stop(0);
-
-               exit(0);
-
-               env->exit_request = 1;
-       }
-       if (env->exit_request) {
-               env->exit_request = 0;
-               env->exception_index = EXCP_INTERRUPT;
-       }
-
-       return ret;
+    struct kvm_run *run = env->kvm_run;
+    int ret, run_ret;
+
+    DPRINTF("kvm_cpu_exec()\n");
+
+    if (kvm_arch_process_async_events(env)) {
+        env->exit_request = 0;
+        return EXCP_HLT;
+    }
+
+    cpu_single_env = env;
+
+    do {
+        if (env->kvm_vcpu_dirty) {
+            kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
+            env->kvm_vcpu_dirty = 0;
+        }
+
+        kvm_arch_pre_run(env, run);
+        if (env->exit_request) {
+            DPRINTF("interrupt exit requested\n");
+            /*
+             * KVM requires us to reenter the kernel after IO exits to complete
+             * instruction emulation. This self-signal will ensure that we
+             * leave ASAP again.
+             */
+            qemu_cpu_kick_self();
+        }
+        cpu_single_env = NULL;
+        qemu_mutex_unlock_iothread();
+
+        run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
+
+        qemu_mutex_lock_iothread();
+        cpu_single_env = env;
+        kvm_arch_post_run(env, run);
+
+        kvm_flush_coalesced_mmio_buffer();
+
+        if (run_ret < 0) {
+            if (run_ret == -EINTR || run_ret == -EAGAIN) {
+                DPRINTF("io window exit\n");
+                ret = EXCP_INTERRUPT;
+                break;
+            }
+            DPRINTF("kvm run failed %s\n", strerror(-run_ret));
+            abort();
+        }
+
+        switch (run->exit_reason) {
+        case KVM_EXIT_IO:
+            DPRINTF("handle_io\n");
+            kvm_handle_io(run->io.port,
+                          (uint8_t *)run + run->io.data_offset,
+                          run->io.direction,
+                          run->io.size,
+                          run->io.count);
+            ret = 0;
+            break;
+        case KVM_EXIT_MMIO:
+            DPRINTF("handle_mmio\n");
+            cpu_physical_memory_rw(run->mmio.phys_addr,
+                                   run->mmio.data,
+                                   run->mmio.len,
+                                   run->mmio.is_write);
+            ret = 0;
+            break;
+        case KVM_EXIT_IRQ_WINDOW_OPEN:
+            DPRINTF("irq_window_open\n");
+            ret = EXCP_INTERRUPT;
+            break;
+        case KVM_EXIT_SHUTDOWN:
+            DPRINTF("shutdown\n");
+            qemu_system_reset_request();
+            ret = EXCP_INTERRUPT;
+            break;
+        case KVM_EXIT_UNKNOWN:
+            fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
+                    (uint64_t)run->hw.hardware_exit_reason);
+            ret = -1;
+            break;
+        case KVM_EXIT_INTERNAL_ERROR:
+            ret = kvm_handle_internal_error(env, run);
+            break;
+        default:
+            DPRINTF("kvm_arch_handle_exit\n");
+            ret = kvm_arch_handle_exit(env, run);
+            break;
+        }
+    } while (ret == 0);
+
+    if (ret < 0) {
+        cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
+        vm_stop(RUN_STATE_INTERNAL_ERROR);
+    }
+
+    env->exit_request = 0;
+    cpu_single_env = NULL;
+    return ret;
 }
 
 int kvm_ioctl(KVMState *s, int type, ...)
 {
-       int ret;
-       void *arg;
-       va_list ap;
-
-       va_start(ap, type);
-       arg = va_arg(ap, void *);
-       va_end(ap);
-
-       ret = ioctl(s->fd, type, arg);
-       if (ret == -1) {
-               ret = -errno;
-       }
-       return ret;
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->fd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
 }
 
 int kvm_vm_ioctl(KVMState *s, int type, ...)
 {
-       int ret;
-       void *arg;
-       va_list ap;
-
-       va_start(ap, type);
-       arg = va_arg(ap, void *);
-       va_end(ap);
-
-       ret = ioctl(s->vmfd, type, arg);
-       if (ret == -1) {
-               ret = -errno;
-       }
-       return ret;
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->vmfd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
 }
 
 int kvm_vcpu_ioctl(CPUState *env, int type, ...)
 {
-       int ret;
-       void *arg;
-       va_list ap;
-
-       va_start(ap, type);
-       arg = va_arg(ap, void *);
-       va_end(ap);
-
-       ret = ioctl(env->kvm_fd, type, arg);
-       if (ret == -1) {
-               ret = -errno;
-       }
-       return ret;
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(env->kvm_fd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
 }
 
 int kvm_has_sync_mmu(void)
 {
-       return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
+    return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
 }
 
 int kvm_has_vcpu_events(void)
 {
-       return kvm_state->vcpu_events;
+    return kvm_state->vcpu_events;
 }
 
 int kvm_has_robust_singlestep(void)
 {
-       return kvm_state->robust_singlestep;
+    return kvm_state->robust_singlestep;
 }
 
 int kvm_has_debugregs(void)
 {
-       return kvm_state->debugregs;
+    return kvm_state->debugregs;
 }
 
 int kvm_has_xsave(void)
 {
-       return kvm_state->xsave;
+    return kvm_state->xsave;
 }
 
 int kvm_has_xcrs(void)
 {
-       return kvm_state->xcrs;
+    return kvm_state->xcrs;
 }
 
 int kvm_has_many_ioeventfds(void)
 {
-       if (!kvm_enabled()) {
-               return 0;
-       }
-       return kvm_state->many_ioeventfds;
+    if (!kvm_enabled()) {
+        return 0;
+    }
+    return kvm_state->many_ioeventfds;
 }
 
 void kvm_setup_guest_memory(void *start, size_t size)
 {
-       if (!kvm_has_sync_mmu()) {
-               int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
-
-               if (ret) {
-                       perror("qemu_madvise");
-                       fprintf(stderr,
-                                       "Need MADV_DONTFORK in absence of synchronous KVM MMU\n");
-                       exit(1);
-               }
-       }
+    if (!kvm_has_sync_mmu()) {
+        int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
+
+        if (ret) {
+            perror("qemu_madvise");
+            fprintf(stderr,
+                    "Need MADV_DONTFORK in absence of synchronous KVM MMU\n");
+            exit(1);
+        }
+    }
 }
 
 #ifdef KVM_CAP_SET_GUEST_DEBUG
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
-               target_ulong pc)
+                                                 target_ulong pc)
 {
-       struct kvm_sw_breakpoint *bp;
-
-       QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
-               if (bp->pc == pc) {
-                       return bp;
-               }
-       }
-       return NULL;
+    struct kvm_sw_breakpoint *bp;
+
+    QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
+        if (bp->pc == pc) {
+            return bp;
+        }
+    }
+    return NULL;
 }
 
 int kvm_sw_breakpoints_active(CPUState *env)
 {
-       return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
+    return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
 }
 
 struct kvm_set_guest_debug_data {
-       struct kvm_guest_debug dbg;
-       CPUState *env;
-       int err;
+    struct kvm_guest_debug dbg;
+    CPUState *env;
+    int err;
 };
 
 static void kvm_invoke_set_guest_debug(void *data)
 {
-       struct kvm_set_guest_debug_data *dbg_data = data;
-       CPUState *env = dbg_data->env;
+    struct kvm_set_guest_debug_data *dbg_data = data;
+    CPUState *env = dbg_data->env;
 
-       dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg);
+    dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg);
 }
 
 int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
 {
-       struct kvm_set_guest_debug_data data;
+    struct kvm_set_guest_debug_data data;
 
-       data.dbg.control = reinject_trap;
+    data.dbg.control = reinject_trap;
 
-       if (env->singlestep_enabled) {
-               data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
-       }
-       kvm_arch_update_guest_debug(env, &data.dbg);
-       data.env = env;
+    if (env->singlestep_enabled) {
+        data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+    }
+    kvm_arch_update_guest_debug(env, &data.dbg);
+    data.env = env;
 
-       run_on_cpu(env, kvm_invoke_set_guest_debug, &data);
-       return data.err;
+    run_on_cpu(env, kvm_invoke_set_guest_debug, &data);
+    return data.err;
 }
 
 int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
-               target_ulong len, int type)
-{
-       struct kvm_sw_breakpoint *bp;
-       CPUState *env;
-       int err;
-
-       if (type == GDB_BREAKPOINT_SW) {
-               bp = kvm_find_sw_breakpoint(current_env, addr);
-               if (bp) {
-                       bp->use_count++;
-                       return 0;
-               }
-
-               bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint));
-               if (!bp) {
-                       return -ENOMEM;
-               }
-
-               bp->pc = addr;
-               bp->use_count = 1;
-               err = kvm_arch_insert_sw_breakpoint(current_env, bp);
-               if (err) {
-                       free(bp);
-                       return err;
-               }
-
-               QTAILQ_INSERT_HEAD(&current_env->kvm_state->kvm_sw_breakpoints,
-                               bp, entry);
-       } else {
-               err = kvm_arch_insert_hw_breakpoint(addr, len, type);
-               if (err) {
-                       return err;
-               }
-       }
-
-       for (env = first_cpu; env != NULL; env = env->next_cpu) {
-               err = kvm_update_guest_debug(env, 0);
-               if (err) {
-                       return err;
-               }
-       }
-       return 0;
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (bp) {
+            bp->use_count++;
+            return 0;
+        }
+
+        bp = g_malloc(sizeof(struct kvm_sw_breakpoint));
+        if (!bp) {
+            return -ENOMEM;
+        }
+
+        bp->pc = addr;
+        bp->use_count = 1;
+        err = kvm_arch_insert_sw_breakpoint(current_env, bp);
+        if (err) {
+            g_free(bp);
+            return err;
+        }
+
+        QTAILQ_INSERT_HEAD(&current_env->kvm_state->kvm_sw_breakpoints,
+                          bp, entry);
+    } else {
+        err = kvm_arch_insert_hw_breakpoint(addr, len, type);
+        if (err) {
+            return err;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
 }
 
 int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
-               target_ulong len, int type)
-{
-       struct kvm_sw_breakpoint *bp;
-       CPUState *env;
-       int err;
-
-       if (type == GDB_BREAKPOINT_SW) {
-               bp = kvm_find_sw_breakpoint(current_env, addr);
-               if (!bp) {
-                       return -ENOENT;
-               }
-
-               if (bp->use_count > 1) {
-                       bp->use_count--;
-                       return 0;
-               }
-
-               err = kvm_arch_remove_sw_breakpoint(current_env, bp);
-               if (err) {
-                       return err;
-               }
-
-               QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry);
-               qemu_free(bp);
-       } else {
-               err = kvm_arch_remove_hw_breakpoint(addr, len, type);
-               if (err) {
-                       return err;
-               }
-       }
-
-       for (env = first_cpu; env != NULL; env = env->next_cpu) {
-               err = kvm_update_guest_debug(env, 0);
-               if (err) {
-                       return err;
-               }
-       }
-       return 0;
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (!bp) {
+            return -ENOENT;
+        }
+
+        if (bp->use_count > 1) {
+            bp->use_count--;
+            return 0;
+        }
+
+        err = kvm_arch_remove_sw_breakpoint(current_env, bp);
+        if (err) {
+            return err;
+        }
+
+        QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry);
+        g_free(bp);
+    } else {
+        err = kvm_arch_remove_hw_breakpoint(addr, len, type);
+        if (err) {
+            return err;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
 }
 
 void kvm_remove_all_breakpoints(CPUState *current_env)
 {
-       struct kvm_sw_breakpoint *bp, *next;
-       KVMState *s = current_env->kvm_state;
-       CPUState *env;
-
-       QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
-               if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
-                       /* Try harder to find a CPU that currently sees the breakpoint. */
-                       for (env = first_cpu; env != NULL; env = env->next_cpu) {
-                               if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) {
-                                       break;
-                               }
-                       }
-               }
-       }
-       kvm_arch_remove_all_hw_breakpoints();
-
-       for (env = first_cpu; env != NULL; env = env->next_cpu) {
-               kvm_update_guest_debug(env, 0);
-       }
+    struct kvm_sw_breakpoint *bp, *next;
+    KVMState *s = current_env->kvm_state;
+    CPUState *env;
+
+    QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
+        if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
+            /* Try harder to find a CPU that currently sees the breakpoint. */
+            for (env = first_cpu; env != NULL; env = env->next_cpu) {
+                if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) {
+                    break;
+                }
+            }
+        }
+    }
+    kvm_arch_remove_all_hw_breakpoints();
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        kvm_update_guest_debug(env, 0);
+    }
 }
 
 #else /* !KVM_CAP_SET_GUEST_DEBUG */
 
 int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
 {
-       return -EINVAL;
+    return -EINVAL;
 }
 
 int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
-               target_ulong len, int type)
+                          target_ulong len, int type)
 {
-       return -EINVAL;
+    return -EINVAL;
 }
 
 int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
-               target_ulong len, int type)
+                          target_ulong len, int type)
 {
-       return -EINVAL;
+    return -EINVAL;
 }
 
 void kvm_remove_all_breakpoints(CPUState *current_env)
@@ -1307,78 +1320,80 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
 
 int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
 {
-       struct kvm_signal_mask *sigmask;
-       int r;
+    struct kvm_signal_mask *sigmask;
+    int r;
 
-       if (!sigset) {
-               return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
-       }
+    if (!sigset) {
+        return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
+    }
 
-       sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
+    sigmask = g_malloc(sizeof(*sigmask) + sizeof(*sigset));
 
-       sigmask->len = 8;
-       memcpy(sigmask->sigset, sigset, sizeof(*sigset));
-       r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
-       free(sigmask);
+    sigmask->len = 8;
+    memcpy(sigmask->sigset, sigset, sizeof(*sigset));
+    r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
+    g_free(sigmask);
 
-       return r;
+    return r;
 }
 
 int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign)
 {
-#ifdef KVM_IOEVENTFD
-       int ret;
-       struct kvm_ioeventfd iofd;
+    int ret;
+    struct kvm_ioeventfd iofd;
 
-       iofd.datamatch = val;
-       iofd.addr = addr;
-       iofd.len = 4;
-       iofd.flags = KVM_IOEVENTFD_FLAG_DATAMATCH;
-       iofd.fd = fd;
+    iofd.datamatch = val;
+    iofd.addr = addr;
+    iofd.len = 4;
+    iofd.flags = KVM_IOEVENTFD_FLAG_DATAMATCH;
+    iofd.fd = fd;
 
-       if (!kvm_enabled()) {
-               return -ENOSYS;
-       }
+    if (!kvm_enabled()) {
+        return -ENOSYS;
+    }
 
-       if (!assign) {
-               iofd.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
-       }
+    if (!assign) {
+        iofd.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+    }
 
-       ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd);
+    ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd);
 
-       if (ret < 0) {
-               return -errno;
-       }
+    if (ret < 0) {
+        return -errno;
+    }
 
-       return 0;
-#else
-       return -ENOSYS;
-#endif
+    return 0;
 }
 
 int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
 {
-#ifdef KVM_IOEVENTFD
-       struct kvm_ioeventfd kick = {
-               .datamatch = val,
-               .addr = addr,
-               .len = 2,
-               .flags = KVM_IOEVENTFD_FLAG_DATAMATCH | KVM_IOEVENTFD_FLAG_PIO,
-               .fd = fd,
-       };
-       int r;
-       if (!kvm_enabled()) {
-               return -ENOSYS;
-       }
-       if (!assign) {
-               kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
-       }
-       r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
-       if (r < 0) {
-               return r;
-       }
-       return 0;
-#else
-       return -ENOSYS;
-#endif
+    struct kvm_ioeventfd kick = {
+        .datamatch = val,
+        .addr = addr,
+        .len = 2,
+        .flags = KVM_IOEVENTFD_FLAG_DATAMATCH | KVM_IOEVENTFD_FLAG_PIO,
+        .fd = fd,
+    };
+    int r;
+    if (!kvm_enabled()) {
+        return -ENOSYS;
+    }
+    if (!assign) {
+        kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+    }
+    r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
+    if (r < 0) {
+        return r;
+    }
+    return 0;
+}
+
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return kvm_arch_on_sigbus_vcpu(env, code, addr);
+}
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return kvm_arch_on_sigbus(code, addr);
 }
index 88682f288bfe14003b62681c5c48bf2f704e5afe..06064b9a8694aa8e035774b952bfc8d3cc5408fb 100644 (file)
@@ -11,9 +11,8 @@
  */
 
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "hw/hw.h"
-#include "exec-all.h"
+#include "cpu.h"
 #include "gdbstub.h"
 #include "kvm.h"
 
@@ -33,16 +32,6 @@ int kvm_init_vcpu(CPUState *env)
     return -ENOSYS;
 }
 
-int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size)
-{
-    return -ENOSYS;
-}
-
-int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
-{
-    return -ENOSYS;
-}
-
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
 {
     return -ENOSYS;
@@ -53,11 +42,6 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
     return -ENOSYS;
 }
 
-int kvm_check_extension(KVMState *s, unsigned int extension)
-{
-    return 0;
-}
-
 int kvm_init(void)
 {
     return -ENOSYS;
@@ -89,16 +73,6 @@ int kvm_has_sync_mmu(void)
     return 0;
 }
 
-int kvm_has_vcpu_events(void)
-{
-    return 0;
-}
-
-int kvm_has_robust_singlestep(void)
-{
-    return 0;
-}
-
 int kvm_has_many_ioeventfds(void)
 {
     return 0;
@@ -110,8 +84,7 @@ void kvm_setup_guest_memory(void *start, size_t size)
 
 int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
 {
-    tb_flush(env);
-    return 0;
+    return -ENOSYS;
 }
 
 int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
@@ -147,6 +120,11 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
     return -ENOSYS;
 }
 
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
 int kvm_on_sigbus(int code, void *addr)
 {
     return 1;
diff --git a/kvm.h b/kvm.h
index ca57517af2feae87ced55d59ace491fb166451d3..e764682a209596f6dc1734ef7c19ecd072b902de 100644 (file)
--- a/kvm.h
+++ b/kvm.h
@@ -58,9 +58,6 @@ int kvm_init_vcpu(CPUState *env);
 int kvm_cpu_exec(CPUState *env);
 
 #if !defined(CONFIG_USER_ONLY)
-int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size);
-int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
-
 void kvm_setup_guest_memory(void *start, size_t size);
 
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
@@ -81,10 +78,14 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
 int kvm_pit_in_kernel(void);
 int kvm_irqchip_in_kernel(void);
 
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_on_sigbus(int code, void *addr);
+
 /* internal API */
 
 struct KVMState;
 typedef struct KVMState KVMState;
+extern KVMState *kvm_state;
 
 int kvm_ioctl(KVMState *s, int type, ...);
 
@@ -96,13 +97,12 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...);
 
 extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
-int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run);
 
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
 
-int kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
-
-int kvm_arch_process_irqchip_events(CPUState *env);
+int kvm_arch_process_async_events(CPUState *env);
 
 int kvm_arch_get_registers(CPUState *env);
 
@@ -121,8 +121,8 @@ int kvm_arch_init_vcpu(CPUState *env);
 
 void kvm_arch_reset_vcpu(CPUState *env);
 
-int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
-int kvm_on_sigbus(int code, void *addr);
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_arch_on_sigbus(int code, void *addr);
 
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
@@ -136,8 +136,6 @@ struct kvm_sw_breakpoint {
 
 QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
 
-int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info);
-
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
                                                  target_ulong pc);
 
@@ -159,19 +157,26 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env);
 
 int kvm_check_extension(KVMState *s, unsigned int extension);
 
-uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
                                       uint32_t index, int reg);
 void kvm_cpu_synchronize_state(CPUState *env);
 void kvm_cpu_synchronize_post_reset(CPUState *env);
 void kvm_cpu_synchronize_post_init(CPUState *env);
 
 /* generic hooks - to be moved/refactored once there are more users */
-
+#ifdef CONFIG_HAX
+void hax_cpu_synchronize_state(CPUState *env);
+void hax_cpu_synchronize_post_reset(CPUState *env);
+void hax_cpu_synchronize_post_init(CPUState *env);
+#endif
 static inline void cpu_synchronize_state(CPUState *env)
 {
     if (kvm_enabled()) {
         kvm_cpu_synchronize_state(env);
     }
+#ifdef CONFIG_HAX
+       hax_cpu_synchronize_state(env);
+#endif
 }
 
 static inline void cpu_synchronize_post_reset(CPUState *env)
@@ -179,6 +184,9 @@ static inline void cpu_synchronize_post_reset(CPUState *env)
     if (kvm_enabled()) {
         kvm_cpu_synchronize_post_reset(env);
     }
+#ifdef CONFIG_HAX
+       hax_cpu_synchronize_post_reset(env);
+#endif
 }
 
 static inline void cpu_synchronize_post_init(CPUState *env)
@@ -186,6 +194,9 @@ static inline void cpu_synchronize_post_init(CPUState *env)
     if (kvm_enabled()) {
         kvm_cpu_synchronize_post_init(env);
     }
+#ifdef CONFIG_HAX
+        hax_cpu_synchronize_post_init(env);
+#endif
 }
 
 
diff --git a/libcacard/Makefile b/libcacard/Makefile
new file mode 100644 (file)
index 0000000..a145569
--- /dev/null
@@ -0,0 +1,66 @@
+-include ../config-host.mak
+-include $(SRC_PATH)/Makefile.objs
+-include $(SRC_PATH)/rules.mak
+
+libcacard_srcpath=$(SRC_PATH)/libcacard
+libcacard_includedir=$(includedir)/cacard
+
+$(call set-vpath, $(SRC_PATH):$(libcacard_srcpath))
+
+# objects linked against normal qemu binaries, not compiled with libtool
+QEMU_OBJS=$(addprefix ../,$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y))
+
+# objects linked into a shared library, built with libtool with -fPIC if required
+QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS)))
+
+QEMU_CFLAGS+=-I../
+
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
+libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
+
+vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
+       $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
+
+clean:
+       rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la *.pc
+       rm -Rf .libs
+
+all: vscclient
+# Dummy command so that make thinks it has done something
+       @true
+
+#########################################################################
+# Rules for building libcacard standalone library
+
+ifeq ($(LIBTOOL),)
+libcacard.la:
+       @echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+       @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB)
+       $(call quiet-command,$(LIBTOOL) --mode=link --quiet --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs),"  lt LINK $@")
+
+libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in
+       sed -e 's|@LIBDIR@|$(libdir)|' \
+               -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \
+           -e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \
+               -e 's|@PREFIX@|$(prefix)|' \
+               < $(libcacard_srcpath)/libcacard.pc.in > libcacard.pc
+
+.PHONY: install-libcacard
+
+install-libcacard: libcacard.pc libcacard.la vscclient
+       $(INSTALL_DIR) "$(DESTDIR)$(libdir)"
+       $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig"
+       $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)"
+       $(INSTALL_DIR) "$(DESTDIR)$(bindir)"
+       $(LIBTOOL) --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)"
+       $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.la "$(DESTDIR)$(libdir)"
+       $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig"
+       for inc in *.h; do \
+               $(LIBTOOL) --mode=install $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \
+       done
+endif
diff --git a/libcacard/cac.c b/libcacard/cac.c
new file mode 100644 (file)
index 0000000..927a4ca
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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) {
+        g_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) {
+            g_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;
+        }
+        g_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 (applet_private == NULL) {
+        return;
+    }
+    pki_applet_data = &(applet_private->u.pki_data);
+    if (pki_applet_data->cert != NULL) {
+        g_free(pki_applet_data->cert);
+    }
+    if (pki_applet_data->sign_buffer != NULL) {
+        g_free(pki_applet_data->sign_buffer);
+    }
+    if (pki_applet_data->key != NULL) {
+        vcard_emul_delete_key(pki_applet_data->key);
+    }
+    g_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 *)g_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 *)g_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..6fe27d5
--- /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 *)g_malloc(sizeof(VCardResponse));
+    new_response->b_data = g_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 *)g_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 *)g_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) {
+            g_free(response->b_data);
+        }
+        g_free(response);
+        break;
+    case VCARD_MALLOC_DATA:
+        /* only the data buffer was malloc'ed */
+        if (response->b_data) {
+            g_free(response->b_data);
+        }
+        break;
+    case VCARD_MALLOC_STRUCT:
+        /* only the structure was malloc'ed */
+        g_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 *)g_malloc(sizeof(VCardAPDU));
+    new_apdu->a_data = g_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) {
+        g_free(new_apdu);
+        return NULL;
+    }
+    *status = vcard_apdu_set_length(new_apdu);
+    if (*status != VCARD7816_STATUS_SUCCESS) {
+        g_free(new_apdu);
+        new_apdu = NULL;
+    }
+    return new_apdu;
+}
+
+void
+vcard_apdu_delete(VCardAPDU *apdu)
+{
+    if (apdu == NULL) {
+        return;
+    }
+    if (apdu->a_data) {
+        g_free(apdu->a_data);
+    }
+    g_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..6192376
--- /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 *)g_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);
+    g_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/libcacard.pc.in b/libcacard/libcacard.pc.in
new file mode 100644 (file)
index 0000000..b6859b0
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@PREFIX@
+exec_prefix=${prefix}
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: cacard
+Description: CA Card library
+Version: @VERSION@
+
+Requires:  nss
+Libs: -L${libdir} -lcacard
+Libs.private:
+Cflags: -I${includedir}
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..b02556e
--- /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 *)g_malloc(sizeof(VCardBufferResponse));
+    new_buffer->buffer = (unsigned char *)g_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) {
+        g_free(buffer_response->buffer);
+    }
+    g_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 *)g_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 = g_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) {
+        g_free(applet->aid);
+        applet->aid = NULL;
+    }
+    g_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 *)g_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);
+    g_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..397485c
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * 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"
+
+typedef enum {
+    VCardEmulUnknown = -1,
+    VCardEmulFalse = 0,
+    VCardEmulTrue = 1
+} VCardEmulTriState;
+
+struct VCardKeyStruct {
+    CERTCertificate *cert;
+    PK11SlotInfo *slot;
+    SECKEYPrivateKey *key;
+    VCardEmulTriState failedX509;
+};
+
+
+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 **)g_malloc(sizeof(unsigned char *)*cert_count);
+    *cert_lenp = (int *)g_malloc(sizeof(int)*cert_count);
+    *keysp = (VCardKey **)g_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 *)g_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);
+    key->failedX509 = VCardEmulUnknown;
+    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;
+    PK11SlotInfo *slot;
+    SECStatus rv;
+    unsigned char buf[2048];
+    unsigned char *bp = NULL;
+    int pad_len;
+    vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS;
+
+    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);
+    if (priv_key == NULL) {
+        /* couldn't get the key, indicate that we aren't logged in */
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    }
+    slot = vcard_emul_card_get_slot(card);
+
+    /*
+     * 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;
+    }
+    /* be able to handle larger keys if necessariy */
+    bp = &buf[0];
+    if (sizeof(buf) < signature_len) {
+        bp = g_malloc(signature_len);
+    }
+
+    /*
+     * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then
+     * choke when they try to do the actual operations. Try to detect
+     * those cases and treat them as if the token didn't claim support for
+     * X_509.
+     */
+    if (key->failedX509 != VCardEmulTrue
+                              && PK11_DoesMechanism(slot, CKM_RSA_X_509)) {
+        rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len,
+                                 buffer, buffer_size);
+        if (rv == SECSuccess) {
+            assert(buffer_size == signature_len);
+            memcpy(buffer, bp, signature_len);
+            key->failedX509 = VCardEmulFalse;
+            goto cleanup;
+        }
+        /*
+         * we've had a successful X509 operation, this failure must be
+         * somethine else
+         */
+        if (key->failedX509 == VCardEmulFalse) {
+            ret = vcard_emul_map_error(PORT_GetError());
+            goto cleanup;
+        }
+        /*
+         * key->failedX509 must be Unknown at this point, try the
+         * non-x_509 case
+         */
+    }
+    /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */
+    /* is this a PKCS #1 formatted signature? */
+    if ((buffer[0] == 0) && (buffer[1] == 1)) {
+        int i;
+
+        for (i = 2; i < buffer_size; i++) {
+            /* rsa signature pad */
+            if (buffer[i] != 0xff) {
+                break;
+            }
+        }
+        if ((i < buffer_size) && (buffer[i] == 0)) {
+            /* yes, we have a properly formated PKCS #1 signature */
+            /*
+             * NOTE: even if we accidentally got an encrypt buffer, which
+             * through shear luck started with 00, 01, ff, 00, it won't matter
+             * because the resulting Sign operation will effectively decrypt
+             * the real buffer.
+             */
+            SECItem signature;
+            SECItem hash;
+
+            i++;
+            hash.data = &buffer[i];
+            hash.len = buffer_size - i;
+            signature.data = bp;
+            signature.len = signature_len;
+            rv = PK11_Sign(priv_key,  &signature, &hash);
+            if (rv != SECSuccess) {
+                ret = vcard_emul_map_error(PORT_GetError());
+                goto cleanup;
+            }
+            assert(buffer_size == signature.len);
+            memcpy(buffer, bp, signature.len);
+            /*
+             * we got here because either the X509 attempt failed, or the
+             * token couldn't do the X509 operation, in either case stay
+             * with the PKCS version for future operations on this key
+             */
+            key->failedX509 = VCardEmulTrue;
+            goto cleanup;
+        }
+    }
+    pad_len = buffer_size - signature_len;
+    assert(pad_len < 4);
+    /*
+     * OK now we've decrypted the payload, package it up in PKCS #1 for the
+     * upper layer.
+     */
+    buffer[0] = 0;
+    buffer[1] = 2; /* RSA_encrypt  */
+    pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */
+    /*
+     * padding for PKCS #1 encrypted data is a string of random bytes. The
+     * random butes protect against potential decryption attacks against RSA.
+     * Since PrivDecrypt has already stripped those bytes, we can't reconstruct
+     * them. This shouldn't matter to the upper level code which should just
+     * strip this code out anyway, so We'll pad with a constant 3.
+     */
+    memset(&buffer[2], 0x03, pad_len);
+    pad_len += 2; /* index to the end of the pad */
+    buffer[pad_len] = 0;
+    pad_len++; /* index to the start of the data */
+    memcpy(&buffer[pad_len], bp, signature_len);
+    /*
+     * we got here because either the X509 attempt failed, or the
+     * token couldn't do the X509 operation, in either case stay
+     * with the PKCS version for future operations on this key
+     */
+    key->failedX509 = VCardEmulTrue;
+cleanup:
+    if (bp != buf) {
+        g_free(bp);
+    }
+    return ret;
+}
+
+/*
+ * 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 = g_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 */
+    g_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 *)g_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) {
+        g_free(vreader_emul->type_params);
+    }
+    g_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;
+    VCard *card;
+
+    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 */
+    card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
+    g_free(certs);
+    g_free(cert_len);
+    g_free(keys);
+
+    return card;
+}
+
+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;
+        }
+        g_free(certs);
+        g_free(cert_len);
+        g_free(keys);
+    }
+
+    /* 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 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 consistent look */
+static VCardEmulOptions options;
+#define READER_STEP 4
+
+/* Expects "args" to be at the beginning of a token (ie right after the ','
+ * ending the previous token), and puts the next token start in "token",
+ * and its length in "token_length". "token" will not be nul-terminated.
+ * After calling the macro, "args" will be advanced to the beginning of
+ * the next token.
+ * This macro may call continue or break.
+ */
+#define NEXT_TOKEN(token) \
+            (token) = args; \
+            args = strpbrk(args, ",)"); \
+            if (*args == 0) { \
+                break; \
+            } \
+            if (*args == ')') { \
+                args++; \
+                continue; \
+            } \
+            (token##_length) = args - (token); \
+            args = strip(args+1);
+
+VCardEmulOptions *
+vcard_emul_options(const char *args)
+{
+    int reader_count = 0;
+    VCardEmulOptions *opts;
+
+    /* 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;
+            size_t name_length;
+            const char *vname;
+            size_t vname_length;
+            const char *type_params;
+            size_t type_params_length;
+            char type_str[100];
+            VCardEmulType type;
+            int count, i;
+            VirtualReaderOptions *vreaderOpt = NULL;
+
+            args = strip(args + 5);
+            if (*args != '(') {
+                continue;
+            }
+            args = strip(args+1);
+
+            NEXT_TOKEN(name)
+            NEXT_TOKEN(vname)
+            NEXT_TOKEN(type_params)
+            type_params_length = MIN(type_params_length, sizeof(type_str)-1);
+            strncpy(type_str, type_params, type_params_length);
+            type_str[type_params_length] = 0;
+            type = vcard_emul_type_from_string(type_str);
+
+            NEXT_TOKEN(type_params)
+
+            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 = g_strndup(name, name_length);
+            vreaderOpt->vname = g_strndup(vname, vname_length);
+            vreaderOpt->card_type = type;
+            vreaderOpt->type_params =
+                g_strndup(type_params, type_params_length);
+            count = count_tokens(args, ',', ')') + 1;
+            vreaderOpt->cert_count = count;
+            vreaderOpt->cert_name = (char **)g_malloc(count*sizeof(char *));
+            for (i = 0; i < count; i++) {
+                const char *cert = args;
+                args = strpbrk(args, ",)");
+                vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
+                args = strip(args+1);
+            }
+            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 = g_strndup(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 = g_strndup(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..ec126df
--- /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 *)g_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) {
+        g_free(reader->name);
+    }
+    if (reader->reader_private_free) {
+        reader->reader_private_free(reader->reader_private);
+    }
+    g_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 *)
+                               g_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);
+    g_free(entry);
+}
+
+
+static VReaderList *
+vreader_list_new(void)
+{
+    VReaderList *new_reader_list;
+
+    new_reader_list = (VReaderList *)g_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;
+    g_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..609ae98
--- /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 existence. 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..e317a25
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * 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");
+        return -1;
+    }
+
+    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 -1;
+    }
+
+    if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
+        /* Error */
+        fprintf(stderr, "Could not connect\n");
+        return -1;
+    }
+    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 = g_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);
+    if (sock == -1) {
+        fprintf(stderr, "error opening socket, exiting.\n");
+        exit(5);
+    }
+
+    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 received 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 ee0419f7ce90b21bcb710e835820edd68cde5b32..90d7f3b162ccea53958aa1a6d05049c9f53ac56f 100644 (file)
 #ifndef _LIBFDT_ENV_H
 #define _LIBFDT_ENV_H
 
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-#include <endian.h>
-#include <byteswap.h>
+#include "bswap.h"
 
-#if __BYTE_ORDER == __BIG_ENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
 #define fdt32_to_cpu(x)                (x)
 #define cpu_to_fdt32(x)                (x)
 #define fdt64_to_cpu(x)                (x)
index 68f4b3d7572f93057def5021160f39d0efc5f2cf..1c635ef12d159980dbf889b04c12cfaf498248a9 100644 (file)
@@ -31,7 +31,8 @@ struct qemu_laiocb {
     struct iocb iocb;
     ssize_t ret;
     size_t nbytes;
-    int async_context_id;
+    QEMUIOVector *qiov;
+    bool is_read;
     QLIST_ENTRY(qemu_laiocb) node;
 };
 
@@ -39,7 +40,6 @@ struct qemu_laio_state {
     io_context_t ctx;
     int efd;
     int count;
-    QLIST_HEAD(, qemu_laiocb) completed_reqs;
 };
 
 static inline ssize_t io_event_ret(struct io_event *ev)
@@ -49,7 +49,6 @@ static inline ssize_t io_event_ret(struct io_event *ev)
 
 /*
  * Completes an AIO request (calls the callback and frees the ACB).
- * Be sure to be in the right AsyncContext before calling this function.
  */
 static void qemu_laio_process_completion(struct qemu_laio_state *s,
     struct qemu_laiocb *laiocb)
@@ -60,10 +59,17 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
 
     ret = laiocb->ret;
     if (ret != -ECANCELED) {
-        if (ret == laiocb->nbytes)
+        if (ret == laiocb->nbytes) {
             ret = 0;
-        else if (ret >= 0)
-            ret = -EINVAL;
+        } else if (ret >= 0) {
+            /* Short reads mean EOF, pad with zeros. */
+            if (laiocb->is_read) {
+                qemu_iovec_memset_skip(laiocb->qiov, 0,
+                    laiocb->qiov->size - ret, ret);
+            } else {
+                ret = -EINVAL;
+            }
+        }
 
         laiocb->common.cb(laiocb->common.opaque, ret);
     }
@@ -71,45 +77,6 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
     qemu_aio_release(laiocb);
 }
 
-/*
- * Processes all queued AIO requests, i.e. requests that have return from OS
- * but their callback was not called yet. Requests that cannot have their
- * callback called in the current AsyncContext, remain in the queue.
- *
- * Returns 1 if at least one request could be completed, 0 otherwise.
- */
-static int qemu_laio_process_requests(void *opaque)
-{
-    struct qemu_laio_state *s = opaque;
-    struct qemu_laiocb *laiocb, *next;
-    int res = 0;
-
-    QLIST_FOREACH_SAFE (laiocb, &s->completed_reqs, node, next) {
-        if (laiocb->async_context_id == get_async_context_id()) {
-            qemu_laio_process_completion(s, laiocb);
-            QLIST_REMOVE(laiocb, node);
-            res = 1;
-        }
-    }
-
-    return res;
-}
-
-/*
- * Puts a request in the completion queue so that its callback is called the
- * next time when it's possible. If we already are in the right AsyncContext,
- * the request is completed immediately instead.
- */
-static void qemu_laio_enqueue_completed(struct qemu_laio_state *s,
-    struct qemu_laiocb* laiocb)
-{
-    if (laiocb->async_context_id == get_async_context_id()) {
-        qemu_laio_process_completion(s, laiocb);
-    } else {
-        QLIST_INSERT_HEAD(&s->completed_reqs, laiocb, node);
-    }
-}
-
 static void qemu_laio_completion_cb(void *opaque)
 {
     struct qemu_laio_state *s = opaque;
@@ -141,7 +108,7 @@ static void qemu_laio_completion_cb(void *opaque)
                     container_of(iocb, struct qemu_laiocb, iocb);
 
             laiocb->ret = io_event_ret(&events[i]);
-            qemu_laio_enqueue_completed(s, laiocb);
+            qemu_laio_process_completion(s, laiocb);
         }
     }
 }
@@ -204,7 +171,8 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     laiocb->nbytes = nb_sectors * 512;
     laiocb->ctx = s;
     laiocb->ret = -EINPROGRESS;
-    laiocb->async_context_id = get_async_context_id();
+    laiocb->is_read = (type == QEMU_AIO_READ);
+    laiocb->qiov = qiov;
 
     iocbs = &laiocb->iocb;
 
@@ -215,6 +183,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     case QEMU_AIO_READ:
         io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
        break;
+    /* Currently Linux kernel does not support other operations */
     default:
         fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
                         __func__, type);
@@ -227,10 +196,10 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
         goto out_dec_count;
     return &laiocb->common;
 
-out_free_aiocb:
-    qemu_aio_release(laiocb);
 out_dec_count:
     s->count--;
+out_free_aiocb:
+    qemu_aio_release(laiocb);
     return NULL;
 }
 
@@ -238,8 +207,7 @@ void *laio_init(void)
 {
     struct qemu_laio_state *s;
 
-    s = qemu_mallocz(sizeof(*s));
-    QLIST_INIT(&s->completed_reqs);
+    s = g_malloc0(sizeof(*s));
     s->efd = eventfd(0, 0);
     if (s->efd == -1)
         goto out_free_state;
@@ -249,13 +217,13 @@ void *laio_init(void)
         goto out_close_efd;
 
     qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
-        qemu_laio_flush_cb, qemu_laio_process_requests, s);
+        qemu_laio_flush_cb, NULL, s);
 
     return s;
 
 out_close_efd:
     close(s->efd);
 out_free_state:
-    qemu_free(s);
+    g_free(s);
     return NULL;
 }
diff --git a/linux-headers/COPYING b/linux-headers/COPYING
new file mode 100644 (file)
index 0000000..ca442d3
--- /dev/null
@@ -0,0 +1,356 @@
+
+   NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+                       Linus Torvalds
+
+----------------------------------------
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/linux-headers/README b/linux-headers/README
new file mode 100644 (file)
index 0000000..5c9026b
--- /dev/null
@@ -0,0 +1,2 @@
+Automatically imported Linux kernel headers.
+Only use scripts/update-linux-headers.sh to update!
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
new file mode 100644 (file)
index 0000000..fb3fddc
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __LINUX_KVM_POWERPC_H
+#define __LINUX_KVM_POWERPC_H
+
+#include <linux/types.h>
+
+/* Select powerpc specific features in <linux/kvm.h> */
+#define __KVM_HAVE_SPAPR_TCE
+#define __KVM_HAVE_PPC_SMT
+
+struct kvm_regs {
+       __u64 pc;
+       __u64 cr;
+       __u64 ctr;
+       __u64 lr;
+       __u64 xer;
+       __u64 msr;
+       __u64 srr0;
+       __u64 srr1;
+       __u64 pid;
+
+       __u64 sprg0;
+       __u64 sprg1;
+       __u64 sprg2;
+       __u64 sprg3;
+       __u64 sprg4;
+       __u64 sprg5;
+       __u64 sprg6;
+       __u64 sprg7;
+
+       __u64 gpr[32];
+};
+
+#define KVM_SREGS_E_IMPL_NONE  0
+#define KVM_SREGS_E_IMPL_FSL   1
+
+#define KVM_SREGS_E_FSL_PIDn   (1 << 0) /* PID1/PID2 */
+
+/*
+ * Feature bits indicate which sections of the sregs struct are valid,
+ * both in KVM_GET_SREGS and KVM_SET_SREGS.  On KVM_SET_SREGS, registers
+ * corresponding to unset feature bits will not be modified.  This allows
+ * restoring a checkpoint made without that feature, while keeping the
+ * default values of the new registers.
+ *
+ * KVM_SREGS_E_BASE contains:
+ * CSRR0/1 (refers to SRR2/3 on 40x)
+ * ESR
+ * DEAR
+ * MCSR
+ * TSR
+ * TCR
+ * DEC
+ * TB
+ * VRSAVE (USPRG0)
+ */
+#define KVM_SREGS_E_BASE               (1 << 0)
+
+/*
+ * KVM_SREGS_E_ARCH206 contains:
+ *
+ * PIR
+ * MCSRR0/1
+ * DECAR
+ * IVPR
+ */
+#define KVM_SREGS_E_ARCH206            (1 << 1)
+
+/*
+ * Contains EPCR, plus the upper half of 64-bit registers
+ * that are 32-bit on 32-bit implementations.
+ */
+#define KVM_SREGS_E_64                 (1 << 2)
+
+#define KVM_SREGS_E_SPRG8              (1 << 3)
+#define KVM_SREGS_E_MCIVPR             (1 << 4)
+
+/*
+ * IVORs are used -- contains IVOR0-15, plus additional IVORs
+ * in combination with an appropriate feature bit.
+ */
+#define KVM_SREGS_E_IVOR               (1 << 5)
+
+/*
+ * Contains MAS0-4, MAS6-7, TLBnCFG, MMUCFG.
+ * Also TLBnPS if MMUCFG[MAVN] = 1.
+ */
+#define KVM_SREGS_E_ARCH206_MMU                (1 << 6)
+
+/* DBSR, DBCR, IAC, DAC, DVC */
+#define KVM_SREGS_E_DEBUG              (1 << 7)
+
+/* Enhanced debug -- DSRR0/1, SPRG9 */
+#define KVM_SREGS_E_ED                 (1 << 8)
+
+/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_SPE                        (1 << 9)
+
+/* External Proxy (EXP) -- EPR */
+#define KVM_SREGS_EXP                  (1 << 10)
+
+/* External PID (E.PD) -- EPSC/EPLC */
+#define KVM_SREGS_E_PD                 (1 << 11)
+
+/* Processor Control (E.PC) -- IVOR36-37 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PC                 (1 << 12)
+
+/* Page table (E.PT) -- EPTCFG */
+#define KVM_SREGS_E_PT                 (1 << 13)
+
+/* Embedded Performance Monitor (E.PM) -- IVOR35 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PM                 (1 << 14)
+
+/*
+ * Special updates:
+ *
+ * Some registers may change even while a vcpu is not running.
+ * To avoid losing these changes, by default these registers are
+ * not updated by KVM_SET_SREGS.  To force an update, set the bit
+ * in u.e.update_special corresponding to the register to be updated.
+ *
+ * The update_special field is zero on return from KVM_GET_SREGS.
+ *
+ * When restoring a checkpoint, the caller can set update_special
+ * to 0xffffffff to ensure that everything is restored, even new features
+ * that the caller doesn't know about.
+ */
+#define KVM_SREGS_E_UPDATE_MCSR                (1 << 0)
+#define KVM_SREGS_E_UPDATE_TSR         (1 << 1)
+#define KVM_SREGS_E_UPDATE_DEC         (1 << 2)
+#define KVM_SREGS_E_UPDATE_DBSR                (1 << 3)
+
+/*
+ * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
+ * previous KVM_GET_REGS.
+ *
+ * Unless otherwise indicated, setting any register with KVM_SET_SREGS
+ * directly sets its value.  It does not trigger any special semantics such
+ * as write-one-to-clear.  Calling KVM_SET_SREGS on an unmodified struct
+ * just received from KVM_GET_SREGS is always a no-op.
+ */
+struct kvm_sregs {
+       __u32 pvr;
+       union {
+               struct {
+                       __u64 sdr1;
+                       struct {
+                               struct {
+                                       __u64 slbe;
+                                       __u64 slbv;
+                               } slb[64];
+                       } ppc64;
+                       struct {
+                               __u32 sr[16];
+                               __u64 ibat[8];
+                               __u64 dbat[8];
+                       } ppc32;
+               } s;
+               struct {
+                       union {
+                               struct { /* KVM_SREGS_E_IMPL_FSL */
+                                       __u32 features; /* KVM_SREGS_E_FSL_ */
+                                       __u32 svr;
+                                       __u64 mcar;
+                                       __u32 hid0;
+
+                                       /* KVM_SREGS_E_FSL_PIDn */
+                                       __u32 pid1, pid2;
+                               } fsl;
+                               __u8 pad[256];
+                       } impl;
+
+                       __u32 features; /* KVM_SREGS_E_ */
+                       __u32 impl_id;  /* KVM_SREGS_E_IMPL_ */
+                       __u32 update_special; /* KVM_SREGS_E_UPDATE_ */
+                       __u32 pir;      /* read-only */
+                       __u64 sprg8;
+                       __u64 sprg9;    /* E.ED */
+                       __u64 csrr0;
+                       __u64 dsrr0;    /* E.ED */
+                       __u64 mcsrr0;
+                       __u32 csrr1;
+                       __u32 dsrr1;    /* E.ED */
+                       __u32 mcsrr1;
+                       __u32 esr;
+                       __u64 dear;
+                       __u64 ivpr;
+                       __u64 mcivpr;
+                       __u64 mcsr;     /* KVM_SREGS_E_UPDATE_MCSR */
+
+                       __u32 tsr;      /* KVM_SREGS_E_UPDATE_TSR */
+                       __u32 tcr;
+                       __u32 decar;
+                       __u32 dec;      /* KVM_SREGS_E_UPDATE_DEC */
+
+                       /*
+                        * Userspace can read TB directly, but the
+                        * value reported here is consistent with "dec".
+                        *
+                        * Read-only.
+                        */
+                       __u64 tb;
+
+                       __u32 dbsr;     /* KVM_SREGS_E_UPDATE_DBSR */
+                       __u32 dbcr[3];
+                       __u32 iac[4];
+                       __u32 dac[2];
+                       __u32 dvc[2];
+                       __u8 num_iac;   /* read-only */
+                       __u8 num_dac;   /* read-only */
+                       __u8 num_dvc;   /* read-only */
+                       __u8 pad;
+
+                       __u32 epr;      /* EXP */
+                       __u32 vrsave;   /* a.k.a. USPRG0 */
+                       __u32 epcr;     /* KVM_SREGS_E_64 */
+
+                       __u32 mas0;
+                       __u32 mas1;
+                       __u64 mas2;
+                       __u64 mas7_3;
+                       __u32 mas4;
+                       __u32 mas6;
+
+                       __u32 ivor_low[16]; /* IVOR0-15 */
+                       __u32 ivor_high[18]; /* IVOR32+, plus room to expand */
+
+                       __u32 mmucfg;   /* read-only */
+                       __u32 eptcfg;   /* E.PT, read-only */
+                       __u32 tlbcfg[4];/* read-only */
+                       __u32 tlbps[4]; /* read-only */
+
+                       __u32 eplc, epsc; /* E.PD */
+               } e;
+               __u8 pad[1020];
+       } u;
+};
+
+struct kvm_fpu {
+       __u64 fpr[32];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#define KVM_REG_MASK           0x001f
+#define KVM_REG_EXT_MASK       0xffe0
+#define KVM_REG_GPR            0x0000
+#define KVM_REG_FPR            0x0020
+#define KVM_REG_QPR            0x0040
+#define KVM_REG_FQPR           0x0060
+
+#define KVM_INTERRUPT_SET      -1U
+#define KVM_INTERRUPT_UNSET    -2U
+#define KVM_INTERRUPT_SET_LEVEL        -3U
+
+#define KVM_CPU_440            1
+#define KVM_CPU_E500V2         2
+#define KVM_CPU_3S_32          3
+#define KVM_CPU_3S_64          4
+
+/* for KVM_CAP_SPAPR_TCE */
+struct kvm_create_spapr_tce {
+       __u64 liobn;
+       __u32 window_size;
+};
+
+/* for KVM_ALLOCATE_RMA */
+struct kvm_allocate_rma {
+       __u64 rma_size;
+};
+
+struct kvm_book3e_206_tlb_entry {
+       __u32 mas8;
+       __u32 mas1;
+       __u64 mas2;
+       __u64 mas7_3;
+};
+
+struct kvm_book3e_206_tlb_params {
+       /*
+        * For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+        *
+        * - The number of ways of TLB0 must be a power of two between 2 and
+        *   16.
+        * - TLB1 must be fully associative.
+        * - The size of TLB0 must be a multiple of the number of ways, and
+        *   the number of sets must be a power of two.
+        * - The size of TLB1 may not exceed 64 entries.
+        * - TLB0 supports 4 KiB pages.
+        * - The page sizes supported by TLB1 are as indicated by
+        *   TLB1CFG (if MMUCFG[MAVN] = 0) or TLB1PS (if MMUCFG[MAVN] = 1)
+        *   as returned by KVM_GET_SREGS.
+        * - TLB2 and TLB3 are reserved, and their entries in tlb_sizes[]
+        *   and tlb_ways[] must be zero.
+        *
+        * tlb_ways[n] = tlb_sizes[n] means the array is fully associative.
+        *
+        * KVM will adjust TLBnCFG based on the sizes configured here,
+        * though arrays greater than 2048 entries will have TLBnCFG[NENTRY]
+        * set to zero.
+        */
+       __u32 tlb_sizes[4];
+       __u32 tlb_ways[4];
+       __u32 reserved[8];
+};
+
+#define KVM_ONE_REG_PPC_HIOR   KVM_ONE_REG_PPC | 0x100
+
+#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h
new file mode 100644 (file)
index 0000000..ad58c90
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
+
+#include <linux/types.h>
+
+struct kvm_vcpu_arch_shared {
+       __u64 scratch1;
+       __u64 scratch2;
+       __u64 scratch3;
+       __u64 critical;         /* Guest may not get interrupts if == r1 */
+       __u64 sprg0;
+       __u64 sprg1;
+       __u64 sprg2;
+       __u64 sprg3;
+       __u64 srr0;
+       __u64 srr1;
+       __u64 dar;
+       __u64 msr;
+       __u32 dsisr;
+       __u32 int_pending;      /* Tells the guest if we have an interrupt */
+       __u32 sr[16];
+};
+
+#define KVM_SC_MAGIC_R0                0x4b564d21 /* "KVM!" */
+#define HC_VENDOR_KVM          (42 << 16)
+#define HC_EV_SUCCESS          0
+#define HC_EV_UNIMPLEMENTED    12
+
+#define KVM_FEATURE_MAGIC_PAGE 1
+
+#define KVM_MAGIC_FEAT_SR      (1 << 0)
+
+
+#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
new file mode 100644 (file)
index 0000000..82b32a1
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __LINUX_KVM_S390_H
+#define __LINUX_KVM_S390_H
+/*
+ * asm-s390/kvm.h - KVM s390 specific structures and definitions
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+#include <linux/types.h>
+
+#define __KVM_S390
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+       /* general purpose regs for s390 */
+       __u64 gprs[16];
+};
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+       __u32 acrs[16];
+       __u64 crs[16];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+       __u32 fpc;
+       __u64 fprs[16];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#endif
diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h
new file mode 100644 (file)
index 0000000..8e2dd67
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * asm-s390/kvm_para.h - definition for paravirtual devices on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#ifndef __S390_KVM_PARA_H
+#define __S390_KVM_PARA_H
+
+
+#endif /* __S390_KVM_PARA_H */
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
new file mode 100644 (file)
index 0000000..5df477a
--- /dev/null
@@ -0,0 +1,193 @@
+#ifndef _ASM_X86_HYPERV_H
+#define _ASM_X86_HYPERV_H
+
+#include <linux/types.h>
+
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HvCpuIdFunctionVersionAndFeatures).
+ */
+#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS  0x40000000
+#define HYPERV_CPUID_INTERFACE                 0x40000001
+#define HYPERV_CPUID_VERSION                   0x40000002
+#define HYPERV_CPUID_FEATURES                  0x40000003
+#define HYPERV_CPUID_ENLIGHTMENT_INFO          0x40000004
+#define HYPERV_CPUID_IMPLEMENT_LIMITS          0x40000005
+
+#define HYPERV_HYPERVISOR_PRESENT_BIT          0x80000000
+#define HYPERV_CPUID_MIN                       0x40000005
+#define HYPERV_CPUID_MAX                       0x4000ffff
+
+/*
+ * Feature identification. EAX indicates which features are available
+ * to the partition based upon the current partition privileges.
+ */
+
+/* VP Runtime (HV_X64_MSR_VP_RUNTIME) available */
+#define HV_X64_MSR_VP_RUNTIME_AVAILABLE                (1 << 0)
+/* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/
+#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE    (1 << 1)
+/*
+ * Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
+ * and HV_X64_MSR_SINT0 through HV_X64_MSR_SINT15) available
+ */
+#define HV_X64_MSR_SYNIC_AVAILABLE             (1 << 2)
+/*
+ * Synthetic Timer MSRs (HV_X64_MSR_STIMER0_CONFIG through
+ * HV_X64_MSR_STIMER3_COUNT) available
+ */
+#define HV_X64_MSR_SYNTIMER_AVAILABLE          (1 << 3)
+/*
+ * APIC access MSRs (HV_X64_MSR_EOI, HV_X64_MSR_ICR and HV_X64_MSR_TPR)
+ * are available
+ */
+#define HV_X64_MSR_APIC_ACCESS_AVAILABLE       (1 << 4)
+/* Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL) available*/
+#define HV_X64_MSR_HYPERCALL_AVAILABLE         (1 << 5)
+/* Access virtual processor index MSR (HV_X64_MSR_VP_INDEX) available*/
+#define HV_X64_MSR_VP_INDEX_AVAILABLE          (1 << 6)
+/* Virtual system reset MSR (HV_X64_MSR_RESET) is available*/
+#define HV_X64_MSR_RESET_AVAILABLE             (1 << 7)
+ /*
+  * Access statistics pages MSRs (HV_X64_MSR_STATS_PARTITION_RETAIL_PAGE,
+  * HV_X64_MSR_STATS_PARTITION_INTERNAL_PAGE, HV_X64_MSR_STATS_VP_RETAIL_PAGE,
+  * HV_X64_MSR_STATS_VP_INTERNAL_PAGE) available
+  */
+#define HV_X64_MSR_STAT_PAGES_AVAILABLE                (1 << 8)
+
+/*
+ * Feature identification: EBX indicates which flags were specified at
+ * partition creation. The format is the same as the partition creation
+ * flag structure defined in section Partition Creation Flags.
+ */
+#define HV_X64_CREATE_PARTITIONS               (1 << 0)
+#define HV_X64_ACCESS_PARTITION_ID             (1 << 1)
+#define HV_X64_ACCESS_MEMORY_POOL              (1 << 2)
+#define HV_X64_ADJUST_MESSAGE_BUFFERS          (1 << 3)
+#define HV_X64_POST_MESSAGES                   (1 << 4)
+#define HV_X64_SIGNAL_EVENTS                   (1 << 5)
+#define HV_X64_CREATE_PORT                     (1 << 6)
+#define HV_X64_CONNECT_PORT                    (1 << 7)
+#define HV_X64_ACCESS_STATS                    (1 << 8)
+#define HV_X64_DEBUGGING                       (1 << 11)
+#define HV_X64_CPU_POWER_MANAGEMENT            (1 << 12)
+#define HV_X64_CONFIGURE_PROFILER              (1 << 13)
+
+/*
+ * Feature identification. EDX indicates which miscellaneous features
+ * are available to the partition.
+ */
+/* The MWAIT instruction is available (per section MONITOR / MWAIT) */
+#define HV_X64_MWAIT_AVAILABLE                         (1 << 0)
+/* Guest debugging support is available */
+#define HV_X64_GUEST_DEBUGGING_AVAILABLE               (1 << 1)
+/* Performance Monitor support is available*/
+#define HV_X64_PERF_MONITOR_AVAILABLE                  (1 << 2)
+/* Support for physical CPU dynamic partitioning events is available*/
+#define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE      (1 << 3)
+/*
+ * Support for passing hypercall input parameter block via XMM
+ * registers is available
+ */
+#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          (1 << 4)
+/* Support for a virtual guest idle state is available */
+#define HV_X64_GUEST_IDLE_STATE_AVAILABLE              (1 << 5)
+
+/*
+ * Implementation recommendations. Indicates which behaviors the hypervisor
+ * recommends the OS implement for optimal performance.
+ */
+ /*
+  * Recommend using hypercall for address space switches rather
+  * than MOV to CR3 instruction
+  */
+#define HV_X64_MWAIT_RECOMMENDED               (1 << 0)
+/* Recommend using hypercall for local TLB flushes rather
+ * than INVLPG or MOV to CR3 instructions */
+#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED     (1 << 1)
+/*
+ * Recommend using hypercall for remote TLB flushes rather
+ * than inter-processor interrupts
+ */
+#define HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED    (1 << 2)
+/*
+ * Recommend using MSRs for accessing APIC registers
+ * EOI, ICR and TPR rather than their memory-mapped counterparts
+ */
+#define HV_X64_APIC_ACCESS_RECOMMENDED         (1 << 3)
+/* Recommend using the hypervisor-provided MSR to initiate a system RESET */
+#define HV_X64_SYSTEM_RESET_RECOMMENDED                (1 << 4)
+/*
+ * Recommend using relaxed timing for this partition. If used,
+ * the VM should disable any watchdog timeouts that rely on the
+ * timely delivery of external interrupts
+ */
+#define HV_X64_RELAXED_TIMING_RECOMMENDED      (1 << 5)
+
+/* MSR used to identify the guest OS. */
+#define HV_X64_MSR_GUEST_OS_ID                 0x40000000
+
+/* MSR used to setup pages used to communicate with the hypervisor. */
+#define HV_X64_MSR_HYPERCALL                   0x40000001
+
+/* MSR used to provide vcpu index */
+#define HV_X64_MSR_VP_INDEX                    0x40000002
+
+/* MSR used to read the per-partition time reference counter */
+#define HV_X64_MSR_TIME_REF_COUNT              0x40000020
+
+/* Define the virtual APIC registers */
+#define HV_X64_MSR_EOI                         0x40000070
+#define HV_X64_MSR_ICR                         0x40000071
+#define HV_X64_MSR_TPR                         0x40000072
+#define HV_X64_MSR_APIC_ASSIST_PAGE            0x40000073
+
+/* Define synthetic interrupt controller model specific registers. */
+#define HV_X64_MSR_SCONTROL                    0x40000080
+#define HV_X64_MSR_SVERSION                    0x40000081
+#define HV_X64_MSR_SIEFP                       0x40000082
+#define HV_X64_MSR_SIMP                                0x40000083
+#define HV_X64_MSR_EOM                         0x40000084
+#define HV_X64_MSR_SINT0                       0x40000090
+#define HV_X64_MSR_SINT1                       0x40000091
+#define HV_X64_MSR_SINT2                       0x40000092
+#define HV_X64_MSR_SINT3                       0x40000093
+#define HV_X64_MSR_SINT4                       0x40000094
+#define HV_X64_MSR_SINT5                       0x40000095
+#define HV_X64_MSR_SINT6                       0x40000096
+#define HV_X64_MSR_SINT7                       0x40000097
+#define HV_X64_MSR_SINT8                       0x40000098
+#define HV_X64_MSR_SINT9                       0x40000099
+#define HV_X64_MSR_SINT10                      0x4000009A
+#define HV_X64_MSR_SINT11                      0x4000009B
+#define HV_X64_MSR_SINT12                      0x4000009C
+#define HV_X64_MSR_SINT13                      0x4000009D
+#define HV_X64_MSR_SINT14                      0x4000009E
+#define HV_X64_MSR_SINT15                      0x4000009F
+
+
+#define HV_X64_MSR_HYPERCALL_ENABLE            0x00000001
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT        12
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK \
+               (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1))
+
+/* Declare the various hypercall operations. */
+#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT                0x0008
+
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE             0x00000001
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT      12
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK       \
+               (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1))
+
+#define HV_PROCESSOR_POWER_STATE_C0            0
+#define HV_PROCESSOR_POWER_STATE_C1            1
+#define HV_PROCESSOR_POWER_STATE_C2            2
+#define HV_PROCESSOR_POWER_STATE_C3            3
+
+/* hypercall status code */
+#define HV_STATUS_SUCCESS                      0
+#define HV_STATUS_INVALID_HYPERCALL_CODE       2
+#define HV_STATUS_INVALID_HYPERCALL_INPUT      3
+#define HV_STATUS_INVALID_ALIGNMENT            4
+
+#endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
new file mode 100644 (file)
index 0000000..4d8dcbd
--- /dev/null
@@ -0,0 +1,324 @@
+#ifndef _ASM_X86_KVM_H
+#define _ASM_X86_KVM_H
+
+/*
+ * KVM x86 specific structures and definitions
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_PIT
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+#define __KVM_HAVE_MSI
+#define __KVM_HAVE_USER_NMI
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
+#define __KVM_HAVE_PIT_STATE2
+#define __KVM_HAVE_XEN_HVM
+#define __KVM_HAVE_VCPU_EVENTS
+#define __KVM_HAVE_DEBUGREGS
+#define __KVM_HAVE_XSAVE
+#define __KVM_HAVE_XCRS
+
+/* Architectural interrupt line count. */
+#define KVM_NR_INTERRUPTS 256
+
+struct kvm_memory_alias {
+       __u32 slot;  /* this has a different namespace than memory slots */
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size;
+       __u64 target_phys_addr;
+};
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+       __u8 last_irr;  /* edge detection */
+       __u8 irr;               /* interrupt request register */
+       __u8 imr;               /* interrupt mask register */
+       __u8 isr;               /* interrupt service register */
+       __u8 priority_add;      /* highest irq priority */
+       __u8 irq_base;
+       __u8 read_reg_select;
+       __u8 poll;
+       __u8 special_mask;
+       __u8 init_state;
+       __u8 auto_eoi;
+       __u8 rotate_on_auto_eoi;
+       __u8 special_fully_nested_mode;
+       __u8 init4;             /* true if 4 byte init */
+       __u8 elcr;              /* PIIX edge/trigger selection */
+       __u8 elcr_mask;
+};
+
+#define KVM_IOAPIC_NUM_PINS  24
+struct kvm_ioapic_state {
+       __u64 base_address;
+       __u32 ioregsel;
+       __u32 id;
+       __u32 irr;
+       __u32 pad;
+       union {
+               __u64 bits;
+               struct {
+                       __u8 vector;
+                       __u8 delivery_mode:3;
+                       __u8 dest_mode:1;
+                       __u8 delivery_status:1;
+                       __u8 polarity:1;
+                       __u8 remote_irr:1;
+                       __u8 trig_mode:1;
+                       __u8 mask:1;
+                       __u8 reserve:7;
+                       __u8 reserved[4];
+                       __u8 dest_id;
+               } fields;
+       } redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
+#define KVM_IRQCHIP_PIC_MASTER   0
+#define KVM_IRQCHIP_PIC_SLAVE    1
+#define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       __u64 rax, rbx, rcx, rdx;
+       __u64 rsi, rdi, rsp, rbp;
+       __u64 r8,  r9,  r10, r11;
+       __u64 r12, r13, r14, r15;
+       __u64 rip, rflags;
+};
+
+/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+       char regs[KVM_APIC_REG_SIZE];
+};
+
+struct kvm_segment {
+       __u64 base;
+       __u32 limit;
+       __u16 selector;
+       __u8  type;
+       __u8  present, dpl, db, s, l, g, avl;
+       __u8  unusable;
+       __u8  padding;
+};
+
+struct kvm_dtable {
+       __u64 base;
+       __u16 limit;
+       __u16 padding[3];
+};
+
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+       /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
+       struct kvm_segment cs, ds, es, fs, gs, ss;
+       struct kvm_segment tr, ldt;
+       struct kvm_dtable gdt, idt;
+       __u64 cr0, cr2, cr3, cr4, cr8;
+       __u64 efer;
+       __u64 apic_base;
+       __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+       __u8  fpr[8][16];
+       __u16 fcw;
+       __u16 fsw;
+       __u8  ftwx;  /* in fxsave format */
+       __u8  pad1;
+       __u16 last_opcode;
+       __u64 last_ip;
+       __u64 last_dp;
+       __u8  xmm[16][16];
+       __u32 mxcsr;
+       __u32 pad2;
+};
+
+struct kvm_msr_entry {
+       __u32 index;
+       __u32 reserved;
+       __u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+       __u32 nmsrs; /* number of msrs in entries */
+       __u32 pad;
+
+       struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+       __u32 nmsrs; /* number of msrs in entries */
+       __u32 indices[0];
+};
+
+
+struct kvm_cpuid_entry {
+       __u32 function;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+       __u32 nent;
+       __u32 padding;
+       struct kvm_cpuid_entry entries[0];
+};
+
+struct kvm_cpuid_entry2 {
+       __u32 function;
+       __u32 index;
+       __u32 flags;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding[3];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
+#define KVM_CPUID_FLAG_STATEFUL_FUNC    2
+#define KVM_CPUID_FLAG_STATE_READ_NEXT  4
+
+/* for KVM_SET_CPUID2 */
+struct kvm_cpuid2 {
+       __u32 nent;
+       __u32 padding;
+       struct kvm_cpuid_entry2 entries[0];
+};
+
+/* for KVM_GET_PIT and KVM_SET_PIT */
+struct kvm_pit_channel_state {
+       __u32 count; /* can be 65536 */
+       __u16 latched_count;
+       __u8 count_latched;
+       __u8 status_latched;
+       __u8 status;
+       __u8 read_state;
+       __u8 write_state;
+       __u8 write_latch;
+       __u8 rw_mode;
+       __u8 mode;
+       __u8 bcd;
+       __u8 gate;
+       __s64 count_load_time;
+};
+
+struct kvm_debug_exit_arch {
+       __u32 exception;
+       __u32 pad;
+       __u64 pc;
+       __u64 dr6;
+       __u64 dr7;
+};
+
+#define KVM_GUESTDBG_USE_SW_BP         0x00010000
+#define KVM_GUESTDBG_USE_HW_BP         0x00020000
+#define KVM_GUESTDBG_INJECT_DB         0x00040000
+#define KVM_GUESTDBG_INJECT_BP         0x00080000
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+       __u64 debugreg[8];
+};
+
+struct kvm_pit_state {
+       struct kvm_pit_channel_state channels[3];
+};
+
+#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
+
+struct kvm_pit_state2 {
+       struct kvm_pit_channel_state channels[3];
+       __u32 flags;
+       __u32 reserved[9];
+};
+
+struct kvm_reinject_control {
+       __u8 pit_reinject;
+       __u8 reserved[31];
+};
+
+/* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
+#define KVM_VCPUEVENT_VALID_NMI_PENDING        0x00000001
+#define KVM_VCPUEVENT_VALID_SIPI_VECTOR        0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW     0x00000004
+
+/* Interrupt shadow states */
+#define KVM_X86_SHADOW_INT_MOV_SS      0x01
+#define KVM_X86_SHADOW_INT_STI         0x02
+
+/* for KVM_GET/SET_VCPU_EVENTS */
+struct kvm_vcpu_events {
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 has_error_code;
+               __u8 pad;
+               __u32 error_code;
+       } exception;
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 soft;
+               __u8 shadow;
+       } interrupt;
+       struct {
+               __u8 injected;
+               __u8 pending;
+               __u8 masked;
+               __u8 pad;
+       } nmi;
+       __u32 sipi_vector;
+       __u32 flags;
+       __u32 reserved[10];
+};
+
+/* for KVM_GET/SET_DEBUGREGS */
+struct kvm_debugregs {
+       __u64 db[4];
+       __u64 dr6;
+       __u64 dr7;
+       __u64 flags;
+       __u64 reserved[9];
+};
+
+/* for KVM_CAP_XSAVE */
+struct kvm_xsave {
+       __u32 region[1024];
+};
+
+#define KVM_MAX_XCRS   16
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
+#endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
new file mode 100644 (file)
index 0000000..f2ac46a
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_H
+
+#include <linux/types.h>
+#include <asm/hyperv.h>
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE    0x40000000
+
+/* This CPUID returns a feature bitmap in eax.  Before enabling a particular
+ * paravirtualization, the appropriate feature bit should be checked.
+ */
+#define KVM_CPUID_FEATURES     0x40000001
+#define KVM_FEATURE_CLOCKSOURCE                0
+#define KVM_FEATURE_NOP_IO_DELAY       1
+#define KVM_FEATURE_MMU_OP             2
+/* This indicates that the new set of kvmclock msrs
+ * are available. The use of 0x11 and 0x12 is deprecated
+ */
+#define KVM_FEATURE_CLOCKSOURCE2        3
+#define KVM_FEATURE_ASYNC_PF           4
+#define KVM_FEATURE_STEAL_TIME         5
+
+/* The last 8 bits are used to indicate how to interpret the flags field
+ * in pvclock structure. If no bits are set, all flags are ignored.
+ */
+#define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT     24
+
+#define MSR_KVM_WALL_CLOCK  0x11
+#define MSR_KVM_SYSTEM_TIME 0x12
+
+#define KVM_MSR_ENABLED 1
+/* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */
+#define MSR_KVM_WALL_CLOCK_NEW  0x4b564d00
+#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
+#define MSR_KVM_ASYNC_PF_EN 0x4b564d02
+#define MSR_KVM_STEAL_TIME  0x4b564d03
+
+struct kvm_steal_time {
+       __u64 steal;
+       __u32 version;
+       __u32 flags;
+       __u32 pad[12];
+};
+
+#define KVM_STEAL_ALIGNMENT_BITS 5
+#define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1)))
+#define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1)
+
+#define KVM_MAX_MMU_OP_BATCH           32
+
+#define KVM_ASYNC_PF_ENABLED                   (1 << 0)
+#define KVM_ASYNC_PF_SEND_ALWAYS               (1 << 1)
+
+/* Operations for KVM_HC_MMU_OP */
+#define KVM_MMU_OP_WRITE_PTE            1
+#define KVM_MMU_OP_FLUSH_TLB           2
+#define KVM_MMU_OP_RELEASE_PT          3
+
+/* Payload for KVM_HC_MMU_OP */
+struct kvm_mmu_op_header {
+       __u32 op;
+       __u32 pad;
+};
+
+struct kvm_mmu_op_write_pte {
+       struct kvm_mmu_op_header header;
+       __u64 pte_phys;
+       __u64 pte_val;
+};
+
+struct kvm_mmu_op_flush_tlb {
+       struct kvm_mmu_op_header header;
+};
+
+struct kvm_mmu_op_release_pt {
+       struct kvm_mmu_op_header header;
+       __u64 pt_phys;
+};
+
+#define KVM_PV_REASON_PAGE_NOT_PRESENT 1
+#define KVM_PV_REASON_PAGE_READY 2
+
+struct kvm_vcpu_pv_apf_data {
+       __u32 reason;
+       __u8 pad[60];
+       __u32 enabled;
+};
+
+
+#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
new file mode 100644 (file)
index 0000000..a8761d3
--- /dev/null
@@ -0,0 +1,863 @@
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+/*
+ * Userspace interface for /dev/kvm - kernel based virtual machine
+ *
+ * Note: you must update KVM_API_VERSION if you change this interface.
+ */
+
+#include <linux/types.h>
+
+#include <linux/ioctl.h>
+#include <asm/kvm.h>
+
+#define KVM_API_VERSION 12
+
+/* *** Deprecated interfaces *** */
+
+#define KVM_TRC_SHIFT           16
+
+#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1))
+
+#define KVM_TRC_VMENTRY         (KVM_TRC_ENTRYEXIT + 0x01)
+#define KVM_TRC_VMEXIT          (KVM_TRC_ENTRYEXIT + 0x02)
+#define KVM_TRC_PAGE_FAULT      (KVM_TRC_HANDLER + 0x01)
+
+#define KVM_TRC_HEAD_SIZE       12
+#define KVM_TRC_CYCLE_SIZE      8
+#define KVM_TRC_EXTRA_MAX       7
+
+#define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
+#define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
+#define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
+#define KVM_TRC_IO_READ          (KVM_TRC_HANDLER + 0x05)
+#define KVM_TRC_IO_WRITE         (KVM_TRC_HANDLER + 0x06)
+#define KVM_TRC_CR_READ          (KVM_TRC_HANDLER + 0x07)
+#define KVM_TRC_CR_WRITE         (KVM_TRC_HANDLER + 0x08)
+#define KVM_TRC_DR_READ          (KVM_TRC_HANDLER + 0x09)
+#define KVM_TRC_DR_WRITE         (KVM_TRC_HANDLER + 0x0A)
+#define KVM_TRC_MSR_READ         (KVM_TRC_HANDLER + 0x0B)
+#define KVM_TRC_MSR_WRITE        (KVM_TRC_HANDLER + 0x0C)
+#define KVM_TRC_CPUID            (KVM_TRC_HANDLER + 0x0D)
+#define KVM_TRC_INTR             (KVM_TRC_HANDLER + 0x0E)
+#define KVM_TRC_NMI              (KVM_TRC_HANDLER + 0x0F)
+#define KVM_TRC_VMMCALL          (KVM_TRC_HANDLER + 0x10)
+#define KVM_TRC_HLT              (KVM_TRC_HANDLER + 0x11)
+#define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
+#define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
+#define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
+#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
+#define KVM_TRC_GTLB_WRITE       (KVM_TRC_HANDLER + 0x16)
+#define KVM_TRC_STLB_WRITE       (KVM_TRC_HANDLER + 0x17)
+#define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
+#define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
+
+struct kvm_user_trace_setup {
+       __u32 buf_size;
+       __u32 buf_nr;
+};
+
+#define __KVM_DEPRECATED_MAIN_W_0x06 \
+       _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
+#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
+
+#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
+
+struct kvm_breakpoint {
+       __u32 enabled;
+       __u32 padding;
+       __u64 address;
+};
+
+struct kvm_debug_guest {
+       __u32 enabled;
+       __u32 pad;
+       struct kvm_breakpoint breakpoints[4];
+       __u32 singlestep;
+};
+
+#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
+
+/* *** End of deprecated interfaces *** */
+
+
+/* for KVM_CREATE_MEMORY_REGION */
+struct kvm_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+};
+
+/* for KVM_SET_USER_MEMORY_REGION */
+struct kvm_userspace_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES  1UL
+#define KVM_MEMSLOT_INVALID      (1UL << 1)
+
+/* for KVM_IRQ_LINE */
+struct kvm_irq_level {
+       /*
+        * ACPI gsi notion of irq.
+        * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
+        * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+        */
+       union {
+               __u32 irq;
+               __s32 status;
+       };
+       __u32 level;
+};
+
+
+struct kvm_irqchip {
+       __u32 chip_id;
+       __u32 pad;
+        union {
+               char dummy[512];  /* reserving space */
+#ifdef __KVM_HAVE_PIT
+               struct kvm_pic_state pic;
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+               struct kvm_ioapic_state ioapic;
+#endif
+       } chip;
+};
+
+/* for KVM_CREATE_PIT2 */
+struct kvm_pit_config {
+       __u32 flags;
+       __u32 pad[15];
+};
+
+#define KVM_PIT_SPEAKER_DUMMY     1
+
+#define KVM_EXIT_UNKNOWN          0
+#define KVM_EXIT_EXCEPTION        1
+#define KVM_EXIT_IO               2
+#define KVM_EXIT_HYPERCALL        3
+#define KVM_EXIT_DEBUG            4
+#define KVM_EXIT_HLT              5
+#define KVM_EXIT_MMIO             6
+#define KVM_EXIT_IRQ_WINDOW_OPEN  7
+#define KVM_EXIT_SHUTDOWN         8
+#define KVM_EXIT_FAIL_ENTRY       9
+#define KVM_EXIT_INTR             10
+#define KVM_EXIT_SET_TPR          11
+#define KVM_EXIT_TPR_ACCESS       12
+#define KVM_EXIT_S390_SIEIC       13
+#define KVM_EXIT_S390_RESET       14
+#define KVM_EXIT_DCR              15
+#define KVM_EXIT_NMI              16
+#define KVM_EXIT_INTERNAL_ERROR   17
+#define KVM_EXIT_OSI              18
+#define KVM_EXIT_PAPR_HCALL      19
+
+/* For KVM_EXIT_INTERNAL_ERROR */
+#define KVM_INTERNAL_ERROR_EMULATION 1
+#define KVM_INTERNAL_ERROR_SIMUL_EX 2
+
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
+struct kvm_run {
+       /* in */
+       __u8 request_interrupt_window;
+       __u8 padding1[7];
+
+       /* out */
+       __u32 exit_reason;
+       __u8 ready_for_interrupt_injection;
+       __u8 if_flag;
+       __u8 padding2[2];
+
+       /* in (pre_kvm_run), out (post_kvm_run) */
+       __u64 cr8;
+       __u64 apic_base;
+
+#ifdef __KVM_S390
+       /* the processor status word for s390 */
+       __u64 psw_mask; /* psw upper half */
+       __u64 psw_addr; /* psw lower half */
+#endif
+       union {
+               /* KVM_EXIT_UNKNOWN */
+               struct {
+                       __u64 hardware_exit_reason;
+               } hw;
+               /* KVM_EXIT_FAIL_ENTRY */
+               struct {
+                       __u64 hardware_entry_failure_reason;
+               } fail_entry;
+               /* KVM_EXIT_EXCEPTION */
+               struct {
+                       __u32 exception;
+                       __u32 error_code;
+               } ex;
+               /* KVM_EXIT_IO */
+               struct {
+#define KVM_EXIT_IO_IN  0
+#define KVM_EXIT_IO_OUT 1
+                       __u8 direction;
+                       __u8 size; /* bytes */
+                       __u16 port;
+                       __u32 count;
+                       __u64 data_offset; /* relative to kvm_run start */
+               } io;
+               struct {
+                       struct kvm_debug_exit_arch arch;
+               } debug;
+               /* KVM_EXIT_MMIO */
+               struct {
+                       __u64 phys_addr;
+                       __u8  data[8];
+                       __u32 len;
+                       __u8  is_write;
+               } mmio;
+               /* KVM_EXIT_HYPERCALL */
+               struct {
+                       __u64 nr;
+                       __u64 args[6];
+                       __u64 ret;
+                       __u32 longmode;
+                       __u32 pad;
+               } hypercall;
+               /* KVM_EXIT_TPR_ACCESS */
+               struct {
+                       __u64 rip;
+                       __u32 is_write;
+                       __u32 pad;
+               } tpr_access;
+               /* KVM_EXIT_S390_SIEIC */
+               struct {
+                       __u8 icptcode;
+                       __u16 ipa;
+                       __u32 ipb;
+               } s390_sieic;
+               /* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR       1
+#define KVM_S390_RESET_CLEAR     2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT  8
+#define KVM_S390_RESET_IPL       16
+               __u64 s390_reset_flags;
+               /* KVM_EXIT_DCR */
+               struct {
+                       __u32 dcrn;
+                       __u32 data;
+                       __u8  is_write;
+               } dcr;
+               struct {
+                       __u32 suberror;
+                       /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
+                       __u32 ndata;
+                       __u64 data[16];
+               } internal;
+               /* KVM_EXIT_OSI */
+               struct {
+                       __u64 gprs[32];
+               } osi;
+               struct {
+                       __u64 nr;
+                       __u64 ret;
+                       __u64 args[9];
+               } papr_hcall;
+               /* Fix the size of the union. */
+               char padding[256];
+       };
+};
+
+/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
+
+struct kvm_coalesced_mmio_zone {
+       __u64 addr;
+       __u32 size;
+       __u32 pad;
+};
+
+struct kvm_coalesced_mmio {
+       __u64 phys_addr;
+       __u32 len;
+       __u32 pad;
+       __u8  data[8];
+};
+
+struct kvm_coalesced_mmio_ring {
+       __u32 first, last;
+       struct kvm_coalesced_mmio coalesced_mmio[0];
+};
+
+#define KVM_COALESCED_MMIO_MAX \
+       ((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
+        sizeof(struct kvm_coalesced_mmio))
+
+/* for KVM_TRANSLATE */
+struct kvm_translation {
+       /* in */
+       __u64 linear_address;
+
+       /* out */
+       __u64 physical_address;
+       __u8  valid;
+       __u8  writeable;
+       __u8  usermode;
+       __u8  pad[5];
+};
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+       /* in */
+       __u32 irq;
+};
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+       __u32 slot;
+       __u32 padding1;
+       union {
+               void *dirty_bitmap; /* one bit per page */
+               __u64 padding2;
+       };
+};
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+       __u32 len;
+       __u8  sigset[0];
+};
+
+/* for KVM_TPR_ACCESS_REPORTING */
+struct kvm_tpr_access_ctl {
+       __u32 enabled;
+       __u32 flags;
+       __u32 reserved[8];
+};
+
+/* for KVM_SET_VAPIC_ADDR */
+struct kvm_vapic_addr {
+       __u64 vapic_addr;
+};
+
+/* for KVM_SET_MPSTATE */
+
+#define KVM_MP_STATE_RUNNABLE          0
+#define KVM_MP_STATE_UNINITIALIZED     1
+#define KVM_MP_STATE_INIT_RECEIVED     2
+#define KVM_MP_STATE_HALTED            3
+#define KVM_MP_STATE_SIPI_RECEIVED     4
+
+struct kvm_mp_state {
+       __u32 mp_state;
+};
+
+struct kvm_s390_psw {
+       __u64 mask;
+       __u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP             0xfffe0000u
+#define KVM_S390_PROGRAM_INT           0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX       0xfffe0002u
+#define KVM_S390_RESTART               0xfffe0003u
+#define KVM_S390_INT_VIRTIO            0xffff2603u
+#define KVM_S390_INT_SERVICE           0xffff2401u
+#define KVM_S390_INT_EMERGENCY         0xffff1201u
+
+struct kvm_s390_interrupt {
+       __u32 type;
+       __u32 parm;
+       __u64 parm64;
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+
+#define KVM_GUESTDBG_ENABLE            0x00000001
+#define KVM_GUESTDBG_SINGLESTEP                0x00000002
+
+struct kvm_guest_debug {
+       __u32 control;
+       __u32 pad;
+       struct kvm_guest_debug_arch arch;
+};
+
+enum {
+       kvm_ioeventfd_flag_nr_datamatch,
+       kvm_ioeventfd_flag_nr_pio,
+       kvm_ioeventfd_flag_nr_deassign,
+       kvm_ioeventfd_flag_nr_max,
+};
+
+#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
+#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
+#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
+
+#define KVM_IOEVENTFD_VALID_FLAG_MASK  ((1 << kvm_ioeventfd_flag_nr_max) - 1)
+
+struct kvm_ioeventfd {
+       __u64 datamatch;
+       __u64 addr;        /* legal pio/mmio address */
+       __u32 len;         /* 1, 2, 4, or 8 bytes    */
+       __s32 fd;
+       __u32 flags;
+       __u8  pad[36];
+};
+
+/* for KVM_ENABLE_CAP */
+struct kvm_enable_cap {
+       /* in */
+       __u32 cap;
+       __u32 flags;
+       __u64 args[4];
+       __u8  pad[64];
+};
+
+/* for KVM_PPC_GET_PVINFO */
+struct kvm_ppc_pvinfo {
+       /* out */
+       __u32 flags;
+       __u32 hcall[4];
+       __u8  pad[108];
+};
+
+#define KVMIO 0xAE
+
+/*
+ * ioctls for /dev/kvm fds:
+ */
+#define KVM_GET_API_VERSION       _IO(KVMIO,   0x00)
+#define KVM_CREATE_VM             _IO(KVMIO,   0x01) /* returns a VM fd */
+#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+
+#define KVM_S390_ENABLE_SIE       _IO(KVMIO,   0x06)
+/*
+ * Check if a kvm extension is available.  Argument is extension number,
+ * return is 1 (yes) or 0 (no, sorry).
+ */
+#define KVM_CHECK_EXTENSION       _IO(KVMIO,   0x03)
+/*
+ * Get size for mmap(vcpu_fd)
+ */
+#define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
+#define KVM_GET_SUPPORTED_CPUID   _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
+#define KVM_TRACE_ENABLE          __KVM_DEPRECATED_MAIN_W_0x06
+#define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
+#define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
+
+/*
+ * Extension capability list.
+ */
+#define KVM_CAP_IRQCHIP          0
+#define KVM_CAP_HLT      1
+#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
+#define KVM_CAP_USER_MEMORY 3
+#define KVM_CAP_SET_TSS_ADDR 4
+#define KVM_CAP_VAPIC 6
+#define KVM_CAP_EXT_CPUID 7
+#define KVM_CAP_CLOCKSOURCE 8
+#define KVM_CAP_NR_VCPUS 9       /* returns recommended max vcpus per vm */
+#define KVM_CAP_NR_MEMSLOTS 10   /* returns max memory slots per vm */
+#define KVM_CAP_PIT 11
+#define KVM_CAP_NOP_IO_DELAY 12
+#define KVM_CAP_PV_MMU 13
+#define KVM_CAP_MP_STATE 14
+#define KVM_CAP_COALESCED_MMIO 15
+#define KVM_CAP_SYNC_MMU 16  /* Changes to host mmap are reflected in guest */
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_ASSIGNMENT 17
+#endif
+#define KVM_CAP_IOMMU 18
+#ifdef __KVM_HAVE_MSI
+#define KVM_CAP_DEVICE_MSI 20
+#endif
+/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
+#ifdef __KVM_HAVE_USER_NMI
+#define KVM_CAP_USER_NMI 22
+#endif
+#ifdef __KVM_HAVE_GUEST_DEBUG
+#define KVM_CAP_SET_GUEST_DEBUG 23
+#endif
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_REINJECT_CONTROL 24
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+#define KVM_CAP_IRQ_ROUTING 25
+#endif
+#define KVM_CAP_IRQ_INJECT_STATUS 26
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_DEASSIGNMENT 27
+#endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
+#define KVM_CAP_ASSIGN_DEV_IRQ 29
+/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
+#define KVM_CAP_IRQFD 32
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_PIT2 33
+#endif
+#define KVM_CAP_SET_BOOT_CPU_ID 34
+#ifdef __KVM_HAVE_PIT_STATE2
+#define KVM_CAP_PIT_STATE2 35
+#endif
+#define KVM_CAP_IOEVENTFD 36
+#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+#ifdef __KVM_HAVE_XEN_HVM
+#define KVM_CAP_XEN_HVM 38
+#endif
+#define KVM_CAP_ADJUST_CLOCK 39
+#define KVM_CAP_INTERNAL_ERROR_DATA 40
+#ifdef __KVM_HAVE_VCPU_EVENTS
+#define KVM_CAP_VCPU_EVENTS 41
+#endif
+#define KVM_CAP_S390_PSW 42
+#define KVM_CAP_PPC_SEGSTATE 43
+#define KVM_CAP_HYPERV 44
+#define KVM_CAP_HYPERV_VAPIC 45
+#define KVM_CAP_HYPERV_SPIN 46
+#define KVM_CAP_PCI_SEGMENT 47
+#define KVM_CAP_PPC_PAIRED_SINGLES 48
+#define KVM_CAP_INTR_SHADOW 49
+#ifdef __KVM_HAVE_DEBUGREGS
+#define KVM_CAP_DEBUGREGS 50
+#endif
+#define KVM_CAP_X86_ROBUST_SINGLESTEP 51
+#define KVM_CAP_PPC_OSI 52
+#define KVM_CAP_PPC_UNSET_IRQ 53
+#define KVM_CAP_ENABLE_CAP 54
+#ifdef __KVM_HAVE_XSAVE
+#define KVM_CAP_XSAVE 55
+#endif
+#ifdef __KVM_HAVE_XCRS
+#define KVM_CAP_XCRS 56
+#endif
+#define KVM_CAP_PPC_GET_PVINFO 57
+#define KVM_CAP_PPC_IRQ_LEVEL 58
+#define KVM_CAP_ASYNC_PF 59
+#define KVM_CAP_TSC_CONTROL 60
+#define KVM_CAP_GET_TSC_KHZ 61
+#define KVM_CAP_PPC_BOOKE_SREGS 62
+#define KVM_CAP_SPAPR_TCE 63
+#define KVM_CAP_PPC_SMT 64
+#define KVM_CAP_PPC_RMA        65
+#define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
+#define KVM_CAP_PPC_PAPR 68
+#define KVM_CAP_SW_TLB 69
+#define KVM_CAP_ONE_REG 70
+
+#ifdef KVM_CAP_IRQ_ROUTING
+
+struct kvm_irq_routing_irqchip {
+       __u32 irqchip;
+       __u32 pin;
+};
+
+struct kvm_irq_routing_msi {
+       __u32 address_lo;
+       __u32 address_hi;
+       __u32 data;
+       __u32 pad;
+};
+
+/* gsi routing entry types */
+#define KVM_IRQ_ROUTING_IRQCHIP 1
+#define KVM_IRQ_ROUTING_MSI 2
+
+struct kvm_irq_routing_entry {
+       __u32 gsi;
+       __u32 type;
+       __u32 flags;
+       __u32 pad;
+       union {
+               struct kvm_irq_routing_irqchip irqchip;
+               struct kvm_irq_routing_msi msi;
+               __u32 pad[8];
+       } u;
+};
+
+struct kvm_irq_routing {
+       __u32 nr;
+       __u32 flags;
+       struct kvm_irq_routing_entry entries[0];
+};
+
+#endif
+
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+       __u64 status;
+       __u64 addr;
+       __u64 misc;
+       __u64 mcg_status;
+       __u8 bank;
+       __u8 pad1[7];
+       __u64 pad2[3];
+};
+#endif
+
+#ifdef KVM_CAP_XEN_HVM
+struct kvm_xen_hvm_config {
+       __u32 flags;
+       __u32 msr;
+       __u64 blob_addr_32;
+       __u64 blob_addr_64;
+       __u8 blob_size_32;
+       __u8 blob_size_64;
+       __u8 pad2[30];
+};
+#endif
+
+#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
+
+struct kvm_irqfd {
+       __u32 fd;
+       __u32 gsi;
+       __u32 flags;
+       __u8  pad[20];
+};
+
+struct kvm_clock_data {
+       __u64 clock;
+       __u32 flags;
+       __u32 pad[9];
+};
+
+#define KVM_MMU_FSL_BOOKE_NOHV         0
+#define KVM_MMU_FSL_BOOKE_HV           1
+
+struct kvm_config_tlb {
+       __u64 params;
+       __u64 array;
+       __u32 mmu_type;
+       __u32 array_len;
+};
+
+struct kvm_dirty_tlb {
+       __u64 bitmap;
+       __u32 num_dirty;
+};
+
+/* Available with KVM_CAP_ONE_REG */
+
+#define KVM_ONE_REG_GENERIC            0x0000000000000000ULL
+
+/*
+ * Architecture specific registers are to be defined in arch headers and
+ * ORed with the arch identifier.
+ */
+#define KVM_ONE_REG_PPC                        0x1000000000000000ULL
+#define KVM_ONE_REG_X86                        0x2000000000000000ULL
+#define KVM_ONE_REG_IA64               0x3000000000000000ULL
+#define KVM_ONE_REG_ARM                        0x4000000000000000ULL
+#define KVM_ONE_REG_S390               0x5000000000000000ULL
+
+struct kvm_one_reg {
+       __u64 id;
+       union {
+               __u8 reg8;
+               __u16 reg16;
+               __u32 reg32;
+               __u64 reg64;
+               __u8 reg128[16];
+               __u8 reg256[32];
+               __u8 reg512[64];
+               __u8 reg1024[128];
+       } u;
+};
+
+/*
+ * ioctls for VM fds
+ */
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO,  0x40, struct kvm_memory_region)
+/*
+ * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
+ * a vcpu fd.
+ */
+#define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO,  0x42, struct kvm_dirty_log)
+/* KVM_SET_MEMORY_ALIAS is obsolete: */
+#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO,  0x43, struct kvm_memory_alias)
+#define KVM_SET_NR_MMU_PAGES      _IO(KVMIO,   0x44)
+#define KVM_GET_NR_MMU_PAGES      _IO(KVMIO,   0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
+                                       struct kvm_userspace_memory_region)
+#define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
+#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+/* Device model IOC */
+#define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
+#define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP           _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP           _IOR(KVMIO,  0x63, struct kvm_irqchip)
+#define KVM_CREATE_PIT            _IO(KVMIO,   0x64)
+#define KVM_GET_PIT               _IOWR(KVMIO, 0x65, struct kvm_pit_state)
+#define KVM_SET_PIT               _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_IRQ_LINE_STATUS       _IOWR(KVMIO, 0x67, struct kvm_irq_level)
+#define KVM_REGISTER_COALESCED_MMIO \
+                       _IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
+#define KVM_UNREGISTER_COALESCED_MMIO \
+                       _IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
+#define KVM_ASSIGN_PCI_DEVICE     _IOR(KVMIO,  0x69, \
+                                      struct kvm_assigned_pci_dev)
+#define KVM_SET_GSI_ROUTING       _IOW(KVMIO,  0x6a, struct kvm_irq_routing)
+/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
+#define KVM_ASSIGN_IRQ            __KVM_DEPRECATED_VM_R_0x70
+#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO,  0x70, struct kvm_assigned_irq)
+#define KVM_REINJECT_CONTROL      _IO(KVMIO,   0x71)
+#define KVM_DEASSIGN_PCI_DEVICE   _IOW(KVMIO,  0x72, \
+                                      struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR    _IOW(KVMIO,  0x73, \
+                                      struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO,  0x74, \
+                                      struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ      _IOW(KVMIO,  0x75, struct kvm_assigned_irq)
+#define KVM_IRQFD                 _IOW(KVMIO,  0x76, struct kvm_irqfd)
+#define KVM_CREATE_PIT2                  _IOW(KVMIO,  0x77, struct kvm_pit_config)
+#define KVM_SET_BOOT_CPU_ID       _IO(KVMIO,   0x78)
+#define KVM_IOEVENTFD             _IOW(KVMIO,  0x79, struct kvm_ioeventfd)
+#define KVM_XEN_HVM_CONFIG        _IOW(KVMIO,  0x7a, struct kvm_xen_hvm_config)
+#define KVM_SET_CLOCK             _IOW(KVMIO,  0x7b, struct kvm_clock_data)
+#define KVM_GET_CLOCK             _IOR(KVMIO,  0x7c, struct kvm_clock_data)
+/* Available with KVM_CAP_PIT_STATE2 */
+#define KVM_GET_PIT2              _IOR(KVMIO,  0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
+/* Available with KVM_CAP_PPC_GET_PVINFO */
+#define KVM_PPC_GET_PVINFO       _IOW(KVMIO,  0xa1, struct kvm_ppc_pvinfo)
+/* Available with KVM_CAP_TSC_CONTROL */
+#define KVM_SET_TSC_KHZ           _IO(KVMIO,  0xa2)
+#define KVM_GET_TSC_KHZ           _IO(KVMIO,  0xa3)
+
+/*
+ * ioctls for vcpu fds
+ */
+#define KVM_RUN                   _IO(KVMIO,   0x80)
+#define KVM_GET_REGS              _IOR(KVMIO,  0x81, struct kvm_regs)
+#define KVM_SET_REGS              _IOW(KVMIO,  0x82, struct kvm_regs)
+#define KVM_GET_SREGS             _IOR(KVMIO,  0x83, struct kvm_sregs)
+#define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
+#define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
+#define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
+/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
+#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_VCPU_W_0x87
+#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
+#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
+#define KVM_GET_FPU               _IOR(KVMIO,  0x8c, struct kvm_fpu)
+#define KVM_SET_FPU               _IOW(KVMIO,  0x8d, struct kvm_fpu)
+#define KVM_GET_LAPIC             _IOR(KVMIO,  0x8e, struct kvm_lapic_state)
+#define KVM_SET_LAPIC             _IOW(KVMIO,  0x8f, struct kvm_lapic_state)
+#define KVM_SET_CPUID2            _IOW(KVMIO,  0x90, struct kvm_cpuid2)
+#define KVM_GET_CPUID2            _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_TPR_ACCESS_REPORTING  _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_SET_VAPIC_ADDR        _IOW(KVMIO,  0x93, struct kvm_vapic_addr)
+/* valid for virtual machine (for floating interrupt)_and_ vcpu */
+#define KVM_S390_INTERRUPT        _IOW(KVMIO,  0x94, struct kvm_s390_interrupt)
+/* store status for s390 */
+#define KVM_S390_STORE_STATUS_NOADDR    (-1ul)
+#define KVM_S390_STORE_STATUS_PREFIXED  (-2ul)
+#define KVM_S390_STORE_STATUS    _IOW(KVMIO,  0x95, unsigned long)
+/* initial ipl psw for s390 */
+#define KVM_S390_SET_INITIAL_PSW  _IOW(KVMIO,  0x96, struct kvm_s390_psw)
+/* initial reset for s390 */
+#define KVM_S390_INITIAL_RESET    _IO(KVMIO,   0x97)
+#define KVM_GET_MP_STATE          _IOR(KVMIO,  0x98, struct kvm_mp_state)
+#define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
+/* Available with KVM_CAP_NMI */
+#define KVM_NMI                   _IO(KVMIO,   0x9a)
+/* Available with KVM_CAP_SET_GUEST_DEBUG */
+#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE         _IOW(KVMIO,  0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO,  0x9d, __u64)
+#define KVM_X86_SET_MCE           _IOW(KVMIO,  0x9e, struct kvm_x86_mce)
+/* IA64 stack access */
+#define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
+#define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
+/* Available with KVM_CAP_VCPU_EVENTS */
+#define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
+#define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
+/* Available with KVM_CAP_DEBUGREGS */
+#define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
+#define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
+#define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap)
+/* Available with KVM_CAP_XSAVE */
+#define KVM_GET_XSAVE            _IOR(KVMIO,  0xa4, struct kvm_xsave)
+#define KVM_SET_XSAVE            _IOW(KVMIO,  0xa5, struct kvm_xsave)
+/* Available with KVM_CAP_XCRS */
+#define KVM_GET_XCRS             _IOR(KVMIO,  0xa6, struct kvm_xcrs)
+#define KVM_SET_XCRS             _IOW(KVMIO,  0xa7, struct kvm_xcrs)
+#define KVM_CREATE_SPAPR_TCE     _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
+/* Available with KVM_CAP_RMA */
+#define KVM_ALLOCATE_RMA         _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_SW_TLB */
+#define KVM_DIRTY_TLB            _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
+/* Available with KVM_CAP_ONE_REG */
+#define KVM_GET_ONE_REG                  _IOWR(KVMIO, 0xab, struct kvm_one_reg)
+#define KVM_SET_ONE_REG                  _IOW(KVMIO,  0xac, struct kvm_one_reg)
+
+#define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
+
+struct kvm_assigned_pci_dev {
+       __u32 assigned_dev_id;
+       __u32 busnr;
+       __u32 devfn;
+       __u32 flags;
+       __u32 segnr;
+       union {
+               __u32 reserved[11];
+       };
+};
+
+#define KVM_DEV_IRQ_HOST_INTX    (1 << 0)
+#define KVM_DEV_IRQ_HOST_MSI     (1 << 1)
+#define KVM_DEV_IRQ_HOST_MSIX    (1 << 2)
+
+#define KVM_DEV_IRQ_GUEST_INTX   (1 << 8)
+#define KVM_DEV_IRQ_GUEST_MSI    (1 << 9)
+#define KVM_DEV_IRQ_GUEST_MSIX   (1 << 10)
+
+#define KVM_DEV_IRQ_HOST_MASK   0x00ff
+#define KVM_DEV_IRQ_GUEST_MASK   0xff00
+
+struct kvm_assigned_irq {
+       __u32 assigned_dev_id;
+       __u32 host_irq; /* ignored (legacy field) */
+       __u32 guest_irq;
+       __u32 flags;
+       union {
+               __u32 reserved[12];
+       };
+};
+
+struct kvm_assigned_msix_nr {
+       __u32 assigned_dev_id;
+       __u16 entry_nr;
+       __u16 padding;
+};
+
+#define KVM_MAX_MSIX_PER_DEV           256
+struct kvm_assigned_msix_entry {
+       __u32 assigned_dev_id;
+       __u32 gsi;
+       __u16 entry; /* The index of entry in the MSI-X table */
+       __u16 padding[3];
+};
+
+#endif /* __LINUX_KVM_H */
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
new file mode 100644 (file)
index 0000000..b315e27
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __LINUX_KVM_PARA_H
+#define __LINUX_KVM_PARA_H
+
+/*
+ * This header file provides a method for making a hypercall to the host
+ * Architectures should define:
+ * - kvm_hypercall0, kvm_hypercall1...
+ * - kvm_arch_para_features
+ * - kvm_para_available
+ */
+
+/* Return values for hypercalls */
+#define KVM_ENOSYS             1000
+#define KVM_EFAULT             EFAULT
+#define KVM_E2BIG              E2BIG
+#define KVM_EPERM              EPERM
+
+#define KVM_HC_VAPIC_POLL_IRQ          1
+#define KVM_HC_MMU_OP                  2
+#define KVM_HC_FEATURES                        3
+#define KVM_HC_PPC_MAP_MAGIC_PAGE      4
+
+/*
+ * hypercalls use architecture specific
+ */
+#include <asm/kvm_para.h>
+
+#endif /* __LINUX_KVM_PARA_H */
+
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
new file mode 100644 (file)
index 0000000..165a484
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+       unsigned int index;
+       unsigned int num;
+};
+
+struct vhost_vring_file {
+       unsigned int index;
+       int fd; /* Pass -1 to unbind from file. */
+
+};
+
+struct vhost_vring_addr {
+       unsigned int index;
+       /* Option flags. */
+       unsigned int flags;
+       /* Flag values: */
+       /* Whether log address is valid. If set enables logging. */
+#define VHOST_VRING_F_LOG 0
+
+       /* Start of array of descriptors (virtually contiguous) */
+       __u64 desc_user_addr;
+       /* Used structure address. Must be 32 bit aligned */
+       __u64 used_user_addr;
+       /* Available structure address. Must be 16 bit aligned */
+       __u64 avail_user_addr;
+       /* Logging support. */
+       /* Log writes to used structure, at offset calculated from specified
+        * address. Address must be 32 bit aligned. */
+       __u64 log_guest_addr;
+};
+
+struct vhost_memory_region {
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr;
+       __u64 flags_padding; /* No flags are currently specified. */
+};
+
+/* All region addresses and sizes must be 4K aligned. */
+#define VHOST_PAGE_SIZE 0x1000
+
+struct vhost_memory {
+       __u32 nregions;
+       __u32 padding;
+       struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility.  Transport bits are used for
+ * vhost specific features. */
+#define VHOST_GET_FEATURES     _IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_FEATURES     _IOW(VHOST_VIRTIO, 0x00, __u64)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE    _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Write logging setup. */
+/* Memory writes can optionally be logged by setting bit at an offset
+ * (calculated from the physical address) from specified log base.
+ * The bit is set using an atomic 32 bit operation. */
+/* Set base address for logging. */
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+/* Specify an eventfd file descriptor to signal on log write. */
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+
+/* Ring setup. */
+/* Set number of descriptors in ring. This parameter can not
+ * be modified while ring is running (bound to a device). */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Set addresses for the ring. */
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net ring to a raw socket, or tap device.
+ * The socket must be already bound to an ethernet device, this device will be
+ * used for transmit.  Pass fd -1 to unbind from the socket and the transmit
+ * device.  This can be used to stop the ring (e.g. for migration). */
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* Feature bits */
+/* Log all write descriptors. Can be changed while device is active. */
+#define VHOST_F_LOG_ALL 26
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
+
+#endif
diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h
new file mode 100644 (file)
index 0000000..4f51d8f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE    1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER         2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK      4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED         0x80
+
+/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
+ * transport being used (eg. virtio_ring), the rest are per-device feature
+ * bits. */
+#define VIRTIO_TRANSPORT_F_START       28
+#define VIRTIO_TRANSPORT_F_END         32
+
+/* Do we get callbacks when the ring is completely used, even if we've
+ * suppressed them? */
+#define VIRTIO_F_NOTIFY_ON_EMPTY       24
+
+#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h
new file mode 100644 (file)
index 0000000..78289ee
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef _LINUX_VIRTIO_RING_H
+#define _LINUX_VIRTIO_RING_H
+/* An interface for efficient virtio implementation, currently for use by KVM
+ * and lguest, but hopefully others soon.  Do NOT change this since it will
+ * break existing servers and clients.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright Rusty Russell IBM Corporation 2007. */
+#include <linux/types.h>
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT      1
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE     2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT  4
+
+/* The Host uses this in used->flags to advise the Guest: don't kick me when
+ * you add a buffer.  It's unreliable, so it's simply an optimization.  Guest
+ * will still kick if it's out of buffers. */
+#define VRING_USED_F_NO_NOTIFY 1
+/* The Guest uses this in avail->flags to advise the Host: don't interrupt me
+ * when you consume a buffer.  It's unreliable, so it's simply an
+ * optimization.  */
+#define VRING_AVAIL_F_NO_INTERRUPT     1
+
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC    28
+
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX                29
+
+/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
+struct vring_desc {
+       /* Address (guest-physical). */
+       __u64 addr;
+       /* Length. */
+       __u32 len;
+       /* The flags as indicated above. */
+       __u16 flags;
+       /* We chain unused descriptors via this, too */
+       __u16 next;
+};
+
+struct vring_avail {
+       __u16 flags;
+       __u16 idx;
+       __u16 ring[];
+};
+
+/* u32 is used here for ids for padding reasons. */
+struct vring_used_elem {
+       /* Index of start of used descriptor chain. */
+       __u32 id;
+       /* Total length of the descriptor chain which was used (written to) */
+       __u32 len;
+};
+
+struct vring_used {
+       __u16 flags;
+       __u16 idx;
+       struct vring_used_elem ring[];
+};
+
+struct vring {
+       unsigned int num;
+
+       struct vring_desc *desc;
+
+       struct vring_avail *avail;
+
+       struct vring_used *used;
+};
+
+/* The standard layout for the ring is a continuous chunk of memory which looks
+ * like this.  We assume num is a power of 2.
+ *
+ * struct vring
+ * {
+ *     // The actual descriptors (16 bytes each)
+ *     struct vring_desc desc[num];
+ *
+ *     // A ring of available descriptor heads with free-running index.
+ *     __u16 avail_flags;
+ *     __u16 avail_idx;
+ *     __u16 available[num];
+ *     __u16 used_event_idx;
+ *
+ *     // Padding to the next align boundary.
+ *     char pad[];
+ *
+ *     // A ring of used descriptor heads with free-running index.
+ *     __u16 used_flags;
+ *     __u16 used_idx;
+ *     struct vring_used_elem used[num];
+ *     __u16 avail_event_idx;
+ * };
+ */
+/* We publish the used event index at the end of the available ring, and vice
+ * versa. They are at the end for backwards compatibility. */
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+
+static __inline__ void vring_init(struct vring *vr, unsigned int num, void *p,
+                             unsigned long align)
+{
+       vr->num = num;
+       vr->desc = p;
+       vr->avail = p + num*sizeof(struct vring_desc);
+       vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
+                           & ~(align - 1));
+}
+
+static __inline__ unsigned vring_size(unsigned int num, unsigned long align)
+{
+       return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+                + align - 1) & ~(align - 1))
+               + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+}
+
+/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
+{
+       /* Note: Xen has similar logic for notification hold-off
+        * in include/xen/interface/io/ring.h with req_event and req_prod
+        * corresponding to event_idx + 1 and new_idx respectively.
+        * Note also that req_event and req_prod in Xen start at 1,
+        * event indexes in virtio start at 0. */
+       return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
+}
+
+#endif /* _LINUX_VIRTIO_RING_H */
index 71822233819b07cc2b99f8d57ae0583fa0b319d1..f6284db22fc790dab10f86e5d264f2d9dde5ab8a 100644 (file)
 #define TARGET_NR_signalfd                     476
 #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
+#define TARGET_NR_recvmmsg                      479
+#define TARGET_NR_fallocate                     480
+#define TARGET_NR_timerfd_create                481
+#define TARGET_NR_timerfd_settime               482
+#define TARGET_NR_timerfd_gettime               483
+#define TARGET_NR_signalfd4                     484
+#define TARGET_NR_eventfd2                      485
+#define TARGET_NR_epoll_create1                 486
+#define TARGET_NR_dup3                          487
+#define TARGET_NR_pipe2                         488
+#define TARGET_NR_inotify_init1                 489
+#define TARGET_NR_preadv                        490
+#define TARGET_NR_pwritev                       491
+#define TARGET_NR_rt_tgsigqueueinfo             492
+#define TARGET_NR_perf_event_open               493
+#define TARGET_NR_fanotify_init                 494
+#define TARGET_NR_fanotify_mark                 495
+#define TARGET_NR_prlimit64                     496
+#define TARGET_NR_name_to_handle_at             497
+#define TARGET_NR_open_by_handle_at             498
+#define TARGET_NR_clock_adjtime                 499
+#define TARGET_NR_syncfs                        500
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 1346fd619d86cf23fb2fd9c8f67a15bb4e311cff..3e7a938253a06f277c3e69681a493d4a349b8e41 100644 (file)
@@ -33,7 +33,7 @@ void loadSingle(const unsigned int Fn, target_ulong addr)
    FPA11 *fpa11 = GET_FPA11();
    fpa11->fType[Fn] = typeSingle;
    /* FIXME - handle failure of get_user() */
-   get_user_u32(fpa11->fpreg[Fn].fSingle, addr);
+   get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr);
 }
 
 static inline
@@ -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 240061dd618dcb94c942ccc26ad2b5a957d8d682..82ac92f0ceaedadf190a7367c0e4fd92c11b0d44 100644 (file)
@@ -37,25 +37,25 @@ const floatx80 floatx80Constant[] = {
 };
 
 const float64 float64Constant[] = {
-  0x0000000000000000ULL,               /* double 0.0 */
-  0x3ff0000000000000ULL,               /* double 1.0 */
-  0x4000000000000000ULL,               /* double 2.0 */
-  0x4008000000000000ULL,               /* double 3.0 */
-  0x4010000000000000ULL,               /* double 4.0 */
-  0x4014000000000000ULL,               /* double 5.0 */
-  0x3fe0000000000000ULL,               /* double 0.5 */
-  0x4024000000000000ULL                        /* double 10.0 */
+  const_float64(0x0000000000000000ULL),                /* double 0.0 */
+  const_float64(0x3ff0000000000000ULL),                /* double 1.0 */
+  const_float64(0x4000000000000000ULL),                /* double 2.0 */
+  const_float64(0x4008000000000000ULL),                /* double 3.0 */
+  const_float64(0x4010000000000000ULL),                /* double 4.0 */
+  const_float64(0x4014000000000000ULL),                /* double 5.0 */
+  const_float64(0x3fe0000000000000ULL),                /* double 0.5 */
+  const_float64(0x4024000000000000ULL)                 /* double 10.0 */
 };
 
 const float32 float32Constant[] = {
-  0x00000000,                          /* single 0.0 */
-  0x3f800000,                          /* single 1.0 */
-  0x40000000,                          /* single 2.0 */
-  0x40400000,                          /* single 3.0 */
-  0x40800000,                          /* single 4.0 */
-  0x40a00000,                          /* single 5.0 */
-  0x3f000000,                          /* single 0.5 */
-  0x41200000                           /* single 10.0 */
+  const_float32(0x00000000),                           /* single 0.0 */
+  const_float32(0x3f800000),                           /* single 1.0 */
+  const_float32(0x40000000),                           /* single 2.0 */
+  const_float32(0x40400000),                           /* single 3.0 */
+  const_float32(0x40800000),                           /* single 4.0 */
+  const_float32(0x40a00000),                           /* single 5.0 */
+  const_float32(0x3f000000),                           /* single 0.5 */
+  const_float32(0x41200000)                            /* single 10.0 */
 };
 
 unsigned int getRegisterCount(const unsigned int opcode)
index 79a216a137024f97c3f1975451f16d802b4ae7b4..7f05879ea3c4e4be9b99adefbc7c7287255c79c7 100644 (file)
 #define TARGET_NR_dup3                         (358)
 #define TARGET_NR_pipe2                        (359)
 #define TARGET_NR_inotify_init1                (360)
+#define TARGET_NR_preadv                       (361)
+#define TARGET_NR_pwritev                      (362)
+#define TARGET_NR_rt_tgsigqueueinfo            (363)
+#define TARGET_NR_perf_event_open              (364)
+#define TARGET_NR_recvmmsg                     (365)
+#define TARGET_NR_accept4                      (366)
+#define TARGET_NR_fanotify_init                (367)
+#define TARGET_NR_fanotify_mark                (368)
+#define TARGET_NR_prlimit64                    (369)
+#define TARGET_NR_name_to_handle_at            (370)
+#define TARGET_NR_open_by_handle_at            (371)
+#define TARGET_NR_clock_adjtime                (372)
+#define TARGET_NR_syncfs                       (373)
index 6132817105adcab53682c88eb366dfcbbb9a38e3..98f1a0b4152f71c6d2c9de9f5dc5766360fa807f 100644 (file)
 #define TARGET_NR_dup3               330
 #define TARGET_NR_pipe2              331
 #define TARGET_NR_inotify_init1      332
+#define TARGET_NR_preadv             333
+#define TARGET_NR_pwritev            334
index 08c44d89331a45eedfc217c98bc3afa427fe1438..4635bb2e5d9fb41426104d9409ce23a77e031926 100644 (file)
@@ -103,13 +103,13 @@ enum {
 
 typedef target_ulong    target_elf_greg_t;
 #ifdef USE_UID16
-typedef uint16_t        target_uid_t;
-typedef uint16_t        target_gid_t;
+typedef target_ushort   target_uid_t;
+typedef target_ushort   target_gid_t;
 #else
-typedef uint32_t        target_uid_t;
-typedef uint32_t        target_gid_t;
+typedef target_uint     target_uid_t;
+typedef target_uint     target_gid_t;
 #endif
-typedef int32_t         target_pid_t;
+typedef target_int      target_pid_t;
 
 #ifdef TARGET_I386
 
@@ -332,6 +332,49 @@ enum
     ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
 };
 
+#define TARGET_HAS_GUEST_VALIDATE_BASE
+/* We want the opportunity to check the suggested base */
+bool guest_validate_base(unsigned long guest_base)
+{
+    unsigned long real_start, test_page_addr;
+
+    /* We need to check that we can force a fault on access to the
+     * commpage at 0xffff0fxx
+     */
+    test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
+    /* Note it needs to be writeable to let us initialise it */
+    real_start = (unsigned long)
+                 mmap((void *)test_page_addr, qemu_host_page_size,
+                     PROT_READ | PROT_WRITE,
+                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+    /* If we can't map it then try another address */
+    if (real_start == -1ul) {
+        return 0;
+    }
+
+    if (real_start != test_page_addr) {
+        /* OS didn't put the page where we asked - unmap and reject */
+        munmap((void *)real_start, qemu_host_page_size);
+        return 0;
+    }
+
+    /* Leave the page mapped
+     * Populate it (mmap should have left it all 0'd)
+     */
+
+    /* Kernel helper versions */
+    __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
+
+    /* Now it's populated make it RO */
+    if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
+        perror("Protecting guest commpage");
+        exit(-1);
+    }
+
+    return 1; /* All good */
+}
+
 #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
@@ -339,11 +382,86 @@ 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
 
 #define ELF_START_MMAP 0x80000000
-
+#define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
+                    | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
 #ifndef TARGET_ABI32
 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
 #else
@@ -376,7 +494,8 @@ static inline void init_thread(struct target_pt_regs *regs,
 
 #else
 #define ELF_START_MMAP 0x80000000
-
+#define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
+                    | HWCAP_SPARC_MULDIV)
 #define elf_check_arch(x) ( (x) == EM_SPARC )
 
 #define ELF_CLASS   ELFCLASS32
@@ -499,8 +618,8 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
 {
     _regs->gpr[1] = infop->start_stack;
 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_addr;
-    infop->entry = ldq_raw(infop->entry) + infop->load_addr;
+    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
+    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
 #endif
     _regs->nip = infop->entry;
 }
@@ -793,6 +912,25 @@ static inline void init_thread(struct target_pt_regs *regs,
 
 #endif /* TARGET_ALPHA */
 
+#ifdef TARGET_S390X
+
+#define ELF_START_MMAP (0x20000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_S390
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->psw.addr = infop->entry;
+    regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
+    regs->gprs[15] = infop->start_stack;
+}
+
+#endif /* TARGET_S390X */
+
 #ifndef ELF_PLATFORM
 #define ELF_PLATFORM (NULL)
 #endif
@@ -834,7 +972,7 @@ struct exec
 #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
 #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
 
-#define DLINFO_ITEMS 12
+#define DLINFO_ITEMS 13
 
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
@@ -967,8 +1105,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
                 offset = p % TARGET_PAGE_SIZE;
                 pag = (char *)page[p/TARGET_PAGE_SIZE];
                 if (!pag) {
-                    pag = (char *)malloc(TARGET_PAGE_SIZE);
-                    memset(pag, 0, TARGET_PAGE_SIZE);
+                    pag = g_try_malloc0(TARGET_PAGE_SIZE);
                     page[p/TARGET_PAGE_SIZE] = pag;
                     if (!pag)
                         return 0;
@@ -1026,7 +1163,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
             info->rss++;
             /* FIXME - check return value of memcpy_to_target() for failure */
             memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
-            free(bprm->page[i]);
+            g_free(bprm->page[i]);
         }
         stack_base += TARGET_PAGE_SIZE;
     }
@@ -1075,6 +1212,33 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
     }
 }
 
+#ifdef CONFIG_USE_FDPIC
+static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
+{
+    uint16_t n;
+    struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
+
+    /* elf32_fdpic_loadseg */
+    n = info->nsegs;
+    while (n--) {
+        sp -= 12;
+        put_user_u32(loadsegs[n].addr, sp+0);
+        put_user_u32(loadsegs[n].p_vaddr, sp+4);
+        put_user_u32(loadsegs[n].p_memsz, sp+8);
+    }
+
+    /* elf32_fdpic_loadmap */
+    sp -= 4;
+    put_user_u16(0, sp+0); /* version */
+    put_user_u16(info->nsegs, sp+2); /* nsegs */
+
+    info->personality = PER_LINUX_FDPIC;
+    info->loadmap_addr = sp;
+
+    return sp;
+}
+#endif
+
 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    struct elfhdr *exec,
                                    struct image_info *info,
@@ -1082,11 +1246,29 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 {
     abi_ulong sp;
     int size;
+    int i;
+    abi_ulong u_rand_bytes;
+    uint8_t k_rand_bytes[16];
     abi_ulong u_platform;
     const char *k_platform;
     const int n = sizeof(elf_addr_t);
 
     sp = p;
+
+#ifdef CONFIG_USE_FDPIC
+    /* Needs to be before we load the env/argc/... */
+    if (elf_is_fdpic(exec)) {
+        /* Need 4 byte alignment for these structs */
+        sp &= ~3;
+        sp = loader_build_fdpic_loadmap(info, sp);
+        info->other_info = interp_info;
+        if (interp_info) {
+            interp_info->other_info = info;
+            sp = loader_build_fdpic_loadmap(interp_info, sp);
+        }
+    }
+#endif
+
     u_platform = 0;
     k_platform = ELF_PLATFORM;
     if (k_platform) {
@@ -1096,6 +1278,20 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
         /* FIXME - check return value of memcpy_to_target() for failure */
         memcpy_to_target(sp, k_platform, len);
     }
+
+    /*
+     * Generate 16 random bytes for userspace PRNG seeding (not
+     * cryptically secure but it's not the aim of QEMU).
+     */
+    srand((unsigned int) time(NULL));
+    for (i = 0; i < 16; i++) {
+        k_rand_bytes[i] = rand();
+    }
+    sp -= 16;
+    u_rand_bytes = sp;
+    /* FIXME - check return value of memcpy_to_target() for failure */
+    memcpy_to_target(sp, k_rand_bytes, 16);
+
     /*
      * Force 16 byte _final_ alignment here for generality.
      */
@@ -1136,6 +1332,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+    NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
+
     if (k_platform)
         NEW_AUX_ENT(AT_PLATFORM, u_platform);
 #ifdef ARCH_DLINFO
@@ -1153,6 +1351,87 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     return sp;
 }
 
+#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
+/* If the guest doesn't have a validation function just agree */
+bool guest_validate_base(unsigned long guest_base)
+{
+    return 1;
+}
+#endif
+
+static void probe_guest_base(const char *image_name,
+                             abi_ulong loaddr, abi_ulong hiaddr)
+{
+    /* Probe for a suitable guest base address, if the user has not set
+     * it explicitly, and set guest_base appropriately.
+     * In case of error we will print a suitable message and exit.
+     */
+#if defined(CONFIG_USE_GUEST_BASE)
+    const char *errmsg;
+    if (!have_guest_base && !reserved_va) {
+        unsigned long host_start, real_start, host_size;
+
+        /* Round addresses to page boundaries.  */
+        loaddr &= qemu_host_page_mask;
+        hiaddr = HOST_PAGE_ALIGN(hiaddr);
+
+        if (loaddr < mmap_min_addr) {
+            host_start = HOST_PAGE_ALIGN(mmap_min_addr);
+        } else {
+            host_start = loaddr;
+            if (host_start != loaddr) {
+                errmsg = "Address overflow loading ELF binary";
+                goto exit_errmsg;
+            }
+        }
+        host_size = hiaddr - loaddr;
+        while (1) {
+            /* Do not use mmap_find_vma here because that is limited to the
+               guest address space.  We are going to make the
+               guest address space fit whatever we're given.  */
+            real_start = (unsigned long)
+                mmap((void *)host_start, host_size, PROT_NONE,
+                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
+            if (real_start == (unsigned long)-1) {
+                goto exit_perror;
+            }
+            guest_base = real_start - loaddr;
+            if ((real_start == host_start) &&
+                guest_validate_base(guest_base)) {
+                break;
+            }
+            /* That address didn't work.  Unmap and try a different one.
+               The address the host picked because is typically right at
+               the top of the host address space and leaves the guest with
+               no usable address space.  Resort to a linear search.  We
+               already compensated for mmap_min_addr, so this should not
+               happen often.  Probably means we got unlucky and host
+               address space randomization put a shared library somewhere
+               inconvenient.  */
+            munmap((void *)real_start, host_size);
+            host_start += qemu_host_page_size;
+            if (host_start == loaddr) {
+                /* Theoretically possible if host doesn't have any suitably
+                   aligned areas.  Normally the first mmap will fail.  */
+                errmsg = "Unable to find space for application";
+                goto exit_errmsg;
+            }
+        }
+        qemu_log("Relocating guest address space from 0x"
+                 TARGET_ABI_FMT_lx " to 0x%lx\n",
+                 loaddr, real_start);
+    }
+    return;
+
+exit_perror:
+    errmsg = strerror(errno);
+exit_errmsg:
+    fprintf(stderr, "%s: %s\n", image_name, errmsg);
+    exit(-1);
+#endif
+}
+
+
 /* Load an ELF image into the address space.
 
    IMAGE_NAME is the filename of the image, to use in error messages.
@@ -1197,6 +1476,11 @@ static void load_elf_image(const char *image_name, int image_fd,
     }
     bswap_phdr(phdr, ehdr->e_phnum);
 
+#ifdef CONFIG_USE_FDPIC
+    info->nsegs = 0;
+    info->pt_dynamic_addr = 0;
+#endif
+
     /* Find the maximum size of the image and allocate an appropriate
        amount of memory to handle that.  */
     loaddr = -1, hiaddr = 0;
@@ -1210,6 +1494,9 @@ static void load_elf_image(const char *image_name, int image_fd,
             if (a > hiaddr) {
                 hiaddr = a;
             }
+#ifdef CONFIG_USE_FDPIC
+            ++info->nsegs;
+#endif
         }
     }
 
@@ -1230,65 +1517,30 @@ static void load_elf_image(const char *image_name, int image_fd,
         /* This is the main executable.  Make sure that the low
            address does not conflict with MMAP_MIN_ADDR or the
            QEMU application itself.  */
-#if defined(CONFIG_USE_GUEST_BASE)
-        /*
-         * In case where user has not explicitly set the guest_base, we
-         * probe here that should we set it automatically.
-         */
-        if (!have_guest_base && !reserved_va) {
-            unsigned long host_start, real_start, host_size;
-
-            /* Round addresses to page boundaries.  */
-            loaddr &= qemu_host_page_mask;
-            hiaddr = HOST_PAGE_ALIGN(hiaddr);
-
-            if (loaddr < mmap_min_addr) {
-                host_start = HOST_PAGE_ALIGN(mmap_min_addr);
-            } else {
-                host_start = loaddr;
-                if (host_start != loaddr) {
-                    errmsg = "Address overflow loading ELF binary";
-                    goto exit_errmsg;
-                }
-            }
-            host_size = hiaddr - loaddr;
-            while (1) {
-                /* Do not use mmap_find_vma here because that is limited to the
-                   guest address space.  We are going to make the
-                   guest address space fit whatever we're given.  */
-                real_start = (unsigned long)
-                    mmap((void *)host_start, host_size, PROT_NONE,
-                         MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
-                if (real_start == (unsigned long)-1) {
-                    goto exit_perror;
-                }
-                if (real_start == host_start) {
-                    break;
-                }
-                /* That address didn't work.  Unmap and try a different one.
-                   The address the host picked because is typically right at
-                   the top of the host address space and leaves the guest with
-                   no usable address space.  Resort to a linear search.  We
-                   already compensated for mmap_min_addr, so this should not
-                   happen often.  Probably means we got unlucky and host
-                   address space randomization put a shared library somewhere
-                   inconvenient.  */
-                munmap((void *)real_start, host_size);
-                host_start += qemu_host_page_size;
-                if (host_start == loaddr) {
-                    /* Theoretically possible if host doesn't have any suitably
-                       aligned areas.  Normally the first mmap will fail.  */
-                    errmsg = "Unable to find space for application";
-                    goto exit_errmsg;
-                }
+        probe_guest_base(image_name, loaddr, hiaddr);
+    }
+    load_bias = load_addr - loaddr;
+
+#ifdef CONFIG_USE_FDPIC
+    {
+        struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
+            g_malloc(sizeof(*loadsegs) * info->nsegs);
+
+        for (i = 0; i < ehdr->e_phnum; ++i) {
+            switch (phdr[i].p_type) {
+            case PT_DYNAMIC:
+                info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
+                break;
+            case PT_LOAD:
+                loadsegs->addr = phdr[i].p_vaddr + load_bias;
+                loadsegs->p_vaddr = phdr[i].p_vaddr;
+                loadsegs->p_memsz = phdr[i].p_memsz;
+                ++loadsegs;
+                break;
             }
-            qemu_log("Relocating guest address space from 0x"
-                     TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start);
-            guest_base = real_start - loaddr;
         }
-#endif
     }
-    load_bias = load_addr - loaddr;
+#endif
 
     info->load_bias = load_bias;
     info->load_addr = load_addr;
@@ -1479,9 +1731,9 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
 {
     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
     struct elf_shdr *shdr;
-    char *strings;
-    struct syminfo *s;
-    struct elf_sym *syms, *new_syms;
+    char *strings = NULL;
+    struct syminfo *s = NULL;
+    struct elf_sym *new_syms, *syms = NULL;
 
     shnum = hdr->e_shnum;
     i = shnum * sizeof(struct elf_shdr);
@@ -1506,24 +1758,19 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
     /* Now know where the strtab and symtab are.  Snarf them.  */
     s = malloc(sizeof(*s));
     if (!s) {
-        return;
+        goto give_up;
     }
 
     i = shdr[str_idx].sh_size;
     s->disas_strtab = strings = malloc(i);
     if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
-        free(s);
-        free(strings);
-        return;
+        goto give_up;
     }
 
     i = shdr[sym_idx].sh_size;
     syms = malloc(i);
     if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
-        free(s);
-        free(strings);
-        free(syms);
-        return;
+        goto give_up;
     }
 
     nsyms = i / sizeof(struct elf_sym);
@@ -1546,16 +1793,18 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
         }
     }
 
+    /* No "useful" symbol.  */
+    if (nsyms == 0) {
+        goto give_up;
+    }
+
     /* Attempt to free the storage associated with the local symbols
        that we threw away.  Whether or not this has any effect on the
        memory allocation depends on the malloc implementation and how
        many symbols we managed to discard.  */
     new_syms = realloc(syms, nsyms * sizeof(*syms));
     if (new_syms == NULL) {
-        free(s);
-        free(syms);
-        free(strings);
-        return;
+        goto give_up;
     }
     syms = new_syms;
 
@@ -1570,6 +1819,13 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
     s->lookup_symbol = lookup_symbolxx;
     s->next = syminfos;
     syminfos = s;
+
+    return;
+
+give_up:
+    free(s);
+    free(strings);
+    free(syms);
 }
 
 int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
@@ -1627,11 +1883,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->start_stack = bprm->p;
 
     /* If we have an interpreter, set that as the program's entry point.
-       Copy the load_addr as well, to help PPC64 interpret the entry
+       Copy the load_bias as well, to help PPC64 interpret the entry
        point as a function descriptor.  Do this after creating elf tables
        so that we copy the original program entry point into the AUXV.  */
     if (elf_interpreter) {
-        info->load_addr = interp_info.load_addr;
+        info->load_bias = interp_info.load_bias;
         info->entry = interp_info.entry;
         free(elf_interpreter);
     }
@@ -1690,19 +1946,20 @@ struct memelfnote {
     size_t     namesz_rounded;
     int        type;
     size_t     datasz;
+    size_t     datasz_rounded;
     void       *data;
     size_t     notesz;
 };
 
 struct target_elf_siginfo {
-    int  si_signo; /* signal number */
-    int  si_code;  /* extra code */
-    int  si_errno; /* errno */
+    target_int  si_signo; /* signal number */
+    target_int  si_code;  /* extra code */
+    target_int  si_errno; /* errno */
 };
 
 struct target_elf_prstatus {
     struct target_elf_siginfo pr_info;      /* Info associated with signal */
-    short              pr_cursig;    /* Current signal */
+    target_short       pr_cursig;    /* Current signal */
     target_ulong       pr_sigpend;   /* XXX */
     target_ulong       pr_sighold;   /* XXX */
     target_pid_t       pr_pid;
@@ -1714,7 +1971,7 @@ struct target_elf_prstatus {
     struct target_timeval pr_cutime; /* XXX Cumulative user time */
     struct target_timeval pr_cstime; /* XXX Cumulative system time */
     target_elf_gregset_t      pr_reg;       /* GP registers */
-    int                pr_fpvalid;   /* XXX */
+    target_int         pr_fpvalid;   /* XXX */
 };
 
 #define ELF_PRARGSZ     (80) /* Number of chars for args */
@@ -1857,7 +2114,7 @@ static struct mm_struct *vma_init(void)
 {
     struct mm_struct *mm;
 
-    if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
+    if ((mm = g_malloc(sizeof (*mm))) == NULL)
         return (NULL);
 
     mm->mm_count = 0;
@@ -1872,9 +2129,9 @@ static void vma_delete(struct mm_struct *mm)
 
     while ((vma = vma_first(mm)) != NULL) {
         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
-        qemu_free(vma);
+        g_free(vma);
     }
-    qemu_free(mm);
+    g_free(mm);
 }
 
 static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
@@ -1882,7 +2139,7 @@ static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
 {
     struct vm_area_struct *vma;
 
-    if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
+    if ((vma = g_malloc0(sizeof (*vma))) == NULL)
         return (-1);
 
     vma->vma_start = start;
@@ -1965,7 +2222,9 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
     note->namesz = namesz;
     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
     note->type = type;
-    note->datasz = roundup(sz, sizeof (int32_t));;
+    note->datasz = sz;
+    note->datasz_rounded = roundup(sz, sizeof (int32_t));
+
     note->data = data;
 
     /*
@@ -1973,7 +2232,7 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
      * ELF document.
      */
     note->notesz = sizeof (struct elf_note) +
-        note->namesz_rounded + note->datasz;
+        note->namesz_rounded + note->datasz_rounded;
 }
 
 static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
@@ -2193,7 +2452,7 @@ static int write_note(struct memelfnote *men, int fd)
         return (-1);
     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
         return (-1);
-    if (dump_write(fd, men->data, men->datasz) != 0)
+    if (dump_write(fd, men->data, men->datasz_rounded) != 0)
         return (-1);
 
     return (0);
@@ -2204,7 +2463,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
     TaskState *ts = (TaskState *)env->opaque;
     struct elf_thread_status *ets;
 
-    ets = qemu_mallocz(sizeof (*ets));
+    ets = g_malloc0(sizeof (*ets));
     ets->num_notes = 1; /* only prstatus is dumped */
     fill_prstatus(&ets->prstatus, ts, 0);
     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
@@ -2228,13 +2487,13 @@ static int fill_note_info(struct elf_note_info *info,
 
     QTAILQ_INIT(&info->thread_list);
 
-    info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
+    info->notes = g_malloc0(NUMNOTES * sizeof (struct memelfnote));
     if (info->notes == NULL)
         return (-ENOMEM);
-    info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
+    info->prstatus = g_malloc0(sizeof (*info->prstatus));
     if (info->prstatus == NULL)
         return (-ENOMEM);
-    info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
+    info->psinfo = g_malloc0(sizeof (*info->psinfo));
     if (info->prstatus == NULL)
         return (-ENOMEM);
 
@@ -2275,12 +2534,12 @@ static void free_note_info(struct elf_note_info *info)
     while (!QTAILQ_EMPTY(&info->thread_list)) {
         ets = QTAILQ_FIRST(&info->thread_list);
         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
-        qemu_free(ets);
+        g_free(ets);
     }
 
-    qemu_free(info->prstatus);
-    qemu_free(info->psinfo);
-    qemu_free(info->notes);
+    g_free(info->prstatus);
+    g_free(info->psinfo);
+    g_free(info->notes);
 }
 
 static int write_note_info(struct elf_note_info *info, int fd)
@@ -2409,7 +2668,7 @@ static int elf_core_dump(int signr, const CPUState *env)
      * ELF specification wants data to start at page boundary so
      * we align it here.
      */
-    offset = roundup(offset, ELF_EXEC_PAGESIZE);
+    data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
     /*
      * Write program headers for memory regions mapped in
@@ -2432,6 +2691,7 @@ static int elf_core_dump(int signr, const CPUState *env)
             phdr.p_flags |= PF_X;
         phdr.p_align = ELF_EXEC_PAGESIZE;
 
+        bswap_phdr(&phdr, 1);
         dump_write(fd, &phdr, sizeof (phdr));
     }
 
@@ -2443,8 +2703,6 @@ static int elf_core_dump(int signr, const CPUState *env)
         goto out;
 
     /* align data to page boundary */
-    data_offset = lseek(fd, 0, SEEK_CUR);
-    data_offset = TARGET_PAGE_ALIGN(data_offset);
     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
         goto out;
 
index 8f9f4a5fcceaffe8737e1c8dde4643bb8c9e11ef..1062da3852106effbb6c6a259429b39c6e0b0e3a 100644 (file)
@@ -41,6 +41,8 @@
 
 #include "qemu.h"
 #include "flat.h"
+#define ntohl(x) be32_to_cpu(x)
+#include <target_flat.h>
 
 //#define DEBUG
 
 #define        DBG_FLT(...)
 #endif
 
-#define flat_reloc_valid(reloc, size)             ((reloc) <= (size))
-#define flat_old_ram_flag(flag)                   (flag)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define flat_get_relocate_addr(relval)            (relval)
-#else
-#define flat_get_relocate_addr(relval)            bswap32(relval)
-#endif
-
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
 #define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused library */
 
@@ -78,8 +72,6 @@ static int load_flat_shared_library(int id, struct lib_info *p);
 
 struct linux_binprm;
 
-#define ntohl(x) be32_to_cpu(x)
-
 /****************************************************************************/
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
@@ -387,12 +379,11 @@ static int load_flat_file(struct linux_binprm * bprm,
     abi_long result;
     abi_ulong realdatastart = 0;
     abi_ulong text_len, data_len, bss_len, stack_len, flags;
-    abi_ulong memp = 0; /* for finding the brk area */
     abi_ulong extra;
     abi_ulong reloc = 0, rp;
     int i, rev, relocs = 0;
     abi_ulong fpos;
-    abi_ulong start_code, end_code;
+    abi_ulong start_code;
     abi_ulong indx_len;
 
     hdr = ((struct flat_hdr *) bprm->buf);             /* exec-header */
@@ -499,7 +490,6 @@ static int load_flat_file(struct linux_binprm * bprm,
         }
 
         reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
-        memp = realdatastart;
 
     } else {
 
@@ -514,7 +504,6 @@ static int load_flat_file(struct linux_binprm * bprm,
         realdatastart = textpos + ntohl(hdr->data_start);
         datapos = realdatastart + indx_len;
         reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
-        memp = textpos;
 
 #ifdef CONFIG_BINFMT_ZFLAT
 #error code needs checking
@@ -560,11 +549,10 @@ static int load_flat_file(struct linux_binprm * bprm,
 
     /* The main program needs a little extra setup in the task structure */
     start_code = textpos + sizeof (struct flat_hdr);
-    end_code = textpos + text_len;
 
     DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
             id ? "Lib" : "Load", bprm->filename,
-            (int) start_code, (int) end_code,
+            (int) start_code, (int) (textpos + text_len),
             (int) datapos,
             (int) (datapos + data_len),
             (int) (datapos + data_len),
@@ -625,6 +613,7 @@ static int load_flat_file(struct linux_binprm * bprm,
      * __start to address 4 so that is okay).
      */
     if (rev > OLD_FLAT_VERSION) {
+        abi_ulong persistent = 0;
         for (i = 0; i < relocs; i++) {
             abi_ulong addr, relval;
 
@@ -633,6 +622,9 @@ static int load_flat_file(struct linux_binprm * bprm,
                relocated first).  */
             if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
                 return -EFAULT;
+            relval = ntohl(relval);
+            if (flat_set_persistent(relval, &persistent))
+                continue;
             addr = flat_get_relocate_addr(relval);
             rp = calc_reloc(addr, libinfo, id, 1);
             if (rp == RELOC_FAILED)
@@ -641,22 +633,20 @@ static int load_flat_file(struct linux_binprm * bprm,
             /* Get the pointer's value.  */
             if (get_user_ual(addr, rp))
                 return -EFAULT;
+            addr = flat_get_addr_from_rp(rp, relval, flags, &persistent);
             if (addr != 0) {
                 /*
                  * Do the relocation.  PIC relocs in the data section are
                  * already in target order
                  */
-
-#ifndef TARGET_WORDS_BIGENDIAN
                 if ((flags & FLAT_FLAG_GOTPIC) == 0)
-                    addr = bswap32(addr);
-#endif
+                    addr = ntohl(addr);
                 addr = calc_reloc(addr, libinfo, id, 0);
                 if (addr == RELOC_FAILED)
                     return -ENOEXEC;
 
                 /* Write back the relocated pointer.  */
-                if (put_user_ual(addr, rp))
+                if (flat_put_addr_at_rp(rp, addr, relval))
                     return -EFAULT;
             }
         }
@@ -733,8 +723,15 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
      * pedantic and include space for the argv/envp array as it may have
      * a lot of entries.
      */
-#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
-    stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
+    stack_len = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        /* the argv strings */
+        stack_len += strlen(bprm->argv[i]);
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        /* the envp strings */
+        stack_len += strlen(bprm->envp[i]);
+    }
     stack_len += (bprm->argc + 1) * 4; /* the argv array */
     stack_len += (bprm->envc + 1) * 4; /* the envp array */
 
@@ -775,7 +772,8 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     stack_len *= sizeof(abi_ulong);
     if ((sp + stack_len) & 15)
         sp -= 16 - ((sp + stack_len) & 15);
-    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
+                             flat_argvp_envp_on_stack());
 
     /* Fake some return addresses to ensure the call chain will
      * initialise library in order for us.  We are required to call
index 3ef71ce0046616ec8714ca488c0c8dad19b30821..74abfcacb410a64cdf036b6d93aec7e6cee18c21 100644 (file)
 #define TARGET_NR_dup3                 330
 #define TARGET_NR_pipe2                331
 #define TARGET_NR_inotify_init1        332
+#define TARGET_NR_preadv                333
+#define TARGET_NR_pwritev               334
+#define TARGET_NR_rt_tgsigqueueinfo     335
+#define TARGET_NR_perf_event_open       336
+#define TARGET_NR_recvmmsg              337
+#define TARGET_NR_fanotify_init         338
+#define TARGET_NR_fanotify_mark         339
+#define TARGET_NR_prlimit64             340
+#define TARGET_NR_name_to_handle_at     341
+#define TARGET_NR_open_by_handle_at     342
+#define TARGET_NR_clock_adjtime         343
+#define TARGET_NR_syncfs                344
index 526aaa2a7649fc2d163edd5fe0cee15bf0c1aafc..6514502dc479b9a983bcddf037ea066e8ec4c9cb 100644 (file)
      IOCTL(KDSKBMODE, 0, TYPE_INT)
      IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
      IOCTL(KDGKBSENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbsentry)))
+     IOCTL(KDGKBLED, 0, TYPE_INT)
+     IOCTL(KDSKBLED, 0, TYPE_INT)
+     IOCTL(KDGETLED, 0, TYPE_INT)
+     IOCTL(KDSETLED, 0, TYPE_INT)
 
      IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
      IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
   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)
   IOCTL(FBIOGET_FSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_fix_screeninfo)))
   IOCTL(FBIOGET_VSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
   IOCTL(FBIOPUT_VSCREENINFO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
+  IOCTL(FBIOGETCMAP,        IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap)))
+  IOCTL(FBIOPUTCMAP,        IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap)))
+  IOCTL(FBIOPAN_DISPLAY,    IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
+  IOCTL(FBIOGET_CON2FBMAP,  IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap)))
+  IOCTL(FBIOPUT_CON2FBMAP,  IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap)))
 
   IOCTL(VT_OPENQRY, IOC_R, MK_PTR(TYPE_INT))
   IOCTL(VT_GETSTATE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_vt_stat)))
   IOCTL(VT_WAITACTIVE, 0, TYPE_INT)
   IOCTL(VT_LOCKSWITCH, 0, TYPE_INT)
   IOCTL(VT_UNLOCKSWITCH, 0, TYPE_INT)
+  IOCTL(VT_GETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode)))
+  IOCTL(VT_SETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode)))
+  IOCTL(VT_RELDISP, 0, TYPE_INT)
+  IOCTL(VT_DISALLOCATE, 0, TYPE_INT)
index ac8c486c5f2329bf56d50037a2b5bf01d5e8d737..b47025f08a7a14ea516fe5f82679782ae02394f7 100644 (file)
@@ -26,22 +26,6 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
     return 0;
 }
 
-static int in_group_p(gid_t g)
-{
-    /* return TRUE if we're in the specified group, FALSE otherwise */
-    int                ngroup;
-    int                i;
-    gid_t      grouplist[NGROUPS];
-
-    ngroup = getgroups(NGROUPS, grouplist);
-    for(i = 0; i < ngroup; i++) {
-       if(grouplist[i] == g) {
-           return 1;
-       }
-    }
-    return 0;
-}
-
 static int count(char ** vec)
 {
     int                i;
@@ -57,7 +41,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
 {
     struct stat                st;
     int mode;
-    int retval, id_change;
+    int retval;
 
     if(fstat(bprm->fd, &st) < 0) {
        return(-errno);
@@ -73,14 +57,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
 
     bprm->e_uid = geteuid();
     bprm->e_gid = getegid();
-    id_change = 0;
 
     /* Set-uid? */
     if(mode & S_ISUID) {
        bprm->e_uid = st.st_uid;
-       if(bprm->e_uid != geteuid()) {
-           id_change = 1;
-       }
     }
 
     /* Set-gid? */
@@ -91,9 +71,6 @@ static int prepare_binprm(struct linux_binprm *bprm)
      */
     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
        bprm->e_gid = st.st_gid;
-       if (!in_group_p(bprm->e_gid)) {
-               id_change = 1;
-       }
     }
 
     retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
@@ -201,7 +178,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     /* Something went wrong, return the inode and free the argument pages*/
     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-        free(bprm->page[i]);
+        g_free(bprm->page[i]);
     }
     return(retval);
 }
index 1c0ba07bfb5848fc524c92705cc25b021fd5199c..4d0937e5059be9a2e9d3c5abdc22601f5ff6522b 100644 (file)
 #define TARGET_NR_dup3                 326
 #define TARGET_NR_pipe2                327
 #define TARGET_NR_inotify_init1        328
+#define TARGET_NR_inotify_init1         328
+#define TARGET_NR_preadv                329
+#define TARGET_NR_pwritev               330
+#define TARGET_NR_rt_tgsigqueueinfo     331
+#define TARGET_NR_perf_event_open       332
+#define TARGET_NR_get_thread_area       333
+#define TARGET_NR_set_thread_area       334
+#define TARGET_NR_atomic_cmpxchg_32     335
+#define TARGET_NR_atomic_barrier        336
+#define TARGET_NR_fanotify_init         337
+#define TARGET_NR_fanotify_mark         338
+#define TARGET_NR_prlimit64             339
+#define TARGET_NR_name_to_handle_at     340
+#define TARGET_NR_open_by_handle_at     341
+#define TARGET_NR_clock_adjtime         342
+#define TARGET_NR_syncfs                343
index 0d627d68dd387120b0d861e8bda48812f75c0fc1..d1bbc577e5fc390a5550497d2809e3d418a4af17 100644 (file)
@@ -29,8 +29,7 @@
 #include "qemu.h"
 #include "qemu-common.h"
 #include "cache-utils.h"
-/* For tb_lock */
-#include "exec-all.h"
+#include "cpu.h"
 #include "tcg.h"
 #include "qemu-timer.h"
 #include "envlist.h"
 char *exec_path;
 
 int singlestep;
+const char *filename;
+const char *argv0;
+int gdbstub_port;
+envlist_t *envlist;
+const char *cpu_model;
 unsigned long mmap_min_addr;
 #if defined(CONFIG_USE_GUEST_BASE)
 unsigned long guest_base;
@@ -47,6 +51,8 @@ int have_guest_base;
 unsigned long reserved_va;
 #endif
 
+static void usage(void);
+
 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 
@@ -319,11 +325,12 @@ void cpu_loop(CPUX86State *env)
                                           env->regs[R_EDX],
                                           env->regs[R_ESI],
                                           env->regs[R_EDI],
-                                          env->regs[R_EBP]);
+                                          env->regs[R_EBP],
+                                          0, 0);
             break;
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
-            /* linux syscall from syscall intruction */
+            /* linux syscall from syscall instruction */
             env->regs[R_EAX] = do_syscall(env,
                                           env->regs[R_EAX],
                                           env->regs[R_EDI],
@@ -331,7 +338,8 @@ void cpu_loop(CPUX86State *env)
                                           env->regs[R_EDX],
                                           env->regs[10],
                                           env->regs[8],
-                                          env->regs[9]);
+                                          env->regs[9],
+                                          0, 0);
             env->eip = env->exception_next_eip;
             break;
 #endif
@@ -455,22 +463,81 @@ void cpu_loop(CPUX86State *env)
 
 #ifdef TARGET_ARM
 
-static void arm_cache_flush(abi_ulong start, abi_ulong last)
+/*
+ * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
+ * Input:
+ * r0 = pointer to oldval
+ * r1 = pointer to newval
+ * r2 = pointer to target value
+ *
+ * Output:
+ * r0 = 0 if *ptr was changed, non-0 if no exchange happened
+ * C set if *ptr was changed, clear if no exchange happened
+ *
+ * Note segv's in kernel helpers are a bit tricky, we can set the
+ * data address sensibly but the PC address is just the entry point.
+ */
+static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
 {
-    abi_ulong addr, last1;
+    uint64_t oldval, newval, val;
+    uint32_t addr, cpsr;
+    target_siginfo_t info;
 
-    if (last < start)
-        return;
-    addr = start;
-    for(;;) {
-        last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
-        if (last1 > last)
-            last1 = last;
-        tb_invalidate_page_range(addr, last1 + 1);
-        if (last1 == last)
-            break;
-        addr = last1 + 1;
+    /* Based on the 32 bit code in do_kernel_trap */
+
+    /* XXX: This only works between threads, not between processes.
+       It's probably possible to implement this with native host
+       operations. However things like ldrex/strex are much harder so
+       there's not much point trying.  */
+    start_exclusive();
+    cpsr = cpsr_read(env);
+    addr = env->regs[2];
+
+    if (get_user_u64(oldval, env->regs[0])) {
+        env->cp15.c6_data = env->regs[0];
+        goto segv;
+    };
+
+    if (get_user_u64(newval, env->regs[1])) {
+        env->cp15.c6_data = env->regs[1];
+        goto segv;
+    };
+
+    if (get_user_u64(val, addr)) {
+        env->cp15.c6_data = addr;
+        goto segv;
     }
+
+    if (val == oldval) {
+        val = newval;
+
+        if (put_user_u64(val, addr)) {
+            env->cp15.c6_data = addr;
+            goto segv;
+        };
+
+        env->regs[0] = 0;
+        cpsr |= CPSR_C;
+    } else {
+        env->regs[0] = -1;
+        cpsr &= ~CPSR_C;
+    }
+    cpsr_write(env, cpsr, CPSR_C);
+    end_exclusive();
+    return;
+
+segv:
+    end_exclusive();
+    /* We get the PC of the entry address - which is as good as anything,
+       on a real kernel what you get depends on which mode it uses. */
+    info.si_signo = SIGSEGV;
+    info.si_errno = 0;
+    /* XXX: check env->error_code */
+    info.si_code = TARGET_SEGV_MAPERR;
+    info._sifields._sigfault._addr = env->cp15.c6_data;
+    queue_signal(env, info.si_signo, &info);
+
+    end_exclusive();
 }
 
 /* Handle a jump to the kernel code page.  */
@@ -512,6 +579,10 @@ do_kernel_trap(CPUARMState *env)
     case 0xffff0fe0: /* __kernel_get_tls */
         env->regs[0] = env->cp15.c13_tls2;
         break;
+    case 0xffff0f60: /* __kernel_cmpxchg64 */
+        arm_kernel_cmpxchg64_helper(env);
+        break;
+
     default:
         return 1;
     }
@@ -717,7 +788,7 @@ void cpu_loop(CPUARMState *env)
                 }
 
                 if (n == ARM_NR_cacheflush) {
-                    arm_cache_flush(env->regs[0], env->regs[1]);
+                    /* nop */
                 } else if (n == ARM_NR_semihosting
                            || n == ARM_NR_thumb_semihosting) {
                     env->regs[0] = do_arm_semihosting (env);
@@ -733,7 +804,7 @@ void cpu_loop(CPUARMState *env)
                     if ( n > ARM_NR_BASE) {
                         switch (n) {
                         case ARM_NR_cacheflush:
-                            arm_cache_flush(env->regs[0], env->regs[1]);
+                            /* nop */
                             break;
                         case ARM_NR_set_tls:
                             cpu_set_tls(env, env->regs[0]);
@@ -753,7 +824,8 @@ void cpu_loop(CPUARMState *env)
                                                   env->regs[2],
                                                   env->regs[3],
                                                   env->regs[4],
-                                                  env->regs[5]);
+                                                  env->regs[5],
+                                                  0, 0);
                     }
                 } else {
                     goto error;
@@ -768,7 +840,6 @@ void cpu_loop(CPUARMState *env)
             goto do_segv;
         case EXCP_DATA_ABORT:
             addr = env->cp15.c6_data;
-            goto do_segv;
         do_segv:
             {
                 info.si_signo = SIGSEGV;
@@ -816,6 +887,84 @@ 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],
+                                                  0, 0);
+                    }
+                } 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
 
@@ -959,7 +1108,8 @@ void cpu_loop (CPUSPARCState *env)
             ret = do_syscall (env, env->gregs[1],
                               env->regwptr[0], env->regwptr[1],
                               env->regwptr[2], env->regwptr[3],
-                              env->regwptr[4], env->regwptr[5]);
+                              env->regwptr[4], env->regwptr[5],
+                              0, 0);
             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
                 env->xcc |= PSR_CARRY;
@@ -998,7 +1148,7 @@ void cpu_loop (CPUSPARCState *env)
         case TT_TFAULT:
         case TT_DFAULT:
             {
-                info.si_signo = SIGSEGV;
+                info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 /* XXX: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
@@ -1016,7 +1166,7 @@ void cpu_loop (CPUSPARCState *env)
         case TT_TFAULT:
         case TT_DFAULT:
             {
-                info.si_signo = SIGSEGV;
+                info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 /* XXX: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
@@ -1041,6 +1191,15 @@ void cpu_loop (CPUSPARCState *env)
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
             break;
+        case TT_ILL_INSN:
+            {
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLOPC;
+                info._sifields._sigfault._addr = env->pc;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
         case EXCP_DEBUG:
             {
                 int sig;
@@ -1182,7 +1341,7 @@ void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
     int trapnr;
-    uint32_t ret;
+    target_ulong ret;
 
     for(;;) {
         cpu_exec_start(env);
@@ -1545,27 +1704,20 @@ void cpu_loop(CPUPPCState *env)
              * PPC ABI uses overflow flag in cr0 to signal an error
              * in syscalls.
              */
-#if 0
-            printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
-                   env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
-#endif
             env->crf[0] &= ~0x1;
             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
                              env->gpr[5], env->gpr[6], env->gpr[7],
-                             env->gpr[8]);
-            if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+                             env->gpr[8], 0, 0);
+            if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid corrupting register state.  */
                 break;
             }
-            if (ret > (uint32_t)(-515)) {
+            if (ret > (target_ulong)(-515)) {
                 env->crf[0] |= 0x1;
                 ret = -ret;
             }
             env->gpr[3] = ret;
-#if 0
-            printf("syscall returned 0x%08x (%d)\n", ret, ret);
-#endif
             break;
         case POWERPC_EXCP_STCX:
             if (do_store_exclusive(env)) {
@@ -1606,7 +1758,7 @@ void cpu_loop(CPUPPCState *env)
 #define MIPS_SYS(name, args) args,
 
 static const uint8_t mips_syscall_args[] = {
-       MIPS_SYS(sys_syscall    , 0)    /* 4000 */
+       MIPS_SYS(sys_syscall    , 8)    /* 4000 */
        MIPS_SYS(sys_exit       , 1)
        MIPS_SYS(sys_fork       , 0)
        MIPS_SYS(sys_read       , 3)
@@ -1812,7 +1964,7 @@ static const uint8_t mips_syscall_args[] = {
        MIPS_SYS(sys_getcwd     , 2)
        MIPS_SYS(sys_capget     , 2)
        MIPS_SYS(sys_capset     , 2)    /* 4205 */
-       MIPS_SYS(sys_sigaltstack        , 0)
+       MIPS_SYS(sys_sigaltstack        , 2)
        MIPS_SYS(sys_sendfile   , 4)
        MIPS_SYS(sys_ni_syscall , 0)
        MIPS_SYS(sys_ni_syscall , 0)
@@ -1922,6 +2074,33 @@ static const uint8_t mips_syscall_args[] = {
        MIPS_SYS(sys_epoll_pwait, 6)
        MIPS_SYS(sys_ioprio_set, 3)
        MIPS_SYS(sys_ioprio_get, 2)
+        MIPS_SYS(sys_utimensat, 4)
+        MIPS_SYS(sys_signalfd, 3)
+        MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
+        MIPS_SYS(sys_eventfd, 1)
+        MIPS_SYS(sys_fallocate, 6)      /* 4320 */
+        MIPS_SYS(sys_timerfd_create, 2)
+        MIPS_SYS(sys_timerfd_gettime, 2)
+        MIPS_SYS(sys_timerfd_settime, 4)
+        MIPS_SYS(sys_signalfd4, 4)
+        MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
+        MIPS_SYS(sys_epoll_create1, 1)
+        MIPS_SYS(sys_dup3, 3)
+        MIPS_SYS(sys_pipe2, 2)
+        MIPS_SYS(sys_inotify_init1, 1)
+        MIPS_SYS(sys_preadv, 6)         /* 4330 */
+        MIPS_SYS(sys_pwritev, 6)
+        MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
+        MIPS_SYS(sys_perf_event_open, 5)
+        MIPS_SYS(sys_accept4, 4)
+        MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
+        MIPS_SYS(sys_fanotify_init, 2)
+        MIPS_SYS(sys_fanotify_mark, 6)
+        MIPS_SYS(sys_prlimit64, 4)
+        MIPS_SYS(sys_name_to_handle_at, 5)
+        MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
+        MIPS_SYS(sys_clock_adjtime, 2)
+        MIPS_SYS(sys_syncfs, 1)
 };
 
 #undef MIPS_SYS
@@ -1990,7 +2169,7 @@ void cpu_loop(CPUMIPSState *env)
             syscall_num = env->active_tc.gpr[2] - 4000;
             env->active_tc.PC += 4;
             if (syscall_num >= sizeof(mips_syscall_args)) {
-                ret = -ENOSYS;
+                ret = -TARGET_ENOSYS;
             } else {
                 int nb_args;
                 abi_ulong sp_reg;
@@ -2000,11 +2179,22 @@ void cpu_loop(CPUMIPSState *env)
                 sp_reg = env->active_tc.gpr[29];
                 switch (nb_args) {
                 /* these arguments are taken from the stack */
-                /* FIXME - what to do if get_user() fails? */
-                case 8: get_user_ual(arg8, sp_reg + 28);
-                case 7: get_user_ual(arg7, sp_reg + 24);
-                case 6: get_user_ual(arg6, sp_reg + 20);
-                case 5: get_user_ual(arg5, sp_reg + 16);
+                case 8:
+                    if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
+                        goto done_syscall;
+                    }
+                case 7:
+                    if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
+                        goto done_syscall;
+                    }
+                case 6:
+                    if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
+                        goto done_syscall;
+                    }
+                case 5:
+                    if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
+                        goto done_syscall;
+                    }
                 default:
                     break;
                 }
@@ -2013,8 +2203,9 @@ void cpu_loop(CPUMIPSState *env)
                                  env->active_tc.gpr[5],
                                  env->active_tc.gpr[6],
                                  env->active_tc.gpr[7],
-                                 arg5, arg6/*, arg7, arg8*/);
+                                 arg5, arg6, arg7, arg8);
             }
+done_syscall:
             if (ret == -TARGET_QEMU_ESIGRETURN) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid clobbering register state.  */
@@ -2030,6 +2221,8 @@ void cpu_loop(CPUMIPSState *env)
             break;
         case EXCP_TLBL:
         case EXCP_TLBS:
+        case EXCP_AdEL:
+        case EXCP_AdES:
             info.si_signo = TARGET_SIGSEGV;
             info.si_errno = 0;
             /* XXX: check env->error_code */
@@ -2101,7 +2294,8 @@ void cpu_loop (CPUState *env)
                              env->gregs[6],
                              env->gregs[7],
                              env->gregs[0],
-                             env->gregs[1]);
+                             env->gregs[1],
+                             0, 0);
             env->gregs[0] = ret;
             break;
         case EXCP_INTERRUPT:
@@ -2170,7 +2364,8 @@ void cpu_loop (CPUState *env)
                              env->regs[12], 
                              env->regs[13], 
                              env->pregs[7], 
-                             env->pregs[11]);
+                             env->pregs[11],
+                             0, 0);
             env->regs[10] = ret;
             break;
         case EXCP_DEBUG:
@@ -2229,7 +2424,8 @@ void cpu_loop (CPUState *env)
                              env->regs[7], 
                              env->regs[8], 
                              env->regs[9], 
-                             env->regs[10]);
+                             env->regs[10],
+                             0, 0);
             env->regs[3] = ret;
             env->sregs[SR_PC] = env->regs[14];
             break;
@@ -2244,6 +2440,13 @@ void cpu_loop (CPUState *env)
             env->iflags &= ~(IMM_FLAG | D_FLAG);
 
             switch (env->sregs[SR_ESR] & 31) {
+                case ESR_EC_DIVZERO:
+                    info.si_signo = SIGFPE;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_FPE_FLTDIV;
+                    info._sifields._sigfault._addr = 0;
+                    queue_signal(env, info.si_signo, &info);
+                    break;
                 case ESR_EC_FPU:
                     info.si_signo = SIGFPE;
                     info.si_errno = 0;
@@ -2258,7 +2461,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;
@@ -2339,7 +2542,8 @@ void cpu_loop(CPUM68KState *env)
                                           env->dregs[3],
                                           env->dregs[4],
                                           env->dregs[5],
-                                          env->aregs[0]);
+                                          env->aregs[0],
+                                          0, 0);
             }
             break;
         case EXCP_INTERRUPT:
@@ -2449,49 +2653,27 @@ void cpu_loop (CPUState *env)
             fprintf(stderr, "Machine check exception. Exit\n");
             exit(1);
             break;
-        case EXCP_ARITH:
-            env->lock_addr = -1;
-            info.si_signo = TARGET_SIGFPE;
-            info.si_errno = 0;
-            info.si_code = TARGET_FPE_FLTINV;
-            info._sifields._sigfault._addr = env->pc;
-            queue_signal(env, info.si_signo, &info);
-            break;
-        case EXCP_HW_INTERRUPT:
+        case EXCP_SMP_INTERRUPT:
+        case EXCP_CLK_INTERRUPT:
+        case EXCP_DEV_INTERRUPT:
             fprintf(stderr, "External interrupt. Exit\n");
             exit(1);
             break;
-        case EXCP_DFAULT:
+        case EXCP_MMFAULT:
             env->lock_addr = -1;
             info.si_signo = TARGET_SIGSEGV;
             info.si_errno = 0;
-            info.si_code = (page_get_flags(env->ipr[IPR_EXC_ADDR]) & PAGE_VALID
+            info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
                             ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
-            info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+            info._sifields._sigfault._addr = env->trap_arg0;
             queue_signal(env, info.si_signo, &info);
             break;
-        case EXCP_DTB_MISS_PAL:
-            fprintf(stderr, "MMU data TLB miss in PALcode\n");
-            exit(1);
-            break;
-        case EXCP_ITB_MISS:
-            fprintf(stderr, "MMU instruction TLB miss\n");
-            exit(1);
-            break;
-        case EXCP_ITB_ACV:
-            fprintf(stderr, "MMU instruction access violation\n");
-            exit(1);
-            break;
-        case EXCP_DTB_MISS_NATIVE:
-            fprintf(stderr, "MMU data TLB miss\n");
-            exit(1);
-            break;
         case EXCP_UNALIGN:
             env->lock_addr = -1;
             info.si_signo = TARGET_SIGBUS;
             info.si_errno = 0;
             info.si_code = TARGET_BUS_ADRALN;
-            info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+            info._sifields._sigfault._addr = env->trap_arg0;
             queue_signal(env, info.si_signo, &info);
             break;
         case EXCP_OPCDEC:
@@ -2503,12 +2685,20 @@ void cpu_loop (CPUState *env)
             info._sifields._sigfault._addr = env->pc;
             queue_signal(env, info.si_signo, &info);
             break;
+        case EXCP_ARITH:
+            env->lock_addr = -1;
+            info.si_signo = TARGET_SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_FLTINV;
+            info._sifields._sigfault._addr = env->pc;
+            queue_signal(env, info.si_signo, &info);
+            break;
         case EXCP_FEN:
             /* No-op.  Linux simply re-enables the FPU.  */
             break;
-        case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+        case EXCP_CALL_PAL:
             env->lock_addr = -1;
-            switch ((trapnr >> 6) | 0x80) {
+            switch (env->error_code) {
             case 0x80:
                 /* BPT */
                 info.si_signo = TARGET_SIGTRAP;
@@ -2531,7 +2721,8 @@ void cpu_loop (CPUState *env)
                 sysret = do_syscall(env, trapnr,
                                     env->ir[IR_A0], env->ir[IR_A1],
                                     env->ir[IR_A2], env->ir[IR_A3],
-                                    env->ir[IR_A4], env->ir[IR_A5]);
+                                    env->ir[IR_A4], env->ir[IR_A5],
+                                    0, 0);
                 if (trapnr == TARGET_NR_sigreturn
                     || trapnr == TARGET_NR_rt_sigreturn) {
                     break;
@@ -2599,8 +2790,6 @@ void cpu_loop (CPUState *env)
                 goto do_sigill;
             }
             break;
-        case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
-            goto do_sigill;
         case EXCP_DEBUG:
             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
             if (info.si_signo) {
@@ -2624,50 +2813,81 @@ void cpu_loop (CPUState *env)
 }
 #endif /* TARGET_ALPHA */
 
-static void usage(void)
+#ifdef TARGET_S390X
+void cpu_loop(CPUS390XState *env)
 {
-    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
-           "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
-           "Linux CPU emulator (compiled for %s emulation)\n"
-           "\n"
-           "Standard options:\n"
-           "-h                print this help\n"
-           "-g port           wait gdb connection to port\n"
-           "-L path           set the elf interpreter prefix (default=%s)\n"
-           "-s size           set the stack size in bytes (default=%ld)\n"
-           "-cpu model        select CPU (-cpu ? for list)\n"
-           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
-           "-E var=value      sets/modifies targets environment variable(s)\n"
-           "-U var            unsets targets environment variable(s)\n"
-           "-0 argv0          forces target process argv[0] to be argv0\n"
-#if defined(CONFIG_USE_GUEST_BASE)
-           "-B address        set guest_base address to address\n"
-           "-R size           reserve size bytes for guest virtual address space\n"
-#endif
-           "\n"
-           "Debug options:\n"
-           "-d options   activate log (logfile=%s)\n"
-           "-p pagesize  set the host page size to 'pagesize'\n"
-           "-singlestep  always run in singlestep mode\n"
-           "-strace      log system calls\n"
-           "\n"
-           "Environment variables:\n"
-           "QEMU_STRACE       Print system calls and arguments similar to the\n"
-           "                  'strace' program.  Enable by setting to any value.\n"
-           "You can use -E and -U options to set/unset environment variables\n"
-           "for target process.  It is possible to provide several variables\n"
-           "by repeating the option.  For example:\n"
-           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
-           "Note that if you provide several changes to single variable\n"
-           "last change will stay in effect.\n"
-           ,
-           TARGET_ARCH,
-           interp_prefix,
-           guest_stack_size,
-           DEBUG_LOGFILE);
-    exit(1);
+    int trapnr;
+    target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_s390x_exec (env);
+
+        switch (trapnr) {
+        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;
+        case EXCP_SVC:
+            {
+                int n = env->int_svc_code;
+                if (!n) {
+                    /* syscalls > 255 */
+                    n = env->regs[1];
+                }
+                env->psw.addr += env->int_svc_ilc;
+                env->regs[2] = do_syscall(env, n,
+                           env->regs[2],
+                           env->regs[3],
+                           env->regs[4],
+                           env->regs[5],
+                           env->regs[6],
+                           env->regs[7],
+                           0, 0);
+            }
+            break;
+        case EXCP_ADDR:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->__excp_addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_SPEC:
+            {
+                fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4));
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLOPC;
+                info._sifields._sigfault._addr = env->__excp_addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
 }
 
+#endif /* TARGET_S390X */
+
 THREAD CPUState *thread_env;
 
 void task_settid(TaskState *ts)
@@ -2703,35 +2923,363 @@ void init_task_state(TaskState *ts)
     }
     ts->sigqueue_table[i].next = NULL;
 }
+
+static void handle_arg_help(const char *arg)
+{
+    usage();
+}
+
+static void handle_arg_log(const char *arg)
+{
+    int mask;
+    const CPULogItem *item;
+
+    mask = cpu_str_to_log_mask(arg);
+    if (!mask) {
+        printf("Log items (comma separated):\n");
+        for (item = cpu_log_items; item->mask != 0; item++) {
+            printf("%-10s %s\n", item->name, item->help);
+        }
+        exit(1);
+    }
+    cpu_set_log(mask);
+}
+
+static void handle_arg_set_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_setenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_unset_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_unsetenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_argv0(const char *arg)
+{
+    argv0 = strdup(arg);
+}
+
+static void handle_arg_stack_size(const char *arg)
+{
+    char *p;
+    guest_stack_size = strtoul(arg, &p, 0);
+    if (guest_stack_size == 0) {
+        usage();
+    }
+
+    if (*p == 'M') {
+        guest_stack_size *= 1024 * 1024;
+    } else if (*p == 'k' || *p == 'K') {
+        guest_stack_size *= 1024;
+    }
+}
+
+static void handle_arg_ld_prefix(const char *arg)
+{
+    interp_prefix = strdup(arg);
+}
+
+static void handle_arg_pagesize(const char *arg)
+{
+    qemu_host_page_size = atoi(arg);
+    if (qemu_host_page_size == 0 ||
+        (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+        fprintf(stderr, "page size must be a power of two\n");
+        exit(1);
+    }
+}
+
+static void handle_arg_gdb(const char *arg)
+{
+    gdbstub_port = atoi(arg);
+}
+
+static void handle_arg_uname(const char *arg)
+{
+    qemu_uname_release = strdup(arg);
+}
+
+static void handle_arg_cpu(const char *arg)
+{
+    cpu_model = strdup(arg);
+    if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
+        /* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list_id)
+        cpu_list_id(stdout, &fprintf, "");
+#elif defined(cpu_list)
+        cpu_list(stdout, &fprintf); /* deprecated */
+#endif
+        exit(1);
+    }
+}
+
+#if defined(CONFIG_USE_GUEST_BASE)
+static void handle_arg_guest_base(const char *arg)
+{
+    guest_base = strtol(arg, NULL, 0);
+    have_guest_base = 1;
+}
+
+static void handle_arg_reserved_va(const char *arg)
+{
+    char *p;
+    int shift = 0;
+    reserved_va = strtoul(arg, &p, 0);
+    switch (*p) {
+    case 'k':
+    case 'K':
+        shift = 10;
+        break;
+    case 'M':
+        shift = 20;
+        break;
+    case 'G':
+        shift = 30;
+        break;
+    }
+    if (shift) {
+        unsigned long unshifted = reserved_va;
+        p++;
+        reserved_va <<= shift;
+        if (((reserved_va >> shift) != unshifted)
+#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+            || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
+#endif
+            ) {
+            fprintf(stderr, "Reserved virtual address too big\n");
+            exit(1);
+        }
+    }
+    if (*p) {
+        fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
+        exit(1);
+    }
+}
+#endif
+
+static void handle_arg_singlestep(const char *arg)
+{
+    singlestep = 1;
+}
+
+static void handle_arg_strace(const char *arg)
+{
+    do_strace = 1;
+}
+
+static void handle_arg_version(const char *arg)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
+           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+    exit(0);
+}
+
+struct qemu_argument {
+    const char *argv;
+    const char *env;
+    bool has_arg;
+    void (*handle_opt)(const char *arg);
+    const char *example;
+    const char *help;
+};
+
+struct qemu_argument arg_table[] = {
+    {"h",          "",                 false, handle_arg_help,
+     "",           "print this help"},
+    {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
+     "port",       "wait gdb connection to 'port'"},
+    {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
+     "path",       "set the elf interpreter prefix to 'path'"},
+    {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
+     "size",       "set the stack size to 'size' bytes"},
+    {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
+     "model",      "select CPU (-cpu ? for list)"},
+    {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
+     "var=value",  "sets targets environment variable (see below)"},
+    {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
+     "var",        "unsets targets environment variable (see below)"},
+    {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
+     "argv0",      "forces target process argv[0] to be 'argv0'"},
+    {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
+     "uname",      "set qemu uname release string to 'uname'"},
+#if defined(CONFIG_USE_GUEST_BASE)
+    {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
+     "address",    "set guest_base address to 'address'"},
+    {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
+     "size",       "reserve 'size' bytes for guest virtual address space"},
+#endif
+    {"d",          "QEMU_LOG",         true,  handle_arg_log,
+     "options",    "activate log"},
+    {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
+     "pagesize",   "set the host page size to 'pagesize'"},
+    {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
+     "",           "run in singlestep mode"},
+    {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
+     "",           "log system calls"},
+    {"version",    "QEMU_VERSION",     false, handle_arg_version,
+     "",           "display version information and exit"},
+    {NULL, NULL, false, NULL, NULL, NULL}
+};
+
+static void usage(void)
+{
+    struct qemu_argument *arginfo;
+    int maxarglen;
+    int maxenvlen;
+
+    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+           "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
+           "\n"
+           "Options and associated environment variables:\n"
+           "\n");
+
+    maxarglen = maxenvlen = 0;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (strlen(arginfo->env) > maxenvlen) {
+            maxenvlen = strlen(arginfo->env);
+        }
+        if (strlen(arginfo->argv) > maxarglen) {
+            maxarglen = strlen(arginfo->argv);
+        }
+    }
+
+    printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
+            maxenvlen+1, "Env-variable");
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->has_arg) {
+            printf("-%s %-*s %-*s %s\n", arginfo->argv,
+                    (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
+                    maxenvlen, arginfo->env, arginfo->help);
+        } else {
+            printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
+                    maxenvlen, arginfo->env,
+                    arginfo->help);
+        }
+    }
+
+    printf("\n"
+           "Defaults:\n"
+           "QEMU_LD_PREFIX  = %s\n"
+           "QEMU_STACK_SIZE = %ld byte\n"
+           "QEMU_LOG        = %s\n",
+           interp_prefix,
+           guest_stack_size,
+           DEBUG_LOGFILE);
+
+    printf("\n"
+           "You can use -E and -U options or the QEMU_SET_ENV and\n"
+           "QEMU_UNSET_ENV environment variables to set and unset\n"
+           "environment variables for the target process.\n"
+           "It is possible to provide several variables by separating them\n"
+           "by commas in getsubopt(3) style. Additionally it is possible to\n"
+           "provide the -E and -U options multiple times.\n"
+           "The following lines are equivalent:\n"
+           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+           "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
+           "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
+           "Note that if you provide several changes to a single variable\n"
+           "the last change will stay in effect.\n");
+
+    exit(1);
+}
+
+static int parse_args(int argc, char **argv)
+{
+    const char *r;
+    int optind;
+    struct qemu_argument *arginfo;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->env == NULL) {
+            continue;
+        }
+
+        r = getenv(arginfo->env);
+        if (r != NULL) {
+            arginfo->handle_opt(r);
+        }
+    }
+
+    optind = 1;
+    for (;;) {
+        if (optind >= argc) {
+            break;
+        }
+        r = argv[optind];
+        if (r[0] != '-') {
+            break;
+        }
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        }
+
+        for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+            if (!strcmp(r, arginfo->argv)) {
+                if (arginfo->has_arg) {
+                    if (optind >= argc) {
+                        usage();
+                    }
+                    arginfo->handle_opt(argv[optind]);
+                    optind++;
+                } else {
+                    arginfo->handle_opt(NULL);
+                }
+                break;
+            }
+        }
+
+        /* no option matched the current argv */
+        if (arginfo->handle_opt == NULL) {
+            usage();
+        }
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+
+    filename = argv[optind];
+    exec_path = argv[optind];
+
+    return optind;
+}
+
 int main(int argc, char **argv, char **envp)
 {
-    const char *filename;
-    const char *cpu_model;
+    const char *log_file = DEBUG_LOGFILE;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     struct linux_binprm bprm;
     TaskState *ts;
     CPUState *env;
     int optind;
-    const char *r;
-    int gdbstub_port = 0;
     char **target_environ, **wrk;
     char **target_argv;
     int target_argc;
-    envlist_t *envlist = NULL;
-    const char *argv0 = NULL;
     int i;
     int ret;
 
-    if (argc <= 1)
-        usage();
-
     qemu_cache_utils_init(envp);
 
-    /* init debug */
-    cpu_set_log_filename(DEBUG_LOGFILE);
-
     if ((envlist = envlist_create()) == NULL) {
         (void) fprintf(stderr, "Unable to allocate envlist\n");
         exit(1);
@@ -2758,143 +3306,9 @@ int main(int argc, char **argv, char **envp)
     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 #endif
 
-    optind = 1;
-    for(;;) {
-        if (optind >= argc)
-            break;
-        r = argv[optind];
-        if (r[0] != '-')
-            break;
-        optind++;
-        r++;
-        if (!strcmp(r, "-")) {
-            break;
-        } else if (!strcmp(r, "d")) {
-            int mask;
-            const CPULogItem *item;
-
-           if (optind >= argc)
-               break;
-
-           r = argv[optind++];
-            mask = cpu_str_to_log_mask(r);
-            if (!mask) {
-                printf("Log items (comma separated):\n");
-                for(item = cpu_log_items; item->mask != 0; item++) {
-                    printf("%-10s %s\n", item->name, item->help);
-                }
-                exit(1);
-            }
-            cpu_set_log(mask);
-        } else if (!strcmp(r, "E")) {
-            r = argv[optind++];
-            if (envlist_setenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "ignore-environment")) {
-            envlist_free(envlist);
-            if ((envlist = envlist_create()) == NULL) {
-                (void) fprintf(stderr, "Unable to allocate envlist\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "U")) {
-            r = argv[optind++];
-            if (envlist_unsetenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "0")) {
-            r = argv[optind++];
-            argv0 = r;
-        } else if (!strcmp(r, "s")) {
-            if (optind >= argc)
-                break;
-            r = argv[optind++];
-            guest_stack_size = strtoul(r, (char **)&r, 0);
-            if (guest_stack_size == 0)
-                usage();
-            if (*r == 'M')
-                guest_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                guest_stack_size *= 1024;
-        } else if (!strcmp(r, "L")) {
-            interp_prefix = argv[optind++];
-        } else if (!strcmp(r, "p")) {
-            if (optind >= argc)
-                break;
-            qemu_host_page_size = atoi(argv[optind++]);
-            if (qemu_host_page_size == 0 ||
-                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
-                fprintf(stderr, "page size must be a power of two\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "g")) {
-            if (optind >= argc)
-                break;
-            gdbstub_port = atoi(argv[optind++]);
-       } else if (!strcmp(r, "r")) {
-           qemu_uname_release = argv[optind++];
-        } else if (!strcmp(r, "cpu")) {
-            cpu_model = argv[optind++];
-            if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
-/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list_id)
-                cpu_list_id(stdout, &fprintf, "");
-#elif defined(cpu_list)
-                cpu_list(stdout, &fprintf); /* deprecated */
-#endif
-                exit(1);
-            }
-#if defined(CONFIG_USE_GUEST_BASE)
-        } else if (!strcmp(r, "B")) {
-           guest_base = strtol(argv[optind++], NULL, 0);
-           have_guest_base = 1;
-        } else if (!strcmp(r, "R")) {
-            char *p;
-            int shift = 0;
-            reserved_va = strtoul(argv[optind++], &p, 0);
-            switch (*p) {
-            case 'k':
-            case 'K':
-                shift = 10;
-                break;
-            case 'M':
-                shift = 20;
-                break;
-            case 'G':
-                shift = 30;
-                break;
-            }
-            if (shift) {
-                unsigned long unshifted = reserved_va;
-                p++;
-                reserved_va <<= shift;
-                if (((reserved_va >> shift) != unshifted)
-#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
-                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
-#endif
-                    ) {
-                    fprintf(stderr, "Reserved virtual address too big\n");
-                    exit(1);
-                }
-            }
-            if (*p) {
-                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
-                exit(1);
-            }
-#endif
-        } else if (!strcmp(r, "drop-ld-preload")) {
-            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
-        } else if (!strcmp(r, "singlestep")) {
-            singlestep = 1;
-        } else if (!strcmp(r, "strace")) {
-            do_strace = 1;
-        } else
-        {
-            usage();
-        }
-    }
-    if (optind >= argc)
-        usage();
-    filename = argv[optind];
-    exec_path = argv[optind];
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    optind = parse_args(argc, argv);
 
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
@@ -2916,6 +3330,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)
@@ -2940,7 +3356,8 @@ int main(int argc, char **argv, char **envp)
         cpu_model = "any";
 #endif
     }
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
@@ -2995,6 +3412,13 @@ int main(int argc, char **argv, char **envp)
         }
         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
     }
+
+    if (reserved_va || have_guest_base) {
+        if (!guest_validate_base(guest_base)) {
+            fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
+            exit(1);
+        }
+    }
 #endif /* CONFIG_USE_GUEST_BASE */
 
     /*
@@ -3038,7 +3462,7 @@ int main(int argc, char **argv, char **envp)
     }
     target_argv[target_argc] = NULL;
 
-    ts = qemu_mallocz (sizeof(TaskState));
+    ts = g_malloc0 (sizeof(TaskState));
     init_task_state(ts);
     /* build Task State */
     ts->info = info;
@@ -3218,6 +3642,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;
@@ -3354,11 +3786,20 @@ int main(int argc, char **argv, char **envp)
            env->regs[15] = regs->acr;      
            env->pc = regs->erp;
     }
+#elif defined(TARGET_S390X)
+    {
+            int i;
+            for (i = 0; i < 16; i++) {
+                env->regs[i] = regs->gprs[i];
+            }
+            env->psw.mask = regs->psw.mask;
+            env->psw.addr = regs->psw.addr;
+    }
 #else
 #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.  */
@@ -3366,7 +3807,11 @@ int main(int argc, char **argv, char **envp)
 #endif
 
     if (gdbstub_port) {
-        gdbserver_start (gdbstub_port);
+        if (gdbserver_start(gdbstub_port) < 0) {
+            fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
+                    gdbstub_port);
+            exit(1);
+        }
         gdb_handlesig(env, 0);
     }
     cpu_loop(env);
index 3e641cdb4dab39f581bf402d11a359c0387694da..f1fe0e7d8f66e65271c87b41a0be31b66c9a7e00 100644 (file)
 #define TARGET_NR_sendmsg              360 /* new */
 #define TARGET_NR_recvmsg              361 /* new */
 #define TARGET_NR_accept04             362 /* new */
-
-#define TARGET_NR_syscalls             363
+#define TARGET_NR_preadv                363 /* new */
+#define TARGET_NR_pwritev               364 /* new */
+#define TARGET_NR_rt_tgsigqueueinfo     365 /* new */
+#define TARGET_NR_perf_event_open       366 /* new */
+#define TARGET_NR_recvmmsg              367 /* new */
+#define TARGET_NR_fanotify_init         368
+#define TARGET_NR_fanotify_mark         369
+#define TARGET_NR_prlimit64             370
+#define TARGET_NR_name_to_handle_at     371
+#define TARGET_NR_open_by_handle_at     372
+#define TARGET_NR_clock_adjtime         373
+#define TARGET_NR_syncfs                374
 
index 059530801bfd32f867770e472facae2cf744a44b..fbdc348ffc26e316fb955ea46fc628319d4b5437 100644 (file)
 #define TARGET_NR_dup3                 (TARGET_NR_Linux + 327)
 #define TARGET_NR_pipe2                (TARGET_NR_Linux + 328)
 #define TARGET_NR_inotify_init1        (TARGET_NR_Linux + 329)
+#define TARGET_NR_preadv                (TARGET_NR_Linux + 330)
+#define TARGET_NR_pwritev               (TARGET_NR_Linux + 331)
+#define TARGET_NR_rt_tgsigqueueinfo     (TARGET_NR_Linux + 332)
+#define TARGET_NR_perf_event_open       (TARGET_NR_Linux + 333)
+#define TARGET_NR_accept4               (TARGET_NR_Linux + 334)
+#define TARGET_NR_recvmmsg              (TARGET_NR_Linux + 335)
+#define TARGET_NR_fanotify_init         (TARGET_NR_Linux + 336)
+#define TARGET_NR_fanotify_mark         (TARGET_NR_Linux + 337)
+#define TARGET_NR_prlimit64             (TARGET_NR_Linux + 338)
+#define TARGET_NR_name_to_handle_at     (TARGET_NR_Linux + 339)
+#define TARGET_NR_open_by_handle_at     (TARGET_NR_Linux + 340)
+#define TARGET_NR_clock_adjtime         (TARGET_NR_Linux + 341)
+#define TARGET_NR_syncfs                (TARGET_NR_Linux + 342)
index ee1d1341462127cacb5b6db43f48be09df990eee..36d27b51596082f174558ce1e73e058d04fe3e1a 100644 (file)
 #define TARGET_NR_dup3                         (TARGET_NR_Linux + 286)
 #define TARGET_NR_pipe2                        (TARGET_NR_Linux + 287)
 #define TARGET_NR_inotify_init1                (TARGET_NR_Linux + 288)
+#define TARGET_NR_preadv                        (TARGET_NR_Linux + 289)
+#define TARGET_NR_pwritev                       (TARGET_NR_Linux + 290)
+#define TARGET_NR_rt_tgsigqueueinfo             (TARGET_NR_Linux + 291)
+#define TARGET_NR_perf_event_open               (TARGET_NR_Linux + 292)
+#define TARGET_NR_accept4                       (TARGET_NR_Linux + 293)
+#define TARGET_NR_recvmmsg                      (TARGET_NR_Linux + 294)
+#define TARGET_NR_fanotify_init                 (TARGET_NR_Linux + 295)
+#define TARGET_NR_fanotify_mark                 (TARGET_NR_Linux + 296)
+#define TARGET_NR_prlimit64                     (TARGET_NR_Linux + 297)
+#define TARGET_NR_name_to_handle_at             (TARGET_NR_Linux + 298)
+#define TARGET_NR_open_by_handle_at             (TARGET_NR_Linux + 299)
+#define TARGET_NR_clock_adjtime                 (TARGET_NR_Linux + 300)
+#define TARGET_NR_syncfs                        (TARGET_NR_Linux + 301)
index 60a99ddf6ebccfdcc7c36d69eb6e9e44cbb6b584..4e1aca3a9be8b252ad92564d1d4c0540e66ed24d 100644 (file)
 #define TARGET_NR_dup3                         (TARGET_NR_Linux + 290)
 #define TARGET_NR_pipe2                        (TARGET_NR_Linux + 291)
 #define TARGET_NR_inotify_init1                (TARGET_NR_Linux + 292)
+#define TARGET_NR_preadv                        (TARGET_NR_Linux + 293)
+#define TARGET_NR_pwritev                       (TARGET_NR_Linux + 294)
+#define TARGET_NR_rt_tgsigqueueinfo             (TARGET_NR_Linux + 295)
+#define TARGET_NR_perf_event_open               (TARGET_NR_Linux + 296)
+#define TARGET_NR_accept4                       (TARGET_NR_Linux + 297)
+#define TARGET_NR_recvmmsg                      (TARGET_NR_Linux + 298)
+#define TARGET_NR_getdents64                    (TARGET_NR_Linux + 299)
+#define TARGET_NR_fanotify_init                 (TARGET_NR_Linux + 300)
+#define TARGET_NR_fanotify_mark                 (TARGET_NR_Linux + 301)
+#define TARGET_NR_prlimit64                     (TARGET_NR_Linux + 302)
+#define TARGET_NR_name_to_handle_at             (TARGET_NR_Linux + 303)
+#define TARGET_NR_open_by_handle_at             (TARGET_NR_Linux + 304)
+#define TARGET_NR_clock_adjtime                 (TARGET_NR_Linux + 305)
+#define TARGET_NR_syncfs                        (TARGET_NR_Linux + 306)
index abf21f606491101fb3e8f0cd8c6877647ff0a62f..994c02bb77f3fdc1b9969e73736f2c0ad2e100c8 100644 (file)
@@ -216,6 +216,7 @@ static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
 
 unsigned long last_brk;
 
+#ifdef CONFIG_USE_GUEST_BASE
 /* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
    of guest address space.  */
 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
@@ -249,6 +250,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
     mmap_next_start = addr;
     return last_addr;
 }
+#endif
 
 /*
  * Find and reserve a free memory area of size 'size'. The search
@@ -271,9 +273,11 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 
     size = HOST_PAGE_ALIGN(size);
 
+#ifdef CONFIG_USE_GUEST_BASE
     if (RESERVED_VA) {
         return mmap_find_vma_reserved(start, size);
     }
+#endif
 
     addr = start;
     wrapped = repeat = 0;
@@ -350,7 +354,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
             }
             wrapped = 1;
             /* Don't actually use 0 when wrapping, instead indicate
-               that we'd truely like an allocation in low memory.  */
+               that we'd truly like an allocation in low memory.  */
             addr = (mmap_min_addr > TARGET_PAGE_SIZE
                      ? TARGET_PAGE_ALIGN(mmap_min_addr)
                      : TARGET_PAGE_SIZE);
index cc84a4c04d6867aee22fed5013a30fdc5b14895a..0673b7d169182f110d260b7a792a15e1a6a43b17 100644 (file)
 #define TARGET_NR_dup3                 316
 #define TARGET_NR_pipe2                317
 #define TARGET_NR_inotify_init1        318
+#define TARGET_NR_perf_event_open       319
+#define TARGET_NR_preadv                320
+#define TARGET_NR_pwritev               321
+#define TARGET_NR_rt_tgsigqueueinfo     322
+#define TARGET_NR_fanotify_init         323
+#define TARGET_NR_fanotify_mark         324
+#define TARGET_NR_prlimit64             325
+#define TARGET_NR_socket                326
+#define TARGET_NR_bind                  327
+#define TARGET_NR_connect               328
+#define TARGET_NR_listen                329
+#define TARGET_NR_accept                330
+#define TARGET_NR_getsockname           331
+#define TARGET_NR_getpeername           332
+#define TARGET_NR_socketpair            333
+#define TARGET_NR_send                  334
+#define TARGET_NR_sendto                335
+#define TARGET_NR_recv                  336
+#define TARGET_NR_recvfrom              337
+#define TARGET_NR_shutdown              338
+#define TARGET_NR_setsockopt            339
+#define TARGET_NR_getsockopt            340
+#define TARGET_NR_sendmsg               341
+#define TARGET_NR_recvmsg               342
+#define TARGET_NR_recvmmsg              343
+#define TARGET_NR_accept4               344
+#define TARGET_NR_name_to_handle_at     345
+#define TARGET_NR_open_by_handle_at     346
+#define TARGET_NR_clock_adjtime         347
+#define TARGET_NR_syncfs                348
index 1adda9fbdb9e3fbfc044afe45119c51523b9fc13..fe7f6624f9f209fa152dc8d8691fd0e5c3a78ee6 100644 (file)
@@ -9,6 +9,12 @@ typedef int32_t abi_long;
 #define TARGET_ABI_FMT_ld "%d"
 #define TARGET_ABI_FMT_lu "%u"
 #define TARGET_ABI_BITS 32
+
+static inline abi_ulong tswapal(abi_ulong v)
+{
+    return tswap32(v);
+}
+
 #else
 typedef target_ulong abi_ulong;
 typedef target_long abi_long;
@@ -20,5 +26,11 @@ typedef target_long abi_long;
 #if TARGET_ABI_BITS == 32
 #define TARGET_ABI32 1
 #endif
+
+static inline abi_ulong tswapal(abi_ulong v)
+{
+    return tswapl(v);
+}
+
 #endif
 #endif
index 32de2413f8f2d15f2ce7fe07c7646b3dcaa34477..55ad9d8586c0ac0b36ffa5160abff3526c97ef03 100644 (file)
@@ -51,6 +51,13 @@ struct image_info {
         abi_ulong       arg_start;
         abi_ulong       arg_end;
        int             personality;
+#ifdef CONFIG_USE_FDPIC
+        abi_ulong       loadmap_addr;
+        uint16_t        nsegs;
+        void           *loadsegs;
+        abi_ulong       pt_dynamic_addr;
+        struct image_info *other_info;
+#endif
 };
 
 #ifdef TARGET_I386
@@ -98,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;
@@ -111,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;
@@ -182,7 +192,8 @@ abi_long do_brk(abi_ulong new_brk);
 void syscall_init(void);
 abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     abi_long arg2, abi_long arg3, abi_long arg4,
-                    abi_long arg5, abi_long arg6);
+                    abi_long arg5, abi_long arg6, abi_long arg7,
+                    abi_long arg8);
 void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 extern THREAD CPUState *thread_env;
 void cpu_loop(CPUState *env);
@@ -191,6 +202,12 @@ int get_osversion(void);
 void fork_start(void);
 void fork_end(int child);
 
+/* Return true if the proposed guest_base is suitable for the guest.
+ * The guest code may leave a page mapped and populate it if the
+ * address is suitable.
+ */
+bool guest_validate_base(unsigned long guest_base);
+
 #include "qemu-log.h"
 
 /* strace.c */
@@ -369,7 +386,7 @@ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
 abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
 
 /* Functions for accessing guest memory.  The tget and tput functions
-   read/write single values, byteswapping as neccessary.  The lock_user
+   read/write single values, byteswapping as necessary.  The lock_user
    gets a pointer to a contiguous area of guest memory, but does not perform
    and byteswapping.  lock_user may return either a pointer to the guest
    memory, or a temporary buffer.  */
diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h
new file mode 100644 (file)
index 0000000..c2ea151
--- /dev/null
@@ -0,0 +1,23 @@
+/* this typedef defines how a Program Status Word looks like */
+typedef struct {
+    abi_ulong mask;
+    abi_ulong addr;
+} __attribute__ ((aligned(8))) target_psw_t;
+
+/*
+ * The pt_regs struct defines the way the registers are stored on
+ * the stack during a system call.
+ */
+
+#define TARGET_NUM_GPRS        16
+
+struct target_pt_regs {
+    abi_ulong args[1];
+    target_psw_t psw;
+    abi_ulong gprs[TARGET_NUM_GPRS];
+    abi_ulong orig_gpr2;
+    unsigned short ilc;
+    unsigned short trap;
+};
+
+#define UNAME_MACHINE "s390x"
diff --git a/linux-user/s390x/syscall_nr.h b/linux-user/s390x/syscall_nr.h
new file mode 100644 (file)
index 0000000..d4529ac
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#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_restart_syscall        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_mknod               14
+#define TARGET_NR_chmod               15
+#define TARGET_NR_lseek               19
+#define TARGET_NR_getpid              20
+#define TARGET_NR_mount               21
+#define TARGET_NR_umount              22
+#define TARGET_NR_ptrace              26
+#define TARGET_NR_alarm               27
+#define TARGET_NR_pause               29
+#define TARGET_NR_utime               30
+#define TARGET_NR_access              33
+#define TARGET_NR_nice                34
+#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_brk                 45
+#define TARGET_NR_signal              48
+#define TARGET_NR_acct                51
+#define TARGET_NR_umount2             52
+#define TARGET_NR_ioctl               54
+#define TARGET_NR_fcntl               55
+#define TARGET_NR_setpgid             57
+#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_sigsuspend          72
+#define TARGET_NR_sigpending          73
+#define TARGET_NR_sethostname         74
+#define TARGET_NR_setrlimit           75
+#define TARGET_NR_getrusage           77
+#define TARGET_NR_gettimeofday        78
+#define TARGET_NR_settimeofday        79
+#define TARGET_NR_symlink             83
+#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_getpriority         96
+#define TARGET_NR_setpriority         97
+#define TARGET_NR_statfs              99
+#define TARGET_NR_fstatfs            100
+#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
+#define TARGET_NR_lookup_dcookie     110
+#define TARGET_NR_vhangup            111
+#define TARGET_NR_idle               112
+#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_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 /* Syscall for Andrew File System */
+#define TARGET_NR_getdents           141
+#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_query_module       167
+#define TARGET_NR_poll               168
+#define TARGET_NR_nfsservctl         169
+#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_pread64            180
+#define TARGET_NR_pwrite64           181
+#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
+#define TARGET_NR_getpmsg              188
+#define TARGET_NR_putpmsg              189
+#define TARGET_NR_vfork                190
+#define TARGET_NR_pivot_root         217
+#define TARGET_NR_mincore            218
+#define TARGET_NR_madvise            219
+#define TARGET_NR_getdents64           220
+#define TARGET_NR_readahead            222
+#define TARGET_NR_setxattr             224
+#define TARGET_NR_lsetxattr            225
+#define TARGET_NR_fsetxattr            226
+#define TARGET_NR_getxattr             227
+#define TARGET_NR_lgetxattr            228
+#define TARGET_NR_fgetxattr            229
+#define TARGET_NR_listxattr            230
+#define TARGET_NR_llistxattr           231
+#define TARGET_NR_flistxattr           232
+#define TARGET_NR_removexattr  233
+#define TARGET_NR_lremovexattr 234
+#define TARGET_NR_fremovexattr 235
+#define TARGET_NR_gettid               236
+#define TARGET_NR_tkill                237
+#define TARGET_NR_futex                238
+#define TARGET_NR_sched_setaffinity    239
+#define TARGET_NR_sched_getaffinity    240
+#define TARGET_NR_tgkill               241
+/* Number 242 is reserved for tux */
+#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_epoll_create 249
+#define TARGET_NR_epoll_ctl            250
+#define TARGET_NR_epoll_wait           251
+#define TARGET_NR_set_tid_address      252
+#define TARGET_NR_fadvise64            253
+#define TARGET_NR_timer_create 254
+#define TARGET_NR_timer_settime        (TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime        (TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun     (TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime        (TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime        (TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep      (TARGET_NR_timer_create+8)
+/* Number 263 is reserved for vserver */
+#define TARGET_NR_statfs64             265
+#define TARGET_NR_fstatfs64            266
+#define TARGET_NR_remap_file_pages     267
+/* Number 268 is reserved for new sys_mbind */
+/* Number 269 is reserved for new sys_get_mempolicy */
+/* Number 270 is reserved for new sys_set_mempolicy */
+#define TARGET_NR_mq_open              271
+#define TARGET_NR_mq_unlink            272
+#define TARGET_NR_mq_timedsend 273
+#define TARGET_NR_mq_timedreceive      274
+#define TARGET_NR_mq_notify            275
+#define TARGET_NR_mq_getsetattr        276
+#define TARGET_NR_kexec_load           277
+#define TARGET_NR_add_key              278
+#define TARGET_NR_request_key  279
+#define TARGET_NR_keyctl               280
+#define TARGET_NR_waitid               281
+#define TARGET_NR_ioprio_set           282
+#define TARGET_NR_ioprio_get           283
+#define TARGET_NR_inotify_init 284
+#define TARGET_NR_inotify_add_watch    285
+#define TARGET_NR_inotify_rm_watch     286
+/* Number 287 is reserved for new sys_migrate_pages */
+#define TARGET_NR_openat               288
+#define TARGET_NR_mkdirat              289
+#define TARGET_NR_mknodat              290
+#define TARGET_NR_fchownat             291
+#define TARGET_NR_futimesat            292
+#define TARGET_NR_unlinkat             294
+#define TARGET_NR_renameat             295
+#define TARGET_NR_linkat               296
+#define TARGET_NR_symlinkat            297
+#define TARGET_NR_readlinkat           298
+#define TARGET_NR_fchmodat             299
+#define TARGET_NR_faccessat            300
+#define TARGET_NR_pselect6             301
+#define TARGET_NR_ppoll                302
+#define TARGET_NR_unshare              303
+#define TARGET_NR_set_robust_list      304
+#define TARGET_NR_get_robust_list      305
+#define TARGET_NR_splice               306
+#define TARGET_NR_sync_file_range      307
+#define TARGET_NR_tee          308
+#define TARGET_NR_vmsplice             309
+/* Number 310 is reserved for new sys_move_pages */
+#define TARGET_NR_getcpu               311
+#define TARGET_NR_epoll_pwait  312
+#define TARGET_NR_utimes               313
+#define TARGET_NR_fallocate            314
+#define TARGET_NR_utimensat            315
+#define TARGET_NR_signalfd             316
+#define TARGET_NR_timerfd              317
+#define TARGET_NR_eventfd              318
+#define TARGET_NR_timerfd_create       319
+#define TARGET_NR_timerfd_settime      320
+#define TARGET_NR_timerfd_gettime      321
+#define TARGET_NR_signalfd4            322
+#define TARGET_NR_eventfd2             323
+#define TARGET_NR_inotify_init1        324
+#define TARGET_NR_pipe2                325
+#define TARGET_NR_dup3         326
+#define TARGET_NR_epoll_create1        327
+#define TARGET_NR_preadv                328
+#define TARGET_NR_pwritev               329
+#define TARGET_NR_rt_tgsigqueueinfo     330
+#define TARGET_NR_perf_event_open       331
+#define TARGET_NR_fanotify_init         332
+#define TARGET_NR_fanotify_mark         333
+#define TARGET_NR_prlimit64             334
+#define TARGET_NR_name_to_handle_at     335
+#define TARGET_NR_open_by_handle_at     336
+#define TARGET_NR_clock_adjtime         337
+#define TARGET_NR_syncfs                338
+
+/*
+ * There are some system calls that are not present on 64 bit, some
+ * have a different name although they do the same (e.g. TARGET_NR_chown32
+ * is TARGET_NR_chown on 64 bit).
+ */
+#ifndef TARGET_S390X
+
+#define TARGET_NR_time          13
+#define TARGET_NR_lchown                16
+#define TARGET_NR_setuid                23
+#define TARGET_NR_getuid                24
+#define TARGET_NR_stime                 25
+#define TARGET_NR_setgid                46
+#define TARGET_NR_getgid                47
+#define TARGET_NR_geteuid               49
+#define TARGET_NR_getegid               50
+#define TARGET_NR_setreuid              70
+#define TARGET_NR_setregid              71
+#define TARGET_NR_getrlimit             76
+#define TARGET_NR_getgroups             80
+#define TARGET_NR_setgroups             81
+#define TARGET_NR_fchown                95
+#define TARGET_NR_ioperm               101
+#define TARGET_NR_setfsuid             138
+#define TARGET_NR_setfsgid             139
+#define TARGET_NR__llseek              140
+#define TARGET_NR__newselect   142
+#define TARGET_NR_setresuid            164
+#define TARGET_NR_getresuid            165
+#define TARGET_NR_setresgid            170
+#define TARGET_NR_getresgid            171
+#define TARGET_NR_chown                182
+#define TARGET_NR_ugetrlimit           191     /* SuS compliant getrlimit */
+#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_fcntl64              221
+#define TARGET_NR_sendfile64           223
+#define TARGET_NR_fadvise64_64 264
+#define TARGET_NR_fstatat64            293
+
+#else
+
+#define TARGET_NR_select               142
+#define TARGET_NR_getrlimit            191     /* SuS compliant getrlimit */
+#define TARGET_NR_lchown               198
+#define TARGET_NR_getuid               199
+#define TARGET_NR_getgid               200
+#define TARGET_NR_geteuid              201
+#define TARGET_NR_getegid              202
+#define TARGET_NR_setreuid             203
+#define TARGET_NR_setregid             204
+#define TARGET_NR_getgroups    205
+#define TARGET_NR_setgroups    206
+#define TARGET_NR_fchown               207
+#define TARGET_NR_setresuid    208
+#define TARGET_NR_getresuid    209
+#define TARGET_NR_setresgid    210
+#define TARGET_NR_getresgid    211
+#define TARGET_NR_chown                212
+#define TARGET_NR_setuid               213
+#define TARGET_NR_setgid               214
+#define TARGET_NR_setfsuid             215
+#define TARGET_NR_setfsgid             216
+#define TARGET_NR_newfstatat           293
+
+#endif
+
diff --git a/linux-user/s390x/target_signal.h b/linux-user/s390x/target_signal.h
new file mode 100644 (file)
index 0000000..b4816b0
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+typedef struct target_sigaltstack {
+    abi_ulong ss_sp;
+    int ss_flags;
+    abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK      1
+#define TARGET_SS_DISABLE      2
+
+#define TARGET_MINSIGSTKSZ     2048
+#define TARGET_SIGSTKSZ        8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state)
+{
+   return state->regs[15];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/s390x/termbits.h b/linux-user/s390x/termbits.h
new file mode 100644 (file)
index 0000000..2a78a05
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *  include/asm-s390/termbits.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/termbits.h"
+ */
+
+#define TARGET_NCCS 19
+struct target_termios {
+    unsigned int c_iflag;              /* input mode flags */
+    unsigned int c_oflag;              /* output mode flags */
+    unsigned int c_cflag;              /* control mode flags */
+    unsigned int c_lflag;              /* local mode flags */
+    unsigned char c_line;                      /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];           /* control characters */
+};
+
+struct target_termios2 {
+    unsigned int c_iflag;              /* input mode flags */
+    unsigned int c_oflag;              /* output mode flags */
+    unsigned int c_cflag;              /* control mode flags */
+    unsigned int c_lflag;              /* local mode flags */
+    unsigned char c_line;                      /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];           /* control characters */
+    unsigned int c_ispeed;             /* input speed */
+    unsigned int c_ospeed;             /* output speed */
+};
+
+struct target_ktermios {
+    unsigned int c_iflag;              /* input mode flags */
+    unsigned int c_oflag;              /* output mode flags */
+    unsigned int c_cflag;              /* control mode flags */
+    unsigned int c_lflag;              /* local mode flags */
+    unsigned char c_line;                      /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];           /* control characters */
+    unsigned int c_ispeed;             /* input speed */
+    unsigned int c_ospeed;             /* output speed */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define TARGET_NL0     0000000
+#define TARGET_NL1     0000400
+#define TARGET_CRDLY   0003000
+#define TARGET_CR0     0000000
+#define TARGET_CR1     0001000
+#define TARGET_CR2     0002000
+#define TARGET_CR3     0003000
+#define TARGET_TABDLY  0014000
+#define TARGET_TAB0    0000000
+#define TARGET_TAB1    0004000
+#define TARGET_TAB2    0010000
+#define TARGET_TAB3    0014000
+#define TARGET_XTABS   0014000
+#define TARGET_BSDLY   0020000
+#define TARGET_BS0     0000000
+#define TARGET_BS1     0020000
+#define TARGET_VTDLY   0040000
+#define TARGET_VT0     0000000
+#define TARGET_VT1     0040000
+#define TARGET_FFDLY   0100000
+#define TARGET_FF0     0000000
+#define TARGET_FF1     0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define TARGET_B0      0000000         /* hang up */
+#define TARGET_B50     0000001
+#define TARGET_B75     0000002
+#define TARGET_B110    0000003
+#define TARGET_B134    0000004
+#define TARGET_B150    0000005
+#define TARGET_B200    0000006
+#define TARGET_B300    0000007
+#define TARGET_B600    0000010
+#define TARGET_B1200   0000011
+#define TARGET_B1800   0000012
+#define TARGET_B2400   0000013
+#define TARGET_B4800   0000014
+#define TARGET_B9600   0000015
+#define TARGET_B19200  0000016
+#define TARGET_B38400  0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define TARGET_CS5     0000000
+#define TARGET_CS6     0000020
+#define TARGET_CS7     0000040
+#define TARGET_CS8     0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_BOTHER  0010000
+#define TARGET_B57600  0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_B500000 0010005
+#define TARGET_B576000 0010006
+#define TARGET_B921600 0010007
+#define TARGET_B1000000 0010010
+#define TARGET_B1152000 0010011
+#define TARGET_B1500000 0010012
+#define TARGET_B2000000 0010013
+#define TARGET_B2500000 0010014
+#define TARGET_B3000000 0010015
+#define TARGET_B3500000 0010016
+#define TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate */
+#define TARGET_CMSPAR    010000000000          /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000          /* flow control */
+
+#define TARGET_IBSHIFT   16            /* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* tcflow() and TCXONC use these */
+#define        TARGET_TCOOFF           0
+#define        TARGET_TCOON            1
+#define        TARGET_TCIOFF           2
+#define        TARGET_TCION            3
+
+/* tcflush() and TCFLSH use these */
+#define        TARGET_TCIFLUSH 0
+#define        TARGET_TCOFLUSH 1
+#define        TARGET_TCIOFLUSH        2
+
+/* tcsetattr uses these */
+#define        TARGET_TCSANOW          0
+#define        TARGET_TCSADRAIN        1
+#define        TARGET_TCSAFLUSH        2
+
+/*
+ *  include/asm-s390/ioctls.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ioctls.h"
+ */
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TARGET_TCGETS          0x5401
+#define TARGET_TCSETS          0x5402
+#define TARGET_TCSETSW         0x5403
+#define TARGET_TCSETSF         0x5404
+#define TARGET_TCGETA          0x5405
+#define TARGET_TCSETA          0x5406
+#define TARGET_TCSETAW         0x5407
+#define TARGET_TCSETAF         0x5408
+#define TARGET_TCSBRK          0x5409
+#define TARGET_TCXONC          0x540A
+#define TARGET_TCFLSH          0x540B
+#define TARGET_TIOCEXCL        0x540C
+#define TARGET_TIOCNXCL        0x540D
+#define TARGET_TIOCSCTTY       0x540E
+#define TARGET_TIOCGPGRP       0x540F
+#define TARGET_TIOCSPGRP       0x5410
+#define TARGET_TIOCOUTQ        0x5411
+#define TARGET_TIOCSTI         0x5412
+#define TARGET_TIOCGWINSZ      0x5413
+#define TARGET_TIOCSWINSZ      0x5414
+#define TARGET_TIOCMGET        0x5415
+#define TARGET_TIOCMBIS        0x5416
+#define TARGET_TIOCMBIC        0x5417
+#define TARGET_TIOCMSET        0x5418
+#define TARGET_TIOCGSOFTCAR    0x5419
+#define TARGET_TIOCSSOFTCAR    0x541A
+#define TARGET_FIONREAD        0x541B
+#define TARGET_TIOCINQ         FIONREAD
+#define TARGET_TIOCLINUX       0x541C
+#define TARGET_TIOCCONS        0x541D
+#define TARGET_TIOCGSERIAL     0x541E
+#define TARGET_TIOCSSERIAL     0x541F
+#define TARGET_TIOCPKT         0x5420
+#define TARGET_FIONBIO         0x5421
+#define TARGET_TIOCNOTTY       0x5422
+#define TARGET_TIOCSETD        0x5423
+#define TARGET_TIOCGETD        0x5424
+#define TARGET_TCSBRKP         0x5425  /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK        0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK        0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID        0x5429  /* Return the session ID of FD */
+#define TARGET_TCGETS2         _IOR('T',0x2A, struct termios2)
+#define TARGET_TCSETS2         _IOW('T',0x2B, struct termios2)
+#define TARGET_TCSETSW2        _IOW('T',0x2C, struct termios2)
+#define TARGET_TCSETSF2        _IOW('T',0x2D, struct termios2)
+#define TARGET_TIOCGPTN        _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK      _IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TARGET_TIOCGDEV        _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */
+
+#define TARGET_FIONCLEX        0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX         0x5451
+#define TARGET_FIOASYNC        0x5452
+#define TARGET_TIOCSERCONFIG   0x5453
+#define TARGET_TIOCSERGWILD    0x5454
+#define TARGET_TIOCSERSWILD    0x5455
+#define TARGET_TIOCGLCKTRMIOS  0x5456
+#define TARGET_TIOCSLCKTRMIOS  0x5457
+#define TARGET_TIOCSERGSTRUCT  0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT      0x545C  /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x545D  /* read serial port inline interrupt counts */
+#define TARGET_FIOQSIZE        0x545E
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA             0
+#define TARGET_TIOCPKT_FLUSHREAD        1
+#define TARGET_TIOCPKT_FLUSHWRITE       2
+#define TARGET_TIOCPKT_STOP             4
+#define TARGET_TIOCPKT_START            8
+#define TARGET_TIOCPKT_NOSTOP          16
+#define TARGET_TIOCPKT_DOSTOP          32
+
+#define TARGET_TIOCSER_TEMT    0x01    /* Transmitter physically empty */
+
index 262b236333fe91a935bb81939aaa6686c854773d..365db586c7b8c69724322c92310d444e95850443 100644 (file)
 #define TARGET_NR_clone                120
 #define TARGET_NR_setdomainname        121
 #define TARGET_NR_uname                122
-#define TARGET_NR_modify_ldt           123
+#define TARGET_NR_cacheflush           123
 #define TARGET_NR_adjtimex             124
 #define TARGET_NR_mprotect             125
 #define TARGET_NR_sigprocmask  126
 #define TARGET_NR_dup3                 330
 #define TARGET_NR_pipe2                331
 #define TARGET_NR_inotify_init1        332
+#define TARGET_NR_preadv                333
+#define TARGET_NR_pwritev               334
+#define TARGET_NR_rt_tgsigqueueinfo     335
+#define TARGET_NR_perf_event_open       336
+#define TARGET_NR_fanotify_init         337
+#define TARGET_NR_fanotify_mark         338
+#define TARGET_NR_prlimit64             339
+
+/* Non-multiplexed socket family */
+#define TARGET_NR_socket                340
+#define TARGET_NR_bind                  341
+#define TARGET_NR_connect               342
+#define TARGET_NR_listen                343
+#define TARGET_NR_accept                344
+#define TARGET_NR_getsockname           345
+#define TARGET_NR_getpeername           346
+#define TARGET_NR_socketpair            347
+#define TARGET_NR_send                  348
+#define TARGET_NR_sendto                349
+#define TARGET_NR_recv                  350
+#define TARGET_NR_recvfrom              351
+#define TARGET_NR_shutdown              352
+#define TARGET_NR_setsockopt            353
+#define TARGET_NR_getsockopt            354
+#define TARGET_NR_sendmsg               355
+#define TARGET_NR_recvmsg               356
+#define TARGET_NR_recvmmsg              357
+#define TARGET_NR_accept4               358
+#define TARGET_NR_name_to_handle_at     359
+#define TARGET_NR_open_by_handle_at     360
+#define TARGET_NR_clock_adjtime         361
+#define TARGET_NR_syncfs                362
index b01bd6401176392d3d580fde5c893a225b7886c1..78e338070224917a3fb4123ead19b4ab1c6eafc2 100644 (file)
@@ -21,7 +21,6 @@
 #include <string.h>
 #include <stdarg.h>
 #include <unistd.h>
-#include <signal.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/ucontext.h>
@@ -153,7 +152,7 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
 
     host_to_target_sigset_internal(&d1, s);
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        d->sig[i] = tswapl(d1.sig[i]);
+        d->sig[i] = tswapal(d1.sig[i]);
 }
 
 static void target_to_host_sigset_internal(sigset_t *d,
@@ -174,7 +173,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
     int i;
 
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        s1.sig[i] = tswapl(s->sig[i]);
+        s1.sig[i] = tswapal(s->sig[i]);
     target_to_host_sigset_internal(d, &s1);
 }
 
@@ -235,14 +234,14 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
         sig == SIGBUS || sig == SIGTRAP) {
         tinfo->_sifields._sigfault._addr =
-            tswapl(info->_sifields._sigfault._addr);
+            tswapal(info->_sifields._sigfault._addr);
     } else if (sig == SIGIO) {
        tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
     } else if (sig >= TARGET_SIGRTMIN) {
         tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
         tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
         tinfo->_sifields._rt._sigval.sival_ptr =
-            tswapl(info->_sifields._rt._sigval.sival_ptr);
+            tswapal(info->_sifields._rt._sigval.sival_ptr);
     }
 }
 
@@ -263,7 +262,7 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
     info->si_pid = tswap32(tinfo->_sifields._rt._pid);
     info->si_uid = tswap32(tinfo->_sifields._rt._uid);
     info->si_value.sival_ptr =
-            (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
+            (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
 }
 
 static int fatal_signal (int sig)
@@ -391,7 +390,7 @@ static void QEMU_NORETURN force_sig(int target_sig)
             target_sig, strsignal(host_sig), "core dumped" );
     }
 
-    /* The proper exit code for dieing from an uncaught signal is
+    /* The proper exit code for dying from an uncaught signal is
      * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
      * a negative value.  To get the proper exit code we need to
      * actually die from an uncaught signal.  Here the default signal
@@ -587,19 +586,19 @@ int do_sigaction(int sig, const struct target_sigaction *act,
             sig, act, oact);
 #endif
     if (oact) {
-        oact->_sa_handler = tswapl(k->_sa_handler);
-        oact->sa_flags = tswapl(k->sa_flags);
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswapal(k->sa_flags);
 #if !defined(TARGET_MIPS)
-        oact->sa_restorer = tswapl(k->sa_restorer);
+        oact->sa_restorer = tswapal(k->sa_restorer);
 #endif
         oact->sa_mask = k->sa_mask;
     }
     if (act) {
         /* FIXME: This is not threadsafe.  */
-        k->_sa_handler = tswapl(act->_sa_handler);
-        k->sa_flags = tswapl(act->sa_flags);
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswapal(act->sa_flags);
 #if !defined(TARGET_MIPS)
-        k->sa_restorer = tswapl(act->sa_restorer);
+        k->sa_restorer = tswapal(act->sa_restorer);
 #endif
         k->sa_mask = act->sa_mask;
 
@@ -982,8 +981,8 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
         env->regs[R_ECX] = tswapl(sc->ecx);
         env->eip = tswapl(sc->eip);
 
-        cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
-        cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
+        cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
+        cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
 
         tmpflags = tswapl(sc->eflags);
         env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
@@ -1275,10 +1274,7 @@ setup_return(CPUState *env, struct target_sigaction *ka,
 
                if (__put_user(retcodes[idx], rc))
                        return 1;
-#if 0
-               flush_icache_range((abi_ulong)rc,
-                                  (abi_ulong)(rc + 1));
-#endif
+
                retcode = rc_addr + thumb;
        }
 
@@ -1299,7 +1295,7 @@ static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUState *env)
     __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
     __put_user(sizeof(*vfpframe), &vfpframe->size);
     for (i = 0; i < 32; i++) {
-        __put_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]);
+        __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
     }
     __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
     __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
@@ -1588,7 +1584,7 @@ static abi_ulong *restore_sigframe_v2_vfp(CPUState *env, abi_ulong *regspace)
         return 0;
     }
     for (i = 0; i < 32; i++) {
-        __get_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]);
+        __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
     }
     __get_user(fpscr, &vfpframe->ufp.fpscr);
     vfp_set_fpscr(env, fpscr);
@@ -2081,7 +2077,6 @@ long do_sigreturn(CPUState *env)
         uint32_t up_psr, pc, npc;
         target_sigset_t set;
         sigset_t host_set;
-        abi_ulong fpu_save_addr;
         int err, i;
 
         sf_addr = env->regwptr[UREG_FP];
@@ -2121,10 +2116,11 @@ long do_sigreturn(CPUState *env)
                err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
        }
 
-        err |= __get_user(fpu_save_addr, &sf->fpu_save);
-
-        //if (fpu_save)
-        //        err |= restore_fpu_state(env, fpu_save);
+        /* FIXME: implement FPU save/restore:
+         * __get_user(fpu_save, &sf->fpu_save);
+         * if (fpu_save)
+         *        err |= restore_fpu_state(env, fpu_save);
+         */
 
         /* This is pretty much atomic, no amount locking would prevent
          * the races which exist anyways.
@@ -2229,7 +2225,6 @@ void sparc64_set_context(CPUSPARCState *env)
     target_mc_gregset_t *grp;
     abi_ulong pc, npc, tstate;
     abi_ulong fp, i7, w_addr;
-    unsigned char fenab;
     int err;
     unsigned int i;
 
@@ -2294,15 +2289,21 @@ void sparc64_set_context(CPUSPARCState *env)
     if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), 
                  abi_ulong) != 0)
         goto do_sigsegv;
-    err |= __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+    /* FIXME this does not match how the kernel handles the FPU in
+     * its sparc64_set_context implementation. In particular the FPU
+     * is only restored if fenab is non-zero in:
+     *   __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+     */
     err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
     {
-        uint32_t *src, *dst;
-        src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
-        dst = env->fpr;
-        /* XXX: check that the CPU storage is the same as user context */
-        for (i = 0; i < 64; i++, dst++, src++)
-            err |= __get_user(*dst, src);
+        uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        for (i = 0; i < 64; i++, src++) {
+            if (i & 1) {
+                err |= __get_user(env->fpr[i/2].l.lower, src);
+            } else {
+                err |= __get_user(env->fpr[i/2].l.upper, src);
+            }
+        }
     }
     err |= __get_user(env->fsr,
                       &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
@@ -2391,12 +2392,14 @@ void sparc64_get_context(CPUSPARCState *env)
     err |= __put_user(i7, &(mcp->mc_i7));
 
     {
-        uint32_t *src, *dst;
-        src = env->fpr;
-        dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
-        /* XXX: check that the CPU storage is the same as user context */
-        for (i = 0; i < 64; i++, dst++, src++)
-            err |= __put_user(*src, dst);
+        uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        for (i = 0; i < 64; i++, dst++) {
+            if (i & 1) {
+                err |= __put_user(env->fpr[i/2].l.lower, dst);
+            } else {
+                err |= __put_user(env->fpr[i/2].l.upper, dst);
+            }
+        }
     }
     err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
     err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
@@ -3062,10 +3065,10 @@ static void setup_frame(int sig, struct target_sigaction *ka,
         goto give_sigsegv;
 
     /* Set up registers for signal handler */
-    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[15] = frame_addr;
     regs->gregs[4] = signal; /* Arg for signal handler */
     regs->gregs[5] = 0;
-    regs->gregs[6] = (unsigned long) &frame->sc;
+    regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
     regs->pc = (unsigned long) ka->_sa_handler;
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -3125,10 +3128,10 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
         goto give_sigsegv;
 
     /* Set up registers for signal handler */
-    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[15] = frame_addr;
     regs->gregs[4] = signal; /* Arg for signal handler */
-    regs->gregs[5] = (unsigned long) &frame->info;
-    regs->gregs[6] = (unsigned long) &frame->uc;
+    regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
+    regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
     regs->pc = (unsigned long) ka->_sa_handler;
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -3379,11 +3382,12 @@ static void setup_frame(int sig, struct target_sigaction *ka,
         goto badframe;
 
     /* Set up registers for signal handler */
-    env->regs[1] = (unsigned long) frame;
+    env->regs[1] = frame_addr;
     /* Signal handler args: */
     env->regs[5] = sig; /* Arg 0: signum */
     env->regs[6] = 0;
-    env->regs[7] = (unsigned long) &frame->uc; /* arg 1: sigcontext */
+    /* arg 1: sigcontext */
+    env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
 
     /* Offset of 4 to handle microblaze rtid r14, 0 */
     env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
@@ -3557,11 +3561,11 @@ static void setup_frame(int sig, struct target_sigaction *ka,
        setup_sigcontext(&frame->sc, env);
 
        /* Move the stack and setup the arguments for the handler.  */
-       env->regs[R_SP] = (uint32_t) (unsigned long) frame;
+       env->regs[R_SP] = frame_addr;
        env->regs[10] = sig;
        env->pc = (unsigned long) ka->_sa_handler;
        /* Link SRP so the guest returns through the trampoline.  */
-       env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
+       env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
 
        unlock_user_struct(frame, frame_addr, 1);
        return;
@@ -3614,6 +3618,339 @@ long do_rt_sigreturn(CPUState *env)
     return -TARGET_ENOSYS;
 }
 
+#elif defined(TARGET_S390X)
+
+#define __NUM_GPRS 16
+#define __NUM_FPRS 16
+#define __NUM_ACRS 16
+
+#define S390_SYSCALL_SIZE   2
+#define __SIGNAL_FRAMESIZE      160 /* FIXME: 31-bit mode -> 96 */
+
+#define _SIGCONTEXT_NSIG        64
+#define _SIGCONTEXT_NSIG_BPW    64 /* FIXME: 31-bit mode -> 32 */
+#define _SIGCONTEXT_NSIG_WORDS  (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define _SIGMASK_COPY_SIZE    (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+#define PSW_ADDR_AMODE            0x0000000000000000UL /* 0x80000000UL for 31-bit */
+#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
+
+typedef struct {
+    target_psw_t psw;
+    target_ulong gprs[__NUM_GPRS];
+    unsigned int acrs[__NUM_ACRS];
+} target_s390_regs_common;
+
+typedef struct {
+    unsigned int fpc;
+    double   fprs[__NUM_FPRS];
+} target_s390_fp_regs;
+
+typedef struct {
+    target_s390_regs_common regs;
+    target_s390_fp_regs     fpregs;
+} target_sigregs;
+
+struct target_sigcontext {
+    target_ulong   oldmask[_SIGCONTEXT_NSIG_WORDS];
+    target_sigregs *sregs;
+};
+
+typedef struct {
+    uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+    struct target_sigcontext sc;
+    target_sigregs sregs;
+    int signo;
+    uint8_t retcode[S390_SYSCALL_SIZE];
+} sigframe;
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    struct target_ucontext *tuc_link;
+    target_stack_t tuc_stack;
+    target_sigregs tuc_mcontext;
+    target_sigset_t tuc_sigmask;   /* mask last for extensibility */
+};
+
+typedef struct {
+    uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+    uint8_t retcode[S390_SYSCALL_SIZE];
+    struct target_siginfo info;
+    struct target_ucontext uc;
+} rt_sigframe;
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUState *env, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Default to using normal stack */
+    sp = env->regs[15];
+
+    /* This is the X/Open sanctioned signal stack switching.  */
+    if (ka->sa_flags & TARGET_SA_ONSTACK) {
+        if (!sas_ss_flags(sp)) {
+            sp = target_sigaltstack_used.ss_sp +
+                 target_sigaltstack_used.ss_size;
+        }
+    }
+
+    /* This is the legacy signal stack switching. */
+    else if (/* FIXME !user_mode(regs) */ 0 &&
+             !(ka->sa_flags & TARGET_SA_RESTORER) &&
+             ka->sa_restorer) {
+        sp = (abi_ulong) ka->sa_restorer;
+    }
+
+    return (sp - frame_size) & -8ul;
+}
+
+static void save_sigregs(CPUState *env, target_sigregs *sregs)
+{
+    int i;
+    //save_access_regs(current->thread.acrs); FIXME
+
+    /* Copy a 'clean' PSW mask to the user to avoid leaking
+       information about whether PER is currently on.  */
+    __put_user(env->psw.mask, &sregs->regs.psw.mask);
+    __put_user(env->psw.addr, &sregs->regs.psw.addr);
+    for (i = 0; i < 16; i++) {
+        __put_user(env->regs[i], &sregs->regs.gprs[i]);
+    }
+    for (i = 0; i < 16; i++) {
+        __put_user(env->aregs[i], &sregs->regs.acrs[i]);
+    }
+    /*
+     * We have to store the fp registers to current->thread.fp_regs
+     * to merge them with the emulated registers.
+     */
+    //save_fp_regs(&current->thread.fp_regs); FIXME
+    for (i = 0; i < 16; i++) {
+        __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
+    }
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+                       target_sigset_t *set, CPUState *env)
+{
+    sigframe *frame;
+    abi_ulong frame_addr;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+            goto give_sigsegv;
+    }
+
+    qemu_log("%s: 1\n", __FUNCTION__);
+    if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
+              goto give_sigsegv;
+    }
+
+    save_sigregs(env, &frame->sregs);
+
+    __put_user((abi_ulong)(unsigned long)&frame->sregs,
+               (abi_ulong *)&frame->sc.sregs);
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+            env->regs[14] = (unsigned long)
+                    ka->sa_restorer | PSW_ADDR_AMODE;
+    } else {
+            env->regs[14] = (unsigned long)
+                    frame->retcode | PSW_ADDR_AMODE;
+            if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
+                           (uint16_t *)(frame->retcode)))
+                    goto give_sigsegv;
+    }
+
+    /* Set up backchain. */
+    if (__put_user(env->regs[15], (abi_ulong *) frame)) {
+            goto give_sigsegv;
+    }
+
+    /* Set up registers for signal handler */
+    env->regs[15] = frame_addr;
+    env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+    env->regs[2] = sig; //map_signal(sig);
+    env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
+
+    /* We forgot to include these in the sigcontext.
+       To avoid breaking binary compatibility, they are passed as args. */
+    env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
+    env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
+
+    /* Place signal number on stack to allow backtrace from handler.  */
+    if (__put_user(env->regs[2], (int *) &frame->signo)) {
+            goto give_sigsegv;
+    }
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    qemu_log("%s: give_sigsegv\n", __FUNCTION__);
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+                           target_sigset_t *set, CPUState *env)
+{
+    int i;
+    rt_sigframe *frame;
+    abi_ulong frame_addr;
+
+    frame_addr = get_sigframe(ka, env, sizeof *frame);
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    qemu_log("%s: 1\n", __FUNCTION__);
+    if (copy_siginfo_to_user(&frame->info, info)) {
+        goto give_sigsegv;
+    }
+
+    /* Create the ucontext.  */
+    __put_user(0, &frame->uc.tuc_flags);
+    __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
+    __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
+    __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+                      &frame->uc.tuc_stack.ss_flags);
+    __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
+    save_sigregs(env, &frame->uc.tuc_mcontext);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user((abi_ulong)set->sig[i],
+        (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+        env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
+    } else {
+        env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
+        if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
+                       (uint16_t *)(frame->retcode))) {
+            goto give_sigsegv;
+        }
+    }
+
+    /* Set up backchain. */
+    if (__put_user(env->regs[15], (abi_ulong *) frame)) {
+        goto give_sigsegv;
+    }
+
+    /* Set up registers for signal handler */
+    env->regs[15] = frame_addr;
+    env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+    env->regs[2] = sig; //map_signal(sig);
+    env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
+    env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
+    return;
+
+give_sigsegv:
+    qemu_log("%s: give_sigsegv\n", __FUNCTION__);
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static int
+restore_sigregs(CPUState *env, target_sigregs *sc)
+{
+    int err = 0;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
+    }
+
+    err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
+    qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
+             __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
+             (unsigned long long)env->psw.addr);
+    err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
+    /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
+
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
+    }
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
+    }
+
+    return err;
+}
+
+long do_sigreturn(CPUState *env)
+{
+    sigframe *frame;
+    abi_ulong frame_addr = env->regs[15];
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    target_sigset_t target_set;
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
+        goto badframe;
+    }
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+
+    if (restore_sigregs(env, &frame->sregs)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->regs[2];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    rt_sigframe *frame;
+    abi_ulong frame_addr = env->regs[15];
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+
+    sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+
+    if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
+        goto badframe;
+    }
+
+    if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
+                       get_sp_from_cpustate(env)) == -EFAULT) {
+        goto badframe;
+    }
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->regs[2];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
 #elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
 
 /* FIXME: Many of the structures are defined for both PPC and PPC64, but
index 5d1ac21ac986ff60142cbf122a763b8c9bcc468e..f201f9f788021de34038489cdcacef19e37296ce 100644 (file)
 #define TARGET_NR_utimes             138 /* SunOS Specific                              */
 #define TARGET_NR_stat64               139 /* Linux sparc32 Specific                      */
 #define TARGET_NR_getpeername        141 /* Common                                      */
+#define TARGET_NR_futex              142 /* gethostid under SunOS                       */
 #define TARGET_NR_gettid             143 /* ENOSYS under SunOS                          */
 #define TARGET_NR_getrlimit          144 /* Common                                      */
 #define TARGET_NR_setrlimit          145 /* Common                                      */
 #define TARGET_NR_getdomainname      162 /* SunOS Specific                              */
 #define TARGET_NR_setdomainname      163 /* Common                                      */
 #define TARGET_NR_quotactl           165 /* Common                                      */
+#define TARGET_NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
 #define TARGET_NR_mount              167 /* Common                                      */
 #define TARGET_NR_ustat              168 /* Common                                      */
 #define TARGET_NR_getdents           174 /* Common                                      */
 #define TARGET_NR_readahead          205 /* Linux Specific                              */
 #define TARGET_NR_socketcall         206 /* Linux Specific                              */
 #define TARGET_NR_syslog             207 /* Linux Specific                              */
+#define TARGET_NR_tgkill             211 /* Linux Specific                              */
 #define TARGET_NR_waitpid            212 /* Linux Specific                              */
 #define TARGET_NR_swapoff            213 /* Linux Specific                              */
 #define TARGET_NR_sysinfo            214 /* Linux Specific                              */
 #define TARGET_NR_pipe2                321
 #define TARGET_NR_inotify_init1        322
 #define TARGET_NR_accept4              323
+#define TARGET_NR_preadv                324
+#define TARGET_NR_pwritev               325
+#define TARGET_NR_rt_tgsigqueueinfo     326
+#define TARGET_NR_perf_event_open       327
+#define TARGET_NR_recvmmsg              328
+#define TARGET_NR_fanotify_init         329
+#define TARGET_NR_fanotify_mark         330
+#define TARGET_NR_prlimit64             331
+#define TARGET_NR_name_to_handle_at     332
+#define TARGET_NR_open_by_handle_at     333
+#define TARGET_NR_clock_adjtime         334
+#define TARGET_NR_syncfs                335
index bdca2a7331ee9bcc2d96c8d9118d30f632a367f6..70988b2ec9f7af79ba70aac960bd134b87660964 100644 (file)
 #define TARGET_NR_pipe2                321
 #define TARGET_NR_inotify_init1        322
 #define TARGET_NR_accept4              323
+#define TARGET_NR_preadv                324
+#define TARGET_NR_pwritev               325
+#define TARGET_NR_rt_tgsigqueueinfo     326
+#define TARGET_NR_perf_event_open       327
+#define TARGET_NR_recvmmsg              328
+#define TARGET_NR_fanotify_init         329
+#define TARGET_NR_fanotify_mark         330
+#define TARGET_NR_prlimit64             331
+#define TARGET_NR_name_to_handle_at     332
+#define TARGET_NR_open_by_handle_at     333
+#define TARGET_NR_clock_adjtime         334
+#define TARGET_NR_syncfs                335
index bf9a0d93917fd68ab8fdaba0c87bc89780e1754f..90027a1106ead4ec821a688ca1f692d77feb4539 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)
@@ -136,7 +169,7 @@ print_fdset(int n, abi_ulong target_fds_addr)
             return;
 
         for (i=n; i>=0; i--) {
-            if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
+            if ((tswapal(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
                 gemu_log("%d,", i );
             }
         unlock_user(target_fds, target_fds_addr, 0);
@@ -212,7 +245,7 @@ print_execve(const struct syscallname *name,
        arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
         if (!arg_ptr)
             return;
-       arg_addr = tswapl(*arg_ptr);
+    arg_addr = tswapal(*arg_ptr);
        unlock_user(arg_ptr, arg_ptr_addr, 0);
         if (!arg_addr)
             break;
@@ -398,6 +431,7 @@ UNUSED static struct flags mmap_flags[] = {
     FLAG_TARGET(MAP_DENYWRITE),
     FLAG_TARGET(MAP_FIXED),
     FLAG_TARGET(MAP_GROWSDOWN),
+    FLAG_TARGET(MAP_EXECUTABLE),
 #ifdef MAP_LOCKED
     FLAG_TARGET(MAP_LOCKED),
 #endif
@@ -407,6 +441,9 @@ UNUSED static struct flags mmap_flags[] = {
     FLAG_TARGET(MAP_NORESERVE),
 #ifdef MAP_POPULATE
     FLAG_TARGET(MAP_POPULATE),
+#endif
+#ifdef TARGET_MAP_UNINITIALIZED
+    FLAG_TARGET(MAP_UNINITIALIZED),
 #endif
     FLAG_END,
 };
@@ -423,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
@@ -437,14 +512,11 @@ get_comma(int last)
 }
 
 static void
-print_flags(const struct flags *f, abi_long tflags, int last)
+print_flags(const struct flags *f, abi_long flags, int last)
 {
     const char *sep = "";
-    int flags;
     int n;
 
-    flags = (int)tswap32(tflags);
-
     if ((flags == 0) && (f->f_value == 0)) {
         gemu_log("%s%s", f->f_string, get_comma(last));
         return;
@@ -461,36 +533,33 @@ print_flags(const struct flags *f, abi_long tflags, int last)
     if (n > 0) {
         /* print rest of the flags as numeric */
         if (flags != 0) {
-            gemu_log("%s%#x%s", sep, flags, get_comma(last));
+            gemu_log("%s%#x%s", sep, (unsigned int)flags, get_comma(last));
         } else {
             gemu_log("%s", get_comma(last));
         }
     } else {
         /* no string version of flags found, print them in hex then */
-        gemu_log("%#x%s", flags, get_comma(last));
+        gemu_log("%#x%s", (unsigned int)flags, get_comma(last));
     }
 }
 
 static void
-print_at_dirfd(abi_long tdirfd, int last)
+print_at_dirfd(abi_long dirfd, int last)
 {
-    int dirfd = tswap32(tdirfd);
-
 #ifdef AT_FDCWD
     if (dirfd == AT_FDCWD) {
         gemu_log("AT_FDCWD%s", get_comma(last));
         return;
     }
 #endif
-    gemu_log("%d%s", dirfd, get_comma(last));
+    gemu_log("%d%s", (int)dirfd, get_comma(last));
 }
 
 static void
-print_file_mode(abi_long tmode, int last)
+print_file_mode(abi_long mode, int last)
 {
     const char *sep = "";
     const struct flags *m;
-    mode_t mode = (mode_t)tswap32(tmode);
 
     for (m = &mode_flags[0]; m->f_string != NULL; m++) {
         if ((m->f_value & mode) == m->f_value) {
@@ -504,16 +573,14 @@ print_file_mode(abi_long tmode, int last)
     mode &= ~S_IFMT;
     /* print rest of the mode as octal */
     if (mode != 0)
-        gemu_log("%s%#o", sep, mode);
+        gemu_log("%s%#o", sep, (unsigned int)mode);
 
     gemu_log("%s", get_comma(last));
 }
 
 static void
-print_open_flags(abi_long tflags, int last)
+print_open_flags(abi_long flags, int last)
 {
-    int flags = tswap32(tflags);
-
     print_flags(open_access_flags, flags & TARGET_O_ACCMODE, 1);
     flags &= ~TARGET_O_ACCMODE;
     if (flags == 0) {
@@ -616,7 +683,7 @@ print_accept(const struct syscallname *name,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
     print_syscall_prologue(name);
-    print_raw_param("%d", tswap32(arg0), 0);
+    print_raw_param("%d", arg0, 0);
     print_pointer(arg1, 0);
     print_number(arg2, 1);
     print_syscall_epilogue(name);
@@ -673,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,
@@ -694,7 +794,7 @@ print_execv(const struct syscallname *name,
 {
     print_syscall_prologue(name);
     print_string(arg0, 0);
-    print_raw_param("0x" TARGET_ABI_FMT_lx, tswapl(arg1), 1);
+    print_raw_param("0x" TARGET_ABI_FMT_lx, arg1, 1);
     print_syscall_epilogue(name);
 }
 #endif
@@ -738,13 +838,8 @@ print_fchownat(const struct syscallname *name,
     print_syscall_prologue(name);
     print_at_dirfd(arg0, 0);
     print_string(arg1, 0);
-#ifdef USE_UID16
-    print_raw_param("%d", tswap16(arg2), 0);
-    print_raw_param("%d", tswap16(arg3), 0);
-#else
-    print_raw_param("%d", tswap32(arg2), 0);
-    print_raw_param("%d", tswap32(arg3), 0);
-#endif
+    print_raw_param("%d", arg2, 0);
+    print_raw_param("%d", arg3, 0);
     print_flags(at_file_flags, arg4, 1);
     print_syscall_epilogue(name);
 }
@@ -757,7 +852,7 @@ print_fcntl(const struct syscallname *name,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
     print_syscall_prologue(name);
-    print_raw_param("%d", tswap32(arg0), 0);
+    print_raw_param("%d", arg0, 0);
     print_flags(fcntl_flags, arg1, 0);
     /*
      * TODO: check flags and print following argument only
@@ -814,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
@@ -838,7 +955,7 @@ print_fstat(const struct syscallname *name,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
     print_syscall_prologue(name);
-    print_raw_param("%d", tswap32(arg0), 0);
+    print_raw_param("%d", arg0, 0);
     print_pointer(arg1, 1);
     print_syscall_epilogue(name);
 }
@@ -872,20 +989,66 @@ print_mkdirat(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR_rmdir
+static void
+print_rmdir(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_string(arg0, 0);
+    print_syscall_epilogue(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,
     abi_long arg0, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
-    int hasdev = (tswapl(arg1) & (S_IFCHR|S_IFBLK));
+    int hasdev = (arg1 & (S_IFCHR|S_IFBLK));
 
     print_syscall_prologue(name);
     print_string(arg0, 0);
     print_file_mode(arg1, (hasdev == 0));
     if (hasdev) {
-        print_raw_param("makedev(%d", major(tswapl(arg2)), 0);
-        print_raw_param("%d)", minor(tswapl(arg2)), 1);
+        print_raw_param("makedev(%d", major(arg2), 0);
+        print_raw_param("%d)", minor(arg2), 1);
     }
     print_syscall_epilogue(name);
 }
@@ -897,15 +1060,15 @@ print_mknodat(const struct syscallname *name,
     abi_long arg0, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
-    int hasdev = (tswapl(arg2) & (S_IFCHR|S_IFBLK));
+    int hasdev = (arg2 & (S_IFCHR|S_IFBLK));
 
     print_syscall_prologue(name);
     print_at_dirfd(arg0, 0);
     print_string(arg1, 0);
     print_file_mode(arg2, (hasdev == 0));
     if (hasdev) {
-        print_raw_param("makedev(%d", major(tswapl(arg3)), 0);
-        print_raw_param("%d)", minor(tswapl(arg3)), 1);
+        print_raw_param("makedev(%d", major(arg3), 0);
+        print_raw_param("%d)", minor(arg3), 1);
     }
     print_syscall_epilogue(name);
 }
@@ -917,7 +1080,7 @@ print_mq_open(const struct syscallname *name,
     abi_long arg0, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
-    int is_creat = (tswapl(arg1) & TARGET_O_CREAT);
+    int is_creat = (arg1 & TARGET_O_CREAT);
 
     print_syscall_prologue(name);
     print_string(arg0, 0);
@@ -936,7 +1099,7 @@ print_open(const struct syscallname *name,
     abi_long arg0, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
-    int is_creat = (tswap32(arg1) & TARGET_O_CREAT);
+    int is_creat = (arg1 & TARGET_O_CREAT);
 
     print_syscall_prologue(name);
     print_string(arg0, 0);
@@ -953,7 +1116,7 @@ print_openat(const struct syscallname *name,
     abi_long arg0, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5)
 {
-    int is_creat = (tswap32(arg2) & TARGET_O_CREAT);
+    int is_creat = (arg2 & TARGET_O_CREAT);
 
     print_syscall_prologue(name);
     print_at_dirfd(arg0, 0);
@@ -1002,7 +1165,7 @@ print_readlink(const struct syscallname *name,
     print_syscall_prologue(name);
     print_string(arg0, 0);
     print_pointer(arg1, 0);
-    print_raw_param("%u", tswapl(arg2), 1);
+    print_raw_param("%u", arg2, 1);
     print_syscall_epilogue(name);
 }
 #endif
@@ -1017,7 +1180,7 @@ print_readlinkat(const struct syscallname *name,
     print_at_dirfd(arg0, 0);
     print_string(arg1, 0);
     print_pointer(arg2, 0);
-    print_raw_param("%u", tswapl(arg3), 1);
+    print_raw_param("%u", arg3, 1);
     print_syscall_epilogue(name);
 }
 #endif
@@ -1199,7 +1362,7 @@ print_utimensat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_mmap
+#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2)
 static void
 print_mmap(const struct syscallname *name,
     abi_long arg0, abi_long arg1, abi_long arg2,
@@ -1207,11 +1370,11 @@ print_mmap(const struct syscallname *name,
 {
     print_syscall_prologue(name);
     print_pointer(arg0, 0);
-    print_raw_param("%d", tswapl(arg1), 0);
+    print_raw_param("%d", arg1, 0);
     print_flags(mmap_prot_flags, arg2, 0);
     print_flags(mmap_flags, arg3, 0);
-    print_raw_param("%d", tswapl(arg4), 0);
-    print_raw_param("%#x", tswapl(arg5), 1);
+    print_raw_param("%d", arg4, 0);
+    print_raw_param("%#x", arg5, 1);
     print_syscall_epilogue(name);
 }
 #define print_mmap2     print_mmap
@@ -1225,7 +1388,7 @@ print_mprotect(const struct syscallname *name,
 {
     print_syscall_prologue(name);
     print_pointer(arg0, 0);
-    print_raw_param("%d", tswapl(arg1), 0);
+    print_raw_param("%d", arg1, 0);
     print_flags(mmap_prot_flags, arg2, 1);
     print_syscall_epilogue(name);
 }
@@ -1239,7 +1402,7 @@ print_munmap(const struct syscallname *name,
 {
     print_syscall_prologue(name);
     print_pointer(arg0, 0);
-    print_raw_param("%d", tswapl(arg1), 1);
+    print_raw_param("%d", arg1, 1);
     print_syscall_epilogue(name);
 }
 #endif
@@ -1253,7 +1416,7 @@ if( cmd == val ) { \
     return; \
 }
 
-    int cmd = (int)tswap32(tflag);
+    int cmd = (int)tflag;
 #ifdef FUTEX_PRIVATE_FLAG
     if (cmd & FUTEX_PRIVATE_FLAG) {
         gemu_log("FUTEX_PRIVATE_FLAG|");
@@ -1287,10 +1450,23 @@ print_futex(const struct syscallname *name,
     print_syscall_prologue(name);
     print_pointer(arg0, 0);
     print_futex_op(arg1, 0);
-    print_raw_param(",%d", tswapl(arg2), 0);
+    print_raw_param(",%d", arg2, 0);
     print_pointer(arg3, 0); /* struct timespec */
     print_pointer(arg4, 0);
-    print_raw_param("%d", tswapl(arg4), 1);
+    print_raw_param("%d", arg4, 1);
+    print_syscall_epilogue(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
index d7be0e7a68101f4de6cc7f02a9e93ec50f0dfb12..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 },
 #ifdef TARGET_NR_mkdirat
 { TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL },
 #endif
+#ifdef TARGET_NR_rmdir
+{ TARGET_NR_rmdir, "rmdir" , NULL, print_rmdir, NULL },
+#endif
 #ifdef TARGET_NR_mknod
 { TARGET_NR_mknod, "mknod" , NULL, print_mknod, NULL },
 #endif
 { 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 499c4d7d62efb3d0cddb3f8175b01da63d7ca95e..f227097801e79aeaa6a20a36080a824653aea92a 100644 (file)
@@ -59,13 +59,20 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 //#include <sys/user.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
-#include <qemu-common.h>
+#include <linux/wireless.h>
+#include "qemu-common.h"
 #ifdef TARGET_GPROF
 #include <sys/gmon.h>
 #endif
 #ifdef CONFIG_EVENTFD
 #include <sys/eventfd.h>
 #endif
+#ifdef CONFIG_EPOLL
+#include <sys/epoll.h>
+#endif
+#ifdef CONFIG_ATTR
+#include "qemu-xattr.h"
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -92,7 +99,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include "cpu-uname.h"
 
 #include "qemu.h"
-#include "qemu-common.h"
 
 #if defined(CONFIG_USE_NPTL)
 #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
@@ -193,7 +199,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
 
@@ -235,6 +242,14 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
           const struct timespec *,timeout,int *,uaddr2,int,val3)
 #endif
 #endif
+#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
+_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
+          unsigned long *, user_mask_ptr);
+#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
+_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
+          unsigned long *, user_mask_ptr);
+_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
+          void *, arg);
 
 static bitmask_transtbl fcntl_flags_tbl[] = {
   { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
@@ -276,7 +291,7 @@ static int sys_uname(struct new_utsname *buf)
    * struct linux kernel uses).
    */
 
-  bzero(buf, sizeof (*buf));
+  memset(buf, 0, sizeof(*buf));
   COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
   COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
   COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
@@ -317,7 +332,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)
 {
@@ -366,25 +381,13 @@ static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
 }
 #endif
 #ifdef TARGET_NR_openat
-static int sys_openat(int dirfd, const char *pathname, int flags, ...)
+static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
 {
   /*
    * open(2) has extra parameter 'mode' when called with
    * flag O_CREAT.
    */
   if ((flags & O_CREAT) != 0) {
-      va_list ap;
-      mode_t mode;
-
-      /*
-       * Get the 'mode' parameter and translate it to
-       * host bits.
-       */
-      va_start(ap, flags);
-      mode = va_arg(ap, mode_t);
-      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
-      va_end(ap);
-
       return (openat(dirfd, pathname, flags, mode));
   }
   return (openat(dirfd, pathname, flags));
@@ -426,7 +429,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
@@ -529,6 +532,39 @@ static int sys_inotify_init1(int flags)
 #undef TARGET_NR_inotify_rm_watch
 #endif /* CONFIG_INOTIFY  */
 
+#if defined(TARGET_NR_ppoll)
+#ifndef __NR_ppoll
+# define __NR_ppoll -1
+#endif
+#define __NR_sys_ppoll __NR_ppoll
+_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
+          struct timespec *, timeout, const __sigset_t *, sigmask,
+          size_t, sigsetsize)
+#endif
+
+#if defined(TARGET_NR_pselect6)
+#ifndef __NR_pselect6
+# define __NR_pselect6 -1
+#endif
+#define __NR_sys_pselect6 __NR_pselect6
+_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
+          fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
+#endif
+
+#if defined(TARGET_NR_prlimit64)
+#ifndef __NR_prlimit64
+# define __NR_prlimit64 -1
+#endif
+#define __NR_sys_prlimit64 __NR_prlimit64
+/* The glibc rlimit structure may not be that used by the underlying syscall */
+struct host_rlimit64 {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
+          const struct host_rlimit64 *, new_limit,
+          struct host_rlimit64 *, old_limit)
+#endif
 
 extern int personality(int);
 extern int flock(int, int);
@@ -536,6 +572,17 @@ extern int setfsuid(int);
 extern int setfsgid(int);
 extern int setgroups(int, gid_t *);
 
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
+#ifdef TARGET_ARM 
+static inline int regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
+}
+#elif defined(TARGET_MIPS)
+static inline int regpairs_aligned(void *cpu_env) { return 1; }
+#else
+static inline int regpairs_aligned(void *cpu_env) { return 0; }
+#endif
+
 #define ERRNO_TABLE_SIZE 1200
 
 /* target_to_host_errno_table[] is initialized from
@@ -689,49 +736,90 @@ char *target_strerror(int err)
 
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
+static abi_ulong brk_page;
 
 void target_set_brk(abi_ulong new_brk)
 {
     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
+    brk_page = HOST_PAGE_ALIGN(target_brk);
 }
 
+//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
+#define DEBUGF_BRK(message, args...)
+
 /* do_brk() must return target values and target errnos. */
 abi_long do_brk(abi_ulong new_brk)
 {
-    abi_ulong brk_page;
     abi_long mapped_addr;
     int        new_alloc_size;
 
-    if (!new_brk)
+    DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
+
+    if (!new_brk) {
+        DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
         return target_brk;
-    if (new_brk < target_original_brk)
+    }
+    if (new_brk < target_original_brk) {
+        DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
         return target_brk;
+    }
 
-    brk_page = HOST_PAGE_ALIGN(target_brk);
-
-    /* If the new brk is less than this, set it and we're done... */
-    if (new_brk < brk_page) {
+    /* If the new brk is less than the highest page reserved to the
+     * target heap allocation, set it and we're almost done...  */
+    if (new_brk <= brk_page) {
+        /* Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  */
+        if (new_brk > target_brk) {
+            memset(g2h(target_brk), 0, new_brk - target_brk);
+        }
        target_brk = new_brk;
+        DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
        return target_brk;
     }
 
-    /* We need to allocate more memory after the brk... */
-    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    /* We need to allocate more memory after the brk... Note that
+     * we don't use MAP_FIXED because that will map over the top of
+     * any existing mapping (like the one with the host libc or qemu
+     * itself); instead we treat "mapped but at wrong address" as
+     * a failure and unmap again.
+     */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
     mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
                                         PROT_READ|PROT_WRITE,
-                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
+                                        MAP_ANON|MAP_PRIVATE, 0, 0));
+
+    if (mapped_addr == brk_page) {
+        /* Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  Technically the new pages are already
+         * initialized to zero since they *are* anonymous mapped
+         * pages, however we have to take care with the contents that
+         * come from the remaining part of the previous page: it may
+         * contains garbage data due to a previous heap usage (grown
+         * then shrunken).  */
+        memset(g2h(target_brk), 0, brk_page - target_brk);
+
+        target_brk = new_brk;
+        brk_page = HOST_PAGE_ALIGN(target_brk);
+        DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
+        return target_brk;
+    } else if (mapped_addr != -1) {
+        /* Mapped but at wrong address, meaning there wasn't actually
+         * enough space for this brk.
+         */
+        target_munmap(mapped_addr, new_alloc_size);
+        mapped_addr = -1;
+        DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
+    }
+    else {
+        DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
+    }
 
 #if defined(TARGET_ALPHA)
     /* We (partially) emulate OSF/1 on Alpha, which requires we
        return a proper errno, not an unchanged brk value.  */
-    if (is_error(mapped_addr)) {
-        return -TARGET_ENOMEM;
-    }
+    return -TARGET_ENOMEM;
 #endif
-
-    if (!is_error(mapped_addr)) {
-       target_brk = new_brk;
-    }
+    /* For everything else, return the previous break. */
     return target_brk;
 }
 
@@ -767,6 +855,20 @@ static inline abi_long copy_from_user_fdset(fd_set *fds,
     return 0;
 }
 
+static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+                                                 abi_ulong target_fds_addr,
+                                                 int n)
+{
+    if (target_fds_addr) {
+        if (copy_from_user_fdset(fds, target_fds_addr, n))
+            return -TARGET_EFAULT;
+        *fds_ptr = fds;
+    } else {
+        *fds_ptr = NULL;
+    }
+    return 0;
+}
+
 static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
                                           const fd_set *fds,
                                           int n)
@@ -819,43 +921,95 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
         return -TARGET_EFAULT;
-    target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
-    target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
-    target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
-    target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
-    target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
-    target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
-    target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
-    target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
-    target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
-    target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
-    target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
-    target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
-    target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
-    target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
-    target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
-    target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
-    target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
-    target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
+    target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
+    target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
+    target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
+    target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
+    target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
+    target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
+    target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
+    target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
+    target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
+    target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
+    target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
+    target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
+    target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
+    target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
+    target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
+    target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
+    target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
+    target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
     unlock_user_struct(target_rusage, target_addr, 1);
 
     return 0;
 }
 
-static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
+static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
 {
-    if (target_rlim == TARGET_RLIM_INFINITY)
+    abi_ulong target_rlim_swap;
+    rlim_t result;
+    
+    target_rlim_swap = tswapal(target_rlim);
+    if (target_rlim_swap == TARGET_RLIM_INFINITY)
         return RLIM_INFINITY;
-    else
-        return tswapl(target_rlim);
+
+    result = target_rlim_swap;
+    if (target_rlim_swap != (rlim_t)result)
+        return RLIM_INFINITY;
+    
+    return result;
 }
 
-static inline target_ulong host_to_target_rlim(rlim_t rlim)
+static inline abi_ulong host_to_target_rlim(rlim_t rlim)
 {
-    if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
-        return TARGET_RLIM_INFINITY;
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
+    
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
+        target_rlim_swap = TARGET_RLIM_INFINITY;
     else
-        return tswapl(rlim);
+        target_rlim_swap = rlim;
+    result = tswapal(target_rlim_swap);
+    
+    return result;
+}
+
+static inline int target_to_host_resource(int code)
+{
+    switch (code) {
+    case TARGET_RLIMIT_AS:
+        return RLIMIT_AS;
+    case TARGET_RLIMIT_CORE:
+        return RLIMIT_CORE;
+    case TARGET_RLIMIT_CPU:
+        return RLIMIT_CPU;
+    case TARGET_RLIMIT_DATA:
+        return RLIMIT_DATA;
+    case TARGET_RLIMIT_FSIZE:
+        return RLIMIT_FSIZE;
+    case TARGET_RLIMIT_LOCKS:
+        return RLIMIT_LOCKS;
+    case TARGET_RLIMIT_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+    case TARGET_RLIMIT_MSGQUEUE:
+        return RLIMIT_MSGQUEUE;
+    case TARGET_RLIMIT_NICE:
+        return RLIMIT_NICE;
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+    case TARGET_RLIMIT_RTPRIO:
+        return RLIMIT_RTPRIO;
+    case TARGET_RLIMIT_SIGPENDING:
+        return RLIMIT_SIGPENDING;
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+    default:
+        return code;
+    }
 }
 
 static inline abi_long copy_from_user_timeval(struct timeval *tv,
@@ -932,6 +1086,7 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
 }
 #endif
 
+#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
 /* do_select() must return target values and target errnos. */
 static abi_long do_select(int n,
                           abi_ulong rfd_addr, abi_ulong wfd_addr,
@@ -942,26 +1097,17 @@ static abi_long do_select(int n,
     struct timeval tv, *tv_ptr;
     abi_long ret;
 
-    if (rfd_addr) {
-        if (copy_from_user_fdset(&rfds, rfd_addr, n))
-            return -TARGET_EFAULT;
-        rfds_ptr = &rfds;
-    } else {
-        rfds_ptr = NULL;
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret) {
+        return ret;
     }
-    if (wfd_addr) {
-        if (copy_from_user_fdset(&wfds, wfd_addr, n))
-            return -TARGET_EFAULT;
-        wfds_ptr = &wfds;
-    } else {
-        wfds_ptr = NULL;
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret) {
+        return ret;
     }
-    if (efd_addr) {
-        if (copy_from_user_fdset(&efds, efd_addr, n))
-            return -TARGET_EFAULT;
-        efds_ptr = &efds;
-    } else {
-        efds_ptr = NULL;
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret) {
+        return ret;
     }
 
     if (target_tv_addr) {
@@ -988,6 +1134,7 @@ static abi_long do_select(int n,
 
     return ret;
 }
+#endif
 
 static abi_long do_pipe2(int host_pipe[], int flags)
 {
@@ -1041,7 +1188,7 @@ static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
     mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
     mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
     if (len == sizeof(struct target_ip_mreqn))
-        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
     unlock_user(target_smreqn, target_addr, 0);
 
     return 0;
@@ -1113,10 +1260,10 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
     struct target_cmsghdr *target_cmsg;
     socklen_t space = 0;
     
-    msg_controllen = tswapl(target_msgh->msg_controllen);
+    msg_controllen = tswapal(target_msgh->msg_controllen);
     if (msg_controllen < sizeof (struct target_cmsghdr)) 
         goto the_end;
-    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
     target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
     if (!target_cmsg)
         return -TARGET_EFAULT;
@@ -1125,7 +1272,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
         void *data = CMSG_DATA(cmsg);
         void *target_data = TARGET_CMSG_DATA(target_cmsg);
 
-        int len = tswapl(target_cmsg->cmsg_len)
+        int len = tswapal(target_cmsg->cmsg_len)
                   - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
 
         space += CMSG_SPACE(len);
@@ -1170,10 +1317,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
     struct target_cmsghdr *target_cmsg;
     socklen_t space = 0;
 
-    msg_controllen = tswapl(target_msgh->msg_controllen);
+    msg_controllen = tswapal(target_msgh->msg_controllen);
     if (msg_controllen < sizeof (struct target_cmsghdr)) 
         goto the_end;
-    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
     target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
     if (!target_cmsg)
         return -TARGET_EFAULT;
@@ -1193,7 +1340,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
 
         target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
         target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
-        target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
 
         if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
             gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
@@ -1212,7 +1359,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
     }
     unlock_user(target_cmsg, target_cmsg_addr, space);
  the_end:
-    target_msgh->msg_controllen = tswapl(space);
+    target_msgh->msg_controllen = tswapal(space);
     return 0;
 }
 
@@ -1361,7 +1508,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
         break;
     default:
     unimplemented:
-        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
+        gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
         ret = -TARGET_ENOPROTOOPT;
     }
     return ret;
@@ -1448,7 +1595,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
             return -TARGET_EFAULT;
         if (len < 0)
             return -TARGET_EINVAL;
-        lv = sizeof(int);
+        lv = sizeof(lv);
         ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
         if (ret < 0)
             return ret;
@@ -1485,7 +1632,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
                 return -TARGET_EFAULT;
             if (len < 0)
                 return -TARGET_EINVAL;
-            lv = sizeof(int);
+            lv = sizeof(lv);
             ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
             if (ret < 0)
                 return ret;
@@ -1532,8 +1679,8 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
     if (!target_vec)
         return -TARGET_EFAULT;
     for(i = 0;i < count; i++) {
-        base = tswapl(target_vec[i].iov_base);
-        vec[i].iov_len = tswapl(target_vec[i].iov_len);
+        base = tswapal(target_vec[i].iov_base);
+        vec[i].iov_len = tswapal(target_vec[i].iov_len);
         if (vec[i].iov_len != 0) {
             vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
             /* Don't check lock_user return value. We must call writev even
@@ -1559,7 +1706,7 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
         return -TARGET_EFAULT;
     for(i = 0;i < count; i++) {
         if (target_vec[i].iov_base) {
-            base = tswapl(target_vec[i].iov_base);
+            base = tswapal(target_vec[i].iov_base);
             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
         }
     }
@@ -1658,7 +1805,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
     if (msgp->msg_name) {
         msg.msg_namelen = tswap32(msgp->msg_namelen);
         msg.msg_name = alloca(msg.msg_namelen);
-        ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
+        ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
                                 msg.msg_namelen);
         if (ret) {
             unlock_user_struct(msgp, target_msg, send ? 0 : 1);
@@ -1668,13 +1815,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
         msg.msg_name = NULL;
         msg.msg_namelen = 0;
     }
-    msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
     msg.msg_control = alloca(msg.msg_controllen);
     msg.msg_flags = tswap32(msgp->msg_flags);
 
-    count = tswapl(msgp->msg_iovlen);
+    count = tswapal(msgp->msg_iovlen);
     vec = alloca(count * sizeof(struct iovec));
-    target_vec = tswapl(msgp->msg_iov);
+    target_vec = tswapal(msgp->msg_iov);
     lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
     msg.msg_iovlen = count;
     msg.msg_iov = vec;
@@ -1860,7 +2007,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
         ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
     } else {
         addr = NULL; /* To keep compiler quiet.  */
-        ret = get_errno(recv(fd, host_msg, len, flags));
+        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
     }
     if (!is_error(ret)) {
         if (target_addr) {
@@ -2177,12 +2324,12 @@ static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
     if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
         return -TARGET_EFAULT;
     target_ip = &(target_sd->sem_perm);
-    host_ip->__key = tswapl(target_ip->__key);
-    host_ip->uid = tswapl(target_ip->uid);
-    host_ip->gid = tswapl(target_ip->gid);
-    host_ip->cuid = tswapl(target_ip->cuid);
-    host_ip->cgid = tswapl(target_ip->cgid);
-    host_ip->mode = tswapl(target_ip->mode);
+    host_ip->__key = tswapal(target_ip->__key);
+    host_ip->uid = tswapal(target_ip->uid);
+    host_ip->gid = tswapal(target_ip->gid);
+    host_ip->cuid = tswapal(target_ip->cuid);
+    host_ip->cgid = tswapal(target_ip->cgid);
+    host_ip->mode = tswap16(target_ip->mode);
     unlock_user_struct(target_sd, target_addr, 0);
     return 0;
 }
@@ -2196,12 +2343,12 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
     if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
         return -TARGET_EFAULT;
     target_ip = &(target_sd->sem_perm);
-    target_ip->__key = tswapl(host_ip->__key);
-    target_ip->uid = tswapl(host_ip->uid);
-    target_ip->gid = tswapl(host_ip->gid);
-    target_ip->cuid = tswapl(host_ip->cuid);
-    target_ip->cgid = tswapl(host_ip->cgid);
-    target_ip->mode = tswapl(host_ip->mode);
+    target_ip->__key = tswapal(host_ip->__key);
+    target_ip->uid = tswapal(host_ip->uid);
+    target_ip->gid = tswapal(host_ip->gid);
+    target_ip->cuid = tswapal(host_ip->cuid);
+    target_ip->cgid = tswapal(host_ip->cgid);
+    target_ip->mode = tswap16(host_ip->mode);
     unlock_user_struct(target_sd, target_addr, 1);
     return 0;
 }
@@ -2215,9 +2362,9 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
         return -TARGET_EFAULT;
     if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
         return -TARGET_EFAULT;
-    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
-    host_sd->sem_otime = tswapl(target_sd->sem_otime);
-    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
+    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
     unlock_user_struct(target_sd, target_addr, 0);
     return 0;
 }
@@ -2231,9 +2378,9 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
         return -TARGET_EFAULT;
     if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
         return -TARGET_EFAULT;;
-    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
-    target_sd->sem_otime = tswapl(host_sd->sem_otime);
-    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
+    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
     unlock_user_struct(target_sd, target_addr, 1);
     return 0;
 }
@@ -2361,9 +2508,9 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
     switch( cmd ) {
        case GETVAL:
        case SETVAL:
-            arg.val = tswapl(target_su.val);
+            arg.val = tswap32(target_su.val);
             ret = get_errno(semctl(semid, semnum, cmd, arg));
-            target_su.val = tswapl(arg.val);
+            target_su.val = tswap32(arg.val);
             break;
        case GETALL:
        case SETALL:
@@ -2479,14 +2626,14 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
         return -TARGET_EFAULT;
     if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
         return -TARGET_EFAULT;
-    host_md->msg_stime = tswapl(target_md->msg_stime);
-    host_md->msg_rtime = tswapl(target_md->msg_rtime);
-    host_md->msg_ctime = tswapl(target_md->msg_ctime);
-    host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
-    host_md->msg_qnum = tswapl(target_md->msg_qnum);
-    host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
-    host_md->msg_lspid = tswapl(target_md->msg_lspid);
-    host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
+    host_md->msg_stime = tswapal(target_md->msg_stime);
+    host_md->msg_rtime = tswapal(target_md->msg_rtime);
+    host_md->msg_ctime = tswapal(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapal(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapal(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
     unlock_user_struct(target_md, target_addr, 0);
     return 0;
 }
@@ -2500,14 +2647,14 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
         return -TARGET_EFAULT;
     if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
         return -TARGET_EFAULT;
-    target_md->msg_stime = tswapl(host_md->msg_stime);
-    target_md->msg_rtime = tswapl(host_md->msg_rtime);
-    target_md->msg_ctime = tswapl(host_md->msg_ctime);
-    target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
-    target_md->msg_qnum = tswapl(host_md->msg_qnum);
-    target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
-    target_md->msg_lspid = tswapl(host_md->msg_lspid);
-    target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
+    target_md->msg_stime = tswapal(host_md->msg_stime);
+    target_md->msg_rtime = tswapal(host_md->msg_rtime);
+    target_md->msg_ctime = tswapal(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapal(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapal(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
     unlock_user_struct(target_md, target_addr, 1);
     return 0;
 }
@@ -2588,7 +2735,7 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp,
     if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
         return -TARGET_EFAULT;
     host_mb = malloc(msgsz+sizeof(long));
-    host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
+    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
     memcpy(host_mb->mtext, target_mb->mtext, msgsz);
     ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
     free(host_mb);
@@ -2610,7 +2757,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
         return -TARGET_EFAULT;
 
     host_mb = malloc(msgsz+sizeof(long));
-    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
 
     if (ret > 0) {
         abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
@@ -2623,7 +2770,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
         unlock_user(target_mtext, target_mtext_addr, ret);
     }
 
-    target_mb->mtype = tswapl(host_mb->mtype);
+    target_mb->mtype = tswapal(host_mb->mtype);
     free(host_mb);
 
 end:
@@ -2952,7 +3099,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,
@@ -3077,6 +3223,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__ } },
@@ -3401,7 +3641,7 @@ static abi_long write_ldt(CPUX86State *env,
     if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
         return -TARGET_EFAULT;
     ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
-    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
     ldt_info.limit = tswap32(target_ldt_info->limit);
     ldt_info.flags = tswap32(target_ldt_info->flags);
     unlock_user_struct(target_ldt_info, ptr, 0);
@@ -3516,7 +3756,7 @@ static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
     if (!target_ldt_info)
         return -TARGET_EFAULT;
     ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
-    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
     ldt_info.limit = tswap32(target_ldt_info->limit);
     ldt_info.flags = tswap32(target_ldt_info->flags);
     if (ldt_info.entry_number == -1) {
@@ -3627,7 +3867,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
     base_addr = (entry_1 >> 16) | 
         (entry_2 & 0xff000000) | 
         ((entry_2 & 0xff) << 16);
-    target_ldt_info->base_addr = tswapl(base_addr);
+    target_ldt_info->base_addr = tswapal(base_addr);
     target_ldt_info->limit = tswap32(limit);
     target_ldt_info->flags = tswap32(flags);
     unlock_user_struct(target_ldt_info, ptr, 1);
@@ -3638,10 +3878,10 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
 #ifndef TARGET_ABI32
 static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
 {
-    abi_long ret;
+    abi_long ret = 0;
     abi_ulong val;
     int idx;
-    
+
     switch(code) {
     case TARGET_ARCH_SET_GS:
     case TARGET_ARCH_SET_FS:
@@ -3660,21 +3900,21 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
             idx = R_FS;
         val = env->segs[idx].base;
         if (put_user(val, addr, abi_ulong))
-            return -TARGET_EFAULT;
+            ret = -TARGET_EFAULT;
         break;
     default:
         ret = -TARGET_EINVAL;
         break;
     }
-    return 0;
+    return ret;
 }
 #endif
 
 #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 {
@@ -3718,9 +3958,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)
 {
@@ -3757,7 +3994,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         new_thread_info info;
         pthread_attr_t attr;
 #endif
-        ts = qemu_mallocz(sizeof(TaskState));
+        ts = g_malloc0(sizeof(TaskState));
         init_task_state(ts);
         /* we create a new CPU instance. */
         new_env = cpu_copy(env);
@@ -3823,7 +4060,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         if (flags & CLONE_NPTL_FLAGS2)
             return -EINVAL;
         /* This is probably going to die very quickly, but do it anyway.  */
-        new_stack = qemu_mallocz (NEW_STACK_SIZE);
+        new_stack = g_malloc0 (NEW_STACK_SIZE);
 #ifdef __ia64__
         ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
 #else
@@ -3930,8 +4167,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
-        fl.l_start = tswapl(target_fl->l_start);
-        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_start = tswapal(target_fl->l_start);
+        fl.l_len = tswapal(target_fl->l_len);
         fl.l_pid = tswap32(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl));
@@ -3940,8 +4177,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
                 return -TARGET_EFAULT;
             target_fl->l_type = tswap16(fl.l_type);
             target_fl->l_whence = tswap16(fl.l_whence);
-            target_fl->l_start = tswapl(fl.l_start);
-            target_fl->l_len = tswapl(fl.l_len);
+            target_fl->l_start = tswapal(fl.l_start);
+            target_fl->l_len = tswapal(fl.l_len);
             target_fl->l_pid = tswap32(fl.l_pid);
             unlock_user_struct(target_fl, arg, 1);
         }
@@ -3953,8 +4190,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
-        fl.l_start = tswapl(target_fl->l_start);
-        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_start = tswapal(target_fl->l_start);
+        fl.l_len = tswapal(target_fl->l_len);
         fl.l_pid = tswap32(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl));
@@ -3965,8 +4202,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl64.l_type = tswap16(target_fl64->l_type) >> 1;
         fl64.l_whence = tswap16(target_fl64->l_whence);
-        fl64.l_start = tswapl(target_fl64->l_start);
-        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_start = tswap64(target_fl64->l_start);
+        fl64.l_len = tswap64(target_fl64->l_len);
         fl64.l_pid = tswap32(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl64));
@@ -3975,8 +4212,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
                 return -TARGET_EFAULT;
             target_fl64->l_type = tswap16(fl64.l_type) >> 1;
             target_fl64->l_whence = tswap16(fl64.l_whence);
-            target_fl64->l_start = tswapl(fl64.l_start);
-            target_fl64->l_len = tswapl(fl64.l_len);
+            target_fl64->l_start = tswap64(fl64.l_start);
+            target_fl64->l_len = tswap64(fl64.l_len);
             target_fl64->l_pid = tswap32(fl64.l_pid);
             unlock_user_struct(target_fl64, arg, 1);
         }
@@ -3987,8 +4224,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl64.l_type = tswap16(target_fl64->l_type) >> 1;
         fl64.l_whence = tswap16(target_fl64->l_whence);
-        fl64.l_start = tswapl(target_fl64->l_start);
-        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_start = tswap64(target_fl64->l_start);
+        fl64.l_len = tswap64(target_fl64->l_len);
         fl64.l_pid = tswap32(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl64));
@@ -4054,7 +4291,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)
@@ -4128,13 +4389,10 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
                                          abi_long arg3,
                                          abi_long arg4)
 {
-#ifdef TARGET_ARM
-    if (((CPUARMState *)cpu_env)->eabi)
-      {
+    if (regpairs_aligned(cpu_env)) {
         arg2 = arg3;
         arg3 = arg4;
-      }
-#endif
+    }
     return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
 }
 #endif
@@ -4145,13 +4403,10 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
                                           abi_long arg3,
                                           abi_long arg4)
 {
-#ifdef TARGET_ARM
-    if (((CPUARMState *)cpu_env)->eabi)
-      {
+    if (regpairs_aligned(cpu_env)) {
         arg2 = arg3;
         arg3 = arg4;
-      }
-#endif
+    }
     return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
 }
 #endif
@@ -4163,8 +4418,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
 
     if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
         return -TARGET_EFAULT;
-    host_ts->tv_sec = tswapl(target_ts->tv_sec);
-    host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
+    host_ts->tv_sec = tswapal(target_ts->tv_sec);
+    host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 0);
     return 0;
 }
@@ -4176,8 +4431,8 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
         return -TARGET_EFAULT;
-    target_ts->tv_sec = tswapl(host_ts->tv_sec);
-    target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
+    target_ts->tv_sec = tswapal(host_ts->tv_sec);
+    target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 1);
     return 0;
 }
@@ -4350,7 +4605,8 @@ int get_osversion(void)
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
 abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     abi_long arg2, abi_long arg3, abi_long arg4,
-                    abi_long arg5, abi_long arg6)
+                    abi_long arg5, abi_long arg6, abi_long arg7,
+                    abi_long arg8)
 {
     abi_long ret;
     struct stat st;
@@ -4398,8 +4654,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                         NULL, NULL, 0);
           }
           thread_env = NULL;
-          qemu_free(cpu_env);
-          qemu_free(ts);
+          g_free(cpu_env);
+          g_free(ts);
           pthread_exit(NULL);
       }
 #endif
@@ -4740,8 +4996,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             if (arg2) {
                 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                     goto efault;
-                tbuf.actime = tswapl(target_tbuf->actime);
-                tbuf.modtime = tswapl(target_tbuf->modtime);
+                tbuf.actime = tswapal(target_tbuf->actime);
+                tbuf.modtime = tswapal(target_tbuf->modtime);
                 unlock_user_struct(target_tbuf, arg2, 0);
                 host_tbuf = &tbuf;
             } else {
@@ -4898,10 +5154,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                 if (!tmsp)
                     goto efault;
-                tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
-                tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
-                tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
-                tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
+                tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
+                tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
+                tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
+                tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
             }
             if (!is_error(ret))
                 ret = host_to_target_clock_t(ret);
@@ -5360,7 +5616,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
     case TARGET_NR_setrlimit:
         {
-            int resource = arg1;
+            int resource = target_to_host_resource(arg1);
             struct target_rlimit *target_rlim;
             struct rlimit rlim;
             if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
@@ -5373,7 +5629,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
     case TARGET_NR_getrlimit:
         {
-            int resource = arg1;
+            int resource = target_to_host_resource(arg1);
             struct target_rlimit *target_rlim;
             struct rlimit rlim;
 
@@ -5414,7 +5670,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
-#ifdef TARGET_NR_select
+#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
     case TARGET_NR_select:
         {
             struct target_sel_arg_struct *sel;
@@ -5423,11 +5679,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
             if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                 goto efault;
-            nsel = tswapl(sel->n);
-            inp = tswapl(sel->inp);
-            outp = tswapl(sel->outp);
-            exp = tswapl(sel->exp);
-            tvp = tswapl(sel->tvp);
+            nsel = tswapal(sel->n);
+            inp = tswapal(sel->inp);
+            outp = tswapal(sel->outp);
+            exp = tswapal(sel->exp);
+            tvp = tswapal(sel->tvp);
             unlock_user_struct(sel, arg1, 0);
             ret = do_select(nsel, inp, outp, exp, tvp);
         }
@@ -5435,7 +5691,107 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_pselect6
     case TARGET_NR_pselect6:
-           goto unimplemented_nowarn;
+        {
+            abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
+            fd_set rfds, wfds, efds;
+            fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+            struct timespec ts, *ts_ptr;
+
+            /*
+             * The 6th arg is actually two args smashed together,
+             * so we cannot use the C library.
+             */
+            sigset_t set;
+            struct {
+                sigset_t *set;
+                size_t size;
+            } sig, *sig_ptr;
+
+            abi_ulong arg_sigset, arg_sigsize, *arg7;
+            target_sigset_t *target_sigset;
+
+            n = arg1;
+            rfd_addr = arg2;
+            wfd_addr = arg3;
+            efd_addr = arg4;
+            ts_addr = arg5;
+
+            ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+            ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+            ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+
+            /*
+             * This takes a timespec, and not a timeval, so we cannot
+             * use the do_select() helper ...
+             */
+            if (ts_addr) {
+                if (target_to_host_timespec(&ts, ts_addr)) {
+                    goto efault;
+                }
+                ts_ptr = &ts;
+            } else {
+                ts_ptr = NULL;
+            }
+
+            /* Extract the two packed args for the sigset */
+            if (arg6) {
+                sig_ptr = &sig;
+                sig.size = _NSIG / 8;
+
+                arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
+                if (!arg7) {
+                    goto efault;
+                }
+                arg_sigset = tswapal(arg7[0]);
+                arg_sigsize = tswapal(arg7[1]);
+                unlock_user(arg7, arg6, 0);
+
+                if (arg_sigset) {
+                    sig.set = &set;
+                    if (arg_sigsize != sizeof(*target_sigset)) {
+                        /* Like the kernel, we enforce correct size sigsets */
+                        ret = -TARGET_EINVAL;
+                        goto fail;
+                    }
+                    target_sigset = lock_user(VERIFY_READ, arg_sigset,
+                                              sizeof(*target_sigset), 1);
+                    if (!target_sigset) {
+                        goto efault;
+                    }
+                    target_to_host_sigset(&set, target_sigset);
+                    unlock_user(target_sigset, arg_sigset, 0);
+                } else {
+                    sig.set = NULL;
+                }
+            } else {
+                sig_ptr = NULL;
+            }
+
+            ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
+                                         ts_ptr, sig_ptr));
+
+            if (!is_error(ret)) {
+                if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+                    goto efault;
+                if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+                    goto efault;
+                if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+                    goto efault;
+
+                if (ts_addr && host_to_target_timespec(ts_addr, &ts))
+                    goto efault;
+            }
+        }
+        break;
 #endif
     case TARGET_NR_symlink:
         {
@@ -5518,25 +5874,31 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #endif
     case TARGET_NR_reboot:
-        goto unimplemented;
+        if (!(p = lock_user_string(arg4)))
+            goto efault;
+        ret = reboot(arg1, arg2, arg3, p);
+        unlock_user(p, arg4, 0);
+        break;
 #ifdef TARGET_NR_readdir
     case TARGET_NR_readdir:
         goto unimplemented;
 #endif
 #ifdef TARGET_NR_mmap
     case TARGET_NR_mmap:
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
+    defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
+    || defined(TARGET_S390X)
         {
             abi_ulong *v;
             abi_ulong v1, v2, v3, v4, v5, v6;
             if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                 goto efault;
-            v1 = tswapl(v[0]);
-            v2 = tswapl(v[1]);
-            v3 = tswapl(v[2]);
-            v4 = tswapl(v[3]);
-            v5 = tswapl(v[4]);
-            v6 = tswapl(v[5]);
+            v1 = tswapal(v[0]);
+            v2 = tswapal(v[1]);
+            v3 = tswapal(v[2]);
+            v4 = tswapal(v[3]);
+            v5 = tswapal(v[4]);
+            v6 = tswapal(v[5]);
             unlock_user(v, arg1, 0);
             ret = get_errno(target_mmap(v1, v2, v3,
                                         target_to_host_bitmask(v4, mmap_flags_tbl),
@@ -5893,8 +6255,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_syscall
     case TARGET_NR_syscall:
-       ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
-       break;
+        ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
+                         arg6, arg7, arg8, 0);
+        break;
 #endif
     case TARGET_NR_wait4:
         {
@@ -6021,6 +6384,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
 #elif defined(TARGET_CRIS)
         ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
+#elif defined(TARGET_S390X)
+        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
 #else
         ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
 #endif
@@ -6109,16 +6474,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR__llseek /* Not on alpha */
     case TARGET_NR__llseek:
         {
+            int64_t res;
 #if !defined(__NR_llseek)
-            ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
-            if (put_user_s64(ret, arg4))
-                goto efault;
+            res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
+            if (res == -1) {
+                ret = get_errno(res);
+            } else {
+                ret = 0;
+            }
 #else
-            int64_t res;
             ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
-            if (put_user_s64(res, arg4))
-                goto efault;
 #endif
+            if ((ret == 0) && put_user_s64(res, arg4)) {
+                goto efault;
+            }
         }
         break;
 #endif
@@ -6152,8 +6521,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     reclen = de->d_reclen;
                    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
                     tde->d_reclen = tswap16(treclen);
-                    tde->d_ino = tswapl(de->d_ino);
-                    tde->d_off = tswapl(de->d_off);
+                    tde->d_ino = tswapal(de->d_ino);
+                    tde->d_off = tswapal(de->d_off);
                    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
                    if (tnamelen > 256)
                         tnamelen = 256;
@@ -6225,13 +6594,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         }
         break;
 #endif /* TARGET_NR_getdents64 */
-#ifdef TARGET_NR__newselect
+#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
+#ifdef TARGET_S390X
+    case TARGET_NR_select:
+#else
     case TARGET_NR__newselect:
+#endif
         ret = do_select(arg1, arg2, arg3, arg4, arg5);
         break;
 #endif
-#ifdef TARGET_NR_poll
+#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
+# ifdef TARGET_NR_poll
     case TARGET_NR_poll:
+# endif
+# ifdef TARGET_NR_ppoll
+    case TARGET_NR_ppoll:
+# endif
         {
             struct target_pollfd *target_pfd;
             unsigned int nfds = arg2;
@@ -6242,20 +6620,57 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
             if (!target_pfd)
                 goto efault;
+
             pfd = alloca(sizeof(struct pollfd) * nfds);
             for(i = 0; i < nfds; i++) {
                 pfd[i].fd = tswap32(target_pfd[i].fd);
                 pfd[i].events = tswap16(target_pfd[i].events);
             }
-            ret = get_errno(poll(pfd, nfds, timeout));
+
+# ifdef TARGET_NR_ppoll
+            if (num == TARGET_NR_ppoll) {
+                struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
+                target_sigset_t *target_set;
+                sigset_t _set, *set = &_set;
+
+                if (arg3) {
+                    if (target_to_host_timespec(timeout_ts, arg3)) {
+                        unlock_user(target_pfd, arg1, 0);
+                        goto efault;
+                    }
+                } else {
+                    timeout_ts = NULL;
+                }
+
+                if (arg4) {
+                    target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
+                    if (!target_set) {
+                        unlock_user(target_pfd, arg1, 0);
+                        goto efault;
+                    }
+                    target_to_host_sigset(set, target_set);
+                } else {
+                    set = NULL;
+                }
+
+                ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
+
+                if (!is_error(ret) && arg3) {
+                    host_to_target_timespec(arg3, timeout_ts);
+                }
+                if (arg4) {
+                    unlock_user(target_set, arg4, 0);
+                }
+            } else
+# endif
+                ret = get_errno(poll(pfd, nfds, timeout));
+
             if (!is_error(ret)) {
                 for(i = 0; i < nfds; i++) {
                     target_pfd[i].revents = tswap16(pfd[i].revents);
                 }
-                ret += nfds * (sizeof(struct target_pollfd)
-                               - sizeof(struct pollfd));
             }
-            unlock_user(target_pfd, arg1, ret);
+            unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
         }
         break;
 #endif
@@ -6301,6 +6716,56 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
            return value. */
         ret = -TARGET_ENOTDIR;
         break;
+    case TARGET_NR_sched_getaffinity:
+        {
+            unsigned int mask_size;
+            unsigned long *mask;
+
+            /*
+             * sched_getaffinity needs multiples of ulong, so need to take
+             * care of mismatches between target ulong and host ulong sizes.
+             */
+            if (arg2 & (sizeof(abi_ulong) - 1)) {
+                ret = -TARGET_EINVAL;
+                break;
+            }
+            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
+
+            mask = alloca(mask_size);
+            ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
+
+            if (!is_error(ret)) {
+                if (copy_to_user(arg3, mask, ret)) {
+                    goto efault;
+                }
+            }
+        }
+        break;
+    case TARGET_NR_sched_setaffinity:
+        {
+            unsigned int mask_size;
+            unsigned long *mask;
+
+            /*
+             * sched_setaffinity needs multiples of ulong, so need to take
+             * care of mismatches between target ulong and host ulong sizes.
+             */
+            if (arg2 & (sizeof(abi_ulong) - 1)) {
+                ret = -TARGET_EINVAL;
+                break;
+            }
+            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
+
+            mask = alloca(mask_size);
+            if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
+                goto efault;
+            }
+            memcpy(mask, p, arg2);
+            unlock_user_struct(p, arg2, 0);
+
+            ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
+        }
+        break;
     case TARGET_NR_sched_setparam:
         {
             struct sched_param *target_schp;
@@ -6404,20 +6869,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_pread
     case TARGET_NR_pread:
-#ifdef TARGET_ARM
-        if (((CPUARMState *)cpu_env)->eabi)
+        if (regpairs_aligned(cpu_env))
             arg4 = arg5;
-#endif
         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
             goto efault;
         ret = get_errno(pread(arg1, p, arg3, arg4));
         unlock_user(p, arg2, ret);
         break;
     case TARGET_NR_pwrite:
-#ifdef TARGET_ARM
-        if (((CPUARMState *)cpu_env)->eabi)
+        if (regpairs_aligned(cpu_env))
             arg4 = arg5;
-#endif
         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
             goto efault;
         ret = get_errno(pwrite(arg1, p, arg3, arg4));
@@ -6451,7 +6912,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_sigaltstack:
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
     defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
-    defined(TARGET_M68K)
+    defined(TARGET_M68K) || defined(TARGET_S390X)
         ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
         break;
 #else
@@ -6477,7 +6938,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_ugetrlimit:
     {
        struct rlimit rlim;
-       ret = get_errno(getrlimit(arg1, &rlim));
+       int resource = target_to_host_resource(arg1);
+       ret = get_errno(getrlimit(resource, &rlim));
        if (!is_error(ret)) {
            struct target_rlimit *target_rlim;
             if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
@@ -6548,25 +7010,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;
@@ -6576,7 +7045,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;
 
@@ -6589,7 +7058,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);
             }
         }
@@ -6597,7 +7066,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;
 
@@ -6608,7 +7077,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));
         }
@@ -6684,7 +7153,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:
@@ -6814,7 +7282,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_osf_sigprocmask:
         {
             abi_ulong mask;
-            int how = arg1;
+            int how;
             sigset_t set, oldset;
 
             switch(arg1) {
@@ -6833,7 +7301,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             }
             mask = arg2;
             target_to_host_old_sigset(&set, &mask);
-            sigprocmask(arg1, &set, &oldset);
+            sigprocmask(how, &set, &oldset);
             host_to_target_old_sigset(&mask, &oldset);
             ret = mask;
         }
@@ -7161,36 +7629,78 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_readahead
     case TARGET_NR_readahead:
 #if TARGET_ABI_BITS == 32
-#ifdef TARGET_ARM
-        if (((CPUARMState *)cpu_env)->eabi)
-        {
+        if (regpairs_aligned(cpu_env)) {
             arg2 = arg3;
             arg3 = arg4;
             arg4 = arg5;
         }
-#endif
         ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
 #else
         ret = get_errno(readahead(arg1, arg2, arg3));
 #endif
         break;
 #endif
+#ifdef CONFIG_ATTR
 #ifdef TARGET_NR_setxattr
-    case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
     case TARGET_NR_fsetxattr:
-    case TARGET_NR_getxattr:
     case TARGET_NR_lgetxattr:
     case TARGET_NR_fgetxattr:
     case TARGET_NR_listxattr:
     case TARGET_NR_llistxattr:
     case TARGET_NR_flistxattr:
-    case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
         ret = -TARGET_EOPNOTSUPP;
         break;
+    case TARGET_NR_setxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_READ, arg3, arg4, 1);
+            if (p && n && v) {
+                ret = get_errno(setxattr(p, n, v, arg4, arg5));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, 0);
+        }
+        break;
+    case TARGET_NR_getxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+            if (p && n && v) {
+                ret = get_errno(getxattr(p, n, v, arg4));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, arg4);
+        }
+        break;
+    case TARGET_NR_removexattr:
+        {
+            void *p, *n;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            if (p && n) {
+                ret = get_errno(removexattr(p, n));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+        }
+        break;
 #endif
+#endif /* CONFIG_ATTR */
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #if defined(TARGET_MIPS)
@@ -7473,8 +7983,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #if defined(TARGET_NR_sync_file_range)
     case TARGET_NR_sync_file_range:
 #if TARGET_ABI_BITS == 32
+#if defined(TARGET_MIPS)
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
+                                        target_offset64(arg5, arg6), arg7));
+#else
         ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
                                         target_offset64(arg4, arg5), arg6));
+#endif /* !TARGET_MIPS */
 #else
         ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
 #endif
@@ -7491,6 +8006,138 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
         break;
 #endif
+#endif
+#if defined(CONFIG_EPOLL)
+#if defined(TARGET_NR_epoll_create)
+    case TARGET_NR_epoll_create:
+        ret = get_errno(epoll_create(arg1));
+        break;
+#endif
+#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
+    case TARGET_NR_epoll_create1:
+        ret = get_errno(epoll_create1(arg1));
+        break;
+#endif
+#if defined(TARGET_NR_epoll_ctl)
+    case TARGET_NR_epoll_ctl:
+    {
+        struct epoll_event ep;
+        struct epoll_event *epp = 0;
+        if (arg4) {
+            struct target_epoll_event *target_ep;
+            if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
+                goto efault;
+            }
+            ep.events = tswap32(target_ep->events);
+            /* The epoll_data_t union is just opaque data to the kernel,
+             * so we transfer all 64 bits across and need not worry what
+             * actual data type it is.
+             */
+            ep.data.u64 = tswap64(target_ep->data.u64);
+            unlock_user_struct(target_ep, arg4, 0);
+            epp = &ep;
+        }
+        ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
+        break;
+    }
+#endif
+
+#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
+#define IMPLEMENT_EPOLL_PWAIT
+#endif
+#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
+#if defined(TARGET_NR_epoll_wait)
+    case TARGET_NR_epoll_wait:
+#endif
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+    case TARGET_NR_epoll_pwait:
+#endif
+    {
+        struct target_epoll_event *target_ep;
+        struct epoll_event *ep;
+        int epfd = arg1;
+        int maxevents = arg3;
+        int timeout = arg4;
+
+        target_ep = lock_user(VERIFY_WRITE, arg2,
+                              maxevents * sizeof(struct target_epoll_event), 1);
+        if (!target_ep) {
+            goto efault;
+        }
+
+        ep = alloca(maxevents * sizeof(struct epoll_event));
+
+        switch (num) {
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+        case TARGET_NR_epoll_pwait:
+        {
+            target_sigset_t *target_set;
+            sigset_t _set, *set = &_set;
+
+            if (arg5) {
+                target_set = lock_user(VERIFY_READ, arg5,
+                                       sizeof(target_sigset_t), 1);
+                if (!target_set) {
+                    unlock_user(target_ep, arg2, 0);
+                    goto efault;
+                }
+                target_to_host_sigset(set, target_set);
+                unlock_user(target_set, arg5, 0);
+            } else {
+                set = NULL;
+            }
+
+            ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
+            break;
+        }
+#endif
+#if defined(TARGET_NR_epoll_wait)
+        case TARGET_NR_epoll_wait:
+            ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
+            break;
+#endif
+        default:
+            ret = -TARGET_ENOSYS;
+        }
+        if (!is_error(ret)) {
+            int i;
+            for (i = 0; i < ret; i++) {
+                target_ep[i].events = tswap32(ep[i].events);
+                target_ep[i].data.u64 = tswap64(ep[i].data.u64);
+            }
+        }
+        unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
+        break;
+    }
+#endif
+#endif
+#ifdef TARGET_NR_prlimit64
+    case TARGET_NR_prlimit64:
+    {
+        /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
+        struct target_rlimit64 *target_rnew, *target_rold;
+        struct host_rlimit64 rnew, rold, *rnewp = 0;
+        if (arg3) {
+            if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
+                goto efault;
+            }
+            rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
+            rnew.rlim_max = tswap64(target_rnew->rlim_max);
+            unlock_user_struct(target_rnew, arg3, 0);
+            rnewp = &rnew;
+        }
+
+        ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
+        if (!is_error(ret) && arg4) {
+            if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
+                goto efault;
+            }
+            target_rold->rlim_cur = tswap64(rold.rlim_cur);
+            target_rold->rlim_max = tswap64(rold.rlim_max);
+            unlock_user_struct(target_rold, arg4, 1);
+        }
+        break;
+    }
 #endif
     default:
     unimplemented:
index d02a9bf401d6f0d5d2c23bb2be2ffc0bec3a7653..9dd1b8e4cf80bb01bc37282ec6a1d47674a96978 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) \
+    || defined(TARGET_S390X)
 
 #define TARGET_IOC_SIZEBITS    14
 #define TARGET_IOC_DIRBITS     2
@@ -205,9 +209,9 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms
   struct target_cmsghdr *__ptr;
 
   __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg
-                                    + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
-  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapl(__mhdr->msg_control))
-      > tswapl(__mhdr->msg_controllen))
+                                    + TARGET_CMSG_ALIGN (tswapal(__cmsg->cmsg_len)));
+  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapal(__mhdr->msg_control))
+      > tswapal(__mhdr->msg_controllen))
     /* No more entries.  */
     return (struct target_cmsghdr *)0;
   return __cmsg;
@@ -288,7 +292,7 @@ static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
 {
     int i;
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        d->sig[i] = tswapl(s->sig[i]);
+        d->sig[i] = tswapal(s->sig[i]);
 }
 #else
 static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
@@ -315,7 +319,11 @@ 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) \
+    || defined(TARGET_S390X)
 
 #if defined(TARGET_SPARC)
 #define TARGET_SA_NOCLDSTOP    8u
@@ -679,10 +687,49 @@ struct target_rlimit {
 
 #if defined(TARGET_ALPHA)
 #define TARGET_RLIM_INFINITY   0x7fffffffffffffffull
-#elif defined(TARGET_MIPS) || defined(TARGET_SPARC)
+#elif defined(TARGET_MIPS) || (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32)
 #define TARGET_RLIM_INFINITY   0x7fffffffUL
 #else
-#define TARGET_RLIM_INFINITY   ((target_ulong)~0UL)
+#define TARGET_RLIM_INFINITY   ((abi_ulong)-1)
+#endif
+
+#if defined(TARGET_MIPS)
+#define TARGET_RLIMIT_CPU              0
+#define TARGET_RLIMIT_FSIZE            1
+#define TARGET_RLIMIT_DATA             2
+#define TARGET_RLIMIT_STACK            3
+#define TARGET_RLIMIT_CORE             4
+#define TARGET_RLIMIT_RSS              7
+#define TARGET_RLIMIT_NPROC            8
+#define TARGET_RLIMIT_NOFILE           5
+#define TARGET_RLIMIT_MEMLOCK          9
+#define TARGET_RLIMIT_AS               6
+#define TARGET_RLIMIT_LOCKS            10
+#define TARGET_RLIMIT_SIGPENDING       11
+#define TARGET_RLIMIT_MSGQUEUE         12
+#define TARGET_RLIMIT_NICE             13
+#define TARGET_RLIMIT_RTPRIO           14
+#else
+#define TARGET_RLIMIT_CPU              0
+#define TARGET_RLIMIT_FSIZE            1
+#define TARGET_RLIMIT_DATA             2
+#define TARGET_RLIMIT_STACK            3
+#define TARGET_RLIMIT_CORE             4
+#define TARGET_RLIMIT_RSS              5
+#if defined(TARGET_SPARC)
+#define TARGET_RLIMIT_NOFILE           6
+#define TARGET_RLIMIT_NPROC            7
+#else
+#define TARGET_RLIMIT_NPROC            6
+#define TARGET_RLIMIT_NOFILE           7
+#endif
+#define TARGET_RLIMIT_MEMLOCK          8
+#define TARGET_RLIMIT_AS               9
+#define TARGET_RLIMIT_LOCKS            10
+#define TARGET_RLIMIT_SIGPENDING       11
+#define TARGET_RLIMIT_MSGQUEUE         12
+#define TARGET_RLIMIT_NICE             13
+#define TARGET_RLIMIT_RTPRIO           14
 #endif
 
 struct target_pollfd {
@@ -700,6 +747,10 @@ struct target_pollfd {
 #define TARGET_KDSKBMODE       0x4b45
 #define TARGET_KDGKBENT               0x4B46   /* gets one entry in translation table */
 #define TARGET_KDGKBSENT       0x4B48  /* gets one function key string entry */
+#define TARGET_KDGKBLED        0x4B64  /* get led flags (not lights) */
+#define TARGET_KDSKBLED        0x4B65  /* set led flags (not lights) */
+#define TARGET_KDGETLED        0x4B31  /* return current led state */
+#define TARGET_KDSETLED        0x4B32  /* set led state [lights, not flags] */
 
 #define TARGET_SIOCATMARK      0x8905
 
@@ -762,6 +813,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> */
 
@@ -917,6 +971,11 @@ struct target_pollfd {
 #define TARGET_FBIOGET_VSCREENINFO    0x4600
 #define TARGET_FBIOPUT_VSCREENINFO    0x4601
 #define TARGET_FBIOGET_FSCREENINFO    0x4602
+#define TARGET_FBIOGETCMAP            0x4604
+#define TARGET_FBIOPUTCMAP            0x4605
+#define TARGET_FBIOPAN_DISPLAY        0x4606
+#define TARGET_FBIOGET_CON2FBMAP      0x460F
+#define TARGET_FBIOPUT_CON2FBMAP      0x4610
 
 /* vt ioctls */
 #define TARGET_VT_OPENQRY             0x5600
@@ -925,6 +984,10 @@ struct target_pollfd {
 #define TARGET_VT_WAITACTIVE          0x5607
 #define TARGET_VT_LOCKSWITCH          0x560b
 #define TARGET_VT_UNLOCKSWITCH        0x560c
+#define TARGET_VT_GETMODE             0x5601
+#define TARGET_VT_SETMODE             0x5602
+#define TARGET_VT_RELDISP             0x5605
+#define TARGET_VT_DISALLOCATE         0x5608
 
 /* from asm/termbits.h */
 
@@ -999,9 +1062,11 @@ struct target_winsize {
 #define TARGET_MAP_NORESERVE   0x4000          /* don't check for reservations */
 #define TARGET_MAP_POPULATE    0x8000          /* populate (prefault) pagetables */
 #define TARGET_MAP_NONBLOCK    0x10000         /* do not block on IO */
+#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;
@@ -1060,7 +1125,7 @@ struct target_stat64 {
        abi_ulong       __pad7;         /* will be high 32 bits of ctime someday */
 
        unsigned long long      st_ino;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #ifdef TARGET_ARM
 struct target_eabi_stat64 {
@@ -1091,7 +1156,7 @@ struct target_eabi_stat64 {
         abi_ulong    target_st_ctime_nsec;
 
         unsigned long long st_ino;
-} __attribute__ ((packed));
+} QEMU_PACKED;
 #endif
 
 #elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
@@ -1234,7 +1299,7 @@ struct target_stat {
 #endif
 };
 
-struct __attribute__((__packed__)) target_stat64 {
+struct QEMU_PACKED target_stat64 {
        unsigned long long st_dev;
         unsigned long long st_ino;
        unsigned int st_mode;
@@ -1281,7 +1346,7 @@ struct target_stat {
 };
 
 /* FIXME: Microblaze no-mmu user-space has a difference stat64 layout...  */
-struct __attribute__((__packed__)) target_stat64 {
+struct QEMU_PACKED target_stat64 {
        uint64_t st_dev;
 #define TARGET_STAT64_HAS_BROKEN_ST_INO 1
        uint32_t pad0;
@@ -1368,7 +1433,7 @@ struct target_stat64 {
        abi_ulong       target_st_ctime_nsec;
 
        unsigned long long      st_ino;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #elif defined(TARGET_ABI_MIPSN64)
 
@@ -1620,7 +1685,7 @@ struct target_stat {
 /* This matches struct stat64 in glibc2.1, hence the absolutely
  * insane amounts of padding around dev_t's.
  */
-struct __attribute__((__packed__)) target_stat64 {
+struct QEMU_PACKED target_stat64 {
        unsigned long long      st_dev;
        unsigned char   __pad0[4];
 
@@ -1677,6 +1742,27 @@ struct target_stat {
 
        abi_long        __unused[3];
 };
+#elif defined(TARGET_S390X)
+struct target_stat {
+    abi_ulong  st_dev;
+    abi_ulong  st_ino;
+    abi_ulong  st_nlink;
+    unsigned int   st_mode;
+    unsigned int   st_uid;
+    unsigned int   st_gid;
+    unsigned int   __pad1;
+    abi_ulong  st_rdev;
+    abi_ulong  st_size;
+    abi_ulong  target_st_atime;
+    abi_ulong  target_st_atime_nsec;
+    abi_ulong  target_st_mtime;
+    abi_ulong  target_st_mtime_nsec;
+    abi_ulong  target_st_ctime;
+    abi_ulong  target_st_ctime_nsec;
+    abi_ulong  st_blksize;
+    abi_long       st_blocks;
+    abi_ulong  __unused[3];
+};
 #else
 #error unsupported CPU
 #endif
@@ -1763,6 +1849,34 @@ struct target_statfs64 {
        abi_long f_frsize;
        abi_long f_spare[5];
 };
+#elif defined(TARGET_S390X)
+struct target_statfs {
+    int32_t  f_type;
+    int32_t  f_bsize;
+    abi_long f_blocks;
+    abi_long f_bfree;
+    abi_long f_bavail;
+    abi_long f_files;
+    abi_long f_ffree;
+    kernel_fsid_t f_fsid;
+    int32_t  f_namelen;
+    int32_t  f_frsize;
+    int32_t  f_spare[5];
+};
+
+struct target_statfs64 {
+    int32_t  f_type;
+    int32_t  f_bsize;
+    abi_long f_blocks;
+    abi_long f_bfree;
+    abi_long f_bavail;
+    abi_long f_files;
+    abi_long f_ffree;
+    kernel_fsid_t f_fsid;
+    int32_t  f_namelen;
+    int32_t  f_frsize;
+    int32_t  f_spare[5];
+};
 #else
 struct target_statfs {
        uint32_t f_type;
@@ -1986,7 +2100,7 @@ struct target_flock64 {
        unsigned long long l_start;
        unsigned long long l_len;
        int  l_pid;
-}__attribute__((packed));
+} QEMU_PACKED;
 
 #ifdef TARGET_ARM
 struct target_eabi_flock64 {
@@ -1996,7 +2110,7 @@ struct target_eabi_flock64 {
        unsigned long long l_start;
        unsigned long long l_len;
        int  l_pid;
-}__attribute__((packed));
+} QEMU_PACKED;
 #endif
 
 /* soundcard defines */
@@ -2205,3 +2319,20 @@ struct target_mq_attr {
 #define FUTEX_CLOCK_REALTIME    256
 #define FUTEX_CMD_MASK          ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
 
+#ifdef CONFIG_EPOLL
+typedef union target_epoll_data {
+    abi_ulong ptr;
+    abi_ulong fd;
+    uint32_t u32;
+    uint64_t u64;
+} target_epoll_data_t;
+
+struct target_epoll_event {
+    uint32_t events;
+    target_epoll_data_t data;
+};
+#endif
+struct target_rlimit64 {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
index 0e67cd8f30e4141fadfc7134b67dda7d8b332fef..c37012517084c8cc78c9889be82102b6faeb4ded 100644 (file)
@@ -161,11 +161,31 @@ STRUCT(fb_var_screeninfo,
        TYPE_INT, /* rotate */
        MK_ARRAY(TYPE_INT, 5)) /* reserved */
 
+STRUCT(fb_cmap,
+       TYPE_INT, /* start  */
+       TYPE_INT, /* len    */
+       TYPE_PTRVOID, /* red    */
+       TYPE_PTRVOID, /* green  */
+       TYPE_PTRVOID, /* blue   */
+       TYPE_PTRVOID) /* transp */
+
+STRUCT(fb_con2fbmap,
+       TYPE_INT, /* console     */
+       TYPE_INT) /* framebuffer */
+
+
 STRUCT(vt_stat,
        TYPE_SHORT, /* v_active */
        TYPE_SHORT, /* v_signal */
        TYPE_SHORT) /* v_state */
 
+STRUCT(vt_mode,
+       TYPE_CHAR,  /* mode   */
+       TYPE_CHAR,  /* waitv  */
+       TYPE_SHORT, /* relsig */
+       TYPE_SHORT, /* acqsig */
+       TYPE_SHORT) /* frsig  */
+
 STRUCT(fiemap_extent,
        TYPE_ULONGLONG, /* fe_logical */
        TYPE_ULONGLONG, /* fe_physical */
diff --git a/linux-user/target_flat.h b/linux-user/target_flat.h
new file mode 100644 (file)
index 0000000..0ba6bdd
--- /dev/null
@@ -0,0 +1,10 @@
+/* If your arch needs to do custom stuff, create your own target_flat.h
+ * header file in linux-user/<your arch>/
+ */
+#define flat_argvp_envp_on_stack()                           1
+#define flat_reloc_valid(reloc, size)                        ((reloc) <= (size))
+#define flat_old_ram_flag(flag)                              (flag)
+#define flat_get_relocate_addr(relval)                       (relval)
+#define flat_get_addr_from_rp(rp, relval, flags, persistent) (rp)
+#define flat_set_persistent(relval, persistent)              (*persistent)
+#define flat_put_addr_at_rp(rp, addr, relval)                put_user_ual(addr, rp)
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 0b2439dfa3cb594c5e0c5b68cddb98ae7d1f6579..2c4ffeb551f3c884118d37a00d9caee044b7079c 100644 (file)
@@ -432,7 +432,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
     env->eflags = (env->eflags & ~SAFE_MASK) |
         (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
 
-    ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
+    ts->vm86plus.cpu_type = tswapal(target_v86->cpu_type);
     switch (ts->vm86plus.cpu_type) {
     case TARGET_CPU_286:
         ts->v86mask = 0;
@@ -468,7 +468,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
            &target_v86->int_revectored, 32);
     memcpy(&ts->vm86plus.int21_revectored,
            &target_v86->int21_revectored, 32);
-    ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
+    ts->vm86plus.vm86plus.flags = tswapal(target_v86->vm86plus.flags);
     memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
            target_v86->vm86plus.vm86dbg_intxxtab, 32);
     unlock_user_struct(target_v86, vm86_addr, 0);
index 568a901d71d823c1edd8ad8962662c599a50f372..947e961ce434666dbcdf622bcde6bb2f7f7f04c4 100644 (file)
 #define TARGET_NR_dup3                 292
 #define TARGET_NR_pipe2                293
 #define TARGET_NR_inotify_init1        294
+#define TARGET_NR_preadv                295
+#define TARGET_NR_pwritev               296
+#define TARGET_NR_rt_tgsigqueueinfo     297
+#define TARGET_NR_perf_event_open       298
+#define TARGET_NR_recvmmsg              299
+#define TARGET_NR_fanotify_init         300
+#define TARGET_NR_fanotify_mark         301
+#define TARGET_NR_prlimit64             302
+#define TARGET_NR_name_to_handle_at     303
+#define TARGET_NR_open_by_handle_at     304
+#define TARGET_NR_clock_adjtime         305
+#define TARGET_NR_syncfs                306
index 0371089b982c47e14a3cf0160a86359d6870335c..bab01ee863181985291e02a9e455cc720c04ff97 100644 (file)
@@ -70,12 +70,12 @@ struct m68k_gdb_stat {
   gdb_time_t  gdb_st_atime;   /* time of last access */
   gdb_time_t  gdb_st_mtime;   /* time of last modification */
   gdb_time_t  gdb_st_ctime;   /* time of last change */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 struct gdb_timeval {
   gdb_time_t tv_sec;  /* second */
   uint64_t tv_usec;   /* microsecond */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #define GDB_O_RDONLY   0x0
 #define GDB_O_WRONLY   0x1
@@ -370,7 +370,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         TaskState *ts = env->opaque;
         /* Allocate the heap using sbrk.  */
         if (!ts->heap_limit) {
-            long ret;
+            abi_ulong ret;
             uint32_t size;
             uint32_t base;
 
@@ -379,8 +379,9 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
             /* Try a big heap, and reduce the size if that fails.  */
             for (;;) {
                 ret = do_brk(base + size);
-                if (ret != -1)
+                if (ret >= (base + size)) {
                     break;
+                }
                 size >>= 1;
             }
             ts->heap_limit = base + size;
diff --git a/main-loop.c b/main-loop.c
new file mode 100644 (file)
index 0000000..cd5a352
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * QEMU System Emulator
+ *
+ * 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "slirp/slirp.h"
+#include "main-loop.h"
+
+#ifndef _WIN32
+
+#include "compatfd.h"
+
+static int io_thread_fd = -1;
+
+void qemu_notify_event(void)
+{
+    /* Write 8 bytes to be compatible with eventfd.  */
+    static const uint64_t val = 1;
+    ssize_t ret;
+
+    if (io_thread_fd == -1) {
+        return;
+    }
+    do {
+        ret = write(io_thread_fd, &val, sizeof(val));
+    } while (ret < 0 && errno == EINTR);
+
+    /* EAGAIN is fine, a read must be pending.  */
+    if (ret < 0 && errno != EAGAIN) {
+        fprintf(stderr, "qemu_notify_event: write() failed: %s\n",
+                strerror(errno));
+        exit(1);
+    }
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    ssize_t len;
+    char buffer[512];
+
+    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
+    do {
+        len = read(fd, buffer, sizeof(buffer));
+    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+}
+
+static int qemu_event_init(void)
+{
+    int err;
+    int fds[2];
+
+    err = qemu_eventfd(fds);
+    if (err == -1) {
+        return -errno;
+    }
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(intptr_t)fds[0]);
+
+    io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN) {
+            break;
+        }
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+        } else if (action.sa_handler) {
+            action.sa_handler(info.ssi_signo);
+        }
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    int sigfd;
+    sigset_t set;
+
+    /*
+     * SIG_IPI must be blocked in the main thread and must not be caught
+     * by sigwait() in the signal thread. Otherwise, the cpu thread will
+     * not catch it reliably.
+     */
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    sigaddset(&set, SIGBUS);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigfd = qemu_signalfd(&set);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl_setfl(sigfd, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(intptr_t)sigfd);
+
+    return 0;
+}
+
+#else /* _WIN32 */
+
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+        return -1;
+    }
+    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+extern void qemu_notify_hax_event(void);
+
+void qemu_notify_event(void)
+{
+#ifdef CONFIG_HAX
+    qemu_notify_hax_event();
+#endif
+    if (!SetEvent(qemu_event_handle)) {
+        fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
+                GetLastError());
+        exit(1);
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    return 0;
+}
+#endif
+
+int qemu_init_main_loop(void)
+{
+    int ret;
+
+    qemu_mutex_lock_iothread();
+    ret = qemu_signal_init();
+    if (ret) {
+        return ret;
+    }
+
+    /* Note eventfd must be drained before signalfd handlers run */
+    ret = qemu_event_init();
+    if (ret) {
+        return ret;
+    }
+
+    return 0;
+}
+
+
+static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
+static int n_poll_fds;
+static int max_priority;
+
+static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
+                             fd_set *xfds, struct timeval *tv)
+{
+    GMainContext *context = g_main_context_default();
+    int i;
+    int timeout = 0, cur_timeout;
+
+    g_main_context_prepare(context, &max_priority);
+
+    n_poll_fds = g_main_context_query(context, max_priority, &timeout,
+                                      poll_fds, ARRAY_SIZE(poll_fds));
+    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
+
+    for (i = 0; i < n_poll_fds; i++) {
+        GPollFD *p = &poll_fds[i];
+
+        if ((p->events & G_IO_IN)) {
+            FD_SET(p->fd, rfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+        if ((p->events & G_IO_OUT)) {
+            FD_SET(p->fd, wfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+        if ((p->events & G_IO_ERR)) {
+            FD_SET(p->fd, xfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+    }
+
+    cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
+    if (timeout >= 0 && timeout < cur_timeout) {
+        tv->tv_sec = timeout / 1000;
+        tv->tv_usec = (timeout % 1000) * 1000;
+    }
+}
+
+static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
+                             bool err)
+{
+    GMainContext *context = g_main_context_default();
+
+    if (!err) {
+        int i;
+
+        for (i = 0; i < n_poll_fds; i++) {
+            GPollFD *p = &poll_fds[i];
+
+            if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
+                p->revents |= G_IO_IN;
+            }
+            if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
+                p->revents |= G_IO_OUT;
+            }
+            if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
+                p->revents |= G_IO_ERR;
+            }
+        }
+    }
+
+    if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+        g_main_context_dispatch(context);
+    }
+}
+
+#ifdef _WIN32
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+    PollingFunc *func;
+    void *opaque;
+    struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    pe = g_malloc0(sizeof(PollingEntry));
+    pe->func = func;
+    pe->opaque = opaque;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+    *ppe = pe;
+    return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+        pe = *ppe;
+        if (pe->func == func && pe->opaque == opaque) {
+            *ppe = pe->next;
+            g_free(pe);
+            break;
+        }
+    }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+    int num;
+    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    WaitObjects *w = &wait_objects;
+    if (w->num >= MAXIMUM_WAIT_OBJECTS) {
+        return -1;
+    }
+    w->events[w->num] = handle;
+    w->func[w->num] = func;
+    w->opaque[w->num] = opaque;
+    w->num++;
+    return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    int i, found;
+    WaitObjects *w = &wait_objects;
+
+    found = 0;
+    for (i = 0; i < w->num; i++) {
+        if (w->events[i] == handle) {
+            found = 1;
+        }
+        if (found) {
+            w->events[i] = w->events[i + 1];
+            w->func[i] = w->func[i + 1];
+            w->opaque[i] = w->opaque[i + 1];
+        }
+    }
+    if (found) {
+        w->num--;
+    }
+}
+
+static void os_host_main_loop_wait(int *timeout)
+{
+    int ret, ret2, i;
+    PollingEntry *pe;
+
+    /* XXX: need to suppress polling by better using win32 events */
+    ret = 0;
+    for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
+        ret |= pe->func(pe->opaque);
+    }
+    if (ret == 0) {
+        int err;
+        WaitObjects *w = &wait_objects;
+
+        qemu_mutex_unlock_iothread();
+        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+        qemu_mutex_lock_iothread();
+        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+            if (w->func[ret - WAIT_OBJECT_0]) {
+                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+            }
+
+            /* Check for additional signaled events */
+            for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+                /* Check if event is signaled */
+                ret2 = WaitForSingleObject(w->events[i], 0);
+                if (ret2 == WAIT_OBJECT_0) {
+                    if (w->func[i]) {
+                        w->func[i](w->opaque[i]);
+                    }
+                } else if (ret2 != WAIT_TIMEOUT) {
+                    err = GetLastError();
+                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+                }
+            }
+        } else if (ret != WAIT_TIMEOUT) {
+            err = GetLastError();
+            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+        }
+    }
+
+    *timeout = 0;
+}
+#else
+static inline void os_host_main_loop_wait(int *timeout)
+{
+}
+#endif
+
+int main_loop_wait(int nonblocking)
+{
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+    int timeout;
+
+    if (nonblocking) {
+        timeout = 0;
+    } else {
+        timeout = qemu_calculate_timeout();
+        qemu_bh_update_timeout(&timeout);
+    }
+
+    os_host_main_loop_wait(&timeout);
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    /* poll any events */
+    /* XXX: separate device handlers from system ones */
+    nfds = -1;
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+
+#ifdef CONFIG_SLIRP
+    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+#endif
+    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+#ifndef _WIN32
+    glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
+#endif // _WIN32
+
+    if (timeout > 0) {
+        qemu_mutex_unlock_iothread();
+    }
+
+    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+
+    if (timeout > 0) {
+        qemu_mutex_lock_iothread();
+    }
+
+    glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+#ifdef CONFIG_SLIRP
+    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+#endif
+
+    qemu_run_all_timers();
+
+    /* Check bottom-halves last in case any of the earlier events triggered
+       them.  */
+    qemu_bh_poll();
+
+    return ret;
+}
diff --git a/main-loop.h b/main-loop.h
new file mode 100644 (file)
index 0000000..8a716b1
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * QEMU System Emulator
+ *
+ * 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.
+ */
+
+#ifndef QEMU_MAIN_LOOP_H
+#define QEMU_MAIN_LOOP_H 1
+
+#ifdef SIGRTMIN
+#define SIG_IPI (SIGRTMIN+4)
+#else
+#define SIG_IPI SIGUSR1
+#endif
+
+/**
+ * qemu_init_main_loop: Set up the process so that it can run the main loop.
+ *
+ * This includes setting up signal handlers.  It should be called before
+ * any other threads are created.  In addition, threads other than the
+ * main one should block signals that are trapped by the main loop.
+ * For simplicity, you can consider these signals to be safe: SIGUSR1,
+ * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
+ * signals if available.  Remember that Windows in practice does not have
+ * signals, though.
+ */
+int qemu_init_main_loop(void);
+
+/**
+ * main_loop_wait: Run one iteration of the main loop.
+ *
+ * If @nonblocking is true, poll for events, otherwise suspend until
+ * one actually occurs.  The main loop usually consists of a loop that
+ * repeatedly calls main_loop_wait(false).
+ *
+ * Main loop services include file descriptor callbacks, bottom halves
+ * and timers (defined in qemu-timer.h).  Bottom halves are similar to timers
+ * that execute immediately, but have a lower overhead and scheduling them
+ * is wait-free, thread-safe and signal-safe.
+ *
+ * It is sometimes useful to put a whole program in a coroutine.  In this
+ * case, the coroutine actually should be started from within the main loop,
+ * so that the main loop can run whenever the coroutine yields.  To do this,
+ * you can use a bottom half to enter the coroutine as soon as the main loop
+ * starts:
+ *
+ *     void enter_co_bh(void *opaque) {
+ *         QEMUCoroutine *co = opaque;
+ *         qemu_coroutine_enter(co, NULL);
+ *     }
+ *
+ *     ...
+ *     QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry);
+ *     QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co);
+ *     qemu_bh_schedule(start_bh);
+ *     while (...) {
+ *         main_loop_wait(false);
+ *     }
+ *
+ * (In the future we may provide a wrapper for this).
+ *
+ * @nonblocking: Whether the caller should block until an event occurs.
+ */
+int main_loop_wait(int nonblocking);
+
+/**
+ * qemu_notify_event: Force processing of pending events.
+ *
+ * Similar to signaling a condition variable, qemu_notify_event forces
+ * main_loop_wait to look at pending events and exit.  The caller of
+ * main_loop_wait will usually call it again very soon, so qemu_notify_event
+ * also has the side effect of recalculating the sets of file descriptors
+ * that the main loop waits for.
+ *
+ * Calling qemu_notify_event is rarely necessary, because main loop
+ * services (bottom halves and timers) call it themselves.  One notable
+ * exception occurs when using qemu_set_fd_handler2 (see below).
+ */
+void qemu_notify_event(void);
+
+#ifdef _WIN32
+/* return TRUE if no sleep should be done afterwards */
+typedef int PollingFunc(void *opaque);
+
+/**
+ * qemu_add_polling_cb: Register a Windows-specific polling callback
+ *
+ * Currently, under Windows some events are polled rather than waited for.
+ * Polling callbacks do not ensure that @func is called timely, because
+ * the main loop might wait for an arbitrarily long time.  If possible,
+ * you should instead create a separate thread that does a blocking poll
+ * and set a Win32 event object.  The event can then be passed to
+ * qemu_add_wait_object.
+ *
+ * Polling callbacks really have nothing Windows specific in them, but
+ * as they are a hack and are currenly not necessary under POSIX systems,
+ * they are only available when QEMU is running under Windows.
+ *
+ * @func: The function that does the polling, and returns 1 to force
+ * immediate completion of main_loop_wait.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_polling_cb(PollingFunc *func, void *opaque);
+
+/**
+ * qemu_del_polling_cb: Unregister a Windows-specific polling callback
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_polling_cb.
+ *
+ * @func: The function that was passed to qemu_add_polling_cb.
+ * @opaque: A pointer-size value that was passed to qemu_add_polling_cb.
+ */
+void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+/**
+ * qemu_add_wait_object: Register a callback for a Windows handle
+ *
+ * Under Windows, the iohandler mechanism can only be used with sockets.
+ * QEMU must use the WaitForMultipleObjects API to wait on other handles.
+ * This function registers a #HANDLE with QEMU, so that it will be included
+ * in the main loop's calls to WaitForMultipleObjects.  When the handle
+ * is in a signaled state, QEMU will call @func.
+ *
+ * @handle: The Windows handle to be observed.
+ * @func: A function to be called when @handle is in a signaled state.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+
+/**
+ * qemu_del_wait_object: Unregister a callback for a Windows handle
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_wait_object.
+ *
+ * @func: The function that was passed to qemu_add_wait_object.
+ * @opaque: A pointer-size value that was passed to qemu_add_wait_object.
+ */
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+#endif
+
+/* async I/O support */
+
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanReadHandler(void *opaque);
+typedef void IOHandler(void *opaque);
+
+/**
+ * qemu_set_fd_handler2: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * @fd_read_poll can be used to disable the @fd_read callback temporarily.
+ * This is useful to avoid calling qemu_set_fd_handler2 every time the
+ * client becomes interested in reading (or dually, stops being interested).
+ * A typical example is when @fd is a listening socket and you want to bound
+ * the number of active clients.  Remember to call qemu_notify_event whenever
+ * the condition may change from %false to %true.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler2 are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed.  Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read_poll: A function that returns 1 if the @fd_read callback
+ * should be fired.  If the function returns 0, the main loop will not
+ * end its iteration even if @fd becomes readable.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read_poll,
+ * @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque);
+
+/**
+ * qemu_set_fd_handler: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed.  Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque);
+
+typedef struct QEMUBH QEMUBH;
+typedef void QEMUBHFunc(void *opaque);
+
+/**
+ * qemu_bh_new: Allocate a new bottom half structure.
+ *
+ * Bottom halves are lightweight callbacks whose invocation is guaranteed
+ * to be wait-free, thread-safe and signal-safe.  The #QEMUBH structure
+ * is opaque and must be allocated prior to its use.
+ */
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
+
+/**
+ * qemu_bh_schedule: Schedule a bottom half.
+ *
+ * Scheduling a bottom half interrupts the main loop and causes the
+ * execution of the callback that was passed to qemu_bh_new.
+ *
+ * Bottom halves that are scheduled from a bottom half handler are instantly
+ * invoked.  This can create an infinite loop if a bottom half handler
+ * schedules itself.
+ *
+ * @bh: The bottom half to be scheduled.
+ */
+void qemu_bh_schedule(QEMUBH *bh);
+
+/**
+ * qemu_bh_cancel: Cancel execution of a bottom half.
+ *
+ * Canceling execution of a bottom half undoes the effect of calls to
+ * qemu_bh_schedule without freeing its resources yet.  While cancellation
+ * itself is also wait-free and thread-safe, it can of course race with the
+ * loop that executes bottom halves unless you are holding the iothread
+ * mutex.  This makes it mostly useless if you are not holding the mutex.
+ *
+ * @bh: The bottom half to be canceled.
+ */
+void qemu_bh_cancel(QEMUBH *bh);
+
+/**
+ *qemu_bh_delete: Cancel execution of a bottom half and free its resources.
+ *
+ * Deleting a bottom half frees the memory that was allocated for it by
+ * qemu_bh_new.  It also implies canceling the bottom half if it was
+ * scheduled.
+ *
+ * @bh: The bottom half to be deleted.
+ */
+void qemu_bh_delete(QEMUBH *bh);
+
+#ifdef CONFIG_POSIX
+/**
+ * qemu_add_child_watch: Register a child process for reaping.
+ *
+ * Under POSIX systems, a parent process must read the exit status of
+ * its child processes using waitpid, or the operating system will not
+ * free some of the resources attached to that process.
+ *
+ * This function directs the QEMU main loop to observe a child process
+ * and call waitpid as soon as it exits; the watch is then removed
+ * automatically.  It is useful whenever QEMU forks a child process
+ * but will find out about its termination by other means such as a
+ * "broken pipe".
+ *
+ * @pid: The pid that QEMU should observe.
+ */
+int qemu_add_child_watch(pid_t pid);
+#endif
+
+/**
+ * qemu_mutex_lock_iothread: Lock the main loop mutex.
+ *
+ * This function locks the main loop mutex.  The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select).  The mutex should be taken
+ * by threads other than the main loop thread when calling
+ * qemu_bh_new(), qemu_set_fd_handler() and basically all other
+ * functions documented in this file.
+ */
+void qemu_mutex_lock_iothread(void);
+
+/**
+ * qemu_mutex_unlock_iothread: Unlock the main loop mutex.
+ *
+ * This function unlocks the main loop mutex.  The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select).  The mutex should be unlocked
+ * as soon as possible by threads other than the main loop thread,
+ * because it prevents the main loop from processing callbacks,
+ * including timers and bottom halves.
+ */
+void qemu_mutex_unlock_iothread(void);
+
+/* internal interfaces */
+
+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);
+
+void qemu_bh_schedule_idle(QEMUBH *bh);
+int qemu_bh_poll(void);
+void qemu_bh_update_timeout(int *timeout);
+
+#endif
diff --git a/memory.c b/memory.c
new file mode 100644 (file)
index 0000000..7c20a07
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,1437 @@
+/*
+ * Physical memory management
+ *
+ * Copyright 2011 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Avi Kivity <avi@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "memory.h"
+#include "exec-memory.h"
+#include "ioport.h"
+#include "bitops.h"
+#include "kvm.h"
+#include <assert.h>
+
+unsigned memory_region_transaction_depth = 0;
+
+typedef struct AddrRange AddrRange;
+
+/*
+ * Note using signed integers limits us to physical addresses at most
+ * 63 bits wide.  They are needed for negative offsetting in aliases
+ * (large MemoryRegion::alias_offset).
+ */
+struct AddrRange {
+    Int128 start;
+    Int128 size;
+};
+
+static AddrRange addrrange_make(Int128 start, Int128 size)
+{
+    return (AddrRange) { start, size };
+}
+
+static bool addrrange_equal(AddrRange r1, AddrRange r2)
+{
+    return int128_eq(r1.start, r2.start) && int128_eq(r1.size, r2.size);
+}
+
+static Int128 addrrange_end(AddrRange r)
+{
+    return int128_add(r.start, r.size);
+}
+
+static AddrRange addrrange_shift(AddrRange range, Int128 delta)
+{
+    int128_addto(&range.start, delta);
+    return range;
+}
+
+static bool addrrange_contains(AddrRange range, Int128 addr)
+{
+    return int128_ge(addr, range.start)
+        && int128_lt(addr, addrrange_end(range));
+}
+
+static bool addrrange_intersects(AddrRange r1, AddrRange r2)
+{
+    return addrrange_contains(r1, r2.start)
+        || addrrange_contains(r2, r1.start);
+}
+
+static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
+{
+    Int128 start = int128_max(r1.start, r2.start);
+    Int128 end = int128_min(addrrange_end(r1), addrrange_end(r2));
+    return addrrange_make(start, int128_sub(end, start));
+}
+
+struct CoalescedMemoryRange {
+    AddrRange addr;
+    QTAILQ_ENTRY(CoalescedMemoryRange) link;
+};
+
+struct MemoryRegionIoeventfd {
+    AddrRange addr;
+    bool match_data;
+    uint64_t data;
+    int fd;
+};
+
+static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a,
+                                           MemoryRegionIoeventfd b)
+{
+    if (int128_lt(a.addr.start, b.addr.start)) {
+        return true;
+    } else if (int128_gt(a.addr.start, b.addr.start)) {
+        return false;
+    } else if (int128_lt(a.addr.size, b.addr.size)) {
+        return true;
+    } else if (int128_gt(a.addr.size, b.addr.size)) {
+        return false;
+    } else if (a.match_data < b.match_data) {
+        return true;
+    } else  if (a.match_data > b.match_data) {
+        return false;
+    } else if (a.match_data) {
+        if (a.data < b.data) {
+            return true;
+        } else if (a.data > b.data) {
+            return false;
+        }
+    }
+    if (a.fd < b.fd) {
+        return true;
+    } else if (a.fd > b.fd) {
+        return false;
+    }
+    return false;
+}
+
+static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
+                                          MemoryRegionIoeventfd b)
+{
+    return !memory_region_ioeventfd_before(a, b)
+        && !memory_region_ioeventfd_before(b, a);
+}
+
+typedef struct FlatRange FlatRange;
+typedef struct FlatView FlatView;
+
+/* Range of memory in the global map.  Addresses are absolute. */
+struct FlatRange {
+    MemoryRegion *mr;
+    target_phys_addr_t offset_in_region;
+    AddrRange addr;
+    uint8_t dirty_log_mask;
+    bool readable;
+    bool readonly;
+};
+
+/* Flattened global view of current active memory hierarchy.  Kept in sorted
+ * order.
+ */
+struct FlatView {
+    FlatRange *ranges;
+    unsigned nr;
+    unsigned nr_allocated;
+};
+
+typedef struct AddressSpace AddressSpace;
+typedef struct AddressSpaceOps AddressSpaceOps;
+
+/* A system address space - I/O, memory, etc. */
+struct AddressSpace {
+    const AddressSpaceOps *ops;
+    MemoryRegion *root;
+    FlatView current_map;
+    int ioeventfd_nb;
+    MemoryRegionIoeventfd *ioeventfds;
+};
+
+struct AddressSpaceOps {
+    void (*range_add)(AddressSpace *as, FlatRange *fr);
+    void (*range_del)(AddressSpace *as, FlatRange *fr);
+    void (*log_start)(AddressSpace *as, FlatRange *fr);
+    void (*log_stop)(AddressSpace *as, FlatRange *fr);
+    void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIoeventfd *fd);
+    void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIoeventfd *fd);
+};
+
+#define FOR_EACH_FLAT_RANGE(var, view)          \
+    for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
+
+static bool flatrange_equal(FlatRange *a, FlatRange *b)
+{
+    return a->mr == b->mr
+        && addrrange_equal(a->addr, b->addr)
+        && a->offset_in_region == b->offset_in_region
+        && a->readable == b->readable
+        && a->readonly == b->readonly;
+}
+
+static void flatview_init(FlatView *view)
+{
+    view->ranges = NULL;
+    view->nr = 0;
+    view->nr_allocated = 0;
+}
+
+/* Insert a range into a given position.  Caller is responsible for maintaining
+ * sorting order.
+ */
+static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range)
+{
+    if (view->nr == view->nr_allocated) {
+        view->nr_allocated = MAX(2 * view->nr, 10);
+        view->ranges = g_realloc(view->ranges,
+                                    view->nr_allocated * sizeof(*view->ranges));
+    }
+    memmove(view->ranges + pos + 1, view->ranges + pos,
+            (view->nr - pos) * sizeof(FlatRange));
+    view->ranges[pos] = *range;
+    ++view->nr;
+}
+
+static void flatview_destroy(FlatView *view)
+{
+    g_free(view->ranges);
+}
+
+static bool can_merge(FlatRange *r1, FlatRange *r2)
+{
+    return int128_eq(addrrange_end(r1->addr), r2->addr.start)
+        && r1->mr == r2->mr
+        && int128_eq(int128_add(int128_make64(r1->offset_in_region),
+                                r1->addr.size),
+                     int128_make64(r2->offset_in_region))
+        && r1->dirty_log_mask == r2->dirty_log_mask
+        && r1->readable == r2->readable
+        && r1->readonly == r2->readonly;
+}
+
+/* Attempt to simplify a view by merging ajacent ranges */
+static void flatview_simplify(FlatView *view)
+{
+    unsigned i, j;
+
+    i = 0;
+    while (i < view->nr) {
+        j = i + 1;
+        while (j < view->nr
+               && can_merge(&view->ranges[j-1], &view->ranges[j])) {
+            int128_addto(&view->ranges[i].addr.size, view->ranges[j].addr.size);
+            ++j;
+        }
+        ++i;
+        memmove(&view->ranges[i], &view->ranges[j],
+                (view->nr - j) * sizeof(view->ranges[j]));
+        view->nr -= j - i;
+    }
+}
+
+static void memory_region_read_accessor(void *opaque,
+                                        target_phys_addr_t addr,
+                                        uint64_t *value,
+                                        unsigned size,
+                                        unsigned shift,
+                                        uint64_t mask)
+{
+    MemoryRegion *mr = opaque;
+    uint64_t tmp;
+
+    tmp = mr->ops->read(mr->opaque, addr, size);
+    *value |= (tmp & mask) << shift;
+}
+
+static void memory_region_write_accessor(void *opaque,
+                                         target_phys_addr_t addr,
+                                         uint64_t *value,
+                                         unsigned size,
+                                         unsigned shift,
+                                         uint64_t mask)
+{
+    MemoryRegion *mr = opaque;
+    uint64_t tmp;
+
+    tmp = (*value >> shift) & mask;
+    mr->ops->write(mr->opaque, addr, tmp, size);
+}
+
+static void access_with_adjusted_size(target_phys_addr_t addr,
+                                      uint64_t *value,
+                                      unsigned size,
+                                      unsigned access_size_min,
+                                      unsigned access_size_max,
+                                      void (*access)(void *opaque,
+                                                     target_phys_addr_t addr,
+                                                     uint64_t *value,
+                                                     unsigned size,
+                                                     unsigned shift,
+                                                     uint64_t mask),
+                                      void *opaque)
+{
+    uint64_t access_mask;
+    unsigned access_size;
+    unsigned i;
+
+    if (!access_size_min) {
+        access_size_min = 1;
+    }
+    if (!access_size_max) {
+        access_size_max = 4;
+    }
+    access_size = MAX(MIN(size, access_size_max), access_size_min);
+    access_mask = -1ULL >> (64 - access_size * 8);
+    for (i = 0; i < size; i += access_size) {
+        /* FIXME: big-endian support */
+        access(opaque, addr + i, value, access_size, i * 8, access_mask);
+    }
+}
+
+static void memory_region_prepare_ram_addr(MemoryRegion *mr);
+
+static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
+{
+    ram_addr_t phys_offset, region_offset;
+
+    memory_region_prepare_ram_addr(fr->mr);
+
+    phys_offset = fr->mr->ram_addr;
+    region_offset = fr->offset_in_region;
+    /* cpu_register_physical_memory_log() wants region_offset for
+     * mmio, but prefers offseting phys_offset for RAM.  Humour it.
+     */
+    if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
+        phys_offset += region_offset;
+        region_offset = 0;
+    }
+
+    if (!fr->readable) {
+        phys_offset &= ~TARGET_PAGE_MASK & ~IO_MEM_ROMD;
+    }
+
+    if (fr->readonly) {
+        phys_offset |= IO_MEM_ROM;
+    }
+
+    cpu_register_physical_memory_log(int128_get64(fr->addr.start),
+                                     int128_get64(fr->addr.size),
+                                     phys_offset,
+                                     region_offset,
+                                     fr->dirty_log_mask);
+}
+
+static void as_memory_range_del(AddressSpace *as, FlatRange *fr)
+{
+    if (fr->dirty_log_mask) {
+        Int128 end = addrrange_end(fr->addr);
+        cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start),
+                                       int128_get64(end));
+    }
+    cpu_register_physical_memory(int128_get64(fr->addr.start),
+                                 int128_get64(fr->addr.size),
+                                 IO_MEM_UNASSIGNED);
+}
+
+static void as_memory_log_start(AddressSpace *as, FlatRange *fr)
+{
+    cpu_physical_log_start(int128_get64(fr->addr.start),
+                           int128_get64(fr->addr.size));
+}
+
+static void as_memory_log_stop(AddressSpace *as, FlatRange *fr)
+{
+    cpu_physical_log_stop(int128_get64(fr->addr.start),
+                          int128_get64(fr->addr.size));
+}
+
+static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+    int r;
+
+    assert(fd->match_data && int128_get64(fd->addr.size) == 4);
+
+    r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start),
+                                    fd->data, true);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+    int r;
+
+    r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start),
+                                    fd->data, false);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static const AddressSpaceOps address_space_ops_memory = {
+    .range_add = as_memory_range_add,
+    .range_del = as_memory_range_del,
+    .log_start = as_memory_log_start,
+    .log_stop = as_memory_log_stop,
+    .ioeventfd_add = as_memory_ioeventfd_add,
+    .ioeventfd_del = as_memory_ioeventfd_del,
+};
+
+static AddressSpace address_space_memory = {
+    .ops = &address_space_ops_memory,
+};
+
+static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
+                                             unsigned width, bool write)
+{
+    const MemoryRegionPortio *mrp;
+
+    for (mrp = mr->ops->old_portio; mrp->size; ++mrp) {
+        if (offset >= mrp->offset && offset < mrp->offset + mrp->len
+            && width == mrp->size
+            && (write ? (bool)mrp->write : (bool)mrp->read)) {
+            return mrp;
+        }
+    }
+    return NULL;
+}
+
+static void memory_region_iorange_read(IORange *iorange,
+                                       uint64_t offset,
+                                       unsigned width,
+                                       uint64_t *data)
+{
+    MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
+
+    if (mr->ops->old_portio) {
+        const MemoryRegionPortio *mrp = find_portio(mr, offset, width, false);
+
+        *data = ((uint64_t)1 << (width * 8)) - 1;
+        if (mrp) {
+            *data = mrp->read(mr->opaque, offset + mr->offset);
+        } else if (width == 2) {
+            mrp = find_portio(mr, offset, 1, false);
+            assert(mrp);
+            *data = mrp->read(mr->opaque, offset + mr->offset) |
+                    (mrp->read(mr->opaque, offset + mr->offset + 1) << 8);
+        }
+        return;
+    }
+    *data = 0;
+    access_with_adjusted_size(offset + mr->offset, data, width,
+                              mr->ops->impl.min_access_size,
+                              mr->ops->impl.max_access_size,
+                              memory_region_read_accessor, mr);
+}
+
+static void memory_region_iorange_write(IORange *iorange,
+                                        uint64_t offset,
+                                        unsigned width,
+                                        uint64_t data)
+{
+    MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
+
+    if (mr->ops->old_portio) {
+        const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true);
+
+        if (mrp) {
+            mrp->write(mr->opaque, offset + mr->offset, data);
+        } else if (width == 2) {
+            mrp = find_portio(mr, offset, 1, false);
+            assert(mrp);
+            mrp->write(mr->opaque, offset + mr->offset, data & 0xff);
+            mrp->write(mr->opaque, offset + mr->offset + 1, data >> 8);
+        }
+        return;
+    }
+    access_with_adjusted_size(offset + mr->offset, &data, width,
+                              mr->ops->impl.min_access_size,
+                              mr->ops->impl.max_access_size,
+                              memory_region_write_accessor, mr);
+}
+
+static const IORangeOps memory_region_iorange_ops = {
+    .read = memory_region_iorange_read,
+    .write = memory_region_iorange_write,
+};
+
+static void as_io_range_add(AddressSpace *as, FlatRange *fr)
+{
+    iorange_init(&fr->mr->iorange, &memory_region_iorange_ops,
+                 int128_get64(fr->addr.start), int128_get64(fr->addr.size));
+    ioport_register(&fr->mr->iorange);
+}
+
+static void as_io_range_del(AddressSpace *as, FlatRange *fr)
+{
+    isa_unassign_ioport(int128_get64(fr->addr.start),
+                        int128_get64(fr->addr.size));
+}
+
+static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+    int r;
+
+    assert(fd->match_data && int128_get64(fd->addr.size) == 2);
+
+    r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start),
+                                   fd->data, true);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+    int r;
+
+    r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start),
+                                   fd->data, false);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static const AddressSpaceOps address_space_ops_io = {
+    .range_add = as_io_range_add,
+    .range_del = as_io_range_del,
+    .ioeventfd_add = as_io_ioeventfd_add,
+    .ioeventfd_del = as_io_ioeventfd_del,
+};
+
+static AddressSpace address_space_io = {
+    .ops = &address_space_ops_io,
+};
+
+/* Render a memory region into the global view.  Ranges in @view obscure
+ * ranges in @mr.
+ */
+static void render_memory_region(FlatView *view,
+                                 MemoryRegion *mr,
+                                 Int128 base,
+                                 AddrRange clip,
+                                 bool readonly)
+{
+    MemoryRegion *subregion;
+    unsigned i;
+    target_phys_addr_t offset_in_region;
+    Int128 remain;
+    Int128 now;
+    FlatRange fr;
+    AddrRange tmp;
+
+    int128_addto(&base, int128_make64(mr->addr));
+    readonly |= mr->readonly;
+
+    tmp = addrrange_make(base, mr->size);
+
+    if (!addrrange_intersects(tmp, clip)) {
+        return;
+    }
+
+    clip = addrrange_intersection(tmp, clip);
+
+    if (mr->alias) {
+        int128_subfrom(&base, int128_make64(mr->alias->addr));
+        int128_subfrom(&base, int128_make64(mr->alias_offset));
+        render_memory_region(view, mr->alias, base, clip, readonly);
+        return;
+    }
+
+    /* Render subregions in priority order. */
+    QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
+        render_memory_region(view, subregion, base, clip, readonly);
+    }
+
+    if (!mr->terminates) {
+        return;
+    }
+
+    offset_in_region = int128_get64(int128_sub(clip.start, base));
+    base = clip.start;
+    remain = clip.size;
+
+    /* Render the region itself into any gaps left by the current view. */
+    for (i = 0; i < view->nr && int128_nz(remain); ++i) {
+        if (int128_ge(base, addrrange_end(view->ranges[i].addr))) {
+            continue;
+        }
+        if (int128_lt(base, view->ranges[i].addr.start)) {
+            now = int128_min(remain,
+                             int128_sub(view->ranges[i].addr.start, base));
+            fr.mr = mr;
+            fr.offset_in_region = offset_in_region;
+            fr.addr = addrrange_make(base, now);
+            fr.dirty_log_mask = mr->dirty_log_mask;
+            fr.readable = mr->readable;
+            fr.readonly = readonly;
+            flatview_insert(view, i, &fr);
+            ++i;
+            int128_addto(&base, now);
+            offset_in_region += int128_get64(now);
+            int128_subfrom(&remain, now);
+        }
+        if (int128_eq(base, view->ranges[i].addr.start)) {
+            now = int128_min(remain, view->ranges[i].addr.size);
+            int128_addto(&base, now);
+            offset_in_region += int128_get64(now);
+            int128_subfrom(&remain, now);
+        }
+    }
+    if (int128_nz(remain)) {
+        fr.mr = mr;
+        fr.offset_in_region = offset_in_region;
+        fr.addr = addrrange_make(base, remain);
+        fr.dirty_log_mask = mr->dirty_log_mask;
+        fr.readable = mr->readable;
+        fr.readonly = readonly;
+        flatview_insert(view, i, &fr);
+    }
+}
+
+/* Render a memory topology into a list of disjoint absolute ranges. */
+static FlatView generate_memory_topology(MemoryRegion *mr)
+{
+    FlatView view;
+
+    flatview_init(&view);
+
+    render_memory_region(&view, mr, int128_zero(),
+                         addrrange_make(int128_zero(), int128_2_64()), false);
+    flatview_simplify(&view);
+
+    return view;
+}
+
+static void address_space_add_del_ioeventfds(AddressSpace *as,
+                                             MemoryRegionIoeventfd *fds_new,
+                                             unsigned fds_new_nb,
+                                             MemoryRegionIoeventfd *fds_old,
+                                             unsigned fds_old_nb)
+{
+    unsigned iold, inew;
+
+    /* Generate a symmetric difference of the old and new fd sets, adding
+     * and deleting as necessary.
+     */
+
+    iold = inew = 0;
+    while (iold < fds_old_nb || inew < fds_new_nb) {
+        if (iold < fds_old_nb
+            && (inew == fds_new_nb
+                || memory_region_ioeventfd_before(fds_old[iold],
+                                                  fds_new[inew]))) {
+            as->ops->ioeventfd_del(as, &fds_old[iold]);
+            ++iold;
+        } else if (inew < fds_new_nb
+                   && (iold == fds_old_nb
+                       || memory_region_ioeventfd_before(fds_new[inew],
+                                                         fds_old[iold]))) {
+            as->ops->ioeventfd_add(as, &fds_new[inew]);
+            ++inew;
+        } else {
+            ++iold;
+            ++inew;
+        }
+    }
+}
+
+static void address_space_update_ioeventfds(AddressSpace *as)
+{
+    FlatRange *fr;
+    unsigned ioeventfd_nb = 0;
+    MemoryRegionIoeventfd *ioeventfds = NULL;
+    AddrRange tmp;
+    unsigned i;
+
+    FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
+        for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
+            tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
+                                  int128_sub(fr->addr.start,
+                                             int128_make64(fr->offset_in_region)));
+            if (addrrange_intersects(fr->addr, tmp)) {
+                ++ioeventfd_nb;
+                ioeventfds = g_realloc(ioeventfds,
+                                          ioeventfd_nb * sizeof(*ioeventfds));
+                ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i];
+                ioeventfds[ioeventfd_nb-1].addr = tmp;
+            }
+        }
+    }
+
+    address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb,
+                                     as->ioeventfds, as->ioeventfd_nb);
+
+    g_free(as->ioeventfds);
+    as->ioeventfds = ioeventfds;
+    as->ioeventfd_nb = ioeventfd_nb;
+}
+
+static void address_space_update_topology_pass(AddressSpace *as,
+                                               FlatView old_view,
+                                               FlatView new_view,
+                                               bool adding)
+{
+    unsigned iold, inew;
+    FlatRange *frold, *frnew;
+
+    /* Generate a symmetric difference of the old and new memory maps.
+     * Kill ranges in the old map, and instantiate ranges in the new map.
+     */
+    iold = inew = 0;
+    while (iold < old_view.nr || inew < new_view.nr) {
+        if (iold < old_view.nr) {
+            frold = &old_view.ranges[iold];
+        } else {
+            frold = NULL;
+        }
+        if (inew < new_view.nr) {
+            frnew = &new_view.ranges[inew];
+        } else {
+            frnew = NULL;
+        }
+
+        if (frold
+            && (!frnew
+                || int128_lt(frold->addr.start, frnew->addr.start)
+                || (int128_eq(frold->addr.start, frnew->addr.start)
+                    && !flatrange_equal(frold, frnew)))) {
+            /* In old, but (not in new, or in new but attributes changed). */
+
+            if (!adding) {
+                as->ops->range_del(as, frold);
+            }
+
+            ++iold;
+        } else if (frold && frnew && flatrange_equal(frold, frnew)) {
+            /* In both (logging may have changed) */
+
+            if (adding) {
+                if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
+                    as->ops->log_stop(as, frnew);
+                } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
+                    as->ops->log_start(as, frnew);
+                }
+            }
+
+            ++iold;
+            ++inew;
+        } else {
+            /* In new */
+
+            if (adding) {
+                as->ops->range_add(as, frnew);
+            }
+
+            ++inew;
+        }
+    }
+}
+
+
+static void address_space_update_topology(AddressSpace *as)
+{
+    FlatView old_view = as->current_map;
+    FlatView new_view = generate_memory_topology(as->root);
+
+    address_space_update_topology_pass(as, old_view, new_view, false);
+    address_space_update_topology_pass(as, old_view, new_view, true);
+
+    as->current_map = new_view;
+    flatview_destroy(&old_view);
+    address_space_update_ioeventfds(as);
+}
+
+static void memory_region_update_topology(void)
+{
+    if (memory_region_transaction_depth) {
+        return;
+    }
+
+    if (address_space_memory.root) {
+        address_space_update_topology(&address_space_memory);
+    }
+    if (address_space_io.root) {
+        address_space_update_topology(&address_space_io);
+    }
+}
+
+void memory_region_transaction_begin(void)
+{
+    ++memory_region_transaction_depth;
+}
+
+void memory_region_transaction_commit(void)
+{
+    assert(memory_region_transaction_depth);
+    --memory_region_transaction_depth;
+    memory_region_update_topology();
+}
+
+static void memory_region_destructor_none(MemoryRegion *mr)
+{
+}
+
+static void memory_region_destructor_ram(MemoryRegion *mr)
+{
+    qemu_ram_free(mr->ram_addr);
+}
+
+static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr)
+{
+    qemu_ram_free_from_ptr(mr->ram_addr);
+}
+
+static void memory_region_destructor_iomem(MemoryRegion *mr)
+{
+    cpu_unregister_io_memory(mr->ram_addr);
+}
+
+static void memory_region_destructor_rom_device(MemoryRegion *mr)
+{
+    qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
+    cpu_unregister_io_memory(mr->ram_addr & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
+}
+
+void memory_region_init(MemoryRegion *mr,
+                        const char *name,
+                        uint64_t size)
+{
+    mr->ops = NULL;
+    mr->parent = NULL;
+    mr->size = int128_make64(size);
+    if (size == UINT64_MAX) {
+        mr->size = int128_2_64();
+    }
+    mr->addr = 0;
+    mr->offset = 0;
+    mr->terminates = false;
+    mr->readable = true;
+    mr->readonly = false;
+    mr->destructor = memory_region_destructor_none;
+    mr->priority = 0;
+    mr->may_overlap = false;
+    mr->alias = NULL;
+    QTAILQ_INIT(&mr->subregions);
+    memset(&mr->subregions_link, 0, sizeof mr->subregions_link);
+    QTAILQ_INIT(&mr->coalesced);
+    mr->name = g_strdup(name);
+    mr->dirty_log_mask = 0;
+    mr->ioeventfd_nb = 0;
+    mr->ioeventfds = NULL;
+}
+
+static bool memory_region_access_valid(MemoryRegion *mr,
+                                       target_phys_addr_t addr,
+                                       unsigned size)
+{
+    if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
+        return false;
+    }
+
+    /* Treat zero as compatibility all valid */
+    if (!mr->ops->valid.max_access_size) {
+        return true;
+    }
+
+    if (size > mr->ops->valid.max_access_size
+        || size < mr->ops->valid.min_access_size) {
+        return false;
+    }
+    return true;
+}
+
+static uint32_t memory_region_read_thunk_n(void *_mr,
+                                           target_phys_addr_t addr,
+                                           unsigned size)
+{
+    MemoryRegion *mr = _mr;
+    uint64_t data = 0;
+
+    if (!memory_region_access_valid(mr, addr, size)) {
+        return -1U; /* FIXME: better signalling */
+    }
+
+    if (!mr->ops->read) {
+        return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr);
+    }
+
+    /* FIXME: support unaligned access */
+    access_with_adjusted_size(addr + mr->offset, &data, size,
+                              mr->ops->impl.min_access_size,
+                              mr->ops->impl.max_access_size,
+                              memory_region_read_accessor, mr);
+
+    return data;
+}
+
+static void memory_region_write_thunk_n(void *_mr,
+                                        target_phys_addr_t addr,
+                                        unsigned size,
+                                        uint64_t data)
+{
+    MemoryRegion *mr = _mr;
+
+    if (!memory_region_access_valid(mr, addr, size)) {
+        return; /* FIXME: better signalling */
+    }
+
+    if (!mr->ops->write) {
+        mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data);
+        return;
+    }
+
+    /* FIXME: support unaligned access */
+    access_with_adjusted_size(addr + mr->offset, &data, size,
+                              mr->ops->impl.min_access_size,
+                              mr->ops->impl.max_access_size,
+                              memory_region_write_accessor, mr);
+}
+
+static uint32_t memory_region_read_thunk_b(void *mr, target_phys_addr_t addr)
+{
+    return memory_region_read_thunk_n(mr, addr, 1);
+}
+
+static uint32_t memory_region_read_thunk_w(void *mr, target_phys_addr_t addr)
+{
+    return memory_region_read_thunk_n(mr, addr, 2);
+}
+
+static uint32_t memory_region_read_thunk_l(void *mr, target_phys_addr_t addr)
+{
+    return memory_region_read_thunk_n(mr, addr, 4);
+}
+
+static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr,
+                                        uint32_t data)
+{
+    memory_region_write_thunk_n(mr, addr, 1, data);
+}
+
+static void memory_region_write_thunk_w(void *mr, target_phys_addr_t addr,
+                                        uint32_t data)
+{
+    memory_region_write_thunk_n(mr, addr, 2, data);
+}
+
+static void memory_region_write_thunk_l(void *mr, target_phys_addr_t addr,
+                                        uint32_t data)
+{
+    memory_region_write_thunk_n(mr, addr, 4, data);
+}
+
+static CPUReadMemoryFunc * const memory_region_read_thunk[] = {
+    memory_region_read_thunk_b,
+    memory_region_read_thunk_w,
+    memory_region_read_thunk_l,
+};
+
+static CPUWriteMemoryFunc * const memory_region_write_thunk[] = {
+    memory_region_write_thunk_b,
+    memory_region_write_thunk_w,
+    memory_region_write_thunk_l,
+};
+
+static void memory_region_prepare_ram_addr(MemoryRegion *mr)
+{
+    if (mr->backend_registered) {
+        return;
+    }
+
+    mr->destructor = memory_region_destructor_iomem;
+    mr->ram_addr = cpu_register_io_memory(memory_region_read_thunk,
+                                          memory_region_write_thunk,
+                                          mr,
+                                          mr->ops->endianness);
+    mr->backend_registered = true;
+}
+
+void memory_region_init_io(MemoryRegion *mr,
+                           const MemoryRegionOps *ops,
+                           void *opaque,
+                           const char *name,
+                           uint64_t size)
+{
+    memory_region_init(mr, name, size);
+    mr->ops = ops;
+    mr->opaque = opaque;
+    mr->terminates = true;
+    mr->backend_registered = false;
+}
+
+void memory_region_init_ram(MemoryRegion *mr,
+                            DeviceState *dev,
+                            const char *name,
+                            uint64_t size)
+{
+    memory_region_init(mr, name, size);
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_ram;
+    mr->ram_addr = qemu_ram_alloc(dev, name, size);
+    mr->backend_registered = true;
+}
+
+void memory_region_init_ram_ptr(MemoryRegion *mr,
+                                DeviceState *dev,
+                                const char *name,
+                                uint64_t size,
+                                void *ptr)
+{
+    memory_region_init(mr, name, size);
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_ram_from_ptr;
+    mr->ram_addr = qemu_ram_alloc_from_ptr(dev, name, size, ptr);
+    mr->backend_registered = true;
+}
+
+void memory_region_init_alias(MemoryRegion *mr,
+                              const char *name,
+                              MemoryRegion *orig,
+                              target_phys_addr_t offset,
+                              uint64_t size)
+{
+    memory_region_init(mr, name, size);
+    mr->alias = orig;
+    mr->alias_offset = offset;
+}
+
+void memory_region_init_rom_device(MemoryRegion *mr,
+                                   const MemoryRegionOps *ops,
+                                   void *opaque,
+                                   DeviceState *dev,
+                                   const char *name,
+                                   uint64_t size)
+{
+    memory_region_init(mr, name, size);
+    mr->ops = ops;
+    mr->opaque = opaque;
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_rom_device;
+    mr->ram_addr = qemu_ram_alloc(dev, name, size);
+    mr->ram_addr |= cpu_register_io_memory(memory_region_read_thunk,
+                                           memory_region_write_thunk,
+                                           mr,
+                                           mr->ops->endianness);
+    mr->ram_addr |= IO_MEM_ROMD;
+    mr->backend_registered = true;
+}
+
+void memory_region_destroy(MemoryRegion *mr)
+{
+    assert(QTAILQ_EMPTY(&mr->subregions));
+    mr->destructor(mr);
+    memory_region_clear_coalescing(mr);
+    g_free((char *)mr->name);
+    g_free(mr->ioeventfds);
+}
+
+uint64_t memory_region_size(MemoryRegion *mr)
+{
+    if (int128_eq(mr->size, int128_2_64())) {
+        return UINT64_MAX;
+    }
+    return int128_get64(mr->size);
+}
+
+void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset)
+{
+    mr->offset = offset;
+}
+
+void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
+{
+    uint8_t mask = 1 << client;
+
+    mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
+    memory_region_update_topology();
+}
+
+bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                             unsigned client)
+{
+    assert(mr->terminates);
+    return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
+}
+
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
+{
+    assert(mr->terminates);
+    return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
+}
+
+void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
+{
+    FlatRange *fr;
+
+    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
+        if (fr->mr == mr) {
+            cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start),
+                                           int128_get64(addrrange_end(fr->addr)));
+        }
+    }
+}
+
+void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
+{
+    if (mr->readonly != readonly) {
+        mr->readonly = readonly;
+        memory_region_update_topology();
+    }
+}
+
+void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable)
+{
+    if (mr->readable != readable) {
+        mr->readable = readable;
+        memory_region_update_topology();
+    }
+}
+
+void memory_region_reset_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                               target_phys_addr_t size, unsigned client)
+{
+    assert(mr->terminates);
+    cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
+                                    mr->ram_addr + addr + size,
+                                    1 << client);
+}
+
+void *memory_region_get_ram_ptr(MemoryRegion *mr)
+{
+    if (mr->alias) {
+        return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset;
+    }
+
+    assert(mr->terminates);
+
+    return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
+}
+
+static void memory_region_update_coalesced_range(MemoryRegion *mr)
+{
+    FlatRange *fr;
+    CoalescedMemoryRange *cmr;
+    AddrRange tmp;
+
+    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
+        if (fr->mr == mr) {
+            qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
+                                           int128_get64(fr->addr.size));
+            QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
+                tmp = addrrange_shift(cmr->addr,
+                                      int128_sub(fr->addr.start,
+                                                 int128_make64(fr->offset_in_region)));
+                if (!addrrange_intersects(tmp, fr->addr)) {
+                    continue;
+                }
+                tmp = addrrange_intersection(tmp, fr->addr);
+                qemu_register_coalesced_mmio(int128_get64(tmp.start),
+                                             int128_get64(tmp.size));
+            }
+        }
+    }
+}
+
+void memory_region_set_coalescing(MemoryRegion *mr)
+{
+    memory_region_clear_coalescing(mr);
+    memory_region_add_coalescing(mr, 0, int128_get64(mr->size));
+}
+
+void memory_region_add_coalescing(MemoryRegion *mr,
+                                  target_phys_addr_t offset,
+                                  uint64_t size)
+{
+    CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr));
+
+    cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size));
+    QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
+    memory_region_update_coalesced_range(mr);
+}
+
+void memory_region_clear_coalescing(MemoryRegion *mr)
+{
+    CoalescedMemoryRange *cmr;
+
+    while (!QTAILQ_EMPTY(&mr->coalesced)) {
+        cmr = QTAILQ_FIRST(&mr->coalesced);
+        QTAILQ_REMOVE(&mr->coalesced, cmr, link);
+        g_free(cmr);
+    }
+    memory_region_update_coalesced_range(mr);
+}
+
+void memory_region_add_eventfd(MemoryRegion *mr,
+                               target_phys_addr_t addr,
+                               unsigned size,
+                               bool match_data,
+                               uint64_t data,
+                               int fd)
+{
+    MemoryRegionIoeventfd mrfd = {
+        .addr.start = int128_make64(addr),
+        .addr.size = int128_make64(size),
+        .match_data = match_data,
+        .data = data,
+        .fd = fd,
+    };
+    unsigned i;
+
+    for (i = 0; i < mr->ioeventfd_nb; ++i) {
+        if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
+            break;
+        }
+    }
+    ++mr->ioeventfd_nb;
+    mr->ioeventfds = g_realloc(mr->ioeventfds,
+                                  sizeof(*mr->ioeventfds) * mr->ioeventfd_nb);
+    memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
+            sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
+    mr->ioeventfds[i] = mrfd;
+    memory_region_update_topology();
+}
+
+void memory_region_del_eventfd(MemoryRegion *mr,
+                               target_phys_addr_t addr,
+                               unsigned size,
+                               bool match_data,
+                               uint64_t data,
+                               int fd)
+{
+    MemoryRegionIoeventfd mrfd = {
+        .addr.start = int128_make64(addr),
+        .addr.size = int128_make64(size),
+        .match_data = match_data,
+        .data = data,
+        .fd = fd,
+    };
+    unsigned i;
+
+    for (i = 0; i < mr->ioeventfd_nb; ++i) {
+        if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
+            break;
+        }
+    }
+    assert(i != mr->ioeventfd_nb);
+    memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1],
+            sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1)));
+    --mr->ioeventfd_nb;
+    mr->ioeventfds = g_realloc(mr->ioeventfds,
+                                  sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
+    memory_region_update_topology();
+}
+
+static void memory_region_add_subregion_common(MemoryRegion *mr,
+                                               target_phys_addr_t offset,
+                                               MemoryRegion *subregion)
+{
+    MemoryRegion *other;
+
+    assert(!subregion->parent);
+    subregion->parent = mr;
+    subregion->addr = offset;
+    QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
+        if (subregion->may_overlap || other->may_overlap) {
+            continue;
+        }
+        if (int128_gt(int128_make64(offset),
+                      int128_add(int128_make64(other->addr), other->size))
+            || int128_le(int128_add(int128_make64(offset), subregion->size),
+                         int128_make64(other->addr))) {
+            continue;
+        }
+#if 0
+        printf("warning: subregion collision %llx/%llx (%s) "
+               "vs %llx/%llx (%s)\n",
+               (unsigned long long)offset,
+               (unsigned long long)int128_get64(subregion->size),
+               subregion->name,
+               (unsigned long long)other->addr,
+               (unsigned long long)int128_get64(other->size),
+               other->name);
+#endif
+    }
+    QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
+        if (subregion->priority >= other->priority) {
+            QTAILQ_INSERT_BEFORE(other, subregion, subregions_link);
+            goto done;
+        }
+    }
+    QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
+done:
+    memory_region_update_topology();
+}
+
+
+void memory_region_add_subregion(MemoryRegion *mr,
+                                 target_phys_addr_t offset,
+                                 MemoryRegion *subregion)
+{
+    subregion->may_overlap = false;
+    subregion->priority = 0;
+    memory_region_add_subregion_common(mr, offset, subregion);
+}
+
+void memory_region_add_subregion_overlap(MemoryRegion *mr,
+                                         target_phys_addr_t offset,
+                                         MemoryRegion *subregion,
+                                         unsigned priority)
+{
+    subregion->may_overlap = true;
+    subregion->priority = priority;
+    memory_region_add_subregion_common(mr, offset, subregion);
+}
+
+void memory_region_del_subregion(MemoryRegion *mr,
+                                 MemoryRegion *subregion)
+{
+    assert(subregion->parent == mr);
+    subregion->parent = NULL;
+    QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
+    memory_region_update_topology();
+}
+
+void set_system_memory_map(MemoryRegion *mr)
+{
+    address_space_memory.root = mr;
+    memory_region_update_topology();
+}
+
+void set_system_io_map(MemoryRegion *mr)
+{
+    address_space_io.root = mr;
+    memory_region_update_topology();
+}
+
+typedef struct MemoryRegionList MemoryRegionList;
+
+struct MemoryRegionList {
+    const MemoryRegion *mr;
+    bool printed;
+    QTAILQ_ENTRY(MemoryRegionList) queue;
+};
+
+typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead;
+
+static void mtree_print_mr(fprintf_function mon_printf, void *f,
+                           const MemoryRegion *mr, unsigned int level,
+                           target_phys_addr_t base,
+                           MemoryRegionListHead *alias_print_queue)
+{
+    MemoryRegionList *new_ml, *ml, *next_ml;
+    MemoryRegionListHead submr_print_queue;
+    const MemoryRegion *submr;
+    unsigned int i;
+
+    if (!mr) {
+        return;
+    }
+
+    for (i = 0; i < level; i++) {
+        mon_printf(f, "  ");
+    }
+
+    if (mr->alias) {
+        MemoryRegionList *ml;
+        bool found = false;
+
+        /* check if the alias is already in the queue */
+        QTAILQ_FOREACH(ml, alias_print_queue, queue) {
+            if (ml->mr == mr->alias && !ml->printed) {
+                found = true;
+            }
+        }
+
+        if (!found) {
+            ml = g_new(MemoryRegionList, 1);
+            ml->mr = mr->alias;
+            ml->printed = false;
+            QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue);
+        }
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s "
+                   TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
+                   base + mr->addr,
+                   base + mr->addr
+                   + (target_phys_addr_t)int128_get64(mr->size) - 1,
+                   mr->priority,
+                   mr->name,
+                   mr->alias->name,
+                   mr->alias_offset,
+                   mr->alias_offset
+                   + (target_phys_addr_t)int128_get64(mr->size) - 1);
+    } else {
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): %s\n",
+                   base + mr->addr,
+                   base + mr->addr
+                   + (target_phys_addr_t)int128_get64(mr->size) - 1,
+                   mr->priority,
+                   mr->name);
+    }
+
+    QTAILQ_INIT(&submr_print_queue);
+
+    QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
+        new_ml = g_new(MemoryRegionList, 1);
+        new_ml->mr = submr;
+        QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+            if (new_ml->mr->addr < ml->mr->addr ||
+                (new_ml->mr->addr == ml->mr->addr &&
+                 new_ml->mr->priority > ml->mr->priority)) {
+                QTAILQ_INSERT_BEFORE(ml, new_ml, queue);
+                new_ml = NULL;
+                break;
+            }
+        }
+        if (new_ml) {
+            QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue);
+        }
+    }
+
+    QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+        mtree_print_mr(mon_printf, f, ml->mr, level + 1, base + mr->addr,
+                       alias_print_queue);
+    }
+
+    QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) {
+        g_free(ml);
+    }
+}
+
+void mtree_info(fprintf_function mon_printf, void *f)
+{
+    MemoryRegionListHead ml_head;
+    MemoryRegionList *ml, *ml2;
+
+    QTAILQ_INIT(&ml_head);
+
+    mon_printf(f, "memory\n");
+    mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
+
+    /* print aliased regions */
+    QTAILQ_FOREACH(ml, &ml_head, queue) {
+        if (!ml->printed) {
+            mon_printf(f, "%s\n", ml->mr->name);
+            mtree_print_mr(mon_printf, f, ml->mr, 0, 0, &ml_head);
+        }
+    }
+
+    QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
+        g_free(ml);
+    }
+
+    if (address_space_io.root &&
+        !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
+        QTAILQ_INIT(&ml_head);
+        mon_printf(f, "I/O\n");
+        mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+    }
+}
diff --git a/memory.h b/memory.h
new file mode 100644 (file)
index 0000000..7fb36d1
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,509 @@
+/*
+ * Physical memory management API
+ *
+ * Copyright 2011 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Avi Kivity <avi@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#ifndef CONFIG_USER_ONLY
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "qemu-common.h"
+#include "cpu-common.h"
+#include "targphys.h"
+#include "qemu-queue.h"
+#include "iorange.h"
+#include "ioport.h"
+#include "int128.h"
+
+typedef struct MemoryRegionOps MemoryRegionOps;
+typedef struct MemoryRegion MemoryRegion;
+typedef struct MemoryRegionPortio MemoryRegionPortio;
+typedef struct MemoryRegionMmio MemoryRegionMmio;
+
+/* Must match *_DIRTY_FLAGS in cpu-all.h.  To be replaced with dynamic
+ * registration.
+ */
+#define DIRTY_MEMORY_VGA       0
+#define DIRTY_MEMORY_CODE      1
+#define DIRTY_MEMORY_MIGRATION 3
+
+struct MemoryRegionMmio {
+    CPUReadMemoryFunc *read[3];
+    CPUWriteMemoryFunc *write[3];
+};
+
+/*
+ * Memory region callbacks
+ */
+struct MemoryRegionOps {
+    /* Read from the memory region. @addr is relative to @mr; @size is
+     * in bytes. */
+    uint64_t (*read)(void *opaque,
+                     target_phys_addr_t addr,
+                     unsigned size);
+    /* Write to the memory region. @addr is relative to @mr; @size is
+     * in bytes. */
+    void (*write)(void *opaque,
+                  target_phys_addr_t addr,
+                  uint64_t data,
+                  unsigned size);
+
+    enum device_endian endianness;
+    /* Guest-visible constraints: */
+    struct {
+        /* If nonzero, specify bounds on access sizes beyond which a machine
+         * check is thrown.
+         */
+        unsigned min_access_size;
+        unsigned max_access_size;
+        /* If true, unaligned accesses are supported.  Otherwise unaligned
+         * accesses throw machine checks.
+         */
+         bool unaligned;
+    } valid;
+    /* Internal implementation constraints: */
+    struct {
+        /* If nonzero, specifies the minimum size implemented.  Smaller sizes
+         * will be rounded upwards and a partial result will be returned.
+         */
+        unsigned min_access_size;
+        /* If nonzero, specifies the maximum size implemented.  Larger sizes
+         * will be done as a series of accesses with smaller sizes.
+         */
+        unsigned max_access_size;
+        /* If true, unaligned accesses are supported.  Otherwise all accesses
+         * are converted to (possibly multiple) naturally aligned accesses.
+         */
+         bool unaligned;
+    } impl;
+
+    /* If .read and .write are not present, old_portio may be used for
+     * backwards compatibility with old portio registration
+     */
+    const MemoryRegionPortio *old_portio;
+    /* If .read and .write are not present, old_mmio may be used for
+     * backwards compatibility with old mmio registration
+     */
+    const MemoryRegionMmio old_mmio;
+};
+
+typedef struct CoalescedMemoryRange CoalescedMemoryRange;
+typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
+
+struct MemoryRegion {
+    /* All fields are private - violators will be prosecuted */
+    const MemoryRegionOps *ops;
+    void *opaque;
+    MemoryRegion *parent;
+    Int128 size;
+    target_phys_addr_t addr;
+    target_phys_addr_t offset;
+    bool backend_registered;
+    void (*destructor)(MemoryRegion *mr);
+    ram_addr_t ram_addr;
+    IORange iorange;
+    bool terminates;
+    bool readable;
+    bool readonly; /* For RAM regions */
+    MemoryRegion *alias;
+    target_phys_addr_t alias_offset;
+    unsigned priority;
+    bool may_overlap;
+    QTAILQ_HEAD(subregions, MemoryRegion) subregions;
+    QTAILQ_ENTRY(MemoryRegion) subregions_link;
+    QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
+    const char *name;
+    uint8_t dirty_log_mask;
+    unsigned ioeventfd_nb;
+    MemoryRegionIoeventfd *ioeventfds;
+};
+
+struct MemoryRegionPortio {
+    uint32_t offset;
+    uint32_t len;
+    unsigned size;
+    IOPortReadFunc *read;
+    IOPortWriteFunc *write;
+};
+
+#define PORTIO_END_OF_LIST() { }
+
+/**
+ * memory_region_init: Initialize a memory region
+ *
+ * The region typically acts as a container for other memory regions.  Us
+ * memory_region_add_subregion() to add subregions.
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region; any subregions beyond this size will be clipped
+ */
+void memory_region_init(MemoryRegion *mr,
+                        const char *name,
+                        uint64_t size);
+/**
+ * memory_region_init_io: Initialize an I/O memory region.
+ *
+ * Accesses into the region will be cause the callbacks in @ops to be called.
+ * if @size is nonzero, subregions will be clipped to @size.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @ops: a structure containing read and write callbacks to be used when
+ *       I/O is performed on the region.
+ * @opaque: passed to to the read and write callbacks of the @ops structure.
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_io(MemoryRegion *mr,
+                           const MemoryRegionOps *ops,
+                           void *opaque,
+                           const char *name,
+                           uint64_t size);
+
+/**
+ * memory_region_init_ram:  Initialize RAM memory region.  Accesses into the
+ *                          region will be modify memory directly.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @dev: a device associated with the region; may be %NULL.
+ * @name: the name of the region; the pair (@dev, @name) must be globally
+ *        unique.  The name is part of the save/restore ABI and so cannot be
+ *        changed.
+ * @size: size of the region.
+ */
+void memory_region_init_ram(MemoryRegion *mr,
+                            DeviceState *dev, /* FIXME: layering violation */
+                            const char *name,
+                            uint64_t size);
+
+/**
+ * memory_region_init_ram:  Initialize RAM memory region from a user-provided.
+ *                          pointer.  Accesses into the region will be modify
+ *                          memory directly.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @dev: a device associated with the region; may be %NULL.
+ * @name: the name of the region; the pair (@dev, @name) must be globally
+ *        unique.  The name is part of the save/restore ABI and so cannot be
+ *        changed.
+ * @size: size of the region.
+ * @ptr: memory to be mapped; must contain at least @size bytes.
+ */
+void memory_region_init_ram_ptr(MemoryRegion *mr,
+                                DeviceState *dev, /* FIXME: layering violation */
+                                const char *name,
+                                uint64_t size,
+                                void *ptr);
+
+/**
+ * memory_region_init_alias: Initialize a memory region that aliases all or a
+ *                           part of another memory region.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @name: used for debugging; not visible to the user or ABI
+ * @orig: the region to be referenced; @mr will be equivalent to
+ *        @orig between @offset and @offset + @size - 1.
+ * @offset: start of the section in @orig to be referenced.
+ * @size: size of the region.
+ */
+void memory_region_init_alias(MemoryRegion *mr,
+                              const char *name,
+                              MemoryRegion *orig,
+                              target_phys_addr_t offset,
+                              uint64_t size);
+
+/**
+ * memory_region_init_rom_device:  Initialize a ROM memory region.  Writes are
+ *                                 handled via callbacks.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @ops: callbacks for write access handling.
+ * @dev: a device associated with the region; may be %NULL.
+ * @name: the name of the region; the pair (@dev, @name) must be globally
+ *        unique.  The name is part of the save/restore ABI and so cannot be
+ *        changed.
+ * @size: size of the region.
+ */
+void memory_region_init_rom_device(MemoryRegion *mr,
+                                   const MemoryRegionOps *ops,
+                                   void *opaque,
+                                   DeviceState *dev, /* FIXME: layering violation */
+                                   const char *name,
+                                   uint64_t size);
+
+/**
+ * memory_region_destroy: Destroy a memory region and relaim all resources.
+ *
+ * @mr: the region to be destroyed.  May not currently be a subregion
+ *      (see memory_region_add_subregion()) or referenced in an alias
+ *      (see memory_region_init_alias()).
+ */
+void memory_region_destroy(MemoryRegion *mr);
+
+/**
+ * memory_region_size: get a memory region's size.
+ *
+ * @mr: the memory region being queried.
+ */
+uint64_t memory_region_size(MemoryRegion *mr);
+
+/**
+ * memory_region_get_ram_ptr: Get a pointer into a RAM memory region.
+ *
+ * Returns a host pointer to a RAM memory region (created with
+ * memory_region_init_ram() or memory_region_init_ram_ptr()).  Use with
+ * care.
+ *
+ * @mr: the memory region being queried.
+ */
+void *memory_region_get_ram_ptr(MemoryRegion *mr);
+
+/**
+ * memory_region_set_offset: Sets an offset to be added to MemoryRegionOps
+ *                           callbacks.
+ *
+ * This function is deprecated and should not be used in new code.
+ */
+void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset);
+
+/**
+ * memory_region_set_log: Turn dirty logging on or off for a region.
+ *
+ * Turns dirty logging on or off for a specified client (display, migration).
+ * Only meaningful for RAM regions.
+ *
+ * @mr: the memory region being updated.
+ * @log: whether dirty logging is to be enabled or disabled.
+ * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
+ *          %DIRTY_MEMORY_VGA.
+ */
+void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
+
+/**
+ * memory_region_get_dirty: Check whether a page is dirty for a specified
+ *                          client.
+ *
+ * Checks whether a page has been written to since the last
+ * call to memory_region_reset_dirty() with the same @client.  Dirty logging
+ * must be enabled.
+ *
+ * @mr: the memory region being queried.
+ * @addr: the address (relative to the start of the region) being queried.
+ * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
+ *          %DIRTY_MEMORY_VGA.
+ */
+bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                             unsigned client);
+
+/**
+ * memory_region_set_dirty: Mark a page as dirty in a memory region.
+ *
+ * Marks a page as dirty, after it has been dirtied outside guest code.
+ *
+ * @mr: the memory region being queried.
+ * @addr: the address (relative to the start of the region) being dirtied.
+ */
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr);
+
+/**
+ * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
+ *                                  any external TLBs (e.g. kvm)
+ *
+ * Flushes dirty information from accelerators such as kvm and vhost-net
+ * and makes it available to users of the memory API.
+ *
+ * @mr: the region being flushed.
+ */
+void memory_region_sync_dirty_bitmap(MemoryRegion *mr);
+
+/**
+ * memory_region_reset_dirty: Mark a range of pages as clean, for a specified
+ *                            client.
+ *
+ * Marks a range of pages as no longer dirty.
+ *
+ * @mr: the region being updated.
+ * @addr: the start of the subrange being cleaned.
+ * @size: the size of the subrange being cleaned.
+ * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
+ *          %DIRTY_MEMORY_VGA.
+ */
+void memory_region_reset_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                               target_phys_addr_t size, unsigned client);
+
+/**
+ * memory_region_set_readonly: Turn a memory region read-only (or read-write)
+ *
+ * Allows a memory region to be marked as read-only (turning it into a ROM).
+ * only useful on RAM regions.
+ *
+ * @mr: the region being updated.
+ * @readonly: whether rhe region is to be ROM or RAM.
+ */
+void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
+
+/**
+ * memory_region_rom_device_set_readable: enable/disable ROM readability
+ *
+ * Allows a ROM device (initialized with memory_region_init_rom_device() to
+ * to be marked as readable (default) or not readable.  When it is readable,
+ * the device is mapped to guest memory.  When not readable, reads are
+ * forwarded to the #MemoryRegion.read function.
+ *
+ * @mr: the memory region to be updated
+ * @readable: whether reads are satisified directly (%true) or via callbacks
+ *            (%false)
+ */
+void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable);
+
+/**
+ * memory_region_set_coalescing: Enable memory coalescing for the region.
+ *
+ * Enabled writes to a region to be queued for later processing. MMIO ->write
+ * callbacks may be delayed until a non-coalesced MMIO is issued.
+ * Only useful for IO regions.  Roughly similar to write-combining hardware.
+ *
+ * @mr: the memory region to be write coalesced
+ */
+void memory_region_set_coalescing(MemoryRegion *mr);
+
+/**
+ * memory_region_add_coalescing: Enable memory coalescing for a sub-range of
+ *                               a region.
+ *
+ * Like memory_region_set_coalescing(), but works on a sub-range of a region.
+ * Multiple calls can be issued coalesced disjoint ranges.
+ *
+ * @mr: the memory region to be updated.
+ * @offset: the start of the range within the region to be coalesced.
+ * @size: the size of the subrange to be coalesced.
+ */
+void memory_region_add_coalescing(MemoryRegion *mr,
+                                  target_phys_addr_t offset,
+                                  uint64_t size);
+
+/**
+ * memory_region_clear_coalescing: Disable MMIO coalescing for the region.
+ *
+ * Disables any coalescing caused by memory_region_set_coalescing() or
+ * memory_region_add_coalescing().  Roughly equivalent to uncacheble memory
+ * hardware.
+ *
+ * @mr: the memory region to be updated.
+ */
+void memory_region_clear_coalescing(MemoryRegion *mr);
+
+/**
+ * memory_region_add_eventfd: Request an eventfd to be triggered when a word
+ *                            is written to a location.
+ *
+ * Marks a word in an IO region (initialized with memory_region_init_io())
+ * as a trigger for an eventfd event.  The I/O callback will not be called.
+ * The caller must be prepared to handle failure (hat is, take the required
+ * action if the callback _is_ called).
+ *
+ * @mr: the memory region being updated.
+ * @addr: the address within @mr that is to be monitored
+ * @size: the size of the access to trigger the eventfd
+ * @match_data: whether to match against @data, instead of just @addr
+ * @data: the data to match against the guest write
+ * @fd: the eventfd to be triggered when @addr, @size, and @data all match.
+ **/
+void memory_region_add_eventfd(MemoryRegion *mr,
+                               target_phys_addr_t addr,
+                               unsigned size,
+                               bool match_data,
+                               uint64_t data,
+                               int fd);
+
+/**
+ * memory_region_del_eventfd: Cancel and eventfd.
+ *
+ * Cancels an eventfd trigger request by a previous memory_region_add_eventfd()
+ * call.
+ *
+ * @mr: the memory region being updated.
+ * @addr: the address within @mr that is to be monitored
+ * @size: the size of the access to trigger the eventfd
+ * @match_data: whether to match against @data, instead of just @addr
+ * @data: the data to match against the guest write
+ * @fd: the eventfd to be triggered when @addr, @size, and @data all match.
+ */
+void memory_region_del_eventfd(MemoryRegion *mr,
+                               target_phys_addr_t addr,
+                               unsigned size,
+                               bool match_data,
+                               uint64_t data,
+                               int fd);
+/**
+ * memory_region_add_subregion: Add a sub-region to a container.
+ *
+ * Adds a sub-region at @offset.  The sub-region may not overlap with other
+ * subregions (except for those explicitly marked as overlapping).  A region
+ * may only be added once as a subregion (unless removed with
+ * memory_region_del_subregion()); use memory_region_init_alias() if you
+ * want a region to be a subregion in multiple locations.
+ *
+ * @mr: the region to contain the new subregion; must be a container
+ *      initialized with memory_region_init().
+ * @offset: the offset relative to @mr where @subregion is added.
+ * @subregion: the subregion to be added.
+ */
+void memory_region_add_subregion(MemoryRegion *mr,
+                                 target_phys_addr_t offset,
+                                 MemoryRegion *subregion);
+/**
+ * memory_region_add_subregion: Add a sub-region to a container, with overlap.
+ *
+ * Adds a sub-region at @offset.  The sub-region may overlap with other
+ * subregions.  Conflicts are resolved by having a higher @priority hide a
+ * lower @priority. Subregions without priority are taken as @priority 0.
+ * A region may only be added once as a subregion (unless removed with
+ * memory_region_del_subregion()); use memory_region_init_alias() if you
+ * want a region to be a subregion in multiple locations.
+ *
+ * @mr: the region to contain the new subregion; must be a container
+ *      initialized with memory_region_init().
+ * @offset: the offset relative to @mr where @subregion is added.
+ * @subregion: the subregion to be added.
+ * @priority: used for resolving overlaps; highest priority wins.
+ */
+void memory_region_add_subregion_overlap(MemoryRegion *mr,
+                                         target_phys_addr_t offset,
+                                         MemoryRegion *subregion,
+                                         unsigned priority);
+/**
+ * memory_region_del_subregion: Remove a subregion.
+ *
+ * Removes a subregion from its container.
+ *
+ * @mr: the container to be updated.
+ * @subregion: the region being removed; must be a current subregion of @mr.
+ */
+void memory_region_del_subregion(MemoryRegion *mr,
+                                 MemoryRegion *subregion);
+
+/* Start a transaction; changes will be accumulated and made visible only
+ * when the transaction ends.
+ */
+void memory_region_transaction_begin(void);
+/* Commit a transaction and make changes visible to the guest.
+ */
+void memory_region_transaction_commit(void);
+
+void mtree_info(fprintf_function mon_printf, void *f);
+
+#endif
+
+#endif
index 14718dd1d1fdbcd5e2f814ba10b658301cb57591..b7b1055e881d877eeb70aa9ae72677e4c3a42da3 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>
     do { } while (0)
 #endif
 
-static int file_errno(FdMigrationState *s)
+static int file_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int file_write(FdMigrationState *s, const void * buf, size_t size)
+static int file_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int exec_close(FdMigrationState *s)
+static int exec_close(MigrationState *s)
 {
     int ret = 0;
     DPRINTF("exec_close\n");
@@ -62,22 +61,14 @@ static int exec_close(FdMigrationState *s)
     return ret;
 }
 
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
-                                              const char *command,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-                                             int blk,
-                                             int inc)
+int exec_start_outgoing_migration(MigrationState *s, const char *command)
 {
-    FdMigrationState *s;
     FILE *f;
 
-    s = qemu_mallocz(sizeof(*s));
-
     f = popen(command, "w");
     if (f == NULL) {
         DPRINTF("Unable to popen exec target\n");
-        goto err_after_alloc;
+        goto err_after_popen;
     }
 
     s->fd = fileno(f);
@@ -93,29 +84,14 @@ MigrationState *exec_start_outgoing_migration(Monitor *mon,
     s->close = exec_close;
     s->get_error = file_errno;
     s->write = file_write;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
 
     migrate_fd_connect(s);
-    return &s->mig_state;
+    return 0;
 
 err_after_open:
     pclose(f);
-err_after_alloc:
-    qemu_free(s);
-    return NULL;
+err_after_popen:
+    return -1;
 }
 
 static void exec_accept_incoming_migration(void *opaque)
index 6d145056324bd7238ec6282c0632494f7cc6e54f..6211124a059d48784a3662d13552aedc8fc56e12 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"
     do { } while (0)
 #endif
 
-static int fd_errno(FdMigrationState *s)
+static int fd_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+static int fd_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int fd_close(FdMigrationState *s)
+static int fd_close(MigrationState *s)
 {
+    struct stat st;
+    int ret;
+
     DPRINTF("fd_close\n");
     if (s->fd != -1) {
-        close(s->fd);
+        ret = fstat(s->fd, &st);
+        if (ret == 0 && S_ISREG(st.st_mode)) {
+            /*
+             * If the file handle is a regular file make sure the
+             * data is flushed to disk before signaling success.
+             */
+            ret = fsync(s->fd);
+            if (ret != 0) {
+                ret = -errno;
+                perror("migration-fd: fsync");
+                return ret;
+            }
+        }
+        ret = close(s->fd);
         s->fd = -1;
+        if (ret != 0) {
+            ret = -errno;
+            perror("migration-fd: close");
+            return ret;
+        }
     }
     return 0;
 }
 
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
-                                           const char *fdname,
-                                           int64_t bandwidth_limit,
-                                           int detach,
-                                           int blk,
-                                           int inc)
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
 {
-    FdMigrationState *s;
-
-    s = qemu_mallocz(sizeof(*s));
-
-    s->fd = monitor_get_fd(mon, fdname);
+    s->fd = monitor_get_fd(s->mon, fdname);
     if (s->fd == -1) {
         DPRINTF("fd_migration: invalid file descriptor identifier\n");
-        goto err_after_alloc;
+        goto err_after_get_fd;
     }
 
     if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
@@ -76,29 +87,14 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon,
     s->get_error = fd_errno;
     s->write = fd_write;
     s->close = fd_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
 
     migrate_fd_connect(s);
-    return &s->mig_state;
+    return 0;
 
 err_after_open:
     close(s->fd);
-err_after_alloc:
-    qemu_free(s);
-    return NULL;
+err_after_get_fd:
+    return -1;
 }
 
 static void fd_accept_incoming_migration(void *opaque)
index b55f419b654f51de8309db59c43020194f632460..5aa742c34bee470a12fe0ad629d877e0e1878801 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"
 
     do { } while (0)
 #endif
 
-static int socket_errno(FdMigrationState *s)
+static int socket_errno(MigrationState *s)
 {
     return socket_error();
 }
 
-static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+static int socket_write(MigrationState *s, const void * buf, size_t size)
 {
     return send(s->fd, buf, size, 0);
 }
 
-static int tcp_close(FdMigrationState *s)
+static int tcp_close(MigrationState *s)
 {
     DPRINTF("tcp_close\n");
     if (s->fd != -1) {
@@ -49,17 +48,16 @@ static int tcp_close(FdMigrationState *s)
     return 0;
 }
 
-
 static void tcp_wait_for_connect(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int val, ret;
     socklen_t valsize = sizeof(val);
 
     DPRINTF("connect completed\n");
     do {
         ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
-    } while (ret == -1 && (s->get_error(s)) == EINTR);
+    } while (ret == -1 && (socket_error()) == EINTR);
 
     if (ret < 0) {
         migrate_fd_error(s);
@@ -76,70 +74,53 @@ static void tcp_wait_for_connect(void *opaque)
     }
 }
 
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
-                                             const char *host_port,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-                                            int blk,
-                                            int inc)
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port)
 {
     struct sockaddr_in addr;
-    FdMigrationState *s;
     int ret;
 
-    if (parse_host_port(&addr, host_port) < 0)
-        return NULL;
-
-    s = qemu_mallocz(sizeof(*s));
+    ret = parse_host_port(&addr, host_port);
+    if (ret < 0) {
+        return ret;
+    }
 
     s->get_error = socket_errno;
     s->write = socket_write;
     s->close = tcp_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
 
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
     s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     if (s->fd == -1) {
-        qemu_free(s);
-        return NULL;
+        DPRINTF("Unable to open socket");
+        return -socket_error();
     }
 
     socket_set_nonblock(s->fd);
 
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
-
     do {
         ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
-        if (ret == -1)
-            ret = -(s->get_error(s));
-
-        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+        if (ret == -1) {
+            ret = -socket_error();
+        }
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
             qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+            return 0;
+        }
     } while (ret == -EINTR);
 
-    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+    if (ret < 0) {
         DPRINTF("connect failed\n");
         migrate_fd_error(s);
-    } else if (ret >= 0)
-        migrate_fd_connect(s);
-
-    return &s->mig_state;
+        return ret;
+    }
+    migrate_fd_connect(s);
+    return 0;
 }
 
 static void tcp_accept_incoming_migration(void *opaque)
 {
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(addr);
-    int s = (unsigned long)opaque;
+    int s = (intptr_t)opaque;
     QEMUFile *f;
     int c;
 
@@ -175,26 +156,30 @@ int tcp_start_incoming_migration(const char *host_port)
     int val;
     int s;
 
+    DPRINTF("Attempting to start an incoming migration\n");
+
     if (parse_host_port(&addr, host_port) < 0) {
         fprintf(stderr, "invalid host/port combination: %s\n", host_port);
         return -EINVAL;
     }
 
     s = qemu_socket(PF_INET, SOCK_STREAM, 0);
-    if (s == -1)
+    if (s == -1) {
         return -socket_error();
+    }
 
     val = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
 
-    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
         goto err;
-
-    if (listen(s, 1) == -1)
+    }
+    if (listen(s, 1) == -1) {
         goto err;
+    }
 
     qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
-                         (void *)(unsigned long)s);
+                         (void *)(intptr_t)s);
 
     return 0;
 
index 57232c07a934156ff8948418970ce925d0da5191..8596353d7d071afa8bfedb26fa32f697706258bb 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"
 
     do { } while (0)
 #endif
 
-static int unix_errno(FdMigrationState *s)
+static int unix_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int unix_write(FdMigrationState *s, const void * buf, size_t size)
+static int unix_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int unix_close(FdMigrationState *s)
+static int unix_close(MigrationState *s)
 {
     DPRINTF("unix_close\n");
     if (s->fd != -1) {
@@ -51,14 +50,14 @@ static int unix_close(FdMigrationState *s)
 
 static void unix_wait_for_connect(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int val, ret;
     socklen_t valsize = sizeof(val);
 
     DPRINTF("connect completed\n");
     do {
         ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
-    } while (ret == -1 && (s->get_error(s)) == EINTR);
+    } while (ret == -1 && errno == EINTR);
 
     if (ret < 0) {
         migrate_fd_error(s);
@@ -75,91 +74,62 @@ static void unix_wait_for_connect(void *opaque)
     }
 }
 
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
-                                              const char *path,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-                                             int blk,
-                                             int inc)
+int unix_start_outgoing_migration(MigrationState *s, const char *path)
 {
-    FdMigrationState *s;
     struct sockaddr_un addr;
     int ret;
 
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
-
-    s = qemu_mallocz(sizeof(*s));
-
     s->get_error = unix_errno;
     s->write = unix_write;
     s->close = unix_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
 
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
     s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
-    if (s->fd < 0) {
+    if (s->fd == -1) {
         DPRINTF("Unable to open socket");
-        goto err_after_alloc;
+        return -errno;
     }
 
     socket_set_nonblock(s->fd);
 
     do {
         ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
-        if (ret == -1)
-           ret = -(s->get_error(s));
-
-        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+        if (ret == -1) {
+            ret = -errno;
+        }
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
            qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+            return 0;
+        }
     } while (ret == -EINTR);
 
-    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+    if (ret < 0) {
         DPRINTF("connect failed\n");
-        goto err_after_open;
-    }
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
+        migrate_fd_error(s);
+        return ret;
     }
-
-    if (ret >= 0)
-        migrate_fd_connect(s);
-
-    return &s->mig_state;
-
-err_after_open:
-    close(s->fd);
-
-err_after_alloc:
-    qemu_free(s);
-    return NULL;
+    migrate_fd_connect(s);
+    return 0;
 }
 
 static void unix_accept_incoming_migration(void *opaque)
 {
     struct sockaddr_un addr;
     socklen_t addrlen = sizeof(addr);
-    int s = (unsigned long)opaque;
+    int s = (intptr_t)opaque;
     QEMUFile *f;
     int c;
 
     do {
         c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
-    } while (c == -1 && socket_error() == EINTR);
+    } while (c == -1 && errno == EINTR);
 
     DPRINTF("accepted migration\n");
 
     if (c == -1) {
         fprintf(stderr, "could not accept migration connection\n");
-        return;
+        goto out2;
     }
 
     f = qemu_fopen_socket(c);
@@ -171,45 +141,49 @@ static void unix_accept_incoming_migration(void *opaque)
     process_incoming_migration(f);
     qemu_fclose(f);
 out:
+    close(c);
+out2:
     qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
     close(s);
-    close(c);
 }
 
 int unix_start_incoming_migration(const char *path)
 {
-    struct sockaddr_un un;
-    int sock;
+    struct sockaddr_un addr;
+    int s;
+    int ret;
 
     DPRINTF("Attempting to start an incoming migration\n");
 
-    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
+    s = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
         fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
-        return -EINVAL;
+        return -errno;
     }
 
-    memset(&un, 0, sizeof(un));
-    un.sun_family = AF_UNIX;
-    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
 
-    unlink(un.sun_path);
-    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
-        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+    unlink(addr.sun_path);
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        ret = -errno;
+        fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno));
         goto err;
     }
-    if (listen(sock, 1) < 0) {
-        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+    if (listen(s, 1) == -1) {
+        fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path,
+                strerror(errno));
+        ret = -errno;
         goto err;
     }
 
-    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
-                        (void *)(unsigned long)sock);
+    qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL,
+                         (void *)(intptr_t)s);
 
     return 0;
 
 err:
-    close(sock);
-
-    return -EINVAL;
+    close(s);
+    return ret;
 }
index 36125720a4d4e86e66372f10570160831440655a..8280d7189aa4265d6b7204863d8d9d5c24d8820d 100644 (file)
@@ -19,7 +19,7 @@
 #include "block.h"
 #include "qemu_socket.h"
 #include "block-migration.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
 
 //#define DEBUG_MIGRATION
 
     do { } while (0)
 #endif
 
-/* Migration speed throttling */
-static int64_t max_throttle = (32 << 20);
+enum {
+    MIG_STATE_ERROR,
+    MIG_STATE_SETUP,
+    MIG_STATE_CANCELLED,
+    MIG_STATE_ACTIVE,
+    MIG_STATE_COMPLETED,
+};
 
-static MigrationState *current_migration;
+#define MAX_THROTTLE  (32 << 20)      /* Migration speed throttling */
 
 static NotifierList migration_state_notifiers =
     NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
 
+/* When we add fault tolerance, we could have several
+   migrations at once.  For now we don't need to add
+   dynamic creation of migration */
+
+static MigrationState *migrate_get_current(void)
+{
+    static MigrationState current_migration = {
+        .state = MIG_STATE_SETUP,
+        .bandwidth_limit = MAX_THROTTLE,
+    };
+
+    return &current_migration;
+}
+
 int qemu_start_incoming_migration(const char *uri)
 {
     const char *p;
@@ -70,91 +89,14 @@ void process_incoming_migration(QEMUFile *f)
     qemu_announce_self();
     DPRINTF("successfully loaded vm state\n");
 
-    incoming_expected = false;
+    /* Make sure all file formats flush their mutable metadata */
+    bdrv_invalidate_cache_all();
 
-    if (autostart)
+    if (autostart) {
         vm_start();
-}
-
-int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    MigrationState *s = NULL;
-    const char *p;
-    int detach = qdict_get_try_bool(qdict, "detach", 0);
-    int blk = qdict_get_try_bool(qdict, "blk", 0);
-    int inc = qdict_get_try_bool(qdict, "inc", 0);
-    const char *uri = qdict_get_str(qdict, "uri");
-
-    if (current_migration &&
-        current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
-        monitor_printf(mon, "migration already in progress\n");
-        return -1;
-    }
-
-    if (qemu_savevm_state_blocked(mon)) {
-        return -1;
-    }
-
-    if (strstart(uri, "tcp:", &p)) {
-        s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
-                                         blk, inc);
-#if !defined(WIN32)
-    } else if (strstart(uri, "exec:", &p)) {
-        s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
-                                          blk, inc);
-    } else if (strstart(uri, "unix:", &p)) {
-        s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
-                                          blk, inc);
-    } else if (strstart(uri, "fd:", &p)) {
-        s = fd_start_outgoing_migration(mon, p, max_throttle, detach, 
-                                        blk, inc);
-#endif
     } else {
-        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
-        return -1;
+        runstate_set(RUN_STATE_PRELAUNCH);
     }
-
-    if (s == NULL) {
-        monitor_printf(mon, "migration failed\n");
-        return -1;
-    }
-
-    if (current_migration) {
-        current_migration->release(current_migration);
-    }
-
-    current_migration = s;
-    notifier_list_notify(&migration_state_notifiers);
-    return 0;
-}
-
-int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    MigrationState *s = current_migration;
-
-    if (s)
-        s->cancel(s);
-
-    return 0;
-}
-
-int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    int64_t d;
-    FdMigrationState *s;
-
-    d = qdict_get_int(qdict, "value");
-    if (d < 0) {
-        d = 0;
-    }
-    max_throttle = d;
-
-    s = migrate_to_fms(current_migration);
-    if (s && s->file) {
-        qemu_file_set_rate_limit(s->file, max_throttle);
-    }
-
-    return 0;
 }
 
 /* amount of nanoseconds we are willing to wait for migration to be down.
@@ -168,102 +110,54 @@ uint64_t migrate_max_downtime(void)
     return max_downtime;
 }
 
-int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
-                            QObject **ret_data)
+MigrationInfo *qmp_query_migrate(Error **errp)
 {
-    double d;
-
-    d = qdict_get_double(qdict, "value") * 1e9;
-    d = MAX(0, MIN(UINT64_MAX, d));
-    max_downtime = (uint64_t)d;
-
-    return 0;
-}
-
-static void migrate_print_status(Monitor *mon, const char *name,
-                                 const QDict *status_dict)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(qdict_get(status_dict, name));
-
-    monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "transferred") >> 10);
-    monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "remaining") >> 10);
-    monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "total") >> 10);
-}
-
-void do_info_migrate_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "Migration status: %s\n",
-                   qdict_get_str(qdict, "status"));
-
-    if (qdict_haskey(qdict, "ram")) {
-        migrate_print_status(mon, "ram", qdict);
-    }
-
-    if (qdict_haskey(qdict, "disk")) {
-        migrate_print_status(mon, "disk", qdict);
-    }
-}
-
-static void migrate_put_status(QDict *qdict, const char *name,
-                               uint64_t trans, uint64_t rem, uint64_t total)
-{
-    QObject *obj;
-
-    obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
-                               "'remaining': %" PRId64 ", "
-                               "'total': %" PRId64 " }", trans, rem, total);
-    qdict_put_obj(qdict, name, obj);
-}
-
-void do_info_migrate(Monitor *mon, QObject **ret_data)
-{
-    QDict *qdict;
-    MigrationState *s = current_migration;
-
-    if (s) {
-        switch (s->get_status(s)) {
-        case MIG_STATE_ACTIVE:
-            qdict = qdict_new();
-            qdict_put(qdict, "status", qstring_from_str("active"));
-
-            migrate_put_status(qdict, "ram", ram_bytes_transferred(),
-                               ram_bytes_remaining(), ram_bytes_total());
-
-            if (blk_mig_active()) {
-                migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
-                                   blk_mig_bytes_remaining(),
-                                   blk_mig_bytes_total());
-            }
-
-            *ret_data = QOBJECT(qdict);
-            break;
-        case MIG_STATE_COMPLETED:
-            *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
-            break;
-        case MIG_STATE_ERROR:
-            *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
-            break;
-        case MIG_STATE_CANCELLED:
-            *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
-            break;
+    MigrationInfo *info = g_malloc0(sizeof(*info));
+    MigrationState *s = migrate_get_current();
+
+    switch (s->state) {
+    case MIG_STATE_SETUP:
+        /* no migration has happened ever */
+        break;
+    case MIG_STATE_ACTIVE:
+        info->has_status = true;
+        info->status = g_strdup("active");
+
+        info->has_ram = true;
+        info->ram = g_malloc0(sizeof(*info->ram));
+        info->ram->transferred = ram_bytes_transferred();
+        info->ram->remaining = ram_bytes_remaining();
+        info->ram->total = ram_bytes_total();
+
+        if (blk_mig_active()) {
+            info->has_disk = true;
+            info->disk = g_malloc0(sizeof(*info->disk));
+            info->disk->transferred = blk_mig_bytes_transferred();
+            info->disk->remaining = blk_mig_bytes_remaining();
+            info->disk->total = blk_mig_bytes_total();
         }
+        break;
+    case MIG_STATE_COMPLETED:
+        info->has_status = true;
+        info->status = g_strdup("completed");
+        break;
+    case MIG_STATE_ERROR:
+        info->has_status = true;
+        info->status = g_strdup("failed");
+        break;
+    case MIG_STATE_CANCELLED:
+        info->has_status = true;
+        info->status = g_strdup("cancelled");
+        break;
     }
+
+    return info;
 }
 
 /* shared migration helpers */
 
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
+static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
 {
-    s->mon = mon;
     if (monitor_suspend(mon) == 0) {
         DPRINTF("suspending monitor\n");
     } else {
@@ -272,15 +166,7 @@ void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
     }
 }
 
-void migrate_fd_error(FdMigrationState *s)
-{
-    DPRINTF("setting error state\n");
-    s->state = MIG_STATE_ERROR;
-    notifier_list_notify(&migration_state_notifiers);
-    migrate_fd_cleanup(s);
-}
-
-int migrate_fd_cleanup(FdMigrationState *s)
+static int migrate_fd_cleanup(MigrationState *s)
 {
     int ret = 0;
 
@@ -292,34 +178,61 @@ int migrate_fd_cleanup(FdMigrationState *s)
             ret = -1;
         }
         s->file = NULL;
+    } else {
+        if (s->mon) {
+            monitor_resume(s->mon);
+        }
     }
 
-    if (s->fd != -1)
+    if (s->fd != -1) {
         close(s->fd);
-
-    /* Don't resume monitor until we've flushed all of the buffers */
-    if (s->mon) {
-        monitor_resume(s->mon);
+        s->fd = -1;
     }
 
-    s->fd = -1;
-
     return ret;
 }
 
-void migrate_fd_put_notify(void *opaque)
+void migrate_fd_error(MigrationState *s)
 {
-    FdMigrationState *s = opaque;
+    DPRINTF("setting error state\n");
+    s->state = MIG_STATE_ERROR;
+    notifier_list_notify(&migration_state_notifiers, s);
+    migrate_fd_cleanup(s);
+}
+
+static void migrate_fd_completed(MigrationState *s)
+{
+    DPRINTF("setting completed state\n");
+    if (migrate_fd_cleanup(s) < 0) {
+        s->state = MIG_STATE_ERROR;
+    } else {
+        s->state = MIG_STATE_COMPLETED;
+        runstate_set(RUN_STATE_POSTMIGRATE);
+    }
+    notifier_list_notify(&migration_state_notifiers, s);
+}
+
+static void migrate_fd_put_notify(void *opaque)
+{
+    MigrationState *s = opaque;
 
     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
     qemu_file_put_notify(s->file);
+    if (s->file && qemu_file_get_error(s->file)) {
+        migrate_fd_error(s);
+    }
 }
 
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
+static ssize_t migrate_fd_put_buffer(void *opaque, const void *data,
+                                     size_t size)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     ssize_t ret;
 
+    if (s->state != MIG_STATE_ACTIVE) {
+        return -EIO;
+    }
+
     do {
         ret = s->write(s, data, size);
     } while (ret == -1 && ((s->get_error(s)) == EINTR));
@@ -329,115 +242,61 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
 
     if (ret == -EAGAIN) {
         qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
-    } else if (ret < 0) {
-        if (s->mon) {
-            monitor_resume(s->mon);
-        }
-        s->state = MIG_STATE_ERROR;
-        notifier_list_notify(&migration_state_notifiers);
     }
 
     return ret;
 }
 
-void migrate_fd_connect(FdMigrationState *s)
+static void migrate_fd_put_ready(void *opaque)
 {
+    MigrationState *s = opaque;
     int ret;
 
-    s->file = qemu_fopen_ops_buffered(s,
-                                      s->bandwidth_limit,
-                                      migrate_fd_put_buffer,
-                                      migrate_fd_put_ready,
-                                      migrate_fd_wait_for_unfreeze,
-                                      migrate_fd_close);
-
-    DPRINTF("beginning savevm\n");
-    ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk,
-                                  s->mig_state.shared);
-    if (ret < 0) {
-        DPRINTF("failed, %d\n", ret);
-        migrate_fd_error(s);
-        return;
-    }
-    
-    migrate_fd_put_ready(s);
-}
-
-void migrate_fd_put_ready(void *opaque)
-{
-    FdMigrationState *s = opaque;
-
     if (s->state != MIG_STATE_ACTIVE) {
         DPRINTF("put_ready returning because of non-active state\n");
         return;
     }
 
     DPRINTF("iterate\n");
-    if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
-        int state;
-        int old_vm_running = vm_running;
+    ret = qemu_savevm_state_iterate(s->mon, s->file);
+    if (ret < 0) {
+        migrate_fd_error(s);
+    } else if (ret == 1) {
+        int old_vm_running = runstate_is_running();
 
         DPRINTF("done iterating\n");
-        vm_stop(0);
+        vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
 
-        if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
-            if (old_vm_running) {
-                vm_start();
-            }
-            state = MIG_STATE_ERROR;
+        if (qemu_savevm_state_complete(s->mon, s->file) < 0) {
+            migrate_fd_error(s);
         } else {
-            state = MIG_STATE_COMPLETED;
+            migrate_fd_completed(s);
         }
-        if (migrate_fd_cleanup(s) < 0) {
+        if (s->state != MIG_STATE_COMPLETED) {
             if (old_vm_running) {
                 vm_start();
             }
-            state = MIG_STATE_ERROR;
         }
-        s->state = state;
-        notifier_list_notify(&migration_state_notifiers);
     }
 }
 
-int migrate_fd_get_status(MigrationState *mig_state)
-{
-    FdMigrationState *s = migrate_to_fms(mig_state);
-    return s->state;
-}
-
-void migrate_fd_cancel(MigrationState *mig_state)
+static void migrate_fd_cancel(MigrationState *s)
 {
-    FdMigrationState *s = migrate_to_fms(mig_state);
-
     if (s->state != MIG_STATE_ACTIVE)
         return;
 
     DPRINTF("cancelling migration\n");
 
     s->state = MIG_STATE_CANCELLED;
-    notifier_list_notify(&migration_state_notifiers);
+    notifier_list_notify(&migration_state_notifiers, s);
     qemu_savevm_state_cancel(s->mon, s->file);
 
     migrate_fd_cleanup(s);
 }
 
-void migrate_fd_release(MigrationState *mig_state)
+static void migrate_fd_wait_for_unfreeze(void *opaque)
 {
-    FdMigrationState *s = migrate_to_fms(mig_state);
-
-    DPRINTF("releasing state\n");
-   
-    if (s->state == MIG_STATE_ACTIVE) {
-        s->state = MIG_STATE_CANCELLED;
-        notifier_list_notify(&migration_state_notifiers);
-        migrate_fd_cleanup(s);
-    }
-    qemu_free(s);
-}
-
-void migrate_fd_wait_for_unfreeze(void *opaque)
-{
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int ret;
 
     DPRINTF("wait for unfreeze\n");
@@ -452,12 +311,19 @@ void migrate_fd_wait_for_unfreeze(void *opaque)
 
         ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
     } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret == -1) {
+        qemu_file_set_error(s->file, -s->get_error(s));
+    }
 }
 
-int migrate_fd_close(void *opaque)
+static int migrate_fd_close(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
 
+    if (s->mon) {
+        monitor_resume(s->mon);
+    }
     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
     return s->close(s);
 }
@@ -472,11 +338,167 @@ void remove_migration_state_change_notifier(Notifier *notify)
     notifier_list_remove(&migration_state_notifiers, notify);
 }
 
-int get_migration_state(void)
+bool migration_is_active(MigrationState *s)
+{
+    return s->state == MIG_STATE_ACTIVE;
+}
+
+bool migration_has_finished(MigrationState *s)
+{
+    return s->state == MIG_STATE_COMPLETED;
+}
+
+bool migration_has_failed(MigrationState *s)
+{
+    return (s->state == MIG_STATE_CANCELLED ||
+            s->state == MIG_STATE_ERROR);
+}
+
+void migrate_fd_connect(MigrationState *s)
+{
+    int ret;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->file = qemu_fopen_ops_buffered(s,
+                                      s->bandwidth_limit,
+                                      migrate_fd_put_buffer,
+                                      migrate_fd_put_ready,
+                                      migrate_fd_wait_for_unfreeze,
+                                      migrate_fd_close);
+
+    DPRINTF("beginning savevm\n");
+    ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared);
+    if (ret < 0) {
+        DPRINTF("failed, %d\n", ret);
+        migrate_fd_error(s);
+        return;
+    }
+    migrate_fd_put_ready(s);
+}
+
+static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
+{
+    MigrationState *s = migrate_get_current();
+    int64_t bandwidth_limit = s->bandwidth_limit;
+
+    memset(s, 0, sizeof(*s));
+    s->bandwidth_limit = bandwidth_limit;
+    s->blk = blk;
+    s->shared = inc;
+
+    /* s->mon is used for two things:
+       - pass fd in fd migration
+       - suspend/resume monitor for not detached migration
+    */
+    s->mon = mon;
+    s->bandwidth_limit = bandwidth_limit;
+    s->state = MIG_STATE_SETUP;
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    return s;
+}
+
+static GSList *migration_blockers;
+
+void migrate_add_blocker(Error *reason)
+{
+    migration_blockers = g_slist_prepend(migration_blockers, reason);
+}
+
+void migrate_del_blocker(Error *reason)
 {
-    if (current_migration) {
-        return migrate_fd_get_status(current_migration);
+    migration_blockers = g_slist_remove(migration_blockers, reason);
+}
+
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    MigrationState *s = migrate_get_current();
+    const char *p;
+    int detach = qdict_get_try_bool(qdict, "detach", 0);
+    int blk = qdict_get_try_bool(qdict, "blk", 0);
+    int inc = qdict_get_try_bool(qdict, "inc", 0);
+    const char *uri = qdict_get_str(qdict, "uri");
+    int ret;
+
+    if (s->state == MIG_STATE_ACTIVE) {
+        monitor_printf(mon, "migration already in progress\n");
+        return -1;
+    }
+
+    if (qemu_savevm_state_blocked(mon)) {
+        return -1;
+    }
+
+    if (migration_blockers) {
+        Error *err = migration_blockers->data;
+        qerror_report_err(err);
+        return -1;
+    }
+
+    s = migrate_init(mon, detach, blk, inc);
+
+    if (strstart(uri, "tcp:", &p)) {
+        ret = tcp_start_outgoing_migration(s, p);
+#if !defined(WIN32)
+    } else if (strstart(uri, "exec:", &p)) {
+        ret = exec_start_outgoing_migration(s, p);
+    } else if (strstart(uri, "unix:", &p)) {
+        ret = unix_start_outgoing_migration(s, p);
+    } else if (strstart(uri, "fd:", &p)) {
+        ret = fd_start_outgoing_migration(s, p);
+#endif
     } else {
-        return MIG_STATE_ERROR;
+        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+        ret  = -EINVAL;
+    }
+
+    if (ret < 0) {
+        monitor_printf(mon, "migration failed: %s\n", strerror(-ret));
+        return ret;
     }
+
+    if (detach) {
+        s->mon = NULL;
+    }
+
+    notifier_list_notify(&migration_state_notifiers, s);
+    return 0;
+}
+
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    migrate_fd_cancel(migrate_get_current());
+    return 0;
+}
+
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int64_t d;
+    MigrationState *s;
+
+    d = qdict_get_int(qdict, "value");
+    if (d < 0) {
+        d = 0;
+    }
+
+    s = migrate_get_current();
+    s->bandwidth_limit = d;
+    qemu_file_set_rate_limit(s->file, s->bandwidth_limit);
+
+    return 0;
+}
+
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+                            QObject **ret_data)
+{
+    double d;
+
+    d = qdict_get_double(qdict, "value") * 1e9;
+    d = MAX(0, MIN(UINT64_MAX, d));
+    max_downtime = (uint64_t)d;
+
+    return 0;
 }
index 21707922ef602a4348cee83e52b9389fd57ea444..0682179bdefee42017f7222783822b263871a7db 100644 (file)
 #include "qdict.h"
 #include "qemu-common.h"
 #include "notify.h"
-
-#define MIG_STATE_ERROR                -1
-#define MIG_STATE_COMPLETED    0
-#define MIG_STATE_CANCELLED    1
-#define MIG_STATE_ACTIVE       2
+#include "error.h"
 
 typedef struct MigrationState MigrationState;
 
 struct MigrationState
 {
-    /* FIXME: add more accessors to print migration info */
-    void (*cancel)(MigrationState *s);
-    int (*get_status)(MigrationState *s);
-    void (*release)(MigrationState *s);
-    int blk;
-    int shared;
-};
-
-typedef struct FdMigrationState FdMigrationState;
-
-struct FdMigrationState
-{
-    MigrationState mig_state;
     int64_t bandwidth_limit;
     QEMUFile *file;
     int fd;
     Monitor *mon;
     int state;
-    int (*get_error)(struct FdMigrationState*);
-    int (*close)(struct FdMigrationState*);
-    int (*write)(struct FdMigrationState*, const void *, size_t);
+    int (*get_error)(MigrationState *s);
+    int (*close)(MigrationState *s);
+    int (*write)(MigrationState *s, const void *buff, size_t size);
     void *opaque;
+    int blk;
+    int shared;
 };
 
 void process_incoming_migration(QEMUFile *f);
@@ -72,71 +57,51 @@ void do_info_migrate(Monitor *mon, QObject **ret_data);
 
 int exec_start_incoming_migration(const char *host_port);
 
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
-                                              const char *host_port,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-                                             int blk,
-                                             int inc);
+int exec_start_outgoing_migration(MigrationState *s, const char *host_port);
 
 int tcp_start_incoming_migration(const char *host_port);
 
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
-                                             const char *host_port,
-                                            int64_t bandwidth_limit,
-                                            int detach,
-                                            int blk,
-                                            int inc);
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port);
 
 int unix_start_incoming_migration(const char *path);
 
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
-                                              const char *path,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-                                             int blk,
-                                             int inc);
+int unix_start_outgoing_migration(MigrationState *s, const char *path);
 
 int fd_start_incoming_migration(const char *path);
 
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
-                                           const char *fdname,
-                                           int64_t bandwidth_limit,
-                                           int detach,
-                                           int blk,
-                                           int inc);
-
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon);
-
-void migrate_fd_error(FdMigrationState *s);
-
-int migrate_fd_cleanup(FdMigrationState *s);
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname);
 
-void migrate_fd_put_notify(void *opaque);
+void migrate_fd_error(MigrationState *s);
 
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
+void migrate_fd_connect(MigrationState *s);
 
-void migrate_fd_connect(FdMigrationState *s);
-
-void migrate_fd_put_ready(void *opaque);
-
-int migrate_fd_get_status(MigrationState *mig_state);
-
-void migrate_fd_cancel(MigrationState *mig_state);
+void add_migration_state_change_notifier(Notifier *notify);
+void remove_migration_state_change_notifier(Notifier *notify);
+bool migration_is_active(MigrationState *);
+bool migration_has_finished(MigrationState *);
+bool migration_has_failed(MigrationState *);
 
-void migrate_fd_release(MigrationState *mig_state);
+uint64_t ram_bytes_remaining(void);
+uint64_t ram_bytes_transferred(void);
+uint64_t ram_bytes_total(void);
 
-void migrate_fd_wait_for_unfreeze(void *opaque);
+int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
+int ram_load(QEMUFile *f, void *opaque, int version_id);
 
-int migrate_fd_close(void *opaque);
+extern int incoming_expected;
 
-static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
-{
-    return container_of(mig_state, FdMigrationState, mig_state);
-}
+/**
+ * @migrate_add_blocker - prevent migration from proceeding
+ *
+ * @reason - an error to be returned whenever migration is attempted
+ */
+void migrate_add_blocker(Error *reason);
 
-void add_migration_state_change_notifier(Notifier *notify);
-void remove_migration_state_change_notifier(Notifier *notify);
-int get_migration_state(void);
+/**
+ * @migrate_del_blocker - remove a blocking error from migration
+ *
+ * @reason - the error blocking migration
+ */
+void migrate_del_blocker(Error *reason);
 
 #endif
index 4d8e85bd94177602b0511c8472e1744a1346d5b7..e3a6e0b49ec229b1992f0dc8552540da9530af5e 100644 (file)
@@ -4841,7 +4841,7 @@ with the -M switch (multiple options should be separated by commas):\n"));
                            Default: based on binary being disassembled.\n"));
 
   fprintf (stream, _("\n\
-  hwr-names=ARCH           Print HWR names according to specified \n\
+  hwr-names=ARCH           Print HWR names according to specified\n\
                           architecture.\n\
                            Default: based on binary being disassembled.\n"));
 
diff --git a/mips.ld b/mips.ld
index 4294761c199b234faf204f6269a55db8fd788e1f..7b610ceed47d3a3a40df4e785b1f752595fa41a0 100644 (file)
--- a/mips.ld
+++ b/mips.ld
@@ -79,36 +79,34 @@ SECTIONS
   }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
index e77d5697685a7927bee40329038eb97d0139f235..91f0e61cbb17e3c21be8704505c9af43bee0c922 100644 (file)
--- a/module.c
+++ b/module.c
@@ -59,7 +59,7 @@ void register_module_init(void (*fn)(void), module_init_type type)
     ModuleEntry *e;
     ModuleTypeList *l;
 
-    e = qemu_mallocz(sizeof(*e));
+    e = g_malloc0(sizeof(*e));
     e->init = fn;
 
     l = find_type(type);
index 9263f1c7e20b84fce57ea4261cd0ee2affe1a077..ef667304c44f825c2f76d16b0a04656a7e9c0dec 100644 (file)
--- a/module.h
+++ b/module.h
@@ -24,12 +24,14 @@ typedef enum {
     MODULE_INIT_BLOCK,
     MODULE_INIT_DEVICE,
     MODULE_INIT_MACHINE,
+    MODULE_INIT_QAPI,
     MODULE_INIT_MAX
 } module_init_type;
 
 #define block_init(function) module_init(function, MODULE_INIT_BLOCK)
 #define device_init(function) module_init(function, MODULE_INIT_DEVICE)
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
+#define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
index 7fc311d720cdafc29ef54222adaff2b2d7888570..1be222ee18aae09f73b2b232fc10dde96a713344 100644 (file)
--- a/monitor.c
+++ b/monitor.c
 #include "json-streamer.h"
 #include "json-parser.h"
 #include "osdep.h"
-#include "exec-all.h"
-#ifdef CONFIG_SIMPLE_TRACE
+#include "cpu.h"
 #include "trace.h"
+#include "trace/control.h"
+#ifdef CONFIG_TRACE_SIMPLE
+#include "trace/simple.h"
 #endif
 #include "ui/qemu-spice.h"
+#include "memory.h"
+#include "qmp-commands.h"
+#include "hmp.h"
+
+/* for pic/irq_info */
+#if defined(TARGET_SPARC)
+#include "hw/sun4m.h"
+#endif
+#include "hw/lm32_pic.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -112,13 +123,12 @@ typedef struct mon_cmd_t {
     void (*user_print)(Monitor *mon, const QObject *data);
     union {
         void (*info)(Monitor *mon);
-        void (*info_new)(Monitor *mon, QObject **ret_data);
-        int  (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
         void (*cmd)(Monitor *mon, const QDict *qdict);
         int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
         int  (*cmd_async)(Monitor *mon, const QDict *params,
                           MonitorCompletion *cb, void *opaque);
     } mhandler;
+    bool qapi;
     int flags;
 } mon_cmd_t;
 
@@ -189,11 +199,10 @@ static inline int mon_print_count_get(const Monitor *mon) { return 0; }
 
 static QLIST_HEAD(mon_list, Monitor) mon_list;
 
-static const mon_cmd_t mon_cmds[];
-static const mon_cmd_t info_cmds[];
+static mon_cmd_t mon_cmds[];
+static mon_cmd_t info_cmds[];
 
 static const mon_cmd_t qmp_cmds[];
-static const mon_cmd_t qmp_query_cmds[];
 
 Monitor *cur_mon;
 Monitor *default_mon;
@@ -247,7 +256,7 @@ static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
 void monitor_flush(Monitor *mon)
 {
     if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
-        qemu_chr_write(mon->chr, mon->outbuf, mon->outbuf_index);
+        qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index);
         mon->outbuf_index = 0;
     }
 }
@@ -367,6 +376,8 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
 {
     QDict *qmp;
 
+    trace_monitor_protocol_emitter(mon);
+
     qmp = qdict_new();
 
     if (!monitor_has_error(mon)) {
@@ -500,7 +511,6 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
     return 0;
 }
 
-static int mon_set_cpu(int cpu_index);
 static void handle_user_command(Monitor *mon, const char *cmdline);
 
 static int do_hmp_passthrough(Monitor *mon, const QDict *params,
@@ -518,7 +528,7 @@ static int do_hmp_passthrough(Monitor *mon, const QDict *params,
     cur_mon = &hmp;
 
     if (qdict_haskey(params, "cpu-index")) {
-        ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+        ret = monitor_set_cpu(qdict_get_int(params, "cpu-index"));
         if (ret < 0) {
             cur_mon = old_mon;
             qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
@@ -592,18 +602,18 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict)
     help_cmd(mon, qdict_get_try_str(qdict, "name"));
 }
 
-#ifdef CONFIG_SIMPLE_TRACE
-static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
+static void do_trace_event_set_state(Monitor *mon, const QDict *qdict)
 {
     const char *tp_name = qdict_get_str(qdict, "name");
     bool new_state = qdict_get_bool(qdict, "option");
-    int ret = st_change_trace_event_state(tp_name, new_state);
+    int ret = trace_event_set_state(tp_name, new_state);
 
     if (!ret) {
         monitor_printf(mon, "unknown event name \"%s\"\n", tp_name);
     }
 }
 
+#ifdef CONFIG_TRACE_SIMPLE
 static void do_trace_file(Monitor *mon, const QDict *qdict)
 {
     const char *op = qdict_get_try_str(qdict, "op");
@@ -636,7 +646,7 @@ static void user_monitor_complete(void *opaque, QObject *ret_data)
         data->user_print(data->mon, ret_data);
     }
     monitor_resume(data->mon);
-    qemu_free(data);
+    g_free(data);
 }
 
 static void qmp_monitor_complete(void *opaque, QObject *ret_data)
@@ -650,17 +660,12 @@ static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
     return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
 }
 
-static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
-    cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
-}
-
 static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
                                    const QDict *params)
 {
     int ret;
 
-    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
+    MonitorCompletionData *cb_data = g_malloc(sizeof(*cb_data));
     cb_data->mon = mon;
     cb_data->user_print = cmd->user_print;
     monitor_suspend(mon);
@@ -668,22 +673,7 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
                                   user_monitor_complete, cb_data);
     if (ret < 0) {
         monitor_resume(mon);
-        qemu_free(cb_data);
-    }
-}
-
-static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
-    int ret;
-
-    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
-    cb_data->mon = mon;
-    cb_data->user_print = cmd->user_print;
-    monitor_suspend(mon);
-    ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
-    if (ret < 0) {
-        monitor_resume(mon);
-        qemu_free(cb_data);
+        g_free(cb_data);
     }
 }
 
@@ -705,129 +695,32 @@ static void do_info(Monitor *mon, const QDict *qdict)
         goto help;
     }
 
-    if (handler_is_async(cmd)) {
-        user_async_info_handler(mon, cmd);
-    } else if (handler_is_qobject(cmd)) {
-        QObject *info_data = NULL;
-
-        cmd->mhandler.info_new(mon, &info_data);
-        if (info_data) {
-            cmd->user_print(mon, info_data);
-            qobject_decref(info_data);
-        }
-    } else {
-        cmd->mhandler.info(mon);
-    }
-
+    cmd->mhandler.info(mon);
     return;
 
 help:
     help_cmd(mon, "info");
 }
 
-static void do_info_version_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-    QDict *qemu;
-
-    qdict = qobject_to_qdict(data);
-    qemu = qdict_get_qdict(qdict, "qemu");
-
-    monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
-                  qdict_get_int(qemu, "major"),
-                  qdict_get_int(qemu, "minor"),
-                  qdict_get_int(qemu, "micro"),
-                  qdict_get_str(qdict, "package"));
-}
-
-static void do_info_version(Monitor *mon, QObject **ret_data)
+CommandInfoList *qmp_query_commands(Error **errp)
 {
-    const char *version = QEMU_VERSION;
-    int major = 0, minor = 0, micro = 0;
-    char *tmp;
-
-    major = strtol(version, &tmp, 10);
-    tmp++;
-    minor = strtol(tmp, &tmp, 10);
-    tmp++;
-    micro = strtol(tmp, &tmp, 10);
-
-    *ret_data = qobject_from_jsonf("{ 'qemu': { 'major': %d, 'minor': %d, \
-        'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION);
-}
-
-static void do_info_name_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-    if (qdict_size(qdict) == 0) {
-        return;
-    }
-
-    monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name"));
-}
-
-static void do_info_name(Monitor *mon, QObject **ret_data)
-{
-    *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) :
-                            qobject_from_jsonf("{}");
-}
-
-static QObject *get_cmd_dict(const char *name)
-{
-    const char *p;
-
-    /* Remove '|' from some commands */
-    p = strchr(name, '|');
-    if (p) {
-        p++;
-    } else {
-        p = name;
-    }
-
-    return qobject_from_jsonf("{ 'name': %s }", p);
-}
-
-static void do_info_commands(Monitor *mon, QObject **ret_data)
-{
-    QList *cmd_list;
+    CommandInfoList *info, *cmd_list = NULL;
     const mon_cmd_t *cmd;
 
-    cmd_list = qlist_new();
-
     for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
-        qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
-    }
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(cmd->name);
 
-    for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
-        char buf[128];
-        snprintf(buf, sizeof(buf), "query-%s", cmd->name);
-        qlist_append_obj(cmd_list, get_cmd_dict(buf));
+        info->next = cmd_list;
+        cmd_list = info;
     }
 
-    *ret_data = QOBJECT(cmd_list);
+    return cmd_list;
 }
 
-static void do_info_uuid_print(Monitor *mon, const QObject *data)
-{
-    monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
-}
-
-static void do_info_uuid(Monitor *mon, QObject **ret_data)
-{
-    char uuid[64];
-
-    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
-                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
-                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
-                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
-                   qemu_uuid[14], qemu_uuid[15]);
-    *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid);
-}
-
-/* get the current CPU defined by the user */
-static int mon_set_cpu(int cpu_index)
+/* set the current CPU defined by the user */
+int monitor_set_cpu(int cpu_index)
 {
     CPUState *env;
 
@@ -843,12 +736,17 @@ static int mon_set_cpu(int cpu_index)
 static CPUState *mon_get_cpu(void)
 {
     if (!cur_mon->mon_cpu) {
-        mon_set_cpu(0);
+        monitor_set_cpu(0);
     }
     cpu_synchronize_state(cur_mon->mon_cpu);
     return cur_mon->mon_cpu;
 }
 
+int monitor_get_cpu_index(void)
+{
+    return mon_get_cpu()->cpu_index;
+}
+
 static void do_info_registers(Monitor *mon)
 {
     CPUState *env;
@@ -862,103 +760,6 @@ static void do_info_registers(Monitor *mon)
 #endif
 }
 
-static void print_cpu_iter(QObject *obj, void *opaque)
-{
-    QDict *cpu;
-    int active = ' ';
-    Monitor *mon = opaque;
-
-    assert(qobject_type(obj) == QTYPE_QDICT);
-    cpu = qobject_to_qdict(obj);
-
-    if (qdict_get_bool(cpu, "current")) {
-        active = '*';
-    }
-
-    monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
-
-#if defined(TARGET_I386)
-    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
-                   (target_ulong) qdict_get_int(cpu, "pc"));
-#elif defined(TARGET_PPC)
-    monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "nip"));
-#elif defined(TARGET_SPARC)
-    monitor_printf(mon, "pc=0x " TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "pc"));
-    monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "npc"));
-#elif defined(TARGET_MIPS)
-    monitor_printf(mon, "PC=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "PC"));
-#endif
-
-    if (qdict_get_bool(cpu, "halted")) {
-        monitor_printf(mon, " (halted)");
-    }
-
-    monitor_printf(mon, "\n");
-}
-
-static void monitor_print_cpus(Monitor *mon, const QObject *data)
-{
-    QList *cpu_list;
-
-    assert(qobject_type(data) == QTYPE_QLIST);
-    cpu_list = qobject_to_qlist(data);
-    qlist_iter(cpu_list, print_cpu_iter, mon);
-}
-
-static void do_info_cpus(Monitor *mon, QObject **ret_data)
-{
-    CPUState *env;
-    QList *cpu_list;
-
-    cpu_list = qlist_new();
-
-    /* just to set the default cpu if not already done */
-    mon_get_cpu();
-
-    for(env = first_cpu; env != NULL; env = env->next_cpu) {
-        QDict *cpu;
-        QObject *obj;
-
-        cpu_synchronize_state(env);
-
-        obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
-                                 env->cpu_index, env == mon->mon_cpu,
-                                 env->halted);
-
-        cpu = qobject_to_qdict(obj);
-
-#if defined(TARGET_I386)
-        qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
-#elif defined(TARGET_PPC)
-        qdict_put(cpu, "nip", qint_from_int(env->nip));
-#elif defined(TARGET_SPARC)
-        qdict_put(cpu, "pc", qint_from_int(env->pc));
-        qdict_put(cpu, "npc", qint_from_int(env->npc));
-#elif defined(TARGET_MIPS)
-        qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
-#endif
-
-        qlist_append(cpu_list, cpu);
-    }
-
-    *ret_data = QOBJECT(cpu_list);
-}
-
-static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    int index = qdict_get_int(qdict, "index");
-    if (mon_set_cpu(index) < 0) {
-        qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
-                      "a CPU number");
-        return -1;
-    }
-    return 0;
-}
-
 static void do_info_jit(Monitor *mon)
 {
     dump_exec_info((FILE *)mon, monitor_fprintf);
@@ -992,30 +793,19 @@ static void do_info_cpu_stats(Monitor *mon)
 }
 #endif
 
-#if defined(CONFIG_SIMPLE_TRACE)
+#if defined(CONFIG_TRACE_SIMPLE)
 static void do_info_trace(Monitor *mon)
 {
     st_print_trace((FILE *)mon, &monitor_fprintf);
 }
-
-static void do_info_trace_events(Monitor *mon)
-{
-    st_print_trace_events((FILE *)mon, &monitor_fprintf);
-}
 #endif
 
-/**
- * do_quit(): Quit QEMU execution
- */
-static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static void do_trace_print_events(Monitor *mon)
 {
-    monitor_suspend(mon);
-    no_shutdown = 0;
-    qemu_system_shutdown_request();
-
-    return 0;
+    trace_print_events((FILE *)mon, &monitor_fprintf);
 }
 
+#ifdef CONFIG_VNC
 static int change_vnc_password(const char *password)
 {
     if (!password || !password[0]) {
@@ -1062,6 +852,13 @@ static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
 
     return 0;
 }
+#else
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+}
+#endif
 
 /**
  * do_change(): Change a removable medium, or VNC configuration
@@ -1127,12 +924,7 @@ static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
         }
         /* Note that setting an empty password will not disable login through
          * this interface. */
-        rc = vnc_display_password(NULL, password);
-        if (rc != 0) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
-            return -1;
-        }
-        return 0;
+        return vnc_display_password(NULL, password);
     }
 
     qerror_report(QERR_INVALID_PARAMETER, "protocol");
@@ -1171,19 +963,49 @@ static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
     }
 
     if (strcmp(protocol, "vnc") == 0) {
-        rc = vnc_display_pw_expire(NULL, when);
-        if (rc != 0) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
+        return vnc_display_pw_expire(NULL, when);
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *fdname = qdict_get_str(qdict, "fdname");
+    CharDriverState *s;
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
             return -1;
         }
-        return 0;
+       qerror_report(QERR_ADD_CLIENT_FAILED);
+       return -1;
+#ifdef CONFIG_VNC
+    } else if (strcmp(protocol, "vnc") == 0) {
+       int fd = monitor_get_fd(mon, fdname);
+        int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
+       vnc_display_add_client(NULL, fd, skipauth);
+       return 0;
+#endif
+    } else if ((s = qemu_chr_find(protocol)) != NULL) {
+       int fd = monitor_get_fd(mon, fdname);
+       if (qemu_chr_add_client(s, fd) < 0) {
+           qerror_report(QERR_ADD_CLIENT_FAILED);
+           return -1;
+       }
+       return 0;
     }
 
     qerror_report(QERR_INVALID_PARAMETER, "protocol");
     return -1;
 }
 
-static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int client_migrate_info(Monitor *mon, const QDict *qdict,
+                               MonitorCompletion cb, void *opaque)
 {
     const char *protocol = qdict_get_str(qdict, "protocol");
     const char *hostname = qdict_get_str(qdict, "hostname");
@@ -1198,7 +1020,8 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_d
             return -1;
         }
 
-        ret = qemu_spice_migrate_info(hostname, port, tls_port, subject);
+        ret = qemu_spice_migrate_info(hostname, port, tls_port, subject,
+                                      cb, opaque);
         if (ret != 0) {
             qerror_report(QERR_UNDEFINED_ERROR);
             return -1;
@@ -1250,15 +1073,6 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
     }
 }
 
-/**
- * do_stop(): Stop VM execution
- */
-static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    vm_stop(EXCP_INTERRUPT);
-    return 0;
-}
-
 static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
 
 struct bdrv_iterate_context {
@@ -1266,6 +1080,11 @@ struct bdrv_iterate_context {
     int err;
 };
 
+static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
+{
+    bdrv_iostatus_reset(bs);
+}
+
 /**
  * do_cont(): Resume emulation.
  */
@@ -1273,10 +1092,16 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     struct bdrv_iterate_context context = { mon, 0 };
 
-    if (incoming_expected) {
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
         qerror_report(QERR_MIGRATION_EXPECTED);
         return -1;
+    } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+               runstate_check(RUN_STATE_SHUTDOWN)) {
+        qerror_report(QERR_RESET_REQUIRED);
+        return -1;
     }
+
+    bdrv_iterate(iostatus_bdrv_it, NULL);
     bdrv_iterate(encrypted_bdrv_it, &context);
     /* only resume the vm if all keys are set and valid */
     if (!context.err) {
@@ -1427,7 +1252,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) {
@@ -1603,7 +1428,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;
@@ -1623,17 +1448,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);
 }
@@ -1873,7 +1697,7 @@ static void do_sendkey(Monitor *mon, const QDict *qdict)
         kbd_put_keycode(keycode & 0x7f);
     }
     /* delayed key up events */
-    qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) +
+    qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
                    muldiv64(get_ticks_per_sec(), hold_time, 1000));
 }
 
@@ -1972,16 +1796,6 @@ static void do_boot_set(Monitor *mon, const QDict *qdict)
     }
 }
 
-/**
- * do_system_reset(): Issue a machine reset
- */
-static int do_system_reset(Monitor *mon, const QDict *qdict,
-                           QObject **ret_data)
-{
-    qemu_system_reset_request();
-    return 0;
-}
-
 /**
  * do_system_powerdown(): Issue a machine powerdown
  */
@@ -2019,12 +1833,12 @@ static void print_pte(Monitor *mon, target_phys_addr_t addr,
 
 static void tlb_info_32(Monitor *mon, CPUState *env)
 {
-    int l1, l2;
+    unsigned int l1, l2;
     uint32_t pgd, pde, pte;
 
     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)) {
@@ -2032,8 +1846,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),
@@ -2048,19 +1861,18 @@ static void tlb_info_32(Monitor *mon, CPUState *env)
 
 static void tlb_info_pae32(Monitor *mon, CPUState *env)
 {
-    int l1, l2, l3;
+    unsigned int l1, l2, l3;
     uint64_t pdpe, pde, pte;
     uint64_t pdp_addr, pd_addr, pt_addr;
 
     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) {
@@ -2070,8 +1882,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)
@@ -2096,13 +1907,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) {
@@ -2112,8 +1922,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) {
@@ -2126,8 +1935,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) +
@@ -2197,7 +2005,8 @@ static void mem_print(Monitor *mon, target_phys_addr_t *pstart,
 
 static void mem_info_32(Monitor *mon, CPUState *env)
 {
-    int l1, l2, prot, last_prot;
+    unsigned int l1, l2;
+    int prot, last_prot;
     uint32_t pgd, pde, pte;
     target_phys_addr_t start, end;
 
@@ -2205,7 +2014,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) {
@@ -2214,12 +2023,12 @@ 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) {
-                        prot = pte & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK);
+                        prot = pte & pde &
+                            (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK);
                     } else {
                         prot = 0;
                     }
@@ -2231,11 +2040,14 @@ static void mem_info_32(Monitor *mon, CPUState *env)
             mem_print(mon, &start, &last_prot, end, prot);
         }
     }
+    /* Flush last range */
+    mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 32, 0);
 }
 
 static void mem_info_pae32(Monitor *mon, CPUState *env)
 {
-    int l1, l2, l3, prot, last_prot;
+    unsigned int l1, l2, l3;
+    int prot, last_prot;
     uint64_t pdpe, pde, pte;
     uint64_t pdp_addr, pd_addr, pt_addr;
     target_phys_addr_t start, end;
@@ -2244,14 +2056,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) {
@@ -2262,13 +2073,12 @@ 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) {
-                                prot = pte & (PG_USER_MASK | PG_RW_MASK |
-                                              PG_PRESENT_MASK);
+                                prot = pte & pde & (PG_USER_MASK | PG_RW_MASK |
+                                                    PG_PRESENT_MASK);
                             } else {
                                 prot = 0;
                             }
@@ -2285,6 +2095,8 @@ static void mem_info_pae32(Monitor *mon, CPUState *env)
             mem_print(mon, &start, &last_prot, end, prot);
         }
     }
+    /* Flush last range */
+    mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 32, 0);
 }
 
 
@@ -2300,46 +2112,46 @@ 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) {
                     if (pdpe & PG_PSE_MASK) {
                         prot = pdpe & (PG_USER_MASK | PG_RW_MASK |
                                        PG_PRESENT_MASK);
+                        prot &= pml4e;
                         mem_print(mon, &start, &last_prot, end, prot);
                     } 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) {
                                 if (pde & PG_PSE_MASK) {
                                     prot = pde & (PG_USER_MASK | PG_RW_MASK |
                                                   PG_PRESENT_MASK);
+                                    prot &= pml4e & pdpe;
                                     mem_print(mon, &start, &last_prot, end, prot);
                                 } else {
                                     pt_addr = pde & 0x3fffffffff000ULL;
                                     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);
                                         if (pte & PG_PRESENT_MASK) {
                                             prot = pte & (PG_USER_MASK | PG_RW_MASK |
                                                           PG_PRESENT_MASK);
+                                            prot &= pml4e & pdpe & pde;
                                         } else {
                                             prot = 0;
                                         }
@@ -2362,6 +2174,8 @@ static void mem_info_64(Monitor *mon, CPUState *env)
             mem_print(mon, &start, &last_prot, end, prot);
         }
     }
+    /* Flush last range */
+    mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 48, 0);
 }
 #endif
 
@@ -2419,7 +2233,7 @@ static void tlb_info(Monitor *mon)
 
 #endif
 
-#if defined(TARGET_SPARC)
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
 static void tlb_info(Monitor *mon)
 {
     CPUState *env1 = mon_get_cpu();
@@ -2428,29 +2242,9 @@ static void tlb_info(Monitor *mon)
 }
 #endif
 
-static void do_info_kvm_print(Monitor *mon, const QObject *data)
+static void do_info_mtree(Monitor *mon)
 {
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "kvm support: ");
-    if (qdict_get_bool(qdict, "present")) {
-        monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ?
-                                    "enabled" : "disabled");
-    } else {
-        monitor_printf(mon, "not compiled\n");
-    }
-}
-
-static void do_info_kvm(Monitor *mon, QObject **ret_data)
-{
-#ifdef CONFIG_KVM
-    *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }",
-                                   kvm_enabled());
-#else
-    *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }");
-#endif
+    mtree_info((fprintf_function)monitor_printf, mon);
 }
 
 static void do_info_numa(Monitor *mon)
@@ -2522,7 +2316,7 @@ static void do_stop_capture(Monitor *mon, const QDict *qdict)
         if (i == n) {
             s->ops.destroy (s->opaque);
             QLIST_REMOVE (s, entries);
-            qemu_free (s);
+            g_free (s);
             return;
         }
     }
@@ -2539,7 +2333,7 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
     int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
     CaptureState *s;
 
-    s = qemu_mallocz (sizeof (*s));
+    s = g_malloc0 (sizeof (*s));
 
     freq = has_freq ? freq : 44100;
     bits = has_bits ? bits : 16;
@@ -2547,7 +2341,7 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
 
     if (wav_start_capture (s, path, freq, bits, nchannels)) {
         monitor_printf(mon, "Failed to add wave capture\n");
-        qemu_free (s);
+        g_free (s);
         return;
     }
     QLIST_INSERT_HEAD (&capture_head, s, entries);
@@ -2555,43 +2349,23 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
 #endif
 
 #if defined(TARGET_I386)
-static void do_inject_nmi(Monitor *mon, const QDict *qdict)
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     CPUState *env;
-    int cpu_index = qdict_get_int(qdict, "cpu_index");
 
-    for (env = first_cpu; env != NULL; env = env->next_cpu)
-        if (env->cpu_index == cpu_index) {
-            cpu_interrupt(env, CPU_INTERRUPT_NMI);
-            break;
-        }
-}
-#endif
-
-static void do_info_status_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "VM status: ");
-    if (qdict_get_bool(qdict, "running")) {
-        monitor_printf(mon, "running");
-        if (qdict_get_bool(qdict, "singlestep")) {
-            monitor_printf(mon, " (single step mode)");
-        }
-    } else {
-        monitor_printf(mon, "paused");
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_interrupt(env, CPU_INTERRUPT_NMI);
     }
 
-    monitor_printf(mon, "\n");
+    return 0;
 }
-
-static void do_info_status(Monitor *mon, QObject **ret_data)
+#else
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
-    *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
-                                    vm_running, singlestep);
+    qerror_report(QERR_UNSUPPORTED);
+    return -1;
 }
+#endif
 
 static qemu_acl *find_acl(Monitor *mon, const char *name)
 {
@@ -2709,12 +2483,15 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
     uint64_t mcg_status = qdict_get_int(qdict, "mcg_status");
     uint64_t addr = qdict_get_int(qdict, "addr");
     uint64_t misc = qdict_get_int(qdict, "misc");
-    int broadcast = qdict_get_try_bool(qdict, "broadcast", 0);
+    int flags = MCE_INJECT_UNCOND_AO;
 
+    if (qdict_get_try_bool(qdict, "broadcast", 0)) {
+        flags |= MCE_INJECT_BROADCAST;
+    }
     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
-        if (cenv->cpu_index == cpu_index && cenv->mcg_cap) {
-            cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc,
-                               broadcast);
+        if (cenv->cpu_index == cpu_index) {
+            cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
+                               flags);
             break;
         }
     }
@@ -2727,7 +2504,7 @@ static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
     mon_fd_t *monfd;
     int fd;
 
-    fd = qemu_chr_get_msgfd(mon->chr);
+    fd = qemu_chr_fe_get_msgfd(mon->chr);
     if (fd == -1) {
         qerror_report(QERR_FD_NOT_SUPPLIED);
         return -1;
@@ -2749,8 +2526,8 @@ static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
         return 0;
     }
 
-    monfd = qemu_mallocz(sizeof(mon_fd_t));
-    monfd->name = qemu_strdup(fdname);
+    monfd = g_malloc0(sizeof(mon_fd_t));
+    monfd->name = g_strdup(fdname);
     monfd->fd = fd;
 
     QLIST_INSERT_HEAD(&mon->fds, monfd, next);
@@ -2769,8 +2546,8 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
         QLIST_REMOVE(monfd, next);
         close(monfd->fd);
-        qemu_free(monfd->name);
-        qemu_free(monfd);
+        g_free(monfd->name);
+        g_free(monfd);
         return 0;
     }
 
@@ -2780,10 +2557,10 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
 static void do_loadvm(Monitor *mon, const QDict *qdict)
 {
-    int saved_vm_running  = vm_running;
+    int saved_vm_running  = runstate_is_running();
     const char *name = qdict_get_str(qdict, "name");
 
-    vm_stop(0);
+    vm_stop(RUN_STATE_RESTORE_VM);
 
     if (load_vmstate(name) == 0 && saved_vm_running) {
         vm_start();
@@ -2805,8 +2582,8 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
 
         /* caller takes ownership of fd */
         QLIST_REMOVE(monfd, next);
-        qemu_free(monfd->name);
-        qemu_free(monfd);
+        g_free(monfd->name);
+        g_free(monfd);
 
         return fd;
     }
@@ -2814,20 +2591,20 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
     return -1;
 }
 
-static const mon_cmd_t mon_cmds[] = {
+/* mon_cmds and info_cmds would be sorted at runtime */
+static mon_cmd_t mon_cmds[] = {
 #include "hmp-commands.h"
     { NULL, NULL, },
 };
 
 /* Please update hmp-commands.hx when adding or changing commands */
-static const mon_cmd_t info_cmds[] = {
+static mon_cmd_t info_cmds[] = {
     {
         .name       = "version",
         .args_type  = "",
         .params     = "",
         .help       = "show the version of QEMU",
-        .user_print = do_info_version_print,
-        .mhandler.info_new = do_info_version,
+        .mhandler.info = hmp_info_version,
     },
     {
         .name       = "network",
@@ -2841,24 +2618,21 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the character devices",
-        .user_print = qemu_chr_info_print,
-        .mhandler.info_new = qemu_chr_info,
+        .mhandler.info = hmp_info_chardev,
     },
     {
         .name       = "block",
         .args_type  = "",
         .params     = "",
         .help       = "show the block devices",
-        .user_print = bdrv_info_print,
-        .mhandler.info_new = bdrv_info,
+        .mhandler.info = hmp_info_block,
     },
     {
         .name       = "blockstats",
         .args_type  = "",
         .params     = "",
         .help       = "show block device statistics",
-        .user_print = bdrv_stats_print,
-        .mhandler.info_new = bdrv_info_stats,
+        .mhandler.info = hmp_info_blockstats,
     },
     {
         .name       = "registers",
@@ -2872,8 +2646,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show infos for each CPU",
-        .user_print = monitor_print_cpus,
-        .mhandler.info_new = do_info_cpus,
+        .mhandler.info = hmp_info_cpus,
     },
     {
         .name       = "history",
@@ -2882,29 +2655,44 @@ static const mon_cmd_t info_cmds[] = {
         .help       = "show the command line history",
         .mhandler.info = do_info_history,
     },
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \
+    defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64))
     {
         .name       = "irq",
         .args_type  = "",
         .params     = "",
         .help       = "show the interrupts statistics (if available)",
+#ifdef TARGET_SPARC
+        .mhandler.info = sun4m_irq_info,
+#elif defined(TARGET_LM32)
+        .mhandler.info = lm32_irq_info,
+#else
         .mhandler.info = irq_info,
+#endif
     },
     {
         .name       = "pic",
         .args_type  = "",
         .params     = "",
         .help       = "show i8259 (PIC) state",
+#ifdef TARGET_SPARC
+        .mhandler.info = sun4m_pic_info,
+#elif defined(TARGET_LM32)
+        .mhandler.info = lm32_do_pic_info,
+#else
         .mhandler.info = pic_info,
+#endif
     },
+#endif
     {
         .name       = "pci",
         .args_type  = "",
         .params     = "",
         .help       = "show PCI info",
-        .user_print = do_pci_info_print,
-        .mhandler.info_new = do_pci_info,
+        .mhandler.info = hmp_info_pci,
     },
-#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC)
+#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
+    defined(TARGET_PPC)
     {
         .name       = "tlb",
         .args_type  = "",
@@ -2922,6 +2710,13 @@ static const mon_cmd_t info_cmds[] = {
         .mhandler.info = mem_info,
     },
 #endif
+    {
+        .name       = "mtree",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show memory tree",
+        .mhandler.info = do_info_mtree,
+    },
     {
         .name       = "jit",
         .args_type  = "",
@@ -2934,8 +2729,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show KVM information",
-        .user_print = do_info_kvm_print,
-        .mhandler.info_new = do_info_kvm,
+        .mhandler.info = hmp_info_kvm,
     },
     {
         .name       = "numa",
@@ -2984,8 +2778,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM status (running|paused)",
-        .user_print = do_info_status_print,
-        .mhandler.info_new = do_info_status,
+        .mhandler.info = hmp_info_status,
     },
     {
         .name       = "pcmcia",
@@ -2999,16 +2792,14 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show which guest mouse is receiving events",
-        .user_print = do_info_mice_print,
-        .mhandler.info_new = do_info_mice,
+        .mhandler.info = hmp_info_mice,
     },
     {
         .name       = "vnc",
         .args_type  = "",
         .params     = "",
         .help       = "show the vnc server status",
-        .user_print = do_info_vnc_print,
-        .mhandler.info_new = do_info_vnc,
+        .mhandler.info = hmp_info_vnc,
     },
 #if defined(CONFIG_SPICE)
     {
@@ -3016,8 +2807,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the spice server status",
-        .user_print = do_info_spice_print,
-        .mhandler.info_new = do_info_spice,
+        .mhandler.info = hmp_info_spice,
     },
 #endif
     {
@@ -3025,16 +2815,14 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM name",
-        .user_print = do_info_name_print,
-        .mhandler.info_new = do_info_name,
+        .mhandler.info = hmp_info_name,
     },
     {
         .name       = "uuid",
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM UUID",
-        .user_print = do_info_uuid_print,
-        .mhandler.info_new = do_info_uuid,
+        .mhandler.info = hmp_info_uuid,
     },
 #if defined(TARGET_PPC)
     {
@@ -3059,17 +2847,14 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show migration status",
-        .user_print = do_info_migrate_print,
-        .mhandler.info_new = do_info_migrate,
+        .mhandler.info = hmp_info_migrate,
     },
     {
         .name       = "balloon",
         .args_type  = "",
         .params     = "",
         .help       = "show balloon information",
-        .user_print = monitor_print_balloon,
-        .mhandler.info_async = do_info_balloon,
-        .flags      = MONITOR_CMD_ASYNC,
+        .mhandler.info = hmp_info_balloon,
     },
     {
         .name       = "qtree",
@@ -3092,7 +2877,7 @@ static const mon_cmd_t info_cmds[] = {
         .help       = "show roms",
         .mhandler.info = do_info_roms,
     },
-#if defined(CONFIG_SIMPLE_TRACE)
+#if defined(CONFIG_TRACE_SIMPLE)
     {
         .name       = "trace",
         .args_type  = "",
@@ -3100,156 +2885,21 @@ static const mon_cmd_t info_cmds[] = {
         .help       = "show current contents of trace buffer",
         .mhandler.info = do_info_trace,
     },
+#endif
     {
         .name       = "trace-events",
         .args_type  = "",
         .params     = "",
         .help       = "show available trace-events & their state",
-        .mhandler.info = do_info_trace_events,
+        .mhandler.info = do_trace_print_events,
     },
-#endif
     {
         .name       = NULL,
     },
 };
 
 static const mon_cmd_t qmp_cmds[] = {
-#include "qmp-commands.h"
-    { /* NULL */ },
-};
-
-static const mon_cmd_t qmp_query_cmds[] = {
-    {
-        .name       = "version",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the version of QEMU",
-        .user_print = do_info_version_print,
-        .mhandler.info_new = do_info_version,
-    },
-    {
-        .name       = "commands",
-        .args_type  = "",
-        .params     = "",
-        .help       = "list QMP available commands",
-        .user_print = monitor_user_noop,
-        .mhandler.info_new = do_info_commands,
-    },
-    {
-        .name       = "chardev",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the character devices",
-        .user_print = qemu_chr_info_print,
-        .mhandler.info_new = qemu_chr_info,
-    },
-    {
-        .name       = "block",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the block devices",
-        .user_print = bdrv_info_print,
-        .mhandler.info_new = bdrv_info,
-    },
-    {
-        .name       = "blockstats",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show block device statistics",
-        .user_print = bdrv_stats_print,
-        .mhandler.info_new = bdrv_info_stats,
-    },
-    {
-        .name       = "cpus",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show infos for each CPU",
-        .user_print = monitor_print_cpus,
-        .mhandler.info_new = do_info_cpus,
-    },
-    {
-        .name       = "pci",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show PCI info",
-        .user_print = do_pci_info_print,
-        .mhandler.info_new = do_pci_info,
-    },
-    {
-        .name       = "kvm",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show KVM information",
-        .user_print = do_info_kvm_print,
-        .mhandler.info_new = do_info_kvm,
-    },
-    {
-        .name       = "status",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM status (running|paused)",
-        .user_print = do_info_status_print,
-        .mhandler.info_new = do_info_status,
-    },
-    {
-        .name       = "mice",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show which guest mouse is receiving events",
-        .user_print = do_info_mice_print,
-        .mhandler.info_new = do_info_mice,
-    },
-    {
-        .name       = "vnc",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the vnc server status",
-        .user_print = do_info_vnc_print,
-        .mhandler.info_new = do_info_vnc,
-    },
-#if defined(CONFIG_SPICE)
-    {
-        .name       = "spice",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the spice server status",
-        .user_print = do_info_spice_print,
-        .mhandler.info_new = do_info_spice,
-    },
-#endif
-    {
-        .name       = "name",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM name",
-        .user_print = do_info_name_print,
-        .mhandler.info_new = do_info_name,
-    },
-    {
-        .name       = "uuid",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM UUID",
-        .user_print = do_info_uuid_print,
-        .mhandler.info_new = do_info_uuid,
-    },
-    {
-        .name       = "migrate",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show migration status",
-        .user_print = do_info_migrate_print,
-        .mhandler.info_new = do_info_migrate,
-    },
-    {
-        .name       = "balloon",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show balloon information",
-        .user_print = monitor_print_balloon,
-        .mhandler.info_async = do_info_balloon,
-        .flags      = MONITOR_CMD_ASYNC,
-    },
+#include "qmp-commands-old.h"
     { /* NULL */ },
 };
 
@@ -3457,7 +3107,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]) },
@@ -3474,7 +3124,76 @@ static const MonitorDef monitor_defs[] = {
     { "sr13", offsetof(CPUState, sr[13]) },
     { "sr14", offsetof(CPUState, sr[14]) },
     { "sr15", offsetof(CPUState, sr[15]) },
-    /* Too lazy to put BATs and SPRs ... */
+    /* Too lazy to put BATs... */
+    { "pvr", offsetof(CPUState, spr[SPR_PVR]) },
+
+    { "srr0", offsetof(CPUState, spr[SPR_SRR0]) },
+    { "srr1", offsetof(CPUState, spr[SPR_SRR1]) },
+    { "sprg0", offsetof(CPUState, spr[SPR_SPRG0]) },
+    { "sprg1", offsetof(CPUState, spr[SPR_SPRG1]) },
+    { "sprg2", offsetof(CPUState, spr[SPR_SPRG2]) },
+    { "sprg3", offsetof(CPUState, spr[SPR_SPRG3]) },
+    { "sprg4", offsetof(CPUState, spr[SPR_SPRG4]) },
+    { "sprg5", offsetof(CPUState, spr[SPR_SPRG5]) },
+    { "sprg6", offsetof(CPUState, spr[SPR_SPRG6]) },
+    { "sprg7", offsetof(CPUState, spr[SPR_SPRG7]) },
+    { "pid", offsetof(CPUState, spr[SPR_BOOKE_PID]) },
+    { "csrr0", offsetof(CPUState, spr[SPR_BOOKE_CSRR0]) },
+    { "csrr1", offsetof(CPUState, spr[SPR_BOOKE_CSRR1]) },
+    { "esr", offsetof(CPUState, spr[SPR_BOOKE_ESR]) },
+    { "dear", offsetof(CPUState, spr[SPR_BOOKE_DEAR]) },
+    { "mcsr", offsetof(CPUState, spr[SPR_BOOKE_MCSR]) },
+    { "tsr", offsetof(CPUState, spr[SPR_BOOKE_TSR]) },
+    { "tcr", offsetof(CPUState, spr[SPR_BOOKE_TCR]) },
+    { "vrsave", offsetof(CPUState, spr[SPR_VRSAVE]) },
+    { "pir", offsetof(CPUState, spr[SPR_BOOKE_PIR]) },
+    { "mcsrr0", offsetof(CPUState, spr[SPR_BOOKE_MCSRR0]) },
+    { "mcsrr1", offsetof(CPUState, spr[SPR_BOOKE_MCSRR1]) },
+    { "decar", offsetof(CPUState, spr[SPR_BOOKE_DECAR]) },
+    { "ivpr", offsetof(CPUState, spr[SPR_BOOKE_IVPR]) },
+    { "epcr", offsetof(CPUState, spr[SPR_BOOKE_EPCR]) },
+    { "sprg8", offsetof(CPUState, spr[SPR_BOOKE_SPRG8]) },
+    { "ivor0", offsetof(CPUState, spr[SPR_BOOKE_IVOR0]) },
+    { "ivor1", offsetof(CPUState, spr[SPR_BOOKE_IVOR1]) },
+    { "ivor2", offsetof(CPUState, spr[SPR_BOOKE_IVOR2]) },
+    { "ivor3", offsetof(CPUState, spr[SPR_BOOKE_IVOR3]) },
+    { "ivor4", offsetof(CPUState, spr[SPR_BOOKE_IVOR4]) },
+    { "ivor5", offsetof(CPUState, spr[SPR_BOOKE_IVOR5]) },
+    { "ivor6", offsetof(CPUState, spr[SPR_BOOKE_IVOR6]) },
+    { "ivor7", offsetof(CPUState, spr[SPR_BOOKE_IVOR7]) },
+    { "ivor8", offsetof(CPUState, spr[SPR_BOOKE_IVOR8]) },
+    { "ivor9", offsetof(CPUState, spr[SPR_BOOKE_IVOR9]) },
+    { "ivor10", offsetof(CPUState, spr[SPR_BOOKE_IVOR10]) },
+    { "ivor11", offsetof(CPUState, spr[SPR_BOOKE_IVOR11]) },
+    { "ivor12", offsetof(CPUState, spr[SPR_BOOKE_IVOR12]) },
+    { "ivor13", offsetof(CPUState, spr[SPR_BOOKE_IVOR13]) },
+    { "ivor14", offsetof(CPUState, spr[SPR_BOOKE_IVOR14]) },
+    { "ivor15", offsetof(CPUState, spr[SPR_BOOKE_IVOR15]) },
+    { "ivor32", offsetof(CPUState, spr[SPR_BOOKE_IVOR32]) },
+    { "ivor33", offsetof(CPUState, spr[SPR_BOOKE_IVOR33]) },
+    { "ivor34", offsetof(CPUState, spr[SPR_BOOKE_IVOR34]) },
+    { "ivor35", offsetof(CPUState, spr[SPR_BOOKE_IVOR35]) },
+    { "ivor36", offsetof(CPUState, spr[SPR_BOOKE_IVOR36]) },
+    { "ivor37", offsetof(CPUState, spr[SPR_BOOKE_IVOR37]) },
+    { "mas0", offsetof(CPUState, spr[SPR_BOOKE_MAS0]) },
+    { "mas1", offsetof(CPUState, spr[SPR_BOOKE_MAS1]) },
+    { "mas2", offsetof(CPUState, spr[SPR_BOOKE_MAS2]) },
+    { "mas3", offsetof(CPUState, spr[SPR_BOOKE_MAS3]) },
+    { "mas4", offsetof(CPUState, spr[SPR_BOOKE_MAS4]) },
+    { "mas6", offsetof(CPUState, spr[SPR_BOOKE_MAS6]) },
+    { "mas7", offsetof(CPUState, spr[SPR_BOOKE_MAS7]) },
+    { "mmucfg", offsetof(CPUState, spr[SPR_MMUCFG]) },
+    { "tlb0cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB0CFG]) },
+    { "tlb1cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB1CFG]) },
+    { "epr", offsetof(CPUState, spr[SPR_BOOKE_EPR]) },
+    { "eplc", offsetof(CPUState, spr[SPR_BOOKE_EPLC]) },
+    { "epsc", offsetof(CPUState, spr[SPR_BOOKE_EPSC]) },
+    { "svr", offsetof(CPUState, spr[SPR_E500_SVR]) },
+    { "mcar", offsetof(CPUState, spr[SPR_Exxx_MCAR]) },
+    { "pid1", offsetof(CPUState, spr[SPR_BOOKE_PID1]) },
+    { "pid2", offsetof(CPUState, spr[SPR_BOOKE_PID2]) },
+    { "hid0", offsetof(CPUState, spr[SPR_HID0]) },
+
 #elif defined(TARGET_SPARC)
     { "g0", offsetof(CPUState, gregs[0]) },
     { "g1", offsetof(CPUState, gregs[1]) },
@@ -3517,55 +3236,55 @@ static const MonitorDef monitor_defs[] = {
 #endif
     { "tbr", offsetof(CPUState, tbr) },
     { "fsr", offsetof(CPUState, fsr) },
-    { "f0", offsetof(CPUState, fpr[0]) },
-    { "f1", offsetof(CPUState, fpr[1]) },
-    { "f2", offsetof(CPUState, fpr[2]) },
-    { "f3", offsetof(CPUState, fpr[3]) },
-    { "f4", offsetof(CPUState, fpr[4]) },
-    { "f5", offsetof(CPUState, fpr[5]) },
-    { "f6", offsetof(CPUState, fpr[6]) },
-    { "f7", offsetof(CPUState, fpr[7]) },
-    { "f8", offsetof(CPUState, fpr[8]) },
-    { "f9", offsetof(CPUState, fpr[9]) },
-    { "f10", offsetof(CPUState, fpr[10]) },
-    { "f11", offsetof(CPUState, fpr[11]) },
-    { "f12", offsetof(CPUState, fpr[12]) },
-    { "f13", offsetof(CPUState, fpr[13]) },
-    { "f14", offsetof(CPUState, fpr[14]) },
-    { "f15", offsetof(CPUState, fpr[15]) },
-    { "f16", offsetof(CPUState, fpr[16]) },
-    { "f17", offsetof(CPUState, fpr[17]) },
-    { "f18", offsetof(CPUState, fpr[18]) },
-    { "f19", offsetof(CPUState, fpr[19]) },
-    { "f20", offsetof(CPUState, fpr[20]) },
-    { "f21", offsetof(CPUState, fpr[21]) },
-    { "f22", offsetof(CPUState, fpr[22]) },
-    { "f23", offsetof(CPUState, fpr[23]) },
-    { "f24", offsetof(CPUState, fpr[24]) },
-    { "f25", offsetof(CPUState, fpr[25]) },
-    { "f26", offsetof(CPUState, fpr[26]) },
-    { "f27", offsetof(CPUState, fpr[27]) },
-    { "f28", offsetof(CPUState, fpr[28]) },
-    { "f29", offsetof(CPUState, fpr[29]) },
-    { "f30", offsetof(CPUState, fpr[30]) },
-    { "f31", offsetof(CPUState, fpr[31]) },
+    { "f0", offsetof(CPUState, fpr[0].l.upper) },
+    { "f1", offsetof(CPUState, fpr[0].l.lower) },
+    { "f2", offsetof(CPUState, fpr[1].l.upper) },
+    { "f3", offsetof(CPUState, fpr[1].l.lower) },
+    { "f4", offsetof(CPUState, fpr[2].l.upper) },
+    { "f5", offsetof(CPUState, fpr[2].l.lower) },
+    { "f6", offsetof(CPUState, fpr[3].l.upper) },
+    { "f7", offsetof(CPUState, fpr[3].l.lower) },
+    { "f8", offsetof(CPUState, fpr[4].l.upper) },
+    { "f9", offsetof(CPUState, fpr[4].l.lower) },
+    { "f10", offsetof(CPUState, fpr[5].l.upper) },
+    { "f11", offsetof(CPUState, fpr[5].l.lower) },
+    { "f12", offsetof(CPUState, fpr[6].l.upper) },
+    { "f13", offsetof(CPUState, fpr[6].l.lower) },
+    { "f14", offsetof(CPUState, fpr[7].l.upper) },
+    { "f15", offsetof(CPUState, fpr[7].l.lower) },
+    { "f16", offsetof(CPUState, fpr[8].l.upper) },
+    { "f17", offsetof(CPUState, fpr[8].l.lower) },
+    { "f18", offsetof(CPUState, fpr[9].l.upper) },
+    { "f19", offsetof(CPUState, fpr[9].l.lower) },
+    { "f20", offsetof(CPUState, fpr[10].l.upper) },
+    { "f21", offsetof(CPUState, fpr[10].l.lower) },
+    { "f22", offsetof(CPUState, fpr[11].l.upper) },
+    { "f23", offsetof(CPUState, fpr[11].l.lower) },
+    { "f24", offsetof(CPUState, fpr[12].l.upper) },
+    { "f25", offsetof(CPUState, fpr[12].l.lower) },
+    { "f26", offsetof(CPUState, fpr[13].l.upper) },
+    { "f27", offsetof(CPUState, fpr[13].l.lower) },
+    { "f28", offsetof(CPUState, fpr[14].l.upper) },
+    { "f29", offsetof(CPUState, fpr[14].l.lower) },
+    { "f30", offsetof(CPUState, fpr[15].l.upper) },
+    { "f31", offsetof(CPUState, fpr[15].l.lower) },
 #ifdef TARGET_SPARC64
-    { "f32", offsetof(CPUState, fpr[32]) },
-    { "f34", offsetof(CPUState, fpr[34]) },
-    { "f36", offsetof(CPUState, fpr[36]) },
-    { "f38", offsetof(CPUState, fpr[38]) },
-    { "f40", offsetof(CPUState, fpr[40]) },
-    { "f42", offsetof(CPUState, fpr[42]) },
-    { "f44", offsetof(CPUState, fpr[44]) },
-    { "f46", offsetof(CPUState, fpr[46]) },
-    { "f48", offsetof(CPUState, fpr[48]) },
-    { "f50", offsetof(CPUState, fpr[50]) },
-    { "f52", offsetof(CPUState, fpr[52]) },
-    { "f54", offsetof(CPUState, fpr[54]) },
-    { "f56", offsetof(CPUState, fpr[56]) },
-    { "f58", offsetof(CPUState, fpr[58]) },
-    { "f60", offsetof(CPUState, fpr[60]) },
-    { "f62", offsetof(CPUState, fpr[62]) },
+    { "f32", offsetof(CPUState, fpr[16]) },
+    { "f34", offsetof(CPUState, fpr[17]) },
+    { "f36", offsetof(CPUState, fpr[18]) },
+    { "f38", offsetof(CPUState, fpr[19]) },
+    { "f40", offsetof(CPUState, fpr[20]) },
+    { "f42", offsetof(CPUState, fpr[21]) },
+    { "f44", offsetof(CPUState, fpr[22]) },
+    { "f46", offsetof(CPUState, fpr[23]) },
+    { "f48", offsetof(CPUState, fpr[24]) },
+    { "f50", offsetof(CPUState, fpr[25]) },
+    { "f52", offsetof(CPUState, fpr[26]) },
+    { "f54", offsetof(CPUState, fpr[27]) },
+    { "f56", offsetof(CPUState, fpr[28]) },
+    { "f58", offsetof(CPUState, fpr[29]) },
+    { "f60", offsetof(CPUState, fpr[30]) },
+    { "f62", offsetof(CPUState, fpr[31]) },
     { "asi", offsetof(CPUState, asi) },
     { "pstate", offsetof(CPUState, pstate) },
     { "cansave", offsetof(CPUState, cansave) },
@@ -3934,7 +3653,7 @@ static char *key_get_info(const char *type, char **key)
     }
     len = p - type;
 
-    str = qemu_malloc(len + 1);
+    str = g_malloc(len + 1);
     memcpy(str, type, len);
     str[len] = '\0';
 
@@ -3978,11 +3697,6 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname)
     return search_dispatch_table(mon_cmds, cmdname);
 }
 
-static const mon_cmd_t *qmp_find_query_cmd(const char *info_item)
-{
-    return search_dispatch_table(qmp_query_cmds, info_item);
-}
-
 static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
 {
     return search_dispatch_table(qmp_cmds, cmdname);
@@ -4317,7 +4031,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
             monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
             goto fail;
         }
-        qemu_free(key);
+        g_free(key);
         key = NULL;
     }
     /* check that all arguments were parsed */
@@ -4332,7 +4046,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
     return cmd;
 
 fail:
-    qemu_free(key);
+    g_free(key);
     return NULL;
 }
 
@@ -4493,9 +4207,9 @@ static void file_completion(const char *input)
             /* stat the file to find out if it's a directory.
              * In that case add a slash to speed up typing long paths
              */
-            stat(file, &sb);
-            if(S_ISDIR(sb.st_mode))
+            if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) {
                 pstrcat(file, sizeof(file), "/");
+            }
             readline_add_completion(cur_mon->rs, file);
         }
     }
@@ -4531,7 +4245,7 @@ static void parse_cmdline(const char *cmdline,
         if (nb_args >= MAX_ARGS)
             break;
         ret = get_str(buf, sizeof(buf), &p);
-        args[nb_args] = qemu_strdup(buf);
+        args[nb_args] = g_strdup(buf);
         nb_args++;
         if (ret < 0)
             break;
@@ -4568,7 +4282,7 @@ static void monitor_find_completion(const char *cmdline)
         if (nb_args >= MAX_ARGS) {
             goto cleanup;
         }
-        args[nb_args++] = qemu_strdup("");
+        args[nb_args++] = g_strdup("");
     }
     if (nb_args <= 1) {
         /* command completion */
@@ -4643,7 +4357,7 @@ static void monitor_find_completion(const char *cmdline)
 
 cleanup:
     for (i = 0; i < nb_args; i++) {
-        qemu_free(args[i]);
+        g_free(args[i]);
     }
 }
 
@@ -4906,22 +4620,6 @@ static QDict *qmp_check_input_obj(QObject *input_obj)
     return input_dict;
 }
 
-static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
-{
-    QObject *ret_data = NULL;
-
-    if (handler_is_async(cmd)) {
-        qmp_async_info_handler(mon, cmd);
-        if (monitor_has_error(mon)) {
-            monitor_protocol_emitter(mon, NULL);
-        }
-    } else {
-        cmd->mhandler.info_new(mon, &ret_data);
-        monitor_protocol_emitter(mon, ret_data);
-        qobject_decref(ret_data);
-    }
-}
-
 static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
                          const QDict *params)
 {
@@ -4942,10 +4640,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
     QObject *obj;
     QDict *input, *args;
     const mon_cmd_t *cmd;
+    const char *cmd_name;
     Monitor *mon = cur_mon;
-    const char *cmd_name, *query_cmd;
 
-    query_cmd = NULL;
     args = input = NULL;
 
     obj = json_parser_parse(tokens, NULL);
@@ -4965,17 +4662,13 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
     qobject_incref(mon->mc->id);
 
     cmd_name = qdict_get_str(input, "execute");
+    trace_handle_qmp_command(mon, cmd_name);
     if (invalid_qmp_mode(mon, cmd_name)) {
         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_out;
     }
 
-    if (strstart(cmd_name, "query-", &query_cmd)) {
-        cmd = qmp_find_query_cmd(query_cmd);
-    } else {
-        cmd = qmp_find_cmd(cmd_name);
-    }
-
+    cmd = qmp_find_cmd(cmd_name);
     if (!cmd) {
         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_out;
@@ -4994,9 +4687,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
         goto err_out;
     }
 
-    if (query_cmd) {
-        qmp_call_query_cmd(mon, cmd);
-    } else if (handler_is_async(cmd)) {
+    if (handler_is_async(cmd)) {
         err = qmp_async_cmd_handler(mon, cmd, args);
         if (err) {
             /* emit the error response */
@@ -5074,9 +4765,9 @@ void monitor_resume(Monitor *mon)
 
 static QObject *get_qmp_greeting(void)
 {
-    QObject *ver;
+    QObject *ver = NULL;
 
-    do_info_version(NULL, &ver);
+    qmp_marshal_input_query_version(NULL, NULL, &ver);
     return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
 }
 
@@ -5142,6 +4833,25 @@ static void monitor_event(void *opaque, int event)
     }
 }
 
+static int
+compare_mon_cmd(const void *a, const void *b)
+{
+    return strcmp(((const mon_cmd_t *)a)->name,
+            ((const mon_cmd_t *)b)->name);
+}
+
+static void sortcmdlist(void)
+{
+    int array_num;
+    int elem_size = sizeof(mon_cmd_t);
+
+    array_num = sizeof(mon_cmds)/elem_size-1;
+    qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd);
+
+    array_num = sizeof(info_cmds)/elem_size-1;
+    qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
+}
+
 
 /*
  * Local variables:
@@ -5157,11 +4867,11 @@ void monitor_init(CharDriverState *chr, int flags)
     Monitor *mon;
 
     if (is_first_init) {
-        key_timer = qemu_new_timer(vm_clock, release_keys, NULL);
+        key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
         is_first_init = 0;
     }
 
-    mon = qemu_mallocz(sizeof(*mon));
+    mon = g_malloc0(sizeof(*mon));
 
     mon->chr = chr;
     mon->flags = flags;
@@ -5171,11 +4881,11 @@ void monitor_init(CharDriverState *chr, int flags)
     }
 
     if (monitor_ctrl_mode(mon)) {
-        mon->mc = qemu_mallocz(sizeof(MonitorControl));
+        mon->mc = g_malloc0(sizeof(MonitorControl));
         /* Control mode requires special handlers */
         qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
                               monitor_control_event, mon);
-        qemu_chr_set_echo(chr, true);
+        qemu_chr_fe_set_echo(chr, true);
     } else {
         qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
                               monitor_event, mon);
@@ -5184,6 +4894,8 @@ void monitor_init(CharDriverState *chr, int flags)
     QLIST_INSERT_HEAD(&mon_list, mon, entry);
     if (!default_mon || (flags & MONITOR_IS_DEFAULT))
         default_mon = mon;
+
+    sortcmdlist();
 }
 
 static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
index 4f2d328db56808c677b8d1c690fa594c7075a2bc..e76795f1f3ef3a90b61b9f46b7b83231edc67626 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -57,6 +57,8 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void monitor_print_filename(Monitor *mon, const char *filename);
 void monitor_flush(Monitor *mon);
+int monitor_set_cpu(int cpu_index);
+int monitor_get_cpu_index(void);
 
 typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
 
diff --git a/nbd.c b/nbd.c
index d8ebc4298fc0f5bd85b7ea1ff7eafd1cdb723af8..e6c931c5ceed95387dd7455bfb2110a23a96caf7 100644 (file)
--- a/nbd.c
+++ b/nbd.c
@@ -17,6 +17,7 @@
  */
 
 #include "nbd.h"
+#include "block.h"
 
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
 #include <inttypes.h>
 
+#ifdef __linux__
+#include <linux/fs.h>
+#endif
+
 #include "qemu_socket.h"
 
 //#define DEBUG_NBD
@@ -49,7 +54,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_SET_TIMEOUT         _IO(0xab, 9)
+#define NBD_SET_FLAGS           _IO(0xab, 10)
 
-#define NBD_OPT_EXPORT_NAME    (1 << 0)
+#define NBD_OPT_EXPORT_NAME     (1 << 0)
 
 /* That's all folks */
 
@@ -78,7 +85,7 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
         ssize_t len;
 
         if (do_read) {
-            len = recv(fd, buffer + offset, size - offset, 0);
+            len = qemu_recv(fd, buffer + offset, size - offset, 0);
         } else {
             len = send(fd, buffer + offset, size - offset, 0);
         }
@@ -107,155 +114,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));
+    /* 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);
     }
-
-    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;
-    }
-
-    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
 
@@ -271,246 +178,275 @@ int unix_socket_outgoing(const char *path)
                   Request (type == 2)
 */
 
-int nbd_negotiate(int csock, off_t size)
+int nbd_negotiate(int csock, off_t size, uint32_t flags)
 {
-       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 ..  27]   flags
+        [28 .. 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);
+    cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS);
+    memset(buf + 28, 0, 124);
+
+    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)
+#ifdef __linux__
+int nbd_init(int fd, int csock, uint32_t flags, 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");
+    if (flags & NBD_FLAG_READ_ONLY) {
+        int read_only = 1;
+        TRACE("Setting readonly attribute");
 
-       if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
-               int serrno = errno;
-               LOG("Failed clearing NBD socket");
-               errno = serrno;
-               return -1;
-       }
+        if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
+            int serrno = errno;
+            LOG("Failed setting read-only attribute");
+            errno = serrno;
+            return -1;
+        }
+    }
 
-       TRACE("Setting NBD socket");
+    if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
+        && errno != ENOTTY) {
+        int serrno = errno;
+        LOG("Failed setting flags");
+        errno = serrno;
+        return -1;
+    }
+
+    TRACE("Clearing 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_CLEAR_SOCK) == -1) {
+        int serrno = errno;
+        LOG("Failed clearing NBD socket");
+        errno = serrno;
+        return -1;
+    }
 
-       TRACE("Negotiation ended");
+    TRACE("Setting NBD socket");
 
-       return 0;
+    if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+        int serrno = errno;
+        LOG("Failed to set NBD socket");
+        errno = serrno;
+        return -1;
+    }
+
+    TRACE("Negotiation ended");
+
+    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;
-
-       TRACE("Doing NBD loop");
-
-       ret = ioctl(fd, NBD_DO_IT);
-       serrno = errno;
+    int ret;
+    int serrno;
+
+    TRACE("Doing NBD loop");
+
+    ret = ioctl(fd, NBD_DO_IT);
+    if (ret == -1 && errno == EPIPE) {
+        /* NBD_DO_IT normally returns EPIPE when someone has disconnected
+         * the socket via NBD_DISCONNECT.  We do not want to return 1 in
+         * that case.
+         */
+        ret = 0;
+    }
+    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)
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     errno = ENOTSUP;
     return -1;
@@ -531,235 +467,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)
+             off_t *offset, uint32_t nbdflags, 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 (nbdflags & NBD_FLAG_READ_ONLY) {
+            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..61553f41280f572aebbd70bd5c3540426d3f00a0 100644 (file)
--- a/nbd.h
+++ b/nbd.h
 
 #include <sys/types.h>
 
-#include <qemu-common.h>
-#include "block_int.h"
+#include "qemu-common.h"
 
 struct nbd_request {
+    uint32_t magic;
     uint32_t type;
     uint64_t handle;
     uint64_t from;
     uint32_t len;
-};
+} QEMU_PACKED;
 
 struct nbd_reply {
+    uint32_t magic;
     uint32_t error;
     uint64_t handle;
-};
+} QEMU_PACKED;
+
+#define NBD_FLAG_HAS_FLAGS      (1 << 0)        /* Flags are there */
+#define NBD_FLAG_READ_ONLY      (1 << 1)        /* Device is read-only */
+#define NBD_FLAG_SEND_FLUSH     (1 << 2)        /* Send FLUSH */
+#define NBD_FLAG_SEND_FUA       (1 << 3)        /* Send FUA (Force Unit Access) */
+#define NBD_FLAG_ROTATIONAL     (1 << 4)        /* Use elevator algorithm - rotational media */
+#define NBD_FLAG_SEND_TRIM      (1 << 5)        /* Send TRIM (discard) */
+
+#define NBD_CMD_MASK_COMMAND   0x0000ffff
+#define NBD_CMD_FLAG_FUA       (1 << 16)
 
 enum {
     NBD_CMD_READ = 0,
     NBD_CMD_WRITE = 1,
-    NBD_CMD_DISC = 2
+    NBD_CMD_DISC = 2,
+    NBD_CMD_FLUSH = 3,
+    NBD_CMD_TRIM = 4
 };
 
 #define NBD_DEFAULT_PORT       10809
@@ -47,17 +60,19 @@ 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);
 
-int nbd_negotiate(int csock, off_t size);
+int nbd_negotiate(int csock, off_t size, uint32_t flags);
 int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
                           off_t *size, size_t *blocksize);
-int nbd_init(int fd, int csock, off_t size, size_t blocksize);
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
 int nbd_send_request(int csock, struct nbd_request *request);
 int nbd_receive_reply(int csock, struct nbd_reply *reply);
 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);
+             off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size);
 int nbd_client(int fd);
 int nbd_disconnect(int fd);
 
diff --git a/net.c b/net.c
index 21d44432eb30fe3d81ba9e31cb89e9de1b18375a..cb52050bfd3f261798ca6fec80e7d09f2f350e4e 100644 (file)
--- a/net.c
+++ b/net.c
 #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"
+#include "iov.h"
 
 static QTAILQ_HEAD(, VLANState) vlans;
 static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
@@ -93,47 +93,6 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
     return 0;
 }
 
-int parse_host_src_port(struct sockaddr_in *haddr,
-                        struct sockaddr_in *saddr,
-                        const char *input_str)
-{
-    char *str = qemu_strdup(input_str);
-    char *host_str = str;
-    char *src_str;
-    const char *src_str2;
-    char *ptr;
-
-    /*
-     * Chop off any extra arguments at the end of the string which
-     * would start with a comma, then fill in the src port information
-     * if it was provided else use the "any address" and "any port".
-     */
-    if ((ptr = strchr(str,',')))
-        *ptr = '\0';
-
-    if ((src_str = strchr(input_str,'@'))) {
-        *src_str = '\0';
-        src_str++;
-    }
-
-    if (parse_host_port(haddr, host_str) < 0)
-        goto fail;
-
-    src_str2 = src_str;
-    if (!src_str || *src_str == '\0')
-        src_str2 = ":0";
-
-    if (parse_host_port(saddr, src_str2) < 0)
-        goto fail;
-
-    free(str);
-    return(0);
-
-fail:
-    free(str);
-    return -1;
-}
-
 int parse_host_port(struct sockaddr_in *saddr, const char *str)
 {
     char buf[512];
@@ -191,12 +150,11 @@ void qemu_macaddr_default_if_unset(MACAddr *macaddr)
 static char *assign_name(VLANClientState *vc1, const char *model)
 {
     VLANState *vlan;
+    VLANClientState *vc;
     char buf[256];
     int id = 0;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        VLANClientState *vc;
-
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
             if (vc != vc1 && strcmp(vc->model, model) == 0) {
                 id++;
@@ -204,9 +162,15 @@ static char *assign_name(VLANClientState *vc1, const char *model)
         }
     }
 
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc != vc1 && strcmp(vc->model, model) == 0) {
+            id++;
+        }
+    }
+
     snprintf(buf, sizeof(buf), "%s.%d", model, id);
 
-    return qemu_strdup(buf);
+    return g_strdup(buf);
 }
 
 static ssize_t qemu_deliver_packet(VLANClientState *sender,
@@ -230,12 +194,12 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info,
 
     assert(info->size >= sizeof(VLANClientState));
 
-    vc = qemu_mallocz(info->size);
+    vc = g_malloc0(info->size);
 
     vc->info = info;
-    vc->model = qemu_strdup(model);
+    vc->model = g_strdup(model);
     if (name) {
-        vc->name = qemu_strdup(name);
+        vc->name = g_strdup(name);
     } else {
         vc->name = assign_name(vc, model);
     }
@@ -304,9 +268,9 @@ static void qemu_free_vlan_client(VLANClientState *vc)
             vc->peer->peer = NULL;
         }
     }
-    qemu_free(vc->name);
-    qemu_free(vc->model);
-    qemu_free(vc);
+    g_free(vc->name);
+    g_free(vc->model);
+    g_free(vc);
 }
 
 void qemu_del_vlan_client(VLANClientState *vc)
@@ -411,11 +375,11 @@ int qemu_can_send_packet(VLANClientState *sender)
         }
 
         /* no can_receive() handler, they can always receive */
-        if (!vc->info->can_receive || vc->info->can_receive(vc)) {
-            return 1;
+        if (vc->info->can_receive && !vc->info->can_receive(vc)) {
+            return 0;
         }
     }
-    return 0;
+    return 1;
 }
 
 static ssize_t qemu_deliver_packet(VLANClientState *sender,
@@ -572,30 +536,13 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
                                int iovcnt)
 {
     uint8_t buffer[4096];
-    size_t offset = 0;
-    int i;
-
-    for (i = 0; i < iovcnt; i++) {
-        size_t len;
+    size_t offset;
 
-        len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
-        memcpy(buffer + offset, iov[i].iov_base, len);
-        offset += len;
-    }
+    offset = iov_to_buf(iov, iovcnt, buffer, 0, sizeof(buffer));
 
     return vc->info->receive(vc, buffer, offset);
 }
 
-static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
-{
-    size_t offset = 0;
-    int i;
-
-    for (i = 0; i < iovcnt; i++)
-        offset += iov[i].iov_len;
-    return offset;
-}
-
 static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
                                        unsigned flags,
                                        const struct iovec *iov,
@@ -605,7 +552,7 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
     VLANClientState *vc = opaque;
 
     if (vc->link_down) {
-        return calc_iov_length(iov, iovcnt);
+        return iov_size(iov, iovcnt);
     }
 
     if (vc->info->receive_iov) {
@@ -633,7 +580,7 @@ static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState *sender,
         }
 
         if (vc->link_down) {
-            ret = calc_iov_length(iov, iovcnt);
+            ret = iov_size(iov, iovcnt);
             continue;
         }
 
@@ -658,7 +605,7 @@ ssize_t qemu_sendv_packet_async(VLANClientState *sender,
     NetQueue *queue;
 
     if (sender->link_down || (!sender->peer && !sender->vlan)) {
-        return calc_iov_length(iov, iovcnt);
+        return iov_size(iov, iovcnt);
     }
 
     if (sender->peer) {
@@ -693,7 +640,7 @@ VLANState *qemu_find_vlan(int id, int allocate)
         return NULL;
     }
 
-    vlan = qemu_mallocz(sizeof(VLANState));
+    vlan = g_malloc0(sizeof(VLANState));
     vlan->id = id;
     QTAILQ_INIT(&vlan->clients);
 
@@ -711,6 +658,8 @@ VLANClientState *qemu_find_netdev(const char *id)
     VLANClientState *vc;
 
     QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc->info->type == NET_CLIENT_TYPE_NIC)
+            continue;
         if (!strcmp(vc->name, id)) {
             return vc;
         }
@@ -761,14 +710,14 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
     int i;
 
     if (!nd->model)
-        nd->model = qemu_strdup(default_model);
+        nd->model = g_strdup(default_model);
 
     for (i = 0 ; models[i]; i++) {
         if (strcmp(nd->model, models[i]) == 0)
             return i;
     }
 
-    error_report("qemu: Unsupported NIC model: %s", nd->model);
+    error_report("Unsupported NIC model: %s", nd->model);
     return -1;
 }
 
@@ -784,12 +733,7 @@ int net_handle_fd_param(Monitor *mon, const char *param)
             return -1;
         }
     } else {
-        char *endptr = NULL;
-
-        fd = strtol(param, &endptr, 10);
-        if (*endptr || (fd == 0 && param == endptr)) {
-            return -1;
-        }
+        fd = qemu_parse_fd(param);
     }
 
     return fd;
@@ -825,27 +769,21 @@ static int net_init_nic(QemuOpts *opts,
         nd->vlan = vlan;
     }
     if (name) {
-        nd->name = qemu_strdup(name);
+        nd->name = g_strdup(name);
     }
     if (qemu_opt_get(opts, "model")) {
-        nd->model = qemu_strdup(qemu_opt_get(opts, "model"));
+        nd->model = g_strdup(qemu_opt_get(opts, "model"));
     }
     if (qemu_opt_get(opts, "addr")) {
-        nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
+        nd->devaddr = g_strdup(qemu_opt_get(opts, "addr"));
     }
 
-    nd->macaddr[0] = 0x52;
-    nd->macaddr[1] = 0x54;
-    nd->macaddr[2] = 0x00;
-    nd->macaddr[3] = 0x12;
-    nd->macaddr[4] = 0x34;
-    nd->macaddr[5] = 0x56 + idx;
-
     if (qemu_opt_get(opts, "macaddr") &&
-        net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) {
+        net_parse_macaddr(nd->macaddr.a, qemu_opt_get(opts, "macaddr")) < 0) {
         error_report("invalid syntax for ethernet address");
         return -1;
     }
+    qemu_macaddr_default_if_unset(&nd->macaddr);
 
     nd->nvectors = qemu_opt_get_number(opts, "vectors",
                                        DEV_NVECTORS_UNSPECIFIED);
@@ -888,14 +826,15 @@ static const struct {
     const char *type;
     net_client_init_func init;
     QemuOptDesc desc[NET_MAX_DESC];
-} net_client_types[] = {
-    {
+} net_client_types[NET_CLIENT_TYPE_MAX] = {
+    [NET_CLIENT_TYPE_NONE] = {
         .type = "none",
         .desc = {
             NET_COMMON_PARAMS_DESC,
             { /* end of list */ }
         },
-    }, {
+    },
+    [NET_CLIENT_TYPE_NIC] = {
         .type = "nic",
         .init = net_init_nic,
         .desc = {
@@ -924,8 +863,9 @@ static const struct {
             },
             { /* end of list */ }
         },
+    },
 #ifdef CONFIG_SLIRP
-    }, {
+    [NET_CLIENT_TYPE_USER] = {
         .type = "user",
         .init = net_init_slirp,
         .desc = {
@@ -985,8 +925,9 @@ static const struct {
             },
             { /* end of list */ }
         },
+    },
 #endif
-    }, {
+    [NET_CLIENT_TYPE_TAP] = {
         .type = "tap",
         .init = net_init_tap,
         .desc = {
@@ -1033,7 +974,8 @@ static const struct {
 #endif /* _WIN32 */
             { /* end of list */ }
         },
-    }, {
+    },
+    [NET_CLIENT_TYPE_SOCKET] = {
         .type = "socket",
         .init = net_init_socket,
         .desc = {
@@ -1061,8 +1003,9 @@ static const struct {
             },
             { /* end of list */ }
         },
+    },
 #ifdef CONFIG_VDE
-    }, {
+    [NET_CLIENT_TYPE_VDE] = {
         .type = "vde",
         .init = net_init_vde,
         .desc = {
@@ -1086,8 +1029,9 @@ static const struct {
             },
             { /* end of list */ }
         },
+    },
 #endif
-    }, {
+    [NET_CLIENT_TYPE_DUMP] = {
         .type = "dump",
         .init = net_init_dump,
         .desc = {
@@ -1104,7 +1048,6 @@ static const struct {
             { /* end of list */ }
         },
     },
-    { /* end of list */ }
 };
 
 int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
@@ -1152,8 +1095,9 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
         name = qemu_opt_get(opts, "name");
     }
 
-    for (i = 0; net_client_types[i].type != NULL; i++) {
-        if (!strcmp(net_client_types[i].type, type)) {
+    for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) {
+        if (net_client_types[i].type != NULL &&
+            !strcmp(net_client_types[i].type, type)) {
             VLANState *vlan = NULL;
             int ret;
 
@@ -1270,7 +1214,7 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     VLANClientState *vc;
 
     vc = qemu_find_netdev(id);
-    if (!vc || vc->info->type == NET_CLIENT_TYPE_NIC) {
+    if (!vc) {
         qerror_report(QERR_DEVICE_NOT_FOUND, id);
         return -1;
     }
@@ -1279,25 +1223,38 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return 0;
 }
 
+static void print_net_client(Monitor *mon, VLANClientState *vc)
+{
+    monitor_printf(mon, "%s: type=%s,%s\n", vc->name,
+                   net_client_types[vc->info->type].type, vc->info_str);
+}
+
 void do_info_network(Monitor *mon)
 {
     VLANState *vlan;
-    VLANClientState *vc;
+    VLANClientState *vc, *peer;
+    net_client_type type;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
         monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
 
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
-            monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
+            monitor_printf(mon, "  ");
+            print_net_client(mon, vc);
         }
     }
     monitor_printf(mon, "Devices not on any VLAN:\n");
     QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
-        monitor_printf(mon, "  %s: %s", vc->name, vc->info_str);
-        if (vc->peer) {
-            monitor_printf(mon, " peer=%s", vc->peer->name);
+        peer = vc->peer;
+        type = vc->info->type;
+        if (!peer || type == NET_CLIENT_TYPE_NIC) {
+            monitor_printf(mon, "  ");
+            print_net_client(mon, vc);
+        } /* else it's a netdev connected to a NIC, printed with the NIC */
+        if (peer && type == NET_CLIENT_TYPE_NIC) {
+            monitor_printf(mon, "   \\ ");
+            print_net_client(mon, peer);
         }
-        monitor_printf(mon, "\n");
     }
 }
 
@@ -1315,7 +1272,11 @@ int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
             }
         }
     }
-    vc = qemu_find_netdev(name);
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!strcmp(vc->name, name)) {
+            goto done;
+        }
+    }
 done:
 
     if (!vc) {
@@ -1328,6 +1289,17 @@ done:
     if (vc->info->link_status_changed) {
         vc->info->link_status_changed(vc);
     }
+
+    /* Notify peer. Don't update peer link status: this makes it possible to
+     * disconnect from host network without notifying the guest.
+     * FIXME: is disconnected link status change operation useful?
+     *
+     * Current behaviour is compatible with qemu vlans where there could be
+     * multiple clients that can still communicate with each other in
+     * disconnected mode. For now maintain this compatibility. */
+    if (vc->peer && vc->peer->info->link_status_changed) {
+        vc->peer->info->link_status_changed(vc->peer);
+    }
     return 0;
 }
 
@@ -1351,15 +1323,29 @@ void net_check_clients(void)
 {
     VLANState *vlan;
     VLANClientState *vc;
-    int has_nic = 0, has_host_dev = 0;
+    int i;
+
+    /* Don't warn about the default network setup that you get if
+     * no command line -net or -netdev 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
+     * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic"
+     * sets up a nic that isn'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:
                 has_nic = 1;
                 break;
-            case NET_CLIENT_TYPE_SLIRP:
+            case NET_CLIENT_TYPE_USER:
             case NET_CLIENT_TYPE_TAP:
             case NET_CLIENT_TYPE_SOCKET:
             case NET_CLIENT_TYPE_VDE:
@@ -1382,6 +1368,20 @@ void net_check_clients(void)
                     vc->name);
         }
     }
+
+    /* Check that all NICs requested via -net nic actually got created.
+     * NICs created via -device don't need to be checked here because
+     * they are always instantiated.
+     */
+    for (i = 0; i < MAX_NICS; i++) {
+        NICInfo *nd = &nd_table[i];
+        if (nd->used && !nd->instantiated) {
+            fprintf(stderr, "Warning: requested NIC (%s, model %s) "
+                    "was not created (not supported by this machine?)\n",
+                    nd->name ? nd->name : "anonymous",
+                    nd->model ? nd->model : "unspecified");
+        }
+    }
 }
 
 static int net_init_client(QemuOpts *opts, void *dummy)
diff --git a/net.h b/net.h
index 6ceca50fc38b0b2c73a38a1fcf93a9a7f30d6576..9f633f8432f6e37da36e4d738f603327a5e3424c 100644 (file)
--- a/net.h
+++ b/net.h
@@ -31,11 +31,13 @@ typedef struct NICConf {
 typedef enum {
     NET_CLIENT_TYPE_NONE,
     NET_CLIENT_TYPE_NIC,
-    NET_CLIENT_TYPE_SLIRP,
+    NET_CLIENT_TYPE_USER,
     NET_CLIENT_TYPE_TAP,
     NET_CLIENT_TYPE_SOCKET,
     NET_CLIENT_TYPE_VDE,
-    NET_CLIENT_TYPE_DUMP
+    NET_CLIENT_TYPE_DUMP,
+
+    NET_CLIENT_TYPE_MAX
 } net_client_type;
 
 typedef void (NetPoll)(VLANClientState *, bool enable);
@@ -127,13 +129,14 @@ int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data);
 #define MAX_NICS 8
 
 struct NICInfo {
-    uint8_t macaddr[6];
+    MACAddr macaddr;
     char *model;
     char *name;
     char *devaddr;
     VLANState *vlan;
     VLANClientState *netdev;
-    int used;
+    int used;         /* is this slot in nd_table[] being used? */
+    int instantiated; /* does this NICInfo correspond to an instantiated NIC? */
     int nvectors;
 };
 
@@ -171,11 +174,6 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
 #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
-#ifdef __sun__
-#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
-#else
-#define SMBD_COMMAND "/usr/sbin/smbd"
-#endif
 
 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
 
index 6db7ecf95939b53d68cf8025acf82c04015dfd78..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;
@@ -67,7 +67,7 @@ static ssize_t dump_receive(VLANClientState *nc, const uint8_t *buf, size_t size
         return size;
     }
 
-    ts = muldiv64(qemu_get_clock(vm_clock), 1000000, get_ticks_per_sec());
+    ts = muldiv64(qemu_get_clock_ns(vm_clock), 1000000, get_ticks_per_sec());
     caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
 
     hdr.ts.tv_sec = ts / 1000000;
index 2ea6cd0b6aa9567fa719ab2fa96f5d1deb4c850a..1ab5247a327d9918c0227cdc13232e8cd2fe4d06 100644 (file)
@@ -63,7 +63,7 @@ NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
 {
     NetQueue *queue;
 
-    queue = qemu_mallocz(sizeof(NetQueue));
+    queue = g_malloc0(sizeof(NetQueue));
 
     queue->deliver = deliver;
     queue->deliver_iov = deliver_iov;
@@ -82,10 +82,10 @@ void qemu_del_net_queue(NetQueue *queue)
 
     QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
         QTAILQ_REMOVE(&queue->packets, packet, entry);
-        qemu_free(packet);
+        g_free(packet);
     }
 
-    qemu_free(queue);
+    g_free(queue);
 }
 
 static ssize_t qemu_net_queue_append(NetQueue *queue,
@@ -97,7 +97,7 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
 {
     NetPacket *packet;
 
-    packet = qemu_malloc(sizeof(NetPacket) + size);
+    packet = g_malloc(sizeof(NetPacket) + size);
     packet->sender = sender;
     packet->flags = flags;
     packet->size = size;
@@ -124,7 +124,7 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
         max_len += iov[i].iov_len;
     }
 
-    packet = qemu_malloc(sizeof(NetPacket) + max_len);
+    packet = g_malloc(sizeof(NetPacket) + max_len);
     packet->sender = sender;
     packet->sent_cb = sent_cb;
     packet->flags = flags;
@@ -227,7 +227,7 @@ void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from)
     QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
         if (packet->sender == from) {
             QTAILQ_REMOVE(&queue->packets, packet, entry);
-            qemu_free(packet);
+            g_free(packet);
         }
     }
 }
@@ -255,6 +255,6 @@ void qemu_net_queue_flush(NetQueue *queue)
             packet->sent_cb(packet->sender, ret);
         }
 
-        qemu_free(packet);
+        g_free(packet);
     }
 }
index 96dff619a38f0d678e78bc74b4c13f5581f3a9a3..6646ecb1c800d31b2e80cdb6f5855b254cfd1006 100644 (file)
@@ -30,7 +30,6 @@
 #endif
 #include "net.h"
 #include "monitor.h"
-#include "sysemu.h"
 #include "qemu_socket.h"
 #include "slirp/libslirp.h"
 
@@ -129,7 +128,7 @@ static void net_slirp_cleanup(VLANClientState *nc)
 }
 
 static NetClientInfo net_slirp_info = {
-    .type = NET_CLIENT_TYPE_SLIRP,
+    .type = NET_CLIENT_TYPE_USER,
     .size = sizeof(SlirpState),
     .receive = net_slirp_receive,
     .cleanup = net_slirp_cleanup,
@@ -241,7 +240,8 @@ static int net_slirp_init(VLANState *vlan, const char *model,
     nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name);
 
     snprintf(nc->info_str, sizeof(nc->info_str),
-             "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
+             "net=%s,restrict=%s", inet_ntoa(net),
+             restricted ? "on" : "off");
 
     s = DO_UPCAST(SlirpState, nc, nc);
 
@@ -305,7 +305,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
 {
     struct in_addr host_addr = { .s_addr = INADDR_ANY };
     int host_port;
-    char buf[256] = "";
+    char buf[256];
     const char *src_str, *p;
     SlirpState *s;
     int is_udp = 0;
@@ -325,11 +325,10 @@ void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    if (!src_str || !src_str[0])
-        goto fail_syntax;
-
     p = src_str;
-    get_str_sep(buf, sizeof(buf), &p, ':');
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
 
     if (!strcmp(buf, "tcp") || buf[0] == '\0') {
         is_udp = 0;
@@ -413,9 +412,8 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str,
 
     if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
                           guest_port) < 0) {
-               // normal case with sdb & multi emulator => comment-out
-        // error_report("could not set up host forwarding rule '%s'",
-        //             redir_str);
+        error_report("could not set up host forwarding rule '%s'",
+                     redir_str);
         return -1;
     }
     return 0;
@@ -451,7 +449,7 @@ int net_slirp_redir(const char *redir_str)
     struct slirp_config_str *config;
 
     if (QTAILQ_EMPTY(&slirp_stacks)) {
-        config = qemu_malloc(sizeof(*config));
+        config = g_malloc(sizeof(*config));
         pstrcpy(config->str, sizeof(config->str), redir_str);
         config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
         config->next = slirp_configs;
@@ -530,7 +528,7 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
     fclose(f);
 
     snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
-             SMBD_COMMAND, smb_conf);
+             CONFIG_SMBD_COMMAND, smb_conf);
 
     if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
         slirp_smb_cleanup(s);
@@ -615,19 +613,19 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         goto fail_syntax;
     }
 
-    fwd = qemu_malloc(sizeof(struct GuestFwd));
-    snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
-    fwd->hd = qemu_chr_open(buf, p, NULL);
+    fwd = g_malloc(sizeof(struct GuestFwd));
+    snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
+    fwd->hd = qemu_chr_new(buf, p, NULL);
     if (!fwd->hd) {
         error_report("could not open guest forwarding device '%s'", buf);
-        qemu_free(fwd);
+        g_free(fwd);
         return -1;
     }
 
     if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
         error_report("conflicting/invalid host:port in guest forwarding "
                      "rule '%s'", config_str);
-        qemu_free(fwd);
+        g_free(fwd);
         return -1;
     }
     fwd->server = server;
@@ -663,7 +661,7 @@ static int net_init_slirp_configs(const char *name, const char *value, void *opa
         return 0;
     }
 
-    config = qemu_mallocz(sizeof(*config));
+    config = g_malloc0(sizeof(*config));
 
     pstrcpy(config->str, sizeof(config->str), value);
 
@@ -691,6 +689,7 @@ int net_init_slirp(QemuOpts *opts,
     const char *bootfile;
     const char *smb_export;
     const char *vsmbsrv;
+    const char *restrict_opt;
     char *vnet = NULL;
     int restricted = 0;
     int ret;
@@ -704,11 +703,23 @@ int net_init_slirp(QemuOpts *opts,
     smb_export  = qemu_opt_get(opts, "smb");
     vsmbsrv     = qemu_opt_get(opts, "smbserver");
 
+    restrict_opt = qemu_opt_get(opts, "restrict");
+    if (restrict_opt) {
+        if (!strcmp(restrict_opt, "on") ||
+            !strcmp(restrict_opt, "yes") || !strcmp(restrict_opt, "y")) {
+            restricted = 1;
+        } else if (strcmp(restrict_opt, "off") &&
+            strcmp(restrict_opt, "no") && strcmp(restrict_opt, "n")) {
+            error_report("invalid option: 'restrict=%s'", restrict_opt);
+            return -1;
+        }
+    }
+
     if (qemu_opt_get(opts, "ip")) {
         const char *ip = qemu_opt_get(opts, "ip");
         int l = strlen(ip) + strlen("/24") + 1;
 
-        vnet = qemu_malloc(l);
+        vnet = g_malloc(l);
 
         /* emulate legacy ip= parameter */
         pstrcpy(vnet, l, ip);
@@ -717,14 +728,9 @@ int net_init_slirp(QemuOpts *opts,
 
     if (qemu_opt_get(opts, "net")) {
         if (vnet) {
-            qemu_free(vnet);
+            g_free(vnet);
         }
-        vnet = qemu_strdup(qemu_opt_get(opts, "net"));
-    }
-
-    if (qemu_opt_get(opts, "restrict") &&
-        qemu_opt_get(opts, "restrict")[0] == 'y') {
-        restricted = 1;
+        vnet = g_strdup(qemu_opt_get(opts, "net"));
     }
 
     qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
@@ -736,10 +742,10 @@ int net_init_slirp(QemuOpts *opts,
     while (slirp_configs) {
         config = slirp_configs;
         slirp_configs = config->next;
-        qemu_free(config);
+        g_free(config);
     }
 
-    qemu_free(vnet);
+    g_free(vnet);
 
     return ret;
 }
@@ -757,7 +763,7 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret
     if (QTAILQ_EMPTY(&slirp_stacks)) {
         struct slirp_config_str *config;
 
-        config = qemu_malloc(sizeof(*config));
+        config = g_malloc(sizeof(*config));
         pstrcpy(config->str, sizeof(config->str), optarg);
         config->flags = SLIRP_CFG_LEGACY;
         config->next = slirp_configs;
index 3182b371a72cbbaa6f45adfa578429a4bd2f68c9..e9ef12877f18ae21dddcbd29c89d36bea7a3dfd2 100644 (file)
@@ -76,7 +76,7 @@ static void net_socket_send(void *opaque)
     uint8_t buf1[4096];
     const uint8_t *buf;
 
-    size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
+    size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
     if (size < 0) {
         err = socket_error();
         if (err != EWOULDBLOCK)
@@ -138,7 +138,7 @@ static void net_socket_send_dgram(void *opaque)
     NetSocketState *s = opaque;
     int size;
 
-    size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
     if (size < 0)
         return;
     if (size == 0) {
@@ -154,6 +154,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
     struct ip_mreq imr;
     int fd;
     int val, ret;
+#ifdef __OpenBSD__
+    unsigned char loop;
+#else
+    int loop;
+#endif
+
     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
                inet_ntoa(mcastaddr->sin_addr),
@@ -197,9 +203,9 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
     }
 
     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
-    val = 1;
+    loop = 1;
     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
-                   (const char *)&val, sizeof(val));
+                   (const char *)&loop, sizeof(loop));
     if (ret < 0) {
        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
        goto fail;
@@ -398,7 +404,7 @@ static int net_socket_listen_init(VLANState *vlan,
     if (parse_host_port(&saddr, host_str) < 0)
         return -1;
 
-    s = qemu_mallocz(sizeof(NetSocketListenState));
+    s = g_malloc0(sizeof(NetSocketListenState));
 
     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     if (fd < 0) {
@@ -422,8 +428,8 @@ static int net_socket_listen_init(VLANState *vlan,
         return -1;
     }
     s->vlan = vlan;
-    s->model = qemu_strdup(model);
-    s->name = name ? qemu_strdup(name) : NULL;
+    s->model = g_strdup(model);
+    s->name = name ? g_strdup(name) : NULL;
     s->fd = fd;
     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
     return 0;
@@ -457,7 +463,7 @@ static int net_socket_connect_init(VLANState *vlan,
             } else if (err == EINPROGRESS) {
                 break;
 #ifdef _WIN32
-            } else if (err == WSAEALREADY) {
+            } else if (err == WSAEALREADY || err == WSAEINVAL) {
                 break;
 #endif
             } else {
@@ -530,7 +536,7 @@ int net_init_socket(QemuOpts *opts,
             qemu_opt_get(opts, "connect") ||
             qemu_opt_get(opts, "mcast") ||
             qemu_opt_get(opts, "localaddr")) {
-            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n");
+            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=");
             return -1;
         }
 
@@ -550,7 +556,7 @@ int net_init_socket(QemuOpts *opts,
             qemu_opt_get(opts, "connect") ||
             qemu_opt_get(opts, "mcast") ||
             qemu_opt_get(opts, "localaddr")) {
-            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n");
+            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=");
             return -1;
         }
 
@@ -566,7 +572,7 @@ int net_init_socket(QemuOpts *opts,
             qemu_opt_get(opts, "listen") ||
             qemu_opt_get(opts, "mcast") ||
             qemu_opt_get(opts, "localaddr")) {
-            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n");
+            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=");
             return -1;
         }
 
index 2f3efdee03b5b57c801ae2c7828c8ee1601f9ffe..4b6b3a41a095de3e035ef85a9c5a911d4af6df6b 100644 (file)
@@ -28,6 +28,8 @@
 #include "qemu-error.h"
 
 #ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <net/if.h>
 #include <net/if_tap.h>
 #endif
 
 int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
 {
     int fd;
+#ifdef TAPGIFNAME
+    struct ifreq ifr;
+#else
     char *dev;
     struct stat s;
+#endif
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
     /* if no ifname is given, always start the search from tap0/tun0. */
@@ -77,14 +83,30 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
 #else
     TFR(fd = open("/dev/tap", O_RDWR));
     if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        fprintf(stderr,
+            "warning: could not open /dev/tap: no virtual network emulation: %s\n",
+            strerror(errno));
         return -1;
     }
 #endif
 
-    fstat(fd, &s);
+#ifdef TAPGIFNAME
+    if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
+        fprintf(stderr, "warning: could not get tap name: %s\n",
+            strerror(errno));
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+#else
+    if (fstat(fd, &s) < 0) {
+        fprintf(stderr,
+            "warning: could not stat /dev/tap: no virtual network emulation: %s\n",
+            strerror(errno));
+        return -1;
+    }
     dev = devname(s.st_rdev, S_IFCHR);
     pstrcpy(ifname, ifname_size, dev);
+#endif
 
     if (*vnet_hdr) {
         /* BSD doesn't have IFF_VNET_HDR */
index ff8cad0ea04c13176103f76babdd03df105d458d..41d581b73445bade0aaa412255b0aee219b0086b 100644 (file)
@@ -73,7 +73,11 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
         pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
     ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
     if (ret != 0) {
-        error_report("could not configure %s (%s): %m", PATH_NET_TUN, ifr.ifr_name);
+        if (ifname[0] != '\0') {
+            error_report("could not configure %s (%s): %m", PATH_NET_TUN, ifr.ifr_name);
+        } else {
+            error_report("could not configure %s: %m", PATH_NET_TUN);
+        }
         close(fd);
         return -1;
     }
index 081904e8d74502684654a8c3463fb9d44816e886..cb886d7fe122bb080aa286cb84b4f6eab731f586 100644 (file)
@@ -480,7 +480,7 @@ static int tap_win32_write(tap_win32_overlapped_t *overlapped,
         }
     }
 
-    return 0;
+    return write_size;
 }
 
 static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
@@ -591,7 +591,6 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
               USERMODEDEVICEDIR,
               device_guid,
               TAPSUFFIX);
-
     handle = CreateFile (
         device_path,
         GENERIC_READ | GENERIC_WRITE,
@@ -600,7 +599,6 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
         OPEN_EXISTING,
         FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
         0 );
-
     if (handle == INVALID_HANDLE_VALUE) {
         return -1;
     }
index b8cd25267cfd5b7518e7214fb6feb7ae26bbeb18..1f26dc9992a016e263af0d4f69c147f274c3acbf 100644 (file)
--- a/net/tap.c
+++ b/net/tap.c
@@ -27,7 +27,6 @@
 
 #include "config-host.h"
 
-#include <signal.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/wait.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;
diff --git a/new_emulator_project b/new_emulator_project
new file mode 100644 (file)
index 0000000..e69de29
index bcd3fc532f9b32ca27b5e4d087391c248cefc529..a6bac1f7837f93adad787f1c06f586c2e35d31d2 100644 (file)
--- a/notify.c
+++ b/notify.c
@@ -29,11 +29,11 @@ void notifier_list_remove(NotifierList *list, Notifier *notifier)
     QTAILQ_REMOVE(&list->notifiers, notifier, node);
 }
 
-void notifier_list_notify(NotifierList *list)
+void notifier_list_notify(NotifierList *list, void *data)
 {
     Notifier *notifier, *next;
 
     QTAILQ_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
-        notifier->notify(notifier);
+        notifier->notify(notifier, data);
     }
 }
index b40522f582de8366aed0fa1e417a6cfa78eb15cb..54fc57cec193b3a5b7a2412bd64faa8fef965b3d 100644 (file)
--- a/notify.h
+++ b/notify.h
@@ -20,7 +20,7 @@ typedef struct Notifier Notifier;
 
 struct Notifier
 {
-    void (*notify)(Notifier *notifier);
+    void (*notify)(Notifier *notifier, void *data);
     QTAILQ_ENTRY(Notifier) node;
 };
 
@@ -38,6 +38,6 @@ void notifier_list_add(NotifierList *list, Notifier *notifier);
 
 void notifier_list_remove(NotifierList *list, Notifier *notifier);
 
-void notifier_list_notify(NotifierList *list);
+void notifier_list_notify(NotifierList *list, void *data);
 
 #endif
index 38c29d1afe42ff3b2e7fc28f938e5798a2551053..dc4a6bb3fffa98d80144284412e7b575f72d914e 100644 (file)
@@ -31,6 +31,7 @@
 /*needed for MAP_POPULATE before including qemu-options.h */
 #include <sys/mman.h>
 #include <pwd.h>
+#include <grp.h>
 #include <libgen.h>
 
 /* Needed early for CONFIG_BSD etc. */
@@ -41,6 +42,7 @@
 
 #ifdef CONFIG_LINUX
 #include <sys/prctl.h>
+#include <sys/syscall.h>
 #endif
 
 #ifdef CONFIG_EVENTFD
@@ -61,14 +63,9 @@ void os_setup_early_signal_handling(void)
     sigaction(SIGPIPE, &act, NULL);
 }
 
-static void termsig_handler(int signal)
+static void termsig_handler(int signal, siginfo_t *info, void *c)
 {
-    qemu_system_shutdown_request();
-}
-
-static void sigchld_handler(int signal)
-{
-    waitpid(-1, NULL, WNOHANG);
+    qemu_system_killed(info->si_signo, info->si_pid);
 }
 
 void os_setup_signal_handling(void)
@@ -76,14 +73,11 @@ void os_setup_signal_handling(void)
     struct sigaction act;
 
     memset(&act, 0, sizeof(act));
-    act.sa_handler = termsig_handler;
+    act.sa_sigaction = termsig_handler;
+    act.sa_flags = SA_SIGINFO;
     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.
@@ -134,12 +128,12 @@ char *os_find_datadir(const char *argv0)
 
     max_len = strlen(dir) +
         MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
-    res = qemu_mallocz(max_len);
+    res = g_malloc0(max_len);
     snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
     if (access(res, R_OK)) {
         snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
         if (access(res, R_OK)) {
-            qemu_free(res);
+            g_free(res);
             res = NULL;
         }
     }
@@ -206,6 +200,11 @@ static void change_process_uid(void)
             fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
             exit(1);
         }
+        if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
+            fprintf(stderr, "Failed to initgroups(\"%s\", %d)\n",
+                    user_pwd->pw_name, user_pwd->pw_gid);
+            exit(1);
+        }
         if (setuid(user_pwd->pw_uid) < 0) {
             fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
             exit(1);
@@ -373,12 +372,24 @@ int qemu_create_pidfile(const char *filename)
         return -1;
     }
     if (lockf(fd, F_TLOCK, 0) == -1) {
+        close(fd);
         return -1;
     }
-    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
     if (write(fd, buffer, len) != len) {
+        close(fd);
         return -1;
     }
 
+    close(fd);
     return 0;
 }
+
+int qemu_get_thread_id(void)
+{
+#if defined (__linux__)
+    return syscall(SYS_gettid);
+#else
+    return getpid();
+#endif
+}
index 566d5e985352467b250396e0236a20e0647af2b0..b85d0768b9e5f4d4b5e7654d96be5ad7821fbff4 100644 (file)
@@ -41,146 +41,31 @@ int setenv(const char *name, const char *value, int overwrite)
     int result = 0;
     if (overwrite || !getenv(name)) {
         size_t length = strlen(name) + strlen(value) + 2;
-        char *string = qemu_malloc(length);
+        char *string = g_malloc(length);
         snprintf(string, length, "%s=%s", name, value);
         result = putenv(string);
     }
     return result;
 }
 
-/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
-    PollingFunc *func;
-    void *opaque;
-    struct PollingEntry *next;
-} PollingEntry;
-
-static PollingEntry *first_polling_entry;
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
-{
-    PollingEntry **ppe, *pe;
-    pe = qemu_mallocz(sizeof(PollingEntry));
-    pe->func = func;
-    pe->opaque = opaque;
-    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
-    *ppe = pe;
-    return 0;
-}
-
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
-{
-    PollingEntry **ppe, *pe;
-    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
-        pe = *ppe;
-        if (pe->func == func && pe->opaque == opaque) {
-            *ppe = pe->next;
-            qemu_free(pe);
-            break;
-        }
-    }
-}
-
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
-    int num;
-    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
-    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
-    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
-    WaitObjects *w = &wait_objects;
-
-    if (w->num >= MAXIMUM_WAIT_OBJECTS)
-        return -1;
-    w->events[w->num] = handle;
-    w->func[w->num] = func;
-    w->opaque[w->num] = opaque;
-    w->num++;
-    return 0;
-}
-
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
-    int i, found;
-    WaitObjects *w = &wait_objects;
-
-    found = 0;
-    for (i = 0; i < w->num; i++) {
-        if (w->events[i] == handle)
-            found = 1;
-        if (found) {
-            w->events[i] = w->events[i + 1];
-            w->func[i] = w->func[i + 1];
-            w->opaque[i] = w->opaque[i + 1];
-        }
-    }
-    if (found)
-        w->num--;
-}
-
-void os_host_main_loop_wait(int *timeout)
-{
-    int ret, ret2, i;
-    PollingEntry *pe;
-
-    /* XXX: need to suppress polling by better using win32 events */
-    ret = 0;
-    for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
-        ret |= pe->func(pe->opaque);
-    }
-    if (ret == 0) {
-        int err;
-        WaitObjects *w = &wait_objects;
-
-        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
-        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
-            if (w->func[ret - WAIT_OBJECT_0])
-                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
-            /* Check for additional signaled events */
-            for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
-                /* Check if event is signaled */
-                ret2 = WaitForSingleObject(w->events[i], 0);
-                if(ret2 == WAIT_OBJECT_0) {
-                    if (w->func[i])
-                        w->func[i](w->opaque[i]);
-                } else if (ret2 == WAIT_TIMEOUT) {
-                } else {
-                    err = GetLastError();
-                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
-                }
-            }
-        } else if (ret == WAIT_TIMEOUT) {
-        } else {
-            err = GetLastError();
-            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
-        }
-    }
-
-    *timeout = 0;
-}
-
 static BOOL WINAPI qemu_ctrl_handler(DWORD type)
 {
     exit(STATUS_CONTROL_C_EXIT);
     return TRUE;
 }
 
+#ifdef CONFIG_MARU
+void os_setup_early_signal_handling(void)
+{
+    SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+}
+#else
 void os_setup_early_signal_handling(void)
 {
     /* Note: cpu_interrupt() is currently not SMP safe, so we force
        QEMU to run on a single CPU */
     HANDLE h;
-    DWORD mask, smask;
+    DWORD_PTR mask, smask;
     int i;
 
     SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
@@ -197,6 +82,7 @@ void os_setup_early_signal_handling(void)
         }
     }
 }
+#endif  /* CONFIG_MARU */
 
 /* Look for support files in the same directory as the executable.  */
 char *os_find_datadir(const char *argv0)
@@ -216,7 +102,7 @@ char *os_find_datadir(const char *argv0)
         p--;
     *p = 0;
     if (access(buf, R_OK) == 0) {
-        return qemu_strdup(buf);
+        return g_strdup(buf);
     }
     return NULL;
 }
@@ -249,18 +135,22 @@ int qemu_create_pidfile(const char *filename)
     OVERLAPPED overlap;
     BOOL ret;
     memset(&overlap, 0, sizeof(overlap));
-
     file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                     OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
+                      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (file == INVALID_HANDLE_VALUE) {
         return -1;
     }
-    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
-    ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
-                     &overlap, NULL);
+    len = snprintf(buffer, sizeof(buffer), "%d\n", getpid());
+    ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len,
+                    NULL, &overlap);
+    CloseHandle(file);
     if (ret == 0) {
         return -1;
     }
     return 0;
 }
+
+int qemu_get_thread_id(void)
+{
+    return GetCurrentThreadId();
+}
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)
diff --git a/osdep.h b/osdep.h
index 8bd30d764d2a4ed922b4de3383d0502980636185..432b91ea7293037c758598465a8e846e83356ee2 100644 (file)
--- a/osdep.h
+++ b/osdep.h
@@ -8,9 +8,7 @@
 #include <sys/signal.h>
 #endif
 
-#ifndef _WIN32
 #include <sys/time.h>
-#endif
 
 #ifndef glue
 #define xglue(x, y) x ## y
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #endif
 
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #endif
 
 #define qemu_printf printf
 
-#if defined (__GNUC__) && defined (__GNUC_MINOR__)
-# define QEMU_GNUC_PREREQ(maj, min) \
-         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-# define QEMU_GNUC_PREREQ(maj, min) 0
-#endif
-
+int qemu_daemon(int nochdir, int noclose);
 void *qemu_memalign(size_t alignment, size_t size);
 void *qemu_vmalloc(size_t size);
 void qemu_vfree(void *ptr);
@@ -125,6 +121,32 @@ void qemu_vfree(void *ptr);
 
 int qemu_madvise(void *addr, size_t len, int advice);
 
+#if defined(__HAIKU__) && defined(__i386__)
+#define FMT_pid "%ld"
+#elif defined(WIN64)
+#define FMT_pid "%" PRId64
+#else
+#define FMT_pid "%d"
+#endif
+
 int qemu_create_pidfile(const char *filename);
+int qemu_get_thread_id(void);
+
+#ifdef _WIN32
+static inline void qemu_timersub(const struct timeval *val1,
+                                 const struct timeval *val2,
+                                 struct timeval *res)
+{
+    res->tv_sec = val1->tv_sec - val2->tv_sec;
+    if (val1->tv_usec < val2->tv_usec) {
+        res->tv_sec--;
+        res->tv_usec = val1->tv_usec - val2->tv_usec + 1000 * 1000;
+    } else {
+        res->tv_usec = val1->tv_usec - val2->tv_usec;
+    }
+}
+#else
+#define qemu_timersub timersub
+#endif
 
 #endif
index 7bc5f7cf0951d047125c2498f812da1c5650529a..ce755496b5baf3b7f334185db478f2871dbba249 100644 (file)
  * THE SOFTWARE.
  */
 
+/* The following block of code temporarily renames the daemon() function so the
+   compiler does not see the warning associated with it in stdlib.h on OSX */
+#ifdef __APPLE__
+#define daemon qemu_fake_daemon_function
+#include <stdlib.h>
+#undef daemon
+extern int daemon(int, int);
+#endif
+
+#if defined(__linux__) && defined(__x86_64__)
+   /* Use 2 MiB alignment so transparent hugepages can be used by KVM.
+      Valgrind does not support alignments larger than 1 MiB,
+      therefore we need special code which handles running on Valgrind. */
+#  define QEMU_VMALLOC_ALIGN (512 * 4096)
+#  define CONFIG_VALGRIND
+#else
+#  define QEMU_VMALLOC_ALIGN getpagesize()
+#endif
+
 #include "config-host.h"
 #include "sysemu.h"
 #include "trace.h"
 #include "qemu_socket.h"
 
+#if defined(CONFIG_VALGRIND)
+static int running_on_valgrind = -1;
+#else
+#  define running_on_valgrind 0
+#endif
+
+int qemu_daemon(int nochdir, int noclose)
+{
+    return daemon(nochdir, noclose);
+}
+
 void *qemu_oom_check(void *ptr)
 {
     if (ptr == NULL) {
@@ -63,7 +93,24 @@ void *qemu_memalign(size_t alignment, size_t size)
 /* alloc shared memory pages */
 void *qemu_vmalloc(size_t size)
 {
-    return qemu_memalign(getpagesize(), size);
+    void *ptr;
+    size_t align = QEMU_VMALLOC_ALIGN;
+
+#if defined(CONFIG_VALGRIND)
+    if (running_on_valgrind < 0) {
+        /* First call, test whether we are running on Valgrind.
+           This is a substitute for RUNNING_ON_VALGRIND from valgrind.h. */
+        const char *ld = getenv("LD_PRELOAD");
+        running_on_valgrind = (ld != NULL && strstr(ld, "vgpreload"));
+    }
+#endif
+
+    if (size < align || running_on_valgrind) {
+        align = getpagesize();
+    }
+    ptr = qemu_memalign(align, size);
+    trace_qemu_vmalloc(size, ptr);
+    return ptr;
 }
 
 void qemu_vfree(void *ptr)
@@ -72,6 +119,13 @@ void qemu_vfree(void *ptr)
     free(ptr);
 }
 
+void socket_set_block(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
+}
+
 void socket_set_nonblock(int fd)
 {
     int f;
@@ -108,8 +162,7 @@ int qemu_pipe(int pipefd[2])
     return ret;
 }
 
-int qemu_utimensat(int dirfd, const char *path, const struct timespec *times,
-                   int flags)
+int qemu_utimens(const char *path, const struct timespec *times)
 {
     struct timeval tv[2], tv_now;
     struct stat st;
@@ -117,7 +170,7 @@ int qemu_utimensat(int dirfd, const char *path, const struct timespec *times,
 #ifdef CONFIG_UTIMENSAT
     int ret;
 
-    ret = utimensat(dirfd, path, times, flags);
+    ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
     if (ret != -1 || errno != ENOSYS) {
         return ret;
     }
index ab29eae45ce3f58da3fe25c5bb3c31b37b4ebeab..5e3de7dc8a52cf1b6131d8764f97ec4e23a5c3c3 100644 (file)
@@ -73,6 +73,12 @@ void qemu_vfree(void *ptr)
     VirtualFree(ptr, 0, MEM_RELEASE);
 }
 
+void socket_set_block(int fd)
+{
+    unsigned long opt = 0;
+    ioctlsocket(fd, FIONBIO, &opt);
+}
+
 void socket_set_nonblock(int fd)
 {
     unsigned long opt = 1;
@@ -93,13 +99,6 @@ void qemu_set_cloexec(int fd)
 {
 }
 
-/* mingw32 needs ffs for compilations without optimization. */
-int ffs(int i)
-{
-    /* Use gcc's builtin ffs. */
-    return __builtin_ffs(i);
-}
-
 /* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
 #define _W32_FT_OFFSET (116444736000000000ULL)
 
index 9d69c62d285e37fbb35d28516cbe5977252ba387..995b355dd7530023891b4865973630024e07e36a 100755 (executable)
@@ -5,6 +5,7 @@ clean()
        cd $SRCDIR/tizen/
        if test -e "Makefile"
        then
+               ./qemu_configure.sh
                make clean
        fi
        rm -rf $SRCDIR/*.zip
@@ -15,8 +16,7 @@ clean()
 build() 
 {
        cd $SRCDIR/tizen/
-       autoconf
-       ./configure
+       ./qemu_configure.sh
        make
 }
 
@@ -29,8 +29,8 @@ install()
     cd $SRCDIR/tizen
     make install
        mv Emulator $BIN_DIR
-       cp $SRCDIR/package/emulator.install.linux $BIN_DIR/../
-       cp $SRCDIR/package/emulator.remove.linux $BIN_DIR/../
+#      cp $SRCDIR/package/emulator.install.linux $BIN_DIR/../
+#      cp $SRCDIR/package/emulator.remove.linux $BIN_DIR/../
 }
 
 [ "$1" = "clean" ] && clean
index 64281a58fe85980c16df745111b036d6dc0dd488..7e4174a804346d92ab0f05dae5c1de6f28affa85 100755 (executable)
@@ -1,41 +1,75 @@
 #!/bin/sh -xe
 # clean
+
 clean()
 {
+       prepare
+
        cd $SRCDIR/tizen/
        if test -e "Makefile"
        then
+               ./qemu_configure.sh
                make clean
        fi
        rm -rf $SRCDIR/*.zip
        rm -rf $SRCDIR/*.tar.gz
 }
 
+#prepare
+prepare()
+{
+       if [ "$JAVA_HOME" = "" ]
+       then
+               echo "Make sure that you have installed JDK"
+        echo "and then set installed JDK/bin path into JAVA_HOME"
+        echo "as a system environment variable on your PC!!"
+               exit 1
+       fi
+
+       PYTHON_DIR=`env | grep PATH | grep Python`
+       if [ "$PYTHON_DIR" = "" ]
+       then
+               echo "Make sure that you have installed Python 2.x version"
+        echo "and then set installed Python/bin path into PATH system variable on your PC!"
+               exit 1
+       fi
+
+       PATH=$PATH:$ROOTDIR/bin:$ROOTDIR/apache-ant-1.8.3/bin
+       export PATH
+       BUILD_CFLAGS=--extra-cflags=-I$ROOTDIR/include
+    BUILD_LDFLAGS=--extra-ldflags=-L$ROOTDIR/lib
+}
+
 # build
 build() 
 {
+       prepare
+
        cd $SRCDIR/tizen/
-       autoconf
-       ./configure
+       ./qemu_configure.sh "$BUILD_CFLAGS $BUILD_LDFLAGS"
        make
+    if [ -f "../i386-softmmu/qemu-system-i386.exe" ]
+    then
+        echo "BUILD SUCCESS"
+    else
+        echo "BUILD FAIL!!!"
+        exit 1;
+    fi
 }
 
 # install
 install() 
 {
+
+       prepare
+
        BIN_DIR=$SRCDIR/package/emulator.package.windows/data
-       VTM_DIR=$BIN_DIR/Emulator/bin/emulator-manager.exe
-       EMUL_DIR=$BIN_DIR/Emulator/bin/emulator-x86.exe
 
        mkdir -p $BIN_DIR
 
-    cd $SRCDIR/tizen
-    make install
+       cd $SRCDIR/tizen
+       make install
        mv Emulator $BIN_DIR
-       editbin.exe /SUBSYSTEM:WINDOWS $VTM_DIR
-       editbin.exe /SUBSYSTEM:WINDOWS $EMUL_DIR
-       cp $SRCDIR/package/emulator.install.windows $BIN_DIR/../
-       cp $SRCDIR/package/emulator.remove.windows $BIN_DIR/../
 }
 
 [ "$1" = "clean" ] && clean
index 3d15f16d5176ea1a4548a157f516a19b2fca1118..bdf7b415e4613df5e7e3f02df3d6a17d1b1af7a1 100644 (file)
@@ -1,17 +1,18 @@
 Package: emulator
-Version: 1.2.22
+Version: 1.2.90
 OS: linux
 Build-host-os: linux
 Maintainer: Yeong-Kyoon Lee<yeongkyoon.lee@samsung.com>
-Install-dependency: emulator-kernel [ linux ]
+Install-dependency: emulator-kernel [ linux ], emulator-manager [ linux ], emulator-dll [ linux ]
 Source: emulator
 Description: Tizen Emulator
 
 Package: emulator
-Version: 1.2.22
+Version: 1.2.90
 OS: windows
 Build-host-os: windows
 Maintainer: Yeong-Kyoon Lee<yeongkyoon.lee@samsung.com>
-Install-dependency: emulator-kernel [ windows ],emulator-dll [ windows ]
+Build-dependency: SDL-1.2.14 [ windows ], jpeg-8b [ windows ], libpng-1.4.5 [ windows ], apache-ant-1.8.3-bin [ windows ]
+Install-dependency: emulator-kernel [ windows ], emulator-manager [ windows ], emulator-dll [ windows ]
 Source: emulator
 Description: Tizen Emulator
diff --git a/path.c b/path.c
index 0d2bf149e4eb12f052c67ae38d2a8c264913a909..ef3f277f17ac436cbb2b37856b52ae50ae2fa2ed 100644 (file)
--- a/path.c
+++ b/path.c
@@ -38,7 +38,8 @@ static int strneq(const char *s1, unsigned int n, const char *s2)
     return s2[i] == 0;
 }
 
-static struct pathelem *add_entry(struct pathelem *root, const char *name);
+static struct pathelem *add_entry(struct pathelem *root, const char *name,
+                                  unsigned char type);
 
 static struct pathelem *new_entry(const char *root,
                                   struct pathelem *parent,
@@ -56,6 +57,15 @@ static struct pathelem *new_entry(const char *root,
 
 #define streq(a,b) (strcmp((a), (b)) == 0)
 
+/* Not all systems provide this feature */
+#if defined(DT_DIR) && defined(DT_UNKNOWN)
+# define dirent_type(dirent) ((dirent)->d_type)
+# define is_dir_maybe(type)  ((type) == DT_DIR || (type) == DT_UNKNOWN)
+#else
+# define dirent_type(dirent) (1)
+# define is_dir_maybe(type)  (type)
+#endif
+
 static struct pathelem *add_dir_maybe(struct pathelem *path)
 {
     DIR *dir;
@@ -65,7 +75,7 @@ static struct pathelem *add_dir_maybe(struct pathelem *path)
 
         while ((dirent = readdir(dir)) != NULL) {
             if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
-                path = add_entry(path, dirent->d_name);
+                path = add_entry(path, dirent->d_name, dirent_type(dirent));
             }
         }
         closedir(dir);
@@ -73,16 +83,22 @@ static struct pathelem *add_dir_maybe(struct pathelem *path)
     return path;
 }
 
-static struct pathelem *add_entry(struct pathelem *root, const char *name)
+static struct pathelem *add_entry(struct pathelem *root, const char *name,
+                                  unsigned char type)
 {
+    struct pathelem **e;
+
     root->num_entries++;
 
     root = realloc(root, sizeof(*root)
                    + sizeof(root->entries[0])*root->num_entries);
+    e = &root->entries[root->num_entries-1];
+
+    *e = new_entry(root->pathname, root, name);
+    if (is_dir_maybe(type)) {
+        *e = add_dir_maybe(*e);
+    }
 
-    root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
-    root->entries[root->num_entries-1]
-        = add_dir_maybe(root->entries[root->num_entries-1]);
     return root;
 }
 
index 3fc09449fac44ae08d1df1c65f0747ed0a724c07..1cebbbc89a29d291992e13bb85a29de94d286b63 100644 (file)
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
-  The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32
-  and Sparc64 are built from OpenBIOS SVN revision 1018.
+  The included images for PowerPC (for 32 and 64 bit PPC CPUs),
+  Sparc32 and Sparc64 are built from OpenBIOS SVN revision
+  1047.
 
-- 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-20111013.
 
-  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
+- sgabios (the Serial Graphics Adapter option ROM) provides a means for
+  legacy x86 software to communicate with an attached serial console as
+  if a video card were attached.  The master sources reside in a subversion
+  repository at http://sgabios.googlecode.com/svn/trunk.  A git mirror is
+  available at git://git.qemu.org/sgabios.git.
 
-  http://rom-o-matic.net/
+- The PXE roms come from the iPXE project. Built with BANNER_TIME 0.
+  Sources available at http://ipxe.org.  Vendor:Device ID -> ROM mapping:
+
+       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:
   git://repo.or.cz/s390-tools.git
+
+- The sources for the Alpha palcode image is available from:
+  git://repo.or.cz/qemu-palcode.git
index e191908bbb06d6ab8fc6a3f16a63c57ce4eb1d6b..bd9ad0e78255baf80fdb0c0ad67853db0a9e7c06 100644 (file)
Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ
old mode 100755 (executable)
new mode 100644 (file)
index 708a22d..e7c3669
Binary files a/pc-bios/linuxboot.bin and b/pc-bios/linuxboot.bin differ
index 3299546696bf21f53f8ce2c9eba7fcb740c547da..c6d302153c7407d5d0127be29b0c35f80e47f8fb 100644 (file)
Binary files a/pc-bios/mpc8544ds.dtb and b/pc-bios/mpc8544ds.dtb differ
index 872152df93dc36c18d2009629e5f0b9ba1b2f4cf..7eb31604fc433e8bb69b35a89a143ede5d45d941 100644 (file)
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
-
-               PowerPC,8544@0 {
-                       device_type = "cpu";
-                       reg = <0x0>;
-                       d-cache-line-size = <32>;       // 32 bytes
-                       i-cache-line-size = <32>;       // 32 bytes
-                       d-cache-size = <0x8000>;                // L1, 32K
-                       i-cache-size = <0x8000>;                // L1, 32K
-                       timebase-frequency = <0>;
-                       bus-frequency = <0>;
-                       clock-frequency = <0>;
-               };
        };
 
        memory {
                        compatible = "chrp,open-pic";
                        device_type = "open-pic";
                };
+
+                global-utilities@e0000 {        //global utilities block
+                        compatible = "fsl,mpc8544-guts";
+                        reg = <0xe0000 0x1000>;
+                        fsl,has-rstcr;
+                };
        };
 
        pci0: pci@e0008000 {
        chosen {
                linux,stdout-path = "/soc8544@e0000000/serial@4500";
        };
+
+       hypervisor {
+       };
 };
index d7da6e04ad6d71d26f577d9d6a019719bcce8766..f74a6e142fddc054d7f40ab346a108532afac40f 100644 (file)
Binary files a/pc-bios/multiboot.bin and b/pc-bios/multiboot.bin differ
index ee6f5ae3b93a0570ff1eea5998716c361b15e989..83b7794ad1ca6edf4693bb8636ddb6e0b30e683a 100644 (file)
Binary files a/pc-bios/openbios-ppc and b/pc-bios/openbios-ppc differ
index b2dc5c5e7b645cd5deffe1bdf36e53ba87b17be9..03353c95ed89056b772a44c4cc1563501226eb26 100644 (file)
Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ
index 70a223d573aead9505cf2579e59af37b897c6202..c8972acaeb320a74a49dceee3c2cb1190d2c8882 100644 (file)
Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ
index 913183739cee764cec43ad24f6ae77fe2fb97d65..cc5ca1b7d178254afef18ce324942f155bbaac24 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "optionrom.h"
 
+#define BOOT_ROM_PRODUCT "multiboot loader"
+
 #define MULTIBOOT_MAGIC                0x2badb002
 
 #define GS_PROT_JUMP           0
index fbdd48a021352042586618118f742e9213acfd69..aa783deed10ecacb39ecae2d1bd2b2f6dcadde13 100644 (file)
 
 #define BOOT_ROM_START                                 \
        OPTION_ROM_START                                \
-       push            %eax;                           \
-       push            %ds;                            \
-                                                       \
-       /* setup ds so we can access the IVT */         \
-       xor             %ax, %ax;                       \
-       mov             %ax, %ds;                       \
-                                                       \
-       /* install our int 19 handler */                \
-       movw            $int19_handler, (0x19*4);       \
-       mov             %cs, (0x19*4+2);                \
-                                                       \
-       pop             %ds;                            \
-       pop             %eax;                           \
        lret;                                           \
-                                                       \
-    int19_handler:;                                    \
+       .org            0x18;                           \
+       .short          0;                              \
+       .short          _pnph;                          \
+    _pnph:                                             \
+       .ascii          "$PnP";                         \
+       .byte           0x01;                           \
+       .byte           ( _pnph_len / 16 );             \
+       .short          0x0000;                         \
+       .byte           0x00;                           \
+       .byte           0x00;                           \
+       .long           0x00000000;                     \
+       .short          _manufacturer;                  \
+       .short          _product;                       \
+       .long           0x00000000;                     \
+       .short          0x0000;                         \
+       .short          0x0000;                         \
+       .short          _bev;                           \
+       .short          0x0000;                         \
+       .short          0x0000;                         \
+       .equ            _pnph_len, . - _pnph;           \
+    _bev:;                                             \
        /* DS = CS */                                   \
        movw            %cs, %ax;                       \
        movw            %ax, %ds;
     _end:
 
 #define BOOT_ROM_END                                   \
+    _manufacturer:;                                    \
+       .asciz "QEMU";                                  \
+    _product:;                                         \
+       .asciz BOOT_ROM_PRODUCT;                        \
        OPTION_ROM_END
 
diff --git a/pc-bios/palcode-clipper b/pc-bios/palcode-clipper
new file mode 100755 (executable)
index 0000000..a92372c
Binary files /dev/null and b/pc-bios/palcode-clipper differ
diff --git a/pc-bios/petalogix-ml605.dtb b/pc-bios/petalogix-ml605.dtb
new file mode 100644 (file)
index 0000000..fbbd45f
Binary files /dev/null and b/pc-bios/petalogix-ml605.dtb 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.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.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.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.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
index f7af9b155dc27500d4619ea6c9eb530d27a79f5d..3115128efe465a024b2deb780573358ae1b829a4 100644 (file)
Binary files a/pc-bios/s390-zipl.rom and b/pc-bios/s390-zipl.rom differ
diff --git a/pc-bios/sgabios.bin b/pc-bios/sgabios.bin
new file mode 100755 (executable)
index 0000000..c3da4c3
Binary files /dev/null and b/pc-bios/sgabios.bin differ
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
new file mode 100644 (file)
index 0000000..1e84582
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
diff --git a/pc-bios/vgabios-maruvga.bin b/pc-bios/vgabios-maruvga.bin
new file mode 100644 (file)
index 0000000..41006f4
Binary files /dev/null and b/pc-bios/vgabios-maruvga.bin differ
diff --git a/pflib.c b/pflib.c
index 1154d0c9a3fc6c5efaf8b61d08b2a485c4fcd170..64cb2b3dda12c774a317b4047bd6a8c74f253178 100644 (file)
--- a/pflib.c
+++ b/pflib.c
@@ -145,7 +145,7 @@ static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt
 {
     if (conv->conv_cnt < cnt) {
         conv->conv_cnt = cnt;
-        conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
+        conv->conv_buf = g_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
     }
     conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
     conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
@@ -156,7 +156,7 @@ static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt
 
 QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
 {
-    QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv));
+    QemuPfConv *conv = g_malloc0(sizeof(QemuPfConv));
 
     conv->src = *src;
     conv->dst = *dst;
@@ -195,7 +195,7 @@ QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
     return conv;
 
 err:
-    qemu_free(conv);
+    g_free(conv);
     return NULL;
 }
 
@@ -207,7 +207,7 @@ void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
 void qemu_pf_conv_put(QemuPfConv *conv)
 {
     if (conv) {
-        qemu_free(conv->conv_buf);
-        qemu_free(conv);
+        g_free(conv->conv_buf);
+        g_free(conv);
     }
 }
index d7db7f43b6804bbc36f52bd8197d590bea60f813..5354e7779c4accc54a8275f112c0f52b50d2ab97 100644 (file)
--- a/poison.h
+++ b/poison.h
@@ -10,6 +10,7 @@
 #pragma GCC poison TARGET_ALPHA
 #pragma GCC poison TARGET_ARM
 #pragma GCC poison TARGET_CRIS
+#pragma GCC poison TARGET_LM32
 #pragma GCC poison TARGET_M68K
 #pragma GCC poison TARGET_MIPS
 #pragma GCC poison TARGET_MIPS64
 #pragma GCC poison CPUState
 #pragma GCC poison env
 
+#pragma GCC poison lduw_phys
+#pragma GCC poison ldl_phys
+#pragma GCC poison ldq_phys
+#pragma GCC poison stl_phys_notdirty
+#pragma GCC poison stq_phys_notdirty
+#pragma GCC poison stw_phys
+#pragma GCC poison stl_phys
+#pragma GCC poison stq_phys
+
 #pragma GCC poison CPU_INTERRUPT_HARD
 #pragma GCC poison CPU_INTERRUPT_EXITTB
-#pragma GCC poison CPU_INTERRUPT_TIMER
-#pragma GCC poison CPU_INTERRUPT_FIQ
 #pragma GCC poison CPU_INTERRUPT_HALT
-#pragma GCC poison CPU_INTERRUPT_SMI
 #pragma GCC poison CPU_INTERRUPT_DEBUG
-#pragma GCC poison CPU_INTERRUPT_VIRQ
-#pragma GCC poison CPU_INTERRUPT_NMI
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_0
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_1
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_2
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_3
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_4
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_0
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_1
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_2
 
 #endif
 #endif
index fa5494db8ceb683d037e969df5f0c1c7c753610a..0c0035cb18b21a6ab8070fb0b3608f1a26e8eb22 100644 (file)
@@ -17,7 +17,6 @@
 #include <unistd.h>
 #include <errno.h>
 #include <time.h>
-#include <signal.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -31,6 +30,7 @@
 
 #include "block/raw-posix-aio.h"
 
+static void do_spawn_thread(void);
 
 struct qemu_paiocb {
     BlockDriverAIOCB common;
@@ -42,7 +42,6 @@ struct qemu_paiocb {
     int aio_niov;
     size_t aio_nbytes;
 #define aio_ioctl_cmd   aio_nbytes /* for QEMU_AIO_IOCTL */
-    int ev_signo;
     off_t aio_offset;
 
     QTAILQ_ENTRY(qemu_paiocb) node;
@@ -50,8 +49,6 @@ struct qemu_paiocb {
     ssize_t ret;
     int active;
     struct qemu_paiocb *next;
-
-    int async_context_id;
 };
 
 typedef struct PosixAioState {
@@ -67,6 +64,9 @@ static pthread_attr_t attr;
 static int max_threads = 64;
 static int cur_threads = 0;
 static int idle_threads = 0;
+static int new_threads = 0;     /* backlog of threads we need to create */
+static int pending_threads = 0; /* threads created but not running yet */
+static QEMUBH *new_thread_bh;
 static QTAILQ_HEAD(, qemu_paiocb) request_list;
 
 #ifdef CONFIG_PREADV
@@ -180,7 +180,6 @@ qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
 
 static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
 {
-    size_t offset = 0;
     ssize_t len;
 
     do {
@@ -188,12 +187,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
             len = qemu_pwritev(aiocb->aio_fildes,
                                aiocb->aio_iov,
                                aiocb->aio_niov,
-                               aiocb->aio_offset + offset);
+                               aiocb->aio_offset);
          else
             len = qemu_preadv(aiocb->aio_fildes,
                               aiocb->aio_iov,
                               aiocb->aio_niov,
-                              aiocb->aio_offset + offset);
+                              aiocb->aio_offset);
     } while (len == -1 && errno == EINTR);
 
     if (len == -1)
@@ -201,6 +200,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
     return len;
 }
 
+/*
+ * Read/writes the data to/from a given linear buffer.
+ *
+ * Returns the number of bytes handles or -errno in case of an error. Short
+ * reads are only returned if the end of the file is reached.
+ */
 static ssize_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
 {
     ssize_t offset = 0;
@@ -302,11 +307,14 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
     return nbytes;
 }
 
+static void posix_aio_notify_event(void);
+
 static void *aio_thread(void *unused)
 {
-    pid_t pid;
-
-    pid = getpid();
+    mutex_lock(&lock);
+    pending_threads--;
+    mutex_unlock(&lock);
+    do_spawn_thread();
 
     while (1) {
         struct qemu_paiocb *aiocb;
@@ -322,7 +330,9 @@ static void *aio_thread(void *unused)
 
         while (QTAILQ_EMPTY(&request_list) &&
                !(ret == ETIMEDOUT)) {
+            idle_threads++;
             ret = cond_timedwait(&cond, &lock, &ts);
+            idle_threads--;
         }
 
         if (QTAILQ_EMPTY(&request_list))
@@ -331,11 +341,23 @@ static void *aio_thread(void *unused)
         aiocb = QTAILQ_FIRST(&request_list);
         QTAILQ_REMOVE(&request_list, aiocb, node);
         aiocb->active = 1;
-        idle_threads--;
         mutex_unlock(&lock);
 
         switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
         case QEMU_AIO_READ:
+            ret = handle_aiocb_rw(aiocb);
+            if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
+                /* A short read means that we have reached EOF. Pad the buffer
+                 * with zeros for bytes after EOF. */
+                QEMUIOVector qiov;
+
+                qemu_iovec_init_external(&qiov, aiocb->aio_iov,
+                                         aiocb->aio_niov);
+                qemu_iovec_memset_skip(&qiov, 0, aiocb->aio_nbytes - ret, ret);
+
+                ret = aiocb->aio_nbytes;
+            }
+            break;
         case QEMU_AIO_WRITE:
             ret = handle_aiocb_rw(aiocb);
             break;
@@ -353,25 +375,31 @@ static void *aio_thread(void *unused)
 
         mutex_lock(&lock);
         aiocb->ret = ret;
-        idle_threads++;
         mutex_unlock(&lock);
 
-        if (kill(pid, aiocb->ev_signo)) die("kill failed");
+        posix_aio_notify_event();
     }
 
-    idle_threads--;
     cur_threads--;
     mutex_unlock(&lock);
 
     return NULL;
 }
 
-static void spawn_thread(void)
+static void do_spawn_thread(void)
 {
     sigset_t set, oldset;
 
-    cur_threads++;
-    idle_threads++;
+    mutex_lock(&lock);
+    if (!new_threads) {
+        mutex_unlock(&lock);
+        return;
+    }
+
+    new_threads--;
+    pending_threads++;
+
+    mutex_unlock(&lock);
 
     /* block all signals */
     if (sigfillset(&set)) die("sigfillset");
@@ -382,6 +410,27 @@ static void spawn_thread(void)
     if (sigprocmask(SIG_SETMASK, &oldset, NULL)) die("sigprocmask restore");
 }
 
+static void spawn_thread_bh_fn(void *opaque)
+{
+    do_spawn_thread();
+}
+
+static void spawn_thread(void)
+{
+    cur_threads++;
+    new_threads++;
+    /* If there are threads being created, they will spawn new workers, so
+     * we don't spend time creating many threads in a loop holding a mutex or
+     * starving the current vcpu.
+     *
+     * If there are no idle threads, ask the main thread to create one, so we
+     * inherit the correct affinity instead of the vcpu affinity.
+     */
+    if (!pending_threads) {
+        qemu_bh_schedule(new_thread_bh);
+    }
+}
+
 static void qemu_paio_submit(struct qemu_paiocb *aiocb)
 {
     aiocb->ret = -EINPROGRESS;
@@ -423,7 +472,6 @@ static int posix_aio_process_queue(void *opaque)
     struct qemu_paiocb *acb, **pacb;
     int ret;
     int result = 0;
-    int async_context_id = get_async_context_id();
 
     for(;;) {
         pacb = &s->first_aio;
@@ -432,12 +480,6 @@ static int posix_aio_process_queue(void *opaque)
             if (!acb)
                 return result;
 
-            /* we're only interested in requests in the right context */
-            if (acb->async_context_id != async_context_id) {
-                pacb = &acb->next;
-                continue;
-            }
-
             ret = qemu_paio_error(acb);
             if (ret == ECANCELED) {
                 /* remove the request */
@@ -455,6 +497,9 @@ static int posix_aio_process_queue(void *opaque)
                 } else {
                     ret = -ret;
                 }
+
+                trace_paio_complete(acb, acb->common.opaque, ret);
+
                 /* remove the request */
                 *pacb = acb->next;
                 /* call the callback */
@@ -499,18 +544,14 @@ static int posix_aio_flush(void *opaque)
 
 static PosixAioState *posix_aio_state;
 
-static void aio_signal_handler(int signum)
+static void posix_aio_notify_event(void)
 {
-    if (posix_aio_state) {
-        char byte = 0;
-        ssize_t ret;
-
-        ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
-        if (ret < 0 && errno != EAGAIN)
-            die("write()");
-    }
+    char byte = 0;
+    ssize_t ret;
 
-    qemu_service_io();
+    ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
+    if (ret < 0 && errno != EAGAIN)
+        die("write()");
 }
 
 static void paio_remove(struct qemu_paiocb *acb)
@@ -537,6 +578,8 @@ static void paio_cancel(BlockDriverAIOCB *blockacb)
     struct qemu_paiocb *acb = (struct qemu_paiocb *)blockacb;
     int active = 0;
 
+    trace_paio_cancel(acb, acb->common.opaque);
+
     mutex_lock(&lock);
     if (!acb->active) {
         QTAILQ_REMOVE(&request_list, acb, node);
@@ -572,8 +615,6 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
         return NULL;
     acb->aio_type = type;
     acb->aio_fildes = fd;
-    acb->ev_signo = SIGUSR2;
-    acb->async_context_id = get_async_context_id();
 
     if (qiov) {
         acb->aio_iov = qiov->iov;
@@ -601,8 +642,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
         return NULL;
     acb->aio_type = QEMU_AIO_IOCTL;
     acb->aio_fildes = fd;
-    acb->ev_signo = SIGUSR2;
-    acb->async_context_id = get_async_context_id();
     acb->aio_offset = 0;
     acb->aio_ioctl_buf = buf;
     acb->aio_ioctl_cmd = req;
@@ -616,7 +655,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
 
 int paio_init(void)
 {
-    struct sigaction act;
     PosixAioState *s;
     int fds[2];
     int ret;
@@ -624,16 +662,12 @@ int paio_init(void)
     if (posix_aio_state)
         return 0;
 
-    s = qemu_malloc(sizeof(PosixAioState));
-
-    sigfillset(&act.sa_mask);
-    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
-    act.sa_handler = aio_signal_handler;
-    sigaction(SIGUSR2, &act, NULL);
+    s = g_malloc(sizeof(PosixAioState));
 
     s->first_aio = NULL;
     if (qemu_pipe(fds) == -1) {
         fprintf(stderr, "failed to create pipe\n");
+        g_free(s);
         return -1;
     }
 
@@ -655,6 +689,7 @@ int paio_init(void)
         die2(ret, "pthread_attr_setdetachstate");
 
     QTAILQ_INIT(&request_list);
+    new_thread_bh = qemu_bh_new(spawn_thread_bh_fn, NULL);
 
     posix_aio_state = s;
     return 0;
diff --git a/ppc.ld b/ppc.ld
index 5248ef15a540c272f16e3b6247ce7b5f86ce7d78..2a0dcad63da7f745dc32e5131bf1d4b50fa99bea 100644 (file)
--- a/ppc.ld
+++ b/ppc.ld
@@ -49,8 +49,20 @@ SECTIONS
   .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
   .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
   .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
-  .rel.plt        : { *(.rel.plt) }
-  .rela.plt       : { *(.rela.plt) }
+  .rel.plt      :
+  {
+    *(.rel.plt)
+    PROVIDE (__rel_iplt_start = .);
+    *(.rel.iplt)
+    PROVIDE (__rel_iplt_end = .);
+  }
+  .rela.plt       :
+  {
+    *(.rela.plt)
+    PROVIDE (__rela_iplt_start = .);
+    *(.rela.iplt)
+    PROVIDE (__rela_iplt_end = .);
+  }
   .init           :
   {
     KEEP (*(.init))
@@ -79,36 +91,34 @@ SECTIONS
   }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
index dea0dbda21c29b0e2377d937dfb0d1ae3b5dd814..e2dafa0b533bcf7a704639fb82fc041604902792 100644 (file)
--- a/ppc64.ld
+++ b/ppc64.ld
@@ -54,8 +54,20 @@ SECTIONS
       *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
       *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
     }
-  .rel.plt        : { *(.rel.plt) }
-  .rela.plt       : { *(.rela.plt) }
+  .rel.plt      :
+  {
+    *(.rel.plt)
+    PROVIDE (__rel_iplt_start = .);
+    *(.rel.iplt)
+    PROVIDE (__rel_iplt_end = .);
+  }
+  .rela.plt       :
+  {
+    *(.rela.plt)
+    PROVIDE (__rela_iplt_start = .);
+    *(.rela.iplt)
+    PROVIDE (__rela_iplt_end = .);
+  }
   .rela.tocbss   : { *(.rela.tocbss) }
   .init           :
   {
@@ -81,14 +93,12 @@ SECTIONS
   .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { KEEP (*(.gcc_except_table))
-*(.gcc_except_table.*) } /* Adjust the address for the data segment.  We want to
-adjust up to +     the same address within the page on the next page up.  */
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
   . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN
 (0x10000, 0x1000);   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { KEEP (*(.gcc_except_table))
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { KEEP (*(.gcc_except_table))
 *(.gcc_except_table.*) }   /* Thread Local Storage sections  */
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
new file mode 100644 (file)
index 0000000..fde5971
--- /dev/null
@@ -0,0 +1,217 @@
+# *-*- Mode: Python -*-*
+
+##
+# @guest-sync:
+#
+# Echo back a unique integer value
+#
+# This is used by clients talking to the guest agent over the
+# wire to ensure the stream is in sync and doesn't contain stale
+# data from previous client. All guest agent responses should be
+# ignored until the provided unique integer value is returned,
+# and it is up to the client to handle stale whole or
+# partially-delivered JSON text in such a way that this response
+# can be obtained.
+#
+# Such clients should also preceed this command
+# with a 0xFF byte to make such the guest agent flushes any
+# partially read JSON data from a previous session.
+#
+# @id: randomly generated 64-bit integer
+#
+# Returns: The unique integer id passed in by the client
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-sync'
+  'data':    { 'id': 'int' },
+  'returns': 'int' }
+
+##
+# @guest-ping:
+#
+# Ping the guest agent, a non-error return implies success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-ping' }
+
+##
+# @guest-info:
+#
+# Get some information about the guest agent.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestAgentInfo', 'data': {'version': 'str'} }
+{ 'command': 'guest-info',
+  'returns': 'GuestAgentInfo' }
+
+##
+# @guest-shutdown:
+#
+# Initiate guest-activated shutdown. Note: this is an asynchronous
+# shutdown request, with no guaruntee of successful shutdown. Errors
+# will be logged to guest's syslog.
+#
+# @mode: #optional "halt", "powerdown" (default), or "reboot"
+#
+# Returns: Nothing on success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } }
+
+##
+# @guest-file-open:
+#
+# Open a file in the guest and retrieve a file handle for it
+#
+# @filepath: Full path to the file in the guest to open.
+#
+# @mode: #optional open mode, as per fopen(), "r" is the default.
+#
+# Returns: Guest file handle on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-open',
+  'data':    { 'path': 'str', '*mode': 'str' },
+  'returns': 'int' }
+
+##
+# @guest-file-close:
+#
+# Close an open file in the guest
+#
+# @handle: filehandle returned by guest-file-open
+#
+# Returns: Nothing on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-close',
+  'data': { 'handle': 'int' } }
+
+##
+# @guest-file-read:
+#
+# Read from an open file in the guest. Data will be base64-encoded
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @count: #optional maximum number of bytes to read (default is 4KB)
+#
+# Returns: GuestFileRead on success. Note: count is number of bytes read
+#          *before* base64 encoding bytes read.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileRead',
+  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
+
+{ 'command': 'guest-file-read',
+  'data':    { 'handle': 'int', '*count': 'int' },
+  'returns': 'GuestFileRead' }
+
+##
+# @guest-file-write:
+#
+# Write to an open file in the guest.
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @buf-b64: base64-encoded string representing data to be written
+#
+# @count: #optional bytes to write (actual bytes, after base64-decode),
+#         default is all content in buf-b64 buffer after base64 decoding
+#
+# Returns: GuestFileWrite on success. Note: count is the number of bytes
+#          base64-decoded bytes written
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileWrite',
+  'data': { 'count': 'int', 'eof': 'bool' } }
+{ 'command': 'guest-file-write',
+  'data':    { 'handle': 'int', 'buf-b64': 'str', '*count': 'int' },
+  'returns': 'GuestFileWrite' }
+
+##
+# @guest-file-seek:
+#
+# Seek to a position in the file, as with fseek(), and return the
+# current file position afterward. Also encapsulates ftell()'s
+# functionality, just Set offset=0, whence=SEEK_CUR.
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @offset: bytes to skip over in the file stream
+#
+# @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
+#
+# Returns: GuestFileSeek on success.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileSeek',
+  'data': { 'position': 'int', 'eof': 'bool' } }
+
+{ 'command': 'guest-file-seek',
+  'data':    { 'handle': 'int', 'offset': 'int', 'whence': 'int' },
+  'returns': 'GuestFileSeek' }
+
+##
+# @guest-file-flush:
+#
+# Write file changes bufferred in userspace to disk/kernel buffers
+#
+# @handle: filehandle returned by guest-file-open
+#
+# Returns: Nothing on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-flush',
+  'data': { 'handle': 'int' } }
+
+##
+# @guest-fsfreeze-status:
+#
+# Get guest fsfreeze state. error state indicates failure to thaw 1 or more
+# previously frozen filesystems, or failure to open a previously cached
+# filesytem (filesystem unmounted/directory changes, etc).
+#
+# Returns: GuestFsfreezeStatus ("thawed", "frozen", etc., as defined below)
+#
+# Since: 0.15.0
+##
+{ 'enum': 'GuestFsfreezeStatus',
+  'data': [ 'thawed', 'frozen', 'error' ] }
+{ 'command': 'guest-fsfreeze-status',
+  'returns': 'GuestFsfreezeStatus' }
+
+##
+# @guest-fsfreeze-freeze:
+#
+# Sync and freeze all non-network guest filesystems
+#
+# Returns: Number of file systems frozen on success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-fsfreeze-freeze',
+  'returns': 'int' }
+
+##
+# @guest-fsfreeze-thaw:
+#
+# Unfreeze frozen guest fileystems
+#
+# Returns: Number of file systems thawed
+#          If error, -1 (unknown error) or -errno
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-fsfreeze-thaw',
+  'returns': 'int' }
diff --git a/qapi-schema-test.json b/qapi-schema-test.json
new file mode 100644 (file)
index 0000000..3acedad
--- /dev/null
@@ -0,0 +1,22 @@
+# *-*- Mode: Python -*-*
+
+# for testing enums
+{ 'enum': 'EnumOne',
+  'data': [ 'value1', 'value2', 'value3' ] }
+{ 'type': 'NestedEnumsOne',
+  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# for testing nested structs
+{ 'type': 'UserDefOne',
+  'data': { 'integer': 'int', 'string': 'str' } }
+
+{ 'type': 'UserDefTwo',
+  'data': { 'string': 'str',
+            'dict': { 'string': 'str',
+                      'dict': { 'userdef': 'UserDefOne', 'string': 'str' },
+                      '*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' }
diff --git a/qapi-schema.json b/qapi-schema.json
new file mode 100644 (file)
index 0000000..cb1ba77
--- /dev/null
@@ -0,0 +1,889 @@
+# -*- Mode: Python -*-
+#
+# QAPI Schema
+
+##
+# @NameInfo:
+#
+# Guest name information.
+#
+# @name: #optional The name of the guest
+#
+# Since 0.14.0
+##
+{ 'type': 'NameInfo', 'data': {'*name': 'str'} }
+
+##
+# @query-name:
+#
+# Return the name information of a guest.
+#
+# Returns: @NameInfo of the guest
+#
+# Since 0.14.0
+##
+{ 'command': 'query-name', 'returns': 'NameInfo' }
+
+##
+# @VersionInfo:
+#
+# A description of QEMU's version.
+#
+# @qemu.major:  The major version of QEMU
+#
+# @qemu.minor:  The minor version of QEMU
+#
+# @qemu.micro:  The micro version of QEMU.  By current convention, a micro
+#               version of 50 signifies a development branch.  A micro version
+#               greater than or equal to 90 signifies a release candidate for
+#               the next minor version.  A micro version of less than 50
+#               signifies a stable release.
+#
+# @package:     QEMU will always set this field to an empty string.  Downstream
+#               versions of QEMU should set this to a non-empty string.  The
+#               exact format depends on the downstream however it highly
+#               recommended that a unique name is used.
+#
+# Since: 0.14.0
+##
+{ 'type': 'VersionInfo',
+  'data': {'qemu': {'major': 'int', 'minor': 'int', 'micro': 'int'},
+           'package': 'str'} }
+
+##
+# @query-version:
+#
+# Returns the current version of QEMU.
+#
+# Returns:  A @VersionInfo object describing the current version of QEMU.
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-version', 'returns': 'VersionInfo' }
+
+##
+# @KvmInfo:
+#
+# Information about support for KVM acceleration
+#
+# @enabled: true if KVM acceleration is active
+#
+# @present: true if KVM acceleration is built into this executable
+#
+# Since: 0.14.0
+##
+{ 'type': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
+
+##
+# @query-kvm:
+#
+# Returns information about KVM acceleration
+#
+# Returns: @KvmInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
+
+##
+# @RunState
+#
+# An enumation of VM run states.
+#
+# @debug: QEMU is running on a debugger
+#
+# @inmigrate: guest is paused waiting for an incoming migration
+#
+# @internal-error: An internal error that prevents further guest execution
+# has occurred
+#
+# @io-error: the last IOP has failed and the device is configured to pause
+# on I/O errors
+#
+# @paused: guest has been paused via the 'stop' command
+#
+# @postmigrate: guest is paused following a successful 'migrate'
+#
+# @prelaunch: QEMU was started with -S and guest has not started
+#
+# @finish-migrate: guest is paused to finish the migration process
+#
+# @restore-vm: guest is paused to restore VM state
+#
+# @running: guest is actively running
+#
+# @save-vm: guest is paused to save the VM state
+#
+# @shutdown: guest is shut down (and -no-shutdown is in use)
+#
+# @watchdog: the watchdog action is configured to pause and has been triggered
+##
+{ 'enum': 'RunState',
+  'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
+            'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
+            'running', 'save-vm', 'shutdown', 'watchdog' ] }
+
+##
+# @StatusInfo:
+#
+# Information about VCPU run state
+#
+# @running: true if all VCPUs are runnable, false if not runnable
+#
+# @singlestep: true if VCPUs are in single-step mode
+#
+# @status: the virtual machine @RunState
+#
+# Since:  0.14.0
+#
+# Notes: @singlestep is enabled through the GDB stub
+##
+{ 'type': 'StatusInfo',
+  'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} }
+
+##
+# @query-status:
+#
+# Query the run status of all VCPUs
+#
+# Returns: @StatusInfo reflecting all VCPUs
+#
+# Since:  0.14.0
+##
+{ 'command': 'query-status', 'returns': 'StatusInfo' }
+
+##
+# @UuidInfo:
+#
+# Guest UUID information.
+#
+# @UUID: the UUID of the guest
+#
+# Since: 0.14.0
+#
+# Notes: If no UUID was specified for the guest, a null UUID is returned.
+##
+{ 'type': 'UuidInfo', 'data': {'UUID': 'str'} }
+
+##
+# @query-uuid:
+#
+# Query the guest UUID information.
+#
+# Returns: The @UuidInfo for the guest
+#
+# Since 0.14.0
+##
+{ 'command': 'query-uuid', 'returns': 'UuidInfo' }
+
+##
+# @ChardevInfo:
+#
+# Information about a character device.
+#
+# @label: the label of the character device
+#
+# @filename: the filename of the character device
+#
+# Notes: @filename is encoded using the QEMU command line character device
+#        encoding.  See the QEMU man page for details.
+#
+# Since: 0.14.0
+##
+{ 'type': 'ChardevInfo', 'data': {'label': 'str', 'filename': 'str'} }
+
+##
+# @query-chardev:
+#
+# Returns information about current character devices.
+#
+# Returns: a list of @ChardevInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
+
+##
+# @CommandInfo:
+#
+# Information about a QMP command
+#
+# @name: The command name
+#
+# Since: 0.14.0
+##
+{ 'type': 'CommandInfo', 'data': {'name': 'str'} }
+
+##
+# @query-commands:
+#
+# Return a list of supported QMP commands by this server
+#
+# Returns: A list of @CommandInfo for all supported commands
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+
+##
+# @MigrationStats
+#
+# Detailed migration status.
+#
+# @transferred: amount of bytes already transferred to the target VM
+#
+# @remaining: amount of bytes remaining to be transferred to the target VM
+#
+# @total: total amount of bytes involved in the migration process
+#
+# Since: 0.14.0.
+##
+{ 'type': 'MigrationStats',
+  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' } }
+
+##
+# @MigrationInfo
+#
+# Information about current migration process.
+#
+# @status: #optional string describing the current migration status.
+#          As of 0.14.0 this can be 'active', 'completed', 'failed' or
+#          'cancelled'. If this field is not returned, no migration process
+#          has been initiated
+#
+# @ram: #optional @MigrationStats containing detailed migration status,
+#       only returned if status is 'active'
+#
+# @disk: #optional @MigrationStats containing detailed disk migration
+#        status, only returned if status is 'active' and it is a block
+#        migration
+#
+# Since: 0.14.0
+##
+{ 'type': 'MigrationInfo',
+  'data': {'*status': 'str', '*ram': 'MigrationStats',
+           '*disk': 'MigrationStats'} }
+
+##
+# @query-migrate
+#
+# Returns information about current migration process.
+#
+# Returns: @MigrationInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
+
+##
+# @MouseInfo:
+#
+# Information about a mouse device.
+#
+# @name: the name of the mouse device
+#
+# @index: the index of the mouse device
+#
+# @current: true if this device is currently receiving mouse events
+#
+# @absolute: true if this device supports absolute coordinates as input
+#
+# Since: 0.14.0
+##
+{ 'type': 'MouseInfo',
+  'data': {'name': 'str', 'index': 'int', 'current': 'bool',
+           'absolute': 'bool'} }
+
+##
+# @query-mice:
+#
+# Returns information about each active mouse device
+#
+# Returns: a list of @MouseInfo for each device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-mice', 'returns': ['MouseInfo'] }
+
+##
+# @CpuInfo:
+#
+# Information about a virtual CPU
+#
+# @CPU: the index of the virtual CPU
+#
+# @current: this only exists for backwards compatible and should be ignored
+# 
+# @halted: true if the virtual CPU is in the halt state.  Halt usually refers
+#          to a processor specific low power mode.
+#
+# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
+#                pointer.
+#                If the target is Sparc, this is the PC component of the
+#                instruction pointer.
+#
+# @nip: #optional If the target is PPC, the instruction pointer
+#
+# @npc: #optional If the target is Sparc, the NPC component of the instruction
+#                 pointer
+#
+# @PC: #optional If the target is MIPS, the instruction pointer
+#
+# @thread_id: ID of the underlying host thread
+#
+# Since: 0.14.0
+#
+# Notes: @halted is a transient state that changes frequently.  By the time the
+#        data is sent to the client, the guest may no longer be halted.
+##
+{ 'type': 'CpuInfo',
+  'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int',
+           '*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} }
+
+##
+# @query-cpus:
+#
+# Returns a list of information about each virtual CPU.
+#
+# Returns: a list of @CpuInfo for each virtual CPU
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+
+##
+# @BlockDeviceInfo:
+#
+# Information about the backing device for a block device.
+#
+# @file: the filename of the backing device
+#
+# @ro: true if the backing device was open read-only
+#
+# @drv: the name of the block format used to open the backing device. As of
+#       0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
+#       'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
+#       'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
+#       'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
+#
+# @backing_file: #optional the name of the backing file (for copy-on-write)
+#
+# @encrypted: true if the backing device is encrypted
+#
+# Since: 0.14.0
+#
+# Notes: This interface is only found in @BlockInfo.
+##
+{ 'type': 'BlockDeviceInfo',
+  'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
+            '*backing_file': 'str', 'encrypted': 'bool' } }
+
+##
+# @BlockDeviceIoStatus:
+#
+# An enumeration of block device I/O status.
+#
+# @ok: The last I/O operation has succeeded
+#
+# @failed: The last I/O operation has failed
+#
+# @nospace: The last I/O operation has failed due to a no-space condition
+#
+# Since: 1.0
+##
+{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
+
+##
+# @BlockInfo:
+#
+# Block device information.  This structure describes a virtual device and
+# the backing device associated with it.
+#
+# @device: The device name associated with the virtual device.
+#
+# @type: This field is returned only for compatibility reasons, it should
+#        not be used (always returns 'unknown')
+#
+# @removable: True if the device supports removable media.
+#
+# @locked: True if the guest has locked this device from having its media
+#          removed
+#
+# @tray_open: #optional True if the device has a tray and it is open
+#             (only present if removable is true)
+#
+# @io-status: #optional @BlockDeviceIoStatus. Only present if the device
+#             supports it and the VM is configured to stop on errors
+#
+# @inserted: #optional @BlockDeviceInfo describing the device if media is
+#            present
+#
+# Since:  0.14.0
+##
+{ 'type': 'BlockInfo',
+  'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
+           'locked': 'bool', '*inserted': 'BlockDeviceInfo',
+           '*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus'} }
+
+##
+# @query-block:
+#
+# Get a list of BlockInfo for all virtual block devices.
+#
+# Returns: a list of @BlockInfo describing each virtual block device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-block', 'returns': ['BlockInfo'] }
+
+##
+# @BlockDeviceStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @rd_bytes:      The number of bytes read by the device.
+#
+# @wr_bytes:      The number of bytes written by the device.
+#
+# @rd_operations: The number of read operations performed by the device.
+#
+# @wr_operations: The number of write operations performed by the device.
+#
+# @flush_operations: The number of cache flush operations performed by the
+#                    device (since 0.15.0)
+#
+# @flush_total_time_ns: Total time spend on cache flushes in nano-seconds
+#                       (since 0.15.0).
+#
+# @wr_total_time_ns: Total time spend on writes in nano-seconds (since 0.15.0).
+#
+# @rd_total_time_ns: Total_time_spend on reads in nano-seconds (since 0.15.0).
+#
+# @wr_highest_offset: The offset after the greatest byte written to the
+#                     device.  The intended use of this information is for
+#                     growable sparse files (like qcow2) that are used on top
+#                     of a physical device.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockDeviceStats',
+  'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int',
+           'wr_operations': 'int', 'flush_operations': 'int',
+           'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int',
+           'rd_total_time_ns': 'int', 'wr_highest_offset': 'int' } }
+
+##
+# @BlockStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @device: #optional If the stats are for a virtual block device, the name
+#          corresponding to the virtual block device.
+#
+# @stats:  A @BlockDeviceStats for the device.
+#
+# @parent: #optional This may point to the backing block device if this is a
+#          a virtual block device.  If it's a backing block, this will point
+#          to the backing file is one is present.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockStats',
+  'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
+           '*parent': 'BlockStats'} }
+
+##
+# @query-blockstats:
+#
+# Query the @BlockStats for all virtual block devices.
+#
+# Returns: A list of @BlockStats for each virtual block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-blockstats', 'returns': ['BlockStats'] }
+
+##
+# @VncClientInfo:
+#
+# Information about a connected VNC client.
+#
+# @host: The host name of the client.  QEMU tries to resolve this to a DNS name
+#        when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+#          'ipv4' if the client is connected via IPv4 and TCP
+#          'unix' if the client is connected via a unix domain socket
+#          'unknown' otherwise
+#
+# @service: The service name of the client's port.  This may depends on the
+#           host system's service database so symbolic names should not be
+#           relied on.
+#
+# @x509_dname: #optional If x509 authentication is in use, the Distinguished
+#              Name of the client.
+#
+# @sasl_username: #optional If SASL authentication is in use, the SASL username
+#                 used for authentication.
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncClientInfo',
+  'data': {'host': 'str', 'family': 'str', 'service': 'str',
+           '*x509_dname': 'str', '*sasl_username': 'str'} }
+
+##
+# @VncInfo:
+#
+# Information about the VNC session.
+#
+# @enabled: true if the VNC server is enabled, false otherwise
+#
+# @host: #optional The hostname the VNC server is bound to.  This depends on
+#        the name resolution on the host and may be an IP address.
+#
+# @family: #optional 'ipv6' if the host is listening for IPv6 connections
+#                    'ipv4' if the host is listening for IPv4 connections
+#                    'unix' if the host is listening on a unix domain socket
+#                    'unknown' otherwise
+#
+# @service: #optional The service name of the server's port.  This may depends
+#           on the host system's service database so symbolic names should not
+#           be relied on.
+#
+# @auth: #optional the current authentication type used by the server
+#        'none' if no authentication is being used
+#        'vnc' if VNC authentication is being used
+#        'vencrypt+plain' if VEncrypt is used with plain text authentication
+#        'vencrypt+tls+none' if VEncrypt is used with TLS and no authentication
+#        'vencrypt+tls+vnc' if VEncrypt is used with TLS and VNC authentication
+#        'vencrypt+tls+plain' if VEncrypt is used with TLS and plain text auth
+#        'vencrypt+x509+none' if VEncrypt is used with x509 and no auth
+#        'vencrypt+x509+vnc' if VEncrypt is used with x509 and VNC auth
+#        'vencrypt+x509+plain' if VEncrypt is used with x509 and plain text auth
+#        'vencrypt+tls+sasl' if VEncrypt is used with TLS and SASL auth
+#        'vencrypt+x509+sasl' if VEncrypt is used with x509 and SASL auth
+#
+# @clients: a list of @VncClientInfo of all currently connected clients
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncInfo',
+  'data': {'enabled': 'bool', '*host': 'str', '*family': 'str',
+           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
+
+##
+# @query-vnc:
+#
+# Returns information about the current VNC server
+#
+# Returns: @VncInfo
+#          If VNC support is not compiled in, FeatureDisabled
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-vnc', 'returns': 'VncInfo' }
+
+##
+# @SpiceChannel
+#
+# Information about a SPICE client channel.
+#
+# @host: The host name of the client.  QEMU tries to resolve this to a DNS name
+#        when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+#          'ipv4' if the client is connected via IPv4 and TCP
+#          'unix' if the client is connected via a unix domain socket
+#          'unknown' otherwise
+#
+# @port: The client's port number.
+#
+# @connection-id: SPICE connection id number.  All channels with the same id
+#                 belong to the same SPICE session.
+#
+# @connection-type: SPICE channel type number.  "1" is the main control channel,
+#                   filter for this one if you want track spice sessions only
+#
+# @channel-id: SPICE channel ID number.  Usually "0", might be different needed
+#              when multiple channels of the same type exist, such as multiple
+#              display channels in a multihead setup
+#
+# @tls: true if the channel is encrypted, false otherwise.
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceChannel',
+  'data': {'host': 'str', 'family': 'str', 'port': 'str',
+           'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
+           'tls': 'bool'} }
+
+##
+# @SpiceInfo
+#
+# Information about the SPICE session.
+# 
+# @enabled: true if the SPICE server is enabled, false otherwise
+#
+# @host: #optional The hostname the SPICE server is bound to.  This depends on
+#        the name resolution on the host and may be an IP address.
+#
+# @port: #optional The SPICE server's port number.
+#
+# @compiled-version: #optional SPICE server version.
+#
+# @tls-port: #optional The SPICE server's TLS port number.
+#
+# @auth: #optional the current authentication type used by the server
+#        'none' if no authentication is being used
+#        'spice' (TODO: describe)
+#
+# @channels: a list of @SpiceChannel for each active spice channel
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceInfo',
+  'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
+           '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
+           '*channels': ['SpiceChannel']} }
+
+##
+# @query-spice
+#
+# Returns information about the current SPICE server
+#
+# Returns: @SpiceInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
+
+##
+# @BalloonInfo:
+#
+# Information about the guest balloon device.
+#
+# @actual: the number of bytes the balloon currently contains
+#
+# @mem_swapped_in: #optional number of pages swapped in within the guest
+#
+# @mem_swapped_out: #optional number of pages swapped out within the guest
+#
+# @major_page_faults: #optional number of major page faults within the guest
+#
+# @minor_page_faults: #optional number of minor page faults within the guest
+#
+# @free_mem: #optional amount of memory (in bytes) free in the guest
+#
+# @total_mem: #optional amount of memory (in bytes) visible to the guest
+#
+# Since: 0.14.0
+#
+# Notes: all current versions of QEMU do not fill out optional information in
+#        this structure.
+##
+{ 'type': 'BalloonInfo',
+  'data': {'actual': 'int', '*mem_swapped_in': 'int',
+           '*mem_swapped_out': 'int', '*major_page_faults': 'int',
+           '*minor_page_faults': 'int', '*free_mem': 'int',
+           '*total_mem': 'int'} }
+
+##
+# @query-balloon:
+#
+# Return information about the balloon device.
+#
+# Returns: @BalloonInfo on success
+#          If the balloon driver is enabled but not functional because the KVM
+#          kernel module cannot support it, KvmMissingCap
+#          If no balloon device is present, DeviceNotActive
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
+
+##
+# @PciMemoryRange:
+#
+# A PCI device memory region
+#
+# @base: the starting address (guest physical)
+#
+# @limit: the ending address (guest physical)
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
+
+##
+# @PciMemoryRegion
+#
+# Information about a PCI device I/O region.
+#
+# @bar: the index of the Base Address Register for this region
+#
+# @type: 'io' if the region is a PIO region
+#        'memory' if the region is a MMIO region
+#
+# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
+#
+# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRegion',
+  'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
+           '*prefetch': 'bool', '*mem_type_64': 'bool' } }
+
+##
+# @PciBridgeInfo:
+#
+# Information about a PCI Bridge device
+#
+# @bus.number: primary bus interface number.  This should be the number of the
+#              bus the device resides on.
+#
+# @bus.secondary: secondary bus interface number.  This is the number of the
+#                 main bus for the bridge
+#
+# @bus.subordinate: This is the highest number bus that resides below the
+#                   bridge.
+#
+# @bus.io_range: The PIO range for all devices on this bridge
+#
+# @bus.memory_range: The MMIO range for all devices on this bridge
+#
+# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
+#                          this bridge
+#
+# @devices: a list of @PciDeviceInfo for each device on this bridge
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciBridgeInfo',
+  'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
+                    'io_range': 'PciMemoryRange',
+                    'memory_range': 'PciMemoryRange',
+                    'prefetchable_range': 'PciMemoryRange' },
+           '*devices': ['PciDeviceInfo']} }
+
+##
+# @PciDeviceInfo:
+#
+# Information about a PCI device
+#
+# @bus: the bus number of the device
+#
+# @slot: the slot the device is located in
+#
+# @function: the function of the slot used by the device
+#
+# @class_info.desc: #optional a string description of the device's class
+#
+# @class_info.class: the class code of the device
+#
+# @id.device: the PCI device id
+#
+# @id.vendor: the PCI vendor id
+#
+# @irq: #optional if an IRQ is assigned to the device, the IRQ number
+#
+# @qdev_id: the device name of the PCI device
+#
+# @pci_bridge: if the device is a PCI bridge, the bridge information
+#
+# @regions: a list of the PCI I/O regions associated with the device
+#
+# Notes: the contents of @class_info.desc are not stable and should only be
+#        treated as informational.
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciDeviceInfo',
+  'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
+           'class_info': {'*desc': 'str', 'class': 'int'},
+           'id': {'device': 'int', 'vendor': 'int'},
+           '*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
+           'regions': ['PciMemoryRegion']} }
+
+##
+# @PciInfo:
+#
+# Information about a PCI bus
+#
+# @bus: the bus index
+#
+# @devices: a list of devices on this bus
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
+
+##
+# @query-pci:
+#
+# Return information about the PCI bus topology of the guest.
+#
+# Returns: a list of @PciInfo for each PCI bus
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-pci', 'returns': ['PciInfo'] }
+
+##
+# @quit:
+#
+# This command will cause the QEMU process to exit gracefully.  While every
+# attempt is made to send the QMP response before terminating, this is not
+# guaranteed.  When using this interface, a premature EOF would not be
+# unexpected.
+#
+# Since: 0.14.0
+##
+{ 'command': 'quit' }
+
+##
+# @stop:
+#
+# Stop all guest VCPU execution.
+#
+# Since:  0.14.0
+#
+# Notes:  This function will succeed even if the guest is already in the stopped
+#         state
+##
+{ 'command': 'stop' }
+
+##
+# @system_reset:
+#
+# Performs a hard reset of a guest.
+#
+# Since: 0.14.0
+##
+{ 'command': 'system_reset' }
+
+##
+# @system_powerdown:
+#
+# Requests that a guest perform a powerdown operation.
+#
+# Since: 0.14.0
+#
+# Notes: A guest may or may not respond to this command.  This command
+#        returning does not indicate that a guest has accepted the request or
+#        that it has shut down.  Many guests will respond to this command by
+#        prompting the user in some way.
+##
+{ 'command': 'system_powerdown' }
+
+##
+# @cpu:
+#
+# This command is a nop that is only provided for the purposes of compatibility.
+#
+# Since: 0.14.0
+#
+# Notes: Do not use this command.
+##
+{ 'command': 'cpu', 'data': {'index': 'int'} }
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
new file mode 100644 (file)
index 0000000..a154523
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi-dealloc-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+    void *value;
+    bool is_list_head;
+    QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisitor
+{
+    Visitor visitor;
+    QTAILQ_HEAD(, StackEntry) stack;
+    bool is_list_head;
+};
+
+static QapiDeallocVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QapiDeallocVisitor, visitor);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
+{
+    StackEntry *e = g_malloc0(sizeof(*e));
+
+    e->value = value;
+
+    /* see if we're just pushing a list head tracker */
+    if (value == NULL) {
+        e->is_list_head = true;
+    }
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
+{
+    StackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    g_free(e);
+    return value;
+}
+
+static void qapi_dealloc_start_struct(Visitor *v, void **obj, const char *kind,
+                                      const char *name, size_t unused,
+                                      Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    void **obj = qapi_dealloc_pop(qov);
+    if (obj) {
+        g_free(*obj);
+    }
+}
+
+static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    qapi_dealloc_push(qov, NULL);
+}
+
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
+                                           Error **errp)
+{
+    GenericList *list = *listp;
+    QapiDeallocVisitor *qov = to_qov(v);
+    StackEntry *e = QTAILQ_FIRST(&qov->stack);
+
+    if (e && e->is_list_head) {
+        e->is_list_head = false;
+        return list;
+    }
+
+    if (list) {
+        list = list->next;
+        g_free(*listp);
+        return list;
+    }
+
+    return NULL;
+}
+
+static void qapi_dealloc_end_list(Visitor *v, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    void *obj = qapi_dealloc_pop(qov);
+    assert(obj == NULL); /* should've been list head tracker with no payload */
+}
+
+static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name,
+                                  Error **errp)
+{
+    if (obj) {
+        g_free(*obj);
+    }
+}
+
+static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name,
+                                  Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visitor *v, bool *obj, const char *name,
+                                   Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name,
+                                     Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[],
+                                   const char *kind, const char *name,
+                                   Error **errp)
+{
+}
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
+{
+    g_free(v);
+}
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
+{
+    QapiDeallocVisitor *v;
+
+    v = g_malloc0(sizeof(*v));
+
+    v->visitor.start_struct = qapi_dealloc_start_struct;
+    v->visitor.end_struct = qapi_dealloc_end_struct;
+    v->visitor.start_list = qapi_dealloc_start_list;
+    v->visitor.next_list = qapi_dealloc_next_list;
+    v->visitor.end_list = qapi_dealloc_end_list;
+    v->visitor.type_enum = qapi_dealloc_type_enum;
+    v->visitor.type_int = qapi_dealloc_type_int;
+    v->visitor.type_bool = qapi_dealloc_type_bool;
+    v->visitor.type_str = qapi_dealloc_type_str;
+    v->visitor.type_number = qapi_dealloc_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qapi-dealloc-visitor.h b/qapi/qapi-dealloc-visitor.h
new file mode 100644 (file)
index 0000000..5842bc7
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_DEALLOC_VISITOR_H
+#define QAPI_DEALLOC_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisitor QapiDeallocVisitor;
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
+
+#endif
diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
new file mode 100644 (file)
index 0000000..27e6be0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Core Definitions for QAPI-generated Types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_TYPES_CORE_H
+#define QAPI_TYPES_CORE_H
+
+#include "qemu-common.h"
+#include "error.h"
+
+/* FIXME this is temporary until we remove middle mode */
+#include "monitor.h"
+
+#endif
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
new file mode 100644 (file)
index 0000000..ddef3ed
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-visit-core.h"
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind,
+                        const char *name, Error **errp)
+{
+    if (!error_is_set(errp) && v->start_handle) {
+        v->start_handle(v, obj, kind, name, errp);
+    }
+}
+
+void visit_end_handle(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_handle) {
+        v->end_handle(v, errp);
+    }
+}
+
+void visit_start_struct(Visitor *v, void **obj, const char *kind,
+                        const char *name, size_t size, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_struct(v, obj, kind, name, size, errp);
+    }
+}
+
+void visit_end_struct(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_struct(v, errp);
+    }
+}
+
+void visit_start_list(Visitor *v, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_list(v, name, errp);
+    }
+}
+
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        return v->next_list(v, list, errp);
+    }
+
+    return 0;
+}
+
+void visit_end_list(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_list(v, errp);
+    }
+}
+
+void visit_start_optional(Visitor *v, bool *present, const char *name,
+                          Error **errp)
+{
+    if (!error_is_set(errp) && v->start_optional) {
+        v->start_optional(v, present, name, errp);
+    }
+}
+
+void visit_end_optional(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_optional) {
+        v->end_optional(v, errp);
+    }
+}
+
+void visit_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_enum(v, obj, strings, kind, name, errp);
+    }
+}
+
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_int(v, obj, name, errp);
+    }
+}
+
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_bool(v, obj, name, errp);
+    }
+}
+
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_str(v, obj, name, errp);
+    }
+}
+
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_number(v, obj, name, errp);
+    }
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
new file mode 100644 (file)
index 0000000..e850746
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QAPI_VISITOR_CORE_H
+#define QAPI_VISITOR_CORE_H
+
+#include "qapi/qapi-types-core.h"
+#include <stdlib.h>
+
+typedef struct GenericList
+{
+    void *value;
+    struct GenericList *next;
+} GenericList;
+
+typedef struct Visitor Visitor;
+
+struct Visitor
+{
+    /* Must be set */
+    void (*start_struct)(Visitor *v, void **obj, const char *kind,
+                         const char *name, size_t size, Error **errp);
+    void (*end_struct)(Visitor *v, Error **errp);
+
+    void (*start_list)(Visitor *v, const char *name, Error **errp);
+    GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
+    void (*end_list)(Visitor *v, Error **errp);
+
+    void (*type_enum)(Visitor *v, int *obj, const char *strings[],
+                      const char *kind, const char *name, Error **errp);
+
+    void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
+    void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
+    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
+    void (*type_number)(Visitor *v, double *obj, const char *name,
+                        Error **errp);
+
+    /* May be NULL */
+    void (*start_optional)(Visitor *v, bool *present, const char *name,
+                           Error **errp);
+    void (*end_optional)(Visitor *v, Error **errp);
+
+    void (*start_handle)(Visitor *v, void **obj, const char *kind,
+                         const char *name, Error **errp);
+    void (*end_handle)(Visitor *v, Error **errp);
+};
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind,
+                        const char *name, Error **errp);
+void visit_end_handle(Visitor *v, Error **errp);
+void visit_start_struct(Visitor *v, void **obj, const char *kind,
+                        const char *name, size_t size, Error **errp);
+void visit_end_struct(Visitor *v, Error **errp);
+void visit_start_list(Visitor *v, const char *name, Error **errp);
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
+void visit_end_list(Visitor *v, Error **errp);
+void visit_start_optional(Visitor *v, bool *present, const char *name,
+                          Error **errp);
+void visit_end_optional(Visitor *v, Error **errp);
+void visit_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name, Error **errp);
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+
+#endif
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
new file mode 100644 (file)
index 0000000..f1c26e4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_CORE_H
+#define QMP_CORE_H
+
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+
+typedef enum QmpCommandType
+{
+    QCT_NORMAL,
+} QmpCommandType;
+
+typedef struct QmpCommand
+{
+    const char *name;
+    QmpCommandType type;
+    QmpCommandFunc *fn;
+    QTAILQ_ENTRY(QmpCommand) node;
+} QmpCommand;
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn);
+QmpCommand *qmp_find_command(const char *name);
+QObject *qmp_dispatch(QObject *request);
+
+#endif
+
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
new file mode 100644 (file)
index 0000000..5584693
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+#include "error.h"
+#include "error_int.h"
+#include "qerror.h"
+
+static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
+{
+    const QDictEntry *ent;
+    const char *arg_name;
+    const QObject *arg_obj;
+    bool has_exec_key = false;
+    QDict *dict = NULL;
+
+    if (qobject_type(request) != QTYPE_QDICT) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT,
+                  "request is not a dictionary");
+        return NULL;
+    }
+
+    dict = qobject_to_qdict(request);
+
+    for (ent = qdict_first(dict); ent;
+         ent = qdict_next(dict, ent)) {
+        arg_name = qdict_entry_key(ent);
+        arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                error_set(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
+                          "string");
+                return NULL;
+            }
+            has_exec_key = true;
+        } else if (strcmp(arg_name, "arguments")) {
+            error_set(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    return dict;
+}
+
+static QObject *do_qmp_dispatch(QObject *request, Error **errp)
+{
+    const char *command;
+    QDict *args, *dict;
+    QmpCommand *cmd;
+    QObject *ret = NULL;
+
+
+    dict = qmp_dispatch_check_obj(request, errp);
+    if (!dict || error_is_set(errp)) {
+        return NULL;
+    }
+
+    command = qdict_get_str(dict, "execute");
+    cmd = qmp_find_command(command);
+    if (cmd == NULL) {
+        error_set(errp, QERR_COMMAND_NOT_FOUND, command);
+        return NULL;
+    }
+
+    if (!qdict_haskey(dict, "arguments")) {
+        args = qdict_new();
+    } else {
+        args = qdict_get_qdict(dict, "arguments");
+        QINCREF(args);
+    }
+
+    switch (cmd->type) {
+    case QCT_NORMAL:
+        cmd->fn(args, &ret, errp);
+        if (!error_is_set(errp) && ret == NULL) {
+            ret = QOBJECT(qdict_new());
+        }
+        break;
+    }
+
+    QDECREF(args);
+
+    return ret;
+}
+
+QObject *qmp_dispatch(QObject *request)
+{
+    Error *err = NULL;
+    QObject *ret;
+    QDict *rsp;
+
+    ret = do_qmp_dispatch(request, &err);
+
+    rsp = qdict_new();
+    if (err) {
+        qdict_put_obj(rsp, "error", error_get_qobject(err));
+        error_free(err);
+    } else if (ret) {
+        qdict_put_obj(rsp, "return", ret);
+    } else {
+        QDECREF(rsp);
+        return NULL;
+    }
+
+    return QOBJECT(rsp);
+}
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
new file mode 100644 (file)
index 0000000..8cbc0ab
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-input-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+    const QObject *obj;
+    const  QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisitor
+{
+    Visitor visitor;
+    QObject *obj;
+    StackObject stack[QIV_STACK_SIZE];
+    int nb_stack;
+};
+
+static QmpInputVisitor *to_qiv(Visitor *v)
+{
+    return container_of(v, QmpInputVisitor, visitor);
+}
+
+static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
+                                           const char *name)
+{
+    const QObject *qobj;
+
+    if (qiv->nb_stack == 0) {
+        qobj = qiv->obj;
+    } else {
+        qobj = qiv->stack[qiv->nb_stack - 1].obj;
+    }
+
+    if (name && qobject_type(qobj) == QTYPE_QDICT) {
+        return qdict_get(qobject_to_qdict(qobj), name);
+    } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
+    }
+
+    return qobj;
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+{
+    qiv->stack[qiv->nb_stack].obj = obj;
+    if (qobject_type(obj) == QTYPE_QLIST) {
+        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
+    }
+    qiv->nb_stack++;
+
+    if (qiv->nb_stack >= QIV_STACK_SIZE) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
+{
+    qiv->nb_stack--;
+    if (qiv->nb_stack < 0) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
+                                   const char *name, size_t size, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "QDict");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (obj) {
+        *obj = g_malloc0(size);
+    }
+}
+
+static void qmp_input_end_struct(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "list");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+}
+
+static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
+                                        Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    GenericList *entry;
+    StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+
+    if (so->entry == NULL) {
+        return NULL;
+    }
+
+    entry = g_malloc0(sizeof(*entry));
+    if (*list) {
+        so->entry = qlist_next(so->entry);
+        if (so->entry == NULL) {
+            g_free(entry);
+            return NULL;
+        }
+        (*list)->next = entry;
+    }
+
+    return entry;
+}
+
+static void qmp_input_end_list(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
+                               Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "integer");
+        return;
+    }
+
+    *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
+                                Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "boolean");
+        return;
+    }
+
+    *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
+                               Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "string");
+        return;
+    }
+
+    *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
+                                  Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "double");
+        return;
+    }
+
+    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
+                                const char *kind, const char *name,
+                                Error **errp)
+{
+    int64_t value = 0;
+    char *enum_str;
+
+    assert(strings);
+
+    qmp_input_type_str(v, &enum_str, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    while (strings[value] != NULL) {
+        if (strcmp(strings[value], enum_str) == 0) {
+            break;
+        }
+        value++;
+    }
+
+    if (strings[value] == NULL) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        g_free(enum_str);
+        return;
+    }
+
+    g_free(enum_str);
+    *obj = value;
+}
+
+static void qmp_input_start_optional(Visitor *v, bool *present,
+                                     const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj) {
+        *present = false;
+        return;
+    }
+
+    *present = true;
+}
+
+static void qmp_input_end_optional(Visitor *v, Error **errp)
+{
+}
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_input_visitor_cleanup(QmpInputVisitor *v)
+{
+    qobject_decref(v->obj);
+    g_free(v);
+}
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
+{
+    QmpInputVisitor *v;
+
+    v = g_malloc0(sizeof(*v));
+
+    v->visitor.start_struct = qmp_input_start_struct;
+    v->visitor.end_struct = qmp_input_end_struct;
+    v->visitor.start_list = qmp_input_start_list;
+    v->visitor.next_list = qmp_input_next_list;
+    v->visitor.end_list = qmp_input_end_list;
+    v->visitor.type_enum = qmp_input_type_enum;
+    v->visitor.type_int = qmp_input_type_int;
+    v->visitor.type_bool = qmp_input_type_bool;
+    v->visitor.type_str = qmp_input_type_str;
+    v->visitor.type_number = qmp_input_type_number;
+    v->visitor.start_optional = qmp_input_start_optional;
+    v->visitor.end_optional = qmp_input_end_optional;
+
+    v->obj = obj;
+    qobject_incref(v->obj);
+
+    return v;
+}
diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
new file mode 100644 (file)
index 0000000..3f798f0
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_INPUT_VISITOR_H
+#define QMP_INPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisitor QmpInputVisitor;
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
+void qmp_input_visitor_cleanup(QmpInputVisitor *v);
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
+
+#endif
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
new file mode 100644 (file)
index 0000000..f76d015
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Core Definitions for QAPI/QMP Command Registry
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-output-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+typedef struct QStackEntry
+{
+    QObject *value;
+    bool is_list_head;
+    QTAILQ_ENTRY(QStackEntry) node;
+} QStackEntry;
+
+typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
+
+struct QmpOutputVisitor
+{
+    Visitor visitor;
+    QStack stack;
+};
+
+#define qmp_output_add(qov, name, value) \
+    qmp_output_add_obj(qov, name, QOBJECT(value))
+#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
+
+static QmpOutputVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QmpOutputVisitor, visitor);
+}
+
+static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
+{
+    QStackEntry *e = g_malloc0(sizeof(*e));
+
+    e->value = value;
+    if (qobject_type(e->value) == QTYPE_QLIST) {
+        e->is_list_head = true;
+    }
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    g_free(e);
+    return value;
+}
+
+static QObject *qmp_output_first(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+    return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
+                               QObject *value)
+{
+    QObject *cur;
+
+    if (QTAILQ_EMPTY(&qov->stack)) {
+        qmp_output_push_obj(qov, value);
+        return;
+    }
+
+    cur = qmp_output_last(qov);
+
+    switch (qobject_type(cur)) {
+    case QTYPE_QDICT:
+        qdict_put_obj(qobject_to_qdict(cur), name, value);
+        break;
+    case QTYPE_QLIST:
+        qlist_append_obj(qobject_to_qlist(cur), value);
+        break;
+    default:
+        qobject_decref(qmp_output_pop(qov));
+        qmp_output_push_obj(qov, value);
+        break;
+    }
+}
+
+static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
+                                    const char *name, size_t unused,
+                                    Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QDict *dict = qdict_new();
+
+    qmp_output_add(qov, name, dict);
+    qmp_output_push(qov, dict);
+}
+
+static void qmp_output_end_struct(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QList *list = qlist_new();
+
+    qmp_output_add(qov, name, list);
+    qmp_output_push(qov, list);
+}
+
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
+                                         Error **errp)
+{
+    GenericList *list = *listp;
+    QmpOutputVisitor *qov = to_qov(v);
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+
+    assert(e);
+    if (e->is_list_head) {
+        e->is_list_head = false;
+        return list;
+    }
+
+    return list ? list->next : NULL;
+}
+
+static void qmp_output_end_list(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
+                                Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
+                                 Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
+                                Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    if (*obj) {
+        qmp_output_add(qov, name, qstring_from_str(*obj));
+    } else {
+        qmp_output_add(qov, name, qstring_from_str(""));
+    }
+}
+
+static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
+                                   Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[],
+                                 const char *kind, const char *name,
+                                 Error **errp)
+{
+    int i = 0;
+    int value = *obj;
+    char *enum_str;
+
+    assert(strings);
+    while (strings[i++] != NULL);
+    if (value < 0 || value >= i - 1) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        return;
+    }
+
+    enum_str = (char *)strings[value];
+    qmp_output_type_str(v, &enum_str, name, errp);
+}
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
+{
+    QObject *obj = qmp_output_first(qov);
+    if (obj) {
+        qobject_incref(obj);
+    }
+    return obj;
+}
+
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
+{
+    QStackEntry *e, *tmp;
+
+    QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
+        QTAILQ_REMOVE(&v->stack, e, node);
+        if (e->value) {
+            qobject_decref(e->value);
+        }
+        g_free(e);
+    }
+
+    g_free(v);
+}
+
+QmpOutputVisitor *qmp_output_visitor_new(void)
+{
+    QmpOutputVisitor *v;
+
+    v = g_malloc0(sizeof(*v));
+
+    v->visitor.start_struct = qmp_output_start_struct;
+    v->visitor.end_struct = qmp_output_end_struct;
+    v->visitor.start_list = qmp_output_start_list;
+    v->visitor.next_list = qmp_output_next_list;
+    v->visitor.end_list = qmp_output_end_list;
+    v->visitor.type_enum = qmp_output_type_enum;
+    v->visitor.type_int = qmp_output_type_int;
+    v->visitor.type_bool = qmp_output_type_bool;
+    v->visitor.type_str = qmp_output_type_str;
+    v->visitor.type_number = qmp_output_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qmp-output-visitor.h b/qapi/qmp-output-visitor.h
new file mode 100644 (file)
index 0000000..4a649c2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Output Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_OUTPUT_VISITOR_H
+#define QMP_OUTPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisitor QmpOutputVisitor;
+
+QmpOutputVisitor *qmp_output_visitor_new(void);
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
+
+#endif
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
new file mode 100644 (file)
index 0000000..5ff99cf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Michael Roth      <mdroth@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qmp-core.h"
+
+static QTAILQ_HEAD(, QmpCommand) qmp_commands =
+    QTAILQ_HEAD_INITIALIZER(qmp_commands);
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn)
+{
+    QmpCommand *cmd = g_malloc0(sizeof(*cmd));
+
+    cmd->name = name;
+    cmd->type = QCT_NORMAL;
+    cmd->fn = fn;
+    QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
+}
+
+QmpCommand *qmp_find_command(const char *name)
+{
+    QmpCommand *i;
+
+    QTAILQ_FOREACH(i, &qmp_commands, node) {
+        if (strcmp(i->name, name) == 0) {
+            return i;
+        }
+    }
+    return NULL;
+}
diff --git a/qbool.c b/qbool.c
index ad4873f62cc97bec60dde88d3b8ef2f5fd03bcea..590cd716eadde40749aadcacc72ddc54efed68c4 100644 (file)
--- a/qbool.c
+++ b/qbool.c
@@ -31,7 +31,7 @@ QBool *qbool_from_int(int value)
 {
     QBool *qb;
 
-    qb = qemu_malloc(sizeof(*qb));
+    qb = g_malloc(sizeof(*qb));
     qb->value = value;
     QOBJECT_INIT(qb, &qbool_type);
 
@@ -64,5 +64,5 @@ QBool *qobject_to_qbool(const QObject *obj)
 static void qbool_destroy_obj(QObject *obj)
 {
     assert(obj != NULL);
-    qemu_free(qobject_to_qbool(obj));
+    g_free(qobject_to_qbool(obj));
 }
diff --git a/qdict.c b/qdict.c
index dee0fb447c4f74d223752945a801729219d927e9..4bf308b61c6227961323d38b48542f0d24fee674 100644 (file)
--- a/qdict.c
+++ b/qdict.c
@@ -35,7 +35,7 @@ QDict *qdict_new(void)
 {
     QDict *qdict;
 
-    qdict = qemu_mallocz(sizeof(*qdict));
+    qdict = g_malloc0(sizeof(*qdict));
     QOBJECT_INIT(qdict, &qdict_type);
 
     return qdict;
@@ -75,8 +75,8 @@ static QDictEntry *alloc_entry(const char *key, QObject *value)
 {
     QDictEntry *entry;
 
-    entry = qemu_mallocz(sizeof(*entry));
-    entry->key = qemu_strdup(key);
+    entry = g_malloc0(sizeof(*entry));
+    entry->key = g_strdup(key);
     entry->value = value;
 
     return entry;
@@ -410,8 +410,8 @@ static void qentry_destroy(QDictEntry *e)
     assert(e->value != NULL);
 
     qobject_decref(e->value);
-    qemu_free(e->key);
-    qemu_free(e);
+    g_free(e->key);
+    g_free(e);
 }
 
 /**
@@ -452,5 +452,5 @@ static void qdict_destroy_obj(QObject *obj)
         }
     }
 
-    qemu_free(qdict);
+    g_free(qdict);
 }
index b77fce23a95962ad29b2526f6a313eae39381047..c11bb2b59f01c0dd265080cbe170d2bf08dbd0c8 100644 (file)
@@ -1,10 +1,38 @@
 #ifndef __QEMU_BARRIER_H
 #define __QEMU_BARRIER_H 1
 
-/* FIXME: arch dependant, x86 version */
-#define smp_wmb()   asm volatile("" ::: "memory")
-
 /* Compiler barrier */
 #define barrier()   asm volatile("" ::: "memory")
 
+#if defined(__i386__) || defined(__x86_64__)
+
+/*
+ * Because of the strongly ordered x86 storage model, wmb() is a nop
+ * on x86(well, a compiler barrier only).  Well, at least as long as
+ * qemu doesn't do accesses to write-combining memory or non-temporal
+ * load/stores from C code.
+ */
+#define smp_wmb()   barrier()
+
+#elif defined(_ARCH_PPC)
+
+/*
+ * We use an eieio() for a wmb() on powerpc.  This assumes we don't
+ * need to order cacheable and non-cacheable stores with respect to
+ * each other
+ */
+#define smp_wmb()   asm volatile("eieio" ::: "memory")
+
+#else
+
+/*
+ * For (host) platforms we don't have explicit barrier definitions
+ * for, we use the gcc __sync_synchronize() primitive to generate a
+ * full barrier.  This should be safe on all platforms, though it may
+ * be overkill.
+ */
+#define smp_wmb()   __sync_synchronize()
+
+#endif
+
 #endif
index 795aec092f7756b4e353f2415fa9efd560a2fd14..202533f4d4e825d90fccc5ec242aa34f73b27fdd 100644 (file)
 #include "hw/usb.h"
 #include "hw/baum.h"
 #include "hw/msmouse.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
 
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <time.h>
 #include <errno.h>
 #include <sys/time.h>
 static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
     QTAILQ_HEAD_INITIALIZER(chardevs);
 
-static void qemu_chr_event(CharDriverState *s, int event)
+void qemu_chr_be_event(CharDriverState *s, int event)
 {
     /* Keep track if the char device is open */
     switch (event) {
@@ -127,7 +126,7 @@ static void qemu_chr_event(CharDriverState *s, int event)
 static void qemu_chr_generic_open_bh(void *opaque)
 {
     CharDriverState *s = opaque;
-    qemu_chr_event(s, CHR_EVENT_OPENED);
+    qemu_chr_be_event(s, CHR_EVENT_OPENED);
     qemu_bh_delete(s->bh);
     s->bh = NULL;
 }
@@ -140,63 +139,66 @@ void qemu_chr_generic_open(CharDriverState *s)
     }
 }
 
-int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
 {
     return s->chr_write(s, buf, len);
 }
 
-int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
 {
     if (!s->chr_ioctl)
         return -ENOTSUP;
     return s->chr_ioctl(s, cmd, arg);
 }
 
-int qemu_chr_can_read(CharDriverState *s)
+int qemu_chr_be_can_write(CharDriverState *s)
 {
     if (!s->chr_can_read)
         return 0;
     return s->chr_can_read(s->handler_opaque);
 }
 
-void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
 {
     s->chr_read(s->handler_opaque, buf, len);
 }
 
-int qemu_chr_get_msgfd(CharDriverState *s)
+int qemu_chr_fe_get_msgfd(CharDriverState *s)
 {
     return s->get_msgfd ? s->get_msgfd(s) : -1;
 }
 
+int qemu_chr_add_client(CharDriverState *s, int fd)
+{
+    return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
+}
+
 void qemu_chr_accept_input(CharDriverState *s)
 {
     if (s->chr_accept_input)
         s->chr_accept_input(s);
 }
 
-void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
 {
     char buf[READ_BUF_LEN];
     va_list ap;
     va_start(ap, fmt);
     vsnprintf(buf, sizeof(buf), fmt, ap);
-    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
+    qemu_chr_fe_write(s, (uint8_t *)buf, strlen(buf));
     va_end(ap);
 }
 
-void qemu_chr_send_event(CharDriverState *s, int event)
-{
-    if (s->chr_send_event)
-        s->chr_send_event(s, event);
-}
-
 void qemu_chr_add_handlers(CharDriverState *s,
                            IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque)
 {
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        /* chr driver being released. */
+        ++s->avail_connections;
+    }
     s->chr_can_read = fd_can_read;
     s->chr_read = fd_read;
     s->chr_event = fd_event;
@@ -216,13 +218,15 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
+static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
-    return chr;
+
+    *_chr= chr;
+    return 0;
 }
 
 /* MUX driver for serial I/O splitting */
@@ -267,7 +271,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                 int64_t ti;
                 int secs;
 
-                ti = qemu_get_clock(rt_clock);
+                ti = qemu_get_clock_ms(rt_clock);
                 if (d->timestamps_start == -1)
                     d->timestamps_start = ti;
                 ti -= d->timestamps_start;
@@ -355,7 +359,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
             bdrv_commit_all();
             break;
         case 'b':
-            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            qemu_chr_be_event(chr, CHR_EVENT_BREAK);
             break;
         case 'c':
             /* Switch to the next registered device */
@@ -467,8 +471,8 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     CharDriverState *chr;
     MuxDriver *d;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    d = qemu_mallocz(sizeof(MuxDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    d = g_malloc0(sizeof(MuxDriver));
 
     chr->opaque = d;
     d->drv = drv;
@@ -476,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);
@@ -531,6 +538,9 @@ int send_all(int fd, const void *_buf, int len1)
 }
 #endif /* !_WIN32 */
 
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients;
+
 #ifndef _WIN32
 
 typedef struct {
@@ -538,8 +548,6 @@ typedef struct {
     int max_size;
 } FDCharDriver;
 
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients = 0;
 
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -552,7 +560,7 @@ static int fd_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     FDCharDriver *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -572,11 +580,11 @@ static void fd_chr_read(void *opaque)
     if (size == 0) {
         /* FD has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
         return;
     }
     if (size > 0) {
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -604,8 +612,8 @@ static void fd_chr_close(struct CharDriverState *chr)
         }
     }
 
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
 /* open a character device to a unix fd */
@@ -614,8 +622,8 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     CharDriverState *chr;
     FDCharDriver *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(FDCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(FDCharDriver));
     s->fd_in = fd_in;
     s->fd_out = fd_out;
     chr->opaque = s;
@@ -628,18 +636,21 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
+static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_out;
 
     TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
                       O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
-    if (fd_out < 0)
-        return NULL;
-    return qemu_chr_open_fd(-1, fd_out);
+    if (fd_out < 0) {
+        return -errno;
+    }
+
+    *_chr = qemu_chr_open_fd(-1, fd_out);
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
+static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
@@ -647,7 +658,7 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
 
     if (filename == NULL) {
         fprintf(stderr, "chardev: pipe: no filename given\n");
-        return NULL;
+        return -EINVAL;
     }
 
     snprintf(filename_in, 256, "%s.in", filename);
@@ -659,11 +670,14 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
            close(fd_in);
        if (fd_out >= 0)
            close(fd_out);
-        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
-        if (fd_in < 0)
-            return NULL;
+        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0) {
+            return -errno;
+        }
     }
-    return qemu_chr_open_fd(fd_in, fd_out);
+
+    *_chr = qemu_chr_open_fd(fd_in, fd_out);
+    return 0;
 }
 
 
@@ -680,8 +694,8 @@ static int stdio_read_poll(void *opaque)
     CharDriverState *chr = opaque;
 
     /* try to flush the queue if needed */
-    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
-        qemu_chr_read(chr, term_fifo, 1);
+    if (term_fifo_size != 0 && qemu_chr_be_can_write(chr) > 0) {
+        qemu_chr_be_write(chr, term_fifo, 1);
         term_fifo_size = 0;
     }
     /* see if we can absorb more chars */
@@ -701,12 +715,12 @@ static void stdio_read(void *opaque)
     if (size == 0) {
         /* stdin has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
         return;
     }
     if (size > 0) {
-        if (qemu_chr_can_read(chr) > 0) {
-            qemu_chr_read(chr, buf, 1);
+        if (qemu_chr_be_can_write(chr) > 0) {
+            qemu_chr_be_write(chr, buf, 1);
         } else if (term_fifo_size == 0) {
             term_fifo[term_fifo_size++] = buf[0];
         }
@@ -754,12 +768,14 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
+static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-        return NULL;
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
+        return -EBUSY;
+    }
+
     if (stdio_nb_clients == 0) {
         old_fd0_flags = fcntl(0, F_GETFL);
         tcgetattr (0, &oldtty);
@@ -774,9 +790,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
     stdio_nb_clients++;
     stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
                                            display_type != DT_NOGRAPHIC);
-    qemu_chr_set_echo(chr, false);
+    qemu_chr_fe_set_echo(chr, false);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 #ifdef __sun__
@@ -868,7 +885,7 @@ static int pty_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     PtyCharDriver *s = chr->opaque;
 
-    s->read_bytes = qemu_chr_can_read(chr);
+    s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
 }
 
@@ -892,7 +909,7 @@ static void pty_chr_read(void *opaque)
     }
     if (size > 0) {
         pty_chr_state(chr, 1);
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -911,7 +928,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr)
      * timeout to the normal (much longer) poll interval before the
      * timer triggers.
      */
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10);
 }
 
 static void pty_chr_state(CharDriverState *chr, int connected)
@@ -925,7 +942,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
         /* (re-)connect poll interval for idle guests: once per second.
          * We check more frequently in case the guests sends data to
          * the virtual device linked to our pty. */
-        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+        qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000);
     } else {
         if (!s->connected)
             qemu_chr_generic_open(chr);
@@ -959,16 +976,16 @@ static void pty_chr_close(struct CharDriverState *chr)
     close(s->fd);
     qemu_del_timer(s->timer);
     qemu_free_timer(s->timer);
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
     PtyCharDriver *s;
     struct termios tty;
-    int slave_fd, len;
+    int master_fd, slave_fd, len;
 #if defined(__OpenBSD__) || defined(__DragonFly__)
     char pty_name[PATH_MAX];
 #define q_ptsname(x) pty_name
@@ -977,11 +994,8 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 #define q_ptsname(x) ptsname(x)
 #endif
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(PtyCharDriver));
-
-    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
-        return NULL;
+    if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+        return -errno;
     }
 
     /* Set raw attributes on the pty. */
@@ -990,20 +1004,25 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
     tcsetattr(slave_fd, TCSAFLUSH, &tty);
     close(slave_fd);
 
-    len = strlen(q_ptsname(s->fd)) + 5;
-    chr->filename = qemu_malloc(len);
-    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
-    qemu_opt_set(opts, "path", q_ptsname(s->fd));
-    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+    chr = g_malloc0(sizeof(CharDriverState));
+
+    len = strlen(q_ptsname(master_fd)) + 5;
+    chr->filename = g_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd));
+    qemu_opt_set(opts, "path", q_ptsname(master_fd));
+    fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd));
 
+    s = g_malloc0(sizeof(PtyCharDriver));
     chr->opaque = s;
     chr->chr_write = pty_chr_write;
     chr->chr_update_read_handler = pty_chr_update_read_handler;
     chr->chr_close = pty_chr_close;
 
-    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+    s->fd = master_fd;
+    s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 static void tty_serial_init(int fd, int speed,
@@ -1204,30 +1223,28 @@ static void qemu_chr_close_tty(CharDriverState *chr)
     }
 }
 
-static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
+static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     int fd;
 
-    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+    TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
     if (fd < 0) {
-        return NULL;
+        return -errno;
     }
     tty_serial_init(fd, 115200, 'N', 8, 1);
     chr = qemu_chr_open_fd(fd, fd);
-    if (!chr) {
-        close(fd);
-        return NULL;
-    }
     chr->chr_ioctl = tty_serial_ioctl;
     chr->chr_close = qemu_chr_close_tty;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 #else  /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
-    return NULL;
+    return -ENOTSUP;
 }
 #endif /* __linux__ || __sun__ */
 
@@ -1337,11 +1354,11 @@ static void pp_close(CharDriverState *chr)
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
     ioctl(fd, PPRELEASE);
     close(fd);
-    qemu_free(drv);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(drv);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1349,19 +1366,20 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
     int fd;
 
     TFR(fd = open(filename, O_RDWR));
-    if (fd < 0)
-        return NULL;
+    if (fd < 0) {
+        return -errno;
+    }
 
     if (ioctl(fd, PPCLAIM) < 0) {
         close(fd);
-        return NULL;
+        return -errno;
     }
 
-    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    drv = g_malloc0(sizeof(ParallelCharDriver));
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
     chr->chr_close = pp_close;
@@ -1369,14 +1387,15 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 
     qemu_chr_generic_open(chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 #endif /* __linux__ */
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)(long)chr->opaque;
+    int fd = (int)(intptr_t)chr->opaque;
     uint8_t b;
 
     switch(cmd) {
@@ -1411,26 +1430,31 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     int fd;
 
-    fd = open(filename, O_RDWR);
-    if (fd < 0)
-        return NULL;
+    fd = qemu_open(filename, O_RDWR);
+    if (fd < 0) {
+        return -errno;
+    }
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    chr->opaque = (void *)(long)fd;
+    chr = g_malloc0(sizeof(CharDriverState));
+    chr->opaque = (void *)(intptr_t)fd;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 #endif
 
 #else /* _WIN32 */
 
+static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+
 typedef struct {
     int max_size;
     HANDLE hcom, hrecv, hsend;
@@ -1439,6 +1463,14 @@ typedef struct {
     DWORD len;
 } WinCharState;
 
+typedef struct {
+    HANDLE  hStdIn;
+    HANDLE  hInputReadyEvent;
+    HANDLE  hInputDoneEvent;
+    HANDLE  hInputThread;
+    uint8_t win_stdio_buf;
+} WinStdioCharState;
+
 #define NSENDBUF 2048
 #define NRECVBUF 2048
 #define MAXCONNECT 1
@@ -1468,7 +1500,7 @@ static void win_chr_close(CharDriverState *chr)
     else
         qemu_del_polling_cb(win_chr_poll, chr);
 
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
 static int win_chr_init(CharDriverState *chr, const char *filename)
@@ -1490,8 +1522,8 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
         fprintf(stderr, "Failed CreateEvent\n");
         goto fail;
     }
-
-    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+    s->hcom = CreateFile(filename,
+                      GENERIC_READ|GENERIC_WRITE, 0, NULL,
                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
     if (s->hcom == INVALID_HANDLE_VALUE) {
         fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
@@ -1576,7 +1608,7 @@ static int win_chr_read_poll(CharDriverState *chr)
 {
     WinCharState *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -1598,7 +1630,7 @@ static void win_chr_readfile(CharDriverState *chr)
     }
 
     if (size > 0) {
-        qemu_chr_read(chr, buf, size);
+        qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -1631,25 +1663,27 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
+static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
     if (win_chr_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
+        g_free(s);
+        g_free(chr);
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
 static int win_chr_pipe_poll(void *opaque)
@@ -1731,57 +1765,278 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
+static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
     if (win_chr_pipe_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
+        g_free(s);
+        g_free(chr);
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr)
 {
     CharDriverState *chr;
     WinCharState *s;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(WinCharState));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(WinCharState));
     s->hcom = fd_out;
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     qemu_chr_generic_open(chr);
-    return chr;
+    *pchr = chr;
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
+static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **chr)
 {
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr);
 }
 
-static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
+static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *file_out = qemu_opt_get(opts, "path");
     HANDLE fd_out;
 
+#ifndef CONFIG_MARU
+    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+#else
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (fd_out == INVALID_HANDLE_VALUE)
-        return NULL;
+#endif
+
+    if (fd_out == INVALID_HANDLE_VALUE) {
+        return -EIO;
+    }
+
+    return qemu_chr_open_win_file(fd_out, _chr);
+}
+
+static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+    DWORD   dwSize;
+    int     len1;
+
+    len1 = len;
+
+    while (len1 > 0) {
+        if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
+            break;
+        }
+        buf  += dwSize;
+        len1 -= dwSize;
+    }
+
+    return len - len1;
+}
+
+static void win_stdio_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+    INPUT_RECORD       buf[4];
+    int                ret;
+    DWORD              dwSize;
+    int                i;
+
+    ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf),
+                           &dwSize);
+
+    if (!ret) {
+        /* Avoid error storm */
+        qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
+        return;
+    }
+
+    for (i = 0; i < dwSize; i++) {
+        KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
 
-    return qemu_chr_open_win_file(fd_out);
+        if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
+            int j;
+            if (kev->uChar.AsciiChar != 0) {
+                for (j = 0; j < kev->wRepeatCount; j++) {
+                    if (qemu_chr_be_can_write(chr)) {
+                        uint8_t c = kev->uChar.AsciiChar;
+                        qemu_chr_be_write(chr, &c, 1);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static DWORD WINAPI win_stdio_thread(LPVOID param)
+{
+    CharDriverState   *chr   = param;
+    WinStdioCharState *stdio = chr->opaque;
+    int                ret;
+    DWORD              dwSize;
+
+    while (1) {
+
+        /* Wait for one byte */
+        ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
+
+        /* Exit in case of error, continue if nothing read */
+        if (!ret) {
+            break;
+        }
+        if (!dwSize) {
+            continue;
+        }
+
+        /* Some terminal emulator returns \r\n for Enter, just pass \n */
+        if (stdio->win_stdio_buf == '\r') {
+            continue;
+        }
+
+        /* Signal the main thread and wait until the byte was eaten */
+        if (!SetEvent(stdio->hInputReadyEvent)) {
+            break;
+        }
+        if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
+            != WAIT_OBJECT_0) {
+            break;
+        }
+    }
+
+    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
+    return 0;
+}
+
+static void win_stdio_thread_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (qemu_chr_be_can_write(chr)) {
+        qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
+    }
+
+    SetEvent(stdio->hInputDoneEvent);
+}
+
+static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
+{
+    WinStdioCharState *stdio  = chr->opaque;
+    DWORD              dwMode = 0;
+
+    GetConsoleMode(stdio->hStdIn, &dwMode);
+
+    if (echo) {
+        SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
+    } else {
+        SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
+    }
+}
+
+static void win_stdio_close(CharDriverState *chr)
+{
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputReadyEvent);
+    }
+    if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputDoneEvent);
+    }
+    if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
+        TerminateThread(stdio->hInputThread, 0);
+    }
+
+    g_free(chr->opaque);
+    g_free(chr);
+    stdio_nb_clients--;
+}
+
+static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState   *chr;
+    WinStdioCharState *stdio;
+    DWORD              dwMode;
+    int                is_console = 0;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS
+        || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
+        return -EIO;
+    }
+
+    chr   = g_malloc0(sizeof(CharDriverState));
+    stdio = g_malloc0(sizeof(WinStdioCharState));
+
+    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "cannot open stdio: invalid handle\n");
+        exit(1);
+    }
+
+    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+
+    chr->opaque    = stdio;
+    chr->chr_write = win_stdio_write;
+    chr->chr_close = win_stdio_close;
+
+    if (stdio_nb_clients == 0) {
+        if (is_console) {
+            if (qemu_add_wait_object(stdio->hStdIn,
+                                     win_stdio_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        } else {
+            DWORD   dwId;
+
+            stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
+                                            chr, 0, &dwId);
+
+            if (stdio->hInputThread == INVALID_HANDLE_VALUE
+                || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+                || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+                fprintf(stderr, "cannot create stdio thread or event\n");
+                exit(1);
+            }
+            if (qemu_add_wait_object(stdio->hInputReadyEvent,
+                                     win_stdio_thread_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        }
+    }
+
+    dwMode |= ENABLE_LINE_INPUT;
+
+    stdio_clients[stdio_nb_clients++] = chr;
+    if (stdio_nb_clients == 1 && is_console) {
+        /* set the terminal in raw mode */
+        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
+        dwMode |= ENABLE_PROCESSED_INPUT;
+    }
+
+    SetConsoleMode(stdio->hStdIn, dwMode);
+
+    chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
+    qemu_chr_fe_set_echo(chr, false);
+
+    *_chr = chr;
+
+    return 0;
 }
 #endif /* !_WIN32 */
 
@@ -1808,15 +2063,15 @@ static int udp_chr_read_poll(void *opaque)
     CharDriverState *chr = opaque;
     NetCharDriver *s = chr->opaque;
 
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
 
     /* If there were any stray characters in the queue process them
      * first
      */
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
         s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
+        s->max_size = qemu_chr_be_can_write(chr);
     }
     return s->max_size;
 }
@@ -1828,16 +2083,16 @@ static void udp_chr_read(void *opaque)
 
     if (s->max_size == 0)
         return;
-    s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
     s->bufptr = s->bufcnt;
     if (s->bufcnt <= 0)
         return;
 
     s->bufptr = 0;
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
         s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
+        s->max_size = qemu_chr_be_can_write(chr);
     }
 }
 
@@ -1855,25 +2110,27 @@ static void udp_chr_close(CharDriverState *chr)
 {
     NetCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
     int fd = -1;
+    int ret;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(NetCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(NetCharDriver));
 
     fd = inet_dgram_opts(opts);
     if (fd < 0) {
         fprintf(stderr, "inet_dgram_opts failed\n");
+        ret = -errno;
         goto return_err;
     }
 
@@ -1884,16 +2141,17 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_close = udp_chr_close;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
 return_err:
-    if (chr)
-        free(chr);
-    if (s)
-        free(s);
-    if (fd >= 0)
+    g_free(chr);
+    g_free(s);
+    if (fd >= 0) {
         closesocket(fd);
-    return NULL;
+    }
+    return ret;
 }
 
 /***********************************************************/
@@ -1928,7 +2186,7 @@ static int tcp_chr_read_poll(void *opaque)
     TCPCharDriver *s = chr->opaque;
     if (!s->connected)
         return 0;
-    s->max_size = qemu_chr_can_read(chr);
+    s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
 }
 
@@ -1961,7 +2219,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
             } else {
                 if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
                     /* Handle IAC break commands by sending a serial break */
-                    qemu_chr_event(chr, CHR_EVENT_BREAK);
+                    qemu_chr_be_event(chr, CHR_EVENT_BREAK);
                     s->do_telnetopt++;
                 }
                 s->do_telnetopt++;
@@ -2043,7 +2301,7 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 {
     TCPCharDriver *s = chr->opaque;
-    return recv(s->fd, buf, len, 0);
+    return qemu_recv(s->fd, buf, len, 0);
 }
 #endif
 
@@ -2064,17 +2322,17 @@ static void tcp_chr_read(void *opaque)
         /* connection closed */
         s->connected = 0;
         if (s->listen_fd >= 0) {
-            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+            qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
         s->fd = -1;
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
     } else if (size > 0) {
         if (s->do_telnetopt)
             tcp_chr_process_IAC_bytes(chr, s, buf, &size);
         if (size > 0)
-            qemu_chr_read(chr, buf, size);
+            qemu_chr_be_write(chr, buf, size);
     }
 }
 
@@ -2117,6 +2375,22 @@ static void socket_set_nodelay(int fd)
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 }
 
+static int tcp_chr_add_client(CharDriverState *chr, int fd)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd != -1)
+       return -1;
+
+    socket_set_nonblock(fd);
+    if (s->do_nodelay)
+        socket_set_nodelay(fd);
+    s->fd = fd;
+    qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
+    tcp_chr_connect(chr);
+
+    return 0;
+}
+
 static void tcp_chr_accept(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2149,30 +2423,26 @@ static void tcp_chr_accept(void *opaque)
             break;
         }
     }
-    socket_set_nonblock(fd);
-    if (s->do_nodelay)
-        socket_set_nodelay(fd);
-    s->fd = fd;
-    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
-    tcp_chr_connect(chr);
+    if (tcp_chr_add_client(chr, fd) < 0)
+       close(fd);
 }
 
 static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     if (s->listen_fd >= 0) {
-        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
         closesocket(s->listen_fd);
     }
-    qemu_free(s);
-    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    g_free(s);
+    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
@@ -2182,6 +2452,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     int do_nodelay;
     int is_unix;
     int is_telnet;
+    int ret;
 
     is_listen      = qemu_opt_get_bool(opts, "server", 0);
     is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
@@ -2191,8 +2462,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     if (!is_listen)
         is_waitconnect = 0;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(TCPCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(TCPCharDriver));
 
     if (is_unix) {
         if (is_listen) {
@@ -2207,8 +2478,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
             fd = inet_connect_opts(opts);
         }
     }
-    if (fd < 0)
+    if (fd < 0) {
+        ret = -errno;
         goto fail;
+    }
 
     if (!is_waitconnect)
         socket_set_nonblock(fd);
@@ -2224,10 +2497,11 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     chr->chr_write = tcp_chr_write;
     chr->chr_close = tcp_chr_close;
     chr->get_msgfd = tcp_get_msgfd;
+    chr->chr_add_client = tcp_chr_add_client;
 
     if (is_listen) {
         s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         if (is_telnet)
             s->do_telnetopt = 1;
 
@@ -2239,7 +2513,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     }
 
     /* for "info chardev" monitor command */
-    chr->filename = qemu_malloc(256);
+    chr->filename = g_malloc(256);
     if (is_unix) {
         snprintf(chr->filename, 256, "unix:%s%s",
                  qemu_opt_get(opts, "path"),
@@ -2260,14 +2534,16 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
         tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);
     }
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
  fail:
     if (fd >= 0)
         closesocket(fd);
-    qemu_free(s);
-    qemu_free(chr);
-    return NULL;
+    g_free(s);
+    g_free(chr);
+    return ret;
 }
 
 /***********************************************************/
@@ -2288,7 +2564,7 @@ static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
         /* grow outbuf */
         d->outbuf_capacity += len;
         d->outbuf_capacity *= 2;
-        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
+        d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity);
     }
 
     memcpy(d->outbuf + d->outbuf_size, buf, len);
@@ -2301,10 +2577,10 @@ void qemu_chr_init_mem(CharDriverState *chr)
 {
     MemoryDriver *d;
 
-    d = qemu_malloc(sizeof(*d));
+    d = g_malloc(sizeof(*d));
     d->outbuf_size = 0;
     d->outbuf_capacity = 4096;
-    d->outbuf = qemu_mallocz(d->outbuf_capacity);
+    d->outbuf = g_malloc0(d->outbuf_capacity);
 
     memset(chr, 0, sizeof(*chr));
     chr->opaque = d;
@@ -2317,13 +2593,13 @@ QString *qemu_chr_mem_to_qs(CharDriverState *chr)
     return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
 }
 
-/* NOTE: this driver can not be closed with qemu_chr_close()! */
+/* NOTE: this driver can not be closed with qemu_chr_delete()! */
 void qemu_chr_close_mem(CharDriverState *chr)
 {
     MemoryDriver *d = chr->opaque;
 
-    qemu_free(d->outbuf);
-    qemu_free(chr->opaque);
+    g_free(d->outbuf);
+    g_free(chr->opaque);
     chr->opaque = NULL;
     chr->chr_write = NULL;
 }
@@ -2460,7 +2736,7 @@ fail:
 
 static const struct {
     const char *name;
-    CharDriverState *(*open)(QemuOpts *opts);
+    int (*open)(QemuOpts *opts, CharDriverState **chr);
 } backend_table[] = {
     { .name = "null",      .open = qemu_chr_open_null },
     { .name = "socket",    .open = qemu_chr_open_socket },
@@ -2472,6 +2748,7 @@ static const struct {
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
     { .name = "console",   .open = qemu_chr_open_win_con },
     { .name = "serial",    .open = qemu_chr_open_win },
+    { .name = "stdio",     .open = qemu_chr_open_win_stdio },
 #else
     { .name = "file",      .open = qemu_chr_open_file_out },
     { .name = "pipe",      .open = qemu_chr_open_pipe },
@@ -2495,11 +2772,12 @@ static const struct {
 #endif
 };
 
-CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s))
 {
     CharDriverState *chr;
     int i;
+    int ret;
 
     if (qemu_opts_id(opts) == NULL) {
         fprintf(stderr, "chardev: no id specified\n");
@@ -2521,32 +2799,35 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
         return NULL;
     }
 
-    chr = backend_table[i].open(opts);
-    if (!chr) {
-        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
-                qemu_opt_get(opts, "backend"));
+    ret = backend_table[i].open(opts, &chr);
+    if (ret < 0) {
+        fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n",
+                qemu_opt_get(opts, "backend"), strerror(-ret));
         return NULL;
     }
 
     if (!chr->filename)
-        chr->filename = qemu_strdup(qemu_opt_get(opts, "backend"));
+        chr->filename = g_strdup(qemu_opt_get(opts, "backend"));
     chr->init = init;
     QTAILQ_INSERT_TAIL(&chardevs, chr, next);
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
         CharDriverState *base = chr;
         int len = strlen(qemu_opts_id(opts)) + 6;
-        base->label = qemu_malloc(len);
+        base->label = g_malloc(len);
         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));
+    chr->label = g_strdup(qemu_opts_id(opts));
     return chr;
 }
 
-CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
 {
     const char *p;
     CharDriverState *chr;
@@ -2560,7 +2841,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     if (!opts)
         return NULL;
 
-    chr = qemu_chr_open_opts(opts, init);
+    chr = qemu_chr_new_from_opts(opts, init);
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         monitor_init(chr, MONITOR_USE_READLINE);
     }
@@ -2568,52 +2849,53 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     return chr;
 }
 
-void qemu_chr_set_echo(struct CharDriverState *chr, bool echo)
+void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo)
 {
     if (chr->chr_set_echo) {
         chr->chr_set_echo(chr, echo);
     }
 }
 
-void qemu_chr_close(CharDriverState *chr)
+void qemu_chr_fe_open(struct CharDriverState *chr)
 {
-    QTAILQ_REMOVE(&chardevs, chr, next);
-    if (chr->chr_close)
-        chr->chr_close(chr);
-    qemu_free(chr->filename);
-    qemu_free(chr->label);
-    qemu_free(chr);
+    if (chr->chr_guest_open) {
+        chr->chr_guest_open(chr);
+    }
 }
 
-static void qemu_chr_qlist_iter(QObject *obj, void *opaque)
+void qemu_chr_fe_close(struct CharDriverState *chr)
 {
-    QDict *chr_dict;
-    Monitor *mon = opaque;
-
-    chr_dict = qobject_to_qdict(obj);
-    monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"),
-                                         qdict_get_str(chr_dict, "filename"));
+    if (chr->chr_guest_close) {
+        chr->chr_guest_close(chr);
+    }
 }
 
-void qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
+void qemu_chr_delete(CharDriverState *chr)
 {
-    qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
+    QTAILQ_REMOVE(&chardevs, chr, next);
+    if (chr->chr_close)
+        chr->chr_close(chr);
+    g_free(chr->filename);
+    g_free(chr->label);
+    g_free(chr);
 }
 
-void qemu_chr_info(Monitor *mon, QObject **ret_data)
+ChardevInfoList *qmp_query_chardev(Error **errp)
 {
-    QList *chr_list;
+    ChardevInfoList *chr_list = NULL;
     CharDriverState *chr;
 
-    chr_list = qlist_new();
-
     QTAILQ_FOREACH(chr, &chardevs, next) {
-        QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }",
-                                          chr->label, chr->filename);
-        qlist_append_obj(chr_list, obj);
+        ChardevInfoList *info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->label = g_strdup(chr->label);
+        info->value->filename = g_strdup(chr->filename);
+
+        info->next = chr_list;
+        chr_list = info;
     }
 
-    *ret_data = QOBJECT(chr_list);
+    return chr_list;
 }
 
 CharDriverState *qemu_chr_find(const char *name)
index 56d9954c527a712daf16615bac315fbaa06e2f6c..8ca1e2d54e875c111301b55862ce0751d533ad55 100644 (file)
@@ -7,6 +7,7 @@
 #include "qemu-config.h"
 #include "qobject.h"
 #include "qstring.h"
+#include "main-loop.h"
 
 /* character device */
 
@@ -57,47 +58,185 @@ struct CharDriverState {
     void (*chr_update_read_handler)(struct CharDriverState *s);
     int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
     int (*get_msgfd)(struct CharDriverState *s);
+    int (*chr_add_client)(struct CharDriverState *chr, int fd);
     IOEventHandler *chr_event;
     IOCanReadHandler *chr_can_read;
     IOReadHandler *chr_read;
     void *handler_opaque;
-    void (*chr_send_event)(struct CharDriverState *chr, int event);
     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 avail_connections;
     QTAILQ_ENTRY(CharDriverState) next;
 };
 
-QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
-CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+/**
+ * @qemu_chr_new_from_opts:
+ *
+ * Create a new character backend from a QemuOpts list.
+ *
+ * @opts see qemu-config.c for a list of valid options
+ * @init not sure..
+ *
+ * Returns: a new character backend
+ */
+CharDriverState *qemu_chr_new_from_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_close(CharDriverState *chr);
-void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+
+/**
+ * @qemu_chr_new:
+ *
+ * Create a new character backend from a URI.
+ *
+ * @label the name of the backend
+ * @filename the URI
+ * @init not sure..
+ *
+ * Returns: a new character backend
+ */
+CharDriverState *qemu_chr_new(const char *label, const char *filename,
+                              void (*init)(struct CharDriverState *s));
+
+/**
+ * @qemu_chr_delete:
+ *
+ * Destroy a character backend.
+ */
+void qemu_chr_delete(CharDriverState *chr);
+
+/**
+ * @qemu_chr_fe_set_echo:
+ *
+ * Ask the backend to override its normal echo setting.  This only really
+ * applies to the stdio backend and is used by the QMP server such that you
+ * can see what you type if you try to type QMP commands.
+ *
+ * @echo true to enable echo, false to disable echo
+ */
+void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo);
+
+/**
+ * @qemu_chr_fe_open:
+ *
+ * Open a character backend.  This function call is an indication that the
+ * front end is ready to begin doing I/O.
+ */
+void qemu_chr_fe_open(struct CharDriverState *chr);
+
+/**
+ * @qemu_chr_fe_close:
+ *
+ * Close a character backend.  This function call indicates that the front end
+ * no longer is able to process I/O.  To process I/O again, the front end will
+ * call @qemu_chr_fe_open.
+ */
+void qemu_chr_fe_close(struct CharDriverState *chr);
+
+/**
+ * @qemu_chr_fe_printf:
+ *
+ * Write to a character backend using a printf style interface.
+ *
+ * @fmt see #printf
+ */
+void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
-int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
-void qemu_chr_send_event(CharDriverState *s, int event);
+
+/**
+ * @qemu_chr_fe_write:
+ *
+ * Write data to a character backend from the front end.  This function will
+ * send data from the front end to the back end.
+ *
+ * @buf the data
+ * @len the number of bytes to send
+ *
+ * Returns: the number of bytes consumed
+ */
+int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
+
+/**
+ * @qemu_chr_fe_ioctl:
+ *
+ * Issue a device specific ioctl to a backend.
+ *
+ * @cmd see CHR_IOCTL_*
+ * @arg the data associated with @cmd
+ *
+ * Returns: if @cmd is not supported by the backend, -ENOTSUP, otherwise the
+ *          return value depends on the semantics of @cmd
+ */
+int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg);
+
+/**
+ * @qemu_chr_fe_get_msgfd:
+ *
+ * For backends capable of fd passing, return the latest file descriptor passed
+ * by a client.
+ *
+ * Returns: -1 if fd passing isn't supported or there is no pending file
+ *          descriptor.  If a file descriptor is returned, subsequent calls to
+ *          this function will return -1 until a client sends a new file
+ *          descriptor.
+ */
+int qemu_chr_fe_get_msgfd(CharDriverState *s);
+
+/**
+ * @qemu_chr_be_can_write:
+ *
+ * Determine how much data the front end can currently accept.  This function
+ * returns the number of bytes the front end can accept.  If it returns 0, the
+ * front end cannot receive data at the moment.  The function must be polled
+ * to determine when data can be received.
+ *
+ * Returns: the number of bytes the front end can receive via @qemu_chr_be_write
+ */
+int qemu_chr_be_can_write(CharDriverState *s);
+
+/**
+ * @qemu_chr_be_write:
+ *
+ * Write data from the back end to the front end.  Before issuing this call,
+ * the caller should call @qemu_chr_be_can_write to determine how much data
+ * the front end can currently accept.
+ *
+ * @buf a buffer to receive data from the front end
+ * @len the number of bytes to receive from the front end
+ */
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+
+
+/**
+ * @qemu_chr_be_event:
+ *
+ * Send an event from the back end to the front end.
+ *
+ * @event the event to send
+ */
+void qemu_chr_be_event(CharDriverState *s, int event);
+
 void qemu_chr_add_handlers(CharDriverState *s,
                            IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque);
-int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+
 void qemu_chr_generic_open(CharDriverState *s);
-int qemu_chr_can_read(CharDriverState *s);
-void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
-int qemu_chr_get_msgfd(CharDriverState *s);
 void qemu_chr_accept_input(CharDriverState *s);
+int qemu_chr_add_client(CharDriverState *s, int fd);
 void qemu_chr_info_print(Monitor *mon, const QObject *ret_data);
 void qemu_chr_info(Monitor *mon, QObject **ret_data);
 CharDriverState *qemu_chr_find(const char *name);
 
+QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
+
 /* add an eventfd to the qemu devices that are polled */
 CharDriverState *qemu_chr_open_eventfd(int eventfd);
 
@@ -109,15 +248,4 @@ void qemu_chr_close_mem(CharDriverState *chr);
 QString *qemu_chr_mem_to_qs(CharDriverState *chr);
 size_t qemu_chr_mem_osize(const CharDriverState *chr);
 
-/* async I/O support */
-
-int qemu_set_fd_handler2(int fd,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque);
-int qemu_set_fd_handler(int fd,
-                        IOHandler *fd_read,
-                        IOHandler *fd_write,
-                        void *opaque);
 #endif
index 14ed6b92d3cbce5102d4f153ee58f2cc54b9ec3e..2ce47aa12d710df967960e696a06413c55f55bce 100644 (file)
@@ -2,22 +2,22 @@
 #ifndef QEMU_COMMON_H
 #define QEMU_COMMON_H
 
+#include "compiler.h"
 #include "config-host.h"
 
-#define QEMU_NORETURN __attribute__ ((__noreturn__))
-#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
-#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#else
-#define QEMU_WARN_UNUSED_RESULT
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__)
+#define WORDS_ALIGNED
 #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;
-typedef struct QEMUBH QEMUBH;
 typedef struct DeviceState DeviceState;
 
+struct Monitor;
+typedef struct Monitor Monitor;
+
 /* we put basic includes here to avoid repeating them in device drivers */
 #include <stdlib.h>
 #include <stdio.h>
@@ -33,7 +33,18 @@ typedef struct DeviceState DeviceState;
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <assert.h>
+#include <signal.h>
+#include <glib.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
@@ -68,22 +79,6 @@ struct iovec {
 #include <sys/uio.h>
 #endif
 
-#if defined __GNUC__
-# if (__GNUC__ < 4) || \
-     defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4)
-   /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
-#  define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
-#  define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
-# else
-   /* Use gnu_printf when supported (qemu uses standard format strings). */
-#  define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
-#  define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
-# endif
-#else
-#define GCC_ATTR /**/
-#define GCC_FMT_ATTR(n, m)
-#endif
-
 typedef int (*fprintf_function)(FILE *f, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
 
@@ -98,17 +93,15 @@ static inline char *realpath(const char *path, char *resolved_path)
     _fullpath(resolved_path, path, _MAX_PATH);
     return resolved_path;
 }
-
-#define PRId64 "I64d"
-#define PRIx64 "I64x"
-#define PRIu64 "I64u"
-#define PRIo64 "I64o"
 #endif
 
+/* icount */
+void configure_icount(const char *option);
+extern int use_icount;
+
 /* FIXME: Remove NEED_CPU_H.  */
 #ifndef NEED_CPU_H
 
-#include <setjmp.h>
 #include "osdep.h"
 #include "bswap.h"
 
@@ -118,26 +111,10 @@ static inline char *realpath(const char *path, char *resolved_path)
 
 #endif /* !defined(NEED_CPU_H) */
 
-/* bottom halves */
-typedef void QEMUBHFunc(void *opaque);
-
-void async_context_push(void);
-void async_context_pop(void);
-int get_async_context_id(void);
-
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
-void qemu_bh_schedule(QEMUBH *bh);
-/* Bottom halfs that are scheduled from a bottom half handler are instantly
- * invoked.  This can create an infinite loop if a bottom half handler
- * schedules itself.  qemu_bh_schedule_idle() avoids this infinite loop by
- * ensuring that the bottom half isn't executed until the next main loop
- * iteration.
- */
-void qemu_bh_schedule_idle(QEMUBH *bh);
-void qemu_bh_cancel(QEMUBH *bh);
-void qemu_bh_delete(QEMUBH *bh);
-int qemu_bh_poll(void);
-void qemu_bh_update_timeout(int *timeout);
+/* main function, renamed */
+#if defined(CONFIG_COCOA)
+int qemu_main(int argc, char **argv, char **envp);
+#endif
 
 void qemu_get_timedate(struct tm *tm, int offset);
 int qemu_timedate_diff(struct tm *tm);
@@ -152,6 +129,7 @@ time_t mktimegm(struct tm *tm);
 int qemu_fls(int i);
 int qemu_fdatasync(int fd);
 int fcntl_setfl(int fd, int flag);
+int qemu_parse_fd(const char *param);
 
 /*
  * strtosz() suffixes used to specify the default treatment of an
@@ -167,6 +145,8 @@ int fcntl_setfl(int fd, int flag);
 #define STRTOSZ_DEFSUFFIX_B    'B'
 int64_t strtosz(const char *nptr, char **end);
 int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
+int64_t strtosz_suffix_unit(const char *nptr, char **end,
+                            const char default_suffix, int64_t unit);
 
 /* path.c */
 void init_paths(const char *prefix);
@@ -188,21 +168,7 @@ const char *path(const char *pathname);
 #define qemu_isascii(c)                isascii((unsigned char)(c))
 #define qemu_toascii(c)                toascii((unsigned char)(c))
 
-#ifdef _WIN32
-/* ffs() in oslib-win32.c for WIN32, strings.h for the rest of the world */
-int ffs(int i);
-#endif
-
 void *qemu_oom_check(void *ptr);
-void *qemu_malloc(size_t size);
-void *qemu_realloc(void *ptr, size_t size);
-void *qemu_mallocz(size_t size);
-void qemu_free(void *ptr);
-char *qemu_strdup(const char *str);
-char *qemu_strndup(const char *str, size_t size);
-
-void qemu_mutex_lock_iothread(void);
-void qemu_mutex_unlock_iothread(void);
 
 int qemu_open(const char *name, int flags, ...);
 ssize_t qemu_write_full(int fd, const void *buf, size_t count)
@@ -214,15 +180,16 @@ int qemu_eventfd(int pipefd[2]);
 int qemu_pipe(int pipefd[2]);
 #endif
 
+#ifdef _WIN32
+#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags)
+#else
+#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags)
+#endif
+
 /* Error handling.  */
 
 void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
-/* IO callbacks.  */
-typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
-typedef int IOCanReadHandler(void *opaque);
-typedef void IOHandler(void *opaque);
-
 struct ParallelIOArg {
     void *buffer;
     int count;
@@ -241,7 +208,7 @@ typedef struct DisplayState DisplayState;
 typedef struct DisplayChangeListener DisplayChangeListener;
 typedef struct DisplaySurface DisplaySurface;
 typedef struct DisplayAllocator DisplayAllocator;
-typedef struct QEMU_PixelFormat PixelFormat;
+typedef struct PixelFormat PixelFormat;
 typedef struct TextConsole TextConsole;
 typedef TextConsole QEMUConsole;
 typedef struct CharDriverState CharDriverState;
@@ -271,24 +238,24 @@ typedef struct I2SCodec I2SCodec;
 typedef struct SSIBus SSIBus;
 typedef struct EventNotifier EventNotifier;
 typedef struct VirtIODevice VirtIODevice;
+typedef struct QEMUSGList QEMUSGList;
 
 typedef uint64_t pcibus_t;
 
-void cpu_exec_init_all(unsigned long tb_size);
+void tcg_exec_init(unsigned long tb_size);
+bool tcg_enabled(void);
+
+void cpu_exec_init_all(void);
 
 /* CPU save/load.  */
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
-/* Force QEMU to stop what it's doing and service IO */
-void qemu_service_io(void);
-
-/* Force QEMU to process pending events */
-void qemu_notify_event(void);
-
 /* Unblock cpu */
 void qemu_cpu_kick(void *env);
-int qemu_cpu_self(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 {
@@ -325,8 +292,19 @@ 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);
 
-struct Monitor;
-typedef struct Monitor Monitor;
+void qemu_progress_init(int enabled, float min_skip);
+void qemu_progress_end(void);
+void qemu_progress_print(float delta, 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..597d7e10b18d19572d9f3038144e0c9dc2d969e5 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 = {
@@ -24,6 +23,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "index",
             .type = QEMU_OPT_NUMBER,
+            .help = "index number",
         },{
             .name = "cyls",
             .type = QEMU_OPT_NUMBER,
@@ -47,6 +47,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "snapshot",
             .type = QEMU_OPT_BOOL,
+            .help = "enable/disable snapshot mode",
         },{
             .name = "file",
             .type = QEMU_OPT_STRING,
@@ -54,7 +55,8 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "cache",
             .type = QEMU_OPT_STRING,
-            .help = "host cache usage (none, writeback, writethrough, unsafe)",
+            .help = "host cache usage (none, writeback, writethrough, "
+                    "directsync, unsafe)",
         },{
             .name = "aio",
             .type = QEMU_OPT_STRING,
@@ -66,12 +68,15 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "serial",
             .type = QEMU_OPT_STRING,
+            .help = "disk serial number",
         },{
             .name = "rerror",
             .type = QEMU_OPT_STRING,
+            .help = "read error action",
         },{
             .name = "werror",
             .type = QEMU_OPT_STRING,
+            .help = "write error action",
         },{
             .name = "addr",
             .type = QEMU_OPT_STRING,
@@ -79,6 +84,7 @@ static QemuOptsList qemu_drive_opts = {
         },{
             .name = "readonly",
             .type = QEMU_OPT_BOOL,
+            .help = "open drive file as read-only",
         },
         { /* end of list */ }
     },
@@ -159,11 +165,11 @@ static QemuOptsList qemu_chardev_opts = {
 
 QemuOptsList qemu_fsdev_opts = {
     .name = "fsdev",
-    .implied_opt_name = "fstype",
+    .implied_opt_name = "fsdriver",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
     .desc = {
         {
-            .name = "fstype",
+            .name = "fsdriver",
             .type = QEMU_OPT_STRING,
         }, {
             .name = "path",
@@ -171,18 +177,25 @@ QemuOptsList qemu_fsdev_opts = {
         }, {
             .name = "security_model",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "writeout",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "readonly",
+            .type = QEMU_OPT_BOOL,
         },
+
         { /*End of list */ }
     },
 };
 
 QemuOptsList qemu_virtfs_opts = {
     .name = "virtfs",
-    .implied_opt_name = "fstype",
+    .implied_opt_name = "fsdriver",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
     .desc = {
         {
-            .name = "fstype",
+            .name = "fsdriver",
             .type = QEMU_OPT_STRING,
         }, {
             .name = "path",
@@ -193,6 +206,12 @@ QemuOptsList qemu_virtfs_opts = {
         }, {
             .name = "security_model",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "writeout",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "readonly",
+            .type = QEMU_OPT_BOOL,
         },
 
         { /*End of list */ }
@@ -297,20 +316,21 @@ static QemuOptsList qemu_mon_opts = {
     },
 };
 
-#ifdef CONFIG_SIMPLE_TRACE
 static QemuOptsList qemu_trace_opts = {
     .name = "trace",
     .implied_opt_name = "trace",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
     .desc = {
         {
+            .name = "events",
+            .type = QEMU_OPT_STRING,
+        },{
             .name = "file",
             .type = QEMU_OPT_STRING,
         },
-        { /* end if list */ }
+        { /* end of list */ }
     },
 };
-#endif
 
 static QemuOptsList qemu_cpudef_opts = {
     .name = "cpudef",
@@ -385,6 +405,12 @@ QemuOptsList qemu_spice_opts = {
         },{
             .name = "disable-ticketing",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "disable-copy-paste",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "sasl",
+            .type = QEMU_OPT_BOOL,
         },{
             .name = "x509-dir",
             .type = QEMU_OPT_STRING,
@@ -431,7 +457,7 @@ QemuOptsList qemu_spice_opts = {
             .name = "playback-compression",
             .type = QEMU_OPT_BOOL,
         },
-        { /* end if list */ }
+        { /* end of list */ }
     },
 };
 
@@ -447,7 +473,51 @@ QemuOptsList qemu_option_rom_opts = {
             .name = "romfile",
             .type = QEMU_OPT_STRING,
         },
-        { /* end if list */ }
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_machine_opts = {
+    .name = "machine",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
+    .desc = {
+        {
+            .name = "type",
+            .type = QEMU_OPT_STRING,
+            .help = "emulated machine"
+        }, {
+            .name = "accel",
+            .type = QEMU_OPT_STRING,
+            .help = "accelerator list",
+        },
+        { /* End of list */ }
+    },
+};
+
+QemuOptsList qemu_boot_opts = {
+    .name = "boot-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
+    .desc = {
+        /* the three names below are not used now */
+        {
+            .name = "order",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "once",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "menu",
+            .type = QEMU_OPT_STRING,
+        /* following are really used */
+        }, {
+            .name = "splash",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "splash-time",
+            .type = QEMU_OPT_STRING,
+        },
+        { /*End of list */ }
     },
 };
 
@@ -461,10 +531,10 @@ static QemuOptsList *vm_config_groups[32] = {
     &qemu_global_opts,
     &qemu_mon_opts,
     &qemu_cpudef_opts,
-#ifdef CONFIG_SIMPLE_TRACE
     &qemu_trace_opts,
-#endif
     &qemu_option_rom_opts,
+    &qemu_machine_opts,
+    &qemu_boot_opts,
     NULL,
 };
 
diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h
new file mode 100644 (file)
index 0000000..d495615
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Coroutine internals
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf@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.
+ */
+
+#ifndef QEMU_COROUTINE_INT_H
+#define QEMU_COROUTINE_INT_H
+
+#include "qemu-queue.h"
+#include "qemu-coroutine.h"
+
+typedef enum {
+    COROUTINE_YIELD = 1,
+    COROUTINE_TERMINATE = 2,
+} CoroutineAction;
+
+struct Coroutine {
+    CoroutineEntry *entry;
+    void *entry_arg;
+    Coroutine *caller;
+    QLIST_ENTRY(Coroutine) pool_next;
+    QTAILQ_ENTRY(Coroutine) co_queue_next;
+};
+
+Coroutine *qemu_coroutine_new(void);
+void qemu_coroutine_delete(Coroutine *co);
+CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to,
+                                      CoroutineAction action);
+
+#endif
diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
new file mode 100644 (file)
index 0000000..6b58160
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * coroutine queues and locks
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf@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 "qemu-coroutine.h"
+#include "qemu-coroutine-int.h"
+#include "qemu-queue.h"
+#include "main-loop.h"
+#include "trace.h"
+
+static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
+    QTAILQ_HEAD_INITIALIZER(unlock_bh_queue);
+static QEMUBH* unlock_bh;
+
+static void qemu_co_queue_next_bh(void *opaque)
+{
+    Coroutine *next;
+
+    trace_qemu_co_queue_next_bh();
+    while ((next = QTAILQ_FIRST(&unlock_bh_queue))) {
+        QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next);
+        qemu_coroutine_enter(next, NULL);
+    }
+}
+
+void qemu_co_queue_init(CoQueue *queue)
+{
+    QTAILQ_INIT(&queue->entries);
+
+    if (!unlock_bh) {
+        unlock_bh = qemu_bh_new(qemu_co_queue_next_bh, NULL);
+    }
+}
+
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
+{
+    Coroutine *self = qemu_coroutine_self();
+    QTAILQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
+    qemu_coroutine_yield();
+    assert(qemu_in_coroutine());
+}
+
+bool qemu_co_queue_next(CoQueue *queue)
+{
+    Coroutine *next;
+
+    next = QTAILQ_FIRST(&queue->entries);
+    if (next) {
+        QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
+        QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next);
+        trace_qemu_co_queue_next(next);
+        qemu_bh_schedule(unlock_bh);
+    }
+
+    return (next != NULL);
+}
+
+bool qemu_co_queue_empty(CoQueue *queue)
+{
+    return (QTAILQ_FIRST(&queue->entries) == NULL);
+}
+
+void qemu_co_mutex_init(CoMutex *mutex)
+{
+    memset(mutex, 0, sizeof(*mutex));
+    qemu_co_queue_init(&mutex->queue);
+}
+
+void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_co_mutex_lock_entry(mutex, self);
+
+    while (mutex->locked) {
+        qemu_co_queue_wait(&mutex->queue);
+    }
+
+    mutex->locked = true;
+
+    trace_qemu_co_mutex_lock_return(mutex, self);
+}
+
+void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_co_mutex_unlock_entry(mutex, self);
+
+    assert(mutex->locked == true);
+    assert(qemu_in_coroutine());
+
+    mutex->locked = false;
+    qemu_co_queue_next(&mutex->queue);
+
+    trace_qemu_co_mutex_unlock_return(mutex, self);
+}
+
+void qemu_co_rwlock_init(CoRwlock *lock)
+{
+    memset(lock, 0, sizeof(*lock));
+    qemu_co_queue_init(&lock->queue);
+}
+
+void qemu_co_rwlock_rdlock(CoRwlock *lock)
+{
+    while (lock->writer) {
+        qemu_co_queue_wait(&lock->queue);
+    }
+    lock->reader++;
+}
+
+void qemu_co_rwlock_unlock(CoRwlock *lock)
+{
+    assert(qemu_in_coroutine());
+    if (lock->writer) {
+        lock->writer = false;
+        while (!qemu_co_queue_empty(&lock->queue)) {
+            /*
+             * Wakeup every body. This will include some
+             * writers too.
+             */
+            qemu_co_queue_next(&lock->queue);
+        }
+    } else {
+        lock->reader--;
+        assert(lock->reader >= 0);
+        /* Wakeup only one waiting writer */
+        if (!lock->reader) {
+            qemu_co_queue_next(&lock->queue);
+        }
+    }
+}
+
+void qemu_co_rwlock_wrlock(CoRwlock *lock)
+{
+    while (lock->writer || lock->reader) {
+        qemu_co_queue_wait(&lock->queue);
+    }
+    lock->writer = true;
+}
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
new file mode 100644 (file)
index 0000000..600be26
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * QEMU coroutines
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *  Kevin Wolf         <kwolf@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "qemu-common.h"
+#include "qemu-coroutine.h"
+#include "qemu-coroutine-int.h"
+
+Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
+{
+    Coroutine *co = qemu_coroutine_new();
+    co->entry = entry;
+    return co;
+}
+
+static void coroutine_swap(Coroutine *from, Coroutine *to)
+{
+    CoroutineAction ret;
+
+    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
+
+    switch (ret) {
+    case COROUTINE_YIELD:
+        return;
+    case COROUTINE_TERMINATE:
+        trace_qemu_coroutine_terminate(to);
+        qemu_coroutine_delete(to);
+        return;
+    default:
+        abort();
+    }
+}
+
+void qemu_coroutine_enter(Coroutine *co, void *opaque)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_coroutine_enter(self, co, opaque);
+
+    if (co->caller) {
+        fprintf(stderr, "Co-routine re-entered recursively\n");
+        abort();
+    }
+
+    co->caller = self;
+    co->entry_arg = opaque;
+    coroutine_swap(self, co);
+}
+
+void coroutine_fn qemu_coroutine_yield(void)
+{
+    Coroutine *self = qemu_coroutine_self();
+    Coroutine *to = self->caller;
+
+    trace_qemu_coroutine_yield(self, to);
+
+    if (!to) {
+        fprintf(stderr, "Co-routine is yielding to no one\n");
+        abort();
+    }
+
+    self->caller = NULL;
+    coroutine_swap(self, to);
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
new file mode 100644 (file)
index 0000000..b8fc4f4
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * QEMU coroutine implementation
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *  Kevin Wolf         <kwolf@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_COROUTINE_H
+#define QEMU_COROUTINE_H
+
+#include <stdbool.h>
+#include "qemu-queue.h"
+
+/**
+ * Coroutines are a mechanism for stack switching and can be used for
+ * cooperative userspace threading.  These functions provide a simple but
+ * useful flavor of coroutines that is suitable for writing sequential code,
+ * rather than callbacks, for operations that need to give up control while
+ * waiting for events to complete.
+ *
+ * These functions are re-entrant and may be used outside the global mutex.
+ */
+
+/**
+ * Mark a function that executes in coroutine context
+ *
+ * Functions that execute in coroutine context cannot be called directly from
+ * normal functions.  In the future it would be nice to enable compiler or
+ * static checker support for catching such errors.  This annotation might make
+ * it possible and in the meantime it serves as documentation.
+ *
+ * For example:
+ *
+ *   static void coroutine_fn foo(void) {
+ *       ....
+ *   }
+ */
+#define coroutine_fn
+
+typedef struct Coroutine Coroutine;
+
+/**
+ * Coroutine entry point
+ *
+ * When the coroutine is entered for the first time, opaque is passed in as an
+ * argument.
+ *
+ * When this function returns, the coroutine is destroyed automatically and
+ * execution continues in the caller who last entered the coroutine.
+ */
+typedef void coroutine_fn CoroutineEntry(void *opaque);
+
+/**
+ * Create a new coroutine
+ *
+ * Use qemu_coroutine_enter() to actually transfer control to the coroutine.
+ */
+Coroutine *qemu_coroutine_create(CoroutineEntry *entry);
+
+/**
+ * Transfer control to a coroutine
+ *
+ * The opaque argument is passed as the argument to the entry point when
+ * entering the coroutine for the first time.  It is subsequently ignored.
+ */
+void qemu_coroutine_enter(Coroutine *coroutine, void *opaque);
+
+/**
+ * Transfer control back to a coroutine's caller
+ *
+ * This function does not return until the coroutine is re-entered using
+ * qemu_coroutine_enter().
+ */
+void coroutine_fn qemu_coroutine_yield(void);
+
+/**
+ * Get the currently executing coroutine
+ */
+Coroutine *coroutine_fn qemu_coroutine_self(void);
+
+/**
+ * Return whether or not currently inside a coroutine
+ *
+ * This can be used to write functions that work both when in coroutine context
+ * and when not in coroutine context.  Note that such functions cannot use the
+ * coroutine_fn annotation since they work outside coroutine context.
+ */
+bool qemu_in_coroutine(void);
+
+
+
+/**
+ * CoQueues are a mechanism to queue coroutines in order to continue executing
+ * them later. They provide the fundamental primitives on which coroutine locks
+ * are built.
+ */
+typedef struct CoQueue {
+    QTAILQ_HEAD(, Coroutine) entries;
+} CoQueue;
+
+/**
+ * Initialise a CoQueue. This must be called before any other operation is used
+ * on the CoQueue.
+ */
+void qemu_co_queue_init(CoQueue *queue);
+
+/**
+ * Adds the current coroutine to the CoQueue and transfers control to the
+ * caller of the coroutine.
+ */
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
+
+/**
+ * Restarts the next coroutine in the CoQueue and removes it from the queue.
+ *
+ * Returns true if a coroutine was restarted, false if the queue is empty.
+ */
+bool qemu_co_queue_next(CoQueue *queue);
+
+/**
+ * Checks if the CoQueue is empty.
+ */
+bool qemu_co_queue_empty(CoQueue *queue);
+
+
+/**
+ * Provides a mutex that can be used to synchronise coroutines
+ */
+typedef struct CoMutex {
+    bool locked;
+    CoQueue queue;
+} CoMutex;
+
+/**
+ * Initialises a CoMutex. This must be called before any other operation is used
+ * on the CoMutex.
+ */
+void qemu_co_mutex_init(CoMutex *mutex);
+
+/**
+ * Locks the mutex. If the lock cannot be taken immediately, control is
+ * transferred to the caller of the current coroutine.
+ */
+void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
+
+/**
+ * Unlocks the mutex and schedules the next coroutine that was waiting for this
+ * lock to be run.
+ */
+void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);
+
+typedef struct CoRwlock {
+    bool writer;
+    int reader;
+    CoQueue queue;
+} CoRwlock;
+
+/**
+ * Initialises a CoRwlock. This must be called before any other operation
+ * is used on the CoRwlock
+ */
+void qemu_co_rwlock_init(CoRwlock *lock);
+
+/**
+ * Read locks the CoRwlock. If the lock cannot be taken immediately because
+ * of a parallel writer, control is transferred to the caller of the current
+ * coroutine.
+ */
+void qemu_co_rwlock_rdlock(CoRwlock *lock);
+
+/**
+ * Write Locks the mutex. If the lock cannot be taken immediately because
+ * of a parallel reader, control is transferred to the caller of the current
+ * coroutine.
+ */
+void qemu_co_rwlock_wrlock(CoRwlock *lock);
+
+/**
+ * Unlocks the read/write lock and schedules the next coroutine that was
+ * waiting for this lock to be run.
+ */
+void qemu_co_rwlock_unlock(CoRwlock *lock);
+
+#endif /* QEMU_COROUTINE_H */
index 86e017ccfad6aa5f9cffdda26b94ab764cfff4c4..9c3cb62ee3765ad0402ed7ff3a94d769d9e5714a 100644 (file)
@@ -110,6 +110,7 @@ For system emulation, the following hardware targets are supported:
 @item Syborg SVP base model (ARM Cortex-A8).
 @item AXIS-Devboard88 (CRISv32 ETRAX-FS).
 @item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze).
+@item Avnet LX60/LX110/LX200 boards (Xtensa)
 @end itemize
 
 @cindex supported user mode targets
@@ -226,7 +227,7 @@ QEMU uses YM3812 emulation by Tatsuyuki Satoh.
 QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
 by Tibor "TS" Schütz.
 
-Not that, by default, GUS shares IRQ(7) with parallel ports and so
+Note that, by default, GUS shares IRQ(7) with parallel ports and so
 qemu must be told to not have parallel ports to have working GUS
 
 @example
@@ -278,12 +279,24 @@ targets do not need a disk image.
 
 @c man begin OPTIONS
 
-During the graphical emulation, you can use the following keys:
+During the graphical emulation, you can use special key combinations to change
+modes. The default key mappings are shown below, but if you use @code{-alt-grab}
+then the modifier is Ctrl-Alt-Shift (instead of Ctrl-Alt) and if you use
+@code{-ctrl-grab} then the modifier is the right Ctrl key (instead of Ctrl-Alt):
+
 @table @key
 @item Ctrl-Alt-f
 @kindex Ctrl-Alt-f
 Toggle full screen
 
+@item Ctrl-Alt-+
+@kindex Ctrl-Alt-+
+Enlarge the screen
+
+@item Ctrl-Alt--
+@kindex Ctrl-Alt--
+Shrink the screen
+
 @item Ctrl-Alt-u
 @kindex Ctrl-Alt-u
 Restore the screen's un-scaled dimensions
@@ -408,6 +421,7 @@ snapshots.
 * disk_images_fat_images::    Virtual FAT disk images
 * disk_images_nbd::           NBD access
 * disk_images_sheepdog::      Sheepdog disk images
+* disk_images_iscsi::         iSCSI LUNs
 @end menu
 
 @node disk_images_quickstart
@@ -682,6 +696,61 @@ qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size}
 qemu sheepdog:@var{hostname}:@var{port}:@var{image}
 @end example
 
+@node disk_images_iscsi
+@subsection iSCSI LUNs
+
+iSCSI is a popular protocol used to access SCSI devices across a computer
+network.
+
+There are two different ways iSCSI devices can be used by QEMU.
+
+The first method is to mount the iSCSI LUN on the host, and make it appear as
+any other ordinary SCSI device on the host and then to access this device as a
+/dev/sd device from QEMU. How to do this differs between host OSes.
+
+The second method involves using the iSCSI initiator that is built into
+QEMU. This provides a mechanism that works the same way regardless of which
+host OS you are running QEMU on. This section will describe this second method
+of using iSCSI together with QEMU.
+
+In QEMU, iSCSI devices are described using special iSCSI URLs
+
+@example
+URL syntax:
+iscsi://[<username>[%<password>]@@]<host>[:<port>]/<target-iqn-name>/<lun>
+@end example
+
+Username and password are optional and only used if your target is set up
+using CHAP authentication for access control.
+Alternatively the username and password can also be set via environment
+variables to have these not show up in the process list
+
+@example
+export LIBISCSI_CHAP_USERNAME=<username>
+export LIBISCSI_CHAP_PASSWORD=<password>
+iscsi://<host>/<target-iqn-name>/<lun>
+@end example
+
+Howto set up a simple iSCSI target on loopback and accessing it via QEMU:
+@example
+This example shows how to set up an iSCSI target with one CDROM and one DISK
+using the Linux STGT software target. This target is available on Red Hat based
+systems as the package 'scsi-target-utils'.
+
+tgtd --iscsi portal=127.0.0.1:3260
+tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.qemu.test
+tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 \
+    -b /IMAGES/disk.img --device-type=disk
+tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \
+    -b /IMAGES/cd.iso --device-type=cd
+tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
+
+qemu-system-i386 -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+    -cdrom iscsi://127.0.0.1/iqn.qemu.test/2
+@end example
+
+
+
 @node pcsys_network
 @section Network emulation
 
@@ -1434,6 +1503,7 @@ differences are mentioned in the following sections.
 * Cris System emulator::
 * Microblaze System emulator::
 * SH4 System emulator::
+* Xtensa System emulator::
 @end menu
 
 @node PowerPC System emulator
@@ -1735,7 +1805,7 @@ PC Keyboard
 IDE controller
 @end itemize
 
-The mipssim pseudo board emulation provides an environment similiar
+The mipssim pseudo board emulation provides an environment similar
 to what the proprietary MIPS emulator uses for running Linux.
 It supports:
 
@@ -2112,6 +2182,59 @@ TODO
 
 TODO
 
+@node Xtensa System emulator
+@section Xtensa System emulator
+@cindex system emulation (Xtensa)
+
+Two executables cover simulation of both Xtensa endian options,
+@file{qemu-system-xtensa} and @file{qemu-system-xtensaeb}.
+Two different machine types are emulated:
+
+@itemize @minus
+@item
+Xtensa emulator pseudo board "sim"
+@item
+Avnet LX60/LX110/LX200 board
+@end itemize
+
+The sim pseudo board emulation provides an environment similar
+to one provided by the proprietary Tensilica ISS.
+It supports:
+
+@itemize @minus
+@item
+A range of Xtensa CPUs, default is the DC232B
+@item
+Console and filesystem access via semihosting calls
+@end itemize
+
+The Avnet LX60/LX110/LX200 emulation supports:
+
+@itemize @minus
+@item
+A range of Xtensa CPUs, default is the DC232B
+@item
+16550 UART
+@item
+OpenCores 10/100 Mbps Ethernet MAC
+@end itemize
+
+@c man begin OPTIONS
+
+The following options are specific to the Xtensa emulation:
+
+@table @option
+
+@item -semihosting
+Enable semihosting syscall emulation.
+
+Xtensa semihosting provides basic file IO calls, such as open/read/write/seek/select.
+Tensilica baremetal libc for ISS and linux platform "sim" use this interface.
+
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
+
+@end table
 @node QEMU User space emulator
 @chapter QEMU User space emulator
 
index 5a35e7c1c2c0f9fa63fcf4bccba8a804af09619c..4b20d283a2a6e2ea1d62454726de3b7d201f8767 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.
@@ -194,6 +193,8 @@ void error_print_loc(void)
 
 /*
  * Print an error message to current monitor if we have one, else to stderr.
+ * Format arguments like sprintf().  The result should not contain
+ * newlines.
  * Prepend the current location and append a newline.
  * It's wrong to call this in a QMP monitor.  Use qerror_report() there.
  */
diff --git a/qemu-ga.c b/qemu-ga.c
new file mode 100644 (file)
index 0000000..4932013
--- /dev/null
+++ b/qemu-ga.c
@@ -0,0 +1,637 @@
+/*
+ * QEMU Guest Agent
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <getopt.h>
+#include <termios.h>
+#include <syslog.h>
+#include "qemu_socket.h"
+#include "json-streamer.h"
+#include "json-parser.h"
+#include "qint.h"
+#include "qjson.h"
+#include "qga/guest-agent-core.h"
+#include "module.h"
+#include "signal.h"
+#include "qerror.h"
+#include "error_int.h"
+
+#define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
+#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
+#define QGA_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
+#define QGA_TIMEOUT_DEFAULT 30*1000 /* ms */
+
+struct GAState {
+    JSONMessageParser parser;
+    GMainLoop *main_loop;
+    GIOChannel *conn_channel;
+    GIOChannel *listen_channel;
+    const char *path;
+    const char *method;
+    bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
+    GACommandState *command_state;
+    GLogLevelFlags log_level;
+    FILE *log_file;
+    bool logging_enabled;
+};
+
+static struct GAState *ga_state;
+
+static void quit_handler(int sig)
+{
+    g_debug("received signal num %d, quitting", sig);
+
+    if (g_main_loop_is_running(ga_state->main_loop)) {
+        g_main_loop_quit(ga_state->main_loop);
+    }
+}
+
+static void register_signal_handlers(void)
+{
+    struct sigaction sigact;
+    int ret;
+
+    memset(&sigact, 0, sizeof(struct sigaction));
+    sigact.sa_handler = quit_handler;
+
+    ret = sigaction(SIGINT, &sigact, NULL);
+    if (ret == -1) {
+        g_error("error configuring signal handler: %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    ret = sigaction(SIGTERM, &sigact, NULL);
+    if (ret == -1) {
+        g_error("error configuring signal handler: %s", strerror(errno));
+    }
+}
+
+static void usage(const char *cmd)
+{
+    printf(
+"Usage: %s -c <channel_opts>\n"
+"QEMU Guest Agent %s\n"
+"\n"
+"  -m, --method      transport method: one of unix-listen, virtio-serial, or\n"
+"                    isa-serial (virtio-serial is the default)\n"
+"  -p, --path        device/socket path (%s is the default for virtio-serial)\n"
+"  -l, --logfile     set logfile path, logs to stderr by default\n"
+"  -f, --pidfile     specify pidfile (default is %s)\n"
+"  -v, --verbose     log extra debugging information\n"
+"  -V, --version     print version information and exit\n"
+"  -d, --daemonize   become a daemon\n"
+"  -h, --help        display this help and exit\n"
+"\n"
+"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
+    , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT);
+}
+
+static void conn_channel_close(GAState *s);
+
+static const char *ga_log_level_str(GLogLevelFlags level)
+{
+    switch (level & G_LOG_LEVEL_MASK) {
+        case G_LOG_LEVEL_ERROR:
+            return "error";
+        case G_LOG_LEVEL_CRITICAL:
+            return "critical";
+        case G_LOG_LEVEL_WARNING:
+            return "warning";
+        case G_LOG_LEVEL_MESSAGE:
+            return "message";
+        case G_LOG_LEVEL_INFO:
+            return "info";
+        case G_LOG_LEVEL_DEBUG:
+            return "debug";
+        default:
+            return "user";
+    }
+}
+
+bool ga_logging_enabled(GAState *s)
+{
+    return s->logging_enabled;
+}
+
+void ga_disable_logging(GAState *s)
+{
+    s->logging_enabled = false;
+}
+
+void ga_enable_logging(GAState *s)
+{
+    s->logging_enabled = true;
+}
+
+static void ga_log(const gchar *domain, GLogLevelFlags level,
+                   const gchar *msg, gpointer opaque)
+{
+    GAState *s = opaque;
+    GTimeVal time;
+    const char *level_str = ga_log_level_str(level);
+
+    if (!ga_logging_enabled(s)) {
+        return;
+    }
+
+    level &= G_LOG_LEVEL_MASK;
+    if (domain && strcmp(domain, "syslog") == 0) {
+        syslog(LOG_INFO, "%s: %s", level_str, msg);
+    } else if (level & s->log_level) {
+        g_get_current_time(&time);
+        fprintf(s->log_file,
+                "%lu.%lu: %s: %s\n", time.tv_sec, time.tv_usec, level_str, msg);
+        fflush(s->log_file);
+    }
+}
+
+static void become_daemon(const char *pidfile)
+{
+    pid_t pid, sid;
+    int pidfd;
+    char *pidstr = NULL;
+
+    pid = fork();
+    if (pid < 0) {
+        exit(EXIT_FAILURE);
+    }
+    if (pid > 0) {
+        exit(EXIT_SUCCESS);
+    }
+
+    pidfd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, S_IRUSR|S_IWUSR);
+    if (pidfd == -1) {
+        g_critical("Cannot create pid file, %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    if (asprintf(&pidstr, "%d", getpid()) == -1) {
+        g_critical("Cannot allocate memory");
+        goto fail;
+    }
+    if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
+        free(pidstr);
+        g_critical("Failed to write pid file");
+        goto fail;
+    }
+
+    umask(0);
+    sid = setsid();
+    if (sid < 0) {
+        goto fail;
+    }
+    if ((chdir("/")) < 0) {
+        goto fail;
+    }
+
+    close(STDIN_FILENO);
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+    free(pidstr);
+    return;
+
+fail:
+    unlink(pidfile);
+    g_critical("failed to daemonize");
+    exit(EXIT_FAILURE);
+}
+
+static int conn_channel_send_buf(GIOChannel *channel, const char *buf,
+                                 gsize count)
+{
+    GError *err = NULL;
+    gsize written = 0;
+    GIOStatus status;
+
+    while (count) {
+        status = g_io_channel_write_chars(channel, buf, count, &written, &err);
+        g_debug("sending data, count: %d", (int)count);
+        if (err != NULL) {
+            g_warning("error sending newline: %s", err->message);
+            return err->code;
+        }
+        if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
+            return -EPIPE;
+        }
+
+        if (status == G_IO_STATUS_NORMAL) {
+            count -= written;
+        }
+    }
+
+    return 0;
+}
+
+static int conn_channel_send_payload(GIOChannel *channel, QObject *payload)
+{
+    int ret = 0;
+    const char *buf;
+    QString *payload_qstr;
+    GError *err = NULL;
+
+    g_assert(payload && channel);
+
+    payload_qstr = qobject_to_json(payload);
+    if (!payload_qstr) {
+        return -EINVAL;
+    }
+
+    qstring_append_chr(payload_qstr, '\n');
+    buf = qstring_get_str(payload_qstr);
+    ret = conn_channel_send_buf(channel, buf, strlen(buf));
+    if (ret) {
+        goto out_free;
+    }
+
+    g_io_channel_flush(channel, &err);
+    if (err != NULL) {
+        g_warning("error flushing payload: %s", err->message);
+        ret = err->code;
+        goto out_free;
+    }
+
+out_free:
+    QDECREF(payload_qstr);
+    if (err) {
+        g_error_free(err);
+    }
+    return ret;
+}
+
+static void process_command(GAState *s, QDict *req)
+{
+    QObject *rsp = NULL;
+    int ret;
+
+    g_assert(req);
+    g_debug("processing command");
+    rsp = qmp_dispatch(QOBJECT(req));
+    if (rsp) {
+        ret = conn_channel_send_payload(s->conn_channel, rsp);
+        if (ret) {
+            g_warning("error sending payload: %s", strerror(ret));
+        }
+        qobject_decref(rsp);
+    } else {
+        g_warning("error getting response");
+    }
+}
+
+/* handle requests/control events coming in over the channel */
+static void process_event(JSONMessageParser *parser, QList *tokens)
+{
+    GAState *s = container_of(parser, GAState, parser);
+    QObject *obj;
+    QDict *qdict;
+    Error *err = NULL;
+    int ret;
+
+    g_assert(s && parser);
+
+    g_debug("process_event: called");
+    obj = json_parser_parse_err(tokens, NULL, &err);
+    if (err || !obj || qobject_type(obj) != QTYPE_QDICT) {
+        qobject_decref(obj);
+        qdict = qdict_new();
+        if (!err) {
+            g_warning("failed to parse event: unknown error");
+            error_set(&err, QERR_JSON_PARSING);
+        } else {
+            g_warning("failed to parse event: %s", error_get_pretty(err));
+        }
+        qdict_put_obj(qdict, "error", error_get_qobject(err));
+        error_free(err);
+    } else {
+        qdict = qobject_to_qdict(obj);
+    }
+
+    g_assert(qdict);
+
+    /* handle host->guest commands */
+    if (qdict_haskey(qdict, "execute")) {
+        process_command(s, qdict);
+    } else {
+        if (!qdict_haskey(qdict, "error")) {
+            QDECREF(qdict);
+            qdict = qdict_new();
+            g_warning("unrecognized payload format");
+            error_set(&err, QERR_UNSUPPORTED);
+            qdict_put_obj(qdict, "error", error_get_qobject(err));
+            error_free(err);
+        }
+        ret = conn_channel_send_payload(s->conn_channel, QOBJECT(qdict));
+        if (ret) {
+            g_warning("error sending payload: %s", strerror(ret));
+        }
+    }
+
+    QDECREF(qdict);
+}
+
+static gboolean conn_channel_read(GIOChannel *channel, GIOCondition condition,
+                                  gpointer data)
+{
+    GAState *s = data;
+    gchar buf[1024];
+    gsize count;
+    GError *err = NULL;
+    memset(buf, 0, 1024);
+    GIOStatus status = g_io_channel_read_chars(channel, buf, 1024,
+                                               &count, &err);
+    if (err != NULL) {
+        g_warning("error reading channel: %s", err->message);
+        conn_channel_close(s);
+        g_error_free(err);
+        return false;
+    }
+    switch (status) {
+    case G_IO_STATUS_ERROR:
+        g_warning("problem");
+        return false;
+    case G_IO_STATUS_NORMAL:
+        g_debug("read data, count: %d, data: %s", (int)count, buf);
+        json_message_parser_feed(&s->parser, (char *)buf, (int)count);
+    case G_IO_STATUS_AGAIN:
+        /* virtio causes us to spin here when no process is attached to
+         * host-side chardev. sleep a bit to mitigate this
+         */
+        if (s->virtio) {
+            usleep(100*1000);
+        }
+        return true;
+    case G_IO_STATUS_EOF:
+        g_debug("received EOF");
+        conn_channel_close(s);
+        if (s->virtio) {
+            return true;
+        }
+        return false;
+    default:
+        g_warning("unknown channel read status, closing");
+        conn_channel_close(s);
+        return false;
+    }
+    return true;
+}
+
+static int conn_channel_add(GAState *s, int fd)
+{
+    GIOChannel *conn_channel;
+    GError *err = NULL;
+
+    g_assert(s && !s->conn_channel);
+    conn_channel = g_io_channel_unix_new(fd);
+    g_assert(conn_channel);
+    g_io_channel_set_encoding(conn_channel, NULL, &err);
+    if (err != NULL) {
+        g_warning("error setting channel encoding to binary");
+        g_error_free(err);
+        return -1;
+    }
+    g_io_add_watch(conn_channel, G_IO_IN | G_IO_HUP,
+                   conn_channel_read, s);
+    s->conn_channel = conn_channel;
+    return 0;
+}
+
+static gboolean listen_channel_accept(GIOChannel *channel,
+                                      GIOCondition condition, gpointer data)
+{
+    GAState *s = data;
+    g_assert(channel != NULL);
+    int ret, conn_fd;
+    bool accepted = false;
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+
+    conn_fd = qemu_accept(g_io_channel_unix_get_fd(s->listen_channel),
+                             (struct sockaddr *)&addr, &addrlen);
+    if (conn_fd == -1) {
+        g_warning("error converting fd to gsocket: %s", strerror(errno));
+        goto out;
+    }
+    fcntl(conn_fd, F_SETFL, O_NONBLOCK);
+    ret = conn_channel_add(s, conn_fd);
+    if (ret) {
+        g_warning("error setting up connection");
+        goto out;
+    }
+    accepted = true;
+
+out:
+    /* only accept 1 connection at a time */
+    return !accepted;
+}
+
+/* start polling for readable events on listen fd, new==true
+ * indicates we should use the existing s->listen_channel
+ */
+static int listen_channel_add(GAState *s, int listen_fd, bool new)
+{
+    if (new) {
+        s->listen_channel = g_io_channel_unix_new(listen_fd);
+    }
+    g_io_add_watch(s->listen_channel, G_IO_IN,
+                   listen_channel_accept, s);
+    return 0;
+}
+
+/* cleanup state for closed connection/session, start accepting new
+ * connections if we're in listening mode
+ */
+static void conn_channel_close(GAState *s)
+{
+    if (strcmp(s->method, "unix-listen") == 0) {
+        g_io_channel_shutdown(s->conn_channel, true, NULL);
+        listen_channel_add(s, 0, false);
+    } else if (strcmp(s->method, "virtio-serial") == 0) {
+        /* we spin on EOF for virtio-serial, so back off a bit. also,
+         * dont close the connection in this case, it'll resume normal
+         * operation when another process connects to host chardev
+         */
+        usleep(100*1000);
+        goto out_noclose;
+    }
+    g_io_channel_unref(s->conn_channel);
+    s->conn_channel = NULL;
+out_noclose:
+    return;
+}
+
+static void init_guest_agent(GAState *s)
+{
+    struct termios tio;
+    int ret, fd;
+
+    if (s->method == NULL) {
+        /* try virtio-serial as our default */
+        s->method = "virtio-serial";
+    }
+
+    if (s->path == NULL) {
+        if (strcmp(s->method, "virtio-serial") != 0) {
+            g_critical("must specify a path for this channel");
+            exit(EXIT_FAILURE);
+        }
+        /* try the default path for the virtio-serial port */
+        s->path = QGA_VIRTIO_PATH_DEFAULT;
+    }
+
+    if (strcmp(s->method, "virtio-serial") == 0) {
+        s->virtio = true;
+        fd = qemu_open(s->path, O_RDWR | O_NONBLOCK | O_ASYNC);
+        if (fd == -1) {
+            g_critical("error opening channel: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        ret = conn_channel_add(s, fd);
+        if (ret) {
+            g_critical("error adding channel to main loop");
+            exit(EXIT_FAILURE);
+        }
+    } else if (strcmp(s->method, "isa-serial") == 0) {
+        fd = qemu_open(s->path, O_RDWR | O_NOCTTY);
+        if (fd == -1) {
+            g_critical("error opening channel: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        tcgetattr(fd, &tio);
+        /* set up serial port for non-canonical, dumb byte streaming */
+        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
+                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
+                         IMAXBEL);
+        tio.c_oflag = 0;
+        tio.c_lflag = 0;
+        tio.c_cflag |= QGA_BAUDRATE_DEFAULT;
+        /* 1 available byte min or reads will block (we'll set non-blocking
+         * elsewhere, else we have to deal with read()=0 instead)
+         */
+        tio.c_cc[VMIN] = 1;
+        tio.c_cc[VTIME] = 0;
+        /* flush everything waiting for read/xmit, it's garbage at this point */
+        tcflush(fd, TCIFLUSH);
+        tcsetattr(fd, TCSANOW, &tio);
+        ret = conn_channel_add(s, fd);
+        if (ret) {
+            g_error("error adding channel to main loop");
+        }
+    } else if (strcmp(s->method, "unix-listen") == 0) {
+        fd = unix_listen(s->path, NULL, strlen(s->path));
+        if (fd == -1) {
+            g_critical("error opening path: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        ret = listen_channel_add(s, fd, true);
+        if (ret) {
+            g_critical("error binding/listening to specified socket");
+            exit(EXIT_FAILURE);
+        }
+    } else {
+        g_critical("unsupported channel method/type: %s", s->method);
+        exit(EXIT_FAILURE);
+    }
+
+    json_message_parser_init(&s->parser, process_event);
+    s->main_loop = g_main_loop_new(NULL, false);
+}
+
+int main(int argc, char **argv)
+{
+    const char *sopt = "hVvdm:p:l:f:";
+    const char *method = NULL, *path = NULL, *pidfile = QGA_PIDFILE_DEFAULT;
+    const struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "logfile", 0, NULL, 'l' },
+        { "pidfile", 0, NULL, 'f' },
+        { "verbose", 0, NULL, 'v' },
+        { "method", 0, NULL, 'm' },
+        { "path", 0, NULL, 'p' },
+        { "daemonize", 0, NULL, 'd' },
+        { NULL, 0, NULL, 0 }
+    };
+    int opt_ind = 0, ch, daemonize = 0;
+    GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
+    FILE *log_file = stderr;
+    GAState *s;
+
+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+        switch (ch) {
+        case 'm':
+            method = optarg;
+            break;
+        case 'p':
+            path = optarg;
+            break;
+        case 'l':
+            log_file = fopen(optarg, "a");
+            if (!log_file) {
+                g_critical("unable to open specified log file: %s",
+                           strerror(errno));
+                return EXIT_FAILURE;
+            }
+            break;
+        case 'f':
+            pidfile = optarg;
+            break;
+        case 'v':
+            /* enable all log levels */
+            log_level = G_LOG_LEVEL_MASK;
+            break;
+        case 'V':
+            printf("QEMU Guest Agent %s\n", QGA_VERSION);
+            return 0;
+        case 'd':
+            daemonize = 1;
+            break;
+        case 'h':
+            usage(argv[0]);
+            return 0;
+        case '?':
+            g_print("Unknown option, try '%s --help' for more information.\n",
+                    argv[0]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (daemonize) {
+        g_debug("starting daemon");
+        become_daemon(pidfile);
+    }
+
+    s = g_malloc0(sizeof(GAState));
+    s->conn_channel = NULL;
+    s->path = path;
+    s->method = method;
+    s->log_file = log_file;
+    s->log_level = log_level;
+    g_log_set_default_handler(ga_log, s);
+    g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
+    s->logging_enabled = true;
+    s->command_state = ga_command_state_new();
+    ga_command_state_init(s, s->command_state);
+    ga_command_state_init_all(s->command_state);
+    ga_state = s;
+
+    module_call_init(MODULE_INIT_QAPI);
+    init_guest_agent(ga_state);
+    register_signal_handlers();
+
+    g_main_loop_run(ga_state->main_loop);
+
+    ga_command_state_cleanup_all(ga_state->command_state);
+    unlink(pidfile);
+
+    return 0;
+}
index 6c7176f8b4643fe120f9abe4bf0258a41d558f05..49dce7c928923f6bee3c7b3e21d62a0bfaa69f4e 100644 (file)
@@ -22,15 +22,15 @@ STEXI
 ETEXI
 
 DEF("commit", img_commit,
-    "commit [-f fmt] filename")
+    "commit [-f fmt] [-t cache] filename")
 STEXI
-@item commit [-f @var{fmt}] @var{filename}
+@item commit [-f @var{fmt}] [-t @var{cache}] @var{filename}
 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] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] 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}
+@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
 
 DEF("info", img_info,
@@ -46,9 +46,9 @@ STEXI
 ETEXI
 
 DEF("rebase", img_rebase,
-    "rebase [-f fmt] [-u] -b backing_file [-F backing_fmt] filename")
+    "rebase [-f fmt] [-t cache] [-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}
+@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 ETEXI
 
 DEF("resize", img_resize,
index 7e3cc4cbd5cc57086703227a4121af11db722e48..01cc0d35ad7d964196d0cbdc9a08ca0c13197cf0 100644 (file)
@@ -40,6 +40,7 @@ typedef struct img_cmd_t {
 
 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
 #define BDRV_O_FLAGS BDRV_O_CACHE_WB
+#define BDRV_DEFAULT_CACHE "writeback"
 
 static void format_print(void *opaque, const char *name)
 {
@@ -64,6 +65,9 @@ static void help(void)
            "Command parameters:\n"
            "  'filename' is a disk image filename\n"
            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
+           "  'cache' is the cache mode used to write the output disk image, the valid\n"
+           "    options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
+           "    and 'unsafe'\n"
            "  'size' is the disk image size in bytes. Optional suffixes\n"
            "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
            "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
@@ -77,6 +81,9 @@ 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"
+           "  '-S' indicates the consecutive number of bytes that must contain only zeros\n"
+           "       for qemu-img to create a sparse image during conversion\n"
            "\n"
            "Parameters to snapshot subcommand:\n"
            "  'snapshot' is the name of the snapshot to create, apply or delete\n"
@@ -303,11 +310,11 @@ static int img_create(int argc, char **argv)
             fmt = optarg;
             break;
         case 'e':
-            error_report("qemu-img: option -e is deprecated, please use \'-o "
+            error_report("option -e is deprecated, please use \'-o "
                   "encryption\' instead!");
             return 1;
         case '6':
-            error_report("qemu-img: option -6 is deprecated, please use \'-o "
+            error_report("option -6 is deprecated, please use \'-o "
                   "compat6\' instead!");
             return 1;
         case 'o':
@@ -325,8 +332,9 @@ static int img_create(int argc, char **argv)
     /* Get image size, if specified */
     if (optind < argc) {
         int64_t sval;
-        sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B);
-        if (sval < 0) {
+        char *end;
+        sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B);
+        if (sval < 0 || *end) {
             error_report("Invalid image size specified! You may use k, M, G or "
                   "T suffixes for ");
             error_report("kilobytes, megabytes, gigabytes and terabytes.");
@@ -440,13 +448,14 @@ static int img_check(int argc, char **argv)
 
 static int img_commit(int argc, char **argv)
 {
-    int c, ret;
-    const char *filename, *fmt;
+    int c, ret, flags;
+    const char *filename, *fmt, *cache;
     BlockDriverState *bs;
 
     fmt = NULL;
+    cache = BDRV_DEFAULT_CACHE;
     for(;;) {
-        c = getopt(argc, argv, "f:h");
+        c = getopt(argc, argv, "f:ht:");
         if (c == -1) {
             break;
         }
@@ -458,6 +467,9 @@ static int img_commit(int argc, char **argv)
         case 'f':
             fmt = optarg;
             break;
+        case 't':
+            cache = optarg;
+            break;
         }
     }
     if (optind >= argc) {
@@ -465,7 +477,14 @@ static int img_commit(int argc, char **argv)
     }
     filename = argv[optind++];
 
-    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
+    flags = BDRV_O_RDWR;
+    ret = bdrv_parse_cache_flags(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
+    bs = bdrv_new_open(filename, fmt, flags);
     if (!bs) {
         return 1;
     }
@@ -495,14 +514,37 @@ static int img_commit(int argc, char **argv)
     return 0;
 }
 
+/*
+ * Checks whether the sector is not a zero sector.
+ *
+ * Attention! The len must be a multiple of 4 * sizeof(long) due to
+ * restriction of optimizations in this function.
+ */
 static int is_not_zero(const uint8_t *sector, int len)
 {
+    /*
+     * Use long as the biggest available internal data type that fits into the
+     * CPU register and unroll the loop to smooth out the effect of memory
+     * latency.
+     */
+
     int i;
-    len >>= 2;
-    for(i = 0;i < len; i++) {
-        if (((uint32_t *)sector)[i] != 0)
+    long d0, d1, d2, d3;
+    const long * const data = (const long *) sector;
+
+    len /= sizeof(long);
+
+    for(i = 0; i < len; i += 4) {
+        d0 = data[i + 0];
+        d1 = data[i + 1];
+        d2 = data[i + 2];
+        d3 = data[i + 3];
+
+        if (d0 || d1 || d2 || d3) {
             return 1;
+        }
     }
+
     return 0;
 }
 
@@ -531,6 +573,48 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
     return v;
 }
 
+/*
+ * Like is_allocated_sectors, but if the buffer starts with a used sector,
+ * up to 'min' consecutive sectors containing zeros are ignored. This avoids
+ * breaking up write requests for only small sparse areas.
+ */
+static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
+    int min)
+{
+    int ret;
+    int num_checked, num_used;
+
+    if (n < min) {
+        min = n;
+    }
+
+    ret = is_allocated_sectors(buf, n, pnum);
+    if (!ret) {
+        return ret;
+    }
+
+    num_used = *pnum;
+    buf += BDRV_SECTOR_SIZE * *pnum;
+    n -= *pnum;
+    num_checked = num_used;
+
+    while (n > 0) {
+        ret = is_allocated_sectors(buf, n, pnum);
+
+        buf += BDRV_SECTOR_SIZE * *pnum;
+        n -= *pnum;
+        num_checked += *pnum;
+        if (ret) {
+            num_used = num_checked;
+        } else if (*pnum >= min) {
+            break;
+        }
+    }
+
+    *pnum = num_used;
+    return 1;
+}
+
 /*
  * Compares two buffers sector by sector. Returns 0 if the first sector of both
  * buffers matches, non-zero otherwise.
@@ -567,7 +651,8 @@ 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;
-    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
+    int progress = 0, flags;
+    const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
     BlockDriver *drv, *proto_drv;
     BlockDriverState **bs = NULL, *out_bs = NULL;
     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
@@ -579,13 +664,16 @@ static int img_convert(int argc, char **argv)
     QEMUOptionParameter *out_baseimg_param;
     char *options = NULL;
     const char *snapshot_name = NULL;
+    float local_progress;
+    int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
 
     fmt = NULL;
     out_fmt = "raw";
+    cache = "unsafe";
     out_baseimg = NULL;
     compress = 0;
     for(;;) {
-        c = getopt(argc, argv, "f:O:B:s:hce6o:");
+        c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
         if (c == -1) {
             break;
         }
@@ -607,11 +695,11 @@ static int img_convert(int argc, char **argv)
             compress = 1;
             break;
         case 'e':
-            error_report("qemu-img: option -e is deprecated, please use \'-o "
+            error_report("option -e is deprecated, please use \'-o "
                   "encryption\' instead!");
             return 1;
         case '6':
-            error_report("qemu-img: option -6 is deprecated, please use \'-o "
+            error_report("option -6 is deprecated, please use \'-o "
                   "compat6\' instead!");
             return 1;
         case 'o':
@@ -620,6 +708,25 @@ static int img_convert(int argc, char **argv)
         case 's':
             snapshot_name = optarg;
             break;
+        case 'S':
+        {
+            int64_t sval;
+            char *end;
+            sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
+            if (sval < 0 || *end) {
+                error_report("Invalid minimum zero buffer size for sparse output specified");
+                return 1;
+            }
+
+            min_sparse = sval / BDRV_SECTOR_SIZE;
+            break;
+        }
+        case 'p':
+            progress = 1;
+            break;
+        case 't':
+            cache = optarg;
+            break;
         }
     }
 
@@ -642,7 +749,10 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
         
-    bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
+    qemu_progress_init(progress, 2.0);
+    qemu_progress_print(0, 100);
+
+    bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
 
     total_sectors = 0;
     for (bs_i = 0; bs_i < bs_n; bs_i++) {
@@ -658,12 +768,12 @@ static int img_convert(int argc, char **argv)
 
     if (snapshot_name != NULL) {
         if (bs_n > 1) {
-            error_report("No support for concatenating multiple snapshot\n");
+            error_report("No support for concatenating multiple snapshot");
             ret = -1;
             goto out;
         }
         if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
-            error_report("Failed to load snapshot\n");
+            error_report("Failed to load snapshot");
             ret = -1;
             goto out;
         }
@@ -716,6 +826,8 @@ static int img_convert(int argc, char **argv)
     if (compress) {
         QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
+        QEMUOptionParameter *preallocation =
+            get_option_parameter(param, BLOCK_OPT_PREALLOC);
 
         if (!drv->bdrv_write_compressed) {
             error_report("Compression not supported for this file format");
@@ -729,6 +841,15 @@ static int img_convert(int argc, char **argv)
             ret = -1;
             goto out;
         }
+
+        if (preallocation && preallocation->value.s
+            && strcmp(preallocation->value.s, "off"))
+        {
+            error_report("Compression and preallocation not supported at "
+                         "the same time");
+            ret = -1;
+            goto out;
+        }
     }
 
     /* Create the new image */
@@ -747,8 +868,14 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
 
-    out_bs = bdrv_new_open(out_filename, out_fmt,
-        BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH);
+    flags = BDRV_O_RDWR;
+    ret = bdrv_parse_cache_flags(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
+    out_bs = bdrv_new_open(out_filename, out_fmt, flags);
     if (!out_bs) {
         ret = -1;
         goto out;
@@ -757,7 +884,7 @@ static int img_convert(int argc, char **argv)
     bs_i = 0;
     bs_offset = 0;
     bdrv_get_geometry(bs[0], &bs_sectors);
-    buf = qemu_malloc(IO_BUF_SIZE);
+    buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
 
     if (compress) {
         ret = bdrv_get_info(out_bs, &bdi);
@@ -773,6 +900,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;
@@ -808,7 +940,8 @@ static int img_convert(int argc, char **argv)
 
                 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
                 if (ret < 0) {
-                    error_report("error while reading");
+                    error_report("error while reading sector %" PRId64 ": %s",
+                                 bs_num, strerror(-ret));
                     goto out;
                 }
 
@@ -826,12 +959,13 @@ static int img_convert(int argc, char **argv)
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);
                 if (ret != 0) {
-                    error_report("error while compressing sector %" PRId64,
-                          sector_num);
+                    error_report("error while compressing sector %" PRId64
+                                 ": %s", sector_num, strerror(-ret));
                     goto out;
                 }
             }
             sector_num += n;
+            qemu_progress_print(local_progress, 100);
         }
         /* signal EOF to align */
         bdrv_write_compressed(out_bs, 0, NULL, 0);
@@ -839,6 +973,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) {
@@ -885,7 +1023,8 @@ static int img_convert(int argc, char **argv)
 
             ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
             if (ret < 0) {
-                error_report("error while reading");
+                error_report("error while reading sector %" PRId64 ": %s",
+                             sector_num - bs_offset, strerror(-ret));
                 goto out;
             }
             /* NOTE: at the same time we convert, we do not write zero
@@ -901,10 +1040,11 @@ static int img_convert(int argc, char **argv)
                    sectors that are entirely 0, since whatever data was
                    already there is garbage, not 0s. */
                 if (!has_zero_init || out_baseimg ||
-                    is_allocated_sectors(buf1, n, &n1)) {
+                    is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
                     ret = bdrv_write(out_bs, sector_num, buf1, n1);
                     if (ret < 0) {
-                        error_report("error while writing");
+                        error_report("error while writing sector %" PRId64
+                                     ": %s", sector_num, strerror(-ret));
                         goto out;
                     }
                 }
@@ -912,12 +1052,14 @@ 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);
+    qemu_vfree(buf);
     if (out_bs) {
         bdrv_delete(out_bs);
     }
@@ -927,7 +1069,7 @@ out:
                 bdrv_delete(bs[bs_i]);
             }
         }
-        qemu_free(bs);
+        g_free(bs);
     }
     if (ret) {
         return 1;
@@ -935,35 +1077,6 @@ out:
     return 0;
 }
 
-#ifdef _WIN32
-static int64_t get_allocated_file_size(const char *filename)
-{
-    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
-    get_compressed_t get_compressed;
-    struct _stati64 st;
-
-    /* WinNT support GetCompressedFileSize to determine allocate size */
-    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
-    if (get_compressed) {
-       DWORD high, low;
-       low = get_compressed(filename, &high);
-       if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
-           return (((int64_t) high) << 32) + low;
-    }
-
-    if (_stati64(filename, &st) < 0)
-        return -1;
-    return st.st_size;
-}
-#else
-static int64_t get_allocated_file_size(const char *filename)
-{
-    struct stat st;
-    if (stat(filename, &st) < 0)
-        return -1;
-    return (int64_t)st.st_blocks * 512;
-}
-#endif
 
 static void dump_snapshots(BlockDriverState *bs)
 {
@@ -980,7 +1093,7 @@ static void dump_snapshots(BlockDriverState *bs)
         sn = &sn_tab[i];
         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
     }
-    qemu_free(sn_tab);
+    g_free(sn_tab);
 }
 
 static int img_info(int argc, char **argv)
@@ -1023,7 +1136,7 @@ static int img_info(int argc, char **argv)
     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
     bdrv_get_geometry(bs, &total_sectors);
     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
-    allocated_size = get_allocated_file_size(filename);
+    allocated_size = bdrv_get_allocated_file_size(bs);
     if (allocated_size < 0) {
         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
     } else {
@@ -1181,17 +1294,18 @@ static int img_rebase(int argc, char **argv)
     BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
     BlockDriver *old_backing_drv, *new_backing_drv;
     char *filename;
-    const char *fmt, *out_basefmt, *out_baseimg;
+    const char *fmt, *cache, *out_basefmt, *out_baseimg;
     int c, flags, ret;
     int unsafe = 0;
+    int progress = 0;
 
     /* Parse commandline parameters */
     fmt = NULL;
+    cache = BDRV_DEFAULT_CACHE;
     out_baseimg = NULL;
     out_basefmt = NULL;
-
     for(;;) {
-        c = getopt(argc, argv, "uhf:F:b:");
+        c = getopt(argc, argv, "uhf:F:b:pt:");
         if (c == -1) {
             break;
         }
@@ -1212,21 +1326,36 @@ static int img_rebase(int argc, char **argv)
         case 'u':
             unsafe = 1;
             break;
+        case 'p':
+            progress = 1;
+            break;
+        case 't':
+            cache = optarg;
+            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);
+
+    flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
+    ret = bdrv_parse_cache_flags(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
     /*
      * Open the images.
      *
      * Ignore the old backing file for unsafe rebase in case we want to correct
      * the reference to a renamed or moved backing file.
      */
-    flags = BDRV_O_FLAGS | BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
     bs = bdrv_new_open(filename, fmt, flags);
     if (!bs) {
         return 1;
@@ -1291,16 +1420,23 @@ static int img_rebase(int argc, char **argv)
      */
     if (!unsafe) {
         uint64_t num_sectors;
+        uint64_t old_backing_num_sectors;
+        uint64_t new_backing_num_sectors;
         uint64_t sector;
         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);
+        buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
+        buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
 
         bdrv_get_geometry(bs, &num_sectors);
+        bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
+        bdrv_get_geometry(bs_new_backing, &new_backing_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? */
@@ -1316,16 +1452,36 @@ static int img_rebase(int argc, char **argv)
                 continue;
             }
 
-            /* Read old and new backing file */
-            ret = bdrv_read(bs_old_backing, sector, buf_old, n);
-            if (ret < 0) {
-                error_report("error while reading from old backing file");
-                goto out;
+            /*
+             * Read old and new backing file and take into consideration that
+             * backing files may be smaller than the COW image.
+             */
+            if (sector >= old_backing_num_sectors) {
+                memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
+            } else {
+                if (sector + n > old_backing_num_sectors) {
+                    n = old_backing_num_sectors - sector;
+                }
+
+                ret = bdrv_read(bs_old_backing, sector, buf_old, n);
+                if (ret < 0) {
+                    error_report("error while reading from old backing file");
+                    goto out;
+                }
             }
-            ret = bdrv_read(bs_new_backing, sector, buf_new, n);
-            if (ret < 0) {
-                error_report("error while reading from new backing file");
-                goto out;
+
+            if (sector >= new_backing_num_sectors) {
+                memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
+            } else {
+                if (sector + n > new_backing_num_sectors) {
+                    n = new_backing_num_sectors - sector;
+                }
+
+                ret = bdrv_read(bs_new_backing, sector, buf_new, n);
+                if (ret < 0) {
+                    error_report("error while reading from new backing file");
+                    goto out;
+                }
             }
 
             /* If they differ, we need to write to the COW file */
@@ -1348,10 +1504,11 @@ static int img_rebase(int argc, char **argv)
 
                 written += pnum;
             }
+            qemu_progress_print(local_progress, 100);
         }
 
-        qemu_free(buf_old);
-        qemu_free(buf_new);
+        qemu_vfree(buf_old);
+        qemu_vfree(buf_new);
     }
 
     /*
@@ -1368,6 +1525,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 +1533,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 +1567,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 +1593,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 ced64a40edf9202ccf8f171ea6ccc0a75b8b94c2..b2ca3a542cd3c7aacc262f3f38a2b3d0d76be55f 100644 (file)
@@ -38,6 +38,17 @@ by the used format or see the format descriptions below for details.
 indicates that target image must be compressed (qcow format only)
 @item -h
 with or without a command shows help and lists the supported formats
+@item -p
+display progress bar (convert and rebase commands only)
+@item -S @var{size}
+indicates the consecutive number of bytes that must contain only zeros
+for qemu-img to create a sparse image during conversion. This value is rounded
+down to the nearest 512 bytes. You may use the common size suffixes like
+@code{k} for kilobytes.
+@item -t @var{cache}
+specifies the cache mode that should be used with the (destination) file. See
+the documentation of the emulator's @code{-drive cache=...} option for allowed
+values.
 @end table
 
 Parameters to snapshot subcommand:
@@ -80,11 +91,11 @@ this case. @var{backing_file} will never be modified unless you use the
 The size can also be specified using the @var{size} option with @code{-o},
 it doesn't need to be specified separately in this case.
 
-@item commit [-f @var{fmt}] @var{filename}
+@item commit [-f @var{fmt}] [-t @var{cache}] @var{filename}
 
 Commit the changes recorded in @var{filename} in its base image.
 
-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 
 Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
 using format @var{output_fmt}. It can be optionally compressed (@code{-c}
@@ -114,7 +125,7 @@ they are displayed too.
 
 List, apply, create or delete snapshots in image @var{filename}.
 
-@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 
 Changes the backing file of an image. Only the formats @code{qcow2} and
 @code{qed} support changing the backing file.
@@ -173,12 +184,6 @@ Linux or NTFS on Windows), then only the written sectors will reserve
 space. Use @code{qemu-img info} to know the real size used by the
 image or @code{ls -ls} on Unix/Linux.
 
-@item host_device
-
-Host device format. This format should be used instead of raw when
-converting to block devices or other devices where "holes" are not
-supported.
-
 @item qcow2
 QEMU image format, the most versatile format. Use it to have smaller
 images (useful if your filesystem does not supports holes, for example
index 4470e49bc88481ebd304df558b716b2893752d82..de26422fcfb976a693fd40abaf4191a50463a790 100644 (file)
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -20,7 +20,7 @@
 
 #define VERSION        "0.0.1"
 
-#define CMD_NOFILE_OK  0x01
+#define CMD_NOFILE_OK   0x01
 
 char *progname;
 static BlockDriverState *bs;
@@ -35,16 +35,16 @@ static int misalign;
  */
 static int parse_pattern(const char *arg)
 {
-       char *endptr = NULL;
-       long pattern;
+    char *endptr = NULL;
+    long pattern;
 
-       pattern = strtol(arg, &endptr, 0);
-       if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
-               printf("%s is not a valid pattern byte\n", arg);
-               return -1;
-       }
+    pattern = strtol(arg, &endptr, 0);
+    if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
+        printf("%s is not a valid pattern byte\n", arg);
+        return -1;
+    }
 
-       return pattern;
+    return pattern;
 }
 
 /*
@@ -54,70 +54,73 @@ static int parse_pattern(const char *arg)
  * that is specified on the command line.
  */
 
-#define MISALIGN_OFFSET                16
+#define MISALIGN_OFFSET     16
 static void *qemu_io_alloc(size_t len, int pattern)
 {
-       void *buf;
-
-       if (misalign)
-               len += MISALIGN_OFFSET;
-       buf = qemu_blockalign(bs, len);
-       memset(buf, pattern, len);
-       if (misalign)
-               buf += MISALIGN_OFFSET;
-       return buf;
+    void *buf;
+
+    if (misalign) {
+        len += MISALIGN_OFFSET;
+    }
+    buf = qemu_blockalign(bs, len);
+    memset(buf, pattern, len);
+    if (misalign) {
+        buf += MISALIGN_OFFSET;
+    }
+    return buf;
 }
 
 static void qemu_io_free(void *p)
 {
-       if (misalign)
-               p -= MISALIGN_OFFSET;
-       qemu_vfree(p);
+    if (misalign) {
+        p -= MISALIGN_OFFSET;
+    }
+    qemu_vfree(p);
 }
 
-static void
-dump_buffer(const void *buffer, int64_t offset, int len)
+static void dump_buffer(const void *buffer, int64_t offset, int len)
 {
-       int i, j;
-       const uint8_t *p;
-
-       for (i = 0, p = buffer; i < len; i += 16) {
-               const uint8_t *s = p;
-
-                printf("%08" PRIx64 ":  ", offset + i);
-               for (j = 0; j < 16 && i + j < len; j++, p++)
-                       printf("%02x ", *p);
-               printf(" ");
-               for (j = 0; j < 16 && i + j < len; j++, s++) {
-                       if (isalnum(*s))
-                               printf("%c", *s);
-                       else
-                               printf(".");
-               }
-               printf("\n");
-       }
+    int i, j;
+    const uint8_t *p;
+
+    for (i = 0, p = buffer; i < len; i += 16) {
+        const uint8_t *s = p;
+
+        printf("%08" PRIx64 ":  ", offset + i);
+        for (j = 0; j < 16 && i + j < len; j++, p++) {
+            printf("%02x ", *p);
+        }
+        printf(" ");
+        for (j = 0; j < 16 && i + j < len; j++, s++) {
+            if (isalnum(*s)) {
+                printf("%c", *s);
+            } else {
+                printf(".");
+            }
+        }
+        printf("\n");
+    }
 }
 
-static void
-print_report(const char *op, struct timeval *t, int64_t offset,
-               int count, int total, int cnt, int Cflag)
+static void print_report(const char *op, struct timeval *t, int64_t offset,
+                         int count, int total, int cnt, int Cflag)
 {
-       char s1[64], s2[64], ts[64];
-
-       timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
-       if (!Cflag) {
-               cvtstr((double)total, s1, sizeof(s1));
-               cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
-                printf("%s %d/%d bytes at offset %" PRId64 "\n",
-                       op, total, count, offset);
-               printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
-                       s1, cnt, ts, s2, tdiv((double)cnt, *t));
-       } else {/* bytes,ops,time,bytes/sec,ops/sec */
-               printf("%d,%d,%s,%.3f,%.3f\n",
-                       total, cnt, ts,
-                       tdiv((double)total, *t),
-                       tdiv((double)cnt, *t));
-       }
+    char s1[64], s2[64], ts[64];
+
+    timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+    if (!Cflag) {
+        cvtstr((double)total, s1, sizeof(s1));
+        cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+        printf("%s %d/%d bytes at offset %" PRId64 "\n",
+               op, total, count, offset);
+        printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+               s1, cnt, ts, s2, tdiv((double)cnt, *t));
+    } else {/* bytes,ops,time,bytes/sec,ops/sec */
+        printf("%d,%d,%s,%.3f,%.3f\n",
+            total, cnt, ts,
+            tdiv((double)total, *t),
+            tdiv((double)cnt, *t));
+    }
 }
 
 /*
@@ -127,192 +130,200 @@ print_report(const char *op, struct timeval *t, int64_t offset,
 static void *
 create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
 {
-       size_t *sizes = calloc(nr_iov, sizeof(size_t));
-       size_t count = 0;
-       void *buf = NULL;
-       void *p;
-       int i;
-
-       for (i = 0; i < nr_iov; i++) {
-               char *arg = argv[i];
-                int64_t len;
-
-               len = cvtnum(arg);
-               if (len < 0) {
-                       printf("non-numeric length argument -- %s\n", arg);
-                       goto fail;
-               }
-
-               /* should be SIZE_T_MAX, but that doesn't exist */
-               if (len > INT_MAX) {
-                       printf("too large length argument -- %s\n", arg);
-                       goto fail;
-               }
-
-               if (len & 0x1ff) {
-                        printf("length argument %" PRId64
-                               " is not sector aligned\n", len);
-                       goto fail;
-               }
-
-               sizes[i] = len;
-               count += len;
-       }
-
-       qemu_iovec_init(qiov, nr_iov);
-
-       buf = p = qemu_io_alloc(count, pattern);
-
-       for (i = 0; i < nr_iov; i++) {
-               qemu_iovec_add(qiov, p, sizes[i]);
-               p += sizes[i];
-       }
+    size_t *sizes = calloc(nr_iov, sizeof(size_t));
+    size_t count = 0;
+    void *buf = NULL;
+    void *p;
+    int i;
+
+    for (i = 0; i < nr_iov; i++) {
+        char *arg = argv[i];
+        int64_t len;
+
+        len = cvtnum(arg);
+        if (len < 0) {
+            printf("non-numeric length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        /* should be SIZE_T_MAX, but that doesn't exist */
+        if (len > INT_MAX) {
+            printf("too large length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        if (len & 0x1ff) {
+            printf("length argument %" PRId64
+                   " is not sector aligned\n", len);
+            goto fail;
+        }
+
+        sizes[i] = len;
+        count += len;
+    }
+
+    qemu_iovec_init(qiov, nr_iov);
+
+    buf = p = qemu_io_alloc(count, pattern);
+
+    for (i = 0; i < nr_iov; i++) {
+        qemu_iovec_add(qiov, p, sizes[i]);
+        p += sizes[i];
+    }
 
 fail:
-       free(sizes);
-       return buf;
+    free(sizes);
+    return buf;
 }
 
 static int do_read(char *buf, int64_t offset, int count, int *total)
 {
-       int ret;
+    int ret;
 
-       ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
-       if (ret < 0)
-               return ret;
-       *total = count;
-       return 1;
+    ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
 }
 
 static int do_write(char *buf, int64_t offset, int count, int *total)
 {
-       int ret;
+    int ret;
 
-       ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
-       if (ret < 0)
-               return ret;
-       *total = count;
-       return 1;
+    ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
 }
 
 static int do_pread(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_pwrite(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
 {
-       *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
-       if (*total < 0)
-               return *total;
-       return 1;
+    *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
 }
 
 #define NOT_DONE 0x7fffffff
 static void aio_rw_done(void *opaque, int ret)
 {
-       *(int *)opaque = ret;
+    *(int *)opaque = ret;
 }
 
 static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
 {
-       BlockDriverAIOCB *acb;
-       int async_ret = NOT_DONE;
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
 
-       acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
-                            aio_rw_done, &async_ret);
-       if (!acb)
-               return -EIO;
-
-       while (async_ret == NOT_DONE)
-               qemu_aio_wait();
+    acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+                         aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
 
-       *total = qiov->size;
-       return async_ret < 0 ? async_ret : 1;
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
 }
 
 static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
 {
-       BlockDriverAIOCB *acb;
-       int async_ret = NOT_DONE;
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
 
-       acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
-                             aio_rw_done, &async_ret);
-       if (!acb)
-               return -EIO;
+    acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+                          aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
 
-       while (async_ret == NOT_DONE)
-               qemu_aio_wait();
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
 
-       *total = qiov->size;
-       return async_ret < 0 ? async_ret : 1;
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
 }
 
 struct multiwrite_async_ret {
-       int num_done;
-       int error;
+    int num_done;
+    int error;
 };
 
 static void multiwrite_cb(void *opaque, int ret)
 {
-       struct multiwrite_async_ret *async_ret = opaque;
+    struct multiwrite_async_ret *async_ret = opaque;
 
-       async_ret->num_done++;
-       if (ret < 0) {
-               async_ret->error = ret;
-       }
+    async_ret->num_done++;
+    if (ret < 0) {
+        async_ret->error = ret;
+    }
 }
 
 static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
 {
-       int i, ret;
-       struct multiwrite_async_ret async_ret = {
-               .num_done = 0,
-               .error = 0,
-       };
-
-       *total = 0;
-       for (i = 0; i < num_reqs; i++) {
-               reqs[i].cb = multiwrite_cb;
-               reqs[i].opaque = &async_ret;
-               *total += reqs[i].qiov->size;
-       }
-
-       ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
-       if (ret < 0) {
-               return ret;
-       }
-
-       while (async_ret.num_done < num_reqs) {
-               qemu_aio_wait();
-       }
-
-       return async_ret.error < 0 ? async_ret.error : 1;
+    int i, ret;
+    struct multiwrite_async_ret async_ret = {
+        .num_done = 0,
+        .error = 0,
+    };
+
+    *total = 0;
+    for (i = 0; i < num_reqs; i++) {
+        reqs[i].cb = multiwrite_cb;
+        reqs[i].opaque = &async_ret;
+        *total += reqs[i].qiov->size;
+    }
+
+    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    while (async_ret.num_done < num_reqs) {
+        qemu_aio_wait();
+    }
+
+    return async_ret.error < 0 ? async_ret.error : 1;
 }
 
-static void
-read_help(void)
+static void read_help(void)
 {
-       printf(
+    printf(
 "\n"
 " reads a range of bytes from the given offset\n"
 "\n"
@@ -335,94 +346,95 @@ read_help(void)
 static int read_f(int argc, char **argv);
 
 static const cmdinfo_t read_cmd = {
-       .name           = "read",
-       .altname        = "r",
-       .cfunc          = read_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
-       .oneline        = "reads a number of bytes at a specified offset",
-       .help           = read_help,
+    .name       = "read",
+    .altname    = "r",
+    .cfunc      = read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = read_help,
 };
 
-static int
-read_f(int argc, char **argv)
+static int read_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
-       int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-       int count;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int pattern = 0, pattern_offset = 0, pattern_count = 0;
-
-       while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
-               switch (c) {
-               case 'b':
-                       bflag = 1;
-                       break;
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'l':
-                       lflag = 1;
-                       pattern_count = cvtnum(optarg);
-                       if (pattern_count < 0) {
-                               printf("non-numeric length argument -- %s\n", optarg);
-                               return 0;
-                       }
-                       break;
-               case 'p':
-                       pflag = 1;
-                       break;
-               case 'P':
-                       Pflag = 1;
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 's':
-                       sflag = 1;
-                       pattern_offset = cvtnum(optarg);
-                       if (pattern_offset < 0) {
-                               printf("non-numeric length argument -- %s\n", optarg);
-                               return 0;
-                       }
-                       break;
-               case 'v':
-                       vflag = 1;
-                       break;
-               default:
-                       return command_usage(&read_cmd);
-               }
-       }
-
-       if (optind != argc - 2)
-               return command_usage(&read_cmd);
-
-       if (bflag && pflag) {
-               printf("-b and -p cannot be specified at the same time\n");
-               return 0;
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+    int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0, pattern_offset = 0, pattern_count = 0;
+
+    while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'l':
+            lflag = 1;
+            pattern_count = cvtnum(optarg);
+            if (pattern_count < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 's':
+            sflag = 1;
+            pattern_offset = cvtnum(optarg);
+            if (pattern_offset < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&read_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&read_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
 
     if (!Pflag && (lflag || sflag)) {
         return command_usage(&read_cmd);
@@ -437,66 +449,68 @@ read_f(int argc, char **argv)
         return 0;
     }
 
-       if (!pflag)
-               if (offset & 0x1ff) {
-                        printf("offset %" PRId64 " is not sector aligned\n",
-                               offset);
-                       return 0;
-
-               if (count & 0x1ff) {
-                       printf("count %d is not sector aligned\n",
-                               count);
-                       return 0;
-               }
-       }
-
-       buf = qemu_io_alloc(count, 0xab);
-
-       gettimeofday(&t1, NULL);
-       if (pflag)
-               cnt = do_pread(buf, offset, count, &total);
-       else if (bflag)
-               cnt = do_load_vmstate(buf, offset, count, &total);
-       else
-               cnt = do_read(buf, offset, count, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("read failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (Pflag) {
-               void* cmp_buf = malloc(pattern_count);
-               memset(cmp_buf, pattern, pattern_count);
-               if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %d bytes\n",
-                               offset + pattern_offset, pattern_count);
-               }
-               free(cmp_buf);
-       }
-
-       if (qflag)
-               goto out;
-
-        if (vflag)
-               dump_buffer(buf, offset, count);
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("read", &t2, offset, count, total, cnt, Cflag);
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, 0xab);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pread(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_load_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_read(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("read failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(pattern_count);
+        memset(cmp_buf, pattern, pattern_count);
+        if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %d bytes\n",
+                   offset + pattern_offset, pattern_count);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, count);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, count, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
+    qemu_io_free(buf);
 
-       return 0;
+    return 0;
 }
 
-static void
-readv_help(void)
+static void readv_help(void)
 {
-       printf(
+    printf(
 "\n"
 " reads a range of bytes from the given offset into multiple buffers\n"
 "\n"
@@ -516,111 +530,115 @@ readv_help(void)
 static int readv_f(int argc, char **argv);
 
 static const cmdinfo_t readv_cmd = {
-       .name           = "readv",
-       .cfunc          = readv_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cqv] [-P pattern ] off len [len..]",
-       .oneline        = "reads a number of bytes at a specified offset",
-       .help           = readv_help,
+    .name       = "readv",
+    .cfunc      = readv_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = readv_help,
 };
 
-static int
-readv_f(int argc, char **argv)
+static int readv_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0, vflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int nr_iov;
-       QEMUIOVector qiov;
-       int pattern = 0;
-       int Pflag = 0;
-
-       while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'P':
-                       Pflag = 1;
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'v':
-                       vflag = 1;
-                       break;
-               default:
-                       return command_usage(&readv_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&readv_cmd);
-
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-       optind++;
-
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
-
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_readv(&qiov, offset, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("readv failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (Pflag) {
-               void* cmp_buf = malloc(qiov.size);
-               memset(cmp_buf, pattern, qiov.size);
-               if (memcmp(buf, cmp_buf, qiov.size)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %zd bytes\n",
-                               offset, qiov.size);
-               }
-               free(cmp_buf);
-       }
-
-       if (qflag)
-               goto out;
-
-        if (vflag)
-               dump_buffer(buf, offset, qiov.size);
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0, vflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    QEMUIOVector qiov;
+    int pattern = 0;
+    int Pflag = 0;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&readv_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&readv_cmd);
+    }
+
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
+    if (buf == NULL) {
+        return 0;
+    }
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_readv(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("readv failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(qiov.size);
+        memset(cmp_buf, pattern, qiov.size);
+        if (memcmp(buf, cmp_buf, qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", offset, qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
-       return 0;
+    qemu_io_free(buf);
+    return 0;
 }
 
-static void
-write_help(void)
+static void write_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset\n"
 "\n"
@@ -640,121 +658,124 @@ write_help(void)
 static int write_f(int argc, char **argv);
 
 static const cmdinfo_t write_cmd = {
-       .name           = "write",
-       .altname        = "w",
-       .cfunc          = write_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-abCpq] [-P pattern ] off len",
-       .oneline        = "writes a number of bytes at a specified offset",
-       .help           = write_help,
+    .name       = "write",
+    .altname    = "w",
+    .cfunc      = write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpq] [-P pattern ] off len",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = write_help,
 };
 
-static int
-write_f(int argc, char **argv)
+static int write_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-       int count;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int pattern = 0xcd;
-
-       while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
-               switch (c) {
-               case 'b':
-                       bflag = 1;
-                       break;
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'p':
-                       pflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               default:
-                       return command_usage(&write_cmd);
-               }
-       }
-
-       if (optind != argc - 2)
-               return command_usage(&write_cmd);
-
-       if (bflag && pflag) {
-               printf("-b and -p cannot be specified at the same time\n");
-               return 0;
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       if (!pflag) {
-               if (offset & 0x1ff) {
-                        printf("offset %" PRId64 " is not sector aligned\n",
-                               offset);
-                       return 0;
-               }
-
-               if (count & 0x1ff) {
-                       printf("count %d is not sector aligned\n",
-                               count);
-                       return 0;
-               }
-       }
-
-       buf = qemu_io_alloc(count, pattern);
-
-       gettimeofday(&t1, NULL);
-       if (pflag)
-               cnt = do_pwrite(buf, offset, count, &total);
-       else if (bflag)
-               cnt = do_save_vmstate(buf, offset, count, &total);
-       else
-               cnt = do_write(buf, offset, count, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("write failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (qflag)
-               goto out;
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0xcd;
+
+    while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&write_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&write_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, pattern);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pwrite(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_save_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_write(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("write failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, count, total, cnt, Cflag);
 
 out:
-       qemu_io_free(buf);
+    qemu_io_free(buf);
 
-       return 0;
+    return 0;
 }
 
 static void
 writev_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset source from multiple buffers\n"
 "\n"
@@ -772,96 +793,100 @@ writev_help(void)
 static int writev_f(int argc, char **argv);
 
 static const cmdinfo_t writev_cmd = {
-       .name           = "writev",
-       .cfunc          = writev_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..]",
-       .oneline        = "writes a number of bytes at a specified offset",
-       .help           = writev_help,
+    .name       = "writev",
+    .cfunc      = writev_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = writev_help,
 };
 
-static int
-writev_f(int argc, char **argv)
+static int writev_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, cnt;
-       char *buf;
-       int64_t offset;
-        /* Some compilers get confused and warn if this is not initialized.  */
-        int total = 0;
-       int nr_iov;
-       int pattern = 0xcd;
-       QEMUIOVector qiov;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       return command_usage(&writev_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&writev_cmd);
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-       optind++;
-
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
-
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_writev(&qiov, offset, &total);
-       gettimeofday(&t2, NULL);
-
-       if (cnt < 0) {
-               printf("writev failed: %s\n", strerror(-cnt));
-               goto out;
-       }
-
-       if (qflag)
-               goto out;
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int pattern = 0xcd;
+    QEMUIOVector qiov;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
+    if (buf == NULL) {
+        return 0;
+    }
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_writev(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("writev failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
 out:
-       qemu_io_free(buf);
-       return 0;
+    qemu_io_free(buf);
+    return 0;
 }
 
-static void
-multiwrite_help(void)
+static void multiwrite_help(void)
 {
-       printf(
+    printf(
 "\n"
 " writes a range of bytes from the given offset source from multiple buffers,\n"
 " in a batch of requests that may be merged by qemu\n"
 "\n"
 " Example:\n"
-" 'multiwrite 512 1k 1k ; 4k 1k' \n"
+" 'multiwrite 512 1k 1k ; 4k 1k'\n"
 "  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
 "\n"
 " Writes into a segment of the currently open file, using a buffer\n"
@@ -876,217 +901,223 @@ multiwrite_help(void)
 static int multiwrite_f(int argc, char **argv);
 
 static const cmdinfo_t multiwrite_cmd = {
-       .name           = "multiwrite",
-       .cfunc          = multiwrite_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
-       .oneline        = "issues multiple write requests at once",
-       .help           = multiwrite_help,
+    .name       = "multiwrite",
+    .cfunc      = multiwrite_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
+    .oneline    = "issues multiple write requests at once",
+    .help       = multiwrite_help,
 };
 
-static int
-multiwrite_f(int argc, char **argv)
+static int multiwrite_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, cnt;
-       char **buf;
-       int64_t offset, first_offset = 0;
-       /* Some compilers get confused and warn if this is not initialized.  */
-       int total = 0;
-       int nr_iov;
-       int nr_reqs;
-       int pattern = 0xcd;
-       QEMUIOVector *qiovs;
-       int i;
-       BlockRequest *reqs;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       return command_usage(&writev_cmd);
-               }
-       }
-
-       if (optind > argc - 2)
-               return command_usage(&writev_cmd);
-
-       nr_reqs = 1;
-       for (i = optind; i < argc; i++) {
-               if (!strcmp(argv[i], ";")) {
-                       nr_reqs++;
-               }
-       }
-
-       reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
-       buf = qemu_malloc(nr_reqs * sizeof(*buf));
-       qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
-
-       for (i = 0; i < nr_reqs; i++) {
-               int j;
-
-               /* Read the offset of the request */
-               offset = cvtnum(argv[optind]);
-               if (offset < 0) {
-                       printf("non-numeric offset argument -- %s\n", argv[optind]);
-                       return 0;
-               }
-               optind++;
-
-               if (offset & 0x1ff) {
-                       printf("offset %lld is not sector aligned\n",
-                               (long long)offset);
-                       return 0;
-               }
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char **buf;
+    int64_t offset, first_offset = 0;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int nr_reqs;
+    int pattern = 0xcd;
+    QEMUIOVector *qiovs;
+    int i;
+    BlockRequest *reqs;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    nr_reqs = 1;
+    for (i = optind; i < argc; i++) {
+        if (!strcmp(argv[i], ";")) {
+            nr_reqs++;
+        }
+    }
+
+    reqs = g_malloc0(nr_reqs * sizeof(*reqs));
+    buf = g_malloc0(nr_reqs * sizeof(*buf));
+    qiovs = g_malloc(nr_reqs * sizeof(*qiovs));
+
+    for (i = 0; i < nr_reqs && optind < argc; i++) {
+        int j;
+
+        /* Read the offset of the request */
+        offset = cvtnum(argv[optind]);
+        if (offset < 0) {
+            printf("non-numeric offset argument -- %s\n", argv[optind]);
+            goto out;
+        }
+        optind++;
+
+        if (offset & 0x1ff) {
+            printf("offset %lld is not sector aligned\n",
+                   (long long)offset);
+            goto out;
+        }
 
         if (i == 0) {
             first_offset = offset;
         }
 
-               /* Read lengths for qiov entries */
-               for (j = optind; j < argc; j++) {
-                       if (!strcmp(argv[j], ";")) {
-                               break;
-                       }
-               }
+        /* Read lengths for qiov entries */
+        for (j = optind; j < argc; j++) {
+            if (!strcmp(argv[j], ";")) {
+                break;
+            }
+        }
 
-               nr_iov = j - optind;
+        nr_iov = j - optind;
 
-               /* Build request */
-               reqs[i].qiov = &qiovs[i];
-               buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
-               reqs[i].sector = offset >> 9;
-               reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
+        /* Build request */
+        buf[i] = create_iovec(&qiovs[i], &argv[optind], nr_iov, pattern);
+        if (buf[i] == NULL) {
+            goto out;
+        }
 
-               optind = j + 1;
+        reqs[i].qiov = &qiovs[i];
+        reqs[i].sector = offset >> 9;
+        reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
 
-               offset += reqs[i].qiov->size;
-               pattern++;
-       }
+        optind = j + 1;
 
-       gettimeofday(&t1, NULL);
-       cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
-       gettimeofday(&t2, NULL);
+        pattern++;
+    }
 
-       if (cnt < 0) {
-               printf("aio_multiwrite failed: %s\n", strerror(-cnt));
-               goto out;
-       }
+    /* If there were empty requests at the end, ignore them */
+    nr_reqs = i;
 
-       if (qflag)
-               goto out;
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("aio_multiwrite failed: %s\n", strerror(-cnt));
+        goto out;
+    }
 
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, t1);
-       print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
 out:
-       for (i = 0; i < nr_reqs; i++) {
-               qemu_io_free(buf[i]);
-               qemu_iovec_destroy(&qiovs[i]);
-       }
-       qemu_free(buf);
-       qemu_free(reqs);
-       qemu_free(qiovs);
-       return 0;
+    for (i = 0; i < nr_reqs; i++) {
+        qemu_io_free(buf[i]);
+        if (reqs[i].qiov != NULL) {
+            qemu_iovec_destroy(&qiovs[i]);
+        }
+    }
+    g_free(buf);
+    g_free(reqs);
+    g_free(qiovs);
+    return 0;
 }
 
 struct aio_ctx {
-       QEMUIOVector qiov;
-       int64_t offset;
-       char *buf;
-       int qflag;
-       int vflag;
-       int Cflag;
-       int Pflag;
-       int pattern;
-       struct timeval t1;
+    QEMUIOVector qiov;
+    int64_t offset;
+    char *buf;
+    int qflag;
+    int vflag;
+    int Cflag;
+    int Pflag;
+    int pattern;
+    struct timeval t1;
 };
 
-static void
-aio_write_done(void *opaque, int ret)
+static void aio_write_done(void *opaque, int ret)
 {
-       struct aio_ctx *ctx = opaque;
-       struct timeval t2;
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
 
-       gettimeofday(&t2, NULL);
+    gettimeofday(&t2, NULL);
 
 
-       if (ret < 0) {
-               printf("aio_write failed: %s\n", strerror(-ret));
-               goto out;
-       }
+    if (ret < 0) {
+        printf("aio_write failed: %s\n", strerror(-ret));
+        goto out;
+    }
 
-       if (ctx->qflag) {
-               goto out;
-       }
+    if (ctx->qflag) {
+        goto out;
+    }
 
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, ctx->t1);
-       print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
-                    ctx->qiov.size, 1, ctx->Cflag);
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
 out:
-       qemu_io_free(ctx->buf);
-       free(ctx);
+    qemu_io_free(ctx->buf);
+    free(ctx);
 }
 
-static void
-aio_read_done(void *opaque, int ret)
+static void aio_read_done(void *opaque, int ret)
 {
-       struct aio_ctx *ctx = opaque;
-       struct timeval t2;
-
-       gettimeofday(&t2, NULL);
-
-       if (ret < 0) {
-               printf("readv failed: %s\n", strerror(-ret));
-               goto out;
-       }
-
-       if (ctx->Pflag) {
-               void *cmp_buf = malloc(ctx->qiov.size);
-
-               memset(cmp_buf, ctx->pattern, ctx->qiov.size);
-               if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
-                       printf("Pattern verification failed at offset %"
-                               PRId64 ", %zd bytes\n",
-                               ctx->offset, ctx->qiov.size);
-               }
-               free(cmp_buf);
-       }
-
-       if (ctx->qflag) {
-               goto out;
-       }
-
-       if (ctx->vflag) {
-               dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
-       }
-
-       /* Finally, report back -- -C gives a parsable format */
-       t2 = tsub(t2, ctx->t1);
-       print_report("read", &t2, ctx->offset, ctx->qiov.size,
-                    ctx->qiov.size, 1, ctx->Cflag);
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
+
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("readv failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    if (ctx->Pflag) {
+        void *cmp_buf = malloc(ctx->qiov.size);
+
+        memset(cmp_buf, ctx->pattern, ctx->qiov.size);
+        if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    if (ctx->vflag) {
+        dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("read", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
 out:
-       qemu_io_free(ctx->buf);
-       free(ctx);
+    qemu_io_free(ctx->buf);
+    free(ctx);
 }
 
-static void
-aio_read_help(void)
+static void aio_read_help(void)
 {
-       printf(
+    printf(
 "\n"
 " asynchronously reads a range of bytes from the given offset\n"
 "\n"
@@ -1107,88 +1138,90 @@ aio_read_help(void)
 static int aio_read_f(int argc, char **argv);
 
 static const cmdinfo_t aio_read_cmd = {
-       .name           = "aio_read",
-       .cfunc          = aio_read_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cqv] [-P pattern ] off len [len..]",
-       .oneline        = "asynchronously reads a number of bytes",
-       .help           = aio_read_help,
+    .name       = "aio_read",
+    .cfunc      = aio_read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously reads a number of bytes",
+    .help       = aio_read_help,
 };
 
-static int
-aio_read_f(int argc, char **argv)
+static int aio_read_f(int argc, char **argv)
 {
-       int nr_iov, c;
-       struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
-       BlockDriverAIOCB *acb;
-
-       while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
-               switch (c) {
-               case 'C':
-                       ctx->Cflag = 1;
-                       break;
-               case 'P':
-                       ctx->Pflag = 1;
-                       ctx->pattern = parse_pattern(optarg);
-                       if (ctx->pattern < 0) {
-                                free(ctx);
-                               return 0;
-                        }
-                       break;
-               case 'q':
-                       ctx->qflag = 1;
-                       break;
-               case 'v':
-                       ctx->vflag = 1;
-                       break;
-               default:
-                       free(ctx);
-                       return command_usage(&aio_read_cmd);
-               }
-       }
-
-       if (optind > argc - 2) {
-               free(ctx);
-               return command_usage(&aio_read_cmd);
-       }
-
-       ctx->offset = cvtnum(argv[optind]);
-       if (ctx->offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               free(ctx);
-               return 0;
-       }
-       optind++;
-
-       if (ctx->offset & 0x1ff) {
-               printf("offset %" PRId64 " is not sector aligned\n",
-                       ctx->offset);
-               free(ctx);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
-
-       gettimeofday(&ctx->t1, NULL);
-       acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
-                             ctx->qiov.size >> 9, aio_read_done, ctx);
-       if (!acb) {
-               free(ctx->buf);
-               free(ctx);
-               return -EIO;
-       }
-
-       return 0;
+    int nr_iov, c;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'P':
+            ctx->Pflag = 1;
+            ctx->pattern = parse_pattern(optarg);
+            if (ctx->pattern < 0) {
+                free(ctx);
+                return 0;
+            }
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'v':
+            ctx->vflag = 1;
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_read_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_read_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
+    if (ctx->buf == NULL) {
+        free(ctx);
+        return 0;
+    }
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
+                         ctx->qiov.size >> 9, aio_read_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
 }
 
-static void
-aio_write_help(void)
+static void aio_write_help(void)
 {
-       printf(
+    printf(
 "\n"
-" asynchronously writes a range of bytes from the given offset source \n"
+" asynchronously writes a range of bytes from the given offset source\n"
 " from multiple buffers\n"
 "\n"
 " Example:\n"
@@ -1207,199 +1240,201 @@ aio_write_help(void)
 static int aio_write_f(int argc, char **argv);
 
 static const cmdinfo_t aio_write_cmd = {
-       .name           = "aio_write",
-       .cfunc          = aio_write_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] [-P pattern ] off len [len..]",
-       .oneline        = "asynchronously writes a number of bytes",
-       .help           = aio_write_help,
+    .name       = "aio_write",
+    .cfunc      = aio_write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously writes a number of bytes",
+    .help       = aio_write_help,
 };
 
-static int
-aio_write_f(int argc, char **argv)
+static int aio_write_f(int argc, char **argv)
 {
-       int nr_iov, c;
-       int pattern = 0xcd;
-       struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
-       BlockDriverAIOCB *acb;
-
-       while ((c = getopt(argc, argv, "CqP:")) != EOF) {
-               switch (c) {
-               case 'C':
-                       ctx->Cflag = 1;
-                       break;
-               case 'q':
-                       ctx->qflag = 1;
-                       break;
-               case 'P':
-                       pattern = parse_pattern(optarg);
-                       if (pattern < 0)
-                               return 0;
-                       break;
-               default:
-                       free(ctx);
-                       return command_usage(&aio_write_cmd);
-               }
-       }
-
-       if (optind > argc - 2) {
-               free(ctx);
-               return command_usage(&aio_write_cmd);
-       }
-
-       ctx->offset = cvtnum(argv[optind]);
-       if (ctx->offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               free(ctx);
-               return 0;
-       }
-       optind++;
-
-       if (ctx->offset & 0x1ff) {
-               printf("offset %" PRId64 " is not sector aligned\n",
-                       ctx->offset);
-               free(ctx);
-               return 0;
-       }
-
-       nr_iov = argc - optind;
-       ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
-
-       gettimeofday(&ctx->t1, NULL);
-       acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
-                             ctx->qiov.size >> 9, aio_write_done, ctx);
-       if (!acb) {
-               free(ctx->buf);
-               free(ctx);
-               return -EIO;
-       }
-
-       return 0;
+    int nr_iov, c;
+    int pattern = 0xcd;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                free(ctx);
+                return 0;
+            }
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_write_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_write_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
+    if (ctx->buf == NULL) {
+        free(ctx);
+        return 0;
+    }
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
+                          ctx->qiov.size >> 9, aio_write_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
 }
 
-static int
-aio_flush_f(int argc, char **argv)
+static int aio_flush_f(int argc, char **argv)
 {
-       qemu_aio_flush();
-       return 0;
+    qemu_aio_flush();
+    return 0;
 }
 
 static const cmdinfo_t aio_flush_cmd = {
-       .name           = "aio_flush",
-       .cfunc          = aio_flush_f,
-       .oneline        = "completes all outstanding aio requests"
+    .name       = "aio_flush",
+    .cfunc      = aio_flush_f,
+    .oneline    = "completes all outstanding aio requests"
 };
 
-static int
-flush_f(int argc, char **argv)
+static int flush_f(int argc, char **argv)
 {
-       bdrv_flush(bs);
-       return 0;
+    bdrv_flush(bs);
+    return 0;
 }
 
 static const cmdinfo_t flush_cmd = {
-       .name           = "flush",
-       .altname        = "f",
-       .cfunc          = flush_f,
-       .oneline        = "flush all in-core file state to disk",
+    .name       = "flush",
+    .altname    = "f",
+    .cfunc      = flush_f,
+    .oneline    = "flush all in-core file state to disk",
 };
 
-static int
-truncate_f(int argc, char **argv)
+static int truncate_f(int argc, char **argv)
 {
-       int64_t offset;
-       int ret;
-
-       offset = cvtnum(argv[1]);
-       if (offset < 0) {
-               printf("non-numeric truncate argument -- %s\n", argv[1]);
-               return 0;
-       }
-
-       ret = bdrv_truncate(bs, offset);
-       if (ret < 0) {
-               printf("truncate: %s\n", strerror(-ret));
-               return 0;
-       }
-
-       return 0;
+    int64_t offset;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset < 0) {
+        printf("non-numeric truncate argument -- %s\n", argv[1]);
+        return 0;
+    }
+
+    ret = bdrv_truncate(bs, offset);
+    if (ret < 0) {
+        printf("truncate: %s\n", strerror(-ret));
+        return 0;
+    }
+
+    return 0;
 }
 
 static const cmdinfo_t truncate_cmd = {
-       .name           = "truncate",
-       .altname        = "t",
-       .cfunc          = truncate_f,
-       .argmin         = 1,
-       .argmax         = 1,
-       .args           = "off",
-       .oneline        = "truncates the current file at the given offset",
+    .name       = "truncate",
+    .altname    = "t",
+    .cfunc      = truncate_f,
+    .argmin     = 1,
+    .argmax     = 1,
+    .args       = "off",
+    .oneline    = "truncates the current file at the given offset",
 };
 
-static int
-length_f(int argc, char **argv)
+static int length_f(int argc, char **argv)
 {
-        int64_t size;
-       char s1[64];
-
-       size = bdrv_getlength(bs);
-       if (size < 0) {
-               printf("getlength: %s\n", strerror(-size));
-               return 0;
-       }
-
-       cvtstr(size, s1, sizeof(s1));
-       printf("%s\n", s1);
-       return 0;
+    int64_t size;
+    char s1[64];
+
+    size = bdrv_getlength(bs);
+    if (size < 0) {
+        printf("getlength: %s\n", strerror(-size));
+        return 0;
+    }
+
+    cvtstr(size, s1, sizeof(s1));
+    printf("%s\n", s1);
+    return 0;
 }
 
 
 static const cmdinfo_t length_cmd = {
-       .name           = "length",
-       .altname        = "l",
-       .cfunc          = length_f,
-       .oneline        = "gets the length of the current file",
+    .name   = "length",
+    .altname    = "l",
+    .cfunc      = length_f,
+    .oneline    = "gets the length of the current file",
 };
 
 
-static int
-info_f(int argc, char **argv)
+static int info_f(int argc, char **argv)
 {
-       BlockDriverInfo bdi;
-       char s1[64], s2[64];
-       int ret;
+    BlockDriverInfo bdi;
+    char s1[64], s2[64];
+    int ret;
 
-       if (bs->drv && bs->drv->format_name)
-               printf("format name: %s\n", bs->drv->format_name);
-       if (bs->drv && bs->drv->protocol_name)
-               printf("format name: %s\n", bs->drv->protocol_name);
+    if (bs->drv && bs->drv->format_name) {
+        printf("format name: %s\n", bs->drv->format_name);
+    }
+    if (bs->drv && bs->drv->protocol_name) {
+        printf("format name: %s\n", bs->drv->protocol_name);
+    }
 
-       ret = bdrv_get_info(bs, &bdi);
-       if (ret)
-               return 0;
+    ret = bdrv_get_info(bs, &bdi);
+    if (ret) {
+        return 0;
+    }
 
-       cvtstr(bdi.cluster_size, s1, sizeof(s1));
-       cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+    cvtstr(bdi.cluster_size, s1, sizeof(s1));
+    cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
 
-       printf("cluster size: %s\n", s1);
-       printf("vm state offset: %s\n", s2);
+    printf("cluster size: %s\n", s1);
+    printf("vm state offset: %s\n", s2);
 
-       return 0;
+    return 0;
 }
 
 
 
 static const cmdinfo_t info_cmd = {
-       .name           = "info",
-       .altname        = "i",
-       .cfunc          = info_f,
-       .oneline        = "prints information about the current file",
+    .name       = "info",
+    .altname    = "i",
+    .cfunc      = info_f,
+    .oneline    = "prints information about the current file",
 };
 
-static void
-discard_help(void)
+static void discard_help(void)
 {
-       printf(
+    printf(
 "\n"
 " discards a range of bytes from the given offset\n"
 "\n"
@@ -1415,148 +1450,147 @@ discard_help(void)
 static int discard_f(int argc, char **argv);
 
 static const cmdinfo_t discard_cmd = {
-       .name           = "discard",
-       .altname        = "d",
-       .cfunc          = discard_f,
-       .argmin         = 2,
-       .argmax         = -1,
-       .args           = "[-Cq] off len",
-       .oneline        = "discards a number of bytes at a specified offset",
-       .help           = discard_help,
+    .name       = "discard",
+    .altname    = "d",
+    .cfunc      = discard_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] off len",
+    .oneline    = "discards a number of bytes at a specified offset",
+    .help       = discard_help,
 };
 
-static int
-discard_f(int argc, char **argv)
+static int discard_f(int argc, char **argv)
 {
-       struct timeval t1, t2;
-       int Cflag = 0, qflag = 0;
-       int c, ret;
-       int64_t offset;
-       int count;
-
-       while ((c = getopt(argc, argv, "Cq")) != EOF) {
-               switch (c) {
-               case 'C':
-                       Cflag = 1;
-                       break;
-               case 'q':
-                       qflag = 1;
-                       break;
-               default:
-                       return command_usage(&discard_cmd);
-               }
-       }
-
-       if (optind != argc - 2) {
-               return command_usage(&discard_cmd);
-       }
-
-       offset = cvtnum(argv[optind]);
-       if (offset < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       optind++;
-       count = cvtnum(argv[optind]);
-       if (count < 0) {
-               printf("non-numeric length argument -- %s\n", argv[optind]);
-               return 0;
-       }
-
-       gettimeofday(&t1, NULL);
-       ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, count >> BDRV_SECTOR_BITS);
-       gettimeofday(&t2, NULL);
-
-       if (ret < 0) {
-               printf("discard failed: %s\n", strerror(-ret));
-               goto out;
-       }
-
-       /* Finally, report back -- -C gives a parsable format */
-       if (!qflag) {
-               t2 = tsub(t2, t1);
-               print_report("discard", &t2, offset, count, count, 1, Cflag);
-       }
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, ret;
+    int64_t offset;
+    int count;
+
+    while ((c = getopt(argc, argv, "Cq")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&discard_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&discard_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    gettimeofday(&t1, NULL);
+    ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
+                       count >> BDRV_SECTOR_BITS);
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("discard failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    if (!qflag) {
+        t2 = tsub(t2, t1);
+        print_report("discard", &t2, offset, count, count, 1, Cflag);
+    }
 
 out:
-       return 0;
+    return 0;
 }
 
-static int
-alloc_f(int argc, char **argv)
+static int alloc_f(int argc, char **argv)
 {
-       int64_t offset;
-       int nb_sectors, remaining;
-       char s1[64];
-       int num, sum_alloc;
-       int ret;
-
-       offset = cvtnum(argv[1]);
-       if (offset & 0x1ff) {
-                printf("offset %" PRId64 " is not sector aligned\n",
-                       offset);
-               return 0;
-       }
-
-       if (argc == 3)
-               nb_sectors = cvtnum(argv[2]);
-       else
-               nb_sectors = 1;
-
-       remaining = nb_sectors;
-       sum_alloc = 0;
-       while (remaining) {
-               ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
-               remaining -= num;
-               if (ret) {
-                       sum_alloc += num;
-               }
-       }
-
-       cvtstr(offset, s1, sizeof(s1));
-
-       printf("%d/%d sectors allocated at offset %s\n",
-              sum_alloc, nb_sectors, s1);
-       return 0;
+    int64_t offset;
+    int nb_sectors, remaining;
+    char s1[64];
+    int num, sum_alloc;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    if (argc == 3) {
+        nb_sectors = cvtnum(argv[2]);
+    } else {
+        nb_sectors = 1;
+    }
+
+    remaining = nb_sectors;
+    sum_alloc = 0;
+    while (remaining) {
+        ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+        remaining -= num;
+        if (ret) {
+            sum_alloc += num;
+        }
+    }
+
+    cvtstr(offset, s1, sizeof(s1));
+
+    printf("%d/%d sectors allocated at offset %s\n",
+           sum_alloc, nb_sectors, s1);
+    return 0;
 }
 
 static const cmdinfo_t alloc_cmd = {
-       .name           = "alloc",
-       .altname        = "a",
-       .argmin         = 1,
-       .argmax         = 2,
-       .cfunc          = alloc_f,
-       .args           = "off [sectors]",
-       .oneline        = "checks if a sector is present in the file",
+    .name       = "alloc",
+    .altname    = "a",
+    .argmin     = 1,
+    .argmax     = 2,
+    .cfunc      = alloc_f,
+    .args       = "off [sectors]",
+    .oneline    = "checks if a sector is present in the file",
 };
 
-static int
-map_f(int argc, char **argv)
+static int map_f(int argc, char **argv)
 {
-       int64_t offset;
-       int64_t nb_sectors;
-       char s1[64];
-       int num, num_checked;
-       int ret;
-       const char *retstr;
-
-       offset = 0;
-       nb_sectors = bs->total_sectors;
-
-       do {
-               num_checked = MIN(nb_sectors, INT_MAX);
-               ret = bdrv_is_allocated(bs, offset, num_checked, &num);
-               retstr = ret ? "    allocated" : "not allocated";
-               cvtstr(offset << 9ULL, s1, sizeof(s1));
-               printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
-                               offset << 9ULL, num, num_checked, retstr, s1, ret);
-
-               offset += num;
-               nb_sectors -= num;
-       } while(offset < bs->total_sectors);
-
-       return 0;
+    int64_t offset;
+    int64_t nb_sectors;
+    char s1[64];
+    int num, num_checked;
+    int ret;
+    const char *retstr;
+
+    offset = 0;
+    nb_sectors = bs->total_sectors;
+
+    do {
+        num_checked = MIN(nb_sectors, INT_MAX);
+        ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+        retstr = ret ? "    allocated" : "not allocated";
+        cvtstr(offset << 9ULL, s1, sizeof(s1));
+        printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
+               offset << 9ULL, num, num_checked, retstr, s1, ret);
+
+        offset += num;
+        nb_sectors -= num;
+    } while (offset < bs->total_sectors);
+
+    return 0;
 }
 
 static const cmdinfo_t map_cmd = {
@@ -1569,50 +1603,49 @@ static const cmdinfo_t map_cmd = {
 };
 
 
-static int
-close_f(int argc, char **argv)
+static int close_f(int argc, char **argv)
 {
-       bdrv_close(bs);
-       bs = NULL;
-       return 0;
+    bdrv_delete(bs);
+    bs = NULL;
+    return 0;
 }
 
 static const cmdinfo_t close_cmd = {
-       .name           = "close",
-       .altname        = "c",
-       .cfunc          = close_f,
-       .oneline        = "close the current open file",
+    .name       = "close",
+    .altname    = "c",
+    .cfunc      = close_f,
+    .oneline    = "close the current open file",
 };
 
 static int openfile(char *name, int flags, int growable)
 {
-       if (bs) {
-               fprintf(stderr, "file open already, try 'help close'\n");
-               return 1;
-       }
-
-       if (growable) {
-               if (bdrv_file_open(&bs, name, flags)) {
-                       fprintf(stderr, "%s: can't open device %s\n", progname, name);
-                       return 1;
-               }
-       } else {
-               bs = bdrv_new("hda");
-
-               if (bdrv_open(bs, name, flags, NULL) < 0) {
-                       fprintf(stderr, "%s: can't open device %s\n", progname, name);
-                       bs = NULL;
-                       return 1;
-               }
-       }
-
-       return 0;
+    if (bs) {
+        fprintf(stderr, "file open already, try 'help close'\n");
+        return 1;
+    }
+
+    if (growable) {
+        if (bdrv_file_open(&bs, name, flags)) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            return 1;
+        }
+    } else {
+        bs = bdrv_new("hda");
+
+        if (bdrv_open(bs, name, flags, NULL) < 0) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            bdrv_delete(bs);
+            bs = NULL;
+            return 1;
+        }
+    }
+
+    return 0;
 }
 
-static void
-open_help(void)
+static void open_help(void)
 {
-       printf(
+    printf(
 "\n"
 " opens a new file in the requested mode\n"
 "\n"
@@ -1630,80 +1663,78 @@ open_help(void)
 static int open_f(int argc, char **argv);
 
 static const cmdinfo_t open_cmd = {
-       .name           = "open",
-       .altname        = "o",
-       .cfunc          = open_f,
-       .argmin         = 1,
-       .argmax         = -1,
-       .flags          = CMD_NOFILE_OK,
-       .args           = "[-Crsn] [path]",
-       .oneline        = "open the file specified by path",
-       .help           = open_help,
+    .name       = "open",
+    .altname    = "o",
+    .cfunc      = open_f,
+    .argmin     = 1,
+    .argmax     = -1,
+    .flags      = CMD_NOFILE_OK,
+    .args       = "[-Crsn] [path]",
+    .oneline    = "open the file specified by path",
+    .help       = open_help,
 };
 
-static int
-open_f(int argc, char **argv)
+static int open_f(int argc, char **argv)
 {
-       int flags = 0;
-       int readonly = 0;
-       int growable = 0;
-       int c;
-
-       while ((c = getopt(argc, argv, "snrg")) != EOF) {
-               switch (c) {
-               case 's':
-                       flags |= BDRV_O_SNAPSHOT;
-                       break;
-               case 'n':
-                       flags |= BDRV_O_NOCACHE;
-                       break;
-               case 'r':
-                       readonly = 1;
-                       break;
-               case 'g':
-                       growable = 1;
-                       break;
-               default:
-                       return command_usage(&open_cmd);
-               }
-       }
-
-       if (!readonly) {
-            flags |= BDRV_O_RDWR;
+    int flags = 0;
+    int readonly = 0;
+    int growable = 0;
+    int c;
+
+    while ((c = getopt(argc, argv, "snrg")) != EOF) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        default:
+            return command_usage(&open_cmd);
         }
+    }
 
-       if (optind != argc - 1)
-               return command_usage(&open_cmd);
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
+
+    if (optind != argc - 1) {
+        return command_usage(&open_cmd);
+    }
 
-       return openfile(argv[optind], flags, growable);
+    return openfile(argv[optind], flags, growable);
 }
 
-static int
-init_args_command(
-        int     index)
+static int init_args_command(int index)
 {
-       /* only one device allowed so far */
-       if (index >= 1)
-               return 0;
-       return ++index;
+    /* only one device allowed so far */
+    if (index >= 1) {
+        return 0;
+    }
+    return ++index;
 }
 
-static int
-init_check_command(
-       const cmdinfo_t *ct)
+static int init_check_command(const cmdinfo_t *ct)
 {
-       if (ct->flags & CMD_FLAG_GLOBAL)
-               return 1;
-       if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
-               fprintf(stderr, "no file open, try 'help open'\n");
-               return 0;
-       }
-       return 1;
+    if (ct->flags & CMD_FLAG_GLOBAL) {
+        return 1;
+    }
+    if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+        fprintf(stderr, "no file open, try 'help open'\n");
+        return 0;
+    }
+    return 1;
 }
 
 static void usage(const char *name)
 {
-       printf(
+    printf(
 "Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
 "QEMU Disk exerciser\n"
 "\n"
@@ -1717,115 +1748,117 @@ static void usage(const char *name)
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
 "\n",
-       name);
+    name);
 }
 
 
 int main(int argc, char **argv)
 {
-       int readonly = 0;
-       int growable = 0;
-       const char *sopt = "hVc:rsnmgk";
-        const struct option lopt[] = {
-               { "help", 0, NULL, 'h' },
-               { "version", 0, NULL, 'V' },
-               { "offset", 1, NULL, 'o' },
-               { "cmd", 1, NULL, 'c' },
-               { "read-only", 0, NULL, 'r' },
-               { "snapshot", 0, NULL, 's' },
-               { "nocache", 0, NULL, 'n' },
-               { "misalign", 0, NULL, 'm' },
-               { "growable", 0, NULL, 'g' },
-               { "native-aio", 0, NULL, 'k' },
-               { NULL, 0, NULL, 0 }
-       };
-       int c;
-       int opt_index = 0;
-       int flags = 0;
-
-       progname = basename(argv[0]);
-
-       while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
-               switch (c) {
-               case 's':
-                       flags |= BDRV_O_SNAPSHOT;
-                       break;
-               case 'n':
-                       flags |= BDRV_O_NOCACHE;
-                       break;
-               case 'c':
-                       add_user_command(optarg);
-                       break;
-               case 'r':
-                       readonly = 1;
-                       break;
-               case 'm':
-                       misalign = 1;
-                       break;
-               case 'g':
-                       growable = 1;
-                       break;
-               case 'k':
-                       flags |= BDRV_O_NATIVE_AIO;
-                       break;
-               case 'V':
-                       printf("%s version %s\n", progname, VERSION);
-                       exit(0);
-               case 'h':
-                       usage(progname);
-                       exit(0);
-               default:
-                       usage(progname);
-                       exit(1);
-               }
-       }
-
-       if ((argc - optind) > 1) {
-               usage(progname);
-               exit(1);
-       }
-
-       bdrv_init();
-
-       /* initialize commands */
-       quit_init();
-       help_init();
-       add_command(&open_cmd);
-       add_command(&close_cmd);
-       add_command(&read_cmd);
-       add_command(&readv_cmd);
-       add_command(&write_cmd);
-       add_command(&writev_cmd);
-       add_command(&multiwrite_cmd);
-       add_command(&aio_read_cmd);
-       add_command(&aio_write_cmd);
-       add_command(&aio_flush_cmd);
-       add_command(&flush_cmd);
-       add_command(&truncate_cmd);
-       add_command(&length_cmd);
-       add_command(&info_cmd);
-       add_command(&discard_cmd);
-       add_command(&alloc_cmd);
-       add_command(&map_cmd);
-
-       add_args_command(init_args_command);
-       add_check_command(init_check_command);
-
-       /* open the device */
-       if (!readonly) {
-            flags |= BDRV_O_RDWR;
+    int readonly = 0;
+    int growable = 0;
+    const char *sopt = "hVc:rsnmgk";
+    const struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "offset", 1, NULL, 'o' },
+        { "cmd", 1, NULL, 'c' },
+        { "read-only", 0, NULL, 'r' },
+        { "snapshot", 0, NULL, 's' },
+        { "nocache", 0, NULL, 'n' },
+        { "misalign", 0, NULL, 'm' },
+        { "growable", 0, NULL, 'g' },
+        { "native-aio", 0, NULL, 'k' },
+        { NULL, 0, NULL, 0 }
+    };
+    int c;
+    int opt_index = 0;
+    int flags = 0;
+
+    progname = basename(argv[0]);
+
+    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'c':
+            add_user_command(optarg);
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'm':
+            misalign = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        case 'k':
+            flags |= BDRV_O_NATIVE_AIO;
+            break;
+        case 'V':
+            printf("%s version %s\n", progname, VERSION);
+            exit(0);
+        case 'h':
+            usage(progname);
+            exit(0);
+        default:
+            usage(progname);
+            exit(1);
         }
+    }
+
+    if ((argc - optind) > 1) {
+        usage(progname);
+        exit(1);
+    }
 
-       if ((argc - optind) == 1)
-               openfile(argv[optind], flags, growable);
-       command_loop();
+    bdrv_init();
+
+    /* initialize commands */
+    quit_init();
+    help_init();
+    add_command(&open_cmd);
+    add_command(&close_cmd);
+    add_command(&read_cmd);
+    add_command(&readv_cmd);
+    add_command(&write_cmd);
+    add_command(&writev_cmd);
+    add_command(&multiwrite_cmd);
+    add_command(&aio_read_cmd);
+    add_command(&aio_write_cmd);
+    add_command(&aio_flush_cmd);
+    add_command(&flush_cmd);
+    add_command(&truncate_cmd);
+    add_command(&length_cmd);
+    add_command(&info_cmd);
+    add_command(&discard_cmd);
+    add_command(&alloc_cmd);
+    add_command(&map_cmd);
+
+    add_args_command(init_args_command);
+    add_check_command(init_check_command);
+
+    /* open the device */
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
+
+    if ((argc - optind) == 1) {
+        openfile(argv[optind], flags, growable);
+    }
+    command_loop();
 
-       /*
-        * Make sure all outstanding requests get flushed the program exits.
-        */
-       qemu_aio_flush();
+    /*
+     * Make sure all outstanding requests get flushed the program exits.
+     */
+    qemu_aio_flush();
 
-       if (bs)
-               bdrv_close(bs);
-       return 0;
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    return 0;
 }
index 65ca0843265452297de9645025248365662cd52d..a72edda1d22a7eb6639efd6e4333a835fe6eaca8 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
 
-/* Locking primitives.  Most of this code should be redundant -
-   system emulation doesn't need/use locking, NPTL userspace uses
-   pthread mutexes, and non-NPTL userspace isn't threadsafe anyway.
-   In either case a spinlock is probably the wrong kind of lock.
-   Spinlocks are only good if you know annother CPU has the lock and is
-   likely to release it soon.  In environments where you have more threads
-   than physical CPUs (the extreme case being a single CPU host) a spinlock
-   simply wastes CPU until the OS decides to preempt it.  */
-#if defined(CONFIG_USE_NPTL)
+/* configure guarantees us that we have pthreads on any host except
+ * mingw32, which doesn't support any of the user-only targets.
+ * So we can simply assume we have pthread mutexes here.
+ */
+#if defined(CONFIG_USER_ONLY)
 
 #include <pthread.h>
 #define spin_lock pthread_mutex_lock
 
 #else
 
-#if defined(__hppa__)
-
-typedef int spinlock_t[4];
-
-#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
-
-static inline void resetlock (spinlock_t *p)
-{
-    (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
-}
-
-#else
-
+/* Empty implementations, on the theory that system mode emulation
+ * is single-threaded. This means that these functions should only
+ * be used from code run in the TCG cpu thread, and cannot protect
+ * data structures which might also be accessed from the IO thread
+ * or from signal handlers.
+ */
 typedef int spinlock_t;
-
 #define SPIN_LOCK_UNLOCKED 0
 
-static inline void resetlock (spinlock_t *p)
-{
-    *p = SPIN_LOCK_UNLOCKED;
-}
-
-#endif
-
-#if defined(_ARCH_PPC)
-static inline int testandset (int *p)
-{
-    int ret;
-    __asm__ __volatile__ (
-                          "      lwarx %0,0,%1\n"
-                          "      xor. %0,%3,%0\n"
-                          "      bne $+12\n"
-                          "      stwcx. %2,0,%1\n"
-                          "      bne- $-16\n"
-                          : "=&r" (ret)
-                          : "r" (p), "r" (1), "r" (0)
-                          : "cr0", "memory");
-    return ret;
-}
-#elif defined(__i386__)
-static inline int testandset (int *p)
-{
-    long int readval = 0;
-
-    __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
-                          : "+m" (*p), "+a" (readval)
-                          : "r" (1)
-                          : "cc");
-    return readval;
-}
-#elif defined(__x86_64__)
-static inline int testandset (int *p)
-{
-    long int readval = 0;
-
-    __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
-                          : "+m" (*p), "+a" (readval)
-                          : "r" (1)
-                          : "cc");
-    return readval;
-}
-#elif defined(__s390__)
-static inline int testandset (int *p)
-{
-    int ret;
-
-    __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
-                         "   jl    0b"
-                         : "=&d" (ret)
-                         : "r" (1), "a" (p), "0" (*p)
-                         : "cc", "memory" );
-    return ret;
-}
-#elif defined(__alpha__)
-static inline int testandset (int *p)
-{
-    int ret;
-    unsigned long one;
-
-    __asm__ __volatile__ ("0:  mov 1,%2\n"
-                         "     ldl_l %0,%1\n"
-                         "     stl_c %2,%1\n"
-                         "     beq %2,1f\n"
-                         ".subsection 2\n"
-                         "1:   br 0b\n"
-                         ".previous"
-                         : "=r" (ret), "=m" (*p), "=r" (one)
-                         : "m" (*p));
-    return ret;
-}
-#elif defined(__sparc__)
-static inline int testandset (int *p)
-{
-       int ret;
-
-       __asm__ __volatile__("ldstub    [%1], %0"
-                            : "=r" (ret)
-                            : "r" (p)
-                            : "memory");
-
-       return (ret ? 1 : 0);
-}
-#elif defined(__arm__)
-static inline int testandset (int *spinlock)
-{
-    register unsigned int ret;
-    __asm__ __volatile__("swp %0, %1, [%2]"
-                         : "=r"(ret)
-                         : "0"(1), "r"(spinlock));
-
-    return ret;
-}
-#elif defined(__mc68000)
-static inline int testandset (int *p)
-{
-    char ret;
-    __asm__ __volatile__("tas %1; sne %0"
-                         : "=r" (ret)
-                         : "m" (p)
-                         : "cc","memory");
-    return ret;
-}
-#elif defined(__hppa__)
-
-/* Because malloc only guarantees 8-byte alignment for malloc'd data,
-   and GCC only guarantees 8-byte alignment for stack locals, we can't
-   be assured of 16-byte alignment for atomic lock data even if we
-   specify "__attribute ((aligned(16)))" in the type declaration.  So,
-   we use a struct containing an array of four ints for the atomic lock
-   type and dynamically select the 16-byte aligned int from the array
-   for the semaphore.  */
-#define __PA_LDCW_ALIGNMENT 16
-static inline void *ldcw_align (void *p) {
-    unsigned long a = (unsigned long)p;
-    a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
-    return (void *)a;
-}
-
-static inline int testandset (spinlock_t *p)
-{
-    unsigned int ret;
-    p = ldcw_align(p);
-    __asm__ __volatile__("ldcw 0(%1),%0"
-                         : "=r" (ret)
-                         : "r" (p)
-                         : "memory" );
-    return !ret;
-}
-
-#elif defined(__ia64)
-
-#include <ia64intrin.h>
-
-static inline int testandset (int *p)
-{
-    return __sync_lock_test_and_set (p, 1);
-}
-#elif defined(__mips__)
-static inline int testandset (int *p)
-{
-    int ret;
-
-    __asm__ __volatile__ (
-       "       .set push               \n"
-       "       .set noat               \n"
-       "       .set mips2              \n"
-       "1:     li      $1, 1           \n"
-       "       ll      %0, %1          \n"
-       "       sc      $1, %1          \n"
-       "       beqz    $1, 1b          \n"
-       "       .set pop                "
-       : "=r" (ret), "+R" (*p)
-       :
-       : "memory");
-
-    return ret;
-}
-#else
-#error unimplemented CPU support
-#endif
-
-#if defined(CONFIG_USER_ONLY)
-static inline void spin_lock(spinlock_t *lock)
-{
-    while (testandset(lock));
-}
-
-static inline void spin_unlock(spinlock_t *lock)
-{
-    resetlock(lock);
-}
-#else
 static inline void spin_lock(spinlock_t *lock)
 {
 }
@@ -232,6 +45,5 @@ static inline void spin_lock(spinlock_t *lock)
 static inline void spin_unlock(spinlock_t *lock)
 {
 }
-#endif
 
 #endif
index e858033e06fdd5c44337eb7e90cd317955340d60..291cba2eaa6cf78eb7e06b0c4143a88c21164053 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "block_int.h"
 #include "nbd.h"
 
 #include <arpa/inet.h>
 #include <signal.h>
 #include <libgen.h>
+#include <pthread.h>
 
 #define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
 
 #define NBD_BUFFER_SIZE (1024*1024)
 
+static int sigterm_wfd;
 static int verbose;
+static char *device;
+static char *srcpath;
+static char *sockpath;
 
 static void usage(const char *name)
 {
@@ -163,21 +168,80 @@ static int find_partition(BlockDriverState *bs, int partition,
     return -1;
 }
 
-static void show_parts(const char *device)
+static void termsig_handler(int signum)
 {
-    if (fork() == 0) {
-        int nbd;
+    static int sigterm_reported;
+    if (!sigterm_reported) {
+        sigterm_reported = (write(sigterm_wfd, "", 1) == 1);
+    }
+}
 
-        /* linux just needs an open() to trigger
-         * the partition table update
-         * but remember to load the module with max_part != 0 :
-         *     modprobe nbd max_part=63
-         */
-        nbd = open(device, O_RDWR);
-        if (nbd != -1)
-              close(nbd);
-        exit(0);
+static void *show_parts(void *arg)
+{
+    int nbd;
+
+    /* linux just needs an open() to trigger
+     * the partition table update
+     * but remember to load the module with max_part != 0 :
+     *     modprobe nbd max_part=63
+     */
+    nbd = open(device, O_RDWR);
+    if (nbd != -1) {
+        close(nbd);
+    }
+    return NULL;
+}
+
+static void *nbd_client_thread(void *arg)
+{
+    int fd = *(int *)arg;
+    off_t size;
+    size_t blocksize;
+    uint32_t nbdflags;
+    int sock;
+    int ret;
+    pthread_t show_parts_thread;
+
+    do {
+        sock = unix_socket_outgoing(sockpath);
+        if (sock == -1) {
+            goto out;
+        }
+    } while (sock == -1);
+
+    ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
+                                &size, &blocksize);
+    if (ret == -1) {
+        goto out;
+    }
+
+    ret = nbd_init(fd, sock, nbdflags, size, blocksize);
+    if (ret == -1) {
+        goto out;
+    }
+
+    /* update partition table */
+    pthread_create(&show_parts_thread, NULL, show_parts, NULL);
+
+    if (verbose) {
+        fprintf(stderr, "NBD device %s is now connected to %s\n",
+                device, srcpath);
+    } else {
+        /* Close stderr so that the qemu-nbd process exits.  */
+        dup2(STDOUT_FILENO, STDERR_FILENO);
+    }
+
+    ret = nbd_client(fd);
+    if (ret) {
+        goto out;
     }
+    close(fd);
+    kill(getpid(), SIGTERM);
+    return (void *) EXIT_SUCCESS;
+
+out:
+    kill(getpid(), SIGTERM);
+    return (void *) EXIT_FAILURE;
 }
 
 int main(int argc, char **argv)
@@ -185,16 +249,13 @@ int main(int argc, char **argv)
     BlockDriverState *bs;
     off_t dev_offset = 0;
     off_t offset = 0;
-    bool readonly = false;
+    uint32_t nbdflags = 0;
     bool disconnect = false;
     const char *bindto = "0.0.0.0";
     int port = NBD_DEFAULT_PORT;
     struct sockaddr_in addr;
     socklen_t addr_len = sizeof(addr);
     off_t fd_size;
-    char *device = NULL;
-    char *socket = NULL;
-    char sockpath[128];
     const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
     struct option lopt[] = {
         { "help", 0, NULL, 'h' },
@@ -230,7 +291,21 @@ int main(int argc, char **argv)
     int nb_fds = 0;
     int max_fd;
     int persistent = 0;
-    uint32_t nbdflags;
+    pthread_t client_thread;
+
+    /* The client thread uses SIGTERM to interrupt the server.  A signal
+     * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
+     */
+    struct sigaction sa_sigterm;
+    int sigterm_fd[2];
+    if (qemu_pipe(sigterm_fd) == -1) {
+        err(EXIT_FAILURE, "Error setting up communication pipe");
+    }
+
+    sigterm_wfd = sigterm_fd[1];
+    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
+    sa_sigterm.sa_handler = termsig_handler;
+    sigaction(SIGTERM, &sa_sigterm, NULL);
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -238,7 +313,7 @@ int main(int argc, char **argv)
             flags |= BDRV_O_SNAPSHOT;
             break;
         case 'n':
-            flags |= BDRV_O_NOCACHE;
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
             break;
         case 'b':
             bindto = optarg;
@@ -263,7 +338,7 @@ int main(int argc, char **argv)
             }
             break;
         case 'r':
-            readonly = true;
+            nbdflags |= NBD_FLAG_READ_ONLY;
             flags &= ~BDRV_O_RDWR;
             break;
         case 'P':
@@ -274,8 +349,8 @@ int main(int argc, char **argv)
                 errx(EXIT_FAILURE, "Invalid partition %d", partition);
             break;
         case 'k':
-            socket = optarg;
-            if (socket[0] != '/')
+            sockpath = optarg;
+            if (sockpath[0] != '/')
                 errx(EXIT_FAILURE, "socket path must be absolute\n");
             break;
         case 'd':
@@ -333,137 +408,141 @@ int main(int argc, char **argv)
        return 0;
     }
 
-    bdrv_init();
-
-    bs = bdrv_new("hda");
-
-    if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {
-        errno = -ret;
-        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
-    }
-
-    fd_size = bs->total_sectors * 512;
-
-    if (partition != -1 &&
-        find_partition(bs, partition, &dev_offset, &fd_size))
-        err(EXIT_FAILURE, "Could not find partition %d", partition);
-
-    if (device) {
+    if (device && !verbose) {
+        int stderr_fd[2];
         pid_t pid;
-        int sock;
+        int ret;
 
-        /* want to fail before daemonizing */
-        if (access(device, R_OK|W_OK) == -1) {
-            err(EXIT_FAILURE, "Could not access '%s'", device);
+        if (qemu_pipe(stderr_fd) == -1) {
+            err(EXIT_FAILURE, "Error setting up communication pipe");
         }
 
-        if (!verbose) {
-            /* detach client and server */
-            if (daemon(0, 0) == -1) {
+        /* Now daemonize, but keep a communication channel open to
+         * print errors and exit with the proper status code.
+         */
+        pid = fork();
+        if (pid == 0) {
+            close(stderr_fd[0]);
+            ret = qemu_daemon(0, 0);
+
+            /* Temporarily redirect stderr to the parent's pipe...  */
+            dup2(stderr_fd[1], STDERR_FILENO);
+            if (ret == -1) {
                 err(EXIT_FAILURE, "Failed to daemonize");
             }
-        }
 
-        if (socket == NULL) {
-            snprintf(sockpath, sizeof(sockpath), SOCKET_PATH,
-                     basename(device));
-            socket = sockpath;
-        }
-
-        pid = fork();
-        if (pid < 0)
-            return 1;
-        if (pid != 0) {
-            off_t size;
-            size_t blocksize;
-
-            ret = 0;
-            bdrv_close(bs);
-
-            do {
-                sock = unix_socket_outgoing(socket);
-                if (sock == -1) {
-                    if (errno != ENOENT && errno != ECONNREFUSED) {
-                        ret = 1;
-                        goto out;
-                    }
-                    sleep(1);  /* wait children */
+            /* ... close the descriptor we inherited and go on.  */
+            close(stderr_fd[1]);
+        } else {
+            bool errors = false;
+            char *buf;
+
+            /* In the parent.  Print error messages from the child until
+             * it closes the pipe.
+             */
+            close(stderr_fd[1]);
+            buf = g_malloc(1024);
+            while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
+                errors = true;
+                ret = qemu_write_full(STDERR_FILENO, buf, ret);
+                if (ret == -1) {
+                    exit(EXIT_FAILURE);
                 }
-            } while (sock == -1);
-
-            fd = open(device, O_RDWR);
-            if (fd == -1) {
-                ret = 1;
-                goto out;
             }
-
-            ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
-                                       &size, &blocksize);
             if (ret == -1) {
-                ret = 1;
-                goto out;
+                err(EXIT_FAILURE, "Cannot read from daemon");
             }
 
-            ret = nbd_init(fd, sock, size, blocksize);
-            if (ret == -1) {
-                ret = 1;
-                goto out;
-            }
+            /* Usually the daemon should not print any message.
+             * Exit with zero status in that case.
+             */
+            exit(errors);
+        }
+    }
 
-            printf("NBD device %s is now connected to file %s\n",
-                    device, argv[optind]);
+    if (device) {
+        /* Open before spawning new threads.  In the future, we may
+         * drop privileges after opening.
+         */
+        fd = open(device, O_RDWR);
+        if (fd == -1) {
+            err(EXIT_FAILURE, "Failed to open %s", device);
+        }
 
-           /* update partition table */
+        if (sockpath == NULL) {
+            sockpath = g_malloc(128);
+            snprintf(sockpath, 128, SOCKET_PATH, basename(device));
+        }
+    }
 
-            show_parts(device);
+    bdrv_init();
+    atexit(bdrv_close_all);
 
-            ret = nbd_client(fd);
-            if (ret) {
-                ret = 1;
-            }
-            close(fd);
- out:
-            kill(pid, SIGTERM);
-            unlink(socket);
+    bs = bdrv_new("hda");
+    srcpath = argv[optind];
+    if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
+        errno = -ret;
+        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
+    }
 
-            return ret;
-        }
-        /* children */
+    fd_size = bs->total_sectors * 512;
+
+    if (partition != -1 &&
+        find_partition(bs, partition, &dev_offset, &fd_size)) {
+        err(EXIT_FAILURE, "Could not find partition %d", partition);
     }
 
-    sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
+    sharing_fds = g_malloc((shared + 1) * sizeof(int));
 
-    if (socket) {
-        sharing_fds[0] = unix_socket_incoming(socket);
+    if (sockpath) {
+        sharing_fds[0] = unix_socket_incoming(sockpath);
     } else {
         sharing_fds[0] = tcp_socket_incoming(bindto, port);
     }
 
     if (sharing_fds[0] == -1)
         return 1;
+
+    if (device) {
+        int ret;
+
+        ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
+        if (ret != 0) {
+            errx(EXIT_FAILURE, "Failed to create client thread: %s",
+                 strerror(ret));
+        }
+    } else {
+        /* Shut up GCC warnings.  */
+        memset(&client_thread, 0, sizeof(client_thread));
+    }
+
     max_fd = sharing_fds[0];
     nb_fds++;
 
     data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
-    if (data == NULL)
+    if (data == NULL) {
         errx(EXIT_FAILURE, "Cannot allocate data buffer");
+    }
 
     do {
-
         FD_ZERO(&fds);
+        FD_SET(sigterm_fd[0], &fds);
         for (i = 0; i < nb_fds; i++)
             FD_SET(sharing_fds[i], &fds);
 
-        ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
-        if (ret == -1)
+        do {
+            ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
+        } while (ret == -1 && errno == EINTR);
+        if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) {
             break;
+        }
 
         if (FD_ISSET(sharing_fds[0], &fds))
             ret--;
         for (i = 1; i < nb_fds && ret; i++) {
             if (FD_ISSET(sharing_fds[i], &fds)) {
                 if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
-                    &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
+                    &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
                     close(sharing_fds[i]);
                     nb_fds--;
                     sharing_fds[i] = sharing_fds[nb_fds];
@@ -479,7 +558,7 @@ int main(int argc, char **argv)
                                              (struct sockaddr *)&addr,
                                              &addr_len);
                 if (sharing_fds[nb_fds] != -1 &&
-                    nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {
+                    nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
                         if (sharing_fds[nb_fds] > max_fd)
                             max_fd = sharing_fds[nb_fds];
                         nb_fds++;
@@ -490,10 +569,16 @@ int main(int argc, char **argv)
     qemu_vfree(data);
 
     close(sharing_fds[0]);
-    bdrv_close(bs);
-    qemu_free(sharing_fds);
-    if (socket)
-        unlink(socket);
+    g_free(sharing_fds);
+    if (sockpath) {
+        unlink(sockpath);
+    }
 
-    return 0;
+    if (device) {
+        void *ret;
+        pthread_join(client_thread, &ret);
+        exit(ret != NULL);
+    } else {
+        exit(EXIT_SUCCESS);
+    }
 }
index 65db54292b051b9434f83ba968ccbc3048f55da7..f97a758a9561397b59641a3bb519ed8f73db4002 100644 (file)
@@ -168,7 +168,7 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
     return NULL;
 }
 
-static int parse_option_bool(const char *name, const char *value, int *ret)
+static int parse_option_bool(const char *name, const char *value, bool *ret)
 {
     if (value != NULL) {
         if (!strcmp(value, "on")) {
@@ -258,7 +258,7 @@ static int parse_option_size(const char *name, const char *value, uint64_t *ret)
 int set_option_parameter(QEMUOptionParameter *list, const char *name,
     const char *value)
 {
-    int flag;
+    bool flag;
 
     // Find a matching parameter
     list = get_option_parameter(list, name);
@@ -277,7 +277,7 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name,
 
     case OPT_STRING:
         if (value != NULL) {
-            list->value.s = qemu_strdup(value);
+            list->value.s = g_strdup(value);
         } else {
             fprintf(stderr, "Option '%s' needs a parameter\n", name);
             return -1;
@@ -337,12 +337,12 @@ void free_option_parameters(QEMUOptionParameter *list)
 
     while (cur && cur->name) {
         if (cur->type == OPT_STRING) {
-            qemu_free(cur->value.s);
+            g_free(cur->value.s);
         }
         cur++;
     }
 
-    qemu_free(list);
+    g_free(list);
 }
 
 /*
@@ -377,7 +377,7 @@ QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
 
     num_options += count_option_parameters(list);
 
-    dest = qemu_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
+    dest = g_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
     dest[num_dest_options].name = NULL;
 
     while (list && list->name) {
@@ -508,7 +508,7 @@ struct QemuOpt {
 
     const QemuOptDesc *desc;
     union {
-        int      boolean;
+        bool boolean;
         uint64_t uint;
     } value;
 
@@ -542,7 +542,7 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
     return opt ? opt->str : NULL;
 }
 
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
 {
     QemuOpt *opt = qemu_opt_find(opts, name);
 
@@ -594,9 +594,9 @@ static int qemu_opt_parse(QemuOpt *opt)
 static void qemu_opt_del(QemuOpt *opt)
 {
     QTAILQ_REMOVE(&opt->opts->head, opt, next);
-    qemu_free((/* !const */ char*)opt->name);
-    qemu_free((/* !const */ char*)opt->str);
-    qemu_free(opt);
+    g_free((/* !const */ char*)opt->name);
+    g_free((/* !const */ char*)opt->str);
+    g_free(opt);
 }
 
 int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
@@ -619,15 +619,15 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
         }
     }
 
-    opt = qemu_mallocz(sizeof(*opt));
-    opt->name = qemu_strdup(name);
+    opt = g_malloc0(sizeof(*opt));
+    opt->name = g_strdup(name);
     opt->opts = opts;
     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
     if (desc[i].name != NULL) {
         opt->desc = desc+i;
     }
     if (value) {
-        opt->str = qemu_strdup(value);
+        opt->str = g_strdup(value);
     }
     if (qemu_opt_parse(opt) < 0) {
         qemu_opt_del(opt);
@@ -636,6 +636,37 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
     return 0;
 }
 
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
+{
+    QemuOpt *opt;
+    const QemuOptDesc *desc = opts->list->desc;
+    int i;
+
+    for (i = 0; desc[i].name != NULL; i++) {
+        if (strcmp(desc[i].name, name) == 0) {
+            break;
+        }
+    }
+    if (desc[i].name == NULL) {
+        if (i == 0) {
+            /* empty list -> allow any */;
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER, name);
+            return -1;
+        }
+    }
+
+    opt = g_malloc0(sizeof(*opt));
+    opt->name = g_strdup(name);
+    opt->opts = opts;
+    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+    if (desc[i].name != NULL) {
+        opt->desc = desc+i;
+    }
+    opt->value.boolean = !!val;
+    return 0;
+}
+
 int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                      int abort_on_failure)
 {
@@ -701,9 +732,9 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exist
             }
         }
     }
-    opts = qemu_mallocz(sizeof(*opts));
+    opts = g_malloc0(sizeof(*opts));
     if (id) {
-        opts->id = qemu_strdup(id);
+        opts->id = g_strdup(id);
     }
     opts->list = list;
     loc_save(&opts->loc);
@@ -754,8 +785,8 @@ void qemu_opts_del(QemuOpts *opts)
         qemu_opt_del(opt);
     }
     QTAILQ_REMOVE(&opts->list->head, opts, next);
-    qemu_free(opts->id);
-    qemu_free(opts);
+    g_free(opts->id);
+    g_free(opts);
 }
 
 int qemu_opts_print(QemuOpts *opts, void *dummy)
index b515813891997f22b9e9cf062c8428746207fa4a..07958e4e907fe37c4d3dfe0352cce2c43240497b 100644 (file)
@@ -105,10 +105,11 @@ struct QemuOptsList {
 };
 
 const char *qemu_opt_get(QemuOpts *opts, const char *name);
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval);
 uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval);
 uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
 int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val);
 typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque);
 int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                      int abort_on_failure);
index 945edf3562096fccfa2efd924db2183cf95483b1..76d0826ac0592419e1ec963fb4ff158cb2df1b2b 100644 (file)
@@ -27,14 +27,29 @@ STEXI
 Display version information and exit
 ETEXI
 
-DEF("M", HAS_ARG, QEMU_OPTION_M,
-    "-M machine      select emulated machine (-M ? for list)\n", QEMU_ARCH_ALL)
+DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
+    "-machine [type=]name[,prop[=value][,...]]\n"
+    "                selects emulated machine (-machine ? for list)\n"
+    "                property accel=accel1[:accel2[:...]] selects accelerator\n"
+    "                supported accelerators are kvm, xen, tcg (default: tcg)\n",
+    QEMU_ARCH_ALL)
 STEXI
-@item -M @var{machine}
-@findex -M
-Select the emulated @var{machine} (@code{-M ?} for list)
+@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
+@findex -machine
+Select the emulated machine by @var{name}. Use @code{-machine ?} to list
+available machines. Supported machine properties are:
+@table @option
+@item accel=@var{accels1}[:@var{accels2}[:...]]
+This is used to enable an accelerator. Depending on the target architecture,
+kvm, xen, or tcg can be available. By default, tcg is used. If there is more
+than one accelerator specified, the next one is used if the previous one fails
+to initialize.
+@end table
 ETEXI
 
+HXCOMM Deprecated by -machine
+DEF("M", HAS_ARG, QEMU_OPTION_M, "", QEMU_ARCH_ALL)
+
 DEF("cpu", HAS_ARG, QEMU_OPTION_cpu,
     "-cpu cpu        select CPU (-cpu ? for list)\n", QEMU_ARCH_ALL)
 STEXI
@@ -118,7 +133,7 @@ ETEXI
 DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
-    "       [,cache=writethrough|writeback|none|unsafe][,format=f]\n"
+    "       [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
     "       [,serial=s][,addr=A][,id=name][,aio=threads|native]\n"
     "       [,readonly=on|off]\n"
     "                use 'file' as a drive image\n", QEMU_ARCH_ALL)
@@ -133,6 +148,9 @@ Define a new drive. Valid options are:
 This option defines which disk image (@pxref{disk_images}) to use with
 this drive. If the filename contains comma, you must double it
 (for instance, "file=my,,file" to use file "my,file").
+
+Special files such as iSCSI devices can be specified using protocol
+specific URLs. See the section for "Device URL Syntax" for more information.
 @item if=@var{interface}
 This option defines on which type on interface the drive is connected.
 Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
@@ -149,7 +167,7 @@ These options have the same definition as they have in @option{-hdachs}.
 @item snapshot=@var{snapshot}
 @var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}).
 @item cache=@var{cache}
-@var{cache} is "none", "writeback", "unsafe", or "writethrough" and controls how the host cache is used to access block data.
+@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data.
 @item aio=@var{aio}
 @var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO.
 @item format=@var{format}
@@ -160,6 +178,14 @@ an untrusted format header.
 This option specifies the serial number to assign to the device.
 @item addr=@var{addr}
 Specify the controller's PCI address (if=virtio only).
+@item werror=@var{action},rerror=@var{action}
+Specify which @var{action} to take on write and read errors. Valid actions are:
+"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
+"report" (report the error to the guest), "enospc" (pause QEMU only if the
+host disk is full; report the error to the guest otherwise).
+The default setting is @option{werror=enospc} and @option{rerror=report}.
+@item readonly
+Open drive @option{file} as read-only. Guest write attempts will fail.
 @end table
 
 By default, writethrough caching is used for all block device.  This means that
@@ -176,6 +202,10 @@ The host page cache can be avoided entirely with @option{cache=none}.  This will
 attempt to do disk IO directly to the guests memory.  QEMU may still perform
 an internal copy of the data.
 
+The host page cache can be avoided while only sending write notifications to
+the guest when the data has been reported as written by the storage subsystem
+using @option{cache=directsync}.
+
 Some block drivers perform badly with @option{cache=writethrough}, most notably,
 qcow2.  If performance is more important than correctness,
 @option{cache=writeback} should be used with qcow2.
@@ -280,10 +310,13 @@ ETEXI
 
 DEF("boot", HAS_ARG, QEMU_OPTION_boot,
     "-boot [order=drives][,once=drives][,menu=on|off]\n"
-    "                'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n",
+    "      [,splash=sp_name][,splash-time=sp_time]\n"
+    "                'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n"
+    "                'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n"
+    "                'sp_time': the period that splash picture last if menu=on, unit is ms\n",
     QEMU_ARCH_ALL)
 STEXI
-@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off]
+@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}]
 @findex -boot
 Specify boot order @var{drives} as a string of drive letters. Valid
 drive letters depend on the target achitecture. The x86 PC uses: a, b
@@ -295,11 +328,20 @@ particular boot order only on the first startup, specify it via
 Interactive boot menus/prompts can be enabled via @option{menu=on} as far
 as firmware/BIOS supports them. The default is non-interactive boot.
 
+A splash picture could be passed to bios, enabling user to show it as logo,
+when option splash=@var{sp_name} is given and menu=on, If firmware/BIOS
+supports them. Currently Seabios for X86 system support it.
+limitation: The splash file could be a jpeg file or a BMP file in 24 BPP
+format(true color). The resolution should be supported by the SVGA mode, so
+the recommended is 320x240, 640x480, 800x640.
+
 @example
 # try to boot from network first, then from hard disk
 qemu -boot order=nc
 # boot from CD-ROM first, switch back to default order after reboot
 qemu -boot once=d
+# boot with a splash picture for 5 seconds.
+qemu -boot menu=on,splash=/root/boot.bmp,splash-time=5000
 @end example
 
 Note: The legacy format '-boot @var{drives}' is still supported but its
@@ -483,76 +525,121 @@ possible drivers and properties, use @code{-device ?} and
 @code{-device @var{driver},?}.
 ETEXI
 
+DEFHEADING()
+
 DEFHEADING(File system options:)
 
 DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
-    "-fsdev local,id=id,path=path,security_model=[mapped|passthrough|none]\n",
+    "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
+    "       [,writeout=immediate][,readonly]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-The general form of a File system device option is:
-@table @option
-
-@item -fsdev @var{fstype} ,id=@var{id} [,@var{options}]
+@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly]
 @findex -fsdev
-Fstype is one of:
-@option{local},
-The specific Fstype will determine the applicable options.
-
-Options to each backend are described below.
-
-@item -fsdev local ,id=@var{id} ,path=@var{path} ,security_model=@var{security_model}
-
-Create a file-system-"device" for local-filesystem.
-
-@option{local} is only available on Linux.
-
-@option{path} specifies the path to be exported. @option{path} is required.
-
-@option{security_model} specifies the security model to be followed.
-@option{security_model} is required.
+Define a new file system device. Valid options are:
+@table @option
+@item @var{fsdriver}
+This option specifies the fs driver backend to use.
+Currently "local" and "handle" file system drivers are supported.
+@item id=@var{id}
+Specifies identifier for this device
+@item path=@var{path}
+Specifies the export path for the file system device. Files under
+this path will be available to the 9p client on the guest.
+@item security_model=@var{security_model}
+Specifies the security model to be used for this export path.
+Supported security models are "passthrough", "mapped" and "none".
+In "passthrough" security model, files are stored using the same
+credentials as they are created on the guest. This requires qemu
+to run as root. In "mapped" security model, some of the file
+attributes like uid, gid, mode bits and link target are stored as
+file attributes. Directories exported by this security model cannot
+interact with other unix tools. "none" security model is same as
+passthrough except the sever won't report failures if it fails to
+set file attributes like ownership. Security model is mandatory
+only for local fsdriver. Other fsdrivers (like handle) don't take
+security model as a parameter.
+@item writeout=@var{writeout}
+This is an optional argument. The only supported value is "immediate".
+This means that host page cache will be used to read and write data but
+write notification will be sent to the guest only when the data has been
+reported as written by the storage subsystem.
+@item readonly
+Enables exporting 9p share as a readonly mount for guests. By default
+read-write access is given.
+@end table
 
+-fsdev option is used along with -device driver "virtio-9p-pci".
+@item -device virtio-9p-pci,fsdev=@var{id},mount_tag=@var{mount_tag}
+Options for virtio-9p-pci driver are:
+@table @option
+@item fsdev=@var{id}
+Specifies the id value specified along with -fsdev option
+@item mount_tag=@var{mount_tag}
+Specifies the tag name to be used by the guest to mount this export point
 @end table
+
 ETEXI
 
+DEFHEADING()
+
 DEFHEADING(Virtual File system pass-through options:)
 
 DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
-    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n",
+    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
+    "        [,writeout=immediate][,readonly]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-The general form of a Virtual File system pass-through option is:
-@table @option
-
-@item -virtfs @var{fstype} [,@var{options}]
+@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}][,readonly]
 @findex -virtfs
-Fstype is one of:
-@option{local},
-The specific Fstype will determine the applicable options.
-
-Options to each backend are described below.
-
-@item -virtfs local ,path=@var{path} ,mount_tag=@var{mount_tag} ,security_model=@var{security_model}
-
-Create a Virtual file-system-pass through for local-filesystem.
-
-@option{local} is only available on Linux.
-
-@option{path} specifies the path to be exported. @option{path} is required.
-
-@option{security_model} specifies the security model to be followed.
-@option{security_model} is required.
-
-
-@option{mount_tag} specifies the tag with which the exported file is mounted.
-@option{mount_tag} is required.
 
+The general form of a Virtual File system pass-through options are:
+@table @option
+@item @var{fsdriver}
+This option specifies the fs driver backend to use.
+Currently "local" and "handle" file system drivers are supported.
+@item id=@var{id}
+Specifies identifier for this device
+@item path=@var{path}
+Specifies the export path for the file system device. Files under
+this path will be available to the 9p client on the guest.
+@item security_model=@var{security_model}
+Specifies the security model to be used for this export path.
+Supported security models are "passthrough", "mapped" and "none".
+In "passthrough" security model, files are stored using the same
+credentials as they are created on the guest. This requires qemu
+to run as root. In "mapped" security model, some of the file
+attributes like uid, gid, mode bits and link target are stored as
+file attributes. Directories exported by this security model cannot
+interact with other unix tools. "none" security model is same as
+passthrough except the sever won't report failures if it fails to
+set file attributes like ownership. Security model is mandatory only
+for local fsdriver. Other fsdrivers (like handle) don't take security
+model as a parameter.
+@item writeout=@var{writeout}
+This is an optional argument. The only supported value is "immediate".
+This means that host page cache will be used to read and write data but
+write notification will be sent to the guest only when the data has been
+reported as written by the storage subsystem.
+@item readonly
+Enables exporting 9p share as a readonly mount for guests. By default
+read-write access is given.
 @end table
 ETEXI
 
+DEF("virtfs_synth", 0, QEMU_OPTION_virtfs_synth,
+    "-virtfs_synth Create synthetic file system image\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -virtfs_synth
+@findex -virtfs_synth
+Create synthetic file system image
+ETEXI
+
 DEFHEADING()
 
 DEF("name", HAS_ARG, QEMU_OPTION_name,
@@ -590,6 +677,37 @@ STEXI
 @table @option
 ETEXI
 
+DEF("display", HAS_ARG, QEMU_OPTION_display,
+    "-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off]\n"
+    "            [,window_close=on|off]|curses|none|\n"
+    "            vnc=<display>[,<optargs>]\n"
+    "                select display type\n", QEMU_ARCH_ALL)
+STEXI
+@item -display @var{type}
+@findex -display
+Select type of display to use. This option is a replacement for the
+old style -sdl/-curses/... options. Valid values for @var{type} are
+@table @option
+@item sdl
+Display video output via SDL (usually in a separate graphics
+window; see the SDL documentation for other possibilities).
+@item curses
+Display video output via curses. For graphics device models which
+support a text mode, QEMU can display this output using a
+curses/ncurses interface. Nothing is displayed when the graphics
+device is in graphical mode or if the graphics device does not support
+a text mode. Generally only the VGA device models support text mode.
+@item none
+Do not display video output. The guest will still see an emulated
+graphics card, but its output will not be displayed to the QEMU
+user. This option differs from the -nographic option in that it
+only affects what is done with video output; -nographic also changes
+the destination of the serial and parallel port data.
+@item vnc
+Start a VNC server on display <arg>
+@end table
+ETEXI
+
 DEF("nographic", 0, QEMU_OPTION_nographic,
     "-nographic      disable graphical output and redirect serial I/Os to console\n",
     QEMU_ARCH_ALL)
@@ -603,11 +721,9 @@ the console. Therefore, you can still use QEMU to debug a Linux kernel
 with a serial console.
 ETEXI
 
-#ifdef CONFIG_CURSES
 DEF("curses", 0, QEMU_OPTION_curses,
     "-curses         use a curses/ncurses interface instead of SDL\n",
     QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -curses
 @findex curses
@@ -616,11 +732,9 @@ QEMU can display the VGA output when in text mode using a
 curses/ncurses interface.  Nothing is displayed in graphical mode.
 ETEXI
 
-#ifdef CONFIG_SDL
 DEF("no-frame", 0, QEMU_OPTION_no_frame,
     "-no-frame       open SDL window without a frame and window decorations\n",
     QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -no-frame
 @findex -no-frame
@@ -629,42 +743,36 @@ available screen space. This makes the using QEMU in a dedicated desktop
 workspace more convenient.
 ETEXI
 
-#ifdef CONFIG_SDL
 DEF("alt-grab", 0, QEMU_OPTION_alt_grab,
     "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n",
     QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -alt-grab
 @findex -alt-grab
-Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt).
+Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). Note that this also
+affects the special keys (for fullscreen, monitor-mode switching, etc).
 ETEXI
 
-#ifdef CONFIG_SDL
 DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab,
     "-ctrl-grab      use Right-Ctrl to grab mouse (instead of Ctrl-Alt)\n",
     QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -ctrl-grab
 @findex -ctrl-grab
-Use Right-Ctrl to grab mouse (instead of Ctrl-Alt).
+Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). Note that this also
+affects the special keys (for fullscreen, monitor-mode switching, etc).
 ETEXI
 
-#ifdef CONFIG_SDL
 DEF("no-quit", 0, QEMU_OPTION_no_quit,
     "-no-quit        disable SDL window close capability\n", QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -no-quit
 @findex -no-quit
 Disable SDL window close capability.
 ETEXI
 
-#ifdef CONFIG_SDL
 DEF("sdl", 0, QEMU_OPTION_sdl,
     "-sdl            enable SDL\n", QEMU_ARCH_ALL)
-#endif
 STEXI
 @item -sdl
 @findex -sdl
@@ -693,9 +801,25 @@ Force using the specified IP version.
 @item password=<secret>
 Set the password you need to authenticate.
 
+@item sasl
+Require that the client use SASL to authenticate with the spice.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials.
+
 @item disable-ticketing
 Allow client connects without authentication.
 
+@item disable-copy-paste
+Disable copy paste between the client and the guest.
+
 @item tls-port=<nr>
 Set the TCP port spice is listening on for encrypted channels.
 
@@ -750,6 +874,15 @@ STEXI
 Rotate graphical output 90 deg left (only PXA LCD).
 ETEXI
 
+DEF("rotate", HAS_ARG, QEMU_OPTION_rotate,
+    "-rotate <deg>   rotate graphical output some deg left (only PXA LCD)\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -rotate
+@findex -rotate
+Rotate graphical output some deg left (only PXA LCD).
+ETEXI
+
 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
     "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
@@ -913,6 +1046,15 @@ option is set, VNC client may receive lossy framebuffer updates
 depending on its encoding settings. Enabling this option can save
 a lot of bandwidth at the expense of quality.
 
+@item non-adaptive
+
+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 helpful to save bandwidth when playing videos. Disabling
+adaptive encodings allows to restore the original static behavior of encodings
+like Tight.
+
 @end table
 ETEXI
 
@@ -984,12 +1126,17 @@ Enable virtio balloon device (default), optionally with PCI address
 ETEXI
 
 DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable,
-    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
+    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,{data|file}=file1[:file2]...]\n"
     "                ACPI table description\n", QEMU_ARCH_I386)
 STEXI
 @item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...]
 @findex -acpitable
 Add ACPI table with specified header fields and context from specified files.
+For file=, take whole ACPI table from the specified files, including all
+ACPI headers (possible overridden by other options).
+For data=, only data
+portion of the table is used, all header information is specified in the
+command line.
 ETEXI
 
 DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
@@ -1037,7 +1184,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
     "                create a new Network Interface Card and connect it to VLAN 'n'\n"
 #ifdef CONFIG_SLIRP
-    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
+    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
     "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
     "         [,hostfwd=rule][,guestfwd=rule]"
 #ifndef _WIN32
@@ -1124,23 +1271,23 @@ 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
 guest network, i.e. x.x.x.2.
 
-@item restrict=y|yes|n|no
-If this options is enabled, the guest will be isolated, i.e. it will not be
+@item restrict=on|off
+If this option is enabled, the guest will be isolated, i.e. it will not be
 able to contact the host and no guest IP packets will be routed over the host
-to the outside. This option does not affect explicitly set forwarding rule.
+to the outside. This option does not affect any explicitly set forwarding rules.
 
 @item hostname=@var{name}
 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
@@ -1178,9 +1325,9 @@ or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000).
 
 Then @file{@var{dir}} can be accessed in @file{\\smbserver\qemu}.
 
-Note that a SAMBA server must be installed on the host OS in
-@file{/usr/sbin/smbd}. QEMU was tested successfully with smbd versions from
-Red Hat 9, Fedora Core 3 and OpenSUSE 11.x.
+Note that a SAMBA server must be installed on the host OS.
+QEMU was tested successfully with smbd versions from Red Hat 9,
+Fedora Core 3 and OpenSUSE 11.x.
 
 @item hostfwd=[tcp|udp]:[@var{hostaddr}]:@var{hostport}-[@var{guestaddr}]:@var{guestport}
 Redirect incoming TCP or UDP connections to the host port @var{hostport} to
@@ -1313,7 +1460,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
 Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
 listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
 and MODE @var{octalmode} to change default ownership and permissions for
-communication port. This option is available only if QEMU has been compiled
+communication port. This option is only available if QEMU has been compiled
 with vde support enabled.
 
 Example:
@@ -1574,21 +1721,108 @@ Connect to a local parallel port.
 @option{path} specifies the path to the parallel port device. @option{path} is
 required.
 
-#if defined(CONFIG_SPICE)
 @item -chardev spicevmc ,id=@var{id} ,debug=@var{debug}, name=@var{name}
 
+@option{spicevmc} is only available when spice support is built in.
+
 @option{debug} debug level for spicevmc
 
 @option{name} name of spice channel to connect to
 
 Connect to a spice virtual machine channel, such as vdiport.
-#endif
 
 @end table
 ETEXI
 
 DEFHEADING()
 
+STEXI
+DEFHEADING(Device URL Syntax:)
+
+In addition to using normal file images for the emulated storage devices,
+QEMU can also use networked resources such as iSCSI devices. These are
+specified using a special URL syntax.
+
+@table @option
+@item iSCSI
+iSCSI support allows QEMU to access iSCSI resources directly and use as
+images for the guest storage. Both disk and cdrom images are supported.
+
+Syntax for specifying iSCSI LUNs is
+``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
+
+Example (without authentication):
+@example
+qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
+--drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+@end example
+
+Example (CHAP username/password via URL):
+@example
+qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
+@end example
+
+Example (CHAP username/password via environment variables):
+@example
+LIBISCSI_CHAP_USERNAME="user" \
+LIBISCSI_CHAP_PASSWORD="password" \
+qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+@end example
+
+iSCSI support is an optional feature of QEMU and only available when
+compiled and linked against libiscsi.
+
+@item NBD
+QEMU supports NBD (Network Block Devices) both using TCP protocol as well
+as Unix Domain Sockets.
+
+Syntax for specifying a NBD device using TCP
+``nbd:<server-ip>:<port>[:exportname=<export>]''
+
+Syntax for specifying a NBD device using Unix Domain Sockets
+``nbd:unix:<domain-socket>[:exportname=<export>]''
+
+
+Example for TCP
+@example
+qemu --drive file=nbd:192.0.2.1:30000
+@end example
+
+Example for Unix Domain Sockets
+@example
+qemu --drive file=nbd:unix:/tmp/nbd-socket
+@end example
+
+@item Sheepdog
+Sheepdog is a distributed storage system for QEMU.
+QEMU supports using either local sheepdog devices or remote networked
+devices.
+
+Syntax for specifying a sheepdog device
+@table @list
+``sheepdog:<vdiname>''
+
+``sheepdog:<vdiname>:<snapid>''
+
+``sheepdog:<vdiname>:<tag>''
+
+``sheepdog:<host>:<port>:<vdiname>''
+
+``sheepdog:<host>:<port>:<vdiname>:<snapid>''
+
+``sheepdog:<host>:<port>:<vdiname>:<tag>''
+@end table
+
+Example
+@example
+qemu --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
+@end example
+
+See also @url{http://http://www.osrg.net/sheepdog/}.
+
+@end table
+ETEXI
+
 DEFHEADING(Bluetooth(R) options:)
 
 DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
@@ -1961,6 +2195,15 @@ STEXI
 Output log in /tmp/qemu.log
 ETEXI
 
+DEF("D", HAS_ARG, QEMU_OPTION_D, \
+    "-D logfile      output log to logfile (instead of the default /tmp/qemu.log)\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -D
+@findex -D
+Output log in logfile instead of /tmp/qemu.log
+ETEXI
+
 DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
     "-hdachs c,h,s[,t]\n" \
     "                force hard disk 0 physical geometry and the optional BIOS\n" \
@@ -2002,6 +2245,25 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+DEF("enable-gl", 0, QEMU_OPTION_enable_gl, \
+    "-enable-gl     enable OpenGL passthrough support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-gl
+@findex -enable-gl
+Enable OpenGL passthrough support. This option requires the support of a
+special libGL installed on the guest OS.
+ETEXI
+
+
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+    "-enable-hax     enable HAX virtualization support\n", QEMU_ARCH_I386)
+STEXI
+@item -enable-hax
+@findex -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. When HAX support detected, emulator will enable it by default. This option will disable the default action
+HAX is only supported in MAC and Windows platform and is not conflict with KVM.
+ETEXI
+
 DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
     "-xen-domid id   specify xen guest domain id\n", QEMU_ARCH_ALL)
 DEF("xen-create", 0, QEMU_OPTION_xen_create,
@@ -2288,11 +2550,11 @@ STEXI
 Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
 ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
-    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K)
+    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA)
 STEXI
 @item -semihosting
 @findex -semihosting
-Semihosting mode (ARM, M68K only).
+Semihosting mode (ARM, M68K, Xtensa only).
 ETEXI
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n", QEMU_ARCH_ARM)
@@ -2328,17 +2590,51 @@ Normally QEMU loads a configuration file from @var{sysconfdir}/qemu.conf and
 @var{sysconfdir}/target-@var{ARCH}.conf on startup.  The @code{-nodefconfig}
 option will prevent QEMU from loading these configuration files at startup.
 ETEXI
-#ifdef CONFIG_SIMPLE_TRACE
 DEF("trace", HAS_ARG, QEMU_OPTION_trace,
-    "-trace\n"
-    "                Specify a trace file to log traces to\n",
+    "-trace [events=<file>][,file=<file>]\n"
+    "                specify tracing options\n",
     QEMU_ARCH_ALL)
 STEXI
-@item -trace
+HXCOMM This line is not accurate, as some sub-options are backend-specific but
+HXCOMM HX does not support conditional compilation of text.
+@item -trace [events=@var{file}][,file=@var{file}]
 @findex -trace
-Specify a trace file to log output traces to.
+
+Specify tracing options.
+
+@table @option
+@item events=@var{file}
+Immediately enable events listed in @var{file}.
+The file must contain one event name (as listed in the @var{trace-events} file)
+per line.
+This option is only available if QEMU has been compiled with
+either @var{simple} or @var{stderr} tracing backend.
+@item file=@var{file}
+Log output traces to @var{file}.
+
+This option is only available if QEMU has been compiled with
+the @var{simple} tracing backend.
+@end table
+ETEXI
+
+DEF("max-touch-point", HAS_ARG, QEMU_OPTION_max_touch_point, \
+    "-max-touch-point [count]\n"
+    "                define maximum number of touch point\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -max-touch-point @var{max_count}
+@findex -max-touch-point
+Use @var{max_count} as Integer
+ETEXI
+
+DEF("disable-skin", 0, QEMU_OPTION_disable_skin, \
+    "-disable-skin\n"
+    "                do not start with java skin process\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -disable-skin
+@findex -disable-skin
 ETEXI
-#endif
 
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
index 81fd9ab389c648c448685adec5ff473fd87527ce..8e1149d9640cde3735aa5c26fb6849acb9d6e6c4 100644 (file)
 #ifndef QEMU_OS_POSIX_H
 #define QEMU_OS_POSIX_H
 
-static inline void os_host_main_loop_wait(int *timeout)
-{
-}
-
 void os_set_line_buffering(void);
 void os_set_proc_name(const char *s);
 void os_setup_signal_handling(void);
@@ -48,7 +44,6 @@ typedef struct timeval qemu_timeval;
 #endif
 #endif
 typedef struct timespec qemu_timespec;
-int qemu_utimensat(int dirfd, const char *path, const qemu_timespec *times,
-    int flags);
+int qemu_utimens(const char *path, const qemu_timespec *times);
 
 #endif
index 1a07e5e264a98a16791b79244ce0afda48461b85..8eda4bdc20dafa69f72b71b5c8aa8fd41dbf93b3 100644 (file)
 #ifndef QEMU_OS_WIN32_H
 #define QEMU_OS_WIN32_H
 
-/* Polling handling */
+#include <windows.h>
+#include <winsock2.h>
+#include "main-loop.h"
 
-/* return TRUE if no sleep should be done afterwards */
-typedef int PollingFunc(void *opaque);
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque);
-void qemu_del_polling_cb(PollingFunc *func, void *opaque);
-
-/* Wait objects handling */
-typedef void WaitObjectFunc(void *opaque);
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-
-void os_host_main_loop_wait(int *timeout);
+/* Declaration of ffs() is missing in MinGW's strings.h. */
+int ffs(int i);
 
 static inline void os_setup_signal_handling(void) {}
 static inline void os_daemonize(void) {}
diff --git a/qemu-progress.c b/qemu-progress.c
new file mode 100644 (file)
index 0000000..5f1b8df
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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>
+
+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;
+}
+
+/*
+ * Initialize progress reporting.
+ * If @enabled is false, actual reporting is suppressed.  The user can
+ * still trigger a report by sending a SIGUSR1.
+ * Reports are also suppressed unless we've had at least @min_skip
+ * percent progress since the last report.
+ */
+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();
+}
+
+/*
+ * Report progress.
+ * @delta is how much progress we made.
+ * If @max is zero, @delta is an absolut value of the total job done.
+ * Else, @delta is a progress delta since the last call, as a fraction
+ * of @max.  I.e. the delta is @delta * @max / 100. This allows
+ * relative accounting of functions which may be a different fraction of
+ * the full job, depending on the context they are called in. I.e.
+ * a function might be considered 40% of the full job if used from
+ * bdrv_img_create() but only 20% if called from img_convert().
+ */
+void qemu_progress_print(float delta, int max)
+{
+    float current;
+
+    if (max == 0) {
+        current = delta;
+    } else {
+        current = state.current + delta / 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 1d077458ce1ba5cba8d07f66c7684a170d316181..22142305a61160232b3fcb20b394c68a7bb4e6bd 100644 (file)
@@ -76,6 +76,8 @@
  * For details on the use of these macros, see the queue(3) manual page.
  */
 
+#include "qemu-barrier.h" /* for smp_wmb() */
+
 /*
  * List definitions.
  */
@@ -122,6 +124,17 @@ struct {                                                                \
         (elm)->field.le_prev = &(head)->lh_first;                       \
 } while (/*CONSTCOND*/0)
 
+#define QLIST_INSERT_HEAD_RCU(head, elm, field) do {                    \
+        (elm)->field.le_prev = &(head)->lh_first;                       \
+        (elm)->field.le_next = (head)->lh_first;                        \
+        smp_wmb(); /* fill elm before linking it */                     \
+        if ((head)->lh_first != NULL)  {                                \
+            (head)->lh_first->field.le_prev = &(elm)->field.le_next;    \
+        }                                                               \
+        (head)->lh_first = (elm);                                       \
+        smp_wmb();                                                      \
+} while (/* CONSTCOND*/0)
+
 #define QLIST_REMOVE(elm, field) do {                                   \
         if ((elm)->field.le_next != NULL)                               \
                 (elm)->field.le_next->field.le_prev =                   \
index 70419e97dba139e4fcc8c071856e3a0e140de590..fc5b465cf362383565fc49c71d6451b8d67c1b51 100644 (file)
@@ -572,6 +572,7 @@ int unix_connect_opts(QemuOpts *opts)
     snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
     if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
         fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
+        close(sock);
        return -1;
     }
 
@@ -593,10 +594,10 @@ int unix_listen(const char *str, char *ostr, int olen)
     if (optstr) {
         len = optstr - str;
         if (len) {
-            path = qemu_malloc(len+1);
+            path = g_malloc(len+1);
             snprintf(path, len+1, "%.*s", len, str);
             qemu_opt_set(opts, "path", path);
-            qemu_free(path);
+            g_free(path);
         }
     } else {
         qemu_opt_set(opts, "path", str);
@@ -627,25 +628,53 @@ 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;
 }
 
 #endif
+
+#ifdef _WIN32
+static void socket_cleanup(void)
+{
+    WSACleanup();
+}
+#endif
+
+int socket_init(void)
+{
+#ifdef _WIN32
+    WSADATA Data;
+    int ret, err;
+
+    ret = WSAStartup(MAKEWORD(2,0), &Data);
+    if (ret != 0) {
+        err = WSAGetLastError();
+        fprintf(stderr, "WSAStartup: %d\n", err);
+        return -1;
+    }
+    atexit(socket_cleanup);
+#endif
+    return 0;
+}
index 138e3ce9add9151b70d506b94e6305360a830c23..62afe45dc2869e63c0d8e4ab3bbd2a88ae05fdf2 100644 (file)
 @chapter Introduction
 
 @menu
-* intro_features::        Features
-* intro_x86_emulation::   x86 and x86-64 emulation
-* intro_arm_emulation::   ARM emulation
-* intro_mips_emulation::  MIPS emulation
-* intro_ppc_emulation::   PowerPC emulation
-* intro_sparc_emulation:: Sparc32 and Sparc64 emulation
-* intro_other_emulation:: Other CPU emulation
+* intro_features::         Features
+* intro_x86_emulation::    x86 and x86-64 emulation
+* intro_arm_emulation::    ARM emulation
+* intro_mips_emulation::   MIPS emulation
+* intro_ppc_emulation::    PowerPC emulation
+* intro_sparc_emulation::  Sparc32 and Sparc64 emulation
+* intro_xtensa_emulation:: Xtensa emulation
+* intro_other_emulation::  Other CPU emulation
 @end menu
 
 @node intro_features
@@ -259,6 +260,31 @@ Current QEMU limitations:
 
 @end itemize
 
+@node intro_xtensa_emulation
+@section Xtensa emulation
+
+@itemize
+
+@item Core Xtensa ISA emulation, including most options: code density,
+loop, extended L32R, 16- and 32-bit multiplication, 32-bit division,
+MAC16, miscellaneous operations, boolean, multiprocessor synchronization,
+conditional store, exceptions, relocatable vectors, unaligned exception,
+interrupts (including high priority and timer), hardware alignment,
+region protection, region translation, MMU, windowed registers, thread
+pointer, processor ID.
+
+@item Not implemented options: FP coprocessor, coprocessor context,
+data/instruction cache (including cache prefetch and locking), XLMI,
+processor interface, debug. Also options not covered by the core ISA
+(e.g. FLIX, wide branches) are not implemented.
+
+@item Can run most Xtensa Linux binaries.
+
+@item New core configuration that requires no additional instructions
+may be created from overlay with minimal amount of hand-written code.
+
+@end itemize
+
 @node intro_other_emulation
 @section Other CPU emulation
 
@@ -409,7 +435,7 @@ generate an addition for the segment base.
 @node Translation cache
 @section Translation cache
 
-A 16 MByte cache holds the most recently used translations. For
+A 32 MByte cache holds the most recently used translations. For
 simplicity, it is completely flushed when it is full. A translation unit
 contains just a single basic block (a block of x86 instructions
 terminated by a jump or by a virtual CPU state change which the
diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
new file mode 100644 (file)
index 0000000..ac3c0c9
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Wrappers around mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Author:
+ *  Marcelo Tosatti <mtosatti@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include "qemu-thread.h"
+
+static void error_exit(int err, const char *msg)
+{
+    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
+    abort();
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+    int err;
+    pthread_mutexattr_t mutexattr;
+
+    pthread_mutexattr_init(&mutexattr);
+    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
+    err = pthread_mutex_init(&mutex->lock, &mutexattr);
+    pthread_mutexattr_destroy(&mutexattr);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_mutex_destroy(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_destroy(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_lock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+    return pthread_mutex_trylock(&mutex->lock);
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_unlock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_init(&cond->cond, NULL);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_destroy(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_destroy(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_signal(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_broadcast(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_cond_wait(&cond->cond, &mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void*),
+                       void *arg)
+{
+    int err;
+
+    /* Leave signal handling to the iothread.  */
+    sigset_t set, oldset;
+
+    sigfillset(&set);
+    pthread_sigmask(SIG_SETMASK, &set, &oldset);
+    err = pthread_create(&thread->thread, NULL, start_routine, arg);
+    if (err)
+        error_exit(err, __func__);
+
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+}
+
+void qemu_thread_get_self(QemuThread *thread)
+{
+    thread->thread = pthread_self();
+}
+
+int qemu_thread_is_self(QemuThread *thread)
+{
+   return pthread_equal(pthread_self(), thread->thread);
+}
+
+void qemu_thread_exit(void *retval)
+{
+    pthread_exit(retval);
+}
diff --git a/qemu-thread-posix.h b/qemu-thread-posix.h
new file mode 100644 (file)
index 0000000..ee4618e
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __QEMU_THREAD_POSIX_H
+#define __QEMU_THREAD_POSIX_H 1
+#include "pthread.h"
+
+struct QemuMutex {
+    pthread_mutex_t lock;
+};
+
+struct QemuCond {
+    pthread_cond_t cond;
+};
+
+struct QemuThread {
+    pthread_t thread;
+};
+
+#endif
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
new file mode 100644 (file)
index 0000000..db8e744
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Win32 implementation for mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Author:
+ *  Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "qemu-thread.h"
+#include <process.h>
+#include <assert.h>
+#include <limits.h>
+
+static void error_exit(int err, const char *msg)
+{
+    char *pstr;
+
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                  NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
+    fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
+    LocalFree(pstr);
+    abort();
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+    mutex->owner = 0;
+    InitializeCriticalSection(&mutex->lock);
+}
+
+void qemu_mutex_destroy(QemuMutex *mutex)
+{
+    assert(mutex->owner == 0);
+    DeleteCriticalSection(&mutex->lock);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+    EnterCriticalSection(&mutex->lock);
+
+    /* Win32 CRITICAL_SECTIONs are recursive.  Assert that we're not
+     * using them as such.
+     */
+    assert(mutex->owner == 0);
+    mutex->owner = GetCurrentThreadId();
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+    int owned;
+
+    owned = TryEnterCriticalSection(&mutex->lock);
+    if (owned) {
+        assert(mutex->owner == 0);
+        mutex->owner = GetCurrentThreadId();
+    }
+    return !owned;
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+    assert(mutex->owner == GetCurrentThreadId());
+    mutex->owner = 0;
+    LeaveCriticalSection(&mutex->lock);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+    memset(cond, 0, sizeof(*cond));
+
+    cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
+    if (!cond->sema) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->continue_event = CreateEvent(NULL,    /* security */
+                                       FALSE,   /* auto-reset */
+                                       FALSE,   /* not signaled */
+                                       NULL);   /* name */
+    if (!cond->continue_event) {
+        error_exit(GetLastError(), __func__);
+    }
+}
+
+void qemu_cond_destroy(QemuCond *cond)
+{
+    BOOL result;
+    result = CloseHandle(cond->continue_event);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->continue_event = 0;
+    result = CloseHandle(cond->sema);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->sema = 0;
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+    DWORD result;
+
+    /*
+     * Signal only when there are waiters.  cond->waiters is
+     * incremented by pthread_cond_wait under the external lock,
+     * so we are safe about that.
+     */
+    if (cond->waiters == 0) {
+        return;
+    }
+
+    /*
+     * Waiting threads decrement it outside the external lock, but
+     * only if another thread is executing pthread_cond_broadcast and
+     * has the mutex.  So, it also cannot be decremented concurrently
+     * with this particular access.
+     */
+    cond->target = cond->waiters - 1;
+    result = SignalObjectAndWait(cond->sema, cond->continue_event,
+                                 INFINITE, FALSE);
+    if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
+        error_exit(GetLastError(), __func__);
+    }
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+    BOOLEAN result;
+    /*
+     * As in pthread_cond_signal, access to cond->waiters and
+     * cond->target is locked via the external mutex.
+     */
+    if (cond->waiters == 0) {
+        return;
+    }
+
+    cond->target = 0;
+    result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+
+    /*
+     * At this point all waiters continue. Each one takes its
+     * slice of the semaphore. Now it's our turn to wait: Since
+     * the external mutex is held, no thread can leave cond_wait,
+     * yet. For this reason, we can be sure that no thread gets
+     * a chance to eat *more* than one slice. OTOH, it means
+     * that the last waiter must send us a wake-up.
+     */
+    WaitForSingleObject(cond->continue_event, INFINITE);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+    /*
+     * This access is protected under the mutex.
+     */
+    cond->waiters++;
+
+    /*
+     * Unlock external mutex and wait for signal.
+     * NOTE: we've held mutex locked long enough to increment
+     * waiters count above, so there's no problem with
+     * leaving mutex unlocked before we wait on semaphore.
+     */
+    qemu_mutex_unlock(mutex);
+    WaitForSingleObject(cond->sema, INFINITE);
+
+    /* Now waiters must rendez-vous with the signaling thread and
+     * let it continue.  For cond_broadcast this has heavy contention
+     * and triggers thundering herd.  So goes life.
+     *
+     * Decrease waiters count.  The mutex is not taken, so we have
+     * to do this atomically.
+     *
+     * All waiters contend for the mutex at the end of this function
+     * until the signaling thread relinquishes it.  To ensure
+     * each waiter consumes exactly one slice of the semaphore,
+     * the signaling thread stops until it is told by the last
+     * waiter that it can go on.
+     */
+    if (InterlockedDecrement(&cond->waiters) == cond->target) {
+        SetEvent(cond->continue_event);
+    }
+
+    qemu_mutex_lock(mutex);
+}
+
+struct QemuThreadData {
+    QemuThread *thread;
+    void *(*start_routine)(void *);
+    void *arg;
+};
+
+static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES;
+
+static unsigned __stdcall win32_start_routine(void *arg)
+{
+    struct QemuThreadData data = *(struct QemuThreadData *) arg;
+    QemuThread *thread = data.thread;
+
+    free(arg);
+    TlsSetValue(qemu_thread_tls_index, thread);
+
+    /*
+     * Use DuplicateHandle instead of assigning thread->thread in the
+     * creating thread to avoid races.  It's simpler this way than with
+     * synchronization.
+     */
+    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+                    GetCurrentProcess(), &thread->thread,
+                    0, FALSE, DUPLICATE_SAME_ACCESS);
+
+    qemu_thread_exit(data.start_routine(data.arg));
+    abort();
+}
+
+void qemu_thread_exit(void *arg)
+{
+    QemuThread *thread = TlsGetValue(qemu_thread_tls_index);
+    thread->ret = arg;
+    CloseHandle(thread->thread);
+    thread->thread = NULL;
+    ExitThread(0);
+}
+
+static inline void qemu_thread_init(void)
+{
+    if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
+        qemu_thread_tls_index = TlsAlloc();
+        if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
+            error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__);
+        }
+    }
+}
+
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void *),
+                       void *arg)
+{
+    HANDLE hThread;
+
+    struct QemuThreadData *data;
+    qemu_thread_init();
+    data = g_malloc(sizeof *data);
+    data->thread = thread;
+    data->start_routine = start_routine;
+    data->arg = arg;
+
+    hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
+                                      data, 0, NULL);
+    if (!hThread) {
+        error_exit(GetLastError(), __func__);
+    }
+    CloseHandle(hThread);
+}
+
+void qemu_thread_get_self(QemuThread *thread)
+{
+    if (!thread->thread) {
+        /* In the main thread of the process.  Initialize the QemuThread
+           pointer in TLS, and use the dummy GetCurrentThread handle as
+           the identifier for qemu_thread_is_self.  */
+        qemu_thread_init();
+        TlsSetValue(qemu_thread_tls_index, thread);
+        thread->thread = GetCurrentThread();
+    }
+}
+
+int qemu_thread_is_self(QemuThread *thread)
+{
+    QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index);
+    return this_thread->thread == thread->thread;
+}
diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h
new file mode 100644 (file)
index 0000000..878f86a
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __QEMU_THREAD_WIN32_H
+#define __QEMU_THREAD_WIN32_H 1
+#include "windows.h"
+
+struct QemuMutex {
+    CRITICAL_SECTION lock;
+    LONG owner;
+};
+
+struct QemuCond {
+    LONG waiters, target;
+    HANDLE sema;
+    HANDLE continue_event;
+};
+
+struct QemuThread {
+    HANDLE thread;
+    void *ret;
+};
+
+#endif
index 19bb30c9406c644f3c63d9fde21297c74c81bb03..e008b60028c8359f3fd57631034253362e2d79b0 100644 (file)
@@ -1,44 +1,44 @@
 #ifndef __QEMU_THREAD_H
 #define __QEMU_THREAD_H 1
-#include "semaphore.h"
-#include "pthread.h"
 
-struct QemuMutex {
-    pthread_mutex_t lock;
-};
-
-struct QemuCond {
-    pthread_cond_t cond;
-};
-
-struct QemuThread {
-    pthread_t thread;
-};
+#include <inttypes.h>
 
 typedef struct QemuMutex QemuMutex;
 typedef struct QemuCond QemuCond;
 typedef struct QemuThread QemuThread;
 
+#ifdef _WIN32
+#include "qemu-thread-win32.h"
+#else
+#include "qemu-thread-posix.h"
+#endif
+
 void qemu_mutex_init(QemuMutex *mutex);
 void qemu_mutex_destroy(QemuMutex *mutex);
 void qemu_mutex_lock(QemuMutex *mutex);
 int qemu_mutex_trylock(QemuMutex *mutex);
-int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs);
 void qemu_mutex_unlock(QemuMutex *mutex);
 
+#define rcu_read_lock() do { } while (0)
+#define rcu_read_unlock() do { } while (0)
+
 void qemu_cond_init(QemuCond *cond);
 void qemu_cond_destroy(QemuCond *cond);
+
+/*
+ * IMPORTANT: The implementation does not guarantee that pthread_cond_signal
+ * and pthread_cond_broadcast can be called except while the same mutex is
+ * held as in the corresponding pthread_cond_wait calls!
+ */
 void qemu_cond_signal(QemuCond *cond);
 void qemu_cond_broadcast(QemuCond *cond);
 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
-int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs);
 
 void qemu_thread_create(QemuThread *thread,
                        void *(*start_routine)(void*),
                        void *arg);
-void qemu_thread_signal(QemuThread *thread, int sig);
-void qemu_thread_self(QemuThread *thread);
-int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2);
+void qemu_thread_get_self(QemuThread *thread);
+int qemu_thread_is_self(QemuThread *thread);
 void qemu_thread_exit(void *retval);
 
 #endif
index b0db780a1e6de35d77e0ca32e56b6958706006f7..cd026c6495fd8b0d0f91e1468c0177701ca69572 100644 (file)
 #include <sys/param.h>
 #endif
 
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/rtc.h>
-/* For the benefit of older linux systems which don't supply it,
-   we use a local copy of hpet.h. */
-/* #include <linux/hpet.h> */
-#include "hpet.h"
-#endif
-
 #ifdef _WIN32
 #include <windows.h>
 #include <mmsystem.h>
 
 #include "qemu-timer.h"
 
-/* Conversion factor from emulated instructions to virtual clock ticks.  */
-int icount_time_shift;
-/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
-#define MAX_ICOUNT_SHIFT 10
-/* Compensate for varying guest execution speed.  */
-int64_t qemu_icount_bias;
-static QEMUTimer *icount_rt_timer;
-static QEMUTimer *icount_vm_timer;
-
-/***********************************************************/
-/* guest cycle counter */
-
-typedef struct TimersState {
-    int64_t cpu_ticks_prev;
-    int64_t cpu_ticks_offset;
-    int64_t cpu_clock_offset;
-    int32_t cpu_ticks_enabled;
-    int64_t dummy;
-} TimersState;
-
-TimersState timers_state;
-
-/* return the host CPU cycle counter and handle stop/restart */
-int64_t cpu_get_ticks(void)
-{
-    if (use_icount) {
-        return cpu_get_icount();
-    }
-    if (!timers_state.cpu_ticks_enabled) {
-        return timers_state.cpu_ticks_offset;
-    } else {
-        int64_t ticks;
-        ticks = cpu_get_real_ticks();
-        if (timers_state.cpu_ticks_prev > ticks) {
-            /* Note: non increasing ticks may happen if the host uses
-               software suspend */
-            timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
-        }
-        timers_state.cpu_ticks_prev = ticks;
-        return ticks + timers_state.cpu_ticks_offset;
-    }
-}
-
-/* return the host CPU monotonic timer and handle stop/restart */
-static int64_t cpu_get_clock(void)
-{
-    int64_t ti;
-    if (!timers_state.cpu_ticks_enabled) {
-        return timers_state.cpu_clock_offset;
-    } else {
-        ti = get_clock();
-        return ti + timers_state.cpu_clock_offset;
-    }
-}
-
-static int64_t qemu_icount_delta(void)
-{
-    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.  */
-        return 0;
-    } else {
-        return cpu_get_icount() - cpu_get_clock();
-    }
-}
-
-/* enable cpu_get_ticks() */
-void cpu_enable_ticks(void)
-{
-    if (!timers_state.cpu_ticks_enabled) {
-        timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
-        timers_state.cpu_clock_offset -= get_clock();
-        timers_state.cpu_ticks_enabled = 1;
-    }
-}
-
-/* disable cpu_get_ticks() : the clock is stopped. You must not call
-   cpu_get_ticks() after that.  */
-void cpu_disable_ticks(void)
-{
-    if (timers_state.cpu_ticks_enabled) {
-        timers_state.cpu_ticks_offset = cpu_get_ticks();
-        timers_state.cpu_clock_offset = cpu_get_clock();
-        timers_state.cpu_ticks_enabled = 0;
-    }
-}
-
 /***********************************************************/
 /* timers */
 
@@ -155,12 +56,17 @@ void cpu_disable_ticks(void)
 struct QEMUClock {
     int type;
     int enabled;
-    /* XXX: add frequency */
+
+    QEMUTimer *active_timers;
+
+    NotifierList reset_notifiers;
+    int64_t last;
 };
 
 struct QEMUTimer {
     QEMUClock *clock;
-    int64_t expire_time;
+    int64_t expire_time;       /* in nanoseconds */
+    int scale;
     QEMUTimerCB *cb;
     void *opaque;
     struct QEMUTimer *next;
@@ -170,15 +76,24 @@ struct qemu_alarm_timer {
     char const *name;
     int (*start)(struct qemu_alarm_timer *t);
     void (*stop)(struct qemu_alarm_timer *t);
-    void (*rearm)(struct qemu_alarm_timer *t);
-    void *priv;
-
+    void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns);
+#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;
@@ -189,12 +104,46 @@ static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
     return !!t->rearm;
 }
 
+static int64_t qemu_next_alarm_deadline(void)
+{
+    int64_t delta;
+    int64_t rtdelta;
+
+    if (!use_icount && vm_clock->active_timers) {
+        delta = vm_clock->active_timers->expire_time -
+                     qemu_get_clock_ns(vm_clock);
+    } else {
+        delta = INT32_MAX;
+    }
+    if (host_clock->active_timers) {
+        int64_t hdelta = host_clock->active_timers->expire_time -
+                 qemu_get_clock_ns(host_clock);
+        if (hdelta < delta) {
+            delta = hdelta;
+        }
+    }
+    if (rt_clock->active_timers) {
+        rtdelta = (rt_clock->active_timers->expire_time -
+                 qemu_get_clock_ns(rt_clock));
+        if (rtdelta < delta) {
+            delta = rtdelta;
+        }
+    }
+
+    return delta;
+}
+
 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 {
-    if (!alarm_has_dynticks(t))
+    int64_t nearest_delta_ns;
+    assert(alarm_has_dynticks(t));
+    if (!rt_clock->active_timers &&
+        !vm_clock->active_timers &&
+        !host_clock->active_timers) {
         return;
-
-    t->rearm(t);
+    }
+    nearest_delta_ns = qemu_next_alarm_deadline();
+    t->rearm(t, nearest_delta_ns);
 }
 
 /* TODO: MIN_TIMER_REARM_NS should be optimized */
@@ -202,107 +151,40 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 
 #ifdef _WIN32
 
-struct qemu_alarm_win32 {
-    MMRESULT timerId;
-    unsigned int period;
-} alarm_win32_data = {0, 0};
+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, int64_t delta);
 
 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);
+static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #else
 
 static int unix_start_timer(struct qemu_alarm_timer *t);
 static void unix_stop_timer(struct qemu_alarm_timer *t);
+static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #ifdef __linux__
 
 static int dynticks_start_timer(struct qemu_alarm_timer *t);
 static void dynticks_stop_timer(struct qemu_alarm_timer *t);
-static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
-
-static int hpet_start_timer(struct qemu_alarm_timer *t);
-static void hpet_stop_timer(struct qemu_alarm_timer *t);
-
-static int rtc_start_timer(struct qemu_alarm_timer *t);
-static void rtc_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #endif /* __linux__ */
 
 #endif /* _WIN32 */
 
-/* Correlation between real and virtual time is always going to be
-   fairly approximate, so ignore small variation.
-   When the guest is idle real and virtual time will be aligned in
-   the IO wait loop.  */
-#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
-
-static void icount_adjust(void)
-{
-    int64_t cur_time;
-    int64_t cur_icount;
-    int64_t delta;
-    static int64_t last_delta;
-    /* If the VM is not running, then do nothing.  */
-    if (!vm_running)
-        return;
-
-    cur_time = cpu_get_clock();
-    cur_icount = qemu_get_clock(vm_clock);
-    delta = cur_icount - cur_time;
-    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
-    if (delta > 0
-        && last_delta + ICOUNT_WOBBLE < delta * 2
-        && icount_time_shift > 0) {
-        /* The guest is getting too far ahead.  Slow time down.  */
-        icount_time_shift--;
-    }
-    if (delta < 0
-        && last_delta - ICOUNT_WOBBLE > delta * 2
-        && icount_time_shift < MAX_ICOUNT_SHIFT) {
-        /* The guest is getting too far behind.  Speed time up.  */
-        icount_time_shift++;
-    }
-    last_delta = delta;
-    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
-}
-
-static void icount_adjust_rt(void * opaque)
-{
-    qemu_mod_timer(icount_rt_timer,
-                   qemu_get_clock(rt_clock) + 1000);
-    icount_adjust();
-}
-
-static void icount_adjust_vm(void * opaque)
-{
-    qemu_mod_timer(icount_vm_timer,
-                   qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10);
-    icount_adjust();
-}
-
-int64_t qemu_icount_round(int64_t count)
-{
-    return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
-}
-
 static struct qemu_alarm_timer alarm_timers[] = {
 #ifndef _WIN32
 #ifdef __linux__
     {"dynticks", dynticks_start_timer,
-     dynticks_stop_timer, dynticks_rearm_timer, NULL},
-    /* HPET - if available - is preferred */
-    {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL},
-    /* ...otherwise try RTC */
-    {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL},
+     dynticks_stop_timer, dynticks_rearm_timer},
 #endif
-    {"unix", unix_start_timer, unix_stop_timer, NULL, NULL},
+    {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer},
 #else
-    {"dynticks", win32_start_timer,
-     win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
-    {"win32", win32_start_timer,
-     win32_stop_timer, NULL, &alarm_win32_data},
+    {"mmtimer", mm_start_timer, mm_stop_timer, mm_rearm_timer},
+    {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer},
 #endif
     {NULL, }
 };
@@ -330,7 +212,7 @@ void configure_alarms(char const *opt)
         exit(0);
     }
 
-    arg = qemu_strdup(opt);
+    arg = g_strdup(opt);
 
     /* Reorder the array */
     name = strtok(arg, ",");
@@ -359,7 +241,7 @@ next:
         name = strtok(NULL, ",");
     }
 
-    qemu_free(arg);
+    g_free(arg);
 
     if (cur) {
         /* Disable remaining timers */
@@ -371,42 +253,72 @@ next:
     }
 }
 
-#define QEMU_NUM_CLOCKS 3
-
 QEMUClock *rt_clock;
 QEMUClock *vm_clock;
 QEMUClock *host_clock;
 
-static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
-
 static QEMUClock *qemu_new_clock(int type)
 {
     QEMUClock *clock;
-    clock = qemu_mallocz(sizeof(QEMUClock));
+
+    clock = g_malloc0(sizeof(QEMUClock));
     clock->type = type;
     clock->enabled = 1;
+    clock->last = INT64_MIN;
+    notifier_list_init(&clock->reset_notifiers);
     return clock;
 }
 
 void qemu_clock_enable(QEMUClock *clock, int enabled)
 {
+    bool old = clock->enabled;
     clock->enabled = enabled;
+    if (enabled && !old) {
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
 }
 
-QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
+int64_t qemu_clock_has_timers(QEMUClock *clock)
+{
+    return !!clock->active_timers;
+}
+
+int64_t qemu_clock_expired(QEMUClock *clock)
+{
+    return (clock->active_timers &&
+            clock->active_timers->expire_time < qemu_get_clock_ns(clock));
+}
+
+int64_t qemu_clock_deadline(QEMUClock *clock)
+{
+    /* To avoid problems with overflow limit this to 2^32.  */
+    int64_t delta = INT32_MAX;
+
+    if (clock->active_timers) {
+        delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock);
+    }
+    if (delta < 0) {
+        delta = 0;
+    }
+    return delta;
+}
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque)
 {
     QEMUTimer *ts;
 
-    ts = qemu_mallocz(sizeof(QEMUTimer));
+    ts = g_malloc0(sizeof(QEMUTimer));
     ts->clock = clock;
     ts->cb = cb;
     ts->opaque = opaque;
+    ts->scale = scale;
     return ts;
 }
 
 void qemu_free_timer(QEMUTimer *ts)
 {
-    qemu_free(ts);
+    g_free(ts);
 }
 
 /* stop a timer, but do not dealloc it */
@@ -416,7 +328,7 @@ void qemu_del_timer(QEMUTimer *ts)
 
     /* NOTE: this code must be signal safe because
        qemu_timer_expired() can be called from a signal. */
-    pt = &active_timers[ts->clock->type];
+    pt = &ts->clock->active_timers;
     for(;;) {
         t = *pt;
         if (!t)
@@ -431,7 +343,7 @@ void qemu_del_timer(QEMUTimer *ts)
 
 /* modify the current timer so that it will be fired when current_time
    >= expire_time. The corresponding callback will be called. */
-void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
 {
     QEMUTimer **pt, *t;
 
@@ -440,13 +352,12 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
     /* add the timer in the sorted list */
     /* NOTE: this code must be signal safe because
        qemu_timer_expired() can be called from a signal. */
-    pt = &active_timers[ts->clock->type];
+    pt = &ts->clock->active_timers;
     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,20 +365,27 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
     *pt = ts;
 
     /* Rearm if necessary  */
-    if (pt == &active_timers[ts->clock->type]) {
+    if (pt == &ts->clock->active_timers) {
         if (!alarm_timer->pending) {
             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();
+        }
     }
 }
 
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+{
+    qemu_mod_timer_ns(ts, expire_time * ts->scale);
+}
+
 int qemu_timer_pending(QEMUTimer *ts)
 {
     QEMUTimer *t;
-    for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+    for (t = ts->clock->active_timers; t != NULL; t = t->next) {
         if (t == ts)
             return 1;
     }
@@ -476,9 +394,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);
+    return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
 }
 
 static void qemu_run_timers(QEMUClock *clock)
@@ -489,12 +405,13 @@ static void qemu_run_timers(QEMUClock *clock)
     if (!clock->enabled)
         return;
 
-    current_time = qemu_get_clock (clock);
-    ptimer_head = &active_timers[clock->type];
+    current_time = qemu_get_clock_ns(clock);
+    ptimer_head = &clock->active_timers;
     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;
@@ -504,25 +421,10 @@ static void qemu_run_timers(QEMUClock *clock)
     }
 }
 
-int64_t qemu_get_clock(QEMUClock *clock)
-{
-    switch(clock->type) {
-    case QEMU_CLOCK_REALTIME:
-        return get_clock() / 1000000;
-    default:
-    case QEMU_CLOCK_VIRTUAL:
-        if (use_icount) {
-            return cpu_get_icount();
-        } else {
-            return cpu_get_clock();
-        }
-    case QEMU_CLOCK_HOST:
-        return get_clock_realtime();
-    }
-}
-
 int64_t qemu_get_clock_ns(QEMUClock *clock)
 {
+    int64_t now, last;
+
     switch(clock->type) {
     case QEMU_CLOCK_REALTIME:
         return get_clock();
@@ -534,86 +436,36 @@ int64_t qemu_get_clock_ns(QEMUClock *clock)
             return cpu_get_clock();
         }
     case QEMU_CLOCK_HOST:
-        return get_clock_realtime();
+        now = get_clock_realtime();
+        last = clock->last;
+        clock->last = now;
+        if (now < last) {
+            notifier_list_notify(&clock->reset_notifiers, &now);
+        }
+        return now;
     }
 }
 
-void init_clocks(void)
+void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 {
-    rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
-    vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
-    host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
-
-    rtc_clock = host_clock;
+    notifier_list_add(&clock->reset_notifiers, notifier);
 }
 
-/* save a timer */
-void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 {
-    uint64_t expire_time;
-
-    if (qemu_timer_pending(ts)) {
-        expire_time = ts->expire_time;
-    } else {
-        expire_time = -1;
-    }
-    qemu_put_be64(f, expire_time);
+    notifier_list_remove(&clock->reset_notifiers, notifier);
 }
 
-void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+void init_clocks(void)
 {
-    uint64_t expire_time;
-
-    expire_time = qemu_get_be64(f);
-    if (expire_time != -1) {
-        qemu_mod_timer(ts, expire_time);
-    } else {
-        qemu_del_timer(ts);
-    }
+    rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
+    vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
+    host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
 }
 
-static const VMStateDescription vmstate_timers = {
-    .name = "timer",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT64(cpu_ticks_offset, TimersState),
-        VMSTATE_INT64(dummy, TimersState),
-        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void configure_icount(const char *option)
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
 {
-    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
-    if (!option)
-        return;
-
-    if (strcmp(option, "auto") != 0) {
-        icount_time_shift = strtol(option, NULL, 0);
-        use_icount = 1;
-        return;
-    }
-
-    use_icount = 2;
-
-    /* 125MIPS seems a reasonable initial guess at the guest speed.
-       It will be corrected fairly quickly anyway.  */
-    icount_time_shift = 3;
-
-    /* Have both realtime and virtual time triggers for speed adjustment.
-       The realtime trigger catches emulated time passing too slowly,
-       the virtual time trigger catches emulated time passing too fast.
-       Realtime triggers occur even when idle, so use them less frequently
-       than VM triggers.  */
-    icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);
-    qemu_mod_timer(icount_rt_timer,
-                   qemu_get_clock(rt_clock) + 1000);
-    icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
-    qemu_mod_timer(icount_vm_timer,
-                   qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10);
+    return qemu_timer_pending(ts) ? ts->expire_time : -1;
 }
 
 void qemu_run_all_timers(void)
@@ -627,20 +479,13 @@ void qemu_run_all_timers(void)
     }
 
     /* vm time timers */
-    if (vm_running) {
-        qemu_run_timers(vm_clock);
-    }
-
+    qemu_run_timers(vm_clock);
     qemu_run_timers(rt_clock);
     qemu_run_timers(host_clock);
 }
 
-static int64_t qemu_next_alarm_deadline(void);
-
 #ifdef _WIN32
-static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
-                                        DWORD_PTR dwUser, DWORD_PTR dw1,
-                                        DWORD_PTR dw2)
+static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused)
 #else
 static void host_alarm_handler(int host_signum)
 #endif
@@ -655,7 +500,7 @@ static void host_alarm_handler(int host_signum)
         static int64_t delta_min = INT64_MAX;
         static int64_t delta_max, delta_cum, last_clock, delta, ti;
         static int count;
-        ti = qemu_get_clock(vm_clock);
+        ti = qemu_get_clock_ns(vm_clock);
         if (last_clock != 0) {
             delta = ti - last_clock;
             if (delta < delta_min)
@@ -686,157 +531,9 @@ static void host_alarm_handler(int host_signum)
     }
 }
 
-int64_t qemu_next_deadline(void)
-{
-    /* To avoid problems with overflow limit this to 2^32.  */
-    int64_t delta = INT32_MAX;
-
-    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;
-
-    return delta;
-}
-
-static int64_t qemu_next_alarm_deadline(void)
-{
-    int64_t delta;
-    int64_t rtdelta;
-
-    if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
-        delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
-                     qemu_get_clock(vm_clock);
-    } else {
-        delta = INT32_MAX;
-    }
-    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 (active_timers[QEMU_CLOCK_REALTIME]) {
-        rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time * 1000000 -
-                 qemu_get_clock_ns(rt_clock));
-        if (rtdelta < delta)
-            delta = rtdelta;
-    }
-
-    return delta;
-}
-
 #if defined(__linux__)
 
-#define RTC_FREQ 1024
-
-static void enable_sigio_timer(int fd)
-{
-    struct sigaction act;
-
-    /* timer signal */
-    sigfillset(&act.sa_mask);
-    act.sa_flags = 0;
-    act.sa_handler = host_alarm_handler;
-
-    sigaction(SIGIO, &act, NULL);
-    fcntl_setfl(fd, O_ASYNC);
-    fcntl(fd, F_SETOWN, getpid());
-}
-
-static int hpet_start_timer(struct qemu_alarm_timer *t)
-{
-    struct hpet_info info;
-    int r, fd;
-
-    fd = qemu_open("/dev/hpet", O_RDONLY);
-    if (fd < 0)
-        return -1;
-
-    /* Set frequency */
-    r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
-    if (r < 0) {
-        fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
-                "error, but for better emulation accuracy type:\n"
-                "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
-        goto fail;
-    }
-
-    /* Check capabilities */
-    r = ioctl(fd, HPET_INFO, &info);
-    if (r < 0)
-        goto fail;
-
-    /* Enable periodic mode */
-    r = ioctl(fd, HPET_EPI, 0);
-    if (info.hi_flags && (r < 0))
-        goto fail;
-
-    /* Enable interrupt */
-    r = ioctl(fd, HPET_IE_ON, 0);
-    if (r < 0)
-        goto fail;
-
-    enable_sigio_timer(fd);
-    t->priv = (void *)(long)fd;
-
-    return 0;
-fail:
-    close(fd);
-    return -1;
-}
-
-static void hpet_stop_timer(struct qemu_alarm_timer *t)
-{
-    int fd = (long)t->priv;
-
-    close(fd);
-}
-
-static int rtc_start_timer(struct qemu_alarm_timer *t)
-{
-    int rtc_fd;
-    unsigned long current_rtc_freq = 0;
-
-    TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY));
-    if (rtc_fd < 0)
-        return -1;
-    ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
-    if (current_rtc_freq != RTC_FREQ &&
-        ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
-        fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
-                "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
-                "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
-        goto fail;
-    }
-    if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
-    fail:
-        close(rtc_fd);
-        return -1;
-    }
-
-    enable_sigio_timer(rtc_fd);
-
-    t->priv = (void *)(long)rtc_fd;
-
-    return 0;
-}
-
-static void rtc_stop_timer(struct qemu_alarm_timer *t)
-{
-    int rtc_fd = (long)t->priv;
-
-    close(rtc_fd);
-}
+#include "compatfd.h"
 
 static int dynticks_start_timer(struct qemu_alarm_timer *t)
 {
@@ -857,6 +554,12 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t)
     memset(&ev, 0, sizeof(ev));
     ev.sigev_value.sival_int = 0;
     ev.sigev_notify = SIGEV_SIGNAL;
+#ifdef SIGEV_THREAD_ID
+    if (qemu_signalfd_available()) {
+        ev.sigev_notify = SIGEV_THREAD_ID;
+        ev._sigev_un._tid = qemu_get_thread_id();
+    }
+#endif /* SIGEV_THREAD_ID */
     ev.sigev_signo = SIGALRM;
 
     if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
@@ -868,32 +571,25 @@ 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)
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t,
+                                 int64_t nearest_delta_ns)
 {
-    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;
 
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST])
-        return;
-
-    nearest_delta_ns = qemu_next_alarm_deadline();
     if (nearest_delta_ns < MIN_TIMER_REARM_NS)
         nearest_delta_ns = MIN_TIMER_REARM_NS;
 
@@ -925,8 +621,6 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
 static int unix_start_timer(struct qemu_alarm_timer *t)
 {
     struct sigaction act;
-    struct itimerval itv;
-    int err;
 
     /* timer signal */
     sigfillset(&act.sa_mask);
@@ -934,18 +628,28 @@ static int unix_start_timer(struct qemu_alarm_timer *t)
     act.sa_handler = host_alarm_handler;
 
     sigaction(SIGALRM, &act, NULL);
+    return 0;
+}
 
-    itv.it_interval.tv_sec = 0;
-    /* for i386 kernel 2.6 to get 1 ms */
-    itv.it_interval.tv_usec = 999;
-    itv.it_value.tv_sec = 0;
-    itv.it_value.tv_usec = 10 * 1000;
+static void unix_rearm_timer(struct qemu_alarm_timer *t,
+                             int64_t nearest_delta_ns)
+{
+    struct itimerval itv;
+    int err;
 
-    err = setitimer(ITIMER_REAL, &itv, NULL);
-    if (err)
-        return -1;
+    if (nearest_delta_ns < MIN_TIMER_REARM_NS)
+        nearest_delta_ns = MIN_TIMER_REARM_NS;
 
-    return 0;
+    itv.it_interval.tv_sec = 0;
+    itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */
+    itv.it_value.tv_sec =  nearest_delta_ns / 1000000000;
+    itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000;
+    err = setitimer(ITIMER_REAL, &itv, NULL);
+    if (err) {
+        perror("setitimer");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
 }
 
 static void unix_stop_timer(struct qemu_alarm_timer *t)
@@ -961,81 +665,154 @@ static void unix_stop_timer(struct qemu_alarm_timer *t)
 
 #ifdef _WIN32
 
-static int win32_start_timer(struct qemu_alarm_timer *t)
+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;
-    struct qemu_alarm_win32 *data = t->priv;
     UINT flags;
 
     memset(&tc, 0, sizeof(tc));
     timeGetDevCaps(&tc, sizeof(tc));
 
-    data->period = tc.wPeriodMin;
-    timeBeginPeriod(data->period);
+    mm_period = tc.wPeriodMin;
+    timeBeginPeriod(mm_period);
 
     flags = TIME_CALLBACK_FUNCTION;
-    if (alarm_has_dynticks(t))
+    if (alarm_has_dynticks(t)) {
         flags |= TIME_ONESHOT;
-    else
+    } else {
         flags |= TIME_PERIODIC;
+    }
 
-    data->timerId = timeSetEvent(1,         // interval (ms)
-                        data->period,       // resolution
-                        host_alarm_handler, // function
-                        (DWORD)t,           // parameter
-                        flags);
+    mm_timer = timeSetEvent(1,                  /* interval (ms) */
+                            mm_period,          /* resolution */
+                            mm_alarm_handler,   /* function */
+                            (DWORD_PTR)t,       /* parameter */
+                            flags);
 
-    if (!data->timerId) {
+    if (!mm_timer) {
         fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
                 GetLastError());
-        timeEndPeriod(data->period);
+        timeEndPeriod(mm_period);
         return -1;
     }
 
     return 0;
 }
 
-static void win32_stop_timer(struct qemu_alarm_timer *t)
+static void mm_stop_timer(struct qemu_alarm_timer *t)
 {
-    struct qemu_alarm_win32 *data = t->priv;
-
-    timeKillEvent(data->timerId);
-    timeEndPeriod(data->period);
+    timeKillEvent(mm_timer);
+    timeEndPeriod(mm_period);
 }
 
-static void win32_rearm_timer(struct qemu_alarm_timer *t)
+static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
 {
-    struct qemu_alarm_win32 *data = t->priv;
-
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST])
-        return;
-
-    timeKillEvent(data->timerId);
+    int nearest_delta_ms = (delta + 999999) / 1000000;
+    if (nearest_delta_ms < 1) {
+        nearest_delta_ms = 1;
+    }
 
-    data->timerId = timeSetEvent(1,
-                        data->period,
-                        host_alarm_handler,
-                        (DWORD)t,
-                        TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
+    timeKillEvent(mm_timer);
+    mm_timer = timeSetEvent(nearest_delta_ms,
+                            mm_period,
+                            mm_alarm_handler,
+                            (DWORD_PTR)t,
+                            TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
 
-    if (!data->timerId) {
+    if (!mm_timer) {
         fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
                 GetLastError());
 
-        timeEndPeriod(data->period);
+        timeEndPeriod(mm_period);
         exit(1);
     }
 }
 
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+    HANDLE hTimer;
+    BOOLEAN success;
+
+    /* If you call ChangeTimerQueueTimer on a one-shot timer (its period
+       is zero) that has already expired, the timer is not updated.  Since
+       creating a new timer is relatively expensive, set a bogus one-hour
+       interval in the dynticks case.  */
+    success = CreateTimerQueueTimer(&hTimer,
+                          NULL,
+                          host_alarm_handler,
+                          t,
+                          1,
+                          alarm_has_dynticks(t) ? 3600000 : 1,
+                          WT_EXECUTEINTIMERTHREAD);
+
+    if (!success) {
+        fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
+                GetLastError());
+        return -1;
+    }
+
+    t->timer = hTimer;
+    return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+    HANDLE hTimer = t->timer;
+
+    if (hTimer) {
+        DeleteTimerQueueTimer(NULL, hTimer, NULL);
+    }
+}
+
+static void win32_rearm_timer(struct qemu_alarm_timer *t,
+                              int64_t nearest_delta_ns)
+{
+    HANDLE hTimer = t->timer;
+    int nearest_delta_ms;
+    BOOLEAN success;
+
+    nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
+    if (nearest_delta_ms < 1) {
+        nearest_delta_ms = 1;
+    }
+    success = ChangeTimerQueueTimer(NULL,
+                                    hTimer,
+                                    nearest_delta_ms,
+                                    3600000);
+
+    if (!success) {
+        fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n",
+                GetLastError());
+        exit(-1);
+    }
+
+}
+
 #endif /* _WIN32 */
 
-static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)
+static void quit_timers(void)
 {
-    if (running)
-        qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
+    struct qemu_alarm_timer *t = alarm_timer;
+    alarm_timer = NULL;
+    t->stop(t);
 }
 
 int init_timer_alarm(void)
@@ -1057,9 +834,9 @@ int init_timer_alarm(void)
     }
 
     /* first event is at time 0 */
+    atexit(quit_timers);
     t->pending = 1;
     alarm_timer = t;
-    qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t);
 
     return 0;
 
@@ -1067,55 +844,8 @@ fail:
     return err;
 }
 
-void quit_timers(void)
-{
-    struct qemu_alarm_timer *t = alarm_timer;
-    alarm_timer = NULL;
-    t->stop(t);
-}
-
 int qemu_calculate_timeout(void)
 {
-    int timeout;
-
-#ifdef CONFIG_IOTHREAD
-    /* 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) {
-        return 1000;
-    }
-#endif
-
-    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_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;
+    return 1000;
 }
 
index 8cd8f8368ad50c1802bf9b05a59f008370f54af3..67ca72e045cec2bd1d23e3d62e583507143c8761 100644 (file)
@@ -2,16 +2,21 @@
 #define QEMU_TIMER_H
 
 #include "qemu-common.h"
+#include "main-loop.h"
+#include "notify.h"
 #include <time.h>
 #include <sys/time.h>
 
 #ifdef _WIN32
 #include <windows.h>
-#include <mmsystem.h>
 #endif
 
 /* timers */
 
+#define SCALE_MS 1000000
+#define SCALE_US 1000
+#define SCALE_NS 1
+
 typedef struct QEMUClock QEMUClock;
 typedef void QEMUTimerCB(void *opaque);
 
@@ -33,26 +38,54 @@ extern QEMUClock *vm_clock;
    the virtual clock. */
 extern QEMUClock *host_clock;
 
-int64_t qemu_get_clock(QEMUClock *clock);
 int64_t qemu_get_clock_ns(QEMUClock *clock);
+int64_t qemu_clock_has_timers(QEMUClock *clock);
+int64_t qemu_clock_expired(QEMUClock *clock);
+int64_t qemu_clock_deadline(QEMUClock *clock);
 void qemu_clock_enable(QEMUClock *clock, int enabled);
+void qemu_clock_warp(QEMUClock *clock);
+
+void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier);
+void qemu_unregister_clock_reset_notifier(QEMUClock *clock,
+                                          Notifier *notifier);
 
-QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque);
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque);
 void qemu_free_timer(QEMUTimer *ts);
 void qemu_del_timer(QEMUTimer *ts);
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
 int qemu_timer_pending(QEMUTimer *ts);
 int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
 
 void qemu_run_all_timers(void);
 int qemu_alarm_pending(void);
-int64_t qemu_next_deadline(void);
 void configure_alarms(char const *opt);
-void configure_icount(const char *option);
 int qemu_calculate_timeout(void);
 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)
+{
+    return qemu_new_timer(clock, SCALE_NS, cb, opaque);
+}
+
+static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb,
+                                           void *opaque)
+{
+    return qemu_new_timer(clock, SCALE_MS, cb, opaque);
+}
+
+static inline int64_t qemu_get_clock_ms(QEMUClock *clock)
+{
+    return qemu_get_clock_ns(clock) / SCALE_MS;
+}
 
 static inline int64_t get_ticks_per_sec(void)
 {
@@ -118,16 +151,10 @@ 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);
-extern int64_t qemu_icount;
-extern int use_icount;
-extern int icount_time_shift;
-extern int64_t qemu_icount_bias;
 int64_t cpu_get_icount(void);
+int64_t cpu_get_clock(void);
 
 /*******************************************/
 /* host CPU ticks (if available) */
@@ -283,22 +310,6 @@ static inline int64_t cpu_get_real_ticks (void)
 }
 #endif
 
-#ifdef NEED_CPU_H
-/* Deterministic execution requires that IO only be performed on the last
-   instruction of a TB so that interrupts take effect immediately.  */
-static inline int can_do_io(CPUState *env)
-{
-    if (!use_icount)
-        return 1;
-
-    /* If not executing code then assume we are ok.  */
-    if (!env->current_tb)
-        return 1;
-
-    return env->can_do_io != 0;
-}
-#endif
-
 #ifdef CONFIG_PROFILER
 static inline int64_t profile_getclock(void)
 {
diff --git a/qemu-tls.h b/qemu-tls.h
new file mode 100644 (file)
index 0000000..5b70f10
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Abstraction layer for defining and using TLS variables
+ *
+ * Copyright (c) 2011 Red Hat, Inc
+ * Copyright (c) 2011 Linaro Limited
+ *
+ * Authors:
+ *  Paolo Bonzini <pbonzini@redhat.com>
+ *  Peter Maydell <peter.maydell@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/>.
+ */
+
+#ifndef QEMU_TLS_H
+#define QEMU_TLS_H
+
+/* Per-thread variables. Note that we only have implementations
+ * which are really thread-local on Linux; the dummy implementations
+ * define plain global variables.
+ *
+ * This means that for the moment use should be restricted to
+ * per-VCPU variables, which are OK because:
+ *  - the only -user mode supporting multiple VCPU threads is linux-user
+ *  - TCG system mode is single-threaded regarding VCPUs
+ *  - KVM system mode is multi-threaded but limited to Linux
+ *
+ * TODO: proper implementations via Win32 .tls sections and
+ * POSIX pthread_getspecific.
+ */
+#ifdef __linux__
+#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x)
+#define DEFINE_TLS(type, x)  __thread __typeof__(type) tls__##x
+#define get_tls(x)           tls__##x
+#else
+/* Dummy implementations which define plain global variables */
+#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x)
+#define DEFINE_TLS(type, x)  __typeof__(type) tls__##x
+#define get_tls(x)           tls__##x
+#endif
+
+#endif
index 392e1c9505bc5dfdc17d3c00ce1d7989428972f1..5df72797452e81b2e4e7283f3032ac57b98d40da 100644 (file)
 #include "monitor.h"
 #include "qemu-timer.h"
 #include "qemu-log.h"
-#include "sysemu.h"
+#include "migration.h"
 
 #include <sys/time.h>
 
 QEMUClock *rt_clock;
+QEMUClock *vm_clock;
 
 FILE *logfile;
 
@@ -29,10 +30,6 @@ struct QEMUBH
     void *opaque;
 };
 
-void qemu_service_io(void)
-{
-}
-
 Monitor *cur_mon;
 
 int monitor_cur_is_qmp(void)
@@ -56,58 +53,51 @@ void monitor_print_filename(Monitor *mon, const char *filename)
 {
 }
 
-void async_context_push(void)
+void monitor_protocol_event(MonitorEvent event, QObject *data)
 {
 }
 
-void async_context_pop(void)
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
 {
+    return 0;
 }
 
-int get_async_context_id(void)
+void qemu_notify_event(void)
 {
-    return 0;
 }
 
-void monitor_protocol_event(MonitorEvent event, QObject *data)
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque)
 {
+    return g_malloc(1);
 }
 
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+void qemu_free_timer(QEMUTimer *ts)
 {
-    QEMUBH *bh;
-
-    bh = qemu_malloc(sizeof(*bh));
-    bh->cb = cb;
-    bh->opaque = opaque;
-
-    return bh;
+    g_free(ts);
 }
 
-int qemu_bh_poll(void)
+void qemu_del_timer(QEMUTimer *ts)
 {
-    return 0;
 }
 
-void qemu_bh_schedule(QEMUBH *bh)
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
 {
-    bh->cb(bh->opaque);
 }
 
-void qemu_bh_cancel(QEMUBH *bh)
+int64_t qemu_get_clock_ns(QEMUClock *clock)
 {
+    return 0;
 }
 
-void qemu_bh_delete(QEMUBH *bh)
+void migrate_add_blocker(Error *reason)
 {
-    qemu_free(bh);
 }
 
-int qemu_set_fd_handler2(int fd,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque)
+void migrate_del_blocker(Error *reason)
 {
-    return 0;
 }
diff --git a/qemu-xattr.h b/qemu-xattr.h
new file mode 100644 (file)
index 0000000..f910d96
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Host xattr.h abstraction
+ *
+ * Copyright 2011 Red Hat Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Avi Kivity <avi@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2, or any
+ * later version.  See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_XATTR_H
+#define QEMU_XATTR_H
+
+/*
+ * Modern distributions (e.g. Fedora 15, have no libattr.so, place attr.h
+ * in /usr/include/sys, and don't have ENOATTR.
+ */
+
+#include "config-host.h"
+
+#ifdef CONFIG_LIBATTR
+#  include <attr/xattr.h>
+#else
+#  define ENOATTR ENODATA
+#  include <sys/xattr.h>
+#endif
+
+#endif
index 2f33e646e6a8f93311c4566faf5712bf4f2b2fbc..9e32fac65106188186c4cf4d361a16047de416c6 100644 (file)
@@ -35,6 +35,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
 /* misc helpers */
 int qemu_socket(int domain, int type, int protocol);
 int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+void socket_set_block(int fd);
 void socket_set_nonblock(int fd);
 int send_all(int fd, const void *buf, int len1);
 
@@ -54,7 +55,6 @@ int unix_connect(const char *path);
 
 /* Old, ipv4 only bits.  Don't use for new code. */
 int parse_host_port(struct sockaddr_in *saddr, const char *str);
-int parse_host_src_port(struct sockaddr_in *haddr,
-                        struct sockaddr_in *saddr,
-                        const char *str);
+int socket_init(void);
+
 #endif /* QEMU_SOCKET_H */
index 485560418bd4284b83c9e2c9a1a5efb977e1a675..25bc91e5870f2ef51c2e932c1b91514fa3e849c4 100644 (file)
--- a/qerror.c
+++ b/qerror.c
@@ -48,6 +48,10 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
         .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
     },
+    {
+        .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+        .desc      = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
+    },
     {
         .error_fmt = QERR_BUS_NOT_FOUND,
         .desc      = "Bus '%(bus)' not found",
@@ -72,6 +76,10 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_DEVICE_IN_USE,
         .desc      = "Device '%(device)' is in use",
     },
+    {
+        .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+        .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+    },
     {
         .error_fmt = QERR_DEVICE_LOCKED,
         .desc      = "Device '%(device)' is locked",
@@ -116,6 +124,10 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_FD_NOT_SUPPLIED,
         .desc      = "No file descriptor supplied via SCM_RIGHTS",
     },
+    {
+        .error_fmt = QERR_FEATURE_DISABLED,
+        .desc      = "The feature '%(name)' is not enabled",
+    },
     {
         .error_fmt = QERR_INVALID_BLOCK_FORMAT,
         .desc      = "Invalid block format '%(name)'",
@@ -140,6 +152,11 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_JSON_PARSING,
         .desc      = "Invalid JSON syntax",
     },
+    {
+        .error_fmt = QERR_JSON_PARSE_ERROR,
+        .desc      = "JSON parse error, %(message)",
+
+    },
     {
         .error_fmt = QERR_KVM_MISSING_CAP,
         .desc      = "Using KVM without %(capability), %(feature) unavailable",
@@ -188,10 +205,18 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_QMP_EXTRA_MEMBER,
         .desc      = "QMP input object member '%(member)' is unexpected",
     },
+    {
+        .error_fmt = QERR_RESET_REQUIRED,
+        .desc      = "Resetting the Virtual Machine is required",
+    },
     {
         .error_fmt = QERR_SET_PASSWD_FAILED,
         .desc      = "Could not set password",
     },
+    {
+        .error_fmt = QERR_ADD_CLIENT_FAILED,
+        .desc      = "Could not add client",
+    },
     {
         .error_fmt = QERR_TOO_MANY_FILES,
         .desc      = "Too many open files",
@@ -200,15 +225,32 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_UNDEFINED_ERROR,
         .desc      = "An undefined error has ocurred",
     },
+    {
+        .error_fmt = QERR_UNSUPPORTED,
+        .desc      = "this feature or command is not currently supported",
+    },
     {
         .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
         .desc      = "'%(device)' uses a %(format) feature which is not "
                      "supported by this qemu version: %(feature)",
     },
+    {
+        .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
+        .desc      = "Migration is disabled when VirtFS export path '%(path)' "
+                     "is mounted in the guest using mount_tag '%(tag)'",
+    },
     {
         .error_fmt = QERR_VNC_SERVER_FAILED,
         .desc      = "Could not start VNC server on %(target)",
     },
+    {
+        .error_fmt = QERR_QGA_LOGGING_FAILED,
+        .desc      = "Guest agent failed to log non-optional log statement",
+    },
+    {
+        .error_fmt = QERR_QGA_COMMAND_FAILED,
+        .desc      = "Guest agent command failed, error was '%(message)'",
+    },
     {}
 };
 
@@ -221,7 +263,7 @@ QError *qerror_new(void)
 {
     QError *qerr;
 
-    qerr = qemu_mallocz(sizeof(*qerr));
+    qerr = g_malloc0(sizeof(*qerr));
     QOBJECT_INIT(qerr, &qerror_type);
 
     return qerr;
@@ -326,12 +368,14 @@ QError *qerror_from_info(const char *file, int linenr, const char *func,
     return qerr;
 }
 
-static void parse_error(const QError *qerror, int c)
+static void parse_error(const QErrorStringTable *entry, int c)
 {
-    qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
+    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
+    abort();
 }
 
-static const char *append_field(QString *outstr, const QError *qerror,
+static const char *append_field(QDict *error, QString *outstr,
+                                const QErrorStringTable *entry,
                                 const char *start)
 {
     QObject *obj;
@@ -340,23 +384,23 @@ static const char *append_field(QString *outstr, const QError *qerror,
     const char *end, *key;
 
     if (*start != '%')
-        parse_error(qerror, '%');
+        parse_error(entry, '%');
     start++;
     if (*start != '(')
-        parse_error(qerror, '(');
+        parse_error(entry, '(');
     start++;
 
     end = strchr(start, ')');
     if (!end)
-        parse_error(qerror, ')');
+        parse_error(entry, ')');
 
     key_qs = qstring_from_substr(start, 0, end - start - 1);
     key = qstring_get_str(key_qs);
 
-    qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
+    qdict = qobject_to_qdict(qdict_get(error, "data"));
     obj = qdict_get(qdict, key);
     if (!obj) {
-        qerror_abort(qerror, "key '%s' not found in QDict", key);
+        abort();
     }
 
     switch (qobject_type(obj)) {
@@ -367,41 +411,60 @@ static const char *append_field(QString *outstr, const QError *qerror,
             qstring_append_int(outstr, qdict_get_int(qdict, key));
             break;
         default:
-            qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
+            abort();
     }
 
     QDECREF(key_qs);
     return ++end;
 }
 
-/**
- * qerror_human(): Format QError data into human-readable string.
- *
- * Formats according to member 'desc' of the specified QError object.
- */
-QString *qerror_human(const QError *qerror)
+static QString *qerror_format_desc(QDict *error,
+                                   const QErrorStringTable *entry)
 {
-    const char *p;
     QString *qstring;
+    const char *p;
 
-    assert(qerror->entry != NULL);
+    assert(entry != NULL);
 
     qstring = qstring_new();
 
-    for (p = qerror->entry->desc; *p != '\0';) {
+    for (p = entry->desc; *p != '\0';) {
         if (*p != '%') {
             qstring_append_chr(qstring, *p++);
         } else if (*(p + 1) == '%') {
             qstring_append_chr(qstring, '%');
             p += 2;
         } else {
-            p = append_field(qstring, qerror, p);
+            p = append_field(error, qstring, entry, p);
         }
     }
 
     return qstring;
 }
 
+QString *qerror_format(const char *fmt, QDict *error)
+{
+    const QErrorStringTable *entry = NULL;
+    int i;
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+            entry = &qerror_table[i];
+            break;
+        }
+    }
+
+    return qerror_format_desc(error, entry);
+}
+
+/**
+ * qerror_human(): Format QError data into human-readable string.
+ */
+QString *qerror_human(const QError *qerror)
+{
+    return qerror_format_desc(qerror->error, qerror->entry);
+}
+
 /**
  * qerror_print(): Print QError data
  *
@@ -436,6 +499,39 @@ void qerror_report_internal(const char *file, int linenr, const char *func,
     }
 }
 
+/* Evil... */
+struct Error
+{
+    QDict *obj;
+    const char *fmt;
+    char *msg;
+};
+
+void qerror_report_err(Error *err)
+{
+    QError *qerr;
+    int i;
+
+    qerr = qerror_new();
+    loc_save(&qerr->loc);
+    QINCREF(err->obj);
+    qerr->error = err->obj;
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
+            qerr->entry = &qerror_table[i];
+            break;
+        }
+    }
+
+    if (monitor_cur_is_qmp()) {
+        monitor_set_error(cur_mon, qerr);
+    } else {
+        qerror_print(qerr);
+        QDECREF(qerr);
+    }
+}
+
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
@@ -459,5 +555,5 @@ static void qerror_destroy_obj(QObject *obj)
     qerr = qobject_to_qerror(obj);
 
     QDECREF(qerr->error);
-    qemu_free(qerr);
+    g_free(qerr);
 }
index f732d45e80bd0092d7c2fd3df6cc0c129f4dc3a2..6414cd9d5b8111c5a588ac2152ff774de3ac10d1 100644 (file)
--- a/qerror.h
+++ b/qerror.h
@@ -15,6 +15,7 @@
 #include "qdict.h"
 #include "qstring.h"
 #include "qemu-error.h"
+#include "error.h"
 #include <stdarg.h>
 
 typedef struct QErrorStringTable {
@@ -39,6 +40,8 @@ QString *qerror_human(const QError *qerror);
 void qerror_print(QError *qerror);
 void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+void qerror_report_err(Error *err);
+QString *qerror_format(const char *fmt, QDict *error);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
 QError *qobject_to_qerror(const QObject *obj);
@@ -51,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_BAD_BUS_FOR_DEVICE \
     "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
+#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
+    "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+
 #define QERR_BUS_NOT_FOUND \
     "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
 
@@ -69,6 +75,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_DEVICE_IN_USE \
     "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
 
+#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
+    "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+
 #define QERR_DEVICE_LOCKED \
     "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
 
@@ -120,6 +129,12 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_JSON_PARSING \
     "{ 'class': 'JSONParsing', 'data': {} }"
 
+#define QERR_JSON_PARSE_ERROR \
+    "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+
+#define QERR_BUFFER_OVERRUN \
+    "{ 'class': 'BufferOverrun', 'data': {} }"
+
 #define QERR_KVM_MISSING_CAP \
     "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
@@ -156,19 +171,40 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_QMP_EXTRA_MEMBER \
     "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
 
+#define QERR_RESET_REQUIRED \
+    "{ 'class': 'ResetRequired', 'data': {} }"
+
 #define QERR_SET_PASSWD_FAILED \
     "{ 'class': 'SetPasswdFailed', 'data': {} }"
 
+#define QERR_ADD_CLIENT_FAILED \
+    "{ 'class': 'AddClientFailed', 'data': {} }"
+
 #define QERR_TOO_MANY_FILES \
     "{ 'class': 'TooManyFiles', 'data': {} }"
 
 #define QERR_UNDEFINED_ERROR \
     "{ 'class': 'UndefinedError', 'data': {} }"
 
+#define QERR_UNSUPPORTED \
+    "{ 'class': 'Unsupported', 'data': {} }"
+
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
     "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
 
+#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
+    "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+
 #define QERR_VNC_SERVER_FAILED \
     "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
+#define QERR_FEATURE_DISABLED \
+    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
+#define QERR_QGA_LOGGING_FAILED \
+    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+
+#define QERR_QGA_COMMAND_FAILED \
+    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+
 #endif /* QERROR_H */
index f8c8a2eb21afc1b6512bdec7b262caf1382a6c4f..98338f3b71a442971e5a69e5d85f78c80194ff85 100644 (file)
--- a/qfloat.c
+++ b/qfloat.c
@@ -31,7 +31,7 @@ QFloat *qfloat_from_double(double value)
 {
     QFloat *qf;
 
-    qf = qemu_malloc(sizeof(*qf));
+    qf = g_malloc(sizeof(*qf));
     qf->value = value;
     QOBJECT_INIT(qf, &qfloat_type);
 
@@ -64,5 +64,5 @@ QFloat *qobject_to_qfloat(const QObject *obj)
 static void qfloat_destroy_obj(QObject *obj)
 {
     assert(obj != NULL);
-    qemu_free(qobject_to_qfloat(obj));
+    g_free(qobject_to_qfloat(obj));
 }
diff --git a/qga/guest-agent-command-state.c b/qga/guest-agent-command-state.c
new file mode 100644 (file)
index 0000000..969da23
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * QEMU Guest Agent command state interfaces
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <glib.h>
+#include "qga/guest-agent-core.h"
+
+struct GACommandState {
+    GSList *groups;
+};
+
+typedef struct GACommandGroup {
+    void (*init)(void);
+    void (*cleanup)(void);
+} GACommandGroup;
+
+/* handle init/cleanup for stateful guest commands */
+
+void ga_command_state_add(GACommandState *cs,
+                          void (*init)(void),
+                          void (*cleanup)(void))
+{
+    GACommandGroup *cg = g_malloc0(sizeof(GACommandGroup));
+    cg->init = init;
+    cg->cleanup = cleanup;
+    cs->groups = g_slist_append(cs->groups, cg);
+}
+
+static void ga_command_group_init(gpointer opaque, gpointer unused)
+{
+    GACommandGroup *cg = opaque;
+
+    g_assert(cg);
+    if (cg->init) {
+        cg->init();
+    }
+}
+
+void ga_command_state_init_all(GACommandState *cs)
+{
+    g_assert(cs);
+    g_slist_foreach(cs->groups, ga_command_group_init, NULL);
+}
+
+static void ga_command_group_cleanup(gpointer opaque, gpointer unused)
+{
+    GACommandGroup *cg = opaque;
+
+    g_assert(cg);
+    if (cg->cleanup) {
+        cg->cleanup();
+    }
+}
+
+void ga_command_state_cleanup_all(GACommandState *cs)
+{
+    g_assert(cs);
+    g_slist_foreach(cs->groups, ga_command_group_cleanup, NULL);
+}
+
+GACommandState *ga_command_state_new(void)
+{
+    GACommandState *cs = g_malloc0(sizeof(GACommandState));
+    cs->groups = NULL;
+    return cs;
+}
diff --git a/qga/guest-agent-commands.c b/qga/guest-agent-commands.c
new file mode 100644 (file)
index 0000000..6da9904
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * QEMU Guest Agent commands
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#if defined(__linux__)
+#include <mntent.h>
+#include <linux/fs.h>
+
+#if defined(__linux__) && defined(FIFREEZE)
+#define CONFIG_FSFREEZE
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "qga/guest-agent-core.h"
+#include "qga-qmp-commands.h"
+#include "qerror.h"
+#include "qemu-queue.h"
+
+static GAState *ga_state;
+
+/* Note: in some situations, like with the fsfreeze, logging may be
+ * temporarilly disabled. if it is necessary that a command be able
+ * to log for accounting purposes, check ga_logging_enabled() beforehand,
+ * and use the QERR_QGA_LOGGING_DISABLED to generate an error
+ */
+static void slog(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    g_logv("syslog", G_LOG_LEVEL_INFO, fmt, ap);
+    va_end(ap);
+}
+
+int64_t qmp_guest_sync(int64_t id, Error **errp)
+{
+    return id;
+}
+
+void qmp_guest_ping(Error **err)
+{
+    slog("guest-ping called");
+}
+
+struct GuestAgentInfo *qmp_guest_info(Error **err)
+{
+    GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
+
+    info->version = g_strdup(QGA_VERSION);
+
+    return info;
+}
+
+void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
+{
+    int ret;
+    const char *shutdown_flag;
+
+    slog("guest-shutdown called, mode: %s", mode);
+    if (!has_mode || strcmp(mode, "powerdown") == 0) {
+        shutdown_flag = "-P";
+    } else if (strcmp(mode, "halt") == 0) {
+        shutdown_flag = "-H";
+    } else if (strcmp(mode, "reboot") == 0) {
+        shutdown_flag = "-r";
+    } else {
+        error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
+                  "halt|powerdown|reboot");
+        return;
+    }
+
+    ret = fork();
+    if (ret == 0) {
+        /* child, start the shutdown */
+        setsid();
+        fclose(stdin);
+        fclose(stdout);
+        fclose(stderr);
+
+        ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
+                    "hypervisor initiated shutdown", (char*)NULL);
+        if (ret) {
+            slog("guest-shutdown failed: %s", strerror(errno));
+        }
+        exit(!!ret);
+    } else if (ret < 0) {
+        error_set(err, QERR_UNDEFINED_ERROR);
+    }
+}
+
+typedef struct GuestFileHandle {
+    uint64_t id;
+    FILE *fh;
+    QTAILQ_ENTRY(GuestFileHandle) next;
+} GuestFileHandle;
+
+static struct {
+    QTAILQ_HEAD(, GuestFileHandle) filehandles;
+} guest_file_state;
+
+static void guest_file_handle_add(FILE *fh)
+{
+    GuestFileHandle *gfh;
+
+    gfh = g_malloc0(sizeof(GuestFileHandle));
+    gfh->id = fileno(fh);
+    gfh->fh = fh;
+    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
+}
+
+static GuestFileHandle *guest_file_handle_find(int64_t id)
+{
+    GuestFileHandle *gfh;
+
+    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
+    {
+        if (gfh->id == id) {
+            return gfh;
+        }
+    }
+
+    return NULL;
+}
+
+int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
+{
+    FILE *fh;
+    int fd;
+    int64_t ret = -1;
+
+    if (!has_mode) {
+        mode = "r";
+    }
+    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
+    fh = fopen(path, mode);
+    if (!fh) {
+        error_set(err, QERR_OPEN_FILE_FAILED, path);
+        return -1;
+    }
+
+    /* set fd non-blocking to avoid common use cases (like reading from a
+     * named pipe) from hanging the agent
+     */
+    fd = fileno(fh);
+    ret = fcntl(fd, F_GETFL);
+    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
+        fclose(fh);
+        return -1;
+    }
+
+    guest_file_handle_add(fh);
+    slog("guest-file-open, handle: %d", fd);
+    return fd;
+}
+
+void qmp_guest_file_close(int64_t handle, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    int ret;
+
+    slog("guest-file-close called, handle: %ld", handle);
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return;
+    }
+
+    ret = fclose(gfh->fh);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
+        return;
+    }
+
+    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
+    g_free(gfh);
+}
+
+struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
+                                          int64_t count, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    GuestFileRead *read_data = NULL;
+    guchar *buf;
+    FILE *fh;
+    size_t read_count;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    if (!has_count) {
+        count = QGA_READ_COUNT_DEFAULT;
+    } else if (count < 0) {
+        error_set(err, QERR_INVALID_PARAMETER, "count");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    buf = g_malloc0(count+1);
+    read_count = fread(buf, 1, count, fh);
+    if (ferror(fh)) {
+        slog("guest-file-read failed, handle: %ld", handle);
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
+    } else {
+        buf[read_count] = 0;
+        read_data = g_malloc0(sizeof(GuestFileRead));
+        read_data->count = read_count;
+        read_data->eof = feof(fh);
+        if (read_count) {
+            read_data->buf_b64 = g_base64_encode(buf, read_count);
+        }
+    }
+    g_free(buf);
+    clearerr(fh);
+
+    return read_data;
+}
+
+GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
+                                     bool has_count, int64_t count, Error **err)
+{
+    GuestFileWrite *write_data = NULL;
+    guchar *buf;
+    gsize buf_len;
+    int write_count;
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    FILE *fh;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    buf = g_base64_decode(buf_b64, &buf_len);
+
+    if (!has_count) {
+        count = buf_len;
+    } else if (count < 0 || count > buf_len) {
+        g_free(buf);
+        error_set(err, QERR_INVALID_PARAMETER, "count");
+        return NULL;
+    }
+
+    write_count = fwrite(buf, 1, count, fh);
+    if (ferror(fh)) {
+        slog("guest-file-write failed, handle: %ld", handle);
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
+    } else {
+        write_data = g_malloc0(sizeof(GuestFileWrite));
+        write_data->count = write_count;
+        write_data->eof = feof(fh);
+    }
+    g_free(buf);
+    clearerr(fh);
+
+    return write_data;
+}
+
+struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
+                                          int64_t whence, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    GuestFileSeek *seek_data = NULL;
+    FILE *fh;
+    int ret;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    ret = fseek(fh, offset, whence);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
+    } else {
+        seek_data = g_malloc0(sizeof(GuestFileRead));
+        seek_data->position = ftell(fh);
+        seek_data->eof = feof(fh);
+    }
+    clearerr(fh);
+
+    return seek_data;
+}
+
+void qmp_guest_file_flush(int64_t handle, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    FILE *fh;
+    int ret;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return;
+    }
+
+    fh = gfh->fh;
+    ret = fflush(fh);
+    if (ret == EOF) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
+    }
+}
+
+static void guest_file_init(void)
+{
+    QTAILQ_INIT(&guest_file_state.filehandles);
+}
+
+#if defined(CONFIG_FSFREEZE)
+static void disable_logging(void)
+{
+    ga_disable_logging(ga_state);
+}
+
+static void enable_logging(void)
+{
+    ga_enable_logging(ga_state);
+}
+
+typedef struct GuestFsfreezeMount {
+    char *dirname;
+    char *devtype;
+    QTAILQ_ENTRY(GuestFsfreezeMount) next;
+} GuestFsfreezeMount;
+
+struct {
+    GuestFsfreezeStatus status;
+    QTAILQ_HEAD(, GuestFsfreezeMount) mount_list;
+} guest_fsfreeze_state;
+
+/*
+ * Walk the mount table and build a list of local file systems
+ */
+static int guest_fsfreeze_build_mount_list(void)
+{
+    struct mntent *ment;
+    GuestFsfreezeMount *mount, *temp;
+    char const *mtab = MOUNTED;
+    FILE *fp;
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next);
+        g_free(mount->dirname);
+        g_free(mount->devtype);
+        g_free(mount);
+    }
+
+    fp = setmntent(mtab, "r");
+    if (!fp) {
+        g_warning("fsfreeze: unable to read mtab");
+        return -1;
+    }
+
+    while ((ment = getmntent(fp))) {
+        /*
+         * An entry which device name doesn't start with a '/' is
+         * either a dummy file system or a network file system.
+         * Add special handling for smbfs and cifs as is done by
+         * coreutils as well.
+         */
+        if ((ment->mnt_fsname[0] != '/') ||
+            (strcmp(ment->mnt_type, "smbfs") == 0) ||
+            (strcmp(ment->mnt_type, "cifs") == 0)) {
+            continue;
+        }
+
+        mount = g_malloc0(sizeof(GuestFsfreezeMount));
+        mount->dirname = g_strdup(ment->mnt_dir);
+        mount->devtype = g_strdup(ment->mnt_type);
+
+        QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next);
+    }
+
+    endmntent(fp);
+
+    return 0;
+}
+
+/*
+ * Return status of freeze/thaw
+ */
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+    return guest_fsfreeze_state.status;
+}
+
+/*
+ * Walk list of mounted file systems in the guest, and freeze the ones which
+ * are real local file systems.
+ */
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+    int ret = 0, i = 0;
+    struct GuestFsfreezeMount *mount, *temp;
+    int fd;
+    char err_msg[512];
+
+    slog("guest-fsfreeze called");
+
+    if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
+        return 0;
+    }
+
+    ret = guest_fsfreeze_build_mount_list();
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* cannot risk guest agent blocking itself on a write in this state */
+    disable_logging();
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        fd = qemu_open(mount->dirname, O_RDONLY);
+        if (fd == -1) {
+            sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno));
+            error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+            goto error;
+        }
+
+        /* we try to cull filesytems we know won't work in advance, but other
+         * filesytems may not implement fsfreeze for less obvious reasons.
+         * these will report EOPNOTSUPP, so we simply ignore them. when
+         * thawing, these filesystems will return an EINVAL instead, due to
+         * not being in a frozen state. Other filesystem-specific
+         * errors may result in EINVAL, however, so the user should check the
+         * number * of filesystems returned here against those returned by the
+         * thaw operation to determine whether everything completed
+         * successfully
+         */
+        ret = ioctl(fd, FIFREEZE);
+        if (ret < 0 && errno != EOPNOTSUPP) {
+            sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno));
+            error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+            close(fd);
+            goto error;
+        }
+        close(fd);
+
+        i++;
+    }
+
+    guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
+    return i;
+
+error:
+    if (i > 0) {
+        qmp_guest_fsfreeze_thaw(NULL);
+    }
+    return 0;
+}
+
+/*
+ * Walk list of frozen file systems in the guest, and thaw them.
+ */
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+    int ret;
+    GuestFsfreezeMount *mount, *temp;
+    int fd, i = 0;
+    bool has_error = false;
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        fd = qemu_open(mount->dirname, O_RDONLY);
+        if (fd == -1) {
+            has_error = true;
+            continue;
+        }
+        ret = ioctl(fd, FITHAW);
+        if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) {
+            has_error = true;
+            close(fd);
+            continue;
+        }
+        close(fd);
+        i++;
+    }
+
+    if (has_error) {
+        guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR;
+    } else {
+        guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
+    }
+    enable_logging();
+    return i;
+}
+
+static void guest_fsfreeze_init(void)
+{
+    guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
+    QTAILQ_INIT(&guest_fsfreeze_state.mount_list);
+}
+
+static void guest_fsfreeze_cleanup(void)
+{
+    int64_t ret;
+    Error *err = NULL;
+
+    if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
+        ret = qmp_guest_fsfreeze_thaw(&err);
+        if (ret < 0 || err) {
+            slog("failed to clean up frozen filesystems");
+        }
+    }
+}
+#else
+/*
+ * Return status of freeze/thaw
+ */
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+
+/*
+ * Walk list of mounted file systems in the guest, and freeze the ones which
+ * are real local file systems.
+ */
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+
+/*
+ * Walk list of frozen file systems in the guest, and thaw them.
+ */
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+#endif
+
+/* register init/cleanup routines for stateful command groups */
+void ga_command_state_init(GAState *s, GACommandState *cs)
+{
+    ga_state = s;
+#if defined(CONFIG_FSFREEZE)
+    ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
+#endif
+    ga_command_state_add(cs, guest_file_init, NULL);
+}
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
new file mode 100644 (file)
index 0000000..e42b91d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * QEMU Guest Agent core declarations
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Adam Litke        <aglitke@linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qapi/qmp-core.h"
+#include "qemu-common.h"
+
+#define QGA_VERSION "1.0"
+#define QGA_READ_COUNT_DEFAULT 4 << 10
+
+typedef struct GAState GAState;
+typedef struct GACommandState GACommandState;
+
+void ga_command_state_init(GAState *s, GACommandState *cs);
+void ga_command_state_add(GACommandState *cs,
+                          void (*init)(void),
+                          void (*cleanup)(void));
+void ga_command_state_init_all(GACommandState *cs);
+void ga_command_state_cleanup_all(GACommandState *cs);
+GACommandState *ga_command_state_new(void);
+bool ga_logging_enabled(GAState *s);
+void ga_disable_logging(GAState *s);
+void ga_enable_logging(GAState *s);
diff --git a/qint.c b/qint.c
index fb3823a7f416319e57cfe2d69f69fd94f2a19659..ee51804fbe9f5a9593b2d277aff9050cc756bc21 100644 (file)
--- a/qint.c
+++ b/qint.c
@@ -30,7 +30,7 @@ QInt *qint_from_int(int64_t value)
 {
     QInt *qi;
 
-    qi = qemu_malloc(sizeof(*qi));
+    qi = g_malloc(sizeof(*qi));
     qi->value = value;
     QOBJECT_INIT(qi, &qint_type);
 
@@ -63,5 +63,5 @@ QInt *qobject_to_qint(const QObject *obj)
 static void qint_destroy_obj(QObject *obj)
 {
     assert(obj != NULL);
-    qemu_free(qobject_to_qint(obj));
+    g_free(qobject_to_qint(obj));
 }
diff --git a/qlist.c b/qlist.c
index 5730fb87f7bd848e2493d55bde055bf9e3965faf..88498b157f5d17ecd905bab8fd860288a5694cc4 100644 (file)
--- a/qlist.c
+++ b/qlist.c
@@ -31,7 +31,7 @@ QList *qlist_new(void)
 {
     QList *qlist;
 
-    qlist = qemu_malloc(sizeof(*qlist));
+    qlist = g_malloc(sizeof(*qlist));
     QTAILQ_INIT(&qlist->head);
     QOBJECT_INIT(qlist, &qlist_type);
 
@@ -64,7 +64,7 @@ void qlist_append_obj(QList *qlist, QObject *value)
 {
     QListEntry *entry;
 
-    entry = qemu_malloc(sizeof(*entry));
+    entry = g_malloc(sizeof(*entry));
     entry->value = value;
 
     QTAILQ_INSERT_TAIL(&qlist->head, entry, next);
@@ -98,7 +98,7 @@ QObject *qlist_pop(QList *qlist)
     QTAILQ_REMOVE(&qlist->head, entry, next);
 
     ret = entry->value;
-    qemu_free(entry);
+    g_free(entry);
 
     return ret;
 }
@@ -150,8 +150,8 @@ static void qlist_destroy_obj(QObject *obj)
     QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) {
         QTAILQ_REMOVE(&qlist->head, entry, next);
         qobject_decref(entry->value);
-        qemu_free(entry);
+        g_free(entry);
     }
 
-    qemu_free(qlist);
+    g_free(qlist);
 }
diff --git a/qlist.h b/qlist.h
index dbe7b92db5262656c3ba1f3a6e2f8a91b91d2f6b..d426bd4a4b61eb3561b42ba1485bf9857b75dfa5 100644 (file)
--- a/qlist.h
+++ b/qlist.h
@@ -16,6 +16,7 @@
 #include "qobject.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
+#include "qemu-queue.h"
 
 typedef struct QListEntry {
     QObject *value;
@@ -50,4 +51,14 @@ QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
+static inline const QListEntry *qlist_first(const QList *qlist)
+{
+    return QTAILQ_FIRST(&qlist->head);
+}
+
+static inline const QListEntry *qlist_next(const QListEntry *entry)
+{
+    return QTAILQ_NEXT(entry, next);
+}
+
 #endif /* QLIST_H */
index df40a3d42e3670376c76778f10399016e90c66e0..97975a520722b723280207c3694d0c10c67dac9f 100644 (file)
@@ -42,7 +42,7 @@ and we're going to establish a deprecation policy for badly defined commands.
 
 If you're planning to adopt QMP, please observe the following:
 
-    1. The deprecation policy will take efect and be documented soon, please
+    1. The deprecation policy will take effect and be documented soon, please
        check the documentation of each used command as soon as a new release of
        QEMU is available
 
@@ -63,10 +63,7 @@ EQMP
     {
         .name       = "quit",
         .args_type  = "",
-        .params     = "",
-        .help       = "quit the emulator",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_quit,
+        .mhandler.cmd_new = qmp_marshal_input_quit,
     },
 
 SQMP
@@ -181,10 +178,7 @@ EQMP
     {
         .name       = "stop",
         .args_type  = "",
-        .params     = "",
-        .help       = "stop emulation",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_stop,
+        .mhandler.cmd_new = qmp_marshal_input_stop,
     },
 
 SQMP
@@ -229,10 +223,7 @@ EQMP
     {
         .name       = "system_reset",
         .args_type  = "",
-        .params     = "",
-        .help       = "reset the system",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_reset,
+        .mhandler.cmd_new = qmp_marshal_input_system_reset,
     },
 
 SQMP
@@ -340,10 +331,7 @@ EQMP
     {
         .name       = "cpu",
         .args_type  = "index:i",
-        .params     = "index",
-        .help       = "set the default CPU",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_cpu_set,
+        .mhandler.cmd_new = qmp_marshal_input_cpu,
     },
 
 SQMP
@@ -427,6 +415,33 @@ Example:
                             "filename": "/tmp/physical-mem-dump" } }
 <- { "return": {} }
 
+EQMP
+
+    {
+        .name       = "inject-nmi",
+        .args_type  = "",
+        .params     = "",
+        .help       = "",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_inject_nmi,
+    },
+
+SQMP
+inject-nmi
+----------
+
+Inject an NMI on guest's CPUs.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "inject-nmi" }
+<- { "return": {} }
+
+Note: inject-nmi is only supported for x86 guest currently, it will
+      returns "Unsupported" error for non-x86 guest.
+
 EQMP
 
     {
@@ -503,79 +518,80 @@ EQMP
     },
 
 SQMP
-client_migrate_info
-------------------
+migrate_set_speed
+-----------------
 
-Set the spice/vnc connection info for the migration target.  The spice/vnc
-server will ask the spice/vnc client to automatically reconnect using the
-new parameters (if specified) once the vm migration finished successfully.
+Set maximum speed for migrations.
 
 Arguments:
 
-- "protocol":     protocol: "spice" or "vnc" (json-string)
-- "hostname":     migration target hostname (json-string)
-- "port":         spice/vnc tcp port for plaintext channels (json-int, optional)
-- "tls-port":     spice tcp port for tls-secured channels (json-int, optional)
-- "cert-subject": server certificate subject (json-string, optional)
+- "value": maximum speed, in bytes per second (json-int)
 
 Example:
 
--> { "execute": "client_migrate_info",
-     "arguments": { "protocol": "spice",
-                    "hostname": "virt42.lab.kraxel.org",
-                    "port": 1234 } }
+-> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
 <- { "return": {} }
 
 EQMP
 
     {
-        .name       = "client_migrate_info",
-        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
-        .params     = "protocol hostname port tls-port cert-subject",
-        .help       = "send migration info to spice/vnc client",
+        .name       = "migrate_set_downtime",
+        .args_type  = "value:T",
+        .params     = "value",
+        .help       = "set maximum tolerated downtime (in seconds) for migrations",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = client_migrate_info,
+        .mhandler.cmd_new = do_migrate_set_downtime,
     },
 
 SQMP
-migrate_set_speed
------------------
+migrate_set_downtime
+--------------------
 
-Set maximum speed for migrations.
+Set maximum tolerated downtime (in seconds) for migrations.
 
 Arguments:
 
-- "value": maximum speed, in bytes per second (json-int)
+- "value": maximum downtime (json-number)
 
 Example:
 
--> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
+-> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
 <- { "return": {} }
 
 EQMP
 
     {
-        .name       = "migrate_set_downtime",
-        .args_type  = "value:T",
-        .params     = "value",
-        .help       = "set maximum tolerated downtime (in seconds) for migrations",
+        .name       = "client_migrate_info",
+        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+        .params     = "protocol hostname port tls-port cert-subject",
+        .help       = "send migration info to spice/vnc client",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_migrate_set_downtime,
+        .mhandler.cmd_async = client_migrate_info,
+        .flags      = MONITOR_CMD_ASYNC,
     },
 
 SQMP
-migrate_set_downtime
---------------------
+client_migrate_info
+------------------
 
-Set maximum tolerated downtime (in seconds) for migrations.
+Set the spice/vnc connection info for the migration target.  The spice/vnc
+server will ask the spice/vnc client to automatically reconnect using the
+new parameters (if specified) once the vm migration finished successfully.
 
 Arguments:
 
-- "value": maximum downtime (json-number)
+- "protocol":     protocol: "spice" or "vnc" (json-string)
+- "hostname":     migration target hostname (json-string)
+- "port":         spice/vnc tcp port for plaintext channels (json-int, optional)
+- "tls-port":     spice tcp port for tls-secured channels (json-int, optional)
+- "cert-subject": server certificate subject (json-string, optional)
 
 Example:
 
--> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
+-> { "execute": "client_migrate_info",
+     "arguments": { "protocol": "spice",
+                    "hostname": "virt42.lab.kraxel.org",
+                    "port": 1234 } }
 <- { "return": {} }
 
 EQMP
@@ -664,6 +680,40 @@ Example:
 -> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } }
 <- { "return": {} }
 
+EQMP
+
+    {
+        .name       = "blockdev-snapshot-sync",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+SQMP
+blockdev-snapshot-sync
+----------------------
+
+Synchronous snapshot of a block device. snapshot-file specifies the
+target of the new image. If the file exists, or if it is a device, the
+snapshot will be created in the existing file/device. If does not
+exist, a new file will be created. format specifies the format of the
+snapshot image, default is qcow2.
+
+Arguments:
+
+- "device": device name to snapshot (json-string)
+- "snapshot-file": name of new image file (json-string)
+- "format": format of new image (json-string, optional)
+
+Example:
+
+-> { "execute": "blockdev-snapshot-sync", "arguments": { "device": "ide-hd0",
+                                                         "snapshot-file":
+                                                        "/some/place/my-image",
+                                                        "format": "qcow2" } }
+<- { "return": {} }
+
 EQMP
 
     {
@@ -857,6 +907,33 @@ Example:
 
 EQMP
 
+    {
+        .name       = "add_client",
+        .args_type  = "protocol:s,fdname:s,skipauth:b?",
+        .params     = "protocol fdname skipauth",
+        .help       = "add a graphics client",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = add_graphics_client,
+    },
+
+SQMP
+add_client
+----------
+
+Add a graphics client
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "fdname": file descriptor name (json-string)
+
+Example:
+
+-> { "execute": "add_client", "arguments": { "protocol": "vnc",
+                                             "fdname": "myclient" } }
+<- { "return": {} }
+
+EQMP
     {
         .name       = "qmp_capabilities",
         .args_type  = "",
@@ -965,6 +1042,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-version",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_version,
+    },
+
 SQMP
 query-commands
 --------------
@@ -996,6 +1079,12 @@ Note: This example has been shortened as the real response is too long.
 
 EQMP
 
+    {
+        .name       = "query-commands",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_commands,
+    },
+
 SQMP
 query-chardev
 -------------
@@ -1026,6 +1115,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-chardev",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_chardev,
+    },
+
 SQMP
 query-block
 -----------
@@ -1039,9 +1134,12 @@ Each json-object contain the following:
 
 - "device": device name (json-string)
 - "type": device type (json-string)
-         - Possible values: "hd", "cdrom", "floppy", "unknown"
+         - deprecated, retained for backward compatibility
+         - Possible values: "unknown"
 - "removable": true if the device is removable, false otherwise (json-bool)
 - "locked": true if the device is locked, false otherwise (json-bool)
+- "tray-open": only present if removable, true if the device has a tray,
+               and it is open (json-bool)
 - "inserted": only present if the device is inserted, it is a json-object
    containing the following:
          - "file": device file name (json-string)
@@ -1054,6 +1152,10 @@ Each json-object contain the following:
                                 "tftp", "vdi", "vmdk", "vpc", "vvfat"
          - "backing_file": backing file name (json-string, optional)
          - "encrypted": true if encrypted, false otherwise (json-bool)
+- "io-status": I/O operation status, only present if the device supports it
+               and the VM is configured to stop on errors. It's always reset
+               to "ok" when the "cont" command is issued (json_string, optional)
+             - Possible values: "ok", "failed", "nospace"
 
 Example:
 
@@ -1061,6 +1163,7 @@ Example:
 <- {
       "return":[
          {
+            "io-status": "ok",
             "device":"ide0-hd0",
             "locked":false,
             "removable":false,
@@ -1070,31 +1173,38 @@ Example:
                "encrypted":false,
                "file":"disks/test.img"
             },
-            "type":"hd"
+            "type":"unknown"
          },
          {
+            "io-status": "ok",
             "device":"ide1-cd0",
             "locked":false,
             "removable":true,
-            "type":"cdrom"
+            "type":"unknown"
          },
          {
             "device":"floppy0",
             "locked":false,
             "removable":true,
-            "type": "floppy"
+            "type":"unknown"
          },
          {
             "device":"sd0",
             "locked":false,
             "removable":true,
-            "type":"floppy"
+            "type":"unknown"
          }
       ]
    }
 
 EQMP
 
+    {
+        .name       = "query-block",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_block,
+    },
+
 SQMP
 query-blockstats
 ----------------
@@ -1112,6 +1222,10 @@ Each json-object contain the following:
     - "wr_bytes": bytes written (json-int)
     - "rd_operations": read operations (json-int)
     - "wr_operations": write operations (json-int)
+    - "flush_operations": cache flush operations (json-int)
+    - "wr_total_time_ns": total time spend on writes in nano-seconds (json-int)
+    - "rd_total_time_ns": total time spend on reads in nano-seconds (json-int)
+    - "flush_total_time_ns": total time spend on cache flushes in nano-seconds (json-int)
     - "wr_highest_offset": Highest offset of a sector written since the
                            BlockDriverState has been opened (json-int)
 - "parent": Contains recursively the statistics of the underlying
@@ -1133,6 +1247,10 @@ Example:
                   "wr_operations":751,
                   "rd_bytes":122567168,
                   "rd_operations":36772
+                  "wr_total_times_ns":313253456
+                  "rd_total_times_ns":3465673657
+                  "flush_total_times_ns":49653
+                  "flush_operations":61,
                }
             },
             "stats":{
@@ -1141,6 +1259,10 @@ Example:
                "wr_operations":692,
                "rd_bytes":122739200,
                "rd_operations":36604
+               "flush_operations":51,
+               "wr_total_times_ns":313253456
+               "rd_total_times_ns":3465673657
+               "flush_total_times_ns":49653
             }
          },
          {
@@ -1151,6 +1273,10 @@ Example:
                "wr_operations":0,
                "rd_bytes":0,
                "rd_operations":0
+               "flush_operations":0,
+               "wr_total_times_ns":0
+               "rd_total_times_ns":0
+               "flush_total_times_ns":0
             }
          },
          {
@@ -1161,6 +1287,10 @@ Example:
                "wr_operations":0,
                "rd_bytes":0,
                "rd_operations":0
+               "flush_operations":0,
+               "wr_total_times_ns":0
+               "rd_total_times_ns":0
+               "flush_total_times_ns":0
             }
          },
          {
@@ -1171,6 +1301,10 @@ Example:
                "wr_operations":0,
                "rd_bytes":0,
                "rd_operations":0
+               "flush_operations":0,
+               "wr_total_times_ns":0
+               "rd_total_times_ns":0
+               "flush_total_times_ns":0
             }
          }
       ]
@@ -1178,6 +1312,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-blockstats",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_blockstats,
+    },
+
 SQMP
 query-cpus
 ----------
@@ -1194,6 +1334,7 @@ Return a json-array. Each CPU is represented by a json-object, which contains:
      "nip": PPC (json-int)
      "pc" and "npc": sparc (json-int)
      "PC": mips (json-int)
+- "thread_id": ID of the underlying host thread (json-int)
 
 Example:
 
@@ -1205,18 +1346,26 @@ Example:
             "current":true,
             "halted":false,
             "pc":3227107138
+            "thread_id":3134
          },
          {
             "CPU":1,
             "current":false,
             "halted":true,
             "pc":7108165
+            "thread_id":3135
          }
       ]
    }
 
 EQMP
 
+    {
+        .name       = "query-cpus",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_cpus,
+    },
+
 SQMP
 query-pci
 ---------
@@ -1428,6 +1577,12 @@ Note: This example has been shortened as the real response is too long.
 
 EQMP
 
+    {
+        .name       = "query-pci",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_pci,
+    },
+
 SQMP
 query-kvm
 ---------
@@ -1446,6 +1601,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-kvm",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_kvm,
+    },
+
 SQMP
 query-status
 ------------
@@ -1455,13 +1616,36 @@ Return a json-object with the following information:
 - "running": true if the VM is running, or false if it is paused (json-bool)
 - "singlestep": true if the VM is in single step mode,
                 false otherwise (json-bool)
+- "status": one of the following values (json-string)
+    "debug" - QEMU is running on a debugger
+    "inmigrate" - guest is paused waiting for an incoming migration
+    "internal-error" - An internal error that prevents further guest
+    execution has occurred
+    "io-error" - the last IOP has failed and the device is configured
+    to pause on I/O errors
+    "paused" - guest has been paused via the 'stop' command
+    "postmigrate" - guest is paused following a successful 'migrate'
+    "prelaunch" - QEMU was started with -S and guest has not started
+    "finish-migrate" - guest is paused to finish the migration process
+    "restore-vm" - guest is paused to restore VM state
+    "running" - guest is actively running
+    "save-vm" - guest is paused to save the VM state
+    "shutdown" - guest is shut down (and -no-shutdown is in use)
+    "watchdog" - the watchdog action is configured to pause and
+     has been triggered
 
 Example:
 
 -> { "execute": "query-status" }
-<- { "return": { "running": true, "singlestep": false } }
+<- { "return": { "running": true, "singlestep": false, "status": "running" } }
 
 EQMP
+    
+    {
+        .name       = "query-status",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_status,
+    },
 
 SQMP
 query-mice
@@ -1501,6 +1685,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-mice",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_mice,
+    },
+
 SQMP
 query-vnc
 ---------
@@ -1558,6 +1748,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-vnc",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_vnc,
+    },
+
 SQMP
 query-spice
 -----------
@@ -1628,6 +1824,14 @@ Example:
 
 EQMP
 
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "query-spice",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_spice,
+    },
+#endif
+
 SQMP
 query-name
 ----------
@@ -1645,6 +1849,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-name",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_name,
+    },
+
 SQMP
 query-uuid
 ----------
@@ -1662,6 +1872,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-uuid",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_uuid,
+    },
+
 SQMP
 query-migrate
 -------------
@@ -1739,6 +1955,12 @@ Examples:
 
 EQMP
 
+    {
+        .name       = "query-migrate",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_migrate,
+    },
+
 SQMP
 query-balloon
 -------------
@@ -1774,3 +1996,8 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-balloon",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_balloon,
+    },
diff --git a/qmp.c b/qmp.c
new file mode 100644 (file)
index 0000000..511dd62
--- /dev/null
+++ b/qmp.c
@@ -0,0 +1,119 @@
+/*
+ * QEMU Management Protocol
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "qemu-common.h"
+#include "sysemu.h"
+#include "qmp-commands.h"
+#include "kvm.h"
+#include "arch_init.h"
+
+NameInfo *qmp_query_name(Error **errp)
+{
+    NameInfo *info = g_malloc0(sizeof(*info));
+
+    if (qemu_name) {
+        info->has_name = true;
+        info->name = g_strdup(qemu_name);
+    }
+
+    return info;
+}
+
+VersionInfo *qmp_query_version(Error **err)
+{
+    VersionInfo *info = g_malloc0(sizeof(*info));
+    const char *version = QEMU_VERSION;
+    char *tmp;
+
+    info->qemu.major = strtol(version, &tmp, 10);
+    tmp++;
+    info->qemu.minor = strtol(tmp, &tmp, 10);
+    tmp++;
+    info->qemu.micro = strtol(tmp, &tmp, 10);
+    info->package = g_strdup(QEMU_PKGVERSION);
+
+    return info;
+}
+
+KvmInfo *qmp_query_kvm(Error **errp)
+{
+    KvmInfo *info = g_malloc0(sizeof(*info));
+
+    info->enabled = kvm_enabled();
+    info->present = kvm_available();
+
+    return info;
+}
+
+UuidInfo *qmp_query_uuid(Error **errp)
+{
+    UuidInfo *info = g_malloc0(sizeof(*info));
+    char uuid[64];
+
+    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
+                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
+                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
+                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
+                   qemu_uuid[14], qemu_uuid[15]);
+
+    info->UUID = g_strdup(uuid);
+    return info;
+}
+
+void qmp_quit(Error **err)
+{
+    no_shutdown = 0;
+    qemu_system_shutdown_request();
+}
+
+void qmp_stop(Error **errp)
+{
+    vm_stop(RUN_STATE_PAUSED);
+}
+
+void qmp_system_reset(Error **errp)
+{
+    qemu_system_reset_request();
+}
+
+void qmp_system_powerdown(Error **erp)
+{
+    qemu_system_powerdown_request();
+}
+
+void qmp_cpu(int64_t index, Error **errp)
+{
+    /* Just do nothing */
+}
+
+#ifndef CONFIG_VNC
+/* If VNC support is enabled, the "true" query-vnc command is
+   defined in the VNC subsystem */
+VncInfo *qmp_query_vnc(Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+    return NULL;
+};
+#endif
+
+#ifndef CONFIG_SPICE
+/* If SPICE support is enabled, the "true" query-spice command is
+   defined in the SPICE subsystem. Also note that we use a small
+   trick to maintain query-spice's original behavior, which is not
+   to be available in the namespace if SPICE is not compiled in */
+SpiceInfo *qmp_query_spice(Error **errp)
+{
+    error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
+    return NULL;
+};
+#endif
index 4e2ba083b71269e53c9e805718817a57031b2598..b7e12e40158200362b196aa566c3024d89360472 100644 (file)
--- a/qstring.c
+++ b/qstring.c
@@ -40,12 +40,12 @@ QString *qstring_from_substr(const char *str, int start, int end)
 {
     QString *qstring;
 
-    qstring = qemu_malloc(sizeof(*qstring));
+    qstring = g_malloc(sizeof(*qstring));
 
     qstring->length = end - start + 1;
     qstring->capacity = qstring->length;
 
-    qstring->string = qemu_malloc(qstring->capacity + 1);
+    qstring->string = g_malloc(qstring->capacity + 1);
     memcpy(qstring->string, str + start, qstring->length);
     qstring->string[qstring->length] = 0;
 
@@ -70,7 +70,7 @@ static void capacity_increase(QString *qstring, size_t len)
         qstring->capacity += len;
         qstring->capacity *= 2; /* use exponential growth */
 
-        qstring->string = qemu_realloc(qstring->string, qstring->capacity + 1);
+        qstring->string = g_realloc(qstring->string, qstring->capacity + 1);
     }
 }
 
@@ -136,6 +136,6 @@ static void qstring_destroy_obj(QObject *obj)
 
     assert(obj != NULL);
     qs = qobject_to_qstring(obj);
-    qemu_free(qs->string);
-    qemu_free(qs);
+    g_free(qs->string);
+    g_free(qs);
 }
index 92f9cd1569a657a10f0a9c1e2177ca522d5c6a3c..a6c0039ad2c23bae5817f7ac37f1b1b73487800f 100644 (file)
@@ -236,7 +236,7 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline)
            new_entry = hist_entry;
            /* Put this entry at the end of history */
            memmove(&rs->history[idx], &rs->history[idx + 1],
-                   (READLINE_MAX_CMDS - idx + 1) * sizeof(char *));
+                   (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
            rs->history[READLINE_MAX_CMDS - 1] = NULL;
            for (; idx < READLINE_MAX_CMDS; idx++) {
                if (rs->history[idx] == NULL)
@@ -264,7 +264,7 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline)
 void readline_add_completion(ReadLineState *rs, const char *str)
 {
     if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
-        rs->completions[rs->nb_completions++] = qemu_strdup(str);
+        rs->completions[rs->nb_completions++] = g_strdup(str);
     }
 }
 
@@ -281,11 +281,11 @@ static void readline_completion(ReadLineState *rs)
 
     rs->nb_completions = 0;
 
-    cmdline = qemu_malloc(rs->cmd_buf_index + 1);
+    cmdline = g_malloc(rs->cmd_buf_index + 1);
     memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
     cmdline[rs->cmd_buf_index] = '\0';
     rs->completion_finder(cmdline);
-    qemu_free(cmdline);
+    g_free(cmdline);
 
     /* no completion found */
     if (rs->nb_completions <= 0)
@@ -466,7 +466,7 @@ const char *readline_get_history(ReadLineState *rs, unsigned int index)
 ReadLineState *readline_init(Monitor *mon,
                              ReadLineCompletionFunc *completion_finder)
 {
-    ReadLineState *rs = qemu_mallocz(sizeof(*rs));
+    ReadLineState *rs = g_malloc0(sizeof(*rs));
 
     rs->hist_entry = -1;
     rs->mon = mon;
index ed59c9e82bde13b6b6edfe3e643746b64b1bb5ed..04a91983ec26e6d398f01a2780663c7e2cac729f 100644 (file)
--- a/rules.mak
+++ b/rules.mak
@@ -15,15 +15,23 @@ MAKEFLAGS += -rR
 QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
 
 %.o: %.c
-       $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  CC    $(TARGET_DIR)$@")
+       $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  CC    $(TARGET_DIR)$@")
+
+ifeq ($(LIBTOOL),)
+%.lo: %.c
+       @echo "missing libtool. please install and rerun configure"; exit 1
+else
+%.lo: %.c
+       $(call quiet-command,$(LIBTOOL) --mode=compile --quiet --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  lt CC $@")
+endif
 
 %.o: %.S
-       $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  AS    $(TARGET_DIR)$@")
+       $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  AS    $(TARGET_DIR)$@")
 
 %.o: %.m
-       $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  OBJC  $(TARGET_DIR)$@")
+       $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  OBJC  $(TARGET_DIR)$@")
 
-LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS),"  LINK  $(TARGET_DIR)$@")
+LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(1)) $(LIBS),"  LINK  $(TARGET_DIR)$@")
 
 %$(EXESUF): %.o
        $(call LINK,$^)
index 3d519745ca3df1cf006a20cd2a4d348a81268ac5..f53cd4c1546ef5d6535a78b401e93bd0257af0a5 100644 (file)
--- a/savevm.c
+++ b/savevm.c
@@ -23,7 +23,6 @@
  */
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <time.h>
 #include <errno.h>
 #include <sys/time.h>
@@ -82,6 +81,8 @@
 #include "migration.h"
 #include "qemu_socket.h"
 #include "qemu-queue.h"
+#include "qemu-timer.h"
+#include "cpus.h"
 
 #define SELF_ANNOUNCE_ROUNDS 5
 
@@ -137,7 +138,7 @@ static void qemu_announce_self_once(void *opaque)
 
     if (--count) {
         /* delay 50ms, 150ms, 250ms, ... */
-        qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
+        qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) +
                        50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
     } else {
            qemu_del_timer(timer);
@@ -148,7 +149,7 @@ static void qemu_announce_self_once(void *opaque)
 void qemu_announce_self(void)
 {
        static QEMUTimer *timer;
-       timer = qemu_new_timer(rt_clock, qemu_announce_self_once, &timer);
+       timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer);
        qemu_announce_self_once(&timer);
 }
 
@@ -173,7 +174,7 @@ struct QEMUFile {
     int buf_size; /* 0 when writing */
     uint8_t buf[IO_BUF_SIZE];
 
-    int has_error;
+    int last_error;
 };
 
 typedef struct QEMUFileStdio
@@ -194,7 +195,7 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
     ssize_t len;
 
     do {
-        len = recv(s->fd, (void *)buf, size, 0);
+        len = qemu_recv(s->fd, buf, size, 0);
     } while (len == -1 && socket_error() == EINTR);
 
     if (len == -1)
@@ -206,7 +207,7 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
 static int socket_close(void *opaque)
 {
     QEMUFileSocket *s = opaque;
-    qemu_free(s);
+    g_free(s);
     return 0;
 }
 
@@ -234,7 +235,7 @@ static int stdio_pclose(void *opaque)
     QEMUFileStdio *s = opaque;
     int ret;
     ret = pclose(s->stdio_file);
-    qemu_free(s);
+    g_free(s);
     return ret;
 }
 
@@ -242,7 +243,7 @@ static int stdio_fclose(void *opaque)
 {
     QEMUFileStdio *s = opaque;
     fclose(s->stdio_file);
-    qemu_free(s);
+    g_free(s);
     return 0;
 }
 
@@ -255,7 +256,7 @@ QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
         return NULL;
     }
 
-    s = qemu_mallocz(sizeof(QEMUFileStdio));
+    s = g_malloc0(sizeof(QEMUFileStdio));
 
     s->stdio_file = stdio_file;
 
@@ -303,7 +304,7 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
         return NULL;
     }
 
-    s = qemu_mallocz(sizeof(QEMUFileStdio));
+    s = g_malloc0(sizeof(QEMUFileStdio));
     s->stdio_file = fdopen(fd, mode);
     if (!s->stdio_file)
         goto fail;
@@ -318,13 +319,13 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
     return s->file;
 
 fail:
-    qemu_free(s);
+    g_free(s);
     return NULL;
 }
 
 QEMUFile *qemu_fopen_socket(int fd)
 {
-    QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
+    QEMUFileSocket *s = g_malloc0(sizeof(QEMUFileSocket));
 
     s->fd = fd;
     s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, 
@@ -358,7 +359,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
         return NULL;
     }
 
-    s = qemu_mallocz(sizeof(QEMUFileStdio));
+    s = g_malloc0(sizeof(QEMUFileStdio));
 
     s->stdio_file = fopen(filename, mode);
     if (!s->stdio_file)
@@ -373,7 +374,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
     }
     return s->file;
 fail:
-    qemu_free(s);
+    g_free(s);
     return NULL;
 }
 
@@ -411,7 +412,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
 {
     QEMUFile *f;
 
-    f = qemu_mallocz(sizeof(QEMUFile));
+    f = g_malloc0(sizeof(QEMUFile));
 
     f->opaque = opaque;
     f->put_buffer = put_buffer;
@@ -425,14 +426,14 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
     return f;
 }
 
-int qemu_file_has_error(QEMUFile *f)
+int qemu_file_get_error(QEMUFile *f)
 {
-    return f->has_error;
+    return f->last_error;
 }
 
-void qemu_file_set_error(QEMUFile *f)
+void qemu_file_set_error(QEMUFile *f, int ret)
 {
-    f->has_error = 1;
+    f->last_error = ret;
 }
 
 void qemu_fflush(QEMUFile *f)
@@ -447,7 +448,7 @@ void qemu_fflush(QEMUFile *f)
         if (len > 0)
             f->buf_offset += f->buf_index;
         else
-            f->has_error = 1;
+            f->last_error = -EINVAL;
         f->buf_index = 0;
     }
 }
@@ -455,6 +456,7 @@ void qemu_fflush(QEMUFile *f)
 static void qemu_fill_buffer(QEMUFile *f)
 {
     int len;
+    int pending;
 
     if (!f->get_buffer)
         return;
@@ -462,13 +464,22 @@ static void qemu_fill_buffer(QEMUFile *f)
     if (f->is_write)
         abort();
 
-    len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+    pending = f->buf_size - f->buf_index;
+    if (pending > 0) {
+        memmove(f->buf, f->buf + f->buf_index, pending);
+    }
+    f->buf_index = 0;
+    f->buf_size = pending;
+
+    len = f->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
+                        IO_BUF_SIZE - pending);
     if (len > 0) {
-        f->buf_index = 0;
-        f->buf_size = len;
+        f->buf_size += len;
         f->buf_offset += len;
+    } else if (len == 0) {
+        f->last_error = -EIO;
     } else if (len != -EAGAIN)
-        f->has_error = 1;
+        f->last_error = len;
 }
 
 int qemu_fclose(QEMUFile *f)
@@ -477,7 +488,7 @@ int qemu_fclose(QEMUFile *f)
     qemu_fflush(f);
     if (f->close)
         ret = f->close(f->opaque);
-    qemu_free(f);
+    g_free(f);
     return ret;
 }
 
@@ -490,13 +501,13 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
 {
     int l;
 
-    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+    if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
         fprintf(stderr,
                 "Attempted to write to buffer while read buffer is not empty\n");
         abort();
     }
 
-    while (!f->has_error && size > 0) {
+    while (!f->last_error && size > 0) {
         l = IO_BUF_SIZE - f->buf_index;
         if (l > size)
             l = size;
@@ -512,7 +523,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
 
 void qemu_put_byte(QEMUFile *f, int v)
 {
-    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+    if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
         fprintf(stderr,
                 "Attempted to write to buffer while read buffer is not empty\n");
         abort();
@@ -524,56 +535,86 @@ void qemu_put_byte(QEMUFile *f, int v)
         qemu_fflush(f);
 }
 
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+static void qemu_file_skip(QEMUFile *f, int size)
 {
-    int size, l;
+    if (f->buf_index + size <= f->buf_size) {
+        f->buf_index += size;
+    }
+}
 
-    if (f->is_write)
+static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
+{
+    int pending;
+    int index;
+
+    if (f->is_write) {
         abort();
+    }
 
-    size = size1;
-    while (size > 0) {
-        l = f->buf_size - f->buf_index;
-        if (l == 0) {
-            qemu_fill_buffer(f);
-            l = f->buf_size - f->buf_index;
-            if (l == 0)
-                break;
+    index = f->buf_index + offset;
+    pending = f->buf_size - index;
+    if (pending < size) {
+        qemu_fill_buffer(f);
+        index = f->buf_index + offset;
+        pending = f->buf_size - index;
+    }
+
+    if (pending <= 0) {
+        return 0;
+    }
+    if (size > pending) {
+        size = pending;
+    }
+
+    memcpy(buf, f->buf + index, size);
+    return size;
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
+{
+    int pending = size;
+    int done = 0;
+
+    while (pending > 0) {
+        int res;
+
+        res = qemu_peek_buffer(f, buf, pending, 0);
+        if (res == 0) {
+            return done;
         }
-        if (l > size)
-            l = size;
-        memcpy(buf, f->buf + f->buf_index, l);
-        f->buf_index += l;
-        buf += l;
-        size -= l;
+        qemu_file_skip(f, res);
+        buf += res;
+        pending -= res;
+        done += res;
     }
-    return size1 - size;
+    return done;
 }
 
-static int qemu_peek_byte(QEMUFile *f)
+static int qemu_peek_byte(QEMUFile *f, int offset)
 {
-    if (f->is_write)
+    int index = f->buf_index + offset;
+
+    if (f->is_write) {
         abort();
+    }
 
-    if (f->buf_index >= f->buf_size) {
+    if (index >= f->buf_size) {
         qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size)
+        index = f->buf_index + offset;
+        if (index >= f->buf_size) {
             return 0;
+        }
     }
-    return f->buf[f->buf_index];
+    return f->buf[index];
 }
 
 int qemu_get_byte(QEMUFile *f)
 {
-    if (f->is_write)
-        abort();
+    int result;
 
-    if (f->buf_index >= f->buf_size) {
-        qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size)
-            return 0;
-    }
-    return f->buf[f->buf_index++];
+    result = qemu_peek_byte(f, 0);
+    qemu_file_skip(f, 1);
+    return result;
 }
 
 int64_t qemu_ftell(QEMUFile *f)
@@ -674,6 +715,30 @@ uint64_t qemu_get_be64(QEMUFile *f)
     return v;
 }
 
+
+/* timer */
+
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_timer_expire_time_ns(ts);
+    qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_get_be64(f);
+    if (expire_time != -1) {
+        qemu_mod_timer_ns(ts, expire_time);
+    } else {
+        qemu_del_timer(ts);
+    }
+}
+
+
 /* bool */
 
 static int get_bool(QEMUFile *f, void *pv, size_t size)
@@ -882,6 +947,27 @@ const VMStateInfo vmstate_info_uint32 = {
     .put  = put_uint32,
 };
 
+/* 32 bit uint. See that the received value is the same than the one
+   in the field */
+
+static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    uint32_t v2;
+    qemu_get_be32s(f, &v2);
+
+    if (*v == v2) {
+        return 0;
+    }
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint32_equal = {
+    .name = "uint32 equal",
+    .get  = get_uint32_equal,
+    .put  = put_uint32,
+};
+
 /* 64 bit unsigned int */
 
 static int get_uint64(QEMUFile *f, void *pv, size_t size)
@@ -986,7 +1072,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)
 {
@@ -1093,7 +1179,7 @@ int register_savevm_live(DeviceState *dev,
 {
     SaveStateEntry *se;
 
-    se = qemu_mallocz(sizeof(SaveStateEntry));
+    se = g_malloc0(sizeof(SaveStateEntry));
     se->version_id = version_id;
     se->section_id = global_section_id++;
     se->set_params = set_params;
@@ -1109,9 +1195,9 @@ int register_savevm_live(DeviceState *dev,
         if (id) {
             pstrcpy(se->idstr, sizeof(se->idstr), id);
             pstrcat(se->idstr, sizeof(se->idstr), "/");
-            qemu_free(id);
+            g_free(id);
 
-            se->compat = qemu_mallocz(sizeof(CompatEntry));
+            se->compat = g_malloc0(sizeof(CompatEntry));
             pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
             se->compat->instance_id = instance_id == -1 ?
                          calculate_compat_instance_id(idstr) : instance_id;
@@ -1153,7 +1239,7 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
         if (path) {
             pstrcpy(id, sizeof(id), path);
             pstrcat(id, sizeof(id), "/");
-            qemu_free(path);
+            g_free(path);
         }
     }
     pstrcat(id, sizeof(id), idstr);
@@ -1162,34 +1248,9 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
         if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
             QTAILQ_REMOVE(&savevm_handlers, se, entry);
             if (se->compat) {
-                qemu_free(se->compat);
+                g_free(se->compat);
             }
-            qemu_free(se);
-        }
-    }
-}
-
-/* mark a device as not to be migrated, that is the device should be
-   unplugged before migration */
-void register_device_unmigratable(DeviceState *dev, const char *idstr,
-                                                            void *opaque)
-{
-    SaveStateEntry *se;
-    char id[256] = "";
-
-    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
-        char *path = dev->parent_bus->info->get_dev_path(dev);
-        if (path) {
-            pstrcpy(id, sizeof(id), path);
-            pstrcat(id, sizeof(id), "/");
-            qemu_free(path);
-        }
-    }
-    pstrcat(id, sizeof(id), idstr);
-
-    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-        if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
-            se->no_migrate = 1;
+            g_free(se);
         }
     }
 }
@@ -1204,7 +1265,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
     /* If this triggers, alias support can be dropped for the vmsd. */
     assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
 
-    se = qemu_mallocz(sizeof(SaveStateEntry));
+    se = g_malloc0(sizeof(SaveStateEntry));
     se->version_id = vmsd->version_id;
     se->section_id = global_section_id++;
     se->save_live_state = NULL;
@@ -1213,15 +1274,16 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
     se->opaque = opaque;
     se->vmsd = vmsd;
     se->alias_id = alias_id;
+    se->no_migrate = vmsd->unmigratable;
 
     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
         char *id = dev->parent_bus->info->get_dev_path(dev);
         if (id) {
             pstrcpy(se->idstr, sizeof(se->idstr), id);
             pstrcat(se->idstr, sizeof(se->idstr), "/");
-            qemu_free(id);
+            g_free(id);
 
-            se->compat = qemu_mallocz(sizeof(CompatEntry));
+            se->compat = g_malloc0(sizeof(CompatEntry));
             pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
             se->compat->instance_id = instance_id == -1 ?
                          calculate_compat_instance_id(vmsd->name) : instance_id;
@@ -1257,9 +1319,9 @@ void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
         if (se->vmsd == vmsd && se->opaque == opaque) {
             QTAILQ_REMOVE(&savevm_handlers, se, entry);
             if (se->compat) {
-                qemu_free(se->compat);
+                g_free(se->compat);
             }
-            qemu_free(se);
+            g_free(se);
         }
     }
 }
@@ -1308,8 +1370,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                 n_elems = field->num;
             } else if (field->flags & VMS_VARRAY_INT32) {
                 n_elems = *(int32_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT32) {
+                n_elems = *(uint32_t *)(opaque+field->num_offset);
             } else if (field->flags & VMS_VARRAY_UINT16) {
                 n_elems = *(uint16_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT8) {
+                n_elems = *(uint8_t *)(opaque+field->num_offset);
             }
             if (field->flags & VMS_POINTER) {
                 base_addr = *(void **)base_addr + field->start;
@@ -1370,6 +1436,8 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                 n_elems = *(int32_t *)(opaque+field->num_offset);
             } else if (field->flags & VMS_VARRAY_UINT16) {
                 n_elems = *(uint16_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT8) {
+                n_elems = *(uint8_t *)(opaque+field->num_offset);
             }
             if (field->flags & VMS_POINTER) {
                 base_addr = *(void **)base_addr + field->start;
@@ -1400,15 +1468,13 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
     return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
 }
 
-static int vmstate_save(QEMUFile *f, SaveStateEntry *se)
+static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
 {
     if (!se->vmsd) {         /* Old style */
         se->save_state(f, se->opaque);
-        return 0;
+        return;
     }
     vmstate_save_state(f,se->vmsd, se->opaque);
-
-       return 0;
 }
 
 #define QEMU_VM_FILE_MAGIC           0x5145564d
@@ -1440,13 +1506,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                             int shared)
 {
     SaveStateEntry *se;
-    int dev = 0;
-       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-               if (se->save_live_state || se->vmsd) {
-                       dev++;
-               }
-       }
-       monitor_printf(mon, "Device_Count=%d\n", dev);
+    int ret;
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if(se->set_params == NULL) {
@@ -1458,7 +1518,6 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
     qemu_put_be32(f, QEMU_VM_FILE_VERSION);
 
-       dev = 0;
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         int len;
 
@@ -1476,23 +1535,32 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
 
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);
-               
-               dev++;
-        se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
-    }
 
-    if (qemu_file_has_error(f)) {
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+        if (ret < 0) {
+            qemu_savevm_state_cancel(mon, f);
+            return ret;
+        }
+    }
+    ret = qemu_file_get_error(f);
+    if (ret != 0) {
         qemu_savevm_state_cancel(mon, f);
-        return -EIO;
     }
 
-    return 0;
+    return ret;
+
 }
 
+/*
+ * this funtion has three return values:
+ *   negative: there was one error, and we have -errno.
+ *   0 : We haven't finished, caller have to go again
+ *   1 : We have finished, we can go to complete phase
+ */
 int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
-    int ret = 1, dev = 0;
+    int ret = 1;
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (se->save_live_state == NULL)
@@ -1501,10 +1569,9 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
         /* Section type */
         qemu_put_byte(f, QEMU_VM_SECTION_PART);
         qemu_put_be32(f, se->section_id);
-               
-               dev++;
+
         ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
-        if (!ret) {
+        if (ret <= 0) {
             /* Do not proceed to the next vmstate before this one reported
                completion of the current stage. This serializes the migration
                and reduces the probability that a faster changing state is
@@ -1512,23 +1579,21 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
             break;
         }
     }
-
-    if (ret)
-        return 1;
-
-    if (qemu_file_has_error(f)) {
+    if (ret != 0) {
+        return ret;
+    }
+    ret = qemu_file_get_error(f);
+    if (ret != 0) {
         qemu_savevm_state_cancel(mon, f);
-        return -EIO;
     }
-
-    return 0;
+    return ret;
 }
 
 int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
-       int r;
-       int dev = 0;
+    int ret;
+
     cpu_synchronize_all_states();
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
@@ -1538,12 +1603,13 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
         /* Section type */
         qemu_put_byte(f, QEMU_VM_SECTION_END);
         qemu_put_be32(f, se->section_id);
-               
-               dev++;
-        se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+        if (ret < 0) {
+            return ret;
+        }
     }
 
-       dev = 0;
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         int len;
 
@@ -1561,24 +1627,13 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);
-               
-               dev++;
-           r = vmstate_save(f, se);
-               if (r < 0) {
-                       monitor_printf(mon, "cannot migrate with device '%s'\n", se->idstr);
-                       return r;
-               }
-               monitor_printf(mon, "Device_Completed:%d:name:%s\n", dev, se->idstr);
-       }
-       
-       monitor_printf(mon, "SaveVM Complete\n");
-    
-       qemu_put_byte(f, QEMU_VM_EOF);
 
-    if (qemu_file_has_error(f))
-        return -EIO;
+        vmstate_save(f, se);
+    }
 
-    return 0;
+    qemu_put_byte(f, QEMU_VM_EOF);
+
+    return qemu_file_get_error(f);
 }
 
 void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
@@ -1594,12 +1649,8 @@ void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
 
 static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
 {
-    int saved_vm_running;
     int ret;
 
-    saved_vm_running = vm_running;
-    vm_stop(0);
-
     if (qemu_savevm_state_blocked(mon)) {
         ret = -EINVAL;
         goto out;
@@ -1618,11 +1669,9 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     ret = qemu_savevm_state_complete(mon, f);
 
 out:
-    if (qemu_file_has_error(f))
-        ret = -EIO;
-
-    if (!ret && saved_vm_running)
-        vm_start();
+    if (ret == 0) {
+        ret = qemu_file_get_error(f);
+    }
 
     return ret;
 }
@@ -1661,29 +1710,36 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection
 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                    void *opaque)
 {
-    const VMStateSubsection *sub = vmsd->subsections;
-
-    if (!sub || !sub->needed) {
-        return 0;
-    }
-
-    while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+    while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
         char idstr[256];
         int ret;
-        uint8_t version_id, len;
+        uint8_t version_id, len, size;
         const VMStateDescription *sub_vmsd;
 
-        qemu_get_byte(f); /* subsection */
-        len = qemu_get_byte(f);
-        qemu_get_buffer(f, (uint8_t *)idstr, len);
-        idstr[len] = 0;
-        version_id = qemu_get_be32(f);
+        len = qemu_peek_byte(f, 1);
+        if (len < strlen(vmsd->name) + 1) {
+            /* subsection name has be be "section_name/a" */
+            return 0;
+        }
+        size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+        if (size != len) {
+            return 0;
+        }
+        idstr[size] = 0;
 
-        sub_vmsd = vmstate_get_subsection(sub, idstr);
+        if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+            /* it don't have a valid subsection name */
+            return 0;
+        }
+        sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
         if (sub_vmsd == NULL) {
             return -ENOENT;
         }
-        assert(!sub_vmsd->subsections);
+        qemu_file_skip(f, 1); /* subsection */
+        qemu_file_skip(f, 1); /* len */
+        qemu_file_skip(f, len); /* idstr */
+        version_id = qemu_get_be32(f);
+
         ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
         if (ret) {
             return ret;
@@ -1707,7 +1763,6 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
             qemu_put_byte(f, len);
             qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
             qemu_put_be32(f, vmsd->version_id);
-            assert(!vmsd->subsections);
             vmstate_save_state(f, vmsd, opaque);
         }
         sub++;
@@ -1780,7 +1835,7 @@ int qemu_loadvm_state(QEMUFile *f)
             }
 
             /* Add entry */
-            le = qemu_mallocz(sizeof(*le));
+            le = g_malloc0(sizeof(*le));
 
             le->se = se;
             le->section_id = section_id;
@@ -1830,11 +1885,12 @@ int qemu_loadvm_state(QEMUFile *f)
 out:
     QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
         QLIST_REMOVE(le, entry);
-        qemu_free(le);
+        g_free(le);
     }
 
-    if (qemu_file_has_error(f))
-        ret = -EIO;
+    if (ret == 0) {
+        ret = qemu_file_get_error(f);
+    }
 
     return ret;
 }
@@ -1857,7 +1913,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
             break;
         }
     }
-    qemu_free(sn_tab);
+    g_free(sn_tab);
     return ret;
 }
 
@@ -1909,7 +1965,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
 
-        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
             continue;
         }
 
@@ -1926,8 +1982,8 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    saved_vm_running = vm_running;
-    vm_stop(0);
+    saved_vm_running = runstate_is_running();
+    vm_stop(RUN_STATE_SAVE_VM);
 
     memset(sn, 0, sizeof(*sn));
 
@@ -1941,7 +1997,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     sn->date_sec = tv.tv_sec;
     sn->date_nsec = tv.tv_usec * 1000;
 #endif
-    sn->vm_clock_nsec = qemu_get_clock(vm_clock);
+    sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
 
     if (name) {
         ret = bdrv_snapshot_find(bs, old_sn, name);
@@ -2019,6 +2075,8 @@ int load_vmstate(const char *name)
     if (ret < 0) {
         return ret;
     } else if (sn.vm_state_size == 0) {
+        error_report("This is a disk-only snapshot. Revert to it offline "
+            "using qemu-img.");
         return -EINVAL;
     }
 
@@ -2027,7 +2085,7 @@ int load_vmstate(const char *name)
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
 
-        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
             continue;
         }
 
@@ -2067,6 +2125,7 @@ int load_vmstate(const char *name)
         return -EINVAL;
     }
 
+    qemu_system_reset(VMRESET_SILENT);
     ret = qemu_loadvm_state(f);
 
     qemu_fclose(f);
@@ -2133,7 +2192,7 @@ void do_info_snapshots(Monitor *mon)
         return;
     }
 
-    available_snapshots = qemu_mallocz(sizeof(int) * nb_sns);
+    available_snapshots = g_malloc0(sizeof(int) * nb_sns);
     total = 0;
     for (i = 0; i < nb_sns; i++) {
         sn = &sn_tab[i];
@@ -2166,7 +2225,7 @@ void do_info_snapshots(Monitor *mon)
         monitor_printf(mon, "There is no suitable snapshot available\n");
     }
 
-    qemu_free(sn_tab);
-    qemu_free(available_snapshots);
+    g_free(sn_tab);
+    g_free(available_snapshots);
 
 }
diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py
new file mode 100755 (executable)
index 0000000..b6d58fd
--- /dev/null
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# Pretty print 9p simpletrace log
+# Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid>
+#
+# Author: Harsh Prateek Bora
+
+import simpletrace
+
+class VirtFSRequestTracker(simpletrace.Analyzer):
+        def begin(self):
+                print "Pretty printing 9p simpletrace log ..."
+
+        def v9fs_rerror(self, tag, id, err):
+                print "RERROR (tag =", tag, ", id =", id, ",err =", err, ")"
+
+        def v9fs_version(self, tag, id, msize, version):
+                print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
+
+        def v9fs_version_return(self, tag, id, msize, version):
+                print "RVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
+
+        def v9fs_attach(self, tag, id, fid, afid, uname, aname):
+                print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")"
+
+        def v9fs_attach_return(self, tag, id, type, version, path):
+                print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
+
+        def v9fs_stat(self, tag, id, fid):
+                print "TSTAT (tag =", tag, ", fid =", fid, ")"
+
+        def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
+                print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
+
+        def v9fs_getattr(self, tag, id, fid, request_mask):
+                print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
+
+        def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
+                print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
+
+        def v9fs_walk(self, tag, id, fid, newfid, nwnames):
+                print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
+
+        def v9fs_walk_return(self, tag, id, nwnames, qids):
+                print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
+
+        def v9fs_open(self, tag, id, fid, mode):
+                print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
+
+        def v9fs_open_return(self, tag, id, type, version, path, iounit):
+                print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+        def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
+                print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
+
+        def v9fs_lcreate_return(self, tag, id, type, version, path, iounit):
+                print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+        def v9fs_fsync(self, tag, id, fid, datasync):
+                print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
+
+        def v9fs_clunk(self, tag, id, fid):
+                print "TCLUNK (tag =", tag, ", fid =", fid, ")"
+
+        def v9fs_read(self, tag, id, fid, off, max_count):
+                print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
+
+        def v9fs_read_return(self, tag, id, count, err):
+                print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
+
+        def v9fs_readdir(self, tag, id, fid, offset, max_count):
+                print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
+
+        def v9fs_readdir_return(self, tag, id, count, retval):
+                print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
+
+        def v9fs_write(self, tag, id, fid, off, count, cnt):
+                print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
+
+        def v9fs_write_return(self, tag, id, total, err):
+                print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
+
+        def v9fs_create(self, tag, id, fid, name, perm, mode):
+                print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
+
+        def v9fs_create_return(self, tag, id, type, version, path, iounit):
+                print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+        def v9fs_symlink(self, tag, id, fid, name, symname, gid):
+                print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
+
+        def v9fs_symlink_return(self, tag, id, type, version, path):
+                print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
+
+        def v9fs_flush(self, tag, id, flush_tag):
+                print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
+
+        def v9fs_link(self, tag, id, dfid, oldfid, name):
+                print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
+
+        def v9fs_remove(self, tag, id, fid):
+                print "TREMOVE (tag =", tag, ", fid =", fid, ")"
+
+        def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
+                print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
+
+        def v9fs_mknod(self, tag, id, fid, mode, major, minor):
+                print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
+
+        def v9fs_lock(self, tag, id, fid, type, start, length):
+                print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+
+        def v9fs_lock_return(self, tag, id, status):
+                print "RLOCK (tag =", tag, ", status =", status, ")"
+
+        def v9fs_getlock(self, tag, id, fid, type, start, length):
+                print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+
+        def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
+                print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
+
+        def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
+                print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
+
+        def v9fs_mkdir_return(self, tag, id, type, version, path, err):
+                print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
+
+        def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
+                print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
+
+        def v9fs_xattrwalk_return(self, tag, id, size):
+                print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
+
+        def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
+                print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
+
+        def v9fs_readlink(self, tag, id, fid):
+                print "TREADLINK (tag =", tag, ", fid =", fid, ")"
+
+        def v9fs_readlink_return(self, tag, id, target):
+                print "RREADLINK (tag =", tag, ", target =", target, ")"
+
+simpletrace.run(VirtFSRequestTracker())
old mode 100644 (file)
new mode 100755 (executable)
index 4fa06c0..04ab990
@@ -859,7 +859,7 @@ sub annotate_values {
                                $av_preprocessor = 0;
                        }
 
-               } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) {
+               } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
                        print "CAST($1)\n" if ($dbg_values > 1);
                        push(@av_paren_type, $type);
                        $type = 'C';
@@ -1495,7 +1495,7 @@ sub process {
                next if ($realfile !~ /\.(h|c|pl)$/);
 
 # in QEMU, no tabs are allowed
-               if ($rawline =~ /\t/) {
+               if ($rawline =~ /^\+.*\t/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("code indent should never use tabs\n" . $herevet);
                        $rpt_cleaners = 1;
@@ -2068,8 +2068,10 @@ sub process {
                                        }
 
                                # , must have a space on the right.
+                                # not required when having a single },{ on one line
                                } elsif ($op eq ',') {
-                                       if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+                                       if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ &&
+                                            ($elements[$n] . $elements[$n + 2]) !~ " *}{") {
                                                ERROR("space required after that '$op' $at\n" . $hereptr);
                                        }
 
@@ -2204,12 +2206,6 @@ sub process {
                        ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
                }
 
-#goto labels aren't indented, allow a single space however
-               if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
-                  !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
-                       WARN("labels should not be indented\n" . $herecurr);
-               }
-
 # Return is not a function.
                if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
                        my $spacing = $1;
@@ -2530,13 +2526,14 @@ sub process {
                                                $allowed = 1;
                                        }
                                }
-                               if (!$seen) {
+                               if ($seen != ($#chunks + 1)) {
                                        WARN("braces {} are necessary for all arms of this statement\n" . $herectx);
                                }
                        }
                }
                if (!defined $suppress_ifbraces{$linenr - 1} &&
                                        $line =~ /\b(if|while|for|else)\b/ &&
+                                       $line !~ /\#\s*if/ &&
                                        $line !~ /\#\s*else/) {
                        my $allowed = 0;
 
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
new file mode 100755 (executable)
index 0000000..d9c48e0
--- /dev/null
@@ -0,0 +1,2149 @@
+#!/usr/bin/perl -w
+# (c) 2007, Joe Perches <joe@perches.com>
+#           created from checkpatch.pl
+#
+# Print selected MAINTAINERS information for
+# the files modified in a patch or for a file
+#
+# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
+#        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
+#
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+my $V = '0.26';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $lk_path = "./";
+my $email = 1;
+my $email_usename = 1;
+my $email_maintainer = 1;
+my $email_list = 1;
+my $email_subscriber_list = 0;
+my $email_git_penguin_chiefs = 0;
+my $email_git = 0;
+my $email_git_all_signature_types = 0;
+my $email_git_blame = 0;
+my $email_git_blame_signatures = 1;
+my $email_git_fallback = 1;
+my $email_git_min_signatures = 1;
+my $email_git_max_maintainers = 5;
+my $email_git_min_percent = 5;
+my $email_git_since = "1-year-ago";
+my $email_hg_since = "-365";
+my $interactive = 0;
+my $email_remove_duplicates = 1;
+my $email_use_mailmap = 1;
+my $output_multiline = 1;
+my $output_separator = ", ";
+my $output_roles = 0;
+my $output_rolestats = 1;
+my $scm = 0;
+my $web = 0;
+my $subsystem = 0;
+my $status = 0;
+my $keywords = 1;
+my $sections = 0;
+my $file_emails = 0;
+my $from_filename = 0;
+my $pattern_depth = 0;
+my $version = 0;
+my $help = 0;
+
+my $vcs_used = 0;
+
+my $exit = 0;
+
+my %commit_author_hash;
+my %commit_signer_hash;
+
+my @penguin_chief = ();
+push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
+#Andrew wants in on most everything - 2009/01/14
+#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
+
+my @penguin_chief_names = ();
+foreach my $chief (@penguin_chief) {
+    if ($chief =~ m/^(.*):(.*)/) {
+       my $chief_name = $1;
+       my $chief_addr = $2;
+       push(@penguin_chief_names, $chief_name);
+    }
+}
+my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+
+# Signature types of people who are either
+#      a) responsible for the code in question, or
+#      b) familiar enough with it to give relevant feedback
+my @signature_tags = ();
+push(@signature_tags, "Signed-off-by:");
+push(@signature_tags, "Reviewed-by:");
+push(@signature_tags, "Acked-by:");
+
+# rfc822 email address - preloaded methods go here.
+my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
+my $rfc822_char = '[\\000-\\377]';
+
+# VCS command support: class-like functions and strings
+
+my %VCS_cmds;
+
+my %VCS_cmds_git = (
+    "execute_cmd" => \&git_execute_cmd,
+    "available" => '(which("git") ne "") && (-d ".git")',
+    "find_signers_cmd" =>
+       "git log --no-color --since=\$email_git_since " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n' .
+                     '%b%n"' .
+           " -- \$file",
+    "find_commit_signers_cmd" =>
+       "git log --no-color " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n' .
+                     '%b%n"' .
+           " -1 \$commit",
+    "find_commit_author_cmd" =>
+       "git log --no-color " .
+           '--format="GitCommit: %H%n' .
+                     'GitAuthor: %an <%ae>%n' .
+                     'GitDate: %aD%n' .
+                     'GitSubject: %s%n"' .
+           " -1 \$commit",
+    "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
+    "blame_file_cmd" => "git blame -l \$file",
+    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([0-9a-f]+) ",
+    "author_pattern" => "^GitAuthor: (.*)",
+    "subject_pattern" => "^GitSubject: (.*)",
+);
+
+my %VCS_cmds_hg = (
+    "execute_cmd" => \&hg_execute_cmd,
+    "available" => '(which("hg") ne "") && (-d ".hg")',
+    "find_signers_cmd" =>
+       "hg log --date=\$email_hg_since " .
+           "--template='HgCommit: {node}\\n" .
+                       "HgAuthor: {author}\\n" .
+                       "HgSubject: {desc}\\n'" .
+           " -- \$file",
+    "find_commit_signers_cmd" =>
+       "hg log " .
+           "--template='HgSubject: {desc}\\n'" .
+           " -r \$commit",
+    "find_commit_author_cmd" =>
+       "hg log " .
+           "--template='HgCommit: {node}\\n" .
+                       "HgAuthor: {author}\\n" .
+                       "HgSubject: {desc|firstline}\\n'" .
+           " -r \$commit",
+    "blame_range_cmd" => "",           # not supported
+    "blame_file_cmd" => "hg blame -n \$file",
+    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([ 0-9a-f]+):",
+    "author_pattern" => "^HgAuthor: (.*)",
+    "subject_pattern" => "^HgSubject: (.*)",
+);
+
+my $conf = which_conf(".get_maintainer.conf");
+if (-f $conf) {
+    my @conf_args;
+    open(my $conffile, '<', "$conf")
+       or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+
+    while (<$conffile>) {
+       my $line = $_;
+
+       $line =~ s/\s*\n?$//g;
+       $line =~ s/^\s*//g;
+       $line =~ s/\s+/ /g;
+
+       next if ($line =~ m/^\s*#/);
+       next if ($line =~ m/^\s*$/);
+
+       my @words = split(" ", $line);
+       foreach my $word (@words) {
+           last if ($word =~ m/^#/);
+           push (@conf_args, $word);
+       }
+    }
+    close($conffile);
+    unshift(@ARGV, @conf_args) if @conf_args;
+}
+
+if (!GetOptions(
+               'email!' => \$email,
+               'git!' => \$email_git,
+               'git-all-signature-types!' => \$email_git_all_signature_types,
+               'git-blame!' => \$email_git_blame,
+               'git-blame-signatures!' => \$email_git_blame_signatures,
+               'git-fallback!' => \$email_git_fallback,
+               'git-chief-penguins!' => \$email_git_penguin_chiefs,
+               'git-min-signatures=i' => \$email_git_min_signatures,
+               'git-max-maintainers=i' => \$email_git_max_maintainers,
+               'git-min-percent=i' => \$email_git_min_percent,
+               'git-since=s' => \$email_git_since,
+               'hg-since=s' => \$email_hg_since,
+               'i|interactive!' => \$interactive,
+               'remove-duplicates!' => \$email_remove_duplicates,
+               'mailmap!' => \$email_use_mailmap,
+               'm!' => \$email_maintainer,
+               'n!' => \$email_usename,
+               'l!' => \$email_list,
+               's!' => \$email_subscriber_list,
+               'multiline!' => \$output_multiline,
+               'roles!' => \$output_roles,
+               'rolestats!' => \$output_rolestats,
+               'separator=s' => \$output_separator,
+               'subsystem!' => \$subsystem,
+               'status!' => \$status,
+               'scm!' => \$scm,
+               'web!' => \$web,
+               'pattern-depth=i' => \$pattern_depth,
+               'k|keywords!' => \$keywords,
+               'sections!' => \$sections,
+               'fe|file-emails!' => \$file_emails,
+               'f|file' => \$from_filename,
+               'v|version' => \$version,
+               'h|help|usage' => \$help,
+               )) {
+    die "$P: invalid argument - use --help if necessary\n";
+}
+
+if ($help != 0) {
+    usage();
+    exit 0;
+}
+
+if ($version != 0) {
+    print("${P} ${V}\n");
+    exit 0;
+}
+
+if (-t STDIN && !@ARGV) {
+    # We're talking to a terminal, but have no command line arguments.
+    die "$P: missing patchfile or -f file - use --help if necessary\n";
+}
+
+$output_multiline = 0 if ($output_separator ne ", ");
+$output_rolestats = 1 if ($interactive);
+$output_roles = 1 if ($output_rolestats);
+
+if ($sections) {
+    $email = 0;
+    $email_list = 0;
+    $scm = 0;
+    $status = 0;
+    $subsystem = 0;
+    $web = 0;
+    $keywords = 0;
+    $interactive = 0;
+} else {
+    my $selections = $email + $scm + $status + $subsystem + $web;
+    if ($selections == 0) {
+       die "$P:  Missing required option: email, scm, status, subsystem or web\n";
+    }
+}
+
+if ($email &&
+    ($email_maintainer + $email_list + $email_subscriber_list +
+     $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
+    die "$P: Please select at least 1 email option\n";
+}
+
+if (!top_of_tree($lk_path)) {
+    die "$P: The current directory does not appear to be "
+       . "a QEMU source tree.\n";
+}
+
+## Read MAINTAINERS for type/value pairs
+
+my @typevalue = ();
+my %keyword_hash;
+
+open (my $maint, '<', "${lk_path}MAINTAINERS")
+    or die "$P: Can't open MAINTAINERS: $!\n";
+while (<$maint>) {
+    my $line = $_;
+
+    if ($line =~ m/^(\C):\s*(.*)/) {
+       my $type = $1;
+       my $value = $2;
+
+       ##Filename pattern matching
+       if ($type eq "F" || $type eq "X") {
+           $value =~ s@\.@\\\.@g;       ##Convert . to \.
+           $value =~ s/\*/\.\*/g;       ##Convert * to .*
+           $value =~ s/\?/\./g;         ##Convert ? to .
+           ##if pattern is a directory and it lacks a trailing slash, add one
+           if ((-d $value)) {
+               $value =~ s@([^/])$@$1/@;
+           }
+       } elsif ($type eq "K") {
+           $keyword_hash{@typevalue} = $value;
+       }
+       push(@typevalue, "$type:$value");
+    } elsif (!/^(\s)*$/) {
+       $line =~ s/\n$//g;
+       push(@typevalue, $line);
+    }
+}
+close($maint);
+
+
+#
+# Read mail address map
+#
+
+my $mailmap;
+
+read_mailmap();
+
+sub read_mailmap {
+    $mailmap = {
+       names => {},
+       addresses => {}
+    };
+
+    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+
+    open(my $mailmap_file, '<', "${lk_path}.mailmap")
+       or warn "$P: Can't open .mailmap: $!\n";
+
+    while (<$mailmap_file>) {
+       s/#.*$//; #strip comments
+       s/^\s+|\s+$//g; #trim
+
+       next if (/^\s*$/); #skip empty lines
+       #entries have one of the following formats:
+       # name1 <mail1>
+       # <mail1> <mail2>
+       # name1 <mail1> <mail2>
+       # name1 <mail1> name2 <mail2>
+       # (see man git-shortlog)
+       if (/^(.+)<(.+)>$/) {
+           my $real_name = $1;
+           my $address = $2;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $address) = parse_email("$real_name <$address>");
+           $mailmap->{names}->{$address} = $real_name;
+
+       } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
+           my $real_address = $1;
+           my $wrong_address = $2;
+
+           $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+       } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
+           my $real_name = $1;
+           my $real_address = $2;
+           my $wrong_address = $3;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $real_address) =
+               parse_email("$real_name <$real_address>");
+           $mailmap->{names}->{$wrong_address} = $real_name;
+           $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+       } elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) {
+           my $real_name = $1;
+           my $real_address = $2;
+           my $wrong_name = $3;
+           my $wrong_address = $4;
+
+           $real_name =~ s/\s+$//;
+           ($real_name, $real_address) =
+               parse_email("$real_name <$real_address>");
+
+           $wrong_name =~ s/\s+$//;
+           ($wrong_name, $wrong_address) =
+               parse_email("$wrong_name <$wrong_address>");
+
+           my $wrong_email = format_email($wrong_name, $wrong_address, 1);
+           $mailmap->{names}->{$wrong_email} = $real_name;
+           $mailmap->{addresses}->{$wrong_email} = $real_address;
+       }
+    }
+    close($mailmap_file);
+}
+
+## use the filenames on the command line or find the filenames in the patchfiles
+
+my @files = ();
+my @range = ();
+my @keyword_tvi = ();
+my @file_emails = ();
+
+if (!@ARGV) {
+    push(@ARGV, "&STDIN");
+}
+
+foreach my $file (@ARGV) {
+    if ($file ne "&STDIN") {
+       ##if $file is a directory and it lacks a trailing slash, add one
+       if ((-d $file)) {
+           $file =~ s@([^/])$@$1/@;
+       } elsif (!(-f $file)) {
+           die "$P: file '${file}' not found\n";
+       }
+    }
+    if ($from_filename) {
+       push(@files, $file);
+       if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
+           open(my $f, '<', $file)
+               or die "$P: Can't open $file: $!\n";
+           my $text = do { local($/) ; <$f> };
+           close($f);
+           if ($keywords) {
+               foreach my $line (keys %keyword_hash) {
+                   if ($text =~ m/$keyword_hash{$line}/x) {
+                       push(@keyword_tvi, $line);
+                   }
+               }
+           }
+           if ($file_emails) {
+               my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g;
+               push(@file_emails, clean_file_emails(@poss_addr));
+           }
+       }
+    } else {
+       my $file_cnt = @files;
+       my $lastfile;
+
+       open(my $patch, "< $file")
+           or die "$P: Can't open $file: $!\n";
+
+       # We can check arbitrary information before the patch
+       # like the commit message, mail headers, etc...
+       # This allows us to match arbitrary keywords against any part
+       # of a git format-patch generated file (subject tags, etc...)
+
+       my $patch_prefix = "";                  #Parsing the intro
+
+       while (<$patch>) {
+           my $patch_line = $_;
+           if (m/^\+\+\+\s+(\S+)/) {
+               my $filename = $1;
+               $filename =~ s@^[^/]*/@@;
+               $filename =~ s@\n@@;
+               $lastfile = $filename;
+               push(@files, $filename);
+               $patch_prefix = "^[+-].*";      #Now parsing the actual patch
+           } elsif (m/^\@\@ -(\d+),(\d+)/) {
+               if ($email_git_blame) {
+                   push(@range, "$lastfile:$1:$2");
+               }
+           } elsif ($keywords) {
+               foreach my $line (keys %keyword_hash) {
+                   if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
+                       push(@keyword_tvi, $line);
+                   }
+               }
+           }
+       }
+       close($patch);
+
+       if ($file_cnt == @files) {
+           warn "$P: file '${file}' doesn't appear to be a patch.  "
+               . "Add -f to options?\n";
+       }
+       @files = sort_and_uniq(@files);
+    }
+}
+
+@file_emails = uniq(@file_emails);
+
+my %email_hash_name;
+my %email_hash_address;
+my @email_to = ();
+my %hash_list_to;
+my @list_to = ();
+my @scm = ();
+my @web = ();
+my @subsystem = ();
+my @status = ();
+my %deduplicate_name_hash = ();
+my %deduplicate_address_hash = ();
+my $signature_pattern;
+
+my @maintainers = get_maintainers();
+
+if (@maintainers) {
+    @maintainers = merge_email(@maintainers);
+    output(@maintainers);
+}
+
+if ($scm) {
+    @scm = uniq(@scm);
+    output(@scm);
+}
+
+if ($status) {
+    @status = uniq(@status);
+    output(@status);
+}
+
+if ($subsystem) {
+    @subsystem = uniq(@subsystem);
+    output(@subsystem);
+}
+
+if ($web) {
+    @web = uniq(@web);
+    output(@web);
+}
+
+exit($exit);
+
+sub range_is_maintained {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+       my $line = $typevalue[$i];
+       if ($line =~ m/^(\C):\s*(.*)/) {
+           my $type = $1;
+           my $value = $2;
+           if ($type eq 'S') {
+               if ($value =~ /(maintain|support)/i) {
+                   return 1;
+               }
+           }
+       }
+    }
+    return 0;
+}
+
+sub range_has_maintainer {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+       my $line = $typevalue[$i];
+       if ($line =~ m/^(\C):\s*(.*)/) {
+           my $type = $1;
+           my $value = $2;
+           if ($type eq 'M') {
+               return 1;
+           }
+       }
+    }
+    return 0;
+}
+
+sub get_maintainers {
+    %email_hash_name = ();
+    %email_hash_address = ();
+    %commit_author_hash = ();
+    %commit_signer_hash = ();
+    @email_to = ();
+    %hash_list_to = ();
+    @list_to = ();
+    @scm = ();
+    @web = ();
+    @subsystem = ();
+    @status = ();
+    %deduplicate_name_hash = ();
+    %deduplicate_address_hash = ();
+    if ($email_git_all_signature_types) {
+       $signature_pattern = "(.+?)[Bb][Yy]:";
+    } else {
+       $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+    }
+
+    # Find responsible parties
+
+    my %exact_pattern_match_hash = ();
+
+    foreach my $file (@files) {
+
+       my %hash;
+       my $tvi = find_first_section();
+       while ($tvi < @typevalue) {
+           my $start = find_starting_index($tvi);
+           my $end = find_ending_index($tvi);
+           my $exclude = 0;
+           my $i;
+
+           #Do not match excluded file patterns
+
+           for ($i = $start; $i < $end; $i++) {
+               my $line = $typevalue[$i];
+               if ($line =~ m/^(\C):\s*(.*)/) {
+                   my $type = $1;
+                   my $value = $2;
+                   if ($type eq 'X') {
+                       if (file_match_pattern($file, $value)) {
+                           $exclude = 1;
+                           last;
+                       }
+                   }
+               }
+           }
+
+           if (!$exclude) {
+               for ($i = $start; $i < $end; $i++) {
+                   my $line = $typevalue[$i];
+                   if ($line =~ m/^(\C):\s*(.*)/) {
+                       my $type = $1;
+                       my $value = $2;
+                       if ($type eq 'F') {
+                           if (file_match_pattern($file, $value)) {
+                               my $value_pd = ($value =~ tr@/@@);
+                               my $file_pd = ($file  =~ tr@/@@);
+                               $value_pd++ if (substr($value,-1,1) ne "/");
+                               $value_pd = -1 if ($value =~ /^\.\*/);
+                               if ($value_pd >= $file_pd &&
+                                   range_is_maintained($start, $end) &&
+                                   range_has_maintainer($start, $end)) {
+                                   $exact_pattern_match_hash{$file} = 1;
+                               }
+                               if ($pattern_depth == 0 ||
+                                   (($file_pd - $value_pd) < $pattern_depth)) {
+                                   $hash{$tvi} = $value_pd;
+                               }
+                           }
+                       }
+                   }
+               }
+           }
+           $tvi = $end + 1;
+       }
+
+       foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+           add_categories($line);
+           if ($sections) {
+               my $i;
+               my $start = find_starting_index($line);
+               my $end = find_ending_index($line);
+               for ($i = $start; $i < $end; $i++) {
+                   my $line = $typevalue[$i];
+                   if ($line =~ /^[FX]:/) {            ##Restore file patterns
+                       $line =~ s/([^\\])\.([^\*])/$1\?$2/g;
+                       $line =~ s/([^\\])\.$/$1\?/g;   ##Convert . back to ?
+                       $line =~ s/\\\./\./g;           ##Convert \. to .
+                       $line =~ s/\.\*/\*/g;           ##Convert .* to *
+                   }
+                   $line =~ s/^([A-Z]):/$1:\t/g;
+                   print("$line\n");
+               }
+               print("\n");
+           }
+       }
+    }
+
+    if ($keywords) {
+       @keyword_tvi = sort_and_uniq(@keyword_tvi);
+       foreach my $line (@keyword_tvi) {
+           add_categories($line);
+       }
+    }
+
+    foreach my $email (@email_to, @list_to) {
+       $email->[0] = deduplicate_email($email->[0]);
+    }
+
+    foreach my $file (@files) {
+       if ($email &&
+           ($email_git || ($email_git_fallback &&
+                           !$exact_pattern_match_hash{$file}))) {
+           vcs_file_signoffs($file);
+       }
+       if ($email && $email_git_blame) {
+           vcs_file_blame($file);
+       }
+    }
+
+    if ($email) {
+       foreach my $chief (@penguin_chief) {
+           if ($chief =~ m/^(.*):(.*)/) {
+               my $email_address;
+
+               $email_address = format_email($1, $2, $email_usename);
+               if ($email_git_penguin_chiefs) {
+                   push(@email_to, [$email_address, 'chief penguin']);
+               } else {
+                   @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+               }
+           }
+       }
+
+       foreach my $email (@file_emails) {
+           my ($name, $address) = parse_email($email);
+
+           my $tmp_email = format_email($name, $address, $email_usename);
+           push_email_address($tmp_email, '');
+           add_role($tmp_email, 'in file');
+       }
+    }
+
+    my @to = ();
+    if ($email || $email_list) {
+       if ($email) {
+           @to = (@to, @email_to);
+       }
+       if ($email_list) {
+           @to = (@to, @list_to);
+       }
+    }
+
+    if ($interactive) {
+       @to = interactive_get_maintainers(\@to);
+    }
+
+    return @to;
+}
+
+sub file_match_pattern {
+    my ($file, $pattern) = @_;
+    if (substr($pattern, -1) eq "/") {
+       if ($file =~ m@^$pattern@) {
+           return 1;
+       }
+    } else {
+       if ($file =~ m@^$pattern@) {
+           my $s1 = ($file =~ tr@/@@);
+           my $s2 = ($pattern =~ tr@/@@);
+           if ($s1 == $s2) {
+               return 1;
+           }
+       }
+    }
+    return 0;
+}
+
+sub usage {
+    print <<EOT;
+usage: $P [options] patchfile
+       $P [options] -f file|directory
+version: $V
+
+MAINTAINER field selection options:
+  --email => print email address(es) if any
+    --git => include recent git \*-by: signers
+    --git-all-signature-types => include signers regardless of signature type
+        or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
+    --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
+    --git-chief-penguins => include ${penguin_chiefs}
+    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
+    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
+    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
+    --git-blame => use git blame to find modified commits for patch or file
+    --git-since => git history to use (default: $email_git_since)
+    --hg-since => hg history to use (default: $email_hg_since)
+    --interactive => display a menu (mostly useful if used with the --git option)
+    --m => include maintainer(s) if any
+    --n => include name 'Full Name <addr\@domain.tld>'
+    --l => include list(s) if any
+    --s => include subscriber only list(s) if any
+    --remove-duplicates => minimize duplicate email names/addresses
+    --roles => show roles (status:subsystem, git-signer, list, etc...)
+    --rolestats => show roles and statistics (commits/total_commits, %)
+    --file-emails => add email addresses found in -f file (default: 0 (off))
+  --scm => print SCM tree(s) if any
+  --status => print status if any
+  --subsystem => print subsystem name if any
+  --web => print website(s) if any
+
+Output type options:
+  --separator [, ] => separator for multiple entries on 1 line
+    using --separator also sets --nomultiline if --separator is not [, ]
+  --multiline => print 1 entry per line
+
+Other options:
+  --pattern-depth => Number of pattern directory traversals (default: 0 (all))
+  --keywords => scan patch for keywords (default: $keywords)
+  --sections => print all of the subsystem sections with pattern matches
+  --mailmap => use .mailmap file (default: $email_use_mailmap)
+  --version => show version
+  --help => show this help information
+
+Default options:
+  [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0
+   --remove-duplicates --rolestats]
+
+Notes:
+  Using "-f directory" may give unexpected results:
+      Used with "--git", git signators for _all_ files in and below
+          directory are examined as git recurses directories.
+          Any specified X: (exclude) pattern matches are _not_ ignored.
+      Used with "--nogit", directory is used as a pattern match,
+          no individual file within the directory or subdirectory
+          is matched.
+      Used with "--git-blame", does not iterate all files in directory
+  Using "--git-blame" is slow and may add old committers and authors
+      that are no longer active maintainers to the output.
+  Using "--roles" or "--rolestats" with git send-email --cc-cmd or any
+      other automated tools that expect only ["name"] <email address>
+      may not work because of additional output after <email address>.
+  Using "--rolestats" and "--git-blame" shows the #/total=% commits,
+      not the percentage of the entire file authored.  # of commits is
+      not a good measure of amount of code authored.  1 major commit may
+      contain a thousand lines, 5 trivial commits may modify a single line.
+  If git is not installed, but mercurial (hg) is installed and an .hg
+      repository exists, the following options apply to mercurial:
+          --git,
+          --git-min-signatures, --git-max-maintainers, --git-min-percent, and
+          --git-blame
+      Use --hg-since not --git-since to control date selection
+  File ".get_maintainer.conf", if it exists in the QEMU source root
+      directory, can change whatever get_maintainer defaults are desired.
+      Entries in this file can be any command line argument.
+      This file is prepended to any additional command line arguments.
+      Multiple lines and # comments are allowed.
+EOT
+}
+
+sub top_of_tree {
+    my ($lk_path) = @_;
+
+    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
+       $lk_path .= "/";
+    }
+    if (    (-f "${lk_path}COPYING")
+        && (-f "${lk_path}MAINTAINERS")
+        && (-f "${lk_path}Makefile")
+        && (-d "${lk_path}docs")
+        && (-f "${lk_path}VERSION")
+        && (-f "${lk_path}vl.c")) {
+       return 1;
+    }
+    return 0;
+}
+
+sub parse_email {
+    my ($formatted_email) = @_;
+
+    my $name = "";
+    my $address = "";
+
+    if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
+       $name = $1;
+       $address = $2;
+    } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
+       $address = $1;
+    } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
+       $address = $1;
+    }
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {         ##has "must quote" chars
+       $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+       $name = "\"$name\"";
+    }
+
+    return ($name, $address);
+}
+
+sub format_email {
+    my ($name, $address, $usename) = @_;
+
+    my $formatted_email;
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
+       $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+       $name = "\"$name\"";
+    }
+
+    if ($usename) {
+       if ("$name" eq "") {
+           $formatted_email = "$address";
+       } else {
+           $formatted_email = "$name <$address>";
+       }
+    } else {
+       $formatted_email = $address;
+    }
+
+    return $formatted_email;
+}
+
+sub find_first_section {
+    my $index = 0;
+
+    while ($index < @typevalue) {
+       my $tv = $typevalue[$index];
+       if (($tv =~ m/^(\C):\s*(.*)/)) {
+           last;
+       }
+       $index++;
+    }
+
+    return $index;
+}
+
+sub find_starting_index {
+    my ($index) = @_;
+
+    while ($index > 0) {
+       my $tv = $typevalue[$index];
+       if (!($tv =~ m/^(\C):\s*(.*)/)) {
+           last;
+       }
+       $index--;
+    }
+
+    return $index;
+}
+
+sub find_ending_index {
+    my ($index) = @_;
+
+    while ($index < @typevalue) {
+       my $tv = $typevalue[$index];
+       if (!($tv =~ m/^(\C):\s*(.*)/)) {
+           last;
+       }
+       $index++;
+    }
+
+    return $index;
+}
+
+sub get_maintainer_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $role;
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+       $subsystem = substr($subsystem, 0, 17);
+       $subsystem =~ s/\s*$//;
+       $subsystem = $subsystem . "...";
+    }
+
+    for ($i = $start + 1; $i < $end; $i++) {
+       my $tv = $typevalue[$i];
+       if ($tv =~ m/^(\C):\s*(.*)/) {
+           my $ptype = $1;
+           my $pvalue = $2;
+           if ($ptype eq "S") {
+               $role = $pvalue;
+           }
+       }
+    }
+
+    $role = lc($role);
+    if      ($role eq "supported") {
+       $role = "supporter";
+    } elsif ($role eq "maintained") {
+       $role = "maintainer";
+    } elsif ($role eq "odd fixes") {
+       $role = "odd fixer";
+    } elsif ($role eq "orphan") {
+       $role = "orphan minder";
+    } elsif ($role eq "obsolete") {
+       $role = "obsolete minder";
+    } elsif ($role eq "buried alive in reporters") {
+       $role = "chief penguin";
+    }
+
+    return $role . ":" . $subsystem;
+}
+
+sub get_list_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+       $subsystem = substr($subsystem, 0, 17);
+       $subsystem =~ s/\s*$//;
+       $subsystem = $subsystem . "...";
+    }
+
+    if ($subsystem eq "THE REST") {
+       $subsystem = "";
+    }
+
+    return $subsystem;
+}
+
+sub add_categories {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    push(@subsystem, $typevalue[$start]);
+
+    for ($i = $start + 1; $i < $end; $i++) {
+       my $tv = $typevalue[$i];
+       if ($tv =~ m/^(\C):\s*(.*)/) {
+           my $ptype = $1;
+           my $pvalue = $2;
+           if ($ptype eq "L") {
+               my $list_address = $pvalue;
+               my $list_additional = "";
+               my $list_role = get_list_role($i);
+
+               if ($list_role ne "") {
+                   $list_role = ":" . $list_role;
+               }
+               if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
+                   $list_address = $1;
+                   $list_additional = $2;
+               }
+               if ($list_additional =~ m/subscribers-only/) {
+                   if ($email_subscriber_list) {
+                       if (!$hash_list_to{lc($list_address)}) {
+                           $hash_list_to{lc($list_address)} = 1;
+                           push(@list_to, [$list_address,
+                                           "subscriber list${list_role}"]);
+                       }
+                   }
+               } else {
+                   if ($email_list) {
+                       if (!$hash_list_to{lc($list_address)}) {
+                           $hash_list_to{lc($list_address)} = 1;
+                           push(@list_to, [$list_address,
+                                           "open list${list_role}"]);
+                       }
+                   }
+               }
+           } elsif ($ptype eq "M") {
+               my ($name, $address) = parse_email($pvalue);
+               if ($name eq "") {
+                   if ($i > 0) {
+                       my $tv = $typevalue[$i - 1];
+                       if ($tv =~ m/^(\C):\s*(.*)/) {
+                           if ($1 eq "P") {
+                               $name = $2;
+                               $pvalue = format_email($name, $address, $email_usename);
+                           }
+                       }
+                   }
+               }
+               if ($email_maintainer) {
+                   my $role = get_maintainer_role($i);
+                   push_email_addresses($pvalue, $role);
+               }
+           } elsif ($ptype eq "T") {
+               push(@scm, $pvalue);
+           } elsif ($ptype eq "W") {
+               push(@web, $pvalue);
+           } elsif ($ptype eq "S") {
+               push(@status, $pvalue);
+           }
+       }
+    }
+}
+
+sub email_inuse {
+    my ($name, $address) = @_;
+
+    return 1 if (($name eq "") && ($address eq ""));
+    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
+    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
+
+    return 0;
+}
+
+sub push_email_address {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+
+    if ($address eq "") {
+       return 0;
+    }
+
+    if (!$email_remove_duplicates) {
+       push(@email_to, [format_email($name, $address, $email_usename), $role]);
+    } elsif (!email_inuse($name, $address)) {
+       push(@email_to, [format_email($name, $address, $email_usename), $role]);
+       $email_hash_name{lc($name)}++ if ($name ne "");
+       $email_hash_address{lc($address)}++;
+    }
+
+    return 1;
+}
+
+sub push_email_addresses {
+    my ($address, $role) = @_;
+
+    my @address_list = ();
+
+    if (rfc822_valid($address)) {
+       push_email_address($address, $role);
+    } elsif (@address_list = rfc822_validlist($address)) {
+       my $array_count = shift(@address_list);
+       while (my $entry = shift(@address_list)) {
+           push_email_address($entry, $role);
+       }
+    } else {
+       if (!push_email_address($address, $role)) {
+           warn("Invalid MAINTAINERS address: '" . $address . "'\n");
+       }
+    }
+}
+
+sub add_role {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, $email_usename);
+
+    foreach my $entry (@email_to) {
+       if ($email_remove_duplicates) {
+           my ($entry_name, $entry_address) = parse_email($entry->[0]);
+           if (($name eq $entry_name || $address eq $entry_address)
+               && ($role eq "" || !($entry->[1] =~ m/$role/))
+           ) {
+               if ($entry->[1] eq "") {
+                   $entry->[1] = "$role";
+               } else {
+                   $entry->[1] = "$entry->[1],$role";
+               }
+           }
+       } else {
+           if ($email eq $entry->[0]
+               && ($role eq "" || !($entry->[1] =~ m/$role/))
+           ) {
+               if ($entry->[1] eq "") {
+                   $entry->[1] = "$role";
+               } else {
+                   $entry->[1] = "$entry->[1],$role";
+               }
+           }
+       }
+    }
+}
+
+sub which {
+    my ($bin) = @_;
+
+    foreach my $path (split(/:/, $ENV{PATH})) {
+       if (-e "$path/$bin") {
+           return "$path/$bin";
+       }
+    }
+
+    return "";
+}
+
+sub which_conf {
+    my ($conf) = @_;
+
+    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+       if (-e "$path/$conf") {
+           return "$path/$conf";
+       }
+    }
+
+    return "";
+}
+
+sub mailmap_email {
+    my ($line) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, 1);
+    my $real_name = $name;
+    my $real_address = $address;
+
+    if (exists $mailmap->{names}->{$email} ||
+       exists $mailmap->{addresses}->{$email}) {
+       if (exists $mailmap->{names}->{$email}) {
+           $real_name = $mailmap->{names}->{$email};
+       }
+       if (exists $mailmap->{addresses}->{$email}) {
+           $real_address = $mailmap->{addresses}->{$email};
+       }
+    } else {
+       if (exists $mailmap->{names}->{$address}) {
+           $real_name = $mailmap->{names}->{$address};
+       }
+       if (exists $mailmap->{addresses}->{$address}) {
+           $real_address = $mailmap->{addresses}->{$address};
+       }
+    }
+    return format_email($real_name, $real_address, 1);
+}
+
+sub mailmap {
+    my (@addresses) = @_;
+
+    my @mapped_emails = ();
+    foreach my $line (@addresses) {
+       push(@mapped_emails, mailmap_email($line));
+    }
+    merge_by_realname(@mapped_emails) if ($email_use_mailmap);
+    return @mapped_emails;
+}
+
+sub merge_by_realname {
+    my %address_map;
+    my (@emails) = @_;
+
+    foreach my $email (@emails) {
+       my ($name, $address) = parse_email($email);
+       if (exists $address_map{$name}) {
+           $address = $address_map{$name};
+           $email = format_email($name, $address, 1);
+       } else {
+           $address_map{$name} = $address;
+       }
+    }
+}
+
+sub git_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    $output =~ s/^\s*//gm;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub hg_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub extract_formatted_signatures {
+    my (@signature_lines) = @_;
+
+    my @type = @signature_lines;
+
+    s/\s*(.*):.*/$1/ for (@type);
+
+    # cut -f2- -d":"
+    s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
+
+## Reformat email addresses (with names) to avoid badly written signatures
+
+    foreach my $signer (@signature_lines) {
+       $signer = deduplicate_email($signer);
+    }
+
+    return (\@type, \@signature_lines);
+}
+
+sub vcs_find_signers {
+    my ($cmd) = @_;
+    my $commits;
+    my @lines = ();
+    my @signatures = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    my $pattern = $VCS_cmds{"commit_pattern"};
+
+    $commits = grep(/$pattern/, @lines);       # of commits
+
+    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
+
+    return (0, @signatures) if !@signatures;
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    if (!$email_git_penguin_chiefs) {
+       @signatures = grep(!/${penguin_chiefs}/i, @signatures);
+    }
+
+    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+
+    return ($commits, @$signers_ref);
+}
+
+sub vcs_find_author {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    if (!$email_git_penguin_chiefs) {
+       @lines = grep(!/${penguin_chiefs}/i, @lines);
+    }
+
+    return @lines if !@lines;
+
+    my @authors = ();
+    foreach my $line (@lines) {
+       if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+           my $author = $1;
+           my ($name, $address) = parse_email($author);
+           $author = format_email($name, $address, 1);
+           push(@authors, $author);
+       }
+    }
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    return @authors;
+}
+
+sub vcs_save_commits {
+    my ($cmd) = @_;
+    my @lines = ();
+    my @commits = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    foreach my $line (@lines) {
+       if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
+           push(@commits, $1);
+       }
+    }
+
+    return @commits;
+}
+
+sub vcs_blame {
+    my ($file) = @_;
+    my $cmd;
+    my @commits = ();
+
+    return @commits if (!(-f $file));
+
+    if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
+       my @all_commits = ();
+
+       $cmd = $VCS_cmds{"blame_file_cmd"};
+       $cmd =~ s/(\$\w+)/$1/eeg;               #interpolate $cmd
+       @all_commits = vcs_save_commits($cmd);
+
+       foreach my $file_range_diff (@range) {
+           next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+           my $diff_file = $1;
+           my $diff_start = $2;
+           my $diff_length = $3;
+           next if ("$file" ne "$diff_file");
+           for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
+               push(@commits, $all_commits[$i]);
+           }
+       }
+    } elsif (@range) {
+       foreach my $file_range_diff (@range) {
+           next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+           my $diff_file = $1;
+           my $diff_start = $2;
+           my $diff_length = $3;
+           next if ("$file" ne "$diff_file");
+           $cmd = $VCS_cmds{"blame_range_cmd"};
+           $cmd =~ s/(\$\w+)/$1/eeg;           #interpolate $cmd
+           push(@commits, vcs_save_commits($cmd));
+       }
+    } else {
+       $cmd = $VCS_cmds{"blame_file_cmd"};
+       $cmd =~ s/(\$\w+)/$1/eeg;               #interpolate $cmd
+       @commits = vcs_save_commits($cmd);
+    }
+
+    foreach my $commit (@commits) {
+       $commit =~ s/^\^//g;
+    }
+
+    return @commits;
+}
+
+my $printed_novcs = 0;
+sub vcs_exists {
+    %VCS_cmds = %VCS_cmds_git;
+    return 1 if eval $VCS_cmds{"available"};
+    %VCS_cmds = %VCS_cmds_hg;
+    return 2 if eval $VCS_cmds{"available"};
+    %VCS_cmds = ();
+    if (!$printed_novcs) {
+       warn("$P: No supported VCS found.  Add --nogit to options?\n");
+       warn("Using a git repository produces better results.\n");
+       warn("Try latest git repository using:\n");
+       warn("git clone git://git.qemu.org/qemu.git\n");
+       $printed_novcs = 1;
+    }
+    return 0;
+}
+
+sub vcs_is_git {
+    vcs_exists();
+    return $vcs_used == 1;
+}
+
+sub vcs_is_hg {
+    return $vcs_used == 2;
+}
+
+sub interactive_get_maintainers {
+    my ($list_ref) = @_;
+    my @list = @$list_ref;
+
+    vcs_exists();
+
+    my %selected;
+    my %authored;
+    my %signed;
+    my $count = 0;
+    my $maintained = 0;
+    foreach my $entry (@list) {
+       $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
+       $selected{$count} = 1;
+       $authored{$count} = 0;
+       $signed{$count} = 0;
+       $count++;
+    }
+
+    #menu loop
+    my $done = 0;
+    my $print_options = 0;
+    my $redraw = 1;
+    while (!$done) {
+       $count = 0;
+       if ($redraw) {
+           printf STDERR "\n%1s %2s %-65s",
+                         "*", "#", "email/list and role:stats";
+           if ($email_git ||
+               ($email_git_fallback && !$maintained) ||
+               $email_git_blame) {
+               print STDERR "auth sign";
+           }
+           print STDERR "\n";
+           foreach my $entry (@list) {
+               my $email = $entry->[0];
+               my $role = $entry->[1];
+               my $sel = "";
+               $sel = "*" if ($selected{$count});
+               my $commit_author = $commit_author_hash{$email};
+               my $commit_signer = $commit_signer_hash{$email};
+               my $authored = 0;
+               my $signed = 0;
+               $authored++ for (@{$commit_author});
+               $signed++ for (@{$commit_signer});
+               printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+               printf STDERR "%4d %4d", $authored, $signed
+                   if ($authored > 0 || $signed > 0);
+               printf STDERR "\n     %s\n", $role;
+               if ($authored{$count}) {
+                   my $commit_author = $commit_author_hash{$email};
+                   foreach my $ref (@{$commit_author}) {
+                       print STDERR "     Author: @{$ref}[1]\n";
+                   }
+               }
+               if ($signed{$count}) {
+                   my $commit_signer = $commit_signer_hash{$email};
+                   foreach my $ref (@{$commit_signer}) {
+                       print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
+                   }
+               }
+
+               $count++;
+           }
+       }
+       my $date_ref = \$email_git_since;
+       $date_ref = \$email_hg_since if (vcs_is_hg());
+       if ($print_options) {
+           $print_options = 0;
+           if (vcs_exists()) {
+               print STDERR <<EOT
+
+Version Control options:
+g  use git history      [$email_git]
+gf use git-fallback     [$email_git_fallback]
+b  use git blame        [$email_git_blame]
+bs use blame signatures [$email_git_blame_signatures]
+c# minimum commits      [$email_git_min_signatures]
+%# min percent          [$email_git_min_percent]
+d# history to use       [$$date_ref]
+x# max maintainers      [$email_git_max_maintainers]
+t  all signature types  [$email_git_all_signature_types]
+m  use .mailmap         [$email_use_mailmap]
+EOT
+           }
+           print STDERR <<EOT
+
+Additional options:
+0  toggle all
+tm toggle maintainers
+tg toggle git entries
+tl toggle open list entries
+ts toggle subscriber list entries
+f  emails in file       [$file_emails]
+k  keywords in file     [$keywords]
+r  remove duplicates    [$email_remove_duplicates]
+p# pattern match depth  [$pattern_depth]
+EOT
+       }
+       print STDERR
+"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+       my $input = <STDIN>;
+       chomp($input);
+
+       $redraw = 1;
+       my $rerun = 0;
+       my @wish = split(/[, ]+/, $input);
+       foreach my $nr (@wish) {
+           $nr = lc($nr);
+           my $sel = substr($nr, 0, 1);
+           my $str = substr($nr, 1);
+           my $val = 0;
+           $val = $1 if $str =~ /^(\d+)$/;
+
+           if ($sel eq "y") {
+               $interactive = 0;
+               $done = 1;
+               $output_rolestats = 0;
+               $output_roles = 0;
+               last;
+           } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
+               $selected{$nr - 1} = !$selected{$nr - 1};
+           } elsif ($sel eq "*" || $sel eq '^') {
+               my $toggle = 0;
+               $toggle = 1 if ($sel eq '*');
+               for (my $i = 0; $i < $count; $i++) {
+                   $selected{$i} = $toggle;
+               }
+           } elsif ($sel eq "0") {
+               for (my $i = 0; $i < $count; $i++) {
+                   $selected{$i} = !$selected{$i};
+               }
+           } elsif ($sel eq "t") {
+               if (lc($str) eq "m") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
+                   }
+               } elsif (lc($str) eq "g") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
+                   }
+               } elsif (lc($str) eq "l") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(open list)/i);
+                   }
+               } elsif (lc($str) eq "s") {
+                   for (my $i = 0; $i < $count; $i++) {
+                       $selected{$i} = !$selected{$i}
+                           if ($list[$i]->[1] =~ /^(subscriber list)/i);
+                   }
+               }
+           } elsif ($sel eq "a") {
+               if ($val > 0 && $val <= $count) {
+                   $authored{$val - 1} = !$authored{$val - 1};
+               } elsif ($str eq '*' || $str eq '^') {
+                   my $toggle = 0;
+                   $toggle = 1 if ($str eq '*');
+                   for (my $i = 0; $i < $count; $i++) {
+                       $authored{$i} = $toggle;
+                   }
+               }
+           } elsif ($sel eq "s") {
+               if ($val > 0 && $val <= $count) {
+                   $signed{$val - 1} = !$signed{$val - 1};
+               } elsif ($str eq '*' || $str eq '^') {
+                   my $toggle = 0;
+                   $toggle = 1 if ($str eq '*');
+                   for (my $i = 0; $i < $count; $i++) {
+                       $signed{$i} = $toggle;
+                   }
+               }
+           } elsif ($sel eq "o") {
+               $print_options = 1;
+               $redraw = 1;
+           } elsif ($sel eq "g") {
+               if ($str eq "f") {
+                   bool_invert(\$email_git_fallback);
+               } else {
+                   bool_invert(\$email_git);
+               }
+               $rerun = 1;
+           } elsif ($sel eq "b") {
+               if ($str eq "s") {
+                   bool_invert(\$email_git_blame_signatures);
+               } else {
+                   bool_invert(\$email_git_blame);
+               }
+               $rerun = 1;
+           } elsif ($sel eq "c") {
+               if ($val > 0) {
+                   $email_git_min_signatures = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "x") {
+               if ($val > 0) {
+                   $email_git_max_maintainers = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "%") {
+               if ($str ne "" && $val >= 0) {
+                   $email_git_min_percent = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "d") {
+               if (vcs_is_git()) {
+                   $email_git_since = $str;
+               } elsif (vcs_is_hg()) {
+                   $email_hg_since = $str;
+               }
+               $rerun = 1;
+           } elsif ($sel eq "t") {
+               bool_invert(\$email_git_all_signature_types);
+               $rerun = 1;
+           } elsif ($sel eq "f") {
+               bool_invert(\$file_emails);
+               $rerun = 1;
+           } elsif ($sel eq "r") {
+               bool_invert(\$email_remove_duplicates);
+               $rerun = 1;
+           } elsif ($sel eq "m") {
+               bool_invert(\$email_use_mailmap);
+               read_mailmap();
+               $rerun = 1;
+           } elsif ($sel eq "k") {
+               bool_invert(\$keywords);
+               $rerun = 1;
+           } elsif ($sel eq "p") {
+               if ($str ne "" && $val >= 0) {
+                   $pattern_depth = $val;
+                   $rerun = 1;
+               }
+           } elsif ($sel eq "h" || $sel eq "?") {
+               print STDERR <<EOT
+
+Interactive mode allows you to select the various maintainers, submitters,
+commit signers and mailing lists that could be CC'd on a patch.
+
+Any *'d entry is selected.
+
+If you have git or hg installed, you can choose to summarize the commit
+history of files in the patch.  Also, each line of the current file can
+be matched to its commit author and that commits signers with blame.
+
+Various knobs exist to control the length of time for active commit
+tracking, the maximum number of commit authors and signers to add,
+and such.
+
+Enter selections at the prompt until you are satisfied that the selected
+maintainers are appropriate.  You may enter multiple selections separated
+by either commas or spaces.
+
+EOT
+           } else {
+               print STDERR "invalid option: '$nr'\n";
+               $redraw = 0;
+           }
+       }
+       if ($rerun) {
+           print STDERR "git-blame can be very slow, please have patience..."
+               if ($email_git_blame);
+           goto &get_maintainers;
+       }
+    }
+
+    #drop not selected entries
+    $count = 0;
+    my @new_emailto = ();
+    foreach my $entry (@list) {
+       if ($selected{$count}) {
+           push(@new_emailto, $list[$count]);
+       }
+       $count++;
+    }
+    return @new_emailto;
+}
+
+sub bool_invert {
+    my ($bool_ref) = @_;
+
+    if ($$bool_ref) {
+       $$bool_ref = 0;
+    } else {
+       $$bool_ref = 1;
+    }
+}
+
+sub deduplicate_email {
+    my ($email) = @_;
+
+    my $matched = 0;
+    my ($name, $address) = parse_email($email);
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+
+    return $email if (!$email_remove_duplicates);
+
+    ($name, $address) = parse_email($email);
+
+    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
+       $name = $deduplicate_name_hash{lc($name)}->[0];
+       $address = $deduplicate_name_hash{lc($name)}->[1];
+       $matched = 1;
+    } elsif ($deduplicate_address_hash{lc($address)}) {
+       $name = $deduplicate_address_hash{lc($address)}->[0];
+       $address = $deduplicate_address_hash{lc($address)}->[1];
+       $matched = 1;
+    }
+    if (!$matched) {
+       $deduplicate_name_hash{lc($name)} = [ $name, $address ];
+       $deduplicate_address_hash{lc($address)} = [ $name, $address ];
+    }
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+    return $email;
+}
+
+sub save_commits_by_author {
+    my (@lines) = @_;
+
+    my @authors = ();
+    my @commits = ();
+    my @subjects = ();
+
+    foreach my $line (@lines) {
+       if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+           my $author = $1;
+           $author = deduplicate_email($author);
+           push(@authors, $author);
+       }
+       push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+       push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+    }
+
+    for (my $i = 0; $i < @authors; $i++) {
+       my $exists = 0;
+       foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
+           if (@{$ref}[0] eq $commits[$i] &&
+               @{$ref}[1] eq $subjects[$i]) {
+               $exists = 1;
+               last;
+           }
+       }
+       if (!$exists) {
+           push(@{$commit_author_hash{$authors[$i]}},
+                [ ($commits[$i], $subjects[$i]) ]);
+       }
+    }
+}
+
+sub save_commits_by_signer {
+    my (@lines) = @_;
+
+    my $commit = "";
+    my $subject = "";
+
+    foreach my $line (@lines) {
+       $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+       $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+       if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
+           my @signatures = ($line);
+           my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+           my @types = @$types_ref;
+           my @signers = @$signers_ref;
+
+           my $type = $types[0];
+           my $signer = $signers[0];
+
+           $signer = deduplicate_email($signer);
+
+           my $exists = 0;
+           foreach my $ref(@{$commit_signer_hash{$signer}}) {
+               if (@{$ref}[0] eq $commit &&
+                   @{$ref}[1] eq $subject &&
+                   @{$ref}[2] eq $type) {
+                   $exists = 1;
+                   last;
+               }
+           }
+           if (!$exists) {
+               push(@{$commit_signer_hash{$signer}},
+                    [ ($commit, $subject, $type) ]);
+           }
+       }
+    }
+}
+
+sub vcs_assign {
+    my ($role, $divisor, @lines) = @_;
+
+    my %hash;
+    my $count = 0;
+
+    return if (@lines <= 0);
+
+    if ($divisor <= 0) {
+       warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
+       $divisor = 1;
+    }
+
+    @lines = mailmap(@lines);
+
+    return if (@lines <= 0);
+
+    @lines = sort(@lines);
+
+    # uniq -c
+    $hash{$_}++ for @lines;
+
+    # sort -rn
+    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+       my $sign_offs = $hash{$line};
+       my $percent = $sign_offs * 100 / $divisor;
+
+       $percent = 100 if ($percent > 100);
+       $count++;
+       last if ($sign_offs < $email_git_min_signatures ||
+                $count > $email_git_max_maintainers ||
+                $percent < $email_git_min_percent);
+       push_email_address($line, '');
+       if ($output_rolestats) {
+           my $fmt_percent = sprintf("%.0f", $percent);
+           add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
+       } else {
+           add_role($line, $role);
+       }
+    }
+}
+
+sub vcs_file_signoffs {
+    my ($file) = @_;
+
+    my @signers = ();
+    my $commits;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    my $cmd = $VCS_cmds{"find_signers_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;          # interpolate $cmd
+
+    ($commits, @signers) = vcs_find_signers($cmd);
+
+    foreach my $signer (@signers) {
+       $signer = deduplicate_email($signer);
+    }
+
+    vcs_assign("commit_signer", $commits, @signers);
+}
+
+sub vcs_file_blame {
+    my ($file) = @_;
+
+    my @signers = ();
+    my @all_commits = ();
+    my @commits = ();
+    my $total_commits;
+    my $total_lines;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    @all_commits = vcs_blame($file);
+    @commits = uniq(@all_commits);
+    $total_commits = @commits;
+    $total_lines = @all_commits;
+
+    if ($email_git_blame_signatures) {
+       if (vcs_is_hg()) {
+           my $commit_count;
+           my @commit_signers = ();
+           my $commit = join(" -r ", @commits);
+           my $cmd;
+
+           $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+           $cmd =~ s/(\$\w+)/$1/eeg;   #substitute variables in $cmd
+
+           ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+           push(@signers, @commit_signers);
+       } else {
+           foreach my $commit (@commits) {
+               my $commit_count;
+               my @commit_signers = ();
+               my $cmd;
+
+               $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+               $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
+
+               ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+               push(@signers, @commit_signers);
+           }
+       }
+    }
+
+    if ($from_filename) {
+       if ($output_rolestats) {
+           my @blame_signers;
+           if (vcs_is_hg()) {{         # Double brace for last exit
+               my $commit_count;
+               my @commit_signers = ();
+               @commits = uniq(@commits);
+               @commits = sort(@commits);
+               my $commit = join(" -r ", @commits);
+               my $cmd;
+
+               $cmd = $VCS_cmds{"find_commit_author_cmd"};
+               $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
+
+               my @lines = ();
+
+               @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+               if (!$email_git_penguin_chiefs) {
+                   @lines = grep(!/${penguin_chiefs}/i, @lines);
+               }
+
+               last if !@lines;
+
+               my @authors = ();
+               foreach my $line (@lines) {
+                   if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+                       my $author = $1;
+                       $author = deduplicate_email($author);
+                       push(@authors, $author);
+                   }
+               }
+
+               save_commits_by_author(@lines) if ($interactive);
+               save_commits_by_signer(@lines) if ($interactive);
+
+               push(@signers, @authors);
+           }}
+           else {
+               foreach my $commit (@commits) {
+                   my $i;
+                   my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+                   $cmd =~ s/(\$\w+)/$1/eeg;   #interpolate $cmd
+                   my @author = vcs_find_author($cmd);
+                   next if !@author;
+
+                   my $formatted_author = deduplicate_email($author[0]);
+
+                   my $count = grep(/$commit/, @all_commits);
+                   for ($i = 0; $i < $count ; $i++) {
+                       push(@blame_signers, $formatted_author);
+                   }
+               }
+           }
+           if (@blame_signers) {
+               vcs_assign("authored lines", $total_lines, @blame_signers);
+           }
+       }
+       foreach my $signer (@signers) {
+           $signer = deduplicate_email($signer);
+       }
+       vcs_assign("commits", $total_commits, @signers);
+    } else {
+       foreach my $signer (@signers) {
+           $signer = deduplicate_email($signer);
+       }
+       vcs_assign("modified commits", $total_commits, @signers);
+    }
+}
+
+sub uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub sort_and_uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = sort @parms;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub clean_file_emails {
+    my (@file_emails) = @_;
+    my @fmt_emails = ();
+
+    foreach my $email (@file_emails) {
+       $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
+       my ($name, $address) = parse_email($email);
+       if ($name eq '"[,\.]"') {
+           $name = "";
+       }
+
+       my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
+       if (@nw > 2) {
+           my $first = $nw[@nw - 3];
+           my $middle = $nw[@nw - 2];
+           my $last = $nw[@nw - 1];
+
+           if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
+                (length($first) == 2 && substr($first, -1) eq ".")) ||
+               (length($middle) == 1 ||
+                (length($middle) == 2 && substr($middle, -1) eq "."))) {
+               $name = "$first $middle $last";
+           } else {
+               $name = "$middle $last";
+           }
+       }
+
+       if (substr($name, -1) =~ /[,\.]/) {
+           $name = substr($name, 0, length($name) - 1);
+       } elsif (substr($name, -2) =~ /[,\.]"/) {
+           $name = substr($name, 0, length($name) - 2) . '"';
+       }
+
+       if (substr($name, 0, 1) =~ /[,\.]/) {
+           $name = substr($name, 1, length($name) - 1);
+       } elsif (substr($name, 0, 2) =~ /"[,\.]/) {
+           $name = '"' . substr($name, 2, length($name) - 2);
+       }
+
+       my $fmt_email = format_email($name, $address, $email_usename);
+       push(@fmt_emails, $fmt_email);
+    }
+    return @fmt_emails;
+}
+
+sub merge_email {
+    my @lines;
+    my %saw;
+
+    for (@_) {
+       my ($address, $role) = @$_;
+       if (!$saw{$address}) {
+           if ($output_roles) {
+               push(@lines, "$address ($role)");
+           } else {
+               push(@lines, $address);
+           }
+           $saw{$address} = 1;
+       }
+    }
+
+    return @lines;
+}
+
+sub output {
+    my (@parms) = @_;
+
+    if ($output_multiline) {
+       foreach my $line (@parms) {
+           print("${line}\n");
+       }
+    } else {
+       print(join($output_separator, @parms));
+       print("\n");
+    }
+}
+
+my $rfc822re;
+
+sub make_rfc822re {
+#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
+#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
+#   This regexp will only work on addresses which have had comments stripped
+#   and replaced with rfc822_lwsp.
+
+    my $specials = '()<>@,;:\\\\".\\[\\]';
+    my $controls = '\\000-\\037\\177';
+
+    my $dtext = "[^\\[\\]\\r\\\\]";
+    my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
+
+    my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
+
+#   Use zero-width assertion to spot the limit of an atom.  A simple
+#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
+    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
+    my $word = "(?:$atom|$quoted_string)";
+    my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
+
+    my $sub_domain = "(?:$atom|$domain_literal)";
+    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
+
+    my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
+
+    my $phrase = "$word*";
+    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
+    my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
+    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
+
+    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
+    my $address = "(?:$mailbox|$group)";
+
+    return "$rfc822_lwsp*$address";
+}
+
+sub rfc822_strip_comments {
+    my $s = shift;
+#   Recursively remove comments, and replace with a single space.  The simpler
+#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
+#   chars in atoms, for example.
+
+    while ($s =~ s/^((?:[^"\\]|\\.)*
+                    (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
+                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
+    return $s;
+}
+
+#   valid: returns true if the parameter is an RFC822 valid address
+#
+sub rfc822_valid {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+
+    return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
+}
+
+#   validlist: In scalar context, returns true if the parameter is an RFC822
+#              valid list of addresses.
+#
+#              In list context, returns an empty list on failure (an invalid
+#              address was found); otherwise a list whose first element is the
+#              number of addresses found and whose remaining elements are the
+#              addresses.  This is needed to disambiguate failure (invalid)
+#              from success with no addresses found, because an empty string is
+#              a valid list.
+
+sub rfc822_validlist {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+    # * null list items are valid according to the RFC
+    # * the '1' business is to aid in distinguishing failure from no results
+
+    my @r;
+    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
+       $s =~ m/^$rfc822_char*$/) {
+        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
+            push(@r, $1);
+        }
+        return wantarray ? (scalar(@r), @r) : 1;
+    }
+    return wantarray ? () : 0;
+}
diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
new file mode 100755 (executable)
index 0000000..56d2bd7
--- /dev/null
@@ -0,0 +1,480 @@
+#!/usr/bin/python
+#
+# top-like utility for displaying kvm statistics
+#
+# Copyright 2006-2008 Qumranet Technologies
+# Copyright 2008-2011 Red Hat, Inc.
+#
+# Authors:
+#  Avi Kivity <avi@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import curses
+import sys, os, time, optparse
+
+class DebugfsProvider(object):
+    def __init__(self):
+        self.base = '/sys/kernel/debug/kvm'
+        self._fields = os.listdir(self.base)
+    def fields(self):
+        return self._fields
+    def select(self, fields):
+        self._fields = fields
+    def read(self):
+        def val(key):
+            return int(file(self.base + '/' + key).read())
+        return dict([(key, val(key)) for key in self._fields])
+
+vmx_exit_reasons = {
+    0: 'EXCEPTION_NMI',
+    1: 'EXTERNAL_INTERRUPT',
+    2: 'TRIPLE_FAULT',
+    7: 'PENDING_INTERRUPT',
+    8: 'NMI_WINDOW',
+    9: 'TASK_SWITCH',
+    10: 'CPUID',
+    12: 'HLT',
+    14: 'INVLPG',
+    15: 'RDPMC',
+    16: 'RDTSC',
+    18: 'VMCALL',
+    19: 'VMCLEAR',
+    20: 'VMLAUNCH',
+    21: 'VMPTRLD',
+    22: 'VMPTRST',
+    23: 'VMREAD',
+    24: 'VMRESUME',
+    25: 'VMWRITE',
+    26: 'VMOFF',
+    27: 'VMON',
+    28: 'CR_ACCESS',
+    29: 'DR_ACCESS',
+    30: 'IO_INSTRUCTION',
+    31: 'MSR_READ',
+    32: 'MSR_WRITE',
+    33: 'INVALID_STATE',
+    36: 'MWAIT_INSTRUCTION',
+    39: 'MONITOR_INSTRUCTION',
+    40: 'PAUSE_INSTRUCTION',
+    41: 'MCE_DURING_VMENTRY',
+    43: 'TPR_BELOW_THRESHOLD',
+    44: 'APIC_ACCESS',
+    48: 'EPT_VIOLATION',
+    49: 'EPT_MISCONFIG',
+    54: 'WBINVD',
+    55: 'XSETBV',
+}
+
+svm_exit_reasons = {
+    0x000: 'READ_CR0',
+    0x003: 'READ_CR3',
+    0x004: 'READ_CR4',
+    0x008: 'READ_CR8',
+    0x010: 'WRITE_CR0',
+    0x013: 'WRITE_CR3',
+    0x014: 'WRITE_CR4',
+    0x018: 'WRITE_CR8',
+    0x020: 'READ_DR0',
+    0x021: 'READ_DR1',
+    0x022: 'READ_DR2',
+    0x023: 'READ_DR3',
+    0x024: 'READ_DR4',
+    0x025: 'READ_DR5',
+    0x026: 'READ_DR6',
+    0x027: 'READ_DR7',
+    0x030: 'WRITE_DR0',
+    0x031: 'WRITE_DR1',
+    0x032: 'WRITE_DR2',
+    0x033: 'WRITE_DR3',
+    0x034: 'WRITE_DR4',
+    0x035: 'WRITE_DR5',
+    0x036: 'WRITE_DR6',
+    0x037: 'WRITE_DR7',
+    0x040: 'EXCP_BASE',
+    0x060: 'INTR',
+    0x061: 'NMI',
+    0x062: 'SMI',
+    0x063: 'INIT',
+    0x064: 'VINTR',
+    0x065: 'CR0_SEL_WRITE',
+    0x066: 'IDTR_READ',
+    0x067: 'GDTR_READ',
+    0x068: 'LDTR_READ',
+    0x069: 'TR_READ',
+    0x06a: 'IDTR_WRITE',
+    0x06b: 'GDTR_WRITE',
+    0x06c: 'LDTR_WRITE',
+    0x06d: 'TR_WRITE',
+    0x06e: 'RDTSC',
+    0x06f: 'RDPMC',
+    0x070: 'PUSHF',
+    0x071: 'POPF',
+    0x072: 'CPUID',
+    0x073: 'RSM',
+    0x074: 'IRET',
+    0x075: 'SWINT',
+    0x076: 'INVD',
+    0x077: 'PAUSE',
+    0x078: 'HLT',
+    0x079: 'INVLPG',
+    0x07a: 'INVLPGA',
+    0x07b: 'IOIO',
+    0x07c: 'MSR',
+    0x07d: 'TASK_SWITCH',
+    0x07e: 'FERR_FREEZE',
+    0x07f: 'SHUTDOWN',
+    0x080: 'VMRUN',
+    0x081: 'VMMCALL',
+    0x082: 'VMLOAD',
+    0x083: 'VMSAVE',
+    0x084: 'STGI',
+    0x085: 'CLGI',
+    0x086: 'SKINIT',
+    0x087: 'RDTSCP',
+    0x088: 'ICEBP',
+    0x089: 'WBINVD',
+    0x08a: 'MONITOR',
+    0x08b: 'MWAIT',
+    0x08c: 'MWAIT_COND',
+    0x400: 'NPF',
+}
+
+vendor_exit_reasons = {
+    'vmx': vmx_exit_reasons,
+    'svm': svm_exit_reasons,
+}
+
+exit_reasons = None
+
+for line in file('/proc/cpuinfo').readlines():
+    if line.startswith('flags'):
+        for flag in line.split():
+            if flag in vendor_exit_reasons:
+                exit_reasons = vendor_exit_reasons[flag]
+
+filters = {
+    'kvm_exit': ('exit_reason', exit_reasons)
+}
+
+def invert(d):
+    return dict((x[1], x[0]) for x in d.iteritems())
+
+for f in filters:
+    filters[f] = (filters[f][0], invert(filters[f][1]))
+
+import ctypes, struct, array
+
+libc = ctypes.CDLL('libc.so.6')
+syscall = libc.syscall
+class perf_event_attr(ctypes.Structure):
+    _fields_ = [('type', ctypes.c_uint32),
+                ('size', ctypes.c_uint32),
+                ('config', ctypes.c_uint64),
+                ('sample_freq', ctypes.c_uint64),
+                ('sample_type', ctypes.c_uint64),
+                ('read_format', ctypes.c_uint64),
+                ('flags', ctypes.c_uint64),
+                ('wakeup_events', ctypes.c_uint32),
+                ('bp_type', ctypes.c_uint32),
+                ('bp_addr', ctypes.c_uint64),
+                ('bp_len', ctypes.c_uint64),
+                ]
+def _perf_event_open(attr, pid, cpu, group_fd, flags):
+    return syscall(298, ctypes.pointer(attr), ctypes.c_int(pid),
+                   ctypes.c_int(cpu), ctypes.c_int(group_fd),
+                   ctypes.c_long(flags))
+
+PERF_TYPE_HARDWARE              = 0
+PERF_TYPE_SOFTWARE              = 1
+PERF_TYPE_TRACEPOINT            = 2
+PERF_TYPE_HW_CACHE              = 3
+PERF_TYPE_RAW                   = 4
+PERF_TYPE_BREAKPOINT            = 5
+
+PERF_SAMPLE_IP                  = 1 << 0
+PERF_SAMPLE_TID                 = 1 << 1
+PERF_SAMPLE_TIME                = 1 << 2
+PERF_SAMPLE_ADDR                = 1 << 3
+PERF_SAMPLE_READ                = 1 << 4
+PERF_SAMPLE_CALLCHAIN           = 1 << 5
+PERF_SAMPLE_ID                  = 1 << 6
+PERF_SAMPLE_CPU                 = 1 << 7
+PERF_SAMPLE_PERIOD              = 1 << 8
+PERF_SAMPLE_STREAM_ID           = 1 << 9
+PERF_SAMPLE_RAW                 = 1 << 10
+
+PERF_FORMAT_TOTAL_TIME_ENABLED  = 1 << 0
+PERF_FORMAT_TOTAL_TIME_RUNNING  = 1 << 1
+PERF_FORMAT_ID                  = 1 << 2
+PERF_FORMAT_GROUP               = 1 << 3
+
+import re
+
+sys_tracing = '/sys/kernel/debug/tracing'
+
+class Group(object):
+    def __init__(self, cpu):
+        self.events = []
+        self.group_leader = None
+        self.cpu = cpu
+    def add_event(self, name, event_set, tracepoint, filter = None):
+        self.events.append(Event(group = self,
+                                 name = name, event_set = event_set,
+                                 tracepoint = tracepoint, filter = filter))
+        if len(self.events) == 1:
+            self.file = os.fdopen(self.events[0].fd)
+    def read(self):
+        bytes = 8 * (1 + len(self.events))
+        fmt = 'xxxxxxxx' + 'q' * len(self.events)
+        return dict(zip([event.name for event in self.events],
+                        struct.unpack(fmt, self.file.read(bytes))))
+
+class Event(object):
+    def __init__(self, group, name, event_set, tracepoint, filter = None):
+        self.name = name
+        attr = perf_event_attr()
+        attr.type = PERF_TYPE_TRACEPOINT
+        attr.size = ctypes.sizeof(attr)
+        id_path = os.path.join(sys_tracing, 'events', event_set,
+                               tracepoint, 'id')
+        id = int(file(id_path).read())
+        attr.config = id
+        attr.sample_type = (PERF_SAMPLE_RAW
+                            | PERF_SAMPLE_TIME
+                            | PERF_SAMPLE_CPU)
+        attr.sample_period = 1
+        attr.read_format = PERF_FORMAT_GROUP
+        group_leader = -1
+        if group.events:
+            group_leader = group.events[0].fd
+        fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
+        if fd == -1:
+            raise Exception('perf_event_open failed')
+        if filter:
+            import fcntl
+            fcntl.ioctl(fd, 0x40082406, filter)
+        self.fd = fd
+    def enable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002400, 0)
+    def disable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002401, 0)
+
+class TracepointProvider(object):
+    def __init__(self):
+        path = os.path.join(sys_tracing, 'events', 'kvm')
+        fields = [f
+                  for f in os.listdir(path)
+                  if os.path.isdir(os.path.join(path, f))]
+        extra = []
+        for f in fields:
+            if f in filters:
+                subfield, values = filters[f]
+                for name, number in values.iteritems():
+                    extra.append(f + '(' + name + ')')
+        fields += extra
+        self._setup(fields)
+        self.select(fields)
+    def fields(self):
+        return self._fields
+    def _setup(self, _fields):
+        self._fields = _fields
+        cpure = r'cpu([0-9]+)'
+        self.cpus = [int(re.match(cpure, x).group(1))
+                     for x in os.listdir('/sys/devices/system/cpu')
+                     if re.match(cpure, x)]
+        import resource
+        nfiles = len(self.cpus) * 1000
+        resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
+        events = []
+        self.group_leaders = []
+        for cpu in self.cpus:
+            group = Group(cpu)
+            for name in _fields:
+                tracepoint = name
+                filter = None
+                m = re.match(r'(.*)\((.*)\)', name)
+                if m:
+                    tracepoint, sub = m.groups()
+                    filter = '%s==%d\0' % (filters[tracepoint][0],
+                                           filters[tracepoint][1][sub])
+                event = group.add_event(name, event_set = 'kvm',
+                                        tracepoint = tracepoint,
+                                        filter = filter)
+            self.group_leaders.append(group)
+    def select(self, fields):
+        for group in self.group_leaders:
+            for event in group.events:
+                if event.name in fields:
+                    event.enable()
+                else:
+                    event.disable()
+    def read(self):
+        from collections import defaultdict
+        ret = defaultdict(int)
+        for group in self.group_leaders:
+            for name, val in group.read().iteritems():
+                ret[name] += val
+        return ret
+
+class Stats:
+    def __init__(self, provider, fields = None):
+        self.provider = provider
+        self.fields_filter = fields
+        self._update()
+    def _update(self):
+        def wanted(key):
+            import re
+            if not self.fields_filter:
+                return True
+            return re.match(self.fields_filter, key) is not None
+        self.values = dict([(key, None)
+                            for key in provider.fields()
+                            if wanted(key)])
+        self.provider.select(self.values.keys())
+    def set_fields_filter(self, fields_filter):
+        self.fields_filter = fields_filter
+        self._update()
+    def get(self):
+        new = self.provider.read()
+        for key in self.provider.fields():
+            oldval = self.values.get(key, (0, 0))
+            newval = new[key]
+            newdelta = None
+            if oldval is not None:
+                newdelta = newval - oldval[0]
+            self.values[key] = (newval, newdelta)
+        return self.values
+
+if not os.access('/sys/kernel/debug', os.F_OK):
+    print 'Please enable CONFIG_DEBUG_FS in your kernel'
+    sys.exit(1)
+if not os.access('/sys/kernel/debug/kvm', os.F_OK):
+    print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
+    print "and ensure the kvm modules are loaded"
+    sys.exit(1)
+
+label_width = 40
+number_width = 10
+
+def tui(screen, stats):
+    curses.use_default_colors()
+    curses.noecho()
+    drilldown = False
+    fields_filter = stats.fields_filter
+    def update_drilldown():
+        if not fields_filter:
+            if drilldown:
+                stats.set_fields_filter(None)
+            else:
+                stats.set_fields_filter(r'^[^\(]*$')
+    update_drilldown()
+    def refresh(sleeptime):
+        screen.erase()
+        screen.addstr(0, 0, 'kvm statistics')
+        row = 2
+        s = stats.get()
+        def sortkey(x):
+            if s[x][1]:
+                return (-s[x][1], -s[x][0])
+            else:
+                return (0, -s[x][0])
+        for key in sorted(s.keys(), key = sortkey):
+            if row >= screen.getmaxyx()[0]:
+                break
+            values = s[key]
+            if not values[0] and not values[1]:
+                break
+            col = 1
+            screen.addstr(row, col, key)
+            col += label_width
+            screen.addstr(row, col, '%10d' % (values[0],))
+            col += number_width
+            if values[1] is not None:
+                screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
+            row += 1
+        screen.refresh()
+
+    sleeptime = 0.25
+    while True:
+        refresh(sleeptime)
+        curses.halfdelay(int(sleeptime * 10))
+        sleeptime = 3
+        try:
+            c = screen.getkey()
+            if c == 'x':
+                drilldown = not drilldown
+                update_drilldown()
+            if c == 'q':
+                break
+        except KeyboardInterrupt:
+            break
+        except curses.error:
+            continue
+
+def batch(stats):
+    s = stats.get()
+    time.sleep(1)
+    s = stats.get()
+    for key in sorted(s.keys()):
+        values = s[key]
+        print '%-22s%10d%10d' % (key, values[0], values[1])
+
+def log(stats):
+    keys = sorted(stats.get().iterkeys())
+    def banner():
+        for k in keys:
+            print '%10s' % k[0:9],
+        print
+    def statline():
+        s = stats.get()
+        for k in keys:
+            print ' %9d' % s[k][1],
+        print
+    line = 0
+    banner_repeat = 20
+    while True:
+        time.sleep(1)
+        if line % banner_repeat == 0:
+            banner()
+        statline()
+        line += 1
+
+options = optparse.OptionParser()
+options.add_option('-1', '--once', '--batch',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'once',
+                   help = 'run in batch mode for one second',
+                   )
+options.add_option('-l', '--log',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'log',
+                   help = 'run in logging mode (like vmstat)',
+                   )
+options.add_option('-f', '--fields',
+                   action = 'store',
+                   default = None,
+                   dest = 'fields',
+                   help = 'fields to display (regex)',
+                   )
+(options, args) = options.parse_args(sys.argv)
+
+try:
+    provider = TracepointProvider()
+except:
+    provider = DebugfsProvider()
+
+stats = Stats(provider, fields = options.fields)
+
+if options.log:
+    log(stats)
+elif not options.once:
+    import curses.wrapper
+    curses.wrapper(tui, stats)
+else:
+    batch(stats)
diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap
new file mode 100755 (executable)
index 0000000..a74ce71
--- /dev/null
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+#
+# tool for querying VMX capabilities
+#
+# Copyright 2009-2010 Red Hat, Inc.
+#
+# Authors:
+#  Avi Kivity <avi@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+MSR_IA32_VMX_BASIC = 0x480
+MSR_IA32_VMX_PINBASED_CTLS = 0x481
+MSR_IA32_VMX_PROCBASED_CTLS = 0x482
+MSR_IA32_VMX_EXIT_CTLS = 0x483
+MSR_IA32_VMX_ENTRY_CTLS = 0x484
+MSR_IA32_VMX_MISC_CTLS = 0x485
+MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B
+MSR_IA32_VMX_EPT_VPID_CAP = 0x48C
+MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D
+MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E
+MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F
+MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490
+
+class msr(object):
+    def __init__(self):
+        try:
+            self.f = file('/dev/cpu/0/msr')
+        except:
+            self.f = file('/dev/msr0')
+    def read(self, index, default = None):
+        import struct
+        self.f.seek(index)
+        try:
+            return struct.unpack('Q', self.f.read(8))[0]
+        except:
+            return default
+
+class Control(object):
+    def __init__(self, name, bits, cap_msr, true_cap_msr = None):
+        self.name = name
+        self.bits = bits
+        self.cap_msr = cap_msr
+        self.true_cap_msr = true_cap_msr
+    def read2(self, nr):
+        m = msr()
+        val = m.read(nr, 0)
+        return (val & 0xffffffff, val >> 32)
+    def show(self):
+        print self.name
+        mbz, mb1 = self.read2(self.cap_msr)
+        tmbz, tmb1 = 0, 0
+        if self.true_cap_msr:
+            tmbz, tmb1 = self.read2(self.true_cap_msr)
+        for bit in sorted(self.bits.keys()):
+            zero = not (mbz & (1 << bit))
+            one = mb1 & (1 << bit)
+            true_zero = not (tmbz & (1 << bit))
+            true_one = tmb1 & (1 << bit)
+            s= '?'
+            if (self.true_cap_msr and true_zero and true_one
+                and one and not zero):
+                s = 'default'
+            elif zero and not one:
+                s = 'no'
+            elif one and not zero:
+                s = 'forced'
+            elif one and zero:
+                s = 'yes'
+            print '  %-40s %s' % (self.bits[bit], s)
+
+class Misc(object):
+    def __init__(self, name, bits, msr):
+        self.name = name
+        self.bits = bits
+        self.msr = msr
+    def show(self):
+        print self.name
+        value = msr().read(self.msr, 0)
+        def first_bit(key):
+            if type(key) is tuple:
+                return key[0]
+            else:
+                return key
+        for bits in sorted(self.bits.keys(), key = first_bit):
+            if type(bits) is tuple:
+                lo, hi = bits
+                fmt = int
+            else:
+                lo = hi = bits
+                def fmt(x):
+                    return { True: 'yes', False: 'no' }[x]
+            v = (value >> lo) & ((1 << (hi - lo + 1)) - 1)
+            print '  %-40s %s' % (self.bits[bits], fmt(v))
+
+controls = [
+    Control(
+        name = 'pin-based controls',
+        bits = {
+            0: 'External interrupt exiting',
+            3: 'NMI exiting',
+            5: 'Virtual NMIs',
+            6: 'Activate VMX-preemption timer',
+            },
+        cap_msr = MSR_IA32_VMX_PINBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+        ),
+
+    Control(
+        name = 'primary processor-based controls',
+        bits = {
+            2: 'Interrupt window exiting',
+            3: 'Use TSC offsetting',
+            7: 'HLT exiting',
+            9: 'INVLPG exiting',
+            10: 'MWAIT exiting',
+            11: 'RDPMC exiting',
+            12: 'RDTSC exiting',
+            15: 'CR3-load exiting',
+            16: 'CR3-store exiting',
+            19: 'CR8-load exiting',
+            20: 'CR8-store exiting',
+            21: 'Use TPR shadow',
+            22: 'NMI-window exiting',
+            23: 'MOV-DR exiting',
+            24: 'Unconditional I/O exiting',
+            25: 'Use I/O bitmaps',
+            27: 'Monitor trap flag',
+            28: 'Use MSR bitmaps',
+            29: 'MONITOR exiting',
+            30: 'PAUSE exiting',
+            31: 'Activate secondary control',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+        ),
+
+    Control(
+        name = 'secondary processor-based controls',
+        bits = {
+            0: 'Virtualize APIC accesses',
+            1: 'Enable EPT',
+            2: 'Descriptor-table exiting',
+            4: 'Virtualize x2APIC mode',
+            5: 'Enable VPID',
+            6: 'WBINVD exiting',
+            7: 'Unrestricted guest',
+            10: 'PAUSE-loop exiting',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
+        ),
+
+    Control(
+        name = 'VM-Exit controls',
+        bits = {
+            2: 'Save debug controls',
+            9: 'Host address-space size',
+            12: 'Load IA32_PERF_GLOBAL_CTRL',
+            15: 'Acknowledge interrupt on exit',
+            18: 'Save IA32_PAT',
+            19: 'Load IA32_PAT',
+            20: 'Save IA32_EFER',
+            21: 'Load IA32_EFER',
+            22: 'Save VMX-preemption timer value',
+            },
+        cap_msr = MSR_IA32_VMX_EXIT_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS,
+        ),
+
+    Control(
+        name = 'VM-Entry controls',
+        bits = {
+            2: 'Load debug controls',
+            9: 'IA-64 mode guest',
+            10: 'Entry to SMM',
+            11: 'Deactivate dual-monitor treatment',
+            13: 'Load IA32_PERF_GLOBAL_CTRL',
+            14: 'Load IA32_PAT',
+            15: 'Load IA32_EFER',
+            },
+        cap_msr = MSR_IA32_VMX_ENTRY_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+        ),
+
+    Misc(
+        name = 'Miscellaneous data',
+        bits = {
+            (0,4): 'VMX-preemption timer scale (log2)',
+            5: 'Store EFER.LMA into IA-32e mode guest control',
+            6: 'HLT activity state',
+            7: 'Shutdown activity state',
+            8: 'Wait-for-SIPI activity state',
+            (16,24): 'Number of CR3-target values',
+            (25,27): 'MSR-load/store count recommenation',
+            (32,62): 'MSEG revision identifier',
+            },
+        msr = MSR_IA32_VMX_MISC_CTLS,
+        ),
+
+    Misc(
+        name = 'VPID and EPT capabilities',
+        bits = {
+            0: 'Execute-only EPT translations',
+            6: 'Page-walk length 4',
+            8: 'Paging-structure memory type UC',
+            14: 'Paging-structure memory type WB',
+            16: '2MB EPT pages',
+            17: '1GB EPT pages',
+            20: 'INVEPT supported',
+            25: 'Single-context INVEPT',
+            26: 'All-context INVEPT',
+            32: 'INVVPID supported',
+            40: 'Individual-address INVVPID',
+            41: 'Single-context INVVPID',
+            42: 'All-context INVVPID',
+            43: 'Single-context-retaining-globals INVVPID',
+            },
+        msr = MSR_IA32_VMX_EPT_VPID_CAP,
+        ),
+    ]
+
+for c in controls:
+    c.show()
diff --git a/scripts/ordereddict.py b/scripts/ordereddict.py
new file mode 100644 (file)
index 0000000..7242b50
--- /dev/null
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# 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.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__end
+        except AttributeError:
+            self.clear()
+        self.update(*args, **kwds)
+
+    def clear(self):
+        self.__end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.__map = {}                 # key --> [key, prev, next]
+        dict.clear(self)
+
+    def __setitem__(self, key, value):
+        if key not in self:
+            end = self.__end
+            curr = end[1]
+            curr[2] = end[1] = self.__map[key] = [key, curr, end]
+        dict.__setitem__(self, key, value)
+
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        key, prev, next = self.__map.pop(key)
+        prev[2] = next
+        next[1] = prev
+
+    def __iter__(self):
+        end = self.__end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.__end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def popitem(self, last=True):
+        if not self:
+            raise KeyError('dictionary is empty')
+        if last:
+            key = reversed(self).next()
+        else:
+            key = iter(self).next()
+        value = self.pop(key)
+        return key, value
+
+    def __reduce__(self):
+        items = [[k, self[k]] for k in self]
+        tmp = self.__map, self.__end
+        del self.__map, self.__end
+        inst_dict = vars(self).copy()
+        self.__map, self.__end = tmp
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def keys(self):
+        return list(self)
+
+    setdefault = DictMixin.setdefault
+    update = DictMixin.update
+    pop = DictMixin.pop
+    values = DictMixin.values
+    items = DictMixin.items
+    iterkeys = DictMixin.iterkeys
+    itervalues = DictMixin.itervalues
+    iteritems = DictMixin.iteritems
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, self.items())
+
+    def copy(self):
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedDict):
+            if len(self) != len(other):
+                return False
+            for p, q in  zip(self.items(), other.items()):
+                if p != q:
+                    return False
+            return True
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
new file mode 100644 (file)
index 0000000..f7def16
--- /dev/null
@@ -0,0 +1,445 @@
+#
+# QAPI command marshaller generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def type_visitor(name):
+    if type(name) == list:
+        return 'visit_type_%sList' % name[0]
+    else:
+        return 'visit_type_%s' % name
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                 visitor=type_visitor(name))
+
+def generate_command_decl(name, args, ret_type):
+    arglist=""
+    for argname, argtype, optional, structured in parse_args(args):
+        argtype = c_type(argtype)
+        if argtype == "char *":
+            argtype = "const char *"
+        if optional:
+            arglist += "bool has_%s, " % c_var(argname)
+        arglist += "%s %s, " % (argtype, c_var(argname))
+    return mcgen('''
+%(ret_type)s qmp_%(name)s(%(args)sError **errp);
+''',
+                 ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+
+def gen_sync_call(name, args, ret_type, indent=0):
+    ret = ""
+    arglist=""
+    retval=""
+    if ret_type:
+        retval = "retval = "
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            arglist += "has_%s, " % c_var(argname)
+        arglist += "%s, " % (c_var(argname))
+    push_indent(indent)
+    ret = mcgen('''
+%(retval)sqmp_%(name)s(%(args)serrp);
+
+''',
+                name=c_var(name), args=arglist, retval=retval).rstrip()
+    if ret_type:
+        ret += "\n" + mcgen(''''
+if (!error_is_set(errp)) {
+    %(marshal_output_call)s
+}
+''',
+                            marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
+    pop_indent(indent)
+    return ret.rstrip()
+
+
+def gen_marshal_output_call(name, ret_type):
+    if not ret_type:
+        return ""
+    return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+
+def gen_visitor_output_containers_decl(ret_type):
+    ret = ""
+    push_indent()
+    if ret_type:
+        ret += mcgen('''
+QmpOutputVisitor *mo;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret
+
+def gen_visitor_input_containers_decl(args):
+    ret = ""
+
+    push_indent()
+    if len(args) > 0:
+        ret += mcgen('''
+QmpInputVisitor *mi;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret.rstrip()
+
+def gen_visitor_input_vars_decl(args):
+    ret = ""
+    push_indent()
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+bool has_%(argname)s = false;
+''',
+                         argname=c_var(argname))
+        if c_type(argtype).endswith("*"):
+            ret += mcgen('''
+%(argtype)s %(argname)s = NULL;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+        else:
+            ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+
+    pop_indent()
+    return ret.rstrip()
+
+def gen_visitor_input_block(args, obj, dealloc=False):
+    ret = ""
+    if len(args) == 0:
+        return ret
+
+    push_indent()
+
+    if dealloc:
+        ret += mcgen('''
+md = qapi_dealloc_visitor_new();
+v = qapi_dealloc_get_visitor(md);
+''')
+    else:
+        ret += mcgen('''
+mi = qmp_input_visitor_new(%(obj)s);
+v = qmp_input_get_visitor(mi);
+''',
+                     obj=obj)
+
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
+if (has_%(c_name)s) {
+''',
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+        ret += mcgen('''
+%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
+''',
+                     c_name=c_var(argname), name=argname, argtype=argtype,
+                     visitor=type_visitor(argtype))
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(v, errp);
+''')
+
+    if dealloc:
+        ret += mcgen('''
+qapi_dealloc_visitor_cleanup(md);
+''')
+    else:
+        ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
+''')
+    pop_indent()
+    return ret.rstrip()
+
+def gen_marshal_output(name, args, ret_type, middle_mode):
+    if not ret_type:
+        return ""
+
+    ret = mcgen('''
+static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+{
+    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+    QmpOutputVisitor *mo = qmp_output_visitor_new();
+    Visitor *v;
+
+    v = qmp_output_get_visitor(mo);
+    %(visitor)s(v, &ret_in, "unused", errp);
+    if (!error_is_set(errp)) {
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+    qmp_output_visitor_cleanup(mo);
+    v = qapi_dealloc_get_visitor(md);
+    %(visitor)s(v, &ret_in, "unused", errp);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_ret_type=c_type(ret_type), c_name=c_var(name),
+                visitor=type_visitor(ret_type))
+
+    return ret
+
+def gen_marshal_input_decl(name, args, ret_type, middle_mode):
+    if middle_mode:
+        return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name)
+    else:
+        return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name)
+
+
+
+def gen_marshal_input(name, args, ret_type, middle_mode):
+    hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
+
+    ret = mcgen('''
+%(header)s
+{
+''',
+                header=hdr)
+
+    if middle_mode:
+        ret += mcgen('''
+    Error *local_err = NULL;
+    Error **errp = &local_err;
+    QDict *args = (QDict *)qdict;
+''')
+
+    if ret_type:
+        if c_type(ret_type).endswith("*"):
+            retval = "    %s retval = NULL;" % c_type(ret_type)
+        else:
+            retval = "    %s retval;" % c_type(ret_type)
+        ret += mcgen('''
+%(retval)s
+''',
+                     retval=retval)
+
+    if len(args) > 0:
+        ret += mcgen('''
+%(visitor_input_containers_decl)s
+%(visitor_input_vars_decl)s
+
+%(visitor_input_block)s
+
+''',
+                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
+                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+    else:
+        ret += mcgen('''
+    (void)args;
+''')
+
+    ret += mcgen('''
+    if (error_is_set(errp)) {
+        goto out;
+    }
+%(sync_call)s
+''',
+                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
+    ret += mcgen('''
+
+out:
+''')
+    ret += mcgen('''
+%(visitor_input_block_cleanup)s
+''',
+                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
+                                                                     dealloc=True))
+
+    if middle_mode:
+        ret += mcgen('''
+
+    if (local_err) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return -1;
+    }
+    return 0;
+''')
+    else:
+        ret += mcgen('''
+    return;
+''')
+
+    ret += mcgen('''
+}
+''')
+
+    return ret
+
+def gen_registry(commands):
+    registry=""
+    push_indent()
+    for cmd in commands:
+        registry += mcgen('''
+qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
+''',
+                     name=cmd['command'], c_name=c_var(cmd['command']))
+    pop_indent()
+    ret = mcgen('''
+static void qmp_init_marshal(void)
+{
+%(registry)s
+}
+
+qapi_init(qmp_init_marshal);
+''',
+                registry=registry.rstrip())
+    return ret
+
+def gen_command_decl_prologue(header, guard, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI function prototypes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "%(prefix)sqapi-types.h"
+#include "error.h"
+
+''',
+                 header=basename(header), guard=guardname(header), prefix=prefix)
+    return ret
+
+def gen_command_def_prologue(prefix="", proxy=False):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QMP->QAPI command dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',
+                prefix=prefix)
+    if not proxy:
+        ret += '#include "%sqmp-commands.h"' % prefix
+    return ret + "\n\n"
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+dispatch_type = "sync"
+c_file = 'qmp-marshal.c'
+h_file = 'qmp-commands.h'
+middle_mode = False
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-t", "--type"):
+        dispatch_type = a
+    elif o in ("-m", "--middle"):
+        middle_mode = True
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+exprs = parse_schema(sys.stdin)
+commands = filter(lambda expr: expr.has_key('command'), exprs)
+
+if dispatch_type == "sync":
+    fdecl = open(h_file, 'w')
+    fdef = open(c_file, 'w')
+    ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    fdecl.write(ret)
+    ret = gen_command_def_prologue(prefix=prefix)
+    fdef.write(ret)
+
+    for cmd in commands:
+        arglist = []
+        ret_type = None
+        if cmd.has_key('data'):
+            arglist = cmd['data']
+        if cmd.has_key('returns'):
+            ret_type = cmd['returns']
+        ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
+        fdecl.write(ret)
+        if ret_type:
+            ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
+            fdef.write(ret)
+
+        if middle_mode:
+            fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
+
+        ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
+        fdef.write(ret)
+
+    fdecl.write("\n#endif\n");
+
+    if not middle_mode:
+        ret = gen_registry(commands)
+        fdef.write(ret)
+
+    fdef.flush()
+    fdef.close()
+    fdecl.flush()
+    fdecl.close()
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
new file mode 100644 (file)
index 0000000..f64d84c
--- /dev/null
@@ -0,0 +1,278 @@
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_fwd_struct(name, members):
+    return mcgen('''
+typedef struct %(name)s %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name)
+
+def generate_struct(structname, fieldname, members):
+    ret = mcgen('''
+struct %(name)s
+{
+''',
+          name=structname)
+
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+    bool has_%(c_name)s;
+''',
+                         c_name=c_var(argname))
+        if structured:
+            push_indent()
+            ret += generate_struct("", argname, argentry)
+            pop_indent()
+        else:
+            ret += mcgen('''
+    %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(argentry), c_name=c_var(argname))
+
+    if len(fieldname):
+        fieldname = " " + fieldname
+    ret += mcgen('''
+}%(field)s;
+''',
+            field=fieldname)
+
+    return ret
+
+def generate_enum_lookup(name, values):
+    ret = mcgen('''
+const char *%(name)s_lookup[] = {
+''',
+                         name=name)
+    i = 0
+    for value in values:
+        ret += mcgen('''
+    "%(value)s",
+''',
+                     value=value.lower())
+
+    ret += mcgen('''
+    NULL,
+};
+
+''')
+    return ret
+
+def generate_enum(name, values):
+    lookup_decl = mcgen('''
+extern const char *%(name)s_lookup[];
+''',
+                name=name)
+
+    enum_decl = mcgen('''
+typedef enum %(name)s
+{
+''',
+                name=name)
+
+    # append automatically generated _MAX value
+    enum_values = values + [ 'MAX' ]
+
+    i = 0
+    for value in enum_values:
+        enum_decl += mcgen('''
+    %(abbrev)s_%(value)s = %(i)d,
+''',
+                     abbrev=de_camel_case(name).upper(),
+                     value=c_var(value).upper(),
+                     i=i)
+        i += 1
+
+    enum_decl += mcgen('''
+} %(name)s;
+''',
+                 name=name)
+
+    return lookup_decl + enum_decl
+
+def generate_union(name, typeinfo):
+    ret = mcgen('''
+struct %(name)s
+{
+    %(name)sKind kind;
+    union {
+''',
+                name=name)
+
+    for key in typeinfo:
+        ret += mcgen('''
+        %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(typeinfo[key]),
+                     c_name=c_var(key))
+
+    ret += mcgen('''
+    };
+};
+''')
+
+    return ret
+
+def generate_type_cleanup_decl(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+def generate_type_cleanup(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+    QapiDeallocVisitor *md;
+    Visitor *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-types.c'
+h_file = 'qapi-types.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * deallocation functions for schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+                  guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_fwd_struct(expr['type'], expr['data'])
+    elif expr.has_key('enum'):
+        ret += generate_enum(expr['enum'], expr['data'])
+        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
+    elif expr.has_key('union'):
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+    else:
+        continue
+    fdecl.write(ret)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+        ret += generate_type_cleanup_decl(expr['type'] + "List")
+        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
+        ret += generate_type_cleanup_decl(expr['type'])
+        fdef.write(generate_type_cleanup(expr['type']) + "\n")
+    elif expr.has_key('union'):
+        ret += generate_union(expr['union'], expr['data'])
+    else:
+        continue
+    fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
new file mode 100644 (file)
index 0000000..62de83d
--- /dev/null
@@ -0,0 +1,246 @@
+#
+# QAPI visitor generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_visit_struct_body(field_prefix, members):
+    ret = ""
+    if len(field_prefix):
+        field_prefix = field_prefix + "."
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(m, (obj && *obj) ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
+if ((*obj)->%(prefix)shas_%(c_name)s) {
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+
+        if structured:
+            ret += mcgen('''
+visit_start_struct(m, NULL, "", "%(name)s", 0, errp);
+''',
+                         name=argname)
+            ret += generate_visit_struct_body(field_prefix + argname, argentry)
+            ret += mcgen('''
+visit_end_struct(m, errp);
+''')
+        else:
+            ret += mcgen('''
+visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         type=type_name(argentry), c_name=c_var(argname),
+                         name=argname)
+
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(m, errp);
+''')
+    return ret
+
+def generate_visit_struct(name, members):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+''',
+                name=name)
+    push_indent()
+    ret += generate_visit_struct_body("", members)
+    pop_indent()
+
+    ret += mcgen('''
+    visit_end_struct(m, errp);
+}
+''')
+    return ret
+
+def generate_visit_list(name, members):
+    return mcgen('''
+
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+{
+    GenericList *i, **head = (GenericList **)obj;
+
+    visit_start_list(m, name, errp);
+
+    for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
+        %(name)sList *native_i = (%(name)sList *)i;
+        visit_type_%(name)s(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+''',
+                name=name)
+
+def generate_visit_enum(name, members):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+{
+    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
+}
+''',
+                 name=name)
+
+def generate_visit_union(name, members):
+    ret = generate_visit_enum('%sKind' % name, members.keys())
+
+    ret += mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+}
+''',
+                 name=name)
+
+    return ret
+
+def generate_declaration(name, members, genlist=True):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+                 name=name)
+
+    return ret
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-visit.c'
+h_file = 'qapi-visit.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor functions
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "%(header)s"
+''',
+                 header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor function
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-visit-core.h"
+#include "%(prefix)sqapi-types.h"
+''',
+                  prefix=prefix, guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    if expr.has_key('type'):
+        ret = generate_visit_struct(expr['type'], expr['data'])
+        ret += generate_visit_list(expr['type'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_declaration(expr['type'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('union'):
+        ret = generate_visit_union(expr['union'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
+        ret += generate_declaration(expr['union'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('enum'):
+        ret = generate_visit_enum(expr['enum'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum(expr['enum'], expr['data'])
+        fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/scripts/qapi.py b/scripts/qapi.py
new file mode 100644 (file)
index 0000000..6e05469
--- /dev/null
@@ -0,0 +1,206 @@
+#
+# QAPI helper library
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+
+def tokenize(data):
+    while len(data):
+        if data[0] in ['{', '}', ':', ',', '[', ']']:
+            yield data[0]
+            data = data[1:]
+        elif data[0] in ' \n':
+            data = data[1:]
+        elif data[0] == "'":
+            data = data[1:]
+            string = ''
+            while data[0] != "'":
+                string += data[0]
+                data = data[1:]
+            data = data[1:]
+            yield string
+
+def parse(tokens):
+    if tokens[0] == '{':
+        ret = OrderedDict()
+        tokens = tokens[1:]
+        while tokens[0] != '}':
+            key = tokens[0]
+            tokens = tokens[1:]
+
+            tokens = tokens[1:] # :
+
+            value, tokens = parse(tokens)
+
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+
+            ret[key] = value
+        tokens = tokens[1:]
+        return ret, tokens
+    elif tokens[0] == '[':
+        ret = []
+        tokens = tokens[1:]
+        while tokens[0] != ']':
+            value, tokens = parse(tokens)
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+            ret.append(value)
+        tokens = tokens[1:]
+        return ret, tokens
+    else:
+        return tokens[0], tokens[1:]
+
+def evaluate(string):
+    return parse(map(lambda x: x, tokenize(string)))[0]
+
+def parse_schema(fp):
+    exprs = []
+    expr = ''
+    expr_eval = None
+
+    for line in fp:
+        if line.startswith('#') or line == '\n':
+            continue
+
+        if line.startswith(' '):
+            expr += line
+        elif expr:
+            expr_eval = evaluate(expr)
+            if expr_eval.has_key('enum'):
+                add_enum(expr_eval['enum'])
+            elif expr_eval.has_key('union'):
+                add_enum('%sKind' % expr_eval['union'])
+            exprs.append(expr_eval)
+            expr = line
+        else:
+            expr += line
+
+    if expr:
+        expr_eval = evaluate(expr)
+        if expr_eval.has_key('enum'):
+            add_enum(expr_eval['enum'])
+        elif expr_eval.has_key('union'):
+            add_enum('%sKind' % expr_eval['union'])
+        exprs.append(expr_eval)
+
+    return exprs
+
+def parse_args(typeinfo):
+    for member in typeinfo:
+        argname = member
+        argentry = typeinfo[member]
+        optional = False
+        structured = False
+        if member.startswith('*'):
+            argname = member[1:]
+            optional = True
+        if isinstance(argentry, OrderedDict):
+            structured = True
+        yield (argname, argentry, optional, structured)
+
+def de_camel_case(name):
+    new_name = ''
+    for ch in name:
+        if ch.isupper() and new_name:
+            new_name += '_'
+        if ch == '-':
+            new_name += '_'
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def camel_case(name):
+    new_name = ''
+    first = True
+    for ch in name:
+        if ch in ['_', '-']:
+            first = True
+        elif first:
+            new_name += ch.upper()
+            first = False
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def c_var(name):
+    return '_'.join(name.split('-')).lstrip("*")
+
+def c_list_type(name):
+    return '%sList' % name
+
+def type_name(name):
+    if type(name) == list:
+        return c_list_type(name[0])
+    return name
+
+enum_types = []
+
+def add_enum(name):
+    global enum_types
+    enum_types.append(name)
+
+def is_enum(name):
+    global enum_types
+    return (name in enum_types)
+
+def c_type(name):
+    if name == 'str':
+        return 'char *'
+    elif name == 'int':
+        return 'int64_t'
+    elif name == 'bool':
+        return 'bool'
+    elif name == 'number':
+        return 'double'
+    elif type(name) == list:
+        return '%s *' % c_list_type(name[0])
+    elif is_enum(name):
+        return name
+    elif name == None or len(name) == 0:
+        return 'void'
+    elif name == name.upper():
+        return '%sEvent *' % camel_case(name)
+    else:
+        return '%s *' % name
+
+def genindent(count):
+    ret = ""
+    for i in range(count):
+        ret += " "
+    return ret
+
+indent_level = 0
+
+def push_indent(indent_amount=4):
+    global indent_level
+    indent_level += indent_amount
+
+def pop_indent(indent_amount=4):
+    global indent_level
+    indent_level -= indent_amount
+
+def cgen(code, **kwds):
+    indent = genindent(indent_level)
+    lines = code.split('\n')
+    lines = map(lambda x: indent + x, lines)
+    return '\n'.join(lines) % kwds + '\n'
+
+def mcgen(code, **kwds):
+    return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
+
+def basename(filename):
+    return filename.split("/")[-1]
+
+def guardname(filename):
+    guard = basename(filename).rsplit(".", 1)[0]
+    for substr in [".", " ", "-"]:
+        guard = guard.replace(substr, "_")
+    return guard.upper() + '_H'
index c50beb733716c0c5b7f8f54f57f590bdc533773b..83a44d8e2a22a6a8f8c273d33348bd45f68211ad 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC program execution by the kernel
+# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390 program execution by the kernel
 
 # load the binfmt_misc module
 if [ ! -d /proc/sys/fs/binfmt_misc ]; then
@@ -63,4 +63,6 @@ fi
 if [ $cpu != "sh" ] ; then
     echo    ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register
     echo    ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register
+if [ $cpu != "s390x" ] ; then
+    echo   ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register
 fi
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
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 553a727..f55e5e6
@@ -9,30 +9,27 @@
 #
 # For help see docs/tracing.txt
 
-import sys
 import struct
 import re
+import inspect
 
 header_event_id = 0xffffffffffffffff
 header_magic    = 0xf2b177cb0aa429b4
 header_version  = 0
+dropped_event_id = 0xfffffffffffffffe
 
 trace_fmt = '=QQQQQQQQ'
 trace_len = struct.calcsize(trace_fmt)
 event_re  = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
 
-def err(msg):
-    sys.stderr.write(msg + '\n')
-    sys.exit(1)
-
 def parse_events(fobj):
-    """Parse a trace-events file."""
+    """Parse a trace-events file into {event_num: (name, arg1, ...)}."""
 
     def get_argnames(args):
         """Extract argument names from a parameter list."""
         return tuple(arg.split()[-1].lstrip('*') for arg in args.split(','))
 
-    events = {}
+    events = {dropped_event_id: ('dropped', 'count')}
     event_num = 0
     for line in fobj:
         m = event_re.match(line.strip())
@@ -45,20 +42,20 @@ def parse_events(fobj):
     return events
 
 def read_record(fobj):
-    """Deserialize a trace record from a file."""
+    """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
     s = fobj.read(trace_len)
     if len(s) != trace_len:
         return None
     return struct.unpack(trace_fmt, s)
 
 def read_trace_file(fobj):
-    """Deserialize trace records from a file."""
+    """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6)."""
     header = read_record(fobj)
     if header is None or \
        header[0] != header_event_id or \
        header[1] != header_magic or \
        header[2] != header_version:
-        err('not a trace file or incompatible version')
+        raise ValueError('not a trace file or incompatible version')
 
     while True:
         rec = read_record(fobj)
@@ -67,27 +64,88 @@ def read_trace_file(fobj):
 
         yield rec
 
-class Formatter(object):
-    def __init__(self, events):
-        self.events = events
-        self.last_timestamp = None
-
-    def format_record(self, rec):
-        if self.last_timestamp is None:
-            self.last_timestamp = rec[1]
-        delta_ns = rec[1] - self.last_timestamp
-        self.last_timestamp = rec[1]
-
-        event = self.events[rec[0]]
-        fields = [event[0], '%0.3f' % (delta_ns / 1000.0)]
-        for i in xrange(1, len(event)):
-            fields.append('%s=0x%x' % (event[i], rec[i + 1]))
-        return ' '.join(fields)
-
-if len(sys.argv) != 3:
-    err('usage: %s <trace-events> <trace-file>' % sys.argv[0])
-
-events = parse_events(open(sys.argv[1], 'r'))
-formatter = Formatter(events)
-for rec in read_trace_file(open(sys.argv[2], 'rb')):
-    print formatter.format_record(rec)
+class Analyzer(object):
+    """A trace file analyzer which processes trace records.
+
+    An analyzer can be passed to run() or process().  The begin() method is
+    invoked, then each trace record is processed, and finally the end() method
+    is invoked.
+
+    If a method matching a trace event name exists, it is invoked to process
+    that trace record.  Otherwise the catchall() method is invoked."""
+
+    def begin(self):
+        """Called at the start of the trace."""
+        pass
+
+    def catchall(self, event, rec):
+        """Called if no specific method for processing a trace event has been found."""
+        pass
+
+    def end(self):
+        """Called at the end of the trace."""
+        pass
+
+def process(events, log, analyzer):
+    """Invoke an analyzer on each event in a log."""
+    if isinstance(events, str):
+        events = parse_events(open(events, 'r'))
+    if isinstance(log, str):
+        log = open(log, 'rb')
+
+    def build_fn(analyzer, event):
+        fn = getattr(analyzer, event[0], None)
+        if fn is None:
+            return analyzer.catchall
+
+        event_argcount = len(event) - 1
+        fn_argcount = len(inspect.getargspec(fn)[0]) - 1
+        if fn_argcount == event_argcount + 1:
+            # Include timestamp as first argument
+            return lambda _, rec: fn(*rec[1:2 + event_argcount])
+        else:
+            # Just arguments, no timestamp
+            return lambda _, rec: fn(*rec[2:2 + event_argcount])
+
+    analyzer.begin()
+    fn_cache = {}
+    for rec in read_trace_file(log):
+        event_num = rec[0]
+        event = events[event_num]
+        if event_num not in fn_cache:
+            fn_cache[event_num] = build_fn(analyzer, event)
+        fn_cache[event_num](event, rec)
+    analyzer.end()
+
+def run(analyzer):
+    """Execute an analyzer on a trace file given on the command-line.
+
+    This function is useful as a driver for simple analysis scripts.  More
+    advanced scripts will want to call process() instead."""
+    import sys
+
+    if len(sys.argv) != 3:
+        sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
+        sys.exit(1)
+
+    events = parse_events(open(sys.argv[1], 'r'))
+    process(events, sys.argv[2], analyzer)
+
+if __name__ == '__main__':
+    class Formatter(Analyzer):
+        def __init__(self):
+            self.last_timestamp = None
+
+        def catchall(self, event, rec):
+            timestamp = rec[1]
+            if self.last_timestamp is None:
+                self.last_timestamp = timestamp
+            delta_ns = timestamp - self.last_timestamp
+            self.last_timestamp = timestamp
+
+            fields = [event[0], '%0.3f' % (delta_ns / 1000.0)]
+            for i in xrange(1, len(event)):
+                fields.append('%s=0x%x' % (event[i], rec[i + 1]))
+            print ' '.join(fields)
+
+    run(Formatter())
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index e046683..4c9951d
@@ -30,18 +30,48 @@ Output formats:
   --stap Generate .stp file (DTrace with SystemTAP only)
 
 Options:
-  --binary      [path]  Full path to QEMU binary
-  --target-arch [arch]  QEMU emulator target arch
-  --target-type [type]  QEMU emulator target type ('system' or 'user')
+  --binary       [path]    Full path to QEMU binary
+  --target-arch  [arch]    QEMU emulator target arch
+  --target-type  [type]    QEMU emulator target type ('system' or 'user')
+  --probe-prefix [prefix]  Prefix for dtrace probe names
+                           (default: qemu-\$targettype-\$targetarch)
 
 EOF
     exit 1
 }
 
+# Print a line without interpreting backslash escapes
+#
+# The built-in echo command may interpret backslash escapes without an option
+# to disable this behavior.
+puts()
+{
+    printf "%s\n" "$1"
+}
+
 # Get the name of a trace event
 get_name()
 {
-    echo ${1%%\(*}
+    local name
+    name=${1%%\(*}
+    echo "${name##* }"
+}
+
+# Get the given property of a trace event
+# 1: trace-events line
+# 2: property name
+# -> return 0 if property is present, or 1 otherwise
+has_property()
+{
+    local props prop
+    props=${1%%\(*}
+    props=${props% *}
+    for prop in $props; do
+        if [ "$prop" = "$2" ]; then
+            return 0
+        fi
+    done
+    return 1
 }
 
 # Get the argument list of a trace event, including types and names
@@ -49,7 +79,7 @@ get_args()
 {
     local args
     args=${1#*\(}
-    args=${args%\)*}
+    args=${args%%\)*}
     echo "$args"
 }
 
@@ -90,27 +120,10 @@ get_argc()
     echo $argc
 }
 
-# Get the format string for a trace event
+# Get the format string including double quotes for a trace event
 get_fmt()
 {
-    local fmt
-    fmt=${1#*\"}
-    fmt=${fmt%\"*}
-    echo "$fmt"
-}
-
-# Get the state of a trace event
-get_state()
-{
-    local str disable state
-    str=$(get_name "$1")
-    disable=${str##disable }
-    if [ "$disable" = "$str" ] ; then
-        state=1
-    else
-        state=0
-    fi
-    echo "$state"
+    puts "${1#*)}"
 }
 
 linetoh_begin_nop()
@@ -156,7 +169,7 @@ linetoc_end_nop()
 linetoh_begin_simple()
 {
     cat <<EOF
-#include "simpletrace.h"
+#include "trace/simple.h"
 EOF
 
     simple_event_num=0
@@ -172,14 +185,10 @@ cast_args_to_uint64_t()
 
 linetoh_simple()
 {
-    local name args argc trace_args state
+    local name args argc trace_args
     name=$(get_name "$1")
     args=$(get_args "$1")
     argc=$(get_argc "$1")
-    state=$(get_state "$1")
-    if [ "$state" = "0" ]; then
-        name=${name##disable }
-    fi
 
     trace_args="$simple_event_num"
     if [ "$argc" -gt 0 ]
@@ -218,14 +227,10 @@ EOF
 
 linetoc_simple()
 {
-    local name state
+    local name
     name=$(get_name "$1")
-    state=$(get_state "$1")
-    if [ "$state" = "0" ] ; then
-        name=${name##disable }
-    fi
     cat <<EOF
-{.tp_name = "$name", .state=$state},
+{.tp_name = "$name", .state=0},
 EOF
     simple_event_num=$((simple_event_num + 1))
 }
@@ -242,7 +247,12 @@ linetoh_begin_stderr()
 {
     cat <<EOF
 #include <stdio.h>
+#include "trace/stderr.h"
+
+extern TraceEvent trace_list[];
 EOF
+
+    stderr_event_num=0
 }
 
 linetoh_stderr()
@@ -261,29 +271,47 @@ linetoh_stderr()
     cat <<EOF
 static inline void trace_$name($args)
 {
-    fprintf(stderr, "$name $fmt\n" $argnames);
+    if (trace_list[$stderr_event_num].state != 0) {
+        fprintf(stderr, "$name " $fmt "\n" $argnames);
+    }
 }
 EOF
+    stderr_event_num=$((stderr_event_num + 1))
+
 }
 
 linetoh_end_stderr()
 {
-return
+    cat <<EOF
+#define NR_TRACE_EVENTS $stderr_event_num
+EOF
 }
 
 linetoc_begin_stderr()
 {
-return
+    cat <<EOF
+#include "trace.h"
+
+TraceEvent trace_list[] = {
+EOF
+    stderr_event_num=0
 }
 
 linetoc_stderr()
 {
-return
+    local name
+    name=$(get_name "$1")
+    cat <<EOF
+{.tp_name = "$name", .state=0},
+EOF
+    stderr_event_num=$(($stderr_event_num + 1))
 }
 
 linetoc_end_stderr()
 {
-return
+    cat <<EOF
+};
+EOF
 }
 #END OF STDERR
 
@@ -336,6 +364,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
@@ -343,7 +372,7 @@ DEFINE_TRACE(ust_$name);
 
 static void ust_${name}_probe($args)
 {
-    trace_mark(ust, $name, "$fmt", $argnames);
+    trace_mark(ust, $name, $fmt$argnames);
 }
 EOF
 
@@ -376,14 +405,10 @@ EOF
 
 linetoh_dtrace()
 {
-    local name args argnames state nameupper
+    local name args argnames nameupper
     name=$(get_name "$1")
     args=$(get_args "$1")
     argnames=$(get_argnames "$1", ",")
-    state=$(get_state "$1")
-    if [ "$state" = "0" ] ; then
-        name=${name##disable }
-    fi
 
     nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
 
@@ -427,13 +452,9 @@ EOF
 
 linetod_dtrace()
 {
-    local name args state
+    local name args
     name=$(get_name "$1")
     args=$(get_args "$1")
-    state=$(get_state "$1")
-    if [ "$state" = "0" ] ; then
-        name=${name##disable }
-    fi
 
     # DTrace provider syntax expects foo() for empty
     # params, not foo(void)
@@ -461,18 +482,14 @@ linetostap_begin_dtrace()
 
 linetostap_dtrace()
 {
-    local i arg name args arglist state
+    local i arg name args arglist
     name=$(get_name "$1")
     args=$(get_args "$1")
     arglist=$(get_argnames "$1", "")
-    state=$(get_state "$1")
-    if [ "$state" = "0" ] ; then
-        name=${name##disable }
-    fi
 
     # Define prototype for probe arguments
     cat <<EOF
-probe qemu.$targettype.$targetarch.$name = process("$binary").mark("$name")
+probe $probeprefix.$name = process("$binary").mark("$name")
 {
 EOF
 
@@ -486,7 +503,7 @@ EOF
         cat <<EOF
   $arg = \$arg$i;
 EOF
-       i="$((i+1))"
+        i="$((i+1))"
     done
 
     cat <<EOF
@@ -513,18 +530,10 @@ convert()
         # Skip comments and empty lines
         test -z "${str%%#*}" && continue
 
-        # Process the line.  The nop backend handles disabled lines.
-        disable=${str%%disable *}
         echo
-        if test -z "$disable"; then
-            # Pass the disabled state as an arg for the simple
-            # or DTrace backends which handle it dynamically.
-            # For all other backends, call lineto$1_nop()
-            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
-                "$process_line" "$str"
-            else
-                "lineto$1_nop" "${str##disable }"
-            fi
+        # Process the line.  The nop backend handles disabled lines.
+        if has_property "$str" "disable"; then
+            "lineto$1_nop" "$str"
         else
             "$process_line" "$str"
         fi
@@ -574,14 +583,17 @@ tracetostap()
        echo "--binary is required for SystemTAP tapset generator"
        exit 1
     fi
-    if [ -z "$targettype" ]; then
+    if [ -z "$probeprefix" -a -z "$targettype" ]; then
        echo "--target-type is required for SystemTAP tapset generator"
        exit 1
     fi
-    if [ -z "$targetarch" ]; then
+    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
        echo "--target-arch is required for SystemTAP tapset generator"
        exit 1
     fi
+    if [ -z "$probeprefix" ]; then
+        probeprefix="qemu.$targettype.$targetarch";
+    fi
     echo "/* This file is autogenerated by tracetool, do not edit. */"
     convert stap
 }
@@ -592,6 +604,7 @@ output=
 binary=
 targettype=
 targetarch=
+probeprefix=
 
 
 until [ -z "$1" ]
@@ -602,6 +615,7 @@ do
     "--binary") shift ; binary="$1" ;;
     "--target-arch") shift ; targetarch="$1" ;;
     "--target-type") shift ; targettype="$1" ;;
+    "--probe-prefix") shift ; probeprefix="$1" ;;
 
     "-h" | "-c" | "-d") output="${1#-}" ;;
     "--stap") output="${1#--}" ;;
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
new file mode 100755 (executable)
index 0000000..9d2a4bc
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh -e
+#
+# Update Linux kernel headers QEMU requires from a specified kernel tree.
+#
+# Copyright (C) 2011 Siemens AG
+#
+# Authors:
+#  Jan Kiszka        <jan.kiszka@siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+# See the COPYING file in the top-level directory.
+
+tmpdir=`mktemp -d`
+linux="$1"
+output="$2"
+
+if [ -z "$linux" ] || ! [ -d "$linux" ]; then
+    cat << EOF
+usage: update-kernel-headers.sh LINUX_PATH [OUTPUT_PATH]
+
+LINUX_PATH      Linux kernel directory to obtain the headers from
+OUTPUT_PATH     output directory, usually the qemu source tree (default: $PWD)
+EOF
+    exit 1
+fi
+
+if [ -z "$output" ]; then
+    output="$PWD"
+fi
+
+for arch in x86 powerpc s390; do
+    make -C "$linux" INSTALL_HDR_PATH="$tmpdir" SRCARCH=$arch headers_install
+
+    rm -rf "$output/linux-headers/asm-$arch"
+    mkdir -p "$output/linux-headers/asm-$arch"
+    for header in kvm.h kvm_para.h; do
+        cp "$tmpdir/include/asm/$header" "$output/linux-headers/asm-$arch"
+    done
+    if [ $arch = x86 ]; then
+        cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86"
+    fi
+done
+
+rm -rf "$output/linux-headers/linux"
+mkdir -p "$output/linux-headers/linux"
+for header in kvm.h kvm_para.h vhost.h virtio_config.h virtio_ring.h; do
+    cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
+done
+if [ -L "$linux/source" ]; then
+    cp "$linux/source/COPYING" "$output/linux-headers"
+else
+    cp "$linux/COPYING" "$output/linux-headers"
+fi
+
+rm -rf "$tmpdir"
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
new file mode 100644 (file)
index 0000000..5d7b8ac
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * ARP table
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "slirp.h"
+
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
+{
+    const uint32_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_add");
+    DEBUG_ARG("ip = 0x%x", ip_addr);
+    DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                ethaddr[0], ethaddr[1], ethaddr[2],
+                ethaddr[3], ethaddr[4], ethaddr[5]));
+
+    /* Check 0.0.0.0/8 invalid source-only addresses */
+    assert((ip_addr & htonl(~(0xf << 28))) != 0);
+
+    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+        /* Do not register broadcast addresses */
+        return;
+    }
+
+    /* Search for an entry */
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
+            /* Update the entry */
+            memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
+            return;
+        }
+    }
+
+    /* No entry found, create a new one */
+    arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
+    memcpy(arptbl->table[arptbl->next_victim].ar_sha,  ethaddr, ETH_ALEN);
+    arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
+}
+
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN])
+{
+    const uint32_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_search");
+    DEBUG_ARG("ip = 0x%x", ip_addr);
+
+    /* Check 0.0.0.0/8 invalid source-only addresses */
+    assert((ip_addr & htonl(~(0xf << 28))) != 0);
+
+    /* If broadcast address */
+    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+        /* return Ethernet broadcast address */
+        memset(out_ethaddr, 0xff, ETH_ALEN);
+        return 1;
+    }
+
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
+            memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
+            DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                        out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                        out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+            return 1;
+        }
+    }
+
+    return 0;
+}
index 0905c6d1bee4e3f67edb16ff43bd707e30d632e4..efd1fe777a3a774be93bb4d54941fd23e74af70b 100644 (file)
@@ -149,6 +149,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     struct in_addr preq_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
+    uint8_t client_ethaddr[ETH_ALEN];
 
     /* extract exact DHCP msg type */
     dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
@@ -164,8 +165,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     if (dhcp_msg_type != DHCPDISCOVER &&
         dhcp_msg_type != DHCPREQUEST)
         return;
-    /* XXX: this is a hack to get the client mac address */
-    memcpy(slirp->client_ethaddr, bp->bp_hwaddr, 6);
+
+    /* Get client's hardware address from bootp request */
+    memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
 
     m = m_get(slirp);
     if (!m) {
@@ -178,25 +180,25 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
 
     if (dhcp_msg_type == DHCPDISCOVER) {
         if (preq_addr.s_addr != htonl(0L)) {
-            bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+            bc = request_addr(slirp, &preq_addr, client_ethaddr);
             if (bc) {
                 daddr.sin_addr = preq_addr;
             }
         }
         if (!bc) {
          new_addr:
-            bc = get_new_addr(slirp, &daddr.sin_addr, slirp->client_ethaddr);
+            bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
             if (!bc) {
                 DPRINTF("no address left\n");
                 return;
             }
         }
-        memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+        memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
     } else if (preq_addr.s_addr != htonl(0L)) {
-        bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+        bc = request_addr(slirp, &preq_addr, client_ethaddr);
         if (bc) {
             daddr.sin_addr = preq_addr;
-            memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+            memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
         } else {
             daddr.sin_addr.s_addr = 0;
         }
@@ -209,6 +211,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
         }
     }
 
+    /* Update ARP table for this IP address */
+    arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
+
     saddr.sin_addr = slirp->vhost_addr;
     saddr.sin_port = htons(BOOTP_SERVER);
 
@@ -218,7 +223,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     rbp->bp_xid = bp->bp_xid;
     rbp->bp_htype = 1;
     rbp->bp_hlen = 6;
-    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
 
     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
@@ -284,7 +289,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     } else {
         static const char nak_msg[] = "requested address not available";
 
-        DPRINTF("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr));
+        DPRINTF("nak'ed addr=%08x\n", ntohl(preq_addr.s_addr));
 
         *q++ = RFC2132_MSG_TYPE;
         *q++ = 1;
index 0f04e13989afbbb5925584e65ae088b1ecc178a4..2852396a4a50ff14e80290f852a7b1389c430f2f 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <slirp.h>
+#include "qemu-timer.h"
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
@@ -153,6 +154,8 @@ diddit:
 void
 if_start(Slirp *slirp)
 {
+    uint64_t now = qemu_get_clock_ns(rt_clock);
+    int requeued = 0;
        struct mbuf *ifm, *ifqt;
 
        DEBUG_CALL("if_start");
@@ -199,11 +202,22 @@ if_start(Slirp *slirp)
                   ifm->ifq_so->so_nqueued = 0;
        }
 
-       /* Encapsulate the packet for sending */
-        if_encap(slirp, (uint8_t *)ifm->m_data, ifm->m_len);
-
-        m_free(ifm);
+        if (ifm->expiration_date < now) {
+            /* Expired */
+            m_free(ifm);
+        } else {
+            /* Encapsulate the packet for sending */
+            if (if_encap(slirp, ifm)) {
+                m_free(ifm);
+            } else {
+                /* re-queue */
+                insque(ifm, ifqt);
+                requeued++;
+            }
+        }
 
        if (slirp->if_queued)
           goto again;
+
+        slirp->if_queued = requeued;
 }
index 48ea38e5ecf29ce8b712a5ad6d55f03be6998205..88c903fccd186e7746a267741c58e28e440407a8 100644 (file)
@@ -74,10 +74,10 @@ typedef uint32_t n_long;                 /* long as received from the net */
  */
 struct ip {
 #ifdef HOST_WORDS_BIGENDIAN
-       u_int ip_v:4,                   /* version */
+       uint8_t ip_v:4,                 /* version */
                ip_hl:4;                /* header length */
 #else
-       u_int ip_hl:4,          /* header length */
+       uint8_t ip_hl:4,                /* header length */
                ip_v:4;                 /* version */
 #endif
        uint8_t         ip_tos;                 /* type of service */
@@ -91,7 +91,7 @@ struct ip {
        uint8_t ip_p;                   /* protocol */
        uint16_t        ip_sum;                 /* checksum */
        struct  in_addr ip_src,ip_dst;  /* source and dest address */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #define        IP_MAXPACKET    65535           /* maximum packet size */
 
@@ -140,10 +140,10 @@ struct    ip_timestamp {
        uint8_t ipt_len;                /* size of structure (variable) */
        uint8_t ipt_ptr;                /* index of current entry */
 #ifdef HOST_WORDS_BIGENDIAN
-       u_int   ipt_oflw:4,             /* overflow counter */
+       uint8_t ipt_oflw:4,             /* overflow counter */
                ipt_flg:4;              /* flags, see below */
 #else
-       u_int   ipt_flg:4,              /* flags, see below */
+       uint8_t ipt_flg:4,              /* flags, see below */
                ipt_oflw:4;             /* overflow counter */
 #endif
        union ipt_timestamp {
@@ -153,7 +153,7 @@ struct      ip_timestamp {
                        n_long ipt_time;
                } ipt_ta[1];
        } ipt_timestamp;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /* flag bits for ipt_flg */
 #define        IPOPT_TS_TSONLY         0               /* timestamps only */
@@ -183,11 +183,11 @@ struct    ip_timestamp {
 struct mbuf_ptr {
        struct mbuf *mptr;
        uint32_t dummy;
-} __attribute__((packed));
+} QEMU_PACKED;
 #else
 struct mbuf_ptr {
        struct mbuf *mptr;
-} __attribute__((packed));
+} QEMU_PACKED;
 #endif
 struct qlink {
        void *next, *prev;
@@ -203,7 +203,7 @@ struct ipovly {
        uint16_t        ih_len;                 /* protocol length */
        struct  in_addr ih_src;         /* source internet address */
        struct  in_addr ih_dst;         /* destination internet address */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /*
  * Ip reassembly queue structure.  Each fragment
@@ -219,7 +219,7 @@ struct ipq {
        uint8_t ipq_p;                  /* protocol of this fragment */
        uint16_t        ipq_id;                 /* sequence id for reassembly */
        struct  in_addr ipq_src,ipq_dst;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 /*
  * Ip header, when holding a fragment.
@@ -229,7 +229,7 @@ struct ipq {
 struct ipasfrag {
        struct qlink ipf_link;
        struct ip ipf_ip;
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #define ipf_off      ipf_ip.ip_off
 #define ipf_tos      ipf_ip.ip_tos
@@ -248,6 +248,6 @@ struct      ipasfrag {
 struct ipoption {
        struct  in_addr ipopt_dst;      /* first-hop dst if source routed */
        int8_t  ipopt_list[MAX_IPOPTLEN];       /* options proper */
-} __attribute__((packed));
+} QEMU_PACKED;
 
 #endif
index 154884e2ebb3a3afb178b7f5bb9fd0825df562cd..4b43994dbcb2e8884e119de0254b5d9e848a36e8 100644 (file)
@@ -60,59 +60,51 @@ static const int icmp_flush[19] = {
 /* ADDR MASK REPLY (18) */ 0
 };
 
-int icmp_attach(struct socket *so);
-void icmp_detach(struct socket *so);
-int icmp_cksum(u_short *p, int n);
-
-int
-icmp_attach(struct socket *so)
+void icmp_init(Slirp *slirp)
 {
-  /* same as udp_attach except socket creation */
-  if((so->s = qemu_socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) != -1) {
-    so->so_expire = curtime + SO_EXPIRE;
-    insque(so, &so->slirp->udb);
-  }
-  return(so->s);
+    slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
+    slirp->icmp_last_so = &slirp->icmp;
 }
 
-void
-icmp_detach(struct socket *so)
+static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
 {
-  /* same as udp_detach */
-  closesocket(so->s);
-  sofree(so);
+    struct ip *ip = mtod(m, struct ip *);
+    struct sockaddr_in addr;
+
+    so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (so->s == -1) {
+        return -1;
+    }
+
+    so->so_m = m;
+    so->so_faddr = ip->ip_dst;
+    so->so_laddr = ip->ip_src;
+    so->so_iptos = ip->ip_tos;
+    so->so_type = IPPROTO_ICMP;
+    so->so_state = SS_ISFCONNECTED;
+    so->so_expire = curtime + SO_EXPIRE;
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr = so->so_faddr;
+
+    insque(so, &so->slirp->icmp);
+
+    if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
+               (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
+                    errno, strerror(errno)));
+        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+        icmp_detach(so);
+    }
+
+    return 0;
 }
 
-int
-icmp_cksum(u_short *p, int n)
+void icmp_detach(struct socket *so)
 {
-    register u_short answer;
-    register long sum = 0;
-    u_short odd_byte = 0;
-
-    while( n > 1 )
-    {
-        sum += *p++;
-        n -= 2;
-   
-    }/* WHILE */
-
-
-    /* mop up an odd byte, if necessary */
-    if( n == 1 )
-    {
-        *( u_char* )( &odd_byte ) = *( u_char* )p;
-        sum += odd_byte;
-   
-    }/* IF */
-
-    sum = ( sum >> 16 ) + ( sum & 0xffff );    /* add hi 16 to low 16 */
-    sum += ( sum >> 16 );                    /* add carry */
-    answer = ~sum;                            /* ones-complement, truncate*/
-   
-    return ( answer );
-
-} /* in_cksum() */
+    closesocket(so->s);
+    sofree(so);
+}
 
 /*
  * Process a received ICMP message.
@@ -135,7 +127,7 @@ icmp_input(struct mbuf *m, int hlen)
    */
   if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
   freeit:
-    m_freem(m);
+    m_free(m);
     goto end_error;
   }
 
@@ -151,30 +143,19 @@ icmp_input(struct mbuf *m, int hlen)
   DEBUG_ARG("icmp_type = %d", icp->icmp_type);
   switch (icp->icmp_type) {
   case ICMP_ECHO:
-    icp->icmp_type = ICMP_ECHOREPLY;
     ip->ip_len += hlen;                     /* since ip_input subtracts this */
     if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
       icmp_reflect(m);
-#ifndef _WIN32
-    } else if( getuid() != 0 ) {
-      char commands[64];
-      int code;
-
-      sprintf( commands, "ping -c 1 %s", inet_ntoa(ip->ip_dst) );
-      code = system( commands ); 
-
-      if( WIFEXITED(code) && WEXITSTATUS(code) == 0 )
-        icmp_reflect(m);
-      else
-        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, "ping failed");
-#endif
+    } else if (slirp->restricted) {
+        goto freeit;
     } else {
-      char icmp_buf[128] ;
-      struct icmp *picmp = (struct icmp *)icmp_buf; 
       struct socket *so;
       struct sockaddr_in addr;
       if ((so = socreate(slirp)) == NULL) goto freeit;
-      if(icmp_attach(so) == -1) {
+      if (icmp_send(so, m, hlen) == 0) {
+        return;
+      }
+      if(udp_attach(so) == -1) {
        DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
                    errno,strerror(errno)));
        sofree(so);
@@ -205,21 +186,12 @@ icmp_input(struct mbuf *m, int hlen)
        addr.sin_addr = so->so_faddr;
       }
       addr.sin_port = so->so_fport;
-
-      picmp->icmp_type = ICMP_ECHO;
-      picmp->icmp_code = 0;
-      picmp->icmp_cksum = 0;
-      picmp->icmp_id = icp->icmp_id;
-      picmp->icmp_seq = icp->icmp_seq;
-      strcpy(icmp_buf+8, icmp_ping_msg);
-      picmp->icmp_cksum = icmp_cksum((u_short *)picmp, sizeof(icmp_ping_msg)+8);
-
-      if(sendto(so->s, picmp, sizeof(icmp_ping_msg)+8, 0,
+      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
                (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
                    errno,strerror(errno)));
        icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
-       icmp_detach(so);
+       udp_detach(so);
       }
     } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
     break;
@@ -231,11 +203,11 @@ icmp_input(struct mbuf *m, int hlen)
   case ICMP_TSTAMP:
   case ICMP_MASKREQ:
   case ICMP_REDIRECT:
-    m_freem(m);
+    m_free(m);
     break;
 
   default:
-    m_freem(m);
+    m_free(m);
   } /* swith */
 
 end_error:
@@ -397,6 +369,7 @@ icmp_reflect(struct mbuf *m)
   m->m_len -= hlen;
   icp = mtod(m, struct icmp *);
 
+  icp->icmp_type = ICMP_ECHOREPLY;
   icp->icmp_cksum = 0;
   icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
 
@@ -427,3 +400,39 @@ icmp_reflect(struct mbuf *m)
 
   (void ) ip_output((struct socket *)NULL, m);
 }
+
+void icmp_receive(struct socket *so)
+{
+    struct mbuf *m = so->so_m;
+    struct ip *ip = mtod(m, struct ip *);
+    int hlen = ip->ip_hl << 2;
+    u_char error_code;
+    struct icmp *icp;
+    int id, len;
+
+    m->m_data += hlen;
+    m->m_len -= hlen;
+    icp = mtod(m, struct icmp *);
+
+    id = icp->icmp_id;
+    len = qemu_recv(so->s, icp, m->m_len, 0);
+    icp->icmp_id = id;
+
+    m->m_data -= hlen;
+    m->m_len += hlen;
+
+    if (len == -1 || len == 0) {
+        if (errno == ENETUNREACH) {
+            error_code = ICMP_UNREACH_NET;
+        } else {
+            error_code = ICMP_UNREACH_HOST;
+        }
+        DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
+                    strerror(errno)));
+        icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
+    } else {
+        icmp_reflect(so->so_m);
+        so->so_m = NULL; /* Don't m_free() it again! */
+    }
+    icmp_detach(so);
+}
index 2692822f879542908a54035c8974816b1834cb79..b3da1f26977255e3fba7ec452b225b5cfc59fd4c 100644 (file)
@@ -153,9 +153,12 @@ struct icmp {
        (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
        (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
 
+void icmp_init(Slirp *slirp);
 void icmp_input(struct mbuf *, int);
 void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
                 const char *message);
 void icmp_reflect(struct mbuf *);
+void icmp_receive(struct socket *so);
+void icmp_detach(struct socket *so);
 
 #endif
index 768ab0cd497360ed1e29634603af86abbaafd26c..c7b3eb48069d70bf5b749242b1cc93b3ac798383 100644 (file)
@@ -58,6 +58,7 @@ ip_init(Slirp *slirp)
     slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
     udp_init(slirp);
     tcp_init(slirp);
+    icmp_init(slirp);
 }
 
 /*
@@ -118,27 +119,6 @@ ip_input(struct mbuf *m)
                goto bad;
        }
 
-    if (slirp->restricted) {
-        if ((ip->ip_dst.s_addr & slirp->vnetwork_mask.s_addr) ==
-            slirp->vnetwork_addr.s_addr) {
-            if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
-                goto bad;
-        } else {
-            uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
-            struct ex_list *ex_ptr;
-
-            if ((ip->ip_dst.s_addr & inv_mask) == inv_mask) {
-                goto bad;
-            }
-            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
-                if (ex_ptr->ex_addr.s_addr == ip->ip_dst.s_addr)
-                    break;
-
-            if (!ex_ptr)
-                goto bad;
-        }
-    }
-
        /* Should drop packet if mbuf too long? hmmm... */
        if (m->m_len > ip->ip_len)
           m_adj(m, ip->ip_len - m->m_len);
@@ -225,7 +205,7 @@ ip_input(struct mbuf *m)
        }
        return;
 bad:
-       m_freem(m);
+       m_free(m);
        return;
 }
 
@@ -318,7 +298,7 @@ ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
                        break;
                }
                q = q->ipf_next;
-               m_freem(dtom(slirp, q->ipf_prev));
+               m_free(dtom(slirp, q->ipf_prev));
                ip_deq(q->ipf_prev);
        }
 
@@ -384,7 +364,7 @@ insert:
        return ip;
 
 dropfrag:
-       m_freem(m);
+       m_free(m);
         return NULL;
 }
 
@@ -400,7 +380,7 @@ ip_freef(Slirp *slirp, struct ipq *fp)
        for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
                p = q->ipf_next;
                ip_deq(q);
-               m_freem(dtom(slirp, q));
+               m_free(dtom(slirp, q));
        }
        remque(&fp->ip_link);
        (void) m_free(dtom(slirp, fp));
@@ -531,7 +511,7 @@ typedef uint32_t n_time;
                                 */
                                break;
                        }
-                       off--;                  / * 0 origin *  /
+                        off--; /* 0 origin */
                        if (off > optlen - sizeof(struct in_addr)) {
                                /*
                                 * End of source route.  Should be for us.
@@ -574,7 +554,7 @@ typedef uint32_t n_time;
                        /*
                         * If no space remains, ignore.
                         */
-                       off--;                   * 0 origin *
+                        off--; /* 0 origin */
                        if (off > optlen - sizeof(struct in_addr))
                                break;
                        bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
index 542f3180beb7ee99ab85cf8cc51d3f3b3e18671e..c82830fe7d299236b04090e2199d20c4602b95d8 100644 (file)
@@ -159,7 +159,7 @@ sendorfree:
                if (error == 0)
                        if_output(so, m);
                else
-                       m_freem(m);
+                       m_free(m);
        }
     }
 
@@ -167,6 +167,6 @@ done:
        return (error);
 
 bad:
-       m_freem(m0);
+       m_free(m0);
        goto done;
 }
index 67c70e32e3c3f71fa533f02a774147339c7d69b1..890fd86c3c93121455fc163555addb680f91597f 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef _LIBSLIRP_H
 #define _LIBSLIRP_H
 
-#include <qemu-common.h>
-
-#ifdef CONFIG_SLIRP
+#include "qemu-common.h"
 
 struct Slirp;
 typedef struct Slirp Slirp;
@@ -44,13 +42,4 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
                              int guest_port);
 
-#else /* !CONFIG_SLIRP */
-
-static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
-                                     fd_set *writefds, fd_set *xfds) { }
-
-static inline void slirp_select_poll(fd_set *readfds, fd_set *writefds,
-                                     fd_set *xfds, int select_error) { }
-#endif /* !CONFIG_SLIRP */
-
 #endif
index 0dd8d81ce4edc05f85b1d4426a13ed3dd6e20e74..028df4b36157c8f6c540098518d45cddd236d346 100644 (file)
@@ -42,5 +42,5 @@ extern int tcp_keepintvl;
 #define PROTO_PPP 0x2
 #endif
 
-void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len);
+int if_encap(Slirp *slirp, struct mbuf *ifm);
 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
index ce2eb843f565dd2c7c53cc024111d892e73ad67b..c699c750962b9533fd148a486d4228b6b1ba8c33 100644 (file)
@@ -70,6 +70,8 @@ m_get(Slirp *slirp)
        m->m_len = 0;
         m->m_nextpkt = NULL;
         m->m_prevpkt = NULL;
+        m->arp_requested = false;
+        m->expiration_date = (uint64_t)-1;
 end_error:
        DEBUG_ARG("m = %lx", (long )m);
        return m;
index 97729e24b00b4021fe7dd296001b17053665eb56..0708840f04e78d675b623043ae980e697e7e32d9 100644 (file)
@@ -33,9 +33,6 @@
 #ifndef _MBUF_H_
 #define _MBUF_H_
 
-#define m_freem m_free
-
-
 #define MINCSIZE 4096  /* Amount to increase mbuf if too small */
 
 /*
@@ -85,6 +82,9 @@ struct m_hdr {
 struct mbuf {
        struct  m_hdr m_hdr;
        Slirp *slirp;
+       bool    arp_requested;
+       uint64_t expiration_date;
+       /* start of dynamic buffer area, must be last element */
        union M_dat {
                char    m_dat_[1]; /* ANSI don't like 0 sized arrays */
                char    *m_ext_;
index 19dbec491f032a5e2eb9144241d6c34ac21d41cc..6c80e69685c2d4525ca5519ab9c5b1c2e0c8a161 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);
@@ -151,11 +153,12 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
                return 0;
 
         case 0:
+                setsid();
+
                /* Set the DISPLAY */
                if (do_pty == 2) {
                        (void) close(master);
 #ifdef TIOCSCTTY /* XXXXX */
-                       (void) setsid();
                        ioctl(s, TIOCSCTTY, (char *)NULL);
 #endif
                } else {
@@ -179,7 +182,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
                   close(s);
 
                i = 0;
-               bptr = qemu_strdup(ex); /* No need to free() this */
+               bptr = g_strdup(ex); /* No need to free() this */
                if (do_pty == 1) {
                        /* Setup "slirp.telnetd -x" */
                        argv[i++] = "slirp.telnetd";
@@ -206,6 +209,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;
@@ -403,4 +407,17 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
                        inet_ntoa(dst_addr), ntohs(dst_port),
                        so->so_rcv.sb_cc, so->so_snd.sb_cc);
     }
+
+    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
+        n = snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
+                     (so->so_expire - curtime) / 1000);
+        src.sin_addr = so->so_laddr;
+        dst_addr = so->so_faddr;
+        memset(&buf[n], ' ', 19 - n);
+        buf[19] = 0;
+        monitor_printf(mon, "%s %3d %15s  -    ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
+        monitor_printf(mon, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
 }
index 332d83b64d054750a0f25114a5b81cbed4095d60..19d69eb623c29f7042ef55c84311d8bcac7cd74a 100644 (file)
 struct in_addr loopback_addr;
 
 /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
-static const uint8_t special_ethaddr[6] = {
+static const uint8_t special_ethaddr[ETH_ALEN] = {
     0x52, 0x55, 0x00, 0x00, 0x00, 0x00
 };
 
-static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
 /* XXX: suppress those select globals */
 fd_set *global_readfds, *global_writefds, *global_xfds;
@@ -202,7 +202,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                   const char *bootfile, struct in_addr vdhcp_start,
                   struct in_addr vnameserver, void *opaque)
 {
-    Slirp *slirp = qemu_mallocz(sizeof(Slirp));
+    Slirp *slirp = g_malloc0(sizeof(Slirp));
 
     slirp_init_once();
 
@@ -222,10 +222,10 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                 vhostname);
     }
     if (tftp_path) {
-        slirp->tftp_prefix = qemu_strdup(tftp_path);
+        slirp->tftp_prefix = g_strdup(tftp_path);
     }
     if (bootfile) {
-        slirp->bootp_filename = qemu_strdup(bootfile);
+        slirp->bootp_filename = g_strdup(bootfile);
     }
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
@@ -246,9 +246,9 @@ void slirp_cleanup(Slirp *slirp)
 
     unregister_savevm(NULL, "slirp", slirp);
 
-    qemu_free(slirp->tftp_prefix);
-    qemu_free(slirp->bootp_filename);
-    qemu_free(slirp);
+    g_free(slirp->tftp_prefix);
+    g_free(slirp->bootp_filename);
+    g_free(slirp);
 }
 
 #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
@@ -373,6 +373,31 @@ void slirp_select_fill(int *pnfds,
                                UPD_NFDS(so->s);
                        }
                }
+
+                /*
+                 * ICMP sockets
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                    so_next = so->so_next;
+
+                    /*
+                     * See if it's timed out
+                     */
+                    if (so->so_expire) {
+                        if (so->so_expire <= curtime) {
+                            icmp_detach(so);
+                            continue;
+                        } else {
+                            do_slowtimo = 1; /* Let socket expire */
+                        }
+                    }
+
+                    if (so->so_state & SS_ISFCONNECTED) {
+                        FD_SET(so->s, readfds);
+                        UPD_NFDS(so->s);
+                    }
+                }
        }
 
         *pnfds = nfds;
@@ -393,7 +418,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
     global_writefds = writefds;
     global_xfds = xfds;
 
-    curtime = qemu_get_clock(rt_clock);
+    curtime = qemu_get_clock_ms(rt_clock);
 
     QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
        /*
@@ -497,7 +522,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
                         */
 #ifdef PROBE_CONN
                        if (so->so_state & SS_ISFCONNECTING) {
-                         ret = recv(so->s, (char *)&ret, 0,0);
+                          ret = qemu_recv(so->s, &ret, 0,0);
 
                          if (ret < 0) {
                            /* XXX */
@@ -542,6 +567,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
                             sorecvfrom(so);
                         }
                }
+
+                /*
+                 * Check incoming ICMP relies.
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                     so_next = so->so_next;
+
+                    if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                        icmp_receive(so);
+                    }
+                }
        }
 
        /*
@@ -562,42 +599,8 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
         global_xfds = NULL;
 }
 
-#define ETH_ALEN 6
-#define ETH_HLEN 14
-
-#define ETH_P_IP       0x0800          /* Internet Protocol packet     */
-#define ETH_P_ARP      0x0806          /* Address Resolution packet    */
-
-#define        ARPOP_REQUEST   1               /* ARP request                  */
-#define        ARPOP_REPLY     2               /* ARP reply                    */
-
-struct ethhdr
-{
-       unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
-       unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
-       unsigned short  h_proto;                /* packet type ID field */
-};
-
-struct arphdr
-{
-       unsigned short  ar_hrd;         /* format of hardware address   */
-       unsigned short  ar_pro;         /* format of protocol address   */
-       unsigned char   ar_hln;         /* length of hardware address   */
-       unsigned char   ar_pln;         /* length of protocol address   */
-       unsigned short  ar_op;          /* ARP opcode (command)         */
-
-        /*
-         *      Ethernet looks like this : This bit is variable sized however...
-         */
-       unsigned char           ar_sha[ETH_ALEN];       /* sender hardware address      */
-       uint32_t                ar_sip;                 /* sender IP address            */
-       unsigned char           ar_tha[ETH_ALEN];       /* target hardware address      */
-       uint32_t                ar_tip  ;               /* target IP address            */
-} __attribute__((packed));
-
 static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
 {
-    struct ethhdr *eh = (struct ethhdr *)pkt;
     struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
     uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
     struct ethhdr *reh = (struct ethhdr *)arp_reply;
@@ -608,6 +611,12 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
     ar_op = ntohs(ah->ar_op);
     switch(ar_op) {
     case ARPOP_REQUEST:
+        if (ah->ar_tip == ah->ar_sip) {
+            /* Gratuitous ARP */
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
+            return;
+        }
+
         if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
             slirp->vnetwork_addr.s_addr) {
             if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
@@ -620,8 +629,8 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
             return;
         arp_ok:
             memset(arp_reply, 0, sizeof(arp_reply));
-            /* XXX: make an ARP request to have the client address */
-            memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
+
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
 
             /* ARP request for alias/dns mac address */
             memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
@@ -642,11 +651,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         }
         break;
     case ARPOP_REPLY:
-        /* reply to request of client mac address ? */
-        if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
-            ah->ar_sip == slirp->client_ipaddr.s_addr) {
-            memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
-        }
+        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
         break;
     default:
         break;
@@ -687,54 +692,66 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
     }
 }
 
-/* output the IP packet to the ethernet device */
-void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
+/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
+ * re-queued.
+ */
+int if_encap(Slirp *slirp, struct mbuf *ifm)
 {
     uint8_t buf[1600];
     struct ethhdr *eh = (struct ethhdr *)buf;
+    uint8_t ethaddr[ETH_ALEN];
+    const struct ip *iph = (const struct ip *)ifm->m_data;
 
-    if (ip_data_len + ETH_HLEN > sizeof(buf))
-        return;
-    
-    if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
+        return 1;
+    }
+
+    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;
         struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
-        const struct ip *iph = (const struct ip *)ip_data;
-
-        /* If the client addr is not known, there is no point in
-           sending the packet to it. Normally the sender should have
-           done an ARP request to get its MAC address. Here we do it
-           in place of sending the packet and we hope that the sender
-           will retry sending its packet. */
-        memset(reh->h_dest, 0xff, ETH_ALEN);
-        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
-        memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
-        reh->h_proto = htons(ETH_P_ARP);
-        rah->ar_hrd = htons(1);
-        rah->ar_pro = htons(ETH_P_IP);
-        rah->ar_hln = ETH_ALEN;
-        rah->ar_pln = 4;
-        rah->ar_op = htons(ARPOP_REQUEST);
-        /* source hw addr */
-        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
-        memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
-        /* source IP */
-        rah->ar_sip = slirp->vhost_addr.s_addr;
-        /* target hw addr (none) */
-        memset(rah->ar_tha, 0, ETH_ALEN);
-        /* target IP */
-        rah->ar_tip = iph->ip_dst.s_addr;
-        slirp->client_ipaddr = iph->ip_dst;
-        slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+
+        if (!ifm->arp_requested) {
+            /* If the client addr is not known, send an ARP request */
+            memset(reh->h_dest, 0xff, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
+            reh->h_proto = htons(ETH_P_ARP);
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REQUEST);
+
+            /* source hw addr */
+            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
+
+            /* source IP */
+            rah->ar_sip = slirp->vhost_addr.s_addr;
+
+            /* target hw addr (none) */
+            memset(rah->ar_tha, 0, ETH_ALEN);
+
+            /* target IP */
+            rah->ar_tip = iph->ip_dst.s_addr;
+            slirp->client_ipaddr = iph->ip_dst;
+            slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+            ifm->arp_requested = true;
+
+            /* Expire request and drop outgoing packet after 1 second */
+            ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
+        }
+        return 0;
     } else {
-        memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
+        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
         memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
         /* XXX: not correct */
         memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
         eh->h_proto = htons(ETH_P_IP);
-        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
-        slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
+        memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
+        slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+        return 1;
     }
 }
 
@@ -801,7 +818,7 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
 {
        if (so->s == -1 && so->extra) {
-               qemu_chr_write(so->extra, buf, len);
+               qemu_chr_fe_write(so->extra, buf, len);
                return len;
        }
 
index 954289a8c8c3b1539b84db26798eaf3f22c86268..28a5c037e6aa4f25f628e63ea0636ab5bd0eb8f4 100644 (file)
@@ -152,6 +152,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
 #include "tcp_var.h"
 #include "tcpip.h"
 #include "udp.h"
+#include "ip_icmp.h"
 #include "mbuf.h"
 #include "sbuf.h"
 #include "socket.h"
@@ -169,6 +170,48 @@ int inet_aton(const char *cp, struct in_addr *ia);
 /* osdep.c */
 int qemu_socket(int domain, int type, int protocol);
 
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP  0x0800        /* Internet Protocol packet  */
+#define ETH_P_ARP 0x0806        /* Address Resolution packet */
+
+#define ARPOP_REQUEST 1         /* ARP request */
+#define ARPOP_REPLY   2         /* ARP reply   */
+
+struct ethhdr {
+    unsigned char  h_dest[ETH_ALEN];   /* destination eth addr */
+    unsigned char  h_source[ETH_ALEN]; /* source ether addr    */
+    unsigned short h_proto;            /* packet type ID field */
+};
+
+struct arphdr {
+    unsigned short ar_hrd;      /* format of hardware address */
+    unsigned short ar_pro;      /* format of protocol address */
+    unsigned char  ar_hln;      /* length of hardware address */
+    unsigned char  ar_pln;      /* length of protocol address */
+    unsigned short ar_op;       /* ARP opcode (command)       */
+
+    /*
+     *  Ethernet looks like this : This bit is variable sized however...
+     */
+    unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+    uint32_t      ar_sip;           /* sender IP address       */
+    unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+    uint32_t      ar_tip;           /* target IP address       */
+} QEMU_PACKED;
+
+#define ARP_TABLE_SIZE 16
+
+typedef struct ArpTable {
+    struct arphdr table[ARP_TABLE_SIZE];
+    int next_victim;
+} ArpTable;
+
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
+
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN]);
 
 struct Slirp {
     QTAILQ_ENTRY(Slirp) entry;
@@ -180,9 +223,6 @@ struct Slirp {
     struct in_addr vdhcp_startaddr;
     struct in_addr vnameserver_addr;
 
-    /* ARP cache for the guest IP addresses (XXX: allow many entries) */
-    uint8_t client_ethaddr[6];
-
     struct in_addr client_ipaddr;
     char client_hostname[33];
 
@@ -218,10 +258,16 @@ struct Slirp {
     struct socket udb;
     struct socket *udp_last_so;
 
+    /* icmp states */
+    struct socket icmp;
+    struct socket *icmp_last_so;
+
     /* tftp states */
     char *tftp_prefix;
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
+    ArpTable arp_table;
+
     void *opaque;
 };
 
index c97691c096890aba8606dfc62002c9102202ed5f..77b0c9819785342087b63b8d55de92ce76872ddb 100644 (file)
@@ -71,6 +71,8 @@ sofree(struct socket *so)
       slirp->tcp_last_so = &slirp->tcb;
   } else if (so == slirp->udp_last_so) {
       slirp->udp_last_so = &slirp->udb;
+  } else if (so == slirp->icmp_last_so) {
+      slirp->icmp_last_so = &slirp->icmp;
   }
   m_free(so->so_m);
 
@@ -164,7 +166,7 @@ soread(struct socket *so)
        nn = readv(so->s, (struct iovec *)iov, n);
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
 #else
-       nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
+       nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
 #endif
        if (nn <= 0) {
                if (nn < 0 && (errno == EINTR || errno == EAGAIN))
@@ -189,7 +191,7 @@ soread(struct socket *so)
         */
        if (n == 2 && nn == iov[0].iov_len) {
             int ret;
-            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+            ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
             if (ret > 0)
                 nn += ret;
         }
@@ -624,8 +626,8 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
        addr.sin_port = hport;
 
        if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
-           (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
            (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
+           (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
            (listen(s,1) < 0)) {
                int tmperrno = errno; /* Don't clobber the real reason we failed */
 
index 9d06836626f6a53c7413deb677f633293db3bf18..b3817cb13c7a4c350fc24be15afd1a1743feba16 100644 (file)
@@ -51,10 +51,10 @@ struct tcphdr {
        tcp_seq th_seq;                 /* sequence number */
        tcp_seq th_ack;                 /* acknowledgement number */
 #ifdef HOST_WORDS_BIGENDIAN
-       u_int   th_off:4,               /* data offset */
+       uint8_t th_off:4,               /* data offset */
                th_x2:4;                /* (unused) */
 #else
-       u_int   th_x2:4,                /* (unused) */
+       uint8_t th_x2:4,                /* (unused) */
                th_off:4;               /* data offset */
 #endif
        uint8_t th_flags;
index e4a77310d012b928754c7708352449038d26356b..942aaf44f1b9e11965c3020d014cf40327bbe5d7 100644 (file)
@@ -136,7 +136,7 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
                i = q->ti_seq + q->ti_len - ti->ti_seq;
                if (i > 0) {
                        if (i >= ti->ti_len) {
-                               m_freem(m);
+                               m_free(m);
                                /*
                                 * Try to present any queued data
                                 * at the left window edge to the user.
@@ -170,7 +170,7 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
                q = tcpiphdr_next(q);
                m = tcpiphdr_prev(q)->ti_mbuf;
                remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
-               m_freem(m);
+               m_free(m);
        }
 
        /*
@@ -197,7 +197,7 @@ present:
                m = ti->ti_mbuf;
                ti = tcpiphdr_next(ti);
                if (so->so_state & SS_FCANTSENDMORE)
-                       m_freem(m);
+                       m_free(m);
                else {
                        if (so->so_emu) {
                                if (tcp_emu(so,m)) sbappend(so, m);
@@ -231,7 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
     Slirp *slirp;
 
        DEBUG_CALL("tcp_input");
-       DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
+       DEBUG_ARGS((dfd, " m = %8lx  iphlen = %2d  inso = %lx\n",
                    (long )m, iphlen, (long )inso ));
 
        /*
@@ -451,7 +451,7 @@ findso:
                                acked = ti->ti_ack - tp->snd_una;
                                sbdrop(&so->so_snd, acked);
                                tp->snd_una = ti->ti_ack;
-                               m_freem(m);
+                               m_free(m);
 
                                /*
                                 * If all outstanding data are acked, stop
@@ -580,7 +580,7 @@ findso:
 
          if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
            u_char code=ICMP_UNREACH_NET;
-           DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
+           DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
                        errno,strerror(errno)));
            if(errno == ECONNREFUSED) {
              /* ACK the SYN, send RST to refuse the connection */
@@ -610,6 +610,7 @@ findso:
            so->so_ti = ti;
            tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
            tp->t_state = TCPS_SYN_RECEIVED;
+           tcp_template(tp);
          }
          return;
 
@@ -910,7 +911,7 @@ trimthenstep6:
 
                if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
                        if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
-                         DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
+                         DEBUG_MISC((dfd, " dup ack  m = %lx  so = %lx\n",
                                      (long )m, (long )so));
                                /*
                                 * If we have outstanding data (other than
@@ -1155,6 +1156,16 @@ step6:
                        tp->rcv_up = tp->rcv_nxt;
 dodata:
 
+       /*
+        * If this is a small packet, then ACK now - with Nagel
+        *      congestion avoidance sender won't send more until
+        *      he gets an ACK.
+        */
+       if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
+           ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
+               tp->t_flags |= TF_ACKNOW;
+       }
+
        /*
         * Process the segment text, merging it into the TCP sequencing queue,
         * and arranging for acknowledgment of receipt if necessary.
@@ -1233,18 +1244,6 @@ dodata:
                }
        }
 
-       /*
-        * If this is a small packet, then ACK now - with Nagel
-        *      congestion avoidance sender won't send more until
-        *      he gets an ACK.
-        *
-        * See above.
-        */
-       if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
-           ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
-               tp->t_flags |= TF_ACKNOW;
-       }
-
        /*
         * Return any desired output.
         */
@@ -1260,7 +1259,7 @@ dropafterack:
         */
        if (tiflags & TH_RST)
                goto drop;
-       m_freem(m);
+       m_free(m);
        tp->t_flags |= TF_ACKNOW;
        (void) tcp_output(tp);
        return;
@@ -1293,7 +1292,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
        int opt, optlen;
 
        DEBUG_CALL("tcp_dooptions");
-       DEBUG_ARGS((dfd," tp = %lx  cnt=%i \n", (long )tp, cnt));
+       DEBUG_ARGS((dfd, " tp = %lx  cnt=%i\n", (long)tp, cnt));
 
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                opt = cp[0];
index b661d2623c52c3d180260d6038b435d7934e7122..143a2383c8570b9d6f971629a098eec917366ab0 100644 (file)
@@ -250,7 +250,7 @@ tcp_close(struct tcpcb *tp)
                t = tcpiphdr_next(t);
                m = tcpiphdr_prev(t)->ti_mbuf;
                remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
-               m_freem(m);
+               m_free(m);
        }
        free(tp);
         so->so_tcpcb = NULL;
@@ -902,7 +902,7 @@ int tcp_ctl(struct socket *so)
                     return 1;
                 }
                 do_pty = ex_ptr->ex_pty;
-                DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
+                DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
                 return fork_exec(so, ex_ptr->ex_exec, do_pty);
             }
         }
index 1821648251f9d093bfb1ffa1b626c7d1b080e785..b78765f3af1b0febd7feea6a98f422b6b9207b81 100644 (file)
@@ -37,7 +37,7 @@ static inline void tftp_session_update(struct tftp_session *spt)
 
 static void tftp_session_terminate(struct tftp_session *spt)
 {
-    qemu_free(spt->filename);
+    g_free(spt->filename);
     spt->slirp = NULL;
 }
 
@@ -54,7 +54,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
 
     /* sessions time out after 5 inactive seconds */
     if ((int)(curtime - spt->timestamp) > 5000) {
-        qemu_free(spt->filename);
+        g_free(spt->filename);
         goto found;
     }
   }
@@ -136,9 +136,9 @@ static int tftp_send_oack(struct tftp_session *spt,
     m->m_data += sizeof(struct udpiphdr);
 
     tp->tp_op = htons(TFTP_OACK);
-    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
+    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
                   key) + 1;
-    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
+    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
                   value) + 1;
 
     saddr.sin_addr = recv_tp->ip.ip_dst;
@@ -283,11 +283,11 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
 
   /* skip header fields */
   k = 0;
-  pktlen -= ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp);
+  pktlen -= offsetof(struct tftp_t, x.tp_buf);
 
   /* prepend tftp_prefix */
   prefix_len = strlen(slirp->tftp_prefix);
-  spt->filename = qemu_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
+  spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
   memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
   spt->filename[prefix_len] = '/';
 
@@ -299,7 +299,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
     }
-    req_fname[k] = (char)tp->x.tp_buf[k];
+    req_fname[k] = tp->x.tp_buf[k];
     if (req_fname[k++] == '\0') {
       break;
     }
@@ -311,7 +311,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
     return;
   }
 
-  if (strcasecmp((const char *)&tp->x.tp_buf[k], "octet") != 0) {
+  if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
       tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
       return;
   }
@@ -340,7 +340,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
   while (k < pktlen) {
       const char *key, *value;
 
-      key = (const char *)&tp->x.tp_buf[k];
+      key = &tp->x.tp_buf[k];
       k += strlen(key) + 1;
 
       if (k >= pktlen) {
@@ -348,7 +348,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
          return;
       }
 
-      value = (const char *)&tp->x.tp_buf[k];
+      value = &tp->x.tp_buf[k];
       k += strlen(value) + 1;
 
       if (strcasecmp(key, "tsize") == 0) {
index b9f0847eb9310177a035d267f93ad54885e8e53d..72e5e91bef6bccc35d7788d40bd29c8686569638 100644 (file)
@@ -26,7 +26,7 @@ struct tftp_t {
       uint16_t tp_error_code;
       uint8_t tp_msg[512];
     } tp_error;
-    uint8_t tp_buf[512 + 2];
+    char tp_buf[512 + 2];
   } x;
 };
 
index 02b3793e9f1dace1de9101780e448c3619dff0ff..5b060f397bbb25b88e39f0557b265a11969ed406 100644 (file)
@@ -120,23 +120,26 @@ udp_input(register struct mbuf *m, int iphlen)
         /*
          *  handle DHCP/BOOTP
          */
-        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
-            bootp_input(m);
-            goto bad;
-        }
-
-        if (slirp->restricted) {
-            goto bad;
-        }
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
+            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+             ip->ip_dst.s_addr == 0xffffffff)) {
+                bootp_input(m);
+                goto bad;
+            }
 
         /*
          *  handle TFTP
          */
-        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
+        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
             tftp_input(m);
             goto bad;
         }
 
+        if (slirp->restricted) {
+            goto bad;
+        }
+
        /*
         * Locate pcb for datagram.
         */
@@ -219,7 +222,7 @@ udp_input(register struct mbuf *m, int iphlen)
 
        return;
 bad:
-       m_freem(m);
+       m_free(m);
        return;
 }
 
index 79278cc763a0e2e2c4dae3e5ea43da6628a5edcf..86a9f8a846774a22f763217904e7138732186a50 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2007 CodeSourcery.
  *
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
  */
 
 static inline uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
index e38bb752f1508032a4fed205e35a8eeda0ba813d..c5a2bcd3e21d645d3dd8e1350ea814f4535174d1 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ *  Software MMU support
+ *
+ * Declare helpers used by TCG for qemu_ld/st ops.
+ *
+ * Used by softmmu_exec.h, TCG targets and exec-all.h.
+ *
+ */
 #ifndef SOFTMMU_DEFS_H
 #define SOFTMMU_DEFS_H
 
index 28d1d53d61e29e9ff628db5e763c53511f75157c..8c73985599f8ba5371c245c4e69b474010c91cc6 100644 (file)
@@ -1,4 +1,14 @@
-/* Common softmmu definitions and inline routines.  */
+/*
+ *  Software MMU support
+ *
+ * Generate inline load/store functions for all MMU modes (typically
+ * at least _user and _kernel) as well as _data versions, for all data
+ * sizes.
+ *
+ * Used by target op helpers.
+ *
+ * MMU mode suffixes are defined in target cpu.h.
+ */
 
 /* XXX: find something cleaner.
  * Furthermore, this is false for 64 bits targets
index 2f95c334094cf49f8ee0937ba35e481ccbc79029..818d7b662efca9abd4ba2b8346c2a5c3ebe494fe 100644 (file)
@@ -1,6 +1,15 @@
 /*
  *  Software MMU support
  *
+ * Generate inline load/store functions for one MMU mode and data
+ * size.
+ *
+ * Generate a store function as well as signed and unsigned loads. For
+ * 32 and 64 bit cases, also generate floating point functions with
+ * the same size.
+ *
+ * Not used directly but included from softmmu_exec.h and exec-all.h.
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
index 73136ae1b13dd0affd54fac07bcf7a981b9677af..71360c14ff6ad67f15374a4dfbf281dcca6e718d 100644 (file)
@@ -1,6 +1,11 @@
 /*
  *  Software MMU support
  *
+ * Generate helpers used by TCG for qemu_ld/st ops and code load
+ * functions.
+ *
+ * Included from target op helpers and exec.c.
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -131,30 +136,23 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
         if ((addr & (DATA_SIZE - 1)) != 0)
             do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 #endif
-        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
     return res;
 }
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && !defined(SOFTMMU_CODE_ACCESS)
-/*
- * extended versions of MMU helpers for x86 TCG target optimization
- * !defined(SOFTMMU_CODE_ACCESS) suppress warnings from exec.c
- */
-DATA_TYPE REGPARM glue(glue(__ldext, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                         int mmu_idx,
-                                                         void *ra)
+/* handle all unaligned cases */
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                        int mmu_idx,
+                                                        void *retaddr)
 {
-    DATA_TYPE res;
-    int index;
-    target_ulong tlb_addr;
+    DATA_TYPE res, res1, res2;
+    int index, shift;
     target_phys_addr_t ioaddr;
     unsigned long addend;
-    void *retaddr;
+    target_ulong tlb_addr, addr1, addr2;
 
-    /* test if there is match for unaligned or IO access */
-    /* XXX: could done more in memory macro in a non portable way */
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
     tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
@@ -163,54 +161,55 @@ DATA_TYPE REGPARM glue(glue(__ldext, SUFFIX), MMUSUFFIX)(target_ulong addr,
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
-            retaddr = ra;
             ioaddr = env->iotlb[mmu_idx][index];
             res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
-            /* slow unaligned access (it spans two pages or IO) */
         do_unaligned_access:
-            retaddr = ra;
-#ifdef ALIGNED_ONLY
-            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+            /* slow unaligned access (it spans two pages) */
+            addr1 = addr & ~(DATA_SIZE - 1);
+            addr2 = addr1 + DATA_SIZE;
+            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
+                                                          mmu_idx, retaddr);
+            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
+                                                          mmu_idx, retaddr);
+            shift = (addr & (DATA_SIZE - 1)) * 8;
+#ifdef TARGET_WORDS_BIGENDIAN
+            res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
+#else
+            res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
 #endif
-            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
-                                                         mmu_idx, retaddr);
+            res = (DATA_TYPE)res;
         } else {
             /* unaligned/aligned access in the same page */
-#ifdef ALIGNED_ONLY
-            if ((addr & (DATA_SIZE - 1)) != 0) {
-                retaddr = ra;
-                do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
-            }
-#endif
             addend = env->tlb_table[mmu_idx][index].addend;
             res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
         }
     } else {
         /* the page is not in the TLB : fill it */
-        retaddr = ra;
-#ifdef ALIGNED_ONLY
-        if ((addr & (DATA_SIZE - 1)) != 0)
-            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
-#endif
-        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
     return res;
 }
-#endif  /* CONFIG_TCG_TARGET_X86_OPT */
 
-/* handle all unaligned cases */
-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                        int mmu_idx,
-                                                        void *retaddr)
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && !defined(SOFTMMU_CODE_ACCESS)
+/* Extended versions of MMU helpers for qemu_ld IR optimization.
+   They get return address arguments because the caller PCs are not where helpers return to.
+   !defined(SOFTMMU_CODE_ACCESS) suppress warnings from exec.c */
+#if defined(__i386__) || defined(__x86_64__)
+DATA_TYPE REGPARM glue(glue(__ldext, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                         int mmu_idx,
+                                                         void *ra)
 {
-    DATA_TYPE res, res1, res2;
-    int index, shift;
+    DATA_TYPE res;
+    int index;
+    target_ulong tlb_addr;
     target_phys_addr_t ioaddr;
     unsigned long addend;
-    target_ulong tlb_addr, addr1, addr2;
+    void *retaddr;
 
+    /* test if there is match for unaligned or IO access */
+    /* XXX: could done more in memory macro in a non portable way */
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
     tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
@@ -219,36 +218,43 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
+            retaddr = ra;
             ioaddr = env->iotlb[mmu_idx][index];
             res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+            /* slow unaligned access (it spans two pages or IO) */
         do_unaligned_access:
-            /* slow unaligned access (it spans two pages) */
-            addr1 = addr & ~(DATA_SIZE - 1);
-            addr2 = addr1 + DATA_SIZE;
-            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
-                                                          mmu_idx, retaddr);
-            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
-                                                          mmu_idx, retaddr);
-            shift = (addr & (DATA_SIZE - 1)) * 8;
-#ifdef TARGET_WORDS_BIGENDIAN
-            res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
-#else
-            res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
+            retaddr = ra;
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 #endif
-            res = (DATA_TYPE)res;
+            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
+                                                         mmu_idx, retaddr);
         } else {
             /* unaligned/aligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = ra;
+                do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+            }
+#endif
             addend = env->tlb_table[mmu_idx][index].addend;
             res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
         }
     } else {
         /* the page is not in the TLB : fill it */
-        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        retaddr = ra;
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+#endif
+        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
     return res;
 }
+#endif  /* defined(__i386__) || defined(__x86_64__) */
+#endif  /* defined(CONFIG_QEMU_LDST_OPTIMIZATION) */
 
 #ifndef SOFTMMU_CODE_ACCESS
 
@@ -332,26 +338,21 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
         if ((addr & (DATA_SIZE - 1)) != 0)
             do_unaligned_access(addr, 1, mmu_idx, retaddr);
 #endif
-        tlb_fill(addr, 1, mmu_idx, retaddr);
+        tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
     }
 }
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT)
-/*
- * extended versions of MMU helpers for x86 TCG target optimization
- * !defined(SOFTMMU_CODE_ACCESS) suppress warnings from exec.c
- */
-void REGPARM glue(glue(__stext, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                    DATA_TYPE val,
-                                                    int mmu_idx,
-                                                    void *ra)
+/* handles all unaligned cases */
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                   DATA_TYPE val,
+                                                   int mmu_idx,
+                                                   void *retaddr)
 {
     target_phys_addr_t ioaddr;
     unsigned long addend;
     target_ulong tlb_addr;
-    void *retaddr;
-    int index;
+    int index, i;
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
@@ -361,51 +362,48 @@ void REGPARM glue(glue(__stext, SUFFIX), MMUSUFFIX)(target_ulong addr,
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
-            retaddr = ra;
             ioaddr = env->iotlb[mmu_idx][index];
             glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
-            retaddr = ra;
-#ifdef ALIGNED_ONLY
-            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+            /* XXX: not efficient, but simple */
+            /* Note: relies on the fact that tlb_fill() does not remove the
+             * previous page from the TLB cache.  */
+            for(i = DATA_SIZE - 1; i >= 0; i--) {
+#ifdef TARGET_WORDS_BIGENDIAN
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
+                                          mmu_idx, retaddr);
+#else
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
+                                          mmu_idx, retaddr);
 #endif
-            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
-                                                   mmu_idx, retaddr);
+            }
         } else {
             /* aligned/unaligned access in the same page */
-#ifdef ALIGNED_ONLY
-            if ((addr & (DATA_SIZE - 1)) != 0) {
-                retaddr = ra;
-                do_unaligned_access(addr, 1, mmu_idx, retaddr);
-            }
-#endif
             addend = env->tlb_table[mmu_idx][index].addend;
             glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
         }
     } else {
         /* the page is not in the TLB : fill it */
-        retaddr = ra;
-#ifdef ALIGNED_ONLY
-        if ((addr & (DATA_SIZE - 1)) != 0)
-            do_unaligned_access(addr, 1, mmu_idx, retaddr);
-#endif
-        tlb_fill(addr, 1, mmu_idx, retaddr);
+        tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
     }
 }
-#endif  /* CONFIG_TCG_TARGET_X86_OPT */
 
-/* handles all unaligned cases */
-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                   DATA_TYPE val,
-                                                   int mmu_idx,
-                                                   void *retaddr)
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION)
+#if defined(__i386__) || defined(__x86_64__)
+/* Extended versions of MMU helpers for qemu_st IR optimization.
+   They get return address arguments because the caller PCs are not where helpers return to. */
+void REGPARM glue(glue(__stext, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                    DATA_TYPE val,
+                                                    int mmu_idx,
+                                                    void *ra)
 {
     target_phys_addr_t ioaddr;
     unsigned long addend;
     target_ulong tlb_addr;
-    int index, i;
+    void *retaddr;
+    int index;
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
@@ -415,33 +413,41 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
+            retaddr = ra;
             ioaddr = env->iotlb[mmu_idx][index];
             glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
-            /* XXX: not efficient, but simple */
-            /* Note: relies on the fact that tlb_fill() does not remove the
-             * previous page from the TLB cache.  */
-            for(i = DATA_SIZE - 1; i >= 0; i--) {
-#ifdef TARGET_WORDS_BIGENDIAN
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
-                                          mmu_idx, retaddr);
-#else
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
-                                          mmu_idx, retaddr);
+            retaddr = ra;
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, 1, mmu_idx, retaddr);
 #endif
-            }
+            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
+                                                   mmu_idx, retaddr);
         } else {
             /* aligned/unaligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = ra;
+                do_unaligned_access(addr, 1, mmu_idx, retaddr);
+            }
+#endif
             addend = env->tlb_table[mmu_idx][index].addend;
             glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
         }
     } else {
         /* the page is not in the TLB : fill it */
-        tlb_fill(addr, 1, mmu_idx, retaddr);
+        retaddr = ra;
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+#endif
+        tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
     }
 }
+#endif  /* defined(__i386__) || defined(__x86_64__) */
+#endif  /* defined(CONFIG_QEMU_LDST_OPTIMIZATION) */
 
 #endif /* !defined(SOFTMMU_CODE_ACCESS) */
 
index 31321be5325d90d0628a2e77d424902af3ccc476..56efe34e73e9958cb3b411e7c808f7c3d86e8b39 100644 (file)
--- a/sparc.ld
+++ b/sparc.ld
@@ -67,23 +67,23 @@ SECTIONS
   .tbss    : { *(.tbss) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors         :
   {
index 517f337c437cd8899e9a2bcf36c9e2888f982833..7e8eaa9fd8f523fc40229e544d36dd99f0e8e8df 100644 (file)
@@ -36,17 +36,16 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
 
     while (len > 0) {
         last_out = MIN(len, VMC_MAX_HOST_WRITE);
-        qemu_chr_read(scd->chr, p, last_out);
-        if (last_out > 0) {
-            out += last_out;
-            len -= last_out;
-            p += last_out;
-        } else {
+        if (qemu_chr_be_can_write(scd->chr) < last_out) {
             break;
         }
+        qemu_chr_be_write(scd->chr, p, last_out);
+        out += last_out;
+        len -= last_out;
+        p += last_out;
     }
 
-    dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+    dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
     trace_spice_vmc_write(out, len + out);
     return out;
 }
@@ -70,11 +69,40 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
     return bytes;
 }
 
+static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
+{
+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+
+#if SPICE_SERVER_VERSION < 0x000901
+    /*
+     * spice-server calls the state callback for the agent channel when the
+     * spice client connects / disconnects. Given that not the client but
+     * the server is doing the parsing of the messages this is wrong as the
+     * server is still listening. Worse, this causes the parser in the server
+     * to go out of sync, so we ignore state calls for subtype vdagent
+     * spicevmc chardevs. For the full story see:
+     * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
+     */
+    if (strcmp(sin->subtype, "vdagent") == 0) {
+        return;
+    }
+#endif
+
+    if ((scd->chr->opened && connected) ||
+        (!scd->chr->opened && !connected)) {
+        return;
+    }
+
+    qemu_chr_be_event(scd->chr,
+                      connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
+}
+
 static SpiceCharDeviceInterface vmc_interface = {
     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
     .base.description   = "spice virtual channel char device",
     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+    .state              = vmc_state,
     .write              = vmc_write,
     .read               = vmc_read,
 };
@@ -113,7 +141,7 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     assert(s->datalen == 0);
     if (s->bufsize < len) {
         s->bufsize = len;
-        s->buffer = qemu_realloc(s->buffer, s->bufsize);
+        s->buffer = g_realloc(s->buffer, s->bufsize);
     }
     memcpy(s->buffer, buf, len);
     s->datapos = s->buffer;
@@ -128,7 +156,19 @@ static void spice_chr_close(struct CharDriverState *chr)
 
     printf("%s\n", __func__);
     vmc_unregister_interface(s);
-    qemu_free(s);
+    g_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)
@@ -148,7 +188,7 @@ static void print_allowed_subtypes(void)
     fprintf(stderr, "\n");
 }
 
-CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
+int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
     SpiceCharDriver *s;
@@ -160,7 +200,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
     if (name == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
         print_allowed_subtypes();
-        return NULL;
+        return -EINVAL;
     }
     for(;*psubtype != NULL; ++psubtype) {
         if (strcmp(name, *psubtype) == 0) {
@@ -171,11 +211,11 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
     if (subtype == NULL) {
         fprintf(stderr, "spice-qemu-char: unsupported name\n");
         print_allowed_subtypes();
-        return NULL;
+        return -EINVAL;
     }
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    s = qemu_mallocz(sizeof(SpiceCharDriver));
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(SpiceCharDriver));
     s->chr = chr;
     s->debug = debug;
     s->active = false;
@@ -183,8 +223,16 @@ 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);
+#if SPICE_SERVER_VERSION < 0x000901
+    /* See comment in vmc_state() */
+    if (strcmp(subtype, "vdagent") == 0) {
+        qemu_chr_generic_open(chr);
+    }
+#endif
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
index b1529c7edf4e9e93f5329e55f6191870befe99c2..0362e5f5b7a75cbb5aac2d363e07b97a84bb9af0 100644 (file)
--- a/sysemu.h
+++ b/sysemu.h
@@ -6,56 +6,52 @@
 #include "qemu-option.h"
 #include "qemu-queue.h"
 #include "qemu-timer.h"
+#include "qapi-types.h"
 #include "notify.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#include "qemu-os-win32.h"
-#endif
-
-#ifdef CONFIG_POSIX
-#include "qemu-os-posix.h"
-#endif
+#include "main-loop.h"
 
 /* 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 const char *bios_name;
 
-extern int vm_running;
 extern const char *qemu_name;
 extern uint8_t qemu_uuid[];
 int qemu_uuid_parse(const char *str, uint8_t *uuid);
 #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
+void runstate_init(void);
+bool runstate_check(RunState state);
+void runstate_set(RunState new_state);
+int runstate_is_running(void);
 typedef struct vm_change_state_entry VMChangeStateEntry;
-typedef void VMChangeStateHandler(void *opaque, int running, int reason);
+typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
 VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
                                                      void *opaque);
 void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
+void vm_state_notify(int running, RunState state);
 
-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);
+#define VMRESET_SILENT   false
+#define VMRESET_REPORT   true
 
-int64_t cpu_get_ticks(void);
-void cpu_enable_ticks(void);
-void cpu_disable_ticks(void);
+void vm_start(void);
+void vm_stop(RunState state);
+void vm_stop_force_state(RunState state);
 
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
+void qemu_system_debug_request(void);
+void qemu_system_vmstop_request(RunState reason);
+int qemu_shutdown_requested_get(void);
+int qemu_reset_requested_get(void);
 int qemu_shutdown_requested(void);
 int qemu_reset_requested(void);
 int qemu_powerdown_requested(void);
+void qemu_system_killed(int signal, pid_t pid);
+void qemu_kill_report(void);
 extern qemu_irq qemu_system_powerdown;
-void qemu_system_reset(void);
+void qemu_system_reset(bool report);
 
 void qemu_add_exit_notifier(Notifier *notify);
 void qemu_remove_exit_notifier(Notifier *notify);
@@ -67,14 +63,8 @@ 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);
-
 bool qemu_savevm_state_blocked(Monitor *mon);
 int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                             int shared);
@@ -86,28 +76,23 @@ 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,
     DT_CURSES,
     DT_SDL,
     DT_NOGRAPHIC,
+    DT_NONE,
 } DisplayType;
 
 extern int autostart;
-extern int incoming_expected;
 extern int bios_size;
 
 typedef enum {
     VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
-// by caramis...
-    VGA_TIZEN
+#ifdef CONFIG_MARU
+    VGA_MARU,
+#endif
 } VGAInterfaceType;
 
 extern int vga_interface_type;
@@ -116,9 +101,9 @@ extern int vga_interface_type;
 #define xenfb_enabled (vga_interface_type == VGA_XENFB)
 #define vmsvga_enabled (vga_interface_type == VGA_VMWARE)
 #define qxl_enabled (vga_interface_type == VGA_QXL)
-// by caramis...
-#define tizen_vga_enabled (vga_interface_type == VGA_TIZEN)
-
+#ifdef CONFIG_MARU
+#define maru_vga_enabled (vga_interface_type == VGA_MARU)
+#endif
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
@@ -139,6 +124,9 @@ extern int no_shutdown;
 extern int semihosting_enabled;
 extern int old_param;
 extern int boot_menu;
+extern uint8_t *boot_splash_filedata;
+extern int boot_splash_filedata_size;
+extern uint8_t qemu_extra_params_fw[2];
 extern QEMUClock *rtc_clock;
 
 #define MAX_NODES 64
@@ -180,8 +168,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 686fb4a6a7c84e6afc6ed1bb276d2b105b6ac78c..9d61d45ab610e9adf0ea985fbab2472f73e956f8 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "cpu-defs.h"
 
-#include <setjmp.h>
-
 #include "softfloat.h"
 
 #define TARGET_HAS_ICE 1
@@ -192,171 +190,39 @@ enum {
 
 #define SWCR_MASK  (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
 
-/* Internal processor registers */
-/* XXX: TOFIX: most of those registers are implementation dependant */
-enum {
-#if defined(CONFIG_USER_ONLY)
-    IPR_EXC_ADDR,
-    IPR_EXC_SUM,
-    IPR_EXC_MASK,
-#else
-    /* Ebox IPRs */
-    IPR_CC           = 0xC0,            /* 21264 */
-    IPR_CC_CTL       = 0xC1,            /* 21264 */
-#define IPR_CC_CTL_ENA_SHIFT 32
-#define IPR_CC_CTL_COUNTER_MASK 0xfffffff0UL
-    IPR_VA           = 0xC2,            /* 21264 */
-    IPR_VA_CTL       = 0xC4,            /* 21264 */
-#define IPR_VA_CTL_VA_48_SHIFT 1
-#define IPR_VA_CTL_VPTB_SHIFT 30
-    IPR_VA_FORM      = 0xC3,            /* 21264 */
-    /* Ibox IPRs */
-    IPR_ITB_TAG      = 0x00,            /* 21264 */
-    IPR_ITB_PTE      = 0x01,            /* 21264 */
-    IPR_ITB_IAP      = 0x02,
-    IPR_ITB_IA       = 0x03,            /* 21264 */
-    IPR_ITB_IS       = 0x04,            /* 21264 */
-    IPR_PMPC         = 0x05,
-    IPR_EXC_ADDR     = 0x06,            /* 21264 */
-    IPR_IVA_FORM     = 0x07,            /* 21264 */
-    IPR_CM           = 0x09,            /* 21264 */
-#define IPR_CM_SHIFT 3
-#define IPR_CM_MASK (3ULL << IPR_CM_SHIFT)      /* 21264 */
-    IPR_IER          = 0x0A,            /* 21264 */
-#define IPR_IER_MASK 0x0000007fffffe000ULL
-    IPR_IER_CM       = 0x0B,            /* 21264: = CM | IER */
-    IPR_SIRR         = 0x0C,            /* 21264 */
-#define IPR_SIRR_SHIFT 14
-#define IPR_SIRR_MASK 0x7fff
-    IPR_ISUM         = 0x0D,            /* 21264 */
-    IPR_HW_INT_CLR   = 0x0E,            /* 21264 */
-    IPR_EXC_SUM      = 0x0F,
-    IPR_PAL_BASE     = 0x10,
-    IPR_I_CTL        = 0x11,
-#define IPR_I_CTL_CHIP_ID_SHIFT 24      /* 21264 */
-#define IPR_I_CTL_BIST_FAIL (1 << 23)   /* 21264 */
-#define IPR_I_CTL_IC_EN_SHIFT 2         /* 21264 */
-#define IPR_I_CTL_SDE1_SHIFT 7          /* 21264 */
-#define IPR_I_CTL_HWE_SHIFT 12          /* 21264 */
-#define IPR_I_CTL_VA_48_SHIFT 15        /* 21264 */
-#define IPR_I_CTL_SPE_SHIFT 3           /* 21264 */
-#define IPR_I_CTL_CALL_PAL_R23_SHIFT 20 /* 21264 */
-    IPR_I_STAT       = 0x16,            /* 21264 */
-    IPR_IC_FLUSH     = 0x13,            /* 21264 */
-    IPR_IC_FLUSH_ASM = 0x12,            /* 21264 */
-    IPR_CLR_MAP      = 0x15,
-    IPR_SLEEP        = 0x17,
-    IPR_PCTX         = 0x40,
-    IPR_PCTX_ASN       = 0x01,  /* field */
-#define IPR_PCTX_ASN_SHIFT 39
-    IPR_PCTX_ASTER     = 0x02,  /* field */
-#define IPR_PCTX_ASTER_SHIFT 5
-    IPR_PCTX_ASTRR     = 0x04,  /* field */
-#define IPR_PCTX_ASTRR_SHIFT 9
-    IPR_PCTX_PPCE      = 0x08,  /* field */
-#define IPR_PCTX_PPCE_SHIFT 1
-    IPR_PCTX_FPE       = 0x10,  /* field */
-#define IPR_PCTX_FPE_SHIFT 2
-    IPR_PCTX_ALL       = 0x5f,  /* all fields */
-    IPR_PCTR_CTL     = 0x14,            /* 21264 */
-    /* Mbox IPRs */
-    IPR_DTB_TAG0     = 0x20,            /* 21264 */
-    IPR_DTB_TAG1     = 0xA0,            /* 21264 */
-    IPR_DTB_PTE0     = 0x21,            /* 21264 */
-    IPR_DTB_PTE1     = 0xA1,            /* 21264 */
-    IPR_DTB_ALTMODE  = 0xA6,
-    IPR_DTB_ALTMODE0 = 0x26,            /* 21264 */
-#define IPR_DTB_ALTMODE_MASK 3
-    IPR_DTB_IAP      = 0xA2,
-    IPR_DTB_IA       = 0xA3,            /* 21264 */
-    IPR_DTB_IS0      = 0x24,
-    IPR_DTB_IS1      = 0xA4,
-    IPR_DTB_ASN0     = 0x25,            /* 21264 */
-    IPR_DTB_ASN1     = 0xA5,            /* 21264 */
-#define IPR_DTB_ASN_SHIFT 56
-    IPR_MM_STAT      = 0x27,            /* 21264 */
-    IPR_M_CTL        = 0x28,            /* 21264 */
-#define IPR_M_CTL_SPE_SHIFT 1
-#define IPR_M_CTL_SPE_MASK 7
-    IPR_DC_CTL       = 0x29,            /* 21264 */
-    IPR_DC_STAT      = 0x2A,            /* 21264 */
-    /* Cbox IPRs */
-    IPR_C_DATA       = 0x2B,
-    IPR_C_SHIFT      = 0x2C,
-
-    IPR_ASN,
-    IPR_ASTEN,
-    IPR_ASTSR,
-    IPR_DATFX,
-    IPR_ESP,
-    IPR_FEN,
-    IPR_IPIR,
-    IPR_IPL,
-    IPR_KSP,
-    IPR_MCES,
-    IPR_PERFMON,
-    IPR_PCBB,
-    IPR_PRBR,
-    IPR_PTBR,
-    IPR_SCBB,
-    IPR_SISR,
-    IPR_SSP,
-    IPR_SYSPTBR,
-    IPR_TBCHK,
-    IPR_TBIA,
-    IPR_TBIAP,
-    IPR_TBIS,
-    IPR_TBISD,
-    IPR_TBISI,
-    IPR_USP,
-    IPR_VIRBND,
-    IPR_VPTB,
-    IPR_WHAMI,
-    IPR_ALT_MODE,
-#endif
-    IPR_LAST,
-};
+/* MMU modes definitions */
 
-typedef struct CPUAlphaState CPUAlphaState;
+/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
+   The Unix PALcode only exposes the kernel and user modes; presumably
+   executive and supervisor are used by VMS.
 
-typedef struct pal_handler_t pal_handler_t;
-struct pal_handler_t {
-    /* Reset */
-    void (*reset)(CPUAlphaState *env);
-    /* Uncorrectable hardware error */
-    void (*machine_check)(CPUAlphaState *env);
-    /* Arithmetic exception */
-    void (*arithmetic)(CPUAlphaState *env);
-    /* Interrupt / correctable hardware error */
-    void (*interrupt)(CPUAlphaState *env);
-    /* Data fault */
-    void (*dfault)(CPUAlphaState *env);
-    /* DTB miss pal */
-    void (*dtb_miss_pal)(CPUAlphaState *env);
-    /* DTB miss native */
-    void (*dtb_miss_native)(CPUAlphaState *env);
-    /* Unaligned access */
-    void (*unalign)(CPUAlphaState *env);
-    /* ITB miss */
-    void (*itb_miss)(CPUAlphaState *env);
-    /* Instruction stream access violation */
-    void (*itb_acv)(CPUAlphaState *env);
-    /* Reserved or privileged opcode */
-    void (*opcdec)(CPUAlphaState *env);
-    /* Floating point exception */
-    void (*fen)(CPUAlphaState *env);
-    /* Call pal instruction */
-    void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
-};
+   PALcode itself uses physical mode for code and kernel mode for data;
+   there are PALmode instructions that can access data via physical mode
+   or via an os-installed "alternate mode", which is one of the 4 above.
 
-#define NB_MMU_MODES 4
+   QEMU does not currently properly distinguish between code/data when
+   looking up addresses.  To avoid having to address this issue, our
+   emulated PALcode will cheat and use the KSEG mapping for its code+data
+   rather than physical addresses.
+
+   Moreover, we're only emulating Unix PALcode, and not attempting VMS.
+
+   All of which allows us to drop all but kernel and user modes.
+   Elide the unused MMU modes to save space.  */
+
+#define NB_MMU_MODES 2
+
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX   0
+#define MMU_USER_IDX     1
+
+typedef struct CPUAlphaState CPUAlphaState;
 
 struct CPUAlphaState {
     uint64_t ir[31];
     float64 fir[31];
     uint64_t pc;
-    uint64_t ipr[IPR_LAST];
-    uint64_t ps;
     uint64_t unique;
     uint64_t lock_addr;
     uint64_t lock_st_addr;
@@ -371,10 +237,37 @@ struct CPUAlphaState {
     uint8_t fpcr_dnod;
     uint8_t fpcr_undz;
 
-    /* Used for HW_LD / HW_ST */
-    uint8_t saved_mode;
-    /* For RC and RS */
+    /* The Internal Processor Registers.  Some of these we assume always
+       exist for use in user-mode.  */
+    uint8_t ps;
     uint8_t intr_flag;
+    uint8_t pal_mode;
+    uint8_t fen;
+
+    uint32_t pcc_ofs;
+
+    /* These pass data from the exception logic in the translator and
+       helpers to the OS entry point.  This is used for both system
+       emulation and user-mode.  */
+    uint64_t trap_arg0;
+    uint64_t trap_arg1;
+    uint64_t trap_arg2;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* The internal data required by our emulation of the Unix PALcode.  */
+    uint64_t exc_addr;
+    uint64_t palbr;
+    uint64_t ptbr;
+    uint64_t vptptr;
+    uint64_t sysval;
+    uint64_t usp;
+    uint64_t shadow[8];
+    uint64_t scratch[24];
+#endif
+
+    /* This alarm doesn't exist in real hardware; we wish it did.  */
+    struct QEMUTimer *alarm_timer;
+    uint64_t alarm_expire;
 
 #if TARGET_LONG_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
@@ -386,14 +279,11 @@ struct CPUAlphaState {
     /* Those resources are used only in Qemu core */
     CPU_COMMON
 
-    uint32_t hflags;
-
     int error_code;
 
     uint32_t features;
     uint32_t amask;
     int implver;
-    pal_handler_t *pal_handler;
 };
 
 #define cpu_init cpu_alpha_init
@@ -401,17 +291,6 @@ struct CPUAlphaState {
 #define cpu_gen_code cpu_alpha_gen_code
 #define cpu_signal_handler cpu_alpha_signal_handler
 
-/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _executive
-#define MMU_MODE2_SUFFIX _supervisor
-#define MMU_MODE3_SUFFIX _user
-#define MMU_USER_IDX 3
-static inline int cpu_mmu_index (CPUState *env)
-{
-    return (env->ps >> 3) & 3;
-}
-
 #include "cpu-all.h"
 
 enum {
@@ -422,36 +301,89 @@ enum {
 };
 
 enum {
-    EXCP_RESET            = 0x0000,
-    EXCP_MCHK             = 0x0020,
-    EXCP_ARITH            = 0x0060,
-    EXCP_HW_INTERRUPT     = 0x00E0,
-    EXCP_DFAULT           = 0x01E0,
-    EXCP_DTB_MISS_PAL     = 0x09E0,
-    EXCP_ITB_MISS         = 0x03E0,
-    EXCP_ITB_ACV          = 0x07E0,
-    EXCP_DTB_MISS_NATIVE  = 0x08E0,
-    EXCP_UNALIGN          = 0x11E0,
-    EXCP_OPCDEC           = 0x13E0,
-    EXCP_FEN              = 0x17E0,
-    EXCP_CALL_PAL         = 0x2000,
-    EXCP_CALL_PALP        = 0x3000,
-    EXCP_CALL_PALE        = 0x4000,
-    /* Pseudo exception for console */
-    EXCP_CONSOLE_DISPATCH = 0x4001,
-    EXCP_CONSOLE_FIXUP    = 0x4002,
-    EXCP_STL_C            = 0x4003,
-    EXCP_STQ_C            = 0x4004,
+    EXCP_RESET,
+    EXCP_MCHK,
+    EXCP_SMP_INTERRUPT,
+    EXCP_CLK_INTERRUPT,
+    EXCP_DEV_INTERRUPT,
+    EXCP_MMFAULT,
+    EXCP_UNALIGN,
+    EXCP_OPCDEC,
+    EXCP_ARITH,
+    EXCP_FEN,
+    EXCP_CALL_PAL,
+    /* For Usermode emulation.  */
+    EXCP_STL_C,
+    EXCP_STQ_C,
+};
+
+/* Alpha-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_TIMER    CPU_INTERRUPT_TGT_EXT_0
+#define CPU_INTERRUPT_SMP      CPU_INTERRUPT_TGT_EXT_1
+#define CPU_INTERRUPT_MCHK     CPU_INTERRUPT_TGT_EXT_2
+
+/* OSF/1 Page table bits.  */
+enum {
+    PTE_VALID = 0x0001,
+    PTE_FOR   = 0x0002,  /* used for page protection (fault on read) */
+    PTE_FOW   = 0x0004,  /* used for page protection (fault on write) */
+    PTE_FOE   = 0x0008,  /* used for page protection (fault on exec) */
+    PTE_ASM   = 0x0010,
+    PTE_KRE   = 0x0100,
+    PTE_URE   = 0x0200,
+    PTE_KWE   = 0x1000,
+    PTE_UWE   = 0x2000
+};
+
+/* Hardware interrupt (entInt) constants.  */
+enum {
+    INT_K_IP,
+    INT_K_CLK,
+    INT_K_MCHK,
+    INT_K_DEV,
+    INT_K_PERF,
+};
+
+/* Memory management (entMM) constants.  */
+enum {
+    MM_K_TNV,
+    MM_K_ACV,
+    MM_K_FOR,
+    MM_K_FOE,
+    MM_K_FOW
 };
 
-/* Arithmetic exception */
-#define EXC_M_IOV       (1<<16)         /* Integer Overflow */
-#define EXC_M_INE       (1<<15)         /* Inexact result */
-#define EXC_M_UNF       (1<<14)         /* Underflow */
-#define EXC_M_FOV       (1<<13)         /* Overflow */
-#define EXC_M_DZE       (1<<12)         /* Division by zero */
-#define EXC_M_INV       (1<<11)         /* Invalid operation */
-#define EXC_M_SWC       (1<<10)         /* Software completion */
+/* Arithmetic exception (entArith) constants.  */
+enum {
+    EXC_M_SWC = 1,      /* Software completion */
+    EXC_M_INV = 2,      /* Invalid operation */
+    EXC_M_DZE = 4,      /* Division by zero */
+    EXC_M_FOV = 8,      /* Overflow */
+    EXC_M_UNF = 16,     /* Underflow */
+    EXC_M_INE = 32,     /* Inexact result */
+    EXC_M_IOV = 64      /* Integer Overflow */
+};
+
+/* Processor status constants.  */
+enum {
+    /* Low 3 bits are interrupt mask level.  */
+    PS_INT_MASK = 7,
+
+    /* Bits 4 and 5 are the mmu mode.  The VMS PALcode uses all 4 modes;
+       The Unix PALcode only uses bit 4.  */
+    PS_USER_MODE = 8
+};
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    if (env->pal_mode) {
+        return MMU_KERNEL_IDX;
+    } else if (env->ps & PS_USER_MODE) {
+        return MMU_USER_IDX;
+    } else {
+        return MMU_KERNEL_IDX;
+    }
+}
 
 enum {
     IR_V0   = 0,
@@ -498,25 +430,53 @@ int cpu_alpha_exec(CPUAlphaState *s);
 int cpu_alpha_signal_handler(int host_signum, void *pinfo,
                              void *puc);
 int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
-                                int mmu_idx, int is_softmmu);
+                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
 void do_interrupt (CPUState *env);
 
 uint64_t cpu_alpha_load_fpcr (CPUState *env);
 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
-#if !defined (CONFIG_USER_ONLY)
-void pal_init (CPUState *env);
-void call_pal (CPUState *env);
+#ifndef CONFIG_USER_ONLY
+void swap_shadow_regs(CPUState *env);
+QEMU_NORETURN void cpu_unassigned_access(CPUState *env1,
+                                         target_phys_addr_t addr, int is_write,
+                                         int is_exec, int unused, int size);
 #endif
 
+/* Bits in TB->FLAGS that control how translation is processed.  */
+enum {
+    TB_FLAGS_PAL_MODE = 1,
+    TB_FLAGS_FEN = 2,
+    TB_FLAGS_USER_MODE = 8,
+
+    TB_FLAGS_AMASK_SHIFT = 4,
+    TB_FLAGS_AMASK_BWX = AMASK_BWX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_FIX = AMASK_FIX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_CIX = AMASK_CIX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_MVI = AMASK_MVI << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_TRAP = AMASK_TRAP << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT,
+};
+
 static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
+                                        target_ulong *cs_base, int *pflags)
 {
+    int flags = 0;
+
     *pc = env->pc;
     *cs_base = 0;
-    *flags = env->ps;
+
+    if (env->pal_mode) {
+        flags = TB_FLAGS_PAL_MODE;
+    } else {
+        flags = env->ps & PS_USER_MODE;
+    }
+    if (env->fen) {
+        flags |= TB_FLAGS_FEN;
+    }
+    flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
+
+    *pflags = flags;
 }
 
 #if defined(CONFIG_USER_ONLY)
@@ -535,4 +495,26 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
 }
 #endif
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    /* Here we are checking to see if the CPU should wake up from HALT.
+       We will have gotten into this state only for WTINT from PALmode.  */
+    /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
+       asleep even if (some) interrupts have been asserted.  For now,
+       assume that if a CPU really wants to stay asleep, it will mask
+       interrupts at the chipset level, which will prevent these bits
+       from being set in the first place.  */
+    return env->interrupt_request & (CPU_INTERRUPT_HARD
+                                     | CPU_INTERRUPT_TIMER
+                                     | CPU_INTERRUPT_SMP
+                                     | CPU_INTERRUPT_MCHK);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
 #endif /* !defined (__CPU_ALPHA_H__) */
index 3ba4478c8e77202dc863a1d7e025621dfa53b507..06d2565a5cbc7b3323631288822502ddbc24830b 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "softfloat.h"
 
 uint64_t cpu_alpha_load_fpcr (CPUState *env)
@@ -160,382 +159,299 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 }
 
 #if defined(CONFIG_USER_ONLY)
-
 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                                int mmu_idx, int is_softmmu)
+                                int mmu_idx)
 {
-    if (rw == 2)
-        env->exception_index = EXCP_ITB_MISS;
-    else
-        env->exception_index = EXCP_DFAULT;
-    env->ipr[IPR_EXC_ADDR] = address;
-
+    env->exception_index = EXCP_MMFAULT;
+    env->trap_arg0 = address;
     return 1;
 }
-
-void do_interrupt (CPUState *env)
+#else
+void swap_shadow_regs(CPUState *env)
 {
-    env->exception_index = -1;
+    uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
+
+    i0 = env->ir[8];
+    i1 = env->ir[9];
+    i2 = env->ir[10];
+    i3 = env->ir[11];
+    i4 = env->ir[12];
+    i5 = env->ir[13];
+    i6 = env->ir[14];
+    i7 = env->ir[25];
+
+    env->ir[8]  = env->shadow[0];
+    env->ir[9]  = env->shadow[1];
+    env->ir[10] = env->shadow[2];
+    env->ir[11] = env->shadow[3];
+    env->ir[12] = env->shadow[4];
+    env->ir[13] = env->shadow[5];
+    env->ir[14] = env->shadow[6];
+    env->ir[25] = env->shadow[7];
+
+    env->shadow[0] = i0;
+    env->shadow[1] = i1;
+    env->shadow[2] = i2;
+    env->shadow[3] = i3;
+    env->shadow[4] = i4;
+    env->shadow[5] = i5;
+    env->shadow[6] = i6;
+    env->shadow[7] = i7;
 }
 
-#else
+/* Returns the OSF/1 entMM failure indication, or -1 on success.  */
+static int get_physical_address(CPUState *env, target_ulong addr,
+                                int prot_need, int mmu_idx,
+                                target_ulong *pphys, int *pprot)
+{
+    target_long saddr = addr;
+    target_ulong phys = 0;
+    target_ulong L1pte, L2pte, L3pte;
+    target_ulong pt, index;
+    int prot = 0;
+    int ret = MM_K_ACV;
+
+    /* Ensure that the virtual address is properly sign-extended from
+       the last implemented virtual address bit.  */
+    if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
+        goto exit;
+    }
+
+    /* Translate the superpage.  */
+    /* ??? When we do more than emulate Unix PALcode, we'll need to
+       determine which KSEG is actually active.  */
+    if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
+        /* User-space cannot access KSEG addresses.  */
+        if (mmu_idx != MMU_KERNEL_IDX) {
+            goto exit;
+        }
+
+        /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
+           We would not do this if the 48-bit KSEG is enabled.  */
+        phys = saddr & ((1ull << 40) - 1);
+        phys |= (saddr & (1ull << 40)) << 3;
+
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        ret = -1;
+        goto exit;
+    }
+
+    /* Interpret the page table exactly like PALcode does.  */
 
-target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+    pt = env->ptbr;
+
+    /* L1 page table read.  */
+    index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
+    L1pte = ldq_phys(pt + index*8);
+
+    if (unlikely((L1pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+    if (unlikely((L1pte & PTE_KRE) == 0)) {
+        goto exit;
+    }
+    pt = L1pte >> 32 << TARGET_PAGE_BITS;
+
+    /* L2 page table read.  */
+    index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
+    L2pte = ldq_phys(pt + index*8);
+
+    if (unlikely((L2pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+    if (unlikely((L2pte & PTE_KRE) == 0)) {
+        goto exit;
+    }
+    pt = L2pte >> 32 << TARGET_PAGE_BITS;
+
+    /* L3 page table read.  */
+    index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
+    L3pte = ldq_phys(pt + index*8);
+
+    phys = L3pte >> 32 << TARGET_PAGE_BITS;
+    if (unlikely((L3pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+
+#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
+# error page bits out of date
+#endif
+
+    /* Check access violations.  */
+    if (L3pte & (PTE_KRE << mmu_idx)) {
+        prot |= PAGE_READ | PAGE_EXEC;
+    }
+    if (L3pte & (PTE_KWE << mmu_idx)) {
+        prot |= PAGE_WRITE;
+    }
+    if (unlikely((prot & prot_need) == 0 && prot_need)) {
+        goto exit;
+    }
+
+    /* Check fault-on-operation violations.  */
+    prot &= ~(L3pte >> 1);
+    ret = -1;
+    if (unlikely((prot & prot_need) == 0)) {
+        ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
+               prot_need & PAGE_WRITE ? MM_K_FOW :
+               prot_need & PAGE_READ ? MM_K_FOR : -1);
+    }
+
+ exit:
+    *pphys = phys;
+    *pprot = prot;
+    return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
-    return -1;
+    target_ulong phys;
+    int prot, fail;
+
+    fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+    return (fail >= 0 ? -1 : phys);
 }
 
-int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                                int mmu_idx, int is_softmmu)
+int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
+                               int mmu_idx)
 {
-    uint32_t opc;
-
-    if (rw == 2) {
-        /* Instruction translation buffer miss */
-        env->exception_index = EXCP_ITB_MISS;
-    } else {
-        if (env->ipr[IPR_EXC_ADDR] & 1)
-            env->exception_index = EXCP_DTB_MISS_PAL;
-        else
-            env->exception_index = EXCP_DTB_MISS_NATIVE;
-        opc = (ldl_code(env->pc) >> 21) << 4;
-        if (rw) {
-            opc |= 0x9;
-        } else {
-            opc |= 0x4;
-        }
-        env->ipr[IPR_MM_STAT] = opc;
+    target_ulong phys;
+    int prot, fail;
+
+    fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
+    if (unlikely(fail >= 0)) {
+        env->exception_index = EXCP_MMFAULT;
+        env->trap_arg0 = addr;
+        env->trap_arg1 = fail;
+        env->trap_arg2 = (rw == 2 ? -1 : rw);
+        return 1;
     }
 
-    return 1;
+    tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+                 prot, mmu_idx, TARGET_PAGE_SIZE);
+    return 0;
 }
+#endif /* USER_ONLY */
 
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+void do_interrupt (CPUState *env)
 {
-    uint64_t hwpcb;
-    int ret = 0;
-
-    hwpcb = env->ipr[IPR_PCBB];
-    switch (iprn) {
-    case IPR_ASN:
-        if (env->features & FEATURE_ASN)
-            *valp = env->ipr[IPR_ASN];
-        else
-            *valp = 0;
-        break;
-    case IPR_ASTEN:
-        *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
-        break;
-    case IPR_ASTSR:
-        *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
-        break;
-    case IPR_DATFX:
-        /* Write only */
-        ret = -1;
-        break;
-    case IPR_ESP:
-        if (env->features & FEATURE_SPS)
-            *valp = env->ipr[IPR_ESP];
-        else
-            *valp = ldq_raw(hwpcb + 8);
-        break;
-    case IPR_FEN:
-        *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
-        break;
-    case IPR_IPIR:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_IPL:
-        *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
-        break;
-    case IPR_KSP:
-        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
-            ret = -1;
-        } else {
-            if (env->features & FEATURE_SPS)
-                *valp = env->ipr[IPR_KSP];
-            else
-                *valp = ldq_raw(hwpcb + 0);
+    int i = env->exception_index;
+
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name = "<unknown>";
+
+        switch (i) {
+        case EXCP_RESET:
+            name = "reset";
+            break;
+        case EXCP_MCHK:
+            name = "mchk";
+            break;
+        case EXCP_SMP_INTERRUPT:
+            name = "smp_interrupt";
+            break;
+        case EXCP_CLK_INTERRUPT:
+            name = "clk_interrupt";
+            break;
+        case EXCP_DEV_INTERRUPT:
+            name = "dev_interrupt";
+            break;
+        case EXCP_MMFAULT:
+            name = "mmfault";
+            break;
+        case EXCP_UNALIGN:
+            name = "unalign";
+            break;
+        case EXCP_OPCDEC:
+            name = "opcdec";
+            break;
+        case EXCP_ARITH:
+            name = "arith";
+            break;
+        case EXCP_FEN:
+            name = "fen";
+            break;
+        case EXCP_CALL_PAL:
+            name = "call_pal";
+            break;
+        case EXCP_STL_C:
+            name = "stl_c";
+            break;
+        case EXCP_STQ_C:
+            name = "stq_c";
+            break;
         }
-        break;
-    case IPR_MCES:
-        *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
-        break;
-    case IPR_PERFMON:
-        /* Implementation specific */
-        *valp = 0;
-        break;
-    case IPR_PCBB:
-        *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
-        break;
-    case IPR_PRBR:
-        *valp = env->ipr[IPR_PRBR];
-        break;
-    case IPR_PTBR:
-        *valp = env->ipr[IPR_PTBR];
-        break;
-    case IPR_SCBB:
-        *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
-        break;
-    case IPR_SIRR:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_SISR:
-        *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
-    case IPR_SSP:
-        if (env->features & FEATURE_SPS)
-            *valp = env->ipr[IPR_SSP];
-        else
-            *valp = ldq_raw(hwpcb + 16);
-        break;
-    case IPR_SYSPTBR:
-        if (env->features & FEATURE_VIRBND)
-            *valp = env->ipr[IPR_SYSPTBR];
-        else
-            ret = -1;
-        break;
-    case IPR_TBCHK:
-        if ((env->features & FEATURE_TBCHK)) {
-            /* XXX: TODO */
-            *valp = 0;
-            ret = -1;
-        } else {
-            ret = -1;
-        }
-        break;
-    case IPR_TBIA:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_TBIAP:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_TBIS:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_TBISD:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_TBISI:
-        /* Write-only */
-        ret = -1;
-        break;
-    case IPR_USP:
-        if (env->features & FEATURE_SPS)
-            *valp = env->ipr[IPR_USP];
-        else
-            *valp = ldq_raw(hwpcb + 24);
-        break;
-    case IPR_VIRBND:
-        if (env->features & FEATURE_VIRBND)
-            *valp = env->ipr[IPR_VIRBND];
-        else
-            ret = -1;
-        break;
-    case IPR_VPTB:
-        *valp = env->ipr[IPR_VPTB];
-        break;
-    case IPR_WHAMI:
-        *valp = env->ipr[IPR_WHAMI];
-        break;
-    default:
-        /* Invalid */
-        ret = -1;
-        break;
+        qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
+                 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
     }
 
-    return ret;
-}
+    env->exception_index = -1;
 
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
-{
-    uint64_t hwpcb, tmp64;
-    uint8_t tmp8;
-    int ret = 0;
-
-    hwpcb = env->ipr[IPR_PCBB];
-    switch (iprn) {
-    case IPR_ASN:
-        /* Read-only */
-        ret = -1;
-        break;
-    case IPR_ASTEN:
-        tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
-        *oldvalp = tmp8;
-        tmp8 &= val & 0xF;
-        tmp8 |= (val >> 4) & 0xF;
-        env->ipr[IPR_ASTEN] &= ~0xF;
-        env->ipr[IPR_ASTEN] |= tmp8;
-        ret = 1;
-        break;
-    case IPR_ASTSR:
-        tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
-        *oldvalp = tmp8;
-        tmp8 &= val & 0xF;
-        tmp8 |= (val >> 4) & 0xF;
-        env->ipr[IPR_ASTSR] &= ~0xF;
-        env->ipr[IPR_ASTSR] |= tmp8;
-        ret = 1;
-    case IPR_DATFX:
-        env->ipr[IPR_DATFX] &= ~0x1;
-        env->ipr[IPR_DATFX] |= val & 1;
-        tmp64 = ldq_raw(hwpcb + 56);
-        tmp64 &= ~0x8000000000000000ULL;
-        tmp64 |= (val & 1) << 63;
-        stq_raw(hwpcb + 56, tmp64);
+#if !defined(CONFIG_USER_ONLY)
+    switch (i) {
+    case EXCP_RESET:
+        i = 0x0000;
         break;
-    case IPR_ESP:
-        if (env->features & FEATURE_SPS)
-            env->ipr[IPR_ESP] = val;
-        else
-            stq_raw(hwpcb + 8, val);
+    case EXCP_MCHK:
+        i = 0x0080;
         break;
-    case IPR_FEN:
-        env->ipr[IPR_FEN] = val & 1;
-        tmp64 = ldq_raw(hwpcb + 56);
-        tmp64 &= ~1;
-        tmp64 |= val & 1;
-        stq_raw(hwpcb + 56, tmp64);
+    case EXCP_SMP_INTERRUPT:
+        i = 0x0100;
         break;
-    case IPR_IPIR:
-        /* XXX: TODO: Send IRQ to CPU #ir[16] */
+    case EXCP_CLK_INTERRUPT:
+        i = 0x0180;
         break;
-    case IPR_IPL:
-        *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
-        env->ipr[IPR_IPL] &= ~0x1F;
-        env->ipr[IPR_IPL] |= val & 0x1F;
-        /* XXX: may issue an interrupt or ASR _now_ */
-        ret = 1;
+    case EXCP_DEV_INTERRUPT:
+        i = 0x0200;
         break;
-    case IPR_KSP:
-        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
-            ret = -1;
-        } else {
-            if (env->features & FEATURE_SPS)
-                env->ipr[IPR_KSP] = val;
-            else
-                stq_raw(hwpcb + 0, val);
-        }
-        break;
-    case IPR_MCES:
-        env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
-        env->ipr[IPR_MCES] |= val & 0x18;
-        break;
-    case IPR_PERFMON:
-        /* Implementation specific */
-        *oldvalp = 0;
-        ret = 1;
+    case EXCP_MMFAULT:
+        i = 0x0280;
         break;
-    case IPR_PCBB:
-        /* Read-only */
-        ret = -1;
+    case EXCP_UNALIGN:
+        i = 0x0300;
         break;
-    case IPR_PRBR:
-        env->ipr[IPR_PRBR] = val;
+    case EXCP_OPCDEC:
+        i = 0x0380;
         break;
-    case IPR_PTBR:
-        /* Read-only */
-        ret = -1;
+    case EXCP_ARITH:
+        i = 0x0400;
         break;
-    case IPR_SCBB:
-        env->ipr[IPR_SCBB] = (uint32_t)val;
+    case EXCP_FEN:
+        i = 0x0480;
         break;
-    case IPR_SIRR:
-        if (val & 0xF) {
-            env->ipr[IPR_SISR] |= 1 << (val & 0xF);
-            /* XXX: request a software interrupt _now_ */
+    case EXCP_CALL_PAL:
+        i = env->error_code;
+        /* There are 64 entry points for both privileged and unprivileged,
+           with bit 0x80 indicating unprivileged.  Each entry point gets
+           64 bytes to do its job.  */
+        if (i & 0x80) {
+            i = 0x2000 + (i - 0x80) * 64;
+        } else {
+            i = 0x1000 + i * 64;
         }
         break;
-    case IPR_SISR:
-        /* Read-only */
-        ret = -1;
-        break;
-    case IPR_SSP:
-        if (env->features & FEATURE_SPS)
-            env->ipr[IPR_SSP] = val;
-        else
-            stq_raw(hwpcb + 16, val);
-        break;
-    case IPR_SYSPTBR:
-        if (env->features & FEATURE_VIRBND)
-            env->ipr[IPR_SYSPTBR] = val;
-        else
-            ret = -1;
-        break;
-    case IPR_TBCHK:
-        /* Read-only */
-        ret = -1;
-        break;
-    case IPR_TBIA:
-        tlb_flush(env, 1);
-        break;
-    case IPR_TBIAP:
-        tlb_flush(env, 1);
-        break;
-    case IPR_TBIS:
-        tlb_flush_page(env, val);
-        break;
-    case IPR_TBISD:
-        tlb_flush_page(env, val);
-        break;
-    case IPR_TBISI:
-        tlb_flush_page(env, val);
-        break;
-    case IPR_USP:
-        if (env->features & FEATURE_SPS)
-            env->ipr[IPR_USP] = val;
-        else
-            stq_raw(hwpcb + 24, val);
-        break;
-    case IPR_VIRBND:
-        if (env->features & FEATURE_VIRBND)
-            env->ipr[IPR_VIRBND] = val;
-        else
-            ret = -1;
-        break;
-    case IPR_VPTB:
-        env->ipr[IPR_VPTB] = val;
-        break;
-    case IPR_WHAMI:
-        /* Read-only */
-        ret = -1;
-        break;
     default:
-        /* Invalid */
-        ret = -1;
-        break;
+        cpu_abort(env, "Unhandled CPU exception");
     }
 
-    return ret;
-}
+    /* Remember where the exception happened.  Emulate real hardware in
+       that the low bit of the PC indicates PALmode.  */
+    env->exc_addr = env->pc | env->pal_mode;
 
-void do_interrupt (CPUState *env)
-{
-    int excp;
+    /* Continue execution at the PALcode entry point.  */
+    env->pc = env->palbr + i;
 
-    env->ipr[IPR_EXC_ADDR] = env->pc | 1;
-    excp = env->exception_index;
-    env->exception_index = -1;
-    env->error_code = 0;
-    /* XXX: disable interrupts and memory mapping */
-    if (env->ipr[IPR_PAL_BASE] != -1ULL) {
-        /* We use native PALcode */
-        env->pc = env->ipr[IPR_PAL_BASE] + excp;
-    } else {
-        /* We use emulated PALcode */
-        call_pal(env);
-        /* Emulate REI */
-        env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
-        env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
-        /* XXX: re-enable interrupts and memory mapping */
+    /* Switch to PALmode.  */
+    if (!env->pal_mode) {
+        env->pal_mode = 1;
+        swap_shadow_regs(env);
     }
+#endif /* !USER_ONLY */
 }
-#endif
 
 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
@@ -548,7 +464,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
     };
     int i;
 
-    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  " TARGET_FMT_lx "\n",
+    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
                 env->pc, env->ps);
     for (i = 0; i < 31; i++) {
         cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
index ccf6a2aae96dafe31f7355c9464bf5ea8a8249d1..b693ceea9712c3bb31b9042bdf64e018b33d6f45 100644 (file)
@@ -100,27 +100,24 @@ DEF_HELPER_1(ieee_input_cmp, i64, i64)
 DEF_HELPER_1(ieee_input_s, i64, i64)
 
 #if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_0(hw_rei, void)
 DEF_HELPER_1(hw_ret, void, i64)
-DEF_HELPER_2(mfpr, i64, int, i64)
-DEF_HELPER_2(mtpr, void, int, i64)
-DEF_HELPER_0(set_alt_mode, void)
-DEF_HELPER_0(restore_mode, void)
-
-DEF_HELPER_1(ld_virt_to_phys, i64, i64)
-DEF_HELPER_1(st_virt_to_phys, i64, i64)
-DEF_HELPER_2(ldl_raw, void, i64, i64)
-DEF_HELPER_2(ldq_raw, void, i64, i64)
-DEF_HELPER_2(ldl_l_raw, void, i64, i64)
-DEF_HELPER_2(ldq_l_raw, void, i64, i64)
-DEF_HELPER_2(ldl_kernel, void, i64, i64)
-DEF_HELPER_2(ldq_kernel, void, i64, i64)
-DEF_HELPER_2(ldl_data, void, i64, i64)
-DEF_HELPER_2(ldq_data, void, i64, i64)
-DEF_HELPER_2(stl_raw, void, i64, i64)
-DEF_HELPER_2(stq_raw, void, i64, i64)
-DEF_HELPER_2(stl_c_raw, i64, i64, i64)
-DEF_HELPER_2(stq_c_raw, i64, i64, i64)
+
+DEF_HELPER_1(ldl_phys, i64, i64)
+DEF_HELPER_1(ldq_phys, i64, i64)
+DEF_HELPER_1(ldl_l_phys, i64, i64)
+DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(stl_phys, void, i64, i64)
+DEF_HELPER_2(stq_phys, void, i64, i64)
+DEF_HELPER_2(stl_c_phys, i64, i64, i64)
+DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+
+DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+
+DEF_HELPER_1(halt, void, i64);
+
+DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
+DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
 #endif
 
 #include "def-helper.h"
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
new file mode 100644 (file)
index 0000000..76d70d9
--- /dev/null
@@ -0,0 +1,87 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static int get_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAlphaState *env = opaque;
+    cpu_alpha_store_fpcr(env, qemu_get_be64(f));
+    return 0;
+}
+
+static void put_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAlphaState *env = opaque;
+    qemu_put_be64(f, cpu_alpha_load_fpcr(env));
+}
+
+static const VMStateInfo vmstate_fpcr = {
+    .name = "fpcr",
+    .get = get_fpcr,
+    .put = put_fpcr,
+};
+
+static VMStateField vmstate_cpu_fields[] = {
+    VMSTATE_UINTTL_ARRAY(ir, CPUState, 31),
+    VMSTATE_UINTTL_ARRAY(fir, CPUState, 31),
+    /* Save the architecture value of the fpcr, not the internally
+       expanded version.  Since this architecture value does not
+       exist in memory to be stored, this requires a but of hoop
+       jumping.  We want OFFSET=0 so that we effectively pass ENV
+       to the helper functions, and we need to fill in the name by
+       hand since there's no field of that name.  */
+    {
+        .name = "fpcr",
+        .version_id = 0,
+        .size = sizeof(uint64_t),
+        .info = &vmstate_fpcr,
+        .flags = VMS_SINGLE,
+        .offset = 0
+    },
+    VMSTATE_UINTTL(pc, CPUState),
+    VMSTATE_UINTTL(unique, CPUState),
+    VMSTATE_UINTTL(lock_addr, CPUState),
+    VMSTATE_UINTTL(lock_value, CPUState),
+    /* Note that lock_st_addr is not saved; it is a temporary
+       used during the execution of the st[lq]_c insns.  */
+
+    VMSTATE_UINT8(ps, CPUState),
+    VMSTATE_UINT8(intr_flag, CPUState),
+    VMSTATE_UINT8(pal_mode, CPUState),
+    VMSTATE_UINT8(fen, CPUState),
+
+    VMSTATE_UINT32(pcc_ofs, CPUState),
+
+    VMSTATE_UINTTL(trap_arg0, CPUState),
+    VMSTATE_UINTTL(trap_arg1, CPUState),
+    VMSTATE_UINTTL(trap_arg2, CPUState),
+
+    VMSTATE_UINTTL(exc_addr, CPUState),
+    VMSTATE_UINTTL(palbr, CPUState),
+    VMSTATE_UINTTL(ptbr, CPUState),
+    VMSTATE_UINTTL(vptptr, CPUState),
+    VMSTATE_UINTTL(sysval, CPUState),
+    VMSTATE_UINTTL(usp, CPUState),
+
+    VMSTATE_UINTTL_ARRAY(shadow, CPUState, 8),
+    VMSTATE_UINTTL_ARRAY(scratch, CPUState, 24),
+
+    VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = vmstate_cpu_fields,
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
index 6c2ae2061f0370d8d1e23650b8211375e84ed5c3..cc102dbd633bd21c4614cc52d6f4cbbfef8400d6 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "host-utils.h"
 #include "softfloat.h"
 #include "helper.h"
+#include "sysemu.h"
 #include "qemu-timer.h"
 
+#define FP_STATUS (env->fp_status)
+
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void QEMU_NORETURN helper_excp (int excp, int error)
+
+/* This should only be called from translate, via gen_excp.
+   We expect that ENV->PC has already been updated.  */
+void QEMU_NORETURN helper_excp(int excp, int error)
+{
+    env->exception_index = excp;
+    env->error_code = error;
+    cpu_loop_exit(env);
+}
+
+static void do_restore_state(void *retaddr)
+{
+    unsigned long pc = (unsigned long)retaddr;
+
+    if (pc) {
+        TranslationBlock *tb = tb_find_pc(pc);
+        if (tb) {
+            cpu_restore_state(tb, env, pc);
+        }
+    }
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX.  */
+static void QEMU_NORETURN dynamic_excp(int excp, int error)
 {
     env->exception_index = excp;
     env->error_code = error;
-    cpu_loop_exit();
+    do_restore_state(GETPC());
+    cpu_loop_exit(env);
+}
+
+static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
+{
+    env->trap_arg0 = exc;
+    env->trap_arg1 = mask;
+    dynamic_excp(EXCP_ARITH, 0);
 }
 
 uint64_t helper_load_pcc (void)
 {
-    /* ??? This isn't a timer for which we have any rate info.  */
+#ifndef CONFIG_USER_ONLY
+    /* In system mode we have access to a decent high-resolution clock.
+       In order to make OS-level time accounting work with the RPCC,
+       present it with a well-timed clock fixed at 250MHz.  */
+    return (((uint64_t)env->pcc_ofs << 32)
+            | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+    /* In user-mode, vm_clock doesn't exist.  Just pass through the host cpu
+       clock ticks.  Also, don't bother taking PCC_OFS into account.  */
     return (uint32_t)cpu_get_real_ticks();
+#endif
 }
 
 uint64_t helper_load_fpcr (void)
@@ -53,7 +97,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 += op2;
     if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return op1;
 }
@@ -63,7 +107,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 = (uint32_t)(op1 + op2);
     if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return op1;
 }
@@ -73,7 +117,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
     uint64_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return res;
 }
@@ -83,7 +127,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
     uint32_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return res;
 }
@@ -93,7 +137,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
     int64_t res = (int64_t)op1 * (int64_t)op2;
 
     if (unlikely((int32_t)res != res)) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return (int64_t)((int32_t)res);
 }
@@ -105,7 +149,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
     muls64(&tl, &th, op1, op2);
     /* If th != 0 && th != -1, then we had an overflow */
     if (unlikely((th + 1) > 1)) {
-        helper_excp(EXCP_ARITH, EXC_M_IOV);
+        arith_excp(EXC_M_IOV, 0);
     }
     return tl;
 }
@@ -373,8 +417,6 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
     if (exc) {
         uint32_t hw_exc = 0;
 
-        env->ipr[IPR_EXC_MASK] |= 1ull << regno;
-
         if (exc & float_flag_invalid) {
             hw_exc |= EXC_M_INV;
         }
@@ -390,7 +432,8 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
         if (exc & float_flag_inexact) {
             hw_exc |= EXC_M_INE;
         }
-        helper_excp(EXCP_ARITH, hw_exc);
+
+        arith_excp(hw_exc, 1ull << regno);
     }
 }
 
@@ -420,7 +463,7 @@ uint64_t helper_ieee_input(uint64_t val)
             if (env->fpcr_dnz) {
                 val &= 1ull << 63;
             } else {
-                helper_excp(EXCP_ARITH, EXC_M_UNF);
+                arith_excp(EXC_M_UNF, 0);
             }
         }
     } else if (exp == 0x7ff) {
@@ -428,7 +471,7 @@ uint64_t helper_ieee_input(uint64_t val)
         /* ??? I'm not sure these exception bit flags are correct.  I do
            know that the Linux kernel, at least, doesn't rely on them and
            just emulates the insn to figure out what exception to use.  */
-        helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+        arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
     }
     return val;
 }
@@ -445,12 +488,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val)
             if (env->fpcr_dnz) {
                 val &= 1ull << 63;
             } else {
-                helper_excp(EXCP_ARITH, EXC_M_UNF);
+                arith_excp(EXC_M_UNF, 0);
             }
         }
     } else if (exp == 0x7ff && frac) {
         /* NaN.  */
-        helper_excp(EXCP_ARITH, EXC_M_INV);
+        arith_excp(EXC_M_INV, 0);
     }
     return val;
 }
@@ -513,7 +556,7 @@ static inline float32 f_to_float32(uint64_t a)
 
     if (unlikely(!exp && mant_sig)) {
         /* Reserved operands / Dirty zero */
-        helper_excp(EXCP_OPCDEC, 0);
+        dynamic_excp(EXCP_OPCDEC, 0);
     }
 
     if (exp < 3) {
@@ -643,7 +686,7 @@ static inline float64 g_to_float64(uint64_t a)
 
     if (!exp && mant_sig) {
         /* Reserved operands / Dirty zero */
-        helper_excp(EXCP_OPCDEC, 0);
+        dynamic_excp(EXCP_OPCDEC, 0);
     }
 
     if (exp < 3) {
@@ -904,10 +947,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 +961,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 +1000,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;
@@ -1155,187 +1199,150 @@ uint64_t helper_cvtqg (uint64_t a)
 
 /* PALcode support special instructions */
 #if !defined (CONFIG_USER_ONLY)
-void helper_hw_rei (void)
-{
-    env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
-    env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
-    env->intr_flag = 0;
-    env->lock_addr = -1;
-    /* XXX: re-enable interrupts and memory mapping */
-}
-
 void helper_hw_ret (uint64_t a)
 {
     env->pc = a & ~3;
-    env->ipr[IPR_EXC_ADDR] = a & 1;
     env->intr_flag = 0;
     env->lock_addr = -1;
-    /* XXX: re-enable interrupts and memory mapping */
+    if ((a & 1) == 0) {
+        env->pal_mode = 0;
+        swap_shadow_regs(env);
+    }
 }
 
-uint64_t helper_mfpr (int iprn, uint64_t val)
+void helper_tbia(void)
 {
-    uint64_t tmp;
-
-    if (cpu_alpha_mfpr(env, iprn, &tmp) == 0)
-        val = tmp;
-
-    return val;
+    tlb_flush(env, 1);
 }
 
-void helper_mtpr (int iprn, uint64_t val)
+void helper_tbis(uint64_t p)
 {
-    cpu_alpha_mtpr(env, iprn, val, NULL);
+    tlb_flush_page(env, p);
 }
 
-void helper_set_alt_mode (void)
+void helper_halt(uint64_t restart)
 {
-    env->saved_mode = env->ps & 0xC;
-    env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
+    if (restart) {
+        qemu_system_reset_request();
+    } else {
+        qemu_system_shutdown_request();
+    }
 }
 
-void helper_restore_mode (void)
+uint64_t helper_get_time(void)
 {
-    env->ps = (env->ps & ~0xC) | env->saved_mode;
+    return qemu_get_clock_ns(rtc_clock);
 }
 
+void helper_set_alarm(uint64_t expire)
+{
+    if (expire) {
+        env->alarm_expire = expire;
+        qemu_mod_timer(env->alarm_timer, expire);
+    } else {
+        qemu_del_timer(env->alarm_timer);
+    }
+}
 #endif
 
 /*****************************************************************************/
 /* Softmmu support */
 #if !defined (CONFIG_USER_ONLY)
-
-/* XXX: the two following helpers are pure hacks.
- *      Hopefully, we emulate the PALcode, then we should never see
- *      HW_LD / HW_ST instructions.
- */
-uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
-{
-    uint64_t tlb_addr, physaddr;
-    int index, mmu_idx;
-    void *retaddr;
-
-    mmu_idx = cpu_mmu_index(env);
-    index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
-    tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
-    if ((virtaddr & TARGET_PAGE_MASK) ==
-        (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
-    } else {
-        /* the page is not in the TLB : fill it */
-        retaddr = GETPC();
-        tlb_fill(virtaddr, 0, mmu_idx, retaddr);
-        goto redo;
-    }
-    return physaddr;
-}
-
-uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
+uint64_t helper_ldl_phys(uint64_t p)
 {
-    uint64_t tlb_addr, physaddr;
-    int index, mmu_idx;
-    void *retaddr;
-
-    mmu_idx = cpu_mmu_index(env);
-    index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
-    tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
-    if ((virtaddr & TARGET_PAGE_MASK) ==
-        (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
-    } else {
-        /* the page is not in the TLB : fill it */
-        retaddr = GETPC();
-        tlb_fill(virtaddr, 1, mmu_idx, retaddr);
-        goto redo;
-    }
-    return physaddr;
+    return (int32_t)ldl_phys(p);
 }
 
-void helper_ldl_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_phys(uint64_t p)
 {
-    ldl_raw(t1, t0);
+    return ldq_phys(p);
 }
 
-void helper_ldq_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldl_l_phys(uint64_t p)
 {
-    ldq_raw(t1, t0);
+    env->lock_addr = p;
+    return env->lock_value = (int32_t)ldl_phys(p);
 }
 
-void helper_ldl_l_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_l_phys(uint64_t p)
 {
-    env->lock = t1;
-    ldl_raw(t1, t0);
+    env->lock_addr = p;
+    return env->lock_value = ldl_phys(p);
 }
 
-void helper_ldq_l_raw(uint64_t t0, uint64_t t1)
+void helper_stl_phys(uint64_t p, uint64_t v)
 {
-    env->lock = t1;
-    ldl_raw(t1, t0);
+    stl_phys(p, v);
 }
 
-void helper_ldl_kernel(uint64_t t0, uint64_t t1)
+void helper_stq_phys(uint64_t p, uint64_t v)
 {
-    ldl_kernel(t1, t0);
+    stq_phys(p, v);
 }
 
-void helper_ldq_kernel(uint64_t t0, uint64_t t1)
+uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
 {
-    ldq_kernel(t1, t0);
-}
+    uint64_t ret = 0;
 
-void helper_ldl_data(uint64_t t0, uint64_t t1)
-{
-    ldl_data(t1, t0);
-}
+    if (p == env->lock_addr) {
+        int32_t old = ldl_phys(p);
+        if (old == (int32_t)env->lock_value) {
+            stl_phys(p, v);
+            ret = 1;
+        }
+    }
+    env->lock_addr = -1;
 
-void helper_ldq_data(uint64_t t0, uint64_t t1)
-{
-    ldq_data(t1, t0);
+    return ret;
 }
 
-void helper_stl_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
 {
-    stl_raw(t1, t0);
-}
+    uint64_t ret = 0;
 
-void helper_stq_raw(uint64_t t0, uint64_t t1)
-{
-    stq_raw(t1, t0);
+    if (p == env->lock_addr) {
+        uint64_t old = ldq_phys(p);
+        if (old == env->lock_value) {
+            stq_phys(p, v);
+            ret = 1;
+        }
+    }
+    env->lock_addr = -1;
+
+    return ret;
 }
 
-uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1)
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+                                              int is_user, void *retaddr)
 {
-    uint64_t ret;
+    uint64_t pc;
+    uint32_t insn;
 
-    if (t1 == env->lock) {
-        stl_raw(t1, t0);
-        ret = 0;
-    } else
-        ret = 1;
+    do_restore_state(retaddr);
 
-    env->lock = 1;
+    pc = env->pc;
+    insn = ldl_code(pc);
 
-    return ret;
+    env->trap_arg0 = addr;
+    env->trap_arg1 = insn >> 26;                /* opcode */
+    env->trap_arg2 = (insn >> 21) & 31;         /* dest regno */
+    helper_excp(EXCP_UNALIGN, 0);
 }
 
-uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
+void QEMU_NORETURN cpu_unassigned_access(CPUState *env1,
+                                         target_phys_addr_t addr, int is_write,
+                                         int is_exec, int unused, int size)
 {
-    uint64_t ret;
-
-    if (t1 == env->lock) {
-        stq_raw(t1, t0);
-        ret = 0;
-    } else
-        ret = 1;
-
-    env->lock = 1;
-
-    return ret;
+    env = env1;
+    env->trap_arg0 = addr;
+    env->trap_arg1 = is_write;
+    dynamic_excp(EXCP_MCHK, 0);
 }
 
+#include "softmmu_exec.h"
+
 #define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
 
 #define SHIFT 0
 #include "softmmu_template.h"
@@ -1353,33 +1360,20 @@ uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
-    TranslationBlock *tb;
     CPUState *saved_env;
-    unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
-    if (!likely(ret == 0)) {
-        if (likely(retaddr)) {
-            /* now we have a real cpu fault */
-            pc = (unsigned long)retaddr;
-            tb = tb_find_pc(pc);
-            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);
-            }
-        }
+    env = env1;
+    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (unlikely(ret != 0)) {
+        do_restore_state(retaddr);
         /* Exception index and error code are already set */
-        cpu_loop_exit();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
-
 #endif
index 3a1c625f73fc84c617e61ddbd5b7e701822e294e..a961159d5d8004ae2698b6dce2b473e589b183b5 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "host-utils.h"
 #include "tcg-op.h"
@@ -47,10 +46,6 @@ struct DisasContext {
     CPUAlphaState *env;
     uint64_t pc;
     int mem_idx;
-#if !defined (CONFIG_USER_ONLY)
-    int pal_mode;
-#endif
-    uint32_t amask;
 
     /* Current rounding mode for this TB.  */
     int tb_rm;
@@ -89,8 +84,10 @@ static TCGv cpu_pc;
 static TCGv cpu_lock_addr;
 static TCGv cpu_lock_st_addr;
 static TCGv cpu_lock_value;
-#ifdef CONFIG_USER_ONLY
-static TCGv cpu_uniq;
+static TCGv cpu_unique;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_sysval;
+static TCGv cpu_usp;
 #endif
 
 /* register names */
@@ -135,9 +132,13 @@ static void alpha_translate_init(void)
                                            offsetof(CPUState, lock_value),
                                            "lock_value");
 
-#ifdef CONFIG_USER_ONLY
-    cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0,
-                                      offsetof(CPUState, unique), "uniq");
+    cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
+                                        offsetof(CPUState, unique), "unique");
+#ifndef CONFIG_USER_ONLY
+    cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
+                                        offsetof(CPUState, sysval), "sysval");
+    cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
+                                     offsetof(CPUState, usp), "usp");
 #endif
 
     /* register helpers */
@@ -147,17 +148,21 @@ static void alpha_translate_init(void)
     done_init = 1;
 }
 
-static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+static void gen_excp_1(int exception, int error_code)
 {
     TCGv_i32 tmp1, tmp2;
 
-    tcg_gen_movi_i64(cpu_pc, ctx->pc);
     tmp1 = tcg_const_i32(exception);
     tmp2 = tcg_const_i32(error_code);
     gen_helper_excp(tmp1, tmp2);
     tcg_temp_free_i32(tmp2);
     tcg_temp_free_i32(tmp1);
+}
 
+static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+{
+    tcg_gen_movi_i64(cpu_pc, ctx->pc);
+    gen_excp_1(exception, error_code);
     return EXIT_NORETURN;
 }
 
@@ -322,7 +327,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
 #if defined(CONFIG_USER_ONLY)
     addr = cpu_lock_st_addr;
 #else
-    addr = tcg_local_new();
+    addr = tcg_temp_local_new();
 #endif
 
     if (rb != 31) {
@@ -345,7 +350,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
 
         lab_fail = gen_new_label();
         lab_done = gen_new_label();
-        tcg_gen_brcond(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
+        tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
 
         val = tcg_temp_new();
         if (quad) {
@@ -353,7 +358,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
         } else {
             tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx);
         }
-        tcg_gen_brcond(TCG_COND_NE, val, cpu_lock_value, lab_fail);
+        tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
 
         if (quad) {
             tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx);
@@ -398,7 +403,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 +422,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 {
@@ -1464,12 +1469,242 @@ static void gen_rx(int ra, int set)
     tcg_temp_free_i32(tmp);
 }
 
+static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
+{
+    /* We're emulating OSF/1 PALcode.  Many of these are trivial access
+       to internal cpu registers.  */
+
+    /* Unprivileged PAL call */
+    if (palcode >= 0x80 && palcode < 0xC0) {
+        switch (palcode) {
+        case 0x86:
+            /* IMB */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x9E:
+            /* RDUNIQUE */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
+            break;
+        case 0x9F:
+            /* WRUNIQUE */
+            tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
+            break;
+        default:
+            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+        }
+        return NO_EXIT;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    /* Privileged PAL code */
+    if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
+        switch (palcode) {
+        case 0x01:
+            /* CFLUSH */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x02:
+            /* DRAINA */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x2D:
+            /* WRVPTPTR */
+            tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUState, vptptr));
+            break;
+        case 0x31:
+            /* WRVAL */
+            tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
+            break;
+        case 0x32:
+            /* RDVAL */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
+            break;
+
+        case 0x35: {
+            /* SWPIPL */
+            TCGv tmp;
+
+            /* Note that we already know we're in kernel mode, so we know
+               that PS only contains the 3 IPL bits.  */
+            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+
+            /* But make sure and store only the 3 IPL bits from the user.  */
+            tmp = tcg_temp_new();
+            tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
+            tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUState, ps));
+            tcg_temp_free(tmp);
+            break;
+        }
+
+        case 0x36:
+            /* RDPS */
+            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+            break;
+        case 0x38:
+            /* WRUSP */
+            tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
+            break;
+        case 0x3A:
+            /* RDUSP */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
+            break;
+        case 0x3C:
+            /* WHAMI */
+            tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
+                              offsetof(CPUState, cpu_index));
+            break;
+
+        default:
+            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+        }
+        return NO_EXIT;
+    }
+#endif
+
+    return gen_invalid(ctx);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+#define PR_BYTE         0x100000
+#define PR_LONG         0x200000
+
+static int cpu_pr_data(int pr)
+{
+    switch (pr) {
+    case  0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
+    case  1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
+    case  2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
+    case  3: return offsetof(CPUAlphaState, trap_arg0);
+    case  4: return offsetof(CPUAlphaState, trap_arg1);
+    case  5: return offsetof(CPUAlphaState, trap_arg2);
+    case  6: return offsetof(CPUAlphaState, exc_addr);
+    case  7: return offsetof(CPUAlphaState, palbr);
+    case  8: return offsetof(CPUAlphaState, ptbr);
+    case  9: return offsetof(CPUAlphaState, vptptr);
+    case 10: return offsetof(CPUAlphaState, unique);
+    case 11: return offsetof(CPUAlphaState, sysval);
+    case 12: return offsetof(CPUAlphaState, usp);
+
+    case 32 ... 39:
+        return offsetof(CPUAlphaState, shadow[pr - 32]);
+    case 40 ... 63:
+        return offsetof(CPUAlphaState, scratch[pr - 40]);
+
+    case 251:
+        return offsetof(CPUAlphaState, alarm_expire);
+    }
+    return 0;
+}
+
+static ExitStatus gen_mfpr(int ra, int regno)
+{
+    int data = cpu_pr_data(regno);
+
+    /* In our emulated PALcode, these processor registers have no
+       side effects from reading.  */
+    if (ra == 31) {
+        return NO_EXIT;
+    }
+
+    if (regno == 250) {
+        /* WALL_TIME */
+        if (use_icount) {
+            gen_io_start();
+            gen_helper_get_time(cpu_ir[ra]);
+            gen_io_end();
+            return EXIT_PC_STALE;
+        } else {
+            gen_helper_get_time(cpu_ir[ra]);
+            return NO_EXIT;
+        }
+    }
+
+    /* The basic registers are data only, and unknown registers
+       are read-zero, write-ignore.  */
+    if (data == 0) {
+        tcg_gen_movi_i64(cpu_ir[ra], 0);
+    } else if (data & PR_BYTE) {
+        tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
+    } else if (data & PR_LONG) {
+        tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
+    } else {
+        tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
+    }
+    return NO_EXIT;
+}
+
+static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
+{
+    TCGv tmp;
+    int data;
+
+    if (rb == 31) {
+        tmp = tcg_const_i64(0);
+    } else {
+        tmp = cpu_ir[rb];
+    }
+
+    switch (regno) {
+    case 255:
+        /* TBIA */
+        gen_helper_tbia();
+        break;
+
+    case 254:
+        /* TBIS */
+        gen_helper_tbis(tmp);
+        break;
+
+    case 253:
+        /* WAIT */
+        tmp = tcg_const_i64(1);
+        tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUState, halted));
+        return gen_excp(ctx, EXCP_HLT, 0);
+
+    case 252:
+        /* HALT */
+        gen_helper_halt(tmp);
+        return EXIT_PC_STALE;
+
+    case 251:
+        /* ALARM */
+        gen_helper_set_alarm(tmp);
+        break;
+
+    default:
+        /* The basic registers are data only, and unknown registers
+           are read-zero, write-ignore.  */
+        data = cpu_pr_data(regno);
+        if (data != 0) {
+            if (data & PR_BYTE) {
+                tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+            } else if (data & PR_LONG) {
+                tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+            } else {
+                tcg_gen_st_i64(tmp, cpu_env, data);
+            }
+        }
+        break;
+    }
+
+    if (rb == 31) {
+        tcg_temp_free(tmp);
+    }
+
+    return NO_EXIT;
+}
+#endif /* !USER_ONLY*/
+
 static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
 {
     uint32_t palcode;
-    int32_t disp21, disp16, disp12;
+    int32_t disp21, disp16;
+#ifndef CONFIG_USER_ONLY
+    int32_t disp12;
+#endif
     uint16_t fn11;
-    uint8_t opc, ra, rb, rc, fpfn, fn7, fn2, islit, real_islit;
+    uint8_t opc, ra, rb, rc, fpfn, fn7, islit, real_islit;
     uint8_t lit;
     ExitStatus ret;
 
@@ -1487,11 +1722,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     palcode = insn & 0x03FFFFFF;
     disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
     disp16 = (int16_t)(insn & 0x0000FFFF);
+#ifndef CONFIG_USER_ONLY
     disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
+#endif
     fn11 = (insn >> 5) & 0x000007FF;
     fpfn = fn11 & 0x3F;
     fn7 = (insn >> 5) & 0x0000007F;
-    fn2 = (insn >> 5) & 0x00000003;
     LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
               opc, ra, rb, rc, disp16);
 
@@ -1499,32 +1735,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     switch (opc) {
     case 0x00:
         /* CALL_PAL */
-#ifdef CONFIG_USER_ONLY
-        if (palcode == 0x9E) {
-            /* RDUNIQUE */
-            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
-            break;
-        } else if (palcode == 0x9F) {
-            /* WRUNIQUE */
-            tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
-            break;
-        }
-#endif
-        if (palcode >= 0x80 && palcode < 0xC0) {
-            /* Unprivileged PAL call */
-            ret = gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
-            break;
-        }
-#ifndef CONFIG_USER_ONLY
-        if (palcode < 0x40) {
-            /* Privileged PAL code */
-            if (ctx->mem_idx & 1)
-                goto invalid_opc;
-            ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0);
-        }
-#endif
-        /* Invalid PAL call */
-        goto invalid_opc;
+        ret = gen_call_pal(ctx, palcode);
+        break;
     case 0x01:
         /* OPC01 */
         goto invalid_opc;
@@ -1566,20 +1778,22 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x0A:
         /* LDBU */
-        if (!(ctx->amask & AMASK_BWX))
-            goto invalid_opc;
-        gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
-        break;
+        if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+            gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
+            break;
+        }
+        goto invalid_opc;
     case 0x0B:
         /* LDQ_U */
         gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1);
         break;
     case 0x0C:
         /* LDWU */
-        if (!(ctx->amask & AMASK_BWX))
-            goto invalid_opc;
-        gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
-        break;
+        if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+            gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
+            break;
+        }
+        goto invalid_opc;
     case 0x0D:
         /* STW */
         gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0);
@@ -1983,20 +2197,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         case 0x61:
             /* AMASK */
             if (likely(rc != 31)) {
-                if (islit)
-                    tcg_gen_movi_i64(cpu_ir[rc], lit);
-                else
-                    tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
-                switch (ctx->env->implver) {
-                case IMPLVER_2106x:
-                    /* EV4, EV45, LCA, LCA45 & EV5 */
-                    break;
-                case IMPLVER_21164:
-                case IMPLVER_21264:
-                case IMPLVER_21364:
-                    tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rc],
-                                     ~(uint64_t)ctx->amask);
-                    break;
+                uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT;
+
+                if (islit) {
+                    tcg_gen_movi_i64(cpu_ir[rc], lit & ~amask);
+                } else {
+                    tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rb], ~amask);
                 }
             }
             break;
@@ -2210,8 +2416,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         switch (fpfn) { /* fn11 & 0x3F */
         case 0x04:
             /* ITOFS */
-            if (!(ctx->amask & AMASK_FIX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
                 goto invalid_opc;
+            }
             if (likely(rc != 31)) {
                 if (ra != 31) {
                     TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2224,20 +2431,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x0A:
             /* SQRTF */
-            if (!(ctx->amask & AMASK_FIX))
-                goto invalid_opc;
-            gen_fsqrtf(rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtf(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x0B:
             /* SQRTS */
-            if (!(ctx->amask & AMASK_FIX))
-                goto invalid_opc;
-            gen_fsqrts(ctx, rb, rc, fn11);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrts(ctx, rb, rc, fn11);
+                break;
+            }
+            goto invalid_opc;
         case 0x14:
             /* ITOFF */
-            if (!(ctx->amask & AMASK_FIX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
                 goto invalid_opc;
+            }
             if (likely(rc != 31)) {
                 if (ra != 31) {
                     TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2250,8 +2460,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x24:
             /* ITOFT */
-            if (!(ctx->amask & AMASK_FIX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
                 goto invalid_opc;
+            }
             if (likely(rc != 31)) {
                 if (ra != 31)
                     tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]);
@@ -2261,16 +2472,18 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x2A:
             /* SQRTG */
-            if (!(ctx->amask & AMASK_FIX))
-                goto invalid_opc;
-            gen_fsqrtg(rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtg(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x02B:
             /* SQRTT */
-            if (!(ctx->amask & AMASK_FIX))
-                goto invalid_opc;
-            gen_fsqrtt(ctx, rb, rc, fn11);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtt(ctx, rb, rc, fn11);
+                break;
+            }
+            goto invalid_opc;
         default:
             goto invalid_opc;
         }
@@ -2547,8 +2760,16 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0xC000:
             /* RPCC */
-            if (ra != 31)
-                gen_helper_load_pcc(cpu_ir[ra]);
+            if (ra != 31) {
+                if (use_icount) {
+                    gen_io_start();
+                    gen_helper_load_pcc(cpu_ir[ra]);
+                    gen_io_end();
+                    ret = EXIT_PC_STALE;
+                } else {
+                    gen_helper_load_pcc(cpu_ir[ra]);
+                }
+            }
             break;
         case 0xE000:
             /* RC */
@@ -2571,18 +2792,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x19:
         /* HW_MFPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
-        goto invalid_opc;
-#else
-        if (!ctx->pal_mode)
-            goto invalid_opc;
-        if (ra != 31) {
-            TCGv tmp = tcg_const_i32(insn & 0xFF);
-            gen_helper_mfpr(cpu_ir[ra], tmp, cpu_ir[ra]);
-            tcg_temp_free(tmp);
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            return gen_mfpr(ra, insn & 0xffff);
         }
-        break;
 #endif
+        goto invalid_opc;
     case 0x1A:
         /* JMP, JSR, RET, JSR_COROUTINE.  These only differ by the branch
            prediction stack action, which of course we don't implement.  */
@@ -2598,13 +2813,15 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x1B:
         /* HW_LD (PALcode) */
-#if defined (CONFIG_USER_ONLY)
-        goto invalid_opc;
-#else
-        if (!ctx->pal_mode)
-            goto invalid_opc;
-        if (ra != 31) {
-            TCGv addr = tcg_temp_new();
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            TCGv addr;
+
+            if (ra == 31) {
+                break;
+            }
+
+            addr = tcg_temp_new();
             if (rb != 31)
                 tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
             else
@@ -2612,27 +2829,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             switch ((insn >> 12) & 0xF) {
             case 0x0:
                 /* Longword physical access (hw_ldl/p) */
-                gen_helper_ldl_raw(cpu_ir[ra], addr);
+                gen_helper_ldl_phys(cpu_ir[ra], addr);
                 break;
             case 0x1:
                 /* Quadword physical access (hw_ldq/p) */
-                gen_helper_ldq_raw(cpu_ir[ra], addr);
+                gen_helper_ldq_phys(cpu_ir[ra], addr);
                 break;
             case 0x2:
                 /* Longword physical access with lock (hw_ldl_l/p) */
-                gen_helper_ldl_l_raw(cpu_ir[ra], addr);
+                gen_helper_ldl_l_phys(cpu_ir[ra], addr);
                 break;
             case 0x3:
                 /* Quadword physical access with lock (hw_ldq_l/p) */
-                gen_helper_ldq_l_raw(cpu_ir[ra], addr);
+                gen_helper_ldq_l_phys(cpu_ir[ra], addr);
                 break;
             case 0x4:
                 /* Longword virtual PTE fetch (hw_ldl/v) */
-                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
-                break;
+                goto invalid_opc;
             case 0x5:
                 /* Quadword virtual PTE fetch (hw_ldq/v) */
-                tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+                goto invalid_opc;
                 break;
             case 0x6:
                 /* Incpu_ir[ra]id */
@@ -2642,63 +2858,47 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
                 goto invalid_opc;
             case 0x8:
                 /* Longword virtual access (hw_ldl) */
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_ldl_raw(cpu_ir[ra], addr);
-                break;
+                goto invalid_opc;
             case 0x9:
                 /* Quadword virtual access (hw_ldq) */
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_ldq_raw(cpu_ir[ra], addr);
-                break;
+                goto invalid_opc;
             case 0xA:
                 /* Longword virtual access with protection check (hw_ldl/w) */
-                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
+                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_KERNEL_IDX);
                 break;
             case 0xB:
                 /* Quadword virtual access with protection check (hw_ldq/w) */
-                tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+                tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_KERNEL_IDX);
                 break;
             case 0xC:
                 /* Longword virtual access with alt access mode (hw_ldl/a)*/
-                gen_helper_set_alt_mode();
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_ldl_raw(cpu_ir[ra], addr);
-                gen_helper_restore_mode();
-                break;
+                goto invalid_opc;
             case 0xD:
                 /* Quadword virtual access with alt access mode (hw_ldq/a) */
-                gen_helper_set_alt_mode();
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_ldq_raw(cpu_ir[ra], addr);
-                gen_helper_restore_mode();
-                break;
+                goto invalid_opc;
             case 0xE:
                 /* Longword virtual access with alternate access mode and
-                 * protection checks (hw_ldl/wa)
-                 */
-                gen_helper_set_alt_mode();
-                gen_helper_ldl_data(cpu_ir[ra], addr);
-                gen_helper_restore_mode();
+                   protection checks (hw_ldl/wa) */
+                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_USER_IDX);
                 break;
             case 0xF:
                 /* Quadword virtual access with alternate access mode and
-                 * protection checks (hw_ldq/wa)
-                 */
-                gen_helper_set_alt_mode();
-                gen_helper_ldq_data(cpu_ir[ra], addr);
-                gen_helper_restore_mode();
+                   protection checks (hw_ldq/wa) */
+                tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_USER_IDX);
                 break;
             }
             tcg_temp_free(addr);
+            break;
         }
-        break;
 #endif
+        goto invalid_opc;
     case 0x1C:
         switch (fn7) {
         case 0x00:
             /* SEXTB */
-            if (!(ctx->amask & AMASK_BWX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_BWX) == 0) {
                 goto invalid_opc;
+            }
             if (likely(rc != 31)) {
                 if (islit)
                     tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit));
@@ -2708,138 +2908,164 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x01:
             /* SEXTW */
-            if (!(ctx->amask & AMASK_BWX))
-                goto invalid_opc;
-            if (likely(rc != 31)) {
-                if (islit)
-                    tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
-                else
-                    tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+            if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
+                    } else {
+                        tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
             }
-            break;
+            goto invalid_opc;
         case 0x30:
             /* CTPOP */
-            if (!(ctx->amask & AMASK_CIX))
-                goto invalid_opc;
-            if (likely(rc != 31)) {
-                if (islit)
-                    tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
-                else
-                    gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
+                    } else {
+                        gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
             }
-            break;
+            goto invalid_opc;
         case 0x31:
             /* PERR */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_perr(ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_perr(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x32:
             /* CTLZ */
-            if (!(ctx->amask & AMASK_CIX))
-                goto invalid_opc;
-            if (likely(rc != 31)) {
-                if (islit)
-                    tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
-                else
-                    gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
+                    } else {
+                        gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
             }
-            break;
+            goto invalid_opc;
         case 0x33:
             /* CTTZ */
-            if (!(ctx->amask & AMASK_CIX))
-                goto invalid_opc;
-            if (likely(rc != 31)) {
-                if (islit)
-                    tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
-                else
-                    gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
+                    } else {
+                        gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
             }
-            break;
+            goto invalid_opc;
         case 0x34:
             /* UNPKBW */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            if (real_islit || ra != 31)
-                goto invalid_opc;
-            gen_unpkbw (rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_unpkbw(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x35:
             /* UNPKBL */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            if (real_islit || ra != 31)
-                goto invalid_opc;
-            gen_unpkbl (rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_unpkbl(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x36:
             /* PKWB */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            if (real_islit || ra != 31)
-                goto invalid_opc;
-            gen_pkwb (rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_pkwb(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x37:
             /* PKLB */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            if (real_islit || ra != 31)
-                goto invalid_opc;
-            gen_pklb (rb, rc);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_pklb(rb, rc);
+                break;
+            }
+            goto invalid_opc;
         case 0x38:
             /* MINSB8 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_minsb8 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minsb8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x39:
             /* MINSW4 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_minsw4 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minsw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3A:
             /* MINUB8 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_minub8 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minub8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3B:
             /* MINUW4 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_minuw4 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minuw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3C:
             /* MAXUB8 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_maxub8 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxub8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3D:
             /* MAXUW4 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_maxuw4 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxuw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3E:
             /* MAXSB8 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_maxsb8 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxsb8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x3F:
             /* MAXSW4 */
-            if (!(ctx->amask & AMASK_MVI))
-                goto invalid_opc;
-            gen_maxsw4 (ra, rb, rc, islit, lit);
-            break;
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxsw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
         case 0x70:
             /* FTOIT */
-            if (!(ctx->amask & AMASK_FIX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
                 goto invalid_opc;
+            }
             if (likely(rc != 31)) {
                 if (ra != 31)
                     tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]);
@@ -2849,8 +3075,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x78:
             /* FTOIS */
-            if (!(ctx->amask & AMASK_FIX))
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
                 goto invalid_opc;
+            }
             if (rc != 31) {
                 TCGv_i32 tmp1 = tcg_temp_new_i32();
                 if (ra != 31)
@@ -2870,57 +3097,36 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x1D:
         /* HW_MTPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
-        goto invalid_opc;
-#else
-        if (!ctx->pal_mode)
-            goto invalid_opc;
-        else {
-            TCGv tmp1 = tcg_const_i32(insn & 0xFF);
-            if (ra != 31)
-                gen_helper_mtpr(tmp1, cpu_ir[ra]);
-            else {
-                TCGv tmp2 = tcg_const_i64(0);
-                gen_helper_mtpr(tmp1, tmp2);
-                tcg_temp_free(tmp2);
-            }
-            tcg_temp_free(tmp1);
-            ret = EXIT_PC_STALE;
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            return gen_mtpr(ctx, rb, insn & 0xffff);
         }
-        break;
 #endif
-    case 0x1E:
-        /* HW_REI (PALcode) */
-#if defined (CONFIG_USER_ONLY)
         goto invalid_opc;
-#else
-        if (!ctx->pal_mode)
-            goto invalid_opc;
-        if (rb == 31) {
-            /* "Old" alpha */
-            gen_helper_hw_rei();
-        } else {
-            TCGv tmp;
-
-            if (ra != 31) {
-                tmp = tcg_temp_new();
-                tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51));
-            } else
-                tmp = tcg_const_i64(((int64_t)insn << 51) >> 51);
-            gen_helper_hw_ret(tmp);
-            tcg_temp_free(tmp);
+    case 0x1E:
+        /* HW_RET (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            if (rb == 31) {
+                /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
+                   address from EXC_ADDR.  This turns out to be useful for our
+                   emulation PALcode, so continue to accept it.  */
+                TCGv tmp = tcg_temp_new();
+                tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, exc_addr));
+                gen_helper_hw_ret(tmp);
+                tcg_temp_free(tmp);
+            } else {
+                gen_helper_hw_ret(cpu_ir[rb]);
+            }
+            ret = EXIT_PC_UPDATED;
+            break;
         }
-        ret = EXIT_PC_UPDATED;
-        break;
 #endif
+        goto invalid_opc;
     case 0x1F:
         /* HW_ST (PALcode) */
-#if defined (CONFIG_USER_ONLY)
-        goto invalid_opc;
-#else
-        if (!ctx->pal_mode)
-            goto invalid_opc;
-        else {
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
             TCGv addr, val;
             addr = tcg_temp_new();
             if (rb != 31)
@@ -2936,30 +3142,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             switch ((insn >> 12) & 0xF) {
             case 0x0:
                 /* Longword physical access */
-                gen_helper_stl_raw(val, addr);
+                gen_helper_stl_phys(addr, val);
                 break;
             case 0x1:
                 /* Quadword physical access */
-                gen_helper_stq_raw(val, addr);
+                gen_helper_stq_phys(addr, val);
                 break;
             case 0x2:
                 /* Longword physical access with lock */
-                gen_helper_stl_c_raw(val, val, addr);
+                gen_helper_stl_c_phys(val, addr, val);
                 break;
             case 0x3:
                 /* Quadword physical access with lock */
-                gen_helper_stq_c_raw(val, val, addr);
+                gen_helper_stq_c_phys(val, addr, val);
                 break;
             case 0x4:
                 /* Longword virtual access */
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_stl_raw(val, addr);
-                break;
+                goto invalid_opc;
             case 0x5:
                 /* Quadword virtual access */
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_stq_raw(val, addr);
-                break;
+                goto invalid_opc;
             case 0x6:
                 /* Invalid */
                 goto invalid_opc;
@@ -2980,18 +3182,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
                 goto invalid_opc;
             case 0xC:
                 /* Longword virtual access with alternate access mode */
-                gen_helper_set_alt_mode();
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_stl_raw(val, addr);
-                gen_helper_restore_mode();
-                break;
+                goto invalid_opc;
             case 0xD:
                 /* Quadword virtual access with alternate access mode */
-                gen_helper_set_alt_mode();
-                gen_helper_st_virt_to_phys(addr, addr);
-                gen_helper_stl_raw(val, addr);
-                gen_helper_restore_mode();
-                break;
+                goto invalid_opc;
             case 0xE:
                 /* Invalid */
                 goto invalid_opc;
@@ -3002,9 +3196,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             if (ra == 31)
                 tcg_temp_free(val);
             tcg_temp_free(addr);
+            break;
         }
-        break;
 #endif
+        goto invalid_opc;
     case 0x20:
         /* LDF */
         gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0);
@@ -3155,13 +3350,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
     ctx.tb = tb;
     ctx.env = env;
     ctx.pc = pc_start;
-    ctx.amask = env->amask;
-#if defined (CONFIG_USER_ONLY)
-    ctx.mem_idx = 0;
-#else
-    ctx.mem_idx = ((env->ps >> 3) & 3);
-    ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
-#endif
+    ctx.mem_idx = cpu_mmu_index(env);
 
     /* ??? Every TB begins with unset rounding mode, to be initialized on
        the first fp insn of the TB.  Alternately we could define a proper
@@ -3211,18 +3400,15 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         ctx.pc += 4;
         ret = translate_one(ctxp, insn);
 
-        if (ret == NO_EXIT) {
-            /* If we reach a page boundary, are single stepping,
-               or exhaust instruction count, stop generation.  */
-            if (env->singlestep_enabled) {
-                gen_excp(&ctx, EXCP_DEBUG, 0);
-                ret = EXIT_PC_UPDATED;
-            } else if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
-                       || gen_opc_ptr >= gen_opc_end
-                       || num_insns >= max_insns
-                       || singlestep) {
-                ret = EXIT_PC_STALE;
-            }
+        /* If we reach a page boundary, are single stepping,
+           or exhaust instruction count, stop generation.  */
+        if (ret == NO_EXIT
+            && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
+                || gen_opc_ptr >= gen_opc_end
+                || num_insns >= max_insns
+                || singlestep
+                || env->singlestep_enabled)) {
+            ret = EXIT_PC_STALE;
         }
     } while (ret == NO_EXIT);
 
@@ -3238,7 +3424,11 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         tcg_gen_movi_i64(cpu_pc, ctx.pc);
         /* FALLTHRU */
     case EXIT_PC_UPDATED:
-        tcg_gen_exit_tb(0);
+        if (env->singlestep_enabled) {
+            gen_excp_1(EXCP_DEBUG, 0);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
         break;
     default:
         abort();
@@ -3304,7 +3494,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
     CPUAlphaState *env;
     int implver, amask, i, max;
 
-    env = qemu_mallocz(sizeof(CPUAlphaState));
+    env = g_malloc0(sizeof(CPUAlphaState));
     cpu_exec_init(env);
     alpha_translate_init();
     tlb_flush(env, 1);
@@ -3325,50 +3515,19 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
     env->implver = implver;
     env->amask = amask;
 
-    env->ps = 0x1F00;
 #if defined (CONFIG_USER_ONLY)
-    env->ps |= 1 << 3;
+    env->ps = PS_USER_MODE;
     cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
                                | FPCR_UNFD | FPCR_INED | FPCR_DNOD));
-#else
-    pal_init(env);
 #endif
     env->lock_addr = -1;
-
-    /* Initialize IPR */
-#if defined (CONFIG_USER_ONLY)
-    env->ipr[IPR_EXC_ADDR] = 0;
-    env->ipr[IPR_EXC_SUM] = 0;
-    env->ipr[IPR_EXC_MASK] = 0;
-#else
-    {
-        // uint64_t hwpcb;
-        // hwpcb = env->ipr[IPR_PCBB];
-        env->ipr[IPR_ASN] = 0;
-        env->ipr[IPR_ASTEN] = 0;
-        env->ipr[IPR_ASTSR] = 0;
-        env->ipr[IPR_DATFX] = 0;
-        /* XXX: fix this */
-        //    env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
-        //    env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
-        //    env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
-        //    env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
-        env->ipr[IPR_FEN] = 0;
-        env->ipr[IPR_IPL] = 31;
-        env->ipr[IPR_MCES] = 0;
-        env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
-        //    env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
-        env->ipr[IPR_SISR] = 0;
-        env->ipr[IPR_VIRBND] = -1ULL;
-    }
-#endif
+    env->fen = 1;
 
     qemu_init_vcpu(env);
     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 5bcd53ac73e374402f28a8b8583b16acf17fe787..c4d742f08484f09d12dbb9b9ac78442dca258de7 100644 (file)
 #define ARMV7M_EXCP_PENDSV  14
 #define ARMV7M_EXCP_SYSTICK 15
 
+/* ARM-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_FIQ   CPU_INTERRUPT_TGT_EXT_1
+
+
 typedef void ARMWriteCPFunc(void *opaque, int cp_info,
                             int srcreg, int operand, uint32_t value);
 typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
@@ -126,8 +130,15 @@ typedef struct CPUARMState {
         uint32_t c6_region[8]; /* MPU base/size registers.  */
         uint32_t c6_insn; /* Fault address registers.  */
         uint32_t c6_data;
+        uint32_t c7_par;  /* Translation result. */
         uint32_t c9_insn; /* Cache lockdown registers.  */
         uint32_t c9_data;
+        uint32_t c9_pmcr; /* performance monitor control register */
+        uint32_t c9_pmcnten; /* perf monitor counter enables */
+        uint32_t c9_pmovsr; /* perf monitor overflow status */
+        uint32_t c9_pmxevtyper; /* perf monitor event type */
+        uint32_t c9_pmuserenr; /* perf monitor user enable */
+        uint32_t c9_pminten; /* perf monitor interrupt enables */
         uint32_t c13_fcse; /* FCSE PID.  */
         uint32_t c13_context; /* Context ID.  */
         uint32_t c13_tls1; /* User RW Thread register.  */
@@ -157,10 +168,6 @@ typedef struct CPUARMState {
     /* Internal CPU feature flags.  */
     uint32_t features;
 
-    /* Callback for vectored interrupt controller.  */
-    int (*get_irq_vector)(struct CPUARMState *);
-    void *irq_opaque;
-
     /* VFP coprocessor state.  */
     struct {
         float64 regs[32];
@@ -220,7 +227,7 @@ typedef struct CPUARMState {
         void *opaque;
     } cp[15];
     void *nvic;
-    struct arm_boot_info *boot_info;
+    const struct arm_boot_info *boot_info;
 } CPUARMState;
 
 CPUARMState *cpu_arm_init(const char *cpu_model);
@@ -237,7 +244,7 @@ uint32_t do_arm_semihosting(CPUARMState *env);
 int cpu_arm_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmuu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
 
 static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
@@ -359,10 +366,17 @@ enum arm_features {
     ARM_FEATURE_VFP3,
     ARM_FEATURE_VFP_FP16,
     ARM_FEATURE_NEON,
-    ARM_FEATURE_DIV,
+    ARM_FEATURE_THUMB_DIV, /* divide supported in Thumb encoding */
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
-    ARM_FEATURE_THUMB2EE
+    ARM_FEATURE_THUMB2EE,
+    ARM_FEATURE_V7MP,    /* v7 Multiprocessing Extensions */
+    ARM_FEATURE_V4T,
+    ARM_FEATURE_V5,
+    ARM_FEATURE_STRONGARM,
+    ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
+    ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
+    ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -393,6 +407,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
@@ -407,6 +423,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define ARM_CPUID_PXA270_C5   0x69054117
 #define ARM_CPUID_ARM1136     0x4117b363
 #define ARM_CPUID_ARM1136_R2  0x4107b362
+#define ARM_CPUID_ARM1176     0x410fb767
 #define ARM_CPUID_ARM11MPCORE 0x410fb022
 #define ARM_CPUID_CORTEXA8    0x410fc080
 #define ARM_CPUID_CORTEXA9    0x410fc090
@@ -431,7 +448,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define cpu_signal_handler cpu_arm_signal_handler
 #define cpu_list arm_cpu_list
 
-#define CPU_SAVE_VERSION 2
+#define CPU_SAVE_VERSION 4
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
@@ -505,4 +522,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
     }
 }
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request &
+        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->regs[15] = tb->pc;
+}
+
 #endif
index b5627672791318aa404456dc79f86918c0f3f088..97af4d0bbae87bdadd3ce41c532eb79d92042a1d 100644 (file)
@@ -3,9 +3,8 @@
 #include <string.h>
 
 #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)
@@ -36,6 +35,12 @@ static uint32_t arm1136_cp15_c0_c1[8] =
 static uint32_t arm1136_cp15_c0_c2[8] =
 { 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
 
+static uint32_t arm1176_cp15_c0_c1[8] =
+{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 };
+
+static uint32_t arm1176_cp15_c0_c2[8] =
+{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
+
 static uint32_t cpu_arm_find_by_name(const char *name);
 
 static inline void set_feature(CPUARMState *env, int feature)
@@ -48,28 +53,47 @@ 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;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
-    case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        /* This is the 1136 r1, which is a v6K core */
+        set_feature(env, ARM_FEATURE_V6K);
+        /* Fall through */
+    case ARM_CPUID_ARM1136_R2:
+        /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+         * older core than plain "arm1136". In particular this does not
+         * have the v6K features.
+         */
+        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);
+        /* These ID register values are correct for 1136 but may be wrong
+         * for 1136_r2 (in particular r0p2 does not actually implement most
+         * of the ID registers).
+         */
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -78,11 +102,30 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
+    case ARM_CPUID_ARM1176:
+        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);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_VAPA);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
+        memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        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);
         set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -91,6 +134,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 +158,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);
@@ -123,6 +170,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP_FP16);
         set_feature(env, ARM_FEATURE_NEON);
         set_feature(env, ARM_FEATURE_THUMB2EE);
+        /* Note that A9 supports the MP extensions even for
+         * A9UP and single-core A9MP (which are both different
+         * and valid configurations; we don't model A9UP).
+         */
+        set_feature(env, ARM_FEATURE_V7MP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
@@ -135,26 +187,33 @@ 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);
         set_feature(env, ARM_FEATURE_M);
-        set_feature(env, ARM_FEATURE_DIV);
+        set_feature(env, ARM_FEATURE_THUMB_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);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
+        set_feature(env, ARM_FEATURE_VFP4);
         set_feature(env, ARM_FEATURE_VFP_FP16);
         set_feature(env, ARM_FEATURE_NEON);
         set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_DIV);
+        set_feature(env, ARM_FEATURE_ARM_DIV);
+        set_feature(env, ARM_FEATURE_V7MP);
         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;
@@ -167,6 +226,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;
@@ -178,6 +239,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);
@@ -185,10 +248,23 @@ 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;
     }
+
+    /* Some features automatically imply others: */
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        set_feature(env, ARM_FEATURE_VAPA);
+    }
+    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
+    }
 }
 
 void cpu_reset(CPUARMState *env)
@@ -226,7 +302,7 @@ void cpu_reset(CPUARMState *env)
         if (rom) {
             /* We should really use ldl_phys here, in case the guest
                modified flash and reset itself.  However images
-               loaded via -kenrel have not been copied yet, so load the
+               loaded via -kernel have not been copied yet, so load the
                values directly from there.  */
             env->regs[13] = ldl_p(rom);
             pc = ldl_p(rom + 4);
@@ -236,10 +312,18 @@ void cpu_reset(CPUARMState *env)
     }
     env->vfp.xregs[ARM_VFP_FPEXC] = 0;
     env->cp15.c2_base_mask = 0xffffc000u;
+    /* v7 performance monitor control register: same implementor
+     * field as main ID register, and we implement no event counters.
+     */
+    env->cp15.c9_pmcr = (id & 0xff000000);
 #endif
     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);
 }
 
@@ -304,7 +388,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
     id = cpu_arm_find_by_name(cpu_model);
     if (id == 0)
         return NULL;
-    env = qemu_mallocz(sizeof(CPUARMState));
+    env = g_malloc0(sizeof(CPUARMState));
     cpu_exec_init(env);
     if (!inited) {
         inited = 1;
@@ -339,12 +423,15 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_ARM1026, "arm1026"},
     { ARM_CPUID_ARM1136, "arm1136"},
     { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
+    { ARM_CPUID_ARM1176, "arm1176"},
     { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
     { ARM_CPUID_CORTEXM3, "cortex-m3"},
     { ARM_CPUID_CORTEXA8, "cortex-a8"},
     { 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" },
@@ -388,7 +475,7 @@ static uint32_t cpu_arm_find_by_name(const char *name)
 
 void cpu_arm_close(CPUARMState *env)
 {
-    free(env);
+    g_free(env);
 }
 
 uint32_t cpsr_read(CPUARMState *env)
@@ -499,7 +586,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     if (rw == 2) {
         env->exception_index = EXCP_PREFETCH_ABORT;
@@ -808,6 +895,7 @@ void do_interrupt(CPUARMState *env)
                 return;
             }
         }
+        env->cp15.c5_insn = 2;
         /* Fall through to prefetch abort.  */
     case EXCP_PREFETCH_ABORT:
         new_mode = ARM_CPU_MODE_ABT;
@@ -850,7 +938,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;
@@ -900,7 +992,7 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
   case 6:
       return prot_ro;
   case 7:
-      if (!arm_feature (env, ARM_FEATURE_V7))
+      if (!arm_feature (env, ARM_FEATURE_V6K))
           return 0;
       return prot_ro;
   default:
@@ -1206,7 +1298,7 @@ static inline int get_phys_addr(CPUState *env, uint32_t address,
 }
 
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
-                              int access_type, int mmu_idx, int is_softmmu)
+                              int access_type, int mmu_idx)
 {
     uint32_t phys_addr;
     target_ulong page_size;
@@ -1341,7 +1433,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;
@@ -1450,8 +1542,49 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
     case 7: /* Cache control.  */
         env->cp15.c15_i_max = 0x000;
         env->cp15.c15_i_min = 0xff0;
-        /* No cache, so nothing to do.  */
-        /* ??? MPCore has VA to PA translation functions.  */
+        if (op1 != 0) {
+            goto bad_reg;
+        }
+        /* No cache, so nothing to do except VA->PA translations. */
+        if (arm_feature(env, ARM_FEATURE_VAPA)) {
+            switch (crm) {
+            case 4:
+                if (arm_feature(env, ARM_FEATURE_V7)) {
+                    env->cp15.c7_par = val & 0xfffff6ff;
+                } else {
+                    env->cp15.c7_par = val & 0xfffff1ff;
+                }
+                break;
+            case 8: {
+                uint32_t phys_addr;
+                target_ulong page_size;
+                int prot;
+                int ret, is_user = op2 & 2;
+                int access_type = op2 & 1;
+
+                if (op2 & 4) {
+                    /* Other states are only available with TrustZone */
+                    goto bad_reg;
+                }
+                ret = get_phys_addr(env, val, access_type, is_user,
+                                    &phys_addr, &prot, &page_size);
+                if (ret == 0) {
+                    /* We do not set any attribute bits in the PAR */
+                    if (page_size == (1 << 24)
+                        && arm_feature(env, ARM_FEATURE_V7)) {
+                        env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1;
+                    } else {
+                        env->cp15.c7_par = phys_addr & 0xfffff000;
+                    }
+                } else {
+                    env->cp15.c7_par = ((ret & (10 << 1)) >> 5) |
+                                       ((ret & (12 << 1)) >> 6) |
+                                       ((ret & 0xf) << 1) | 1;
+                }
+                break;
+            }
+            }
+        }
         break;
     case 8: /* MMU TLB control.  */
         switch (op2) {
@@ -1475,6 +1608,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) {
@@ -1500,6 +1635,81 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
         case 1: /* TCM memory region registers.  */
             /* Not implemented.  */
             goto bad_reg;
+        case 12: /* Performance monitor control */
+            /* Performance monitors are implementation defined in v7,
+             * but with an ARM recommended set of registers, which we
+             * follow (although we don't actually implement any counters)
+             */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* performance monitor control register */
+                /* only the DP, X, D and E bits are writable */
+                env->cp15.c9_pmcr &= ~0x39;
+                env->cp15.c9_pmcr |= (val & 0x39);
+                break;
+            case 1: /* Count enable set register */
+                val &= (1 << 31);
+                env->cp15.c9_pmcnten |= val;
+                break;
+            case 2: /* Count enable clear */
+                val &= (1 << 31);
+                env->cp15.c9_pmcnten &= ~val;
+                break;
+            case 3: /* Overflow flag status */
+                env->cp15.c9_pmovsr &= ~val;
+                break;
+            case 4: /* Software increment */
+                /* RAZ/WI since we don't implement the software-count event */
+                break;
+            case 5: /* Event counter selection register */
+                /* Since we don't implement any events, writing to this register
+                 * is actually UNPREDICTABLE. So we choose to RAZ/WI.
+                 */
+                break;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 13: /* Performance counters */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* Cycle count register: not implemented, so RAZ/WI */
+                break;
+            case 1: /* Event type select */
+                env->cp15.c9_pmxevtyper = val & 0xff;
+                break;
+            case 2: /* Event count register */
+                /* Unimplemented (we have no events), RAZ/WI */
+                break;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 14: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* user enable */
+                env->cp15.c9_pmuserenr = val & 1;
+                /* changes access rights for cp registers, so flush tbs */
+                tb_flush(env);
+                break;
+            case 1: /* interrupt enable set */
+                /* We have no event counters so only the C bit can be changed */
+                val &= (1 << 31);
+                env->cp15.c9_pminten |= val;
+                break;
+            case 2: /* interrupt enable clear */
+                val &= (1 << 31);
+                env->cp15.c9_pminten &= ~val;
+                break;
+            }
+            break;
         default:
             goto bad_reg;
         }
@@ -1602,12 +1812,28 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                     return 0;
                 case 3: /* TLB type register.  */
                     return 0; /* No lockable TLB entries.  */
-                case 5: /* CPU ID */
-                    if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
-                        return env->cpu_index | 0x80000900;
-                    } else {
-                        return env->cpu_index;
+                case 5: /* MPIDR */
+                    /* The MPIDR was standardised in v7; prior to
+                     * this it was implemented only in the 11MPCore.
+                     * For all other pre-v7 cores it does not exist.
+                     */
+                    if (arm_feature(env, ARM_FEATURE_V7) ||
+                        ARM_CPUID(env) == ARM_CPUID_ARM11MPCORE) {
+                        int mpidr = env->cpu_index;
+                        /* We don't support setting cluster ID ([8..11])
+                         * so these bits always RAZ.
+                         */
+                        if (arm_feature(env, ARM_FEATURE_V7MP)) {
+                            mpidr |= (1 << 31);
+                            /* Cores which are uniprocessor (non-coherent)
+                             * but still implement the MP extensions set
+                             * bit 30. (For instance, A9UP.) However we do
+                             * not currently model any of those cores.
+                             */
+                        }
+                        return mpidr;
                     }
+                    /* otherwise fall through to the unimplemented-reg case */
                 default:
                     goto bad_reg;
                 }
@@ -1666,6 +1892,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                 return 1;
             case ARM_CPUID_ARM1136:
             case ARM_CPUID_ARM1136_R2:
+            case ARM_CPUID_ARM1176:
                 return 7;
             case ARM_CPUID_ARM11MPCORE:
                 return 1;
@@ -1767,32 +1994,89 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
            }
         }
     case 7: /* Cache control.  */
+        if (crm == 4 && op1 == 0 && op2 == 0) {
+            return env->cp15.c7_par;
+        }
         /* FIXME: Should only clear Z flag if destination is r15.  */
         env->ZF = 0;
         return 0;
     case 8: /* MMU TLB control.  */
         goto bad_reg;
-    case 9: /* Cache lockdown.  */
-        switch (op1) {
-        case 0: /* L1 cache.  */
-           if (arm_feature(env, ARM_FEATURE_OMAPCP))
-               return 0;
+    case 9:
+        switch (crm) {
+        case 0: /* Cache lockdown */
+            switch (op1) {
+            case 0: /* L1 cache.  */
+                if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+                    return 0;
+                }
+                switch (op2) {
+                case 0:
+                    return env->cp15.c9_data;
+                case 1:
+                    return env->cp15.c9_insn;
+                default:
+                    goto bad_reg;
+                }
+            case 1: /* L2 cache */
+                if (crm != 0) {
+                    goto bad_reg;
+                }
+                /* L2 Lockdown and Auxiliary control.  */
+                return 0;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 12: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
             switch (op2) {
-            case 0:
-                return env->cp15.c9_data;
-            case 1:
-                return env->cp15.c9_insn;
+            case 0: /* performance monitor control register */
+                return env->cp15.c9_pmcr;
+            case 1: /* count enable set */
+            case 2: /* count enable clear */
+                return env->cp15.c9_pmcnten;
+            case 3: /* overflow flag status */
+                return env->cp15.c9_pmovsr;
+            case 4: /* software increment */
+            case 5: /* event counter selection register */
+                return 0; /* Unimplemented, RAZ/WI */
             default:
                 goto bad_reg;
             }
-        case 1: /* L2 cache */
-            if (crm != 0)
+        case 13: /* Performance counters */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 1: /* Event type select */
+                return env->cp15.c9_pmxevtyper;
+            case 0: /* Cycle count register */
+            case 2: /* Event count register */
+                /* Unimplemented, so RAZ/WI */
+                return 0;
+            default:
+                goto bad_reg;
+            }
+        case 14: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* user enable */
+                return env->cp15.c9_pmuserenr;
+            case 1: /* interrupt enable set */
+            case 2: /* interrupt enable clear */
+                return env->cp15.c9_pminten;
+            default:
                 goto bad_reg;
-            /* L2 Lockdown and Auxiliary control.  */
-            return 0;
+            }
         default:
             goto bad_reg;
         }
+        break;
     case 10: /* MMU TLB lockdown.  */
         /* ??? TLB lockdown not implemented.  */
         return 0;
@@ -1888,11 +2172,11 @@ uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg)
         return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp;
     case 16: /* PRIMASK */
         return (env->uncached_cpsr & CPSR_I) != 0;
-    case 17: /* FAULTMASK */
-        return (env->uncached_cpsr & CPSR_F) != 0;
-    case 18: /* BASEPRI */
-    case 19: /* BASEPRI_MAX */
+    case 17: /* BASEPRI */
+    case 18: /* BASEPRI_MAX */
         return env->v7m.basepri;
+    case 19: /* FAULTMASK */
+        return (env->uncached_cpsr & CPSR_F) != 0;
     case 20: /* CONTROL */
         return env->v7m.control;
     default:
@@ -1944,20 +2228,20 @@ void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val)
         else
             env->uncached_cpsr &= ~CPSR_I;
         break;
-    case 17: /* FAULTMASK */
-        if (val & 1)
-            env->uncached_cpsr |= CPSR_F;
-        else
-            env->uncached_cpsr &= ~CPSR_F;
-        break;
-    case 18: /* BASEPRI */
+    case 17: /* BASEPRI */
         env->v7m.basepri = val & 0xff;
         break;
-    case 19: /* BASEPRI_MAX */
+    case 18: /* BASEPRI_MAX */
         val &= 0xff;
         if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0))
             env->v7m.basepri = val;
         break;
+    case 19: /* FAULTMASK */
+        if (val & 1)
+            env->uncached_cpsr |= CPSR_F;
+        else
+            env->uncached_cpsr &= ~CPSR_F;
+        break;
     case 20: /* CONTROL */
         env->v7m.control = val & 3;
         switch_v7m_sp(env, (val & 2) != 0);
@@ -2105,7 +2389,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
 /* Signed modulo arithmetic.  */
 #define SARITH16(a, b, n, op) do { \
     int32_t sum; \
-    sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \
+    sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
     RESULT(sum, n, 16); \
     if (sum >= 0) \
         ge |= 3 << (n * 2); \
@@ -2113,7 +2397,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
 
 #define SARITH8(a, b, n, op) do { \
     int32_t sum; \
-    sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \
+    sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
     RESULT(sum, n, 8); \
     if (sum >= 0) \
         ge |= 1 << n; \
@@ -2249,7 +2533,7 @@ static inline int vfp_exceptbits_from_host(int host_bits)
         target_bits |= 2;
     if (host_bits & float_flag_overflow)
         target_bits |= 4;
-    if (host_bits & float_flag_underflow)
+    if (host_bits & (float_flag_underflow | float_flag_output_denormal))
         target_bits |= 8;
     if (host_bits & float_flag_inexact)
         target_bits |= 0x10;
@@ -2346,13 +2630,15 @@ void vfp_set_fpscr(CPUState *env, uint32_t val)
 #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
 
 #define VFP_BINOP(name) \
-float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \
+float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \
 { \
-    return float32_ ## name (a, b, &env->vfp.fp_status); \
+    float_status *fpst = fpstp; \
+    return float32_ ## name(a, b, fpst); \
 } \
-float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \
+float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \
 { \
-    return float64_ ## name (a, b, &env->vfp.fp_status); \
+    float_status *fpst = fpstp; \
+    return float64_ ## name(a, b, fpst); \
 }
 VFP_BINOP(add)
 VFP_BINOP(sub)
@@ -2420,136 +2706,39 @@ 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)
-{
-    return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status);
-}
-
-float64 VFP_HELPER(uito, d)(float32 x, CPUState *env)
-{
-    return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status);
-}
-
-float32 VFP_HELPER(sito, s)(float32 x, CPUState *env)
-{
-    return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status);
-}
-
-float64 VFP_HELPER(sito, d)(float32 x, CPUState *env)
-{
-    return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status);
-}
-
-/* Float to integer conversion.  */
-float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
-{
-    if (float32_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
-}
-
-float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
-{
-    if (float64_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
-}
-
-float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
-{
-    if (float32_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
-}
+/* Integer to float and float to integer conversions */
 
-float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
-{
-    if (float64_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
+#define CONV_ITOF(name, fsz, sign) \
+    float##fsz HELPER(name)(uint32_t x, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    return sign##int32_to_##float##fsz(x, fpst); \
 }
 
-float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
-{
-    if (float32_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
+#define CONV_FTOI(name, fsz, sign, round) \
+uint32_t HELPER(name)(float##fsz x, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    if (float##fsz##_is_any_nan(x)) { \
+        float_raise(float_flag_invalid, fpst); \
+        return 0; \
+    } \
+    return float##fsz##_to_##sign##int32##round(x, fpst); \
 }
 
-float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
-{
-    if (float64_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
-}
+#define FLOAT_CONVS(name, p, fsz, sign) \
+CONV_ITOF(vfp_##name##to##p, fsz, sign) \
+CONV_FTOI(vfp_to##name##p, fsz, sign, ) \
+CONV_FTOI(vfp_to##name##z##p, fsz, sign, _round_to_zero)
 
-float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
-{
-    if (float32_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
-}
+FLOAT_CONVS(si, s, 32, )
+FLOAT_CONVS(si, d, 64, )
+FLOAT_CONVS(ui, s, 32, u)
+FLOAT_CONVS(ui, d, 64, u)
 
-float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
-{
-    if (float64_is_any_nan(x)) {
-        return float32_zero;
-    }
-    return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
-}
+#undef CONV_ITOF
+#undef CONV_FTOI
+#undef FLOAT_CONVS
 
 /* floating point conversion */
 float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
@@ -2571,110 +2760,342 @@ 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 HELPER(vfp_##name##to##p)(uint##fsz##_t  x, uint32_t shift, \
+                                    void *fpstp) \
 { \
-    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_status *fpst = fpstp; \
+    float##fsz tmp; \
+    tmp = sign##int32_to_##float##fsz((itype##_t)x, fpst); \
+    return float##fsz##_scalbn(tmp, -(int)shift, fpst); \
 } \
-ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
+uint##fsz##_t HELPER(vfp_to##name##p)(float##fsz x, uint32_t shift, \
+                                       void *fpstp) \
 { \
-    ftype tmp; \
-    if (ftype##_is_any_nan(x)) { \
-        return ftype##_zero; \
+    float_status *fpst = fpstp; \
+    float##fsz tmp; \
+    if (float##fsz##_is_any_nan(x)) { \
+        float_raise(float_flag_invalid, fpst); \
+        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, fpst); \
+    return float##fsz##_to_##itype##_round_to_zero(tmp, fpst); \
+}
+
+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.  */
-float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+static float32 do_fcvt_f16_to_f32(uint32_t a, CPUState *env, float_status *s)
 {
-    float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float16_to_float32(a, ieee, s);
+    float32 r = float16_to_float32(make_float16(a), ieee, s);
+    if (ieee) {
+        return float32_maybe_silence_nan(r);
+    }
+    return r;
 }
 
-uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
+static uint32_t do_fcvt_f32_to_f16(float32 a, CPUState *env, float_status *s)
 {
-    float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float32_to_float16(a, ieee, s);
+    float16 r = float32_to_float16(a, ieee, s);
+    if (ieee) {
+        r = float16_maybe_silence_nan(r);
+    }
+    return float16_val(r);
 }
 
+float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status);
+}
+
+uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status);
+}
+
+float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
+}
+
+uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status);
+}
+
+#define float32_two make_float32(0x40000000)
+#define float32_three make_float32(0x40400000)
+#define float32_one_point_five make_float32(0x3fc00000)
+
 float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
 {
-    float_status *s = &env->vfp.fp_status;
-    float32 two = int32_to_float32(2, s);
-    return float32_sub(two, float32_mul(a, b, s), s);
+    float_status *s = &env->vfp.standard_fp_status;
+    if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
+        (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
+        if (!(float32_is_zero(a) || float32_is_zero(b))) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        return float32_two;
+    }
+    return float32_sub(float32_two, float32_mul(a, b, s), s);
 }
 
 float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env)
 {
     float_status *s = &env->vfp.standard_fp_status;
-    float32 two = int32_to_float32(2, s);
-    float32 three = int32_to_float32(3, s);
     float32 product;
     if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
         (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
-        product = float32_zero;
-    } else {
-        product = float32_mul(a, b, s);
+        if (!(float32_is_zero(a) || float32_is_zero(b))) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        return float32_one_point_five;
     }
-    return float32_div(float32_sub(three, product, s), two, s);
+    product = float32_mul(a, b, s);
+    return float32_div(float32_sub(float32_three, product, s), float32_two, s);
 }
 
 /* NEON helpers.  */
 
-/* TODO: The architecture specifies the value that the estimate functions
-   should return.  We return the exact reciprocal/root instead.  */
+/* Constants 256 and 512 are used in some helpers; we avoid relying on
+ * int->float conversions at run-time.  */
+#define float64_256 make_float64(0x4070000000000000LL)
+#define float64_512 make_float64(0x4080000000000000LL)
+
+/* The algorithm that must be used to calculate the estimate
+ * is specified by the ARM ARM.
+ */
+static float64 recip_estimate(float64 a, CPUState *env)
+{
+    /* These calculations mustn't set any fp exception flags,
+     * so we use a local copy of the fp_status.
+     */
+    float_status dummy_status = env->vfp.standard_fp_status;
+    float_status *s = &dummy_status;
+    /* q = (int)(a * 512.0) */
+    float64 q = float64_mul(float64_512, a, s);
+    int64_t q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* r = 1.0 / (((double)q + 0.5) / 512.0) */
+    q = int64_to_float64(q_int, s);
+    q = float64_add(q, float64_half, s);
+    q = float64_div(q, float64_512, s);
+    q = float64_div(float64_one, q, s);
+
+    /* s = (int)(256.0 * r + 0.5) */
+    q = float64_mul(q, float64_256, s);
+    q = float64_add(q, float64_half, s);
+    q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* return (double)s / 256.0 */
+    return float64_div(int64_to_float64(q_int, s), float64_256, s);
+}
+
 float32 HELPER(recpe_f32)(float32 a, CPUState *env)
 {
-    float_status *s = &env->vfp.fp_status;
-    float32 one = int32_to_float32(1, s);
-    return float32_div(one, a, s);
+    float_status *s = &env->vfp.standard_fp_status;
+    float64 f64;
+    uint32_t val32 = float32_val(a);
+
+    int result_exp;
+    int a_exp = (val32  & 0x7f800000) >> 23;
+    int sign = val32 & 0x80000000;
+
+    if (float32_is_any_nan(a)) {
+        if (float32_is_signaling_nan(a)) {
+            float_raise(float_flag_invalid, s);
+        }
+        return float32_default_nan;
+    } else if (float32_is_infinity(a)) {
+        return float32_set_sign(float32_zero, float32_is_neg(a));
+    } else if (float32_is_zero_or_denormal(a)) {
+        if (!float32_is_zero(a)) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        float_raise(float_flag_divbyzero, s);
+        return float32_set_sign(float32_infinity, float32_is_neg(a));
+    } else if (a_exp >= 253) {
+        float_raise(float_flag_underflow, s);
+        return float32_set_sign(float32_zero, float32_is_neg(a));
+    }
+
+    f64 = make_float64((0x3feULL << 52)
+                       | ((int64_t)(val32 & 0x7fffff) << 29));
+
+    result_exp = 253 - a_exp;
+
+    f64 = recip_estimate(f64, env);
+
+    val32 = sign
+        | ((result_exp & 0xff) << 23)
+        | ((float64_val(f64) >> 29) & 0x7fffff);
+    return make_float32(val32);
+}
+
+/* The algorithm that must be used to calculate the estimate
+ * is specified by the ARM ARM.
+ */
+static float64 recip_sqrt_estimate(float64 a, CPUState *env)
+{
+    /* These calculations mustn't set any fp exception flags,
+     * so we use a local copy of the fp_status.
+     */
+    float_status dummy_status = env->vfp.standard_fp_status;
+    float_status *s = &dummy_status;
+    float64 q;
+    int64_t q_int;
+
+    if (float64_lt(a, float64_half, s)) {
+        /* range 0.25 <= a < 0.5 */
+
+        /* a in units of 1/512 rounded down */
+        /* q0 = (int)(a * 512.0);  */
+        q = float64_mul(float64_512, a, s);
+        q_int = float64_to_int64_round_to_zero(q, s);
+
+        /* reciprocal root r */
+        /* r = 1.0 / sqrt(((double)q0 + 0.5) / 512.0);  */
+        q = int64_to_float64(q_int, s);
+        q = float64_add(q, float64_half, s);
+        q = float64_div(q, float64_512, s);
+        q = float64_sqrt(q, s);
+        q = float64_div(float64_one, q, s);
+    } else {
+        /* range 0.5 <= a < 1.0 */
+
+        /* a in units of 1/256 rounded down */
+        /* q1 = (int)(a * 256.0); */
+        q = float64_mul(float64_256, a, s);
+        int64_t q_int = float64_to_int64_round_to_zero(q, s);
+
+        /* reciprocal root r */
+        /* r = 1.0 /sqrt(((double)q1 + 0.5) / 256); */
+        q = int64_to_float64(q_int, s);
+        q = float64_add(q, float64_half, s);
+        q = float64_div(q, float64_256, s);
+        q = float64_sqrt(q, s);
+        q = float64_div(float64_one, q, s);
+    }
+    /* r in units of 1/256 rounded to nearest */
+    /* s = (int)(256.0 * r + 0.5); */
+
+    q = float64_mul(q, float64_256,s );
+    q = float64_add(q, float64_half, s);
+    q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* return (double)s / 256.0;*/
+    return float64_div(int64_to_float64(q_int, s), float64_256, s);
 }
 
 float32 HELPER(rsqrte_f32)(float32 a, CPUState *env)
 {
-    float_status *s = &env->vfp.fp_status;
-    float32 one = int32_to_float32(1, s);
-    return float32_div(one, float32_sqrt(a, s), s);
+    float_status *s = &env->vfp.standard_fp_status;
+    int result_exp;
+    float64 f64;
+    uint32_t val;
+    uint64_t val64;
+
+    val = float32_val(a);
+
+    if (float32_is_any_nan(a)) {
+        if (float32_is_signaling_nan(a)) {
+            float_raise(float_flag_invalid, s);
+        }
+        return float32_default_nan;
+    } else if (float32_is_zero_or_denormal(a)) {
+        if (!float32_is_zero(a)) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        float_raise(float_flag_divbyzero, s);
+        return float32_set_sign(float32_infinity, float32_is_neg(a));
+    } else if (float32_is_neg(a)) {
+        float_raise(float_flag_invalid, s);
+        return float32_default_nan;
+    } else if (float32_is_infinity(a)) {
+        return float32_zero;
+    }
+
+    /* Normalize to a double-precision value between 0.25 and 1.0,
+     * preserving the parity of the exponent.  */
+    if ((val & 0x800000) == 0) {
+        f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
+                           | (0x3feULL << 52)
+                           | ((uint64_t)(val & 0x7fffff) << 29));
+    } else {
+        f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
+                           | (0x3fdULL << 52)
+                           | ((uint64_t)(val & 0x7fffff) << 29));
+    }
+
+    result_exp = (380 - ((val & 0x7f800000) >> 23)) / 2;
+
+    f64 = recip_sqrt_estimate(f64, env);
+
+    val64 = float64_val(f64);
+
+    val = ((result_exp & 0xff) << 23)
+        | ((val64 >> 29)  & 0x7fffff);
+    return make_float32(val);
 }
 
 uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env)
 {
-    float_status *s = &env->vfp.fp_status;
-    float32 tmp;
-    tmp = int32_to_float32(a, s);
-    tmp = float32_scalbn(tmp, -32, s);
-    tmp = helper_recpe_f32(tmp, env);
-    tmp = float32_scalbn(tmp, 31, s);
-    return float32_to_int32(tmp, s);
+    float64 f64;
+
+    if ((a & 0x80000000) == 0) {
+        return 0xffffffff;
+    }
+
+    f64 = make_float64((0x3feULL << 52)
+                       | ((int64_t)(a & 0x7fffffff) << 21));
+
+    f64 = recip_estimate (f64, env);
+
+    return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
 }
 
 uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env)
 {
-    float_status *s = &env->vfp.fp_status;
-    float32 tmp;
-    tmp = int32_to_float32(a, s);
-    tmp = float32_scalbn(tmp, -32, s);
-    tmp = helper_rsqrte_f32(tmp, env);
-    tmp = float32_scalbn(tmp, 31, s);
-    return float32_to_int32(tmp, s);
+    float64 f64;
+
+    if ((a & 0xc0000000) == 0) {
+        return 0xffffffff;
+    }
+
+    if (a & 0x80000000) {
+        f64 = make_float64((0x3feULL << 52)
+                           | ((uint64_t)(a & 0x7fffffff) << 21));
+    } else { /* bits 31-30 == '01' */
+        f64 = make_float64((0x3fdULL << 52)
+                           | ((uint64_t)(a & 0x3fffffff) << 22));
+    }
+
+    f64 = recip_sqrt_estimate(f64, env);
+
+    return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
+}
+
+/* VFPv4 fused multiply-accumulate */
+float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float32_muladd(a, b, c, 0, fpst);
+}
+
+float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float64_muladd(a, b, c, 0, fpst);
 }
 
 void HELPER(set_teecr)(CPUState *env, uint32_t val)
diff --git a/target-arm/helper.h b/target-arm/helper.h
new file mode 100644 (file)
index 0000000..16dd5fc
--- /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, ptr)
+DEF_HELPER_3(vfp_addd, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_subs, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_subd, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_muls, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_muld, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_divs, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_divd, f64, f64, f64, ptr)
+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, ptr)
+DEF_HELPER_2(vfp_uitod, f64, i32, ptr)
+DEF_HELPER_2(vfp_sitos, f32, i32, ptr)
+DEF_HELPER_2(vfp_sitod, f64, i32, ptr)
+
+DEF_HELPER_2(vfp_touis, i32, f32, ptr)
+DEF_HELPER_2(vfp_touid, i32, f64, ptr)
+DEF_HELPER_2(vfp_touizs, i32, f32, ptr)
+DEF_HELPER_2(vfp_touizd, i32, f64, ptr)
+DEF_HELPER_2(vfp_tosis, i32, f32, ptr)
+DEF_HELPER_2(vfp_tosid, i32, f64, ptr)
+DEF_HELPER_2(vfp_tosizs, i32, f32, ptr)
+DEF_HELPER_2(vfp_tosizd, i32, f64, ptr)
+
+DEF_HELPER_3(vfp_toshs, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_tosls, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_touhs, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_touls, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_toshd, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_tosld, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_touhd, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_tould, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_shtos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_sltos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_uhtos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_ultos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_shtod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_sltod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_uhtod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_ultod, f64, i64, i32, ptr)
+
+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_4(vfp_muladdd, f64, f64, f64, f64, ptr)
+DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr)
+
+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_3(neon_min_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_max_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_abd_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
+
+/* 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..843994d8d50ef5a8d78b5651bf76e1a727038998 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "cpu.h"
 #include "exec-all.h"
-#include "helpers.h"
+#include "helper.h"
 
 /* iwMMXt macros extracted from GNU gdb.  */
 
index 3925d3a2d587aeeeb540e2e6245497a6ea399b64..aaee9b9c114f2d47a81103760b166a1b5ba69e1e 100644 (file)
@@ -41,8 +41,15 @@ void cpu_save(QEMUFile *f, void *opaque)
     }
     qemu_put_be32(f, env->cp15.c6_insn);
     qemu_put_be32(f, env->cp15.c6_data);
+    qemu_put_be32(f, env->cp15.c7_par);
     qemu_put_be32(f, env->cp15.c9_insn);
     qemu_put_be32(f, env->cp15.c9_data);
+    qemu_put_be32(f, env->cp15.c9_pmcr);
+    qemu_put_be32(f, env->cp15.c9_pmcnten);
+    qemu_put_be32(f, env->cp15.c9_pmovsr);
+    qemu_put_be32(f, env->cp15.c9_pmxevtyper);
+    qemu_put_be32(f, env->cp15.c9_pmuserenr);
+    qemu_put_be32(f, env->cp15.c9_pminten);
     qemu_put_be32(f, env->cp15.c13_fcse);
     qemu_put_be32(f, env->cp15.c13_context);
     qemu_put_be32(f, env->cp15.c13_tls1);
@@ -148,8 +155,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     }
     env->cp15.c6_insn = qemu_get_be32(f);
     env->cp15.c6_data = qemu_get_be32(f);
+    env->cp15.c7_par = qemu_get_be32(f);
     env->cp15.c9_insn = qemu_get_be32(f);
     env->cp15.c9_data = qemu_get_be32(f);
+    env->cp15.c9_pmcr = qemu_get_be32(f);
+    env->cp15.c9_pmcnten = qemu_get_be32(f);
+    env->cp15.c9_pmovsr = qemu_get_be32(f);
+    env->cp15.c9_pmxevtyper = qemu_get_be32(f);
+    env->cp15.c9_pmuserenr = qemu_get_be32(f);
+    env->cp15.c9_pminten = qemu_get_be32(f);
     env->cp15.c13_fcse = qemu_get_be32(f);
     env->cp15.c13_context = qemu_get_be32(f);
     env->cp15.c13_tls1 = qemu_get_be32(f);
@@ -175,7 +189,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         env->vfp.vec_stride = qemu_get_be32(f);
 
         if (arm_feature(env, ARM_FEATURE_VFP3)) {
-            for (i = 0;  i < 16; i++) {
+            for (i = 16;  i < 32; i++) {
                 CPU_DoubleU u;
                 u.l.upper = qemu_get_be32(f);
                 u.l.lower = qemu_get_be32(f);
index 268af33a6cb52d7a663a74d65c7d668ff49d4e1a..b51e35a30fe18f23c3a4f5b5bdfd6d61fce6381e 100644 (file)
@@ -4,46 +4,20 @@
  * Copyright (c) 2007, 2008 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
  */
 #include <stdlib.h>
 #include <stdio.h>
 
 #include "cpu.h"
 #include "exec-all.h"
-#include "helpers.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 NEON_TYPE1(name, type) \
 typedef struct \
 { \
@@ -543,14 +517,9 @@ uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop)
 #define NEON_FN(dest, src1, src2) do { \
     int8_t tmp; \
     tmp = (int8_t)src2; \
-    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+    if ((tmp >= (ssize_t)sizeof(src1) * 8) \
+        || (tmp <= -(ssize_t)sizeof(src1) * 8)) { \
         dest = 0; \
-    } else if (tmp < -(ssize_t)sizeof(src1) * 8) { \
-        dest = src1 >> (sizeof(src1) * 8 - 1); \
-    } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \
-        dest = src1 >> (tmp - 1); \
-        dest++; \
-        dest >>= 1; \
     } else if (tmp < 0) { \
         dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
     } else { \
@@ -558,23 +527,45 @@ uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop)
     }} while (0)
 NEON_VOP(rshl_s8, neon_s8, 4)
 NEON_VOP(rshl_s16, neon_s16, 2)
-NEON_VOP(rshl_s32, neon_s32, 1)
 #undef NEON_FN
 
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
+{
+    int32_t dest;
+    int32_t val = (int32_t)valop;
+    int8_t shift = (int8_t)shiftop;
+    if ((shift >= 32) || (shift <= -32)) {
+        dest = 0;
+    } else if (shift < 0) {
+        int64_t big_dest = ((int64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
 uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
 {
     int8_t shift = (int8_t)shiftop;
     int64_t val = valop;
-    if (shift >= 64) {
+    if ((shift >= 64) || (shift <= -64)) {
         val = 0;
-    } else if (shift < -64) {
-        val >>= 63;
-    } else if (shift == -63) {
-        val >>= 63;
-        val++;
-        val >>= 1;
     } else if (shift < 0) {
-        val = (val + ((int64_t)1 << (-1 - shift))) >> -shift;
+        val >>= (-shift - 1);
+        if (val == INT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x4000000000000000LL;
+        } else {
+            val++;
+            val >>= 1;
+        }
     } else {
         val <<= shift;
     }
@@ -588,7 +579,7 @@ uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
         tmp < -(ssize_t)sizeof(src1) * 8) { \
         dest = 0; \
     } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \
-        dest = src1 >> (tmp - 1); \
+        dest = src1 >> (-tmp - 1); \
     } else if (tmp < 0) { \
         dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
     } else { \
@@ -596,20 +587,48 @@ uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
     }} while (0)
 NEON_VOP(rshl_u8, neon_u8, 4)
 NEON_VOP(rshl_u16, neon_u16, 2)
-NEON_VOP(rshl_u32, neon_u32, 1)
 #undef NEON_FN
 
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
+{
+    uint32_t dest;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32 || shift < -32) {
+        dest = 0;
+    } else if (shift == -32) {
+        dest = val >> 31;
+    } else if (shift < 0) {
+        uint64_t big_dest = ((uint64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
 uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
 {
     int8_t shift = (uint8_t)shiftop;
-    if (shift >= 64 || shift < 64) {
+    if (shift >= 64 || shift < -64) {
         val = 0;
     } else if (shift == -64) {
         /* Rounding a 1-bit result just preserves that bit.  */
         val >>= 63;
-    } if (shift < 0) {
-        val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift;
-        val >>= -shift;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == UINT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x8000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
     } else {
         val <<= shift;
     }
@@ -773,7 +792,18 @@ uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
 #define NEON_FN(dest, src1, src2) do { \
     int8_t tmp; \
     tmp = (int8_t)src2; \
-    if (tmp < 0) { \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = ~0; \
+        } else { \
+            dest = 0; \
+        } \
+    } else if (tmp < -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \
+        dest = src1 >> (sizeof(src1) * 8 - 1); \
+    } else if (tmp < 0) { \
         dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
     } else { \
         dest = src1 << tmp; \
@@ -784,14 +814,63 @@ uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
     }} while (0)
 NEON_VOP_ENV(qrshl_u8, neon_u8, 4)
 NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
-NEON_VOP_ENV(qrshl_u32, neon_u32, 1)
 #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 dest;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32) {
+        if (val) {
+            SET_QC();
+            dest = ~0;
+        } else {
+            dest = 0;
+        }
+    } else if (shift < -32) {
+        dest = 0;
+    } else if (shift == -32) {
+        dest = val >> 31;
+    } else if (shift < 0) {
+        uint64_t big_dest = ((uint64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+        if ((dest >> shift) != val) {
+            SET_QC();
+            dest = ~0;
+        }
+    }
+    return dest;
+}
+
+/* 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)
 {
     int8_t shift = (int8_t)shiftop;
-    if (shift < 0) {
-        val = (val + (1 << (-1 - shift))) >> -shift;
+    if (shift >= 64) {
+        if (val) {
+            SET_QC();
+            val = ~0;
+        }
+    } else if (shift < -64) {
+        val = 0;
+    } else if (shift == -64) {
+        val >>= 63;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == UINT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x8000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
     } else { \
         uint64_t tmp = val;
         val <<= shift;
@@ -806,33 +885,94 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
 #define NEON_FN(dest, src1, src2) do { \
     int8_t tmp; \
     tmp = (int8_t)src2; \
-    if (tmp < 0) { \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = (1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } else { \
+            dest = 0; \
+        } \
+    } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp < 0) { \
         dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
     } else { \
         dest = src1 << tmp; \
         if ((dest >> tmp) != src1) { \
             SET_QC(); \
-            dest = src1 >> 31; \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
         } \
     }} while (0)
 NEON_VOP_ENV(qrshl_s8, neon_s8, 4)
 NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
-NEON_VOP_ENV(qrshl_s32, neon_s32, 1)
 #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)
+{
+    int32_t dest;
+    int32_t val = (int32_t)valop;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32) {
+        if (val) {
+            SET_QC();
+            dest = (val >> 31) ^ ~SIGNBIT;
+        } else {
+            dest = 0;
+        }
+    } else if (shift <= -32) {
+        dest = 0;
+    } else if (shift < 0) {
+        int64_t big_dest = ((int64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+        if ((dest >> shift) != val) {
+            SET_QC();
+            dest = (val >> 31) ^ ~SIGNBIT;
+        }
+    }
+    return dest;
+}
+
+/* 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)
 {
     int8_t shift = (uint8_t)shiftop;
     int64_t val = valop;
 
-    if (shift < 0) {
-        val = (val + (1 << (-1 - shift))) >> -shift;
+    if (shift >= 64) {
+        if (val) {
+            SET_QC();
+            val = (val >> 63) ^ ~SIGNBIT64;
+        }
+    } else if (shift <= -64) {
+        val = 0;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == INT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x4000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
     } else {
-        int64_t tmp = val;;
+        int64_t tmp = val;
         val <<= shift;
         if ((val >> shift) != tmp) {
             SET_QC();
-            val = tmp >> 31;
+            val = (tmp >> 63) ^ ~SIGNBIT64;
         }
     }
     return val;
@@ -895,6 +1035,36 @@ uint32_t HELPER(neon_mul_p8)(uint32_t op1, uint32_t op2)
     return result;
 }
 
+uint64_t HELPER(neon_mull_p8)(uint32_t op1, uint32_t op2)
+{
+    uint64_t result = 0;
+    uint64_t mask;
+    uint64_t op2ex = op2;
+    op2ex = (op2ex & 0xff) |
+        ((op2ex & 0xff00) << 8) |
+        ((op2ex & 0xff0000) << 16) |
+        ((op2ex & 0xff000000) << 24);
+    while (op1) {
+        mask = 0;
+        if (op1 & 1) {
+            mask |= 0xffff;
+        }
+        if (op1 & (1 << 8)) {
+            mask |= (0xffffU << 16);
+        }
+        if (op1 & (1 << 16)) {
+            mask |= (0xffffULL << 32);
+        }
+        if (op1 & (1 << 24)) {
+            mask |= (0xffffULL << 48);
+        }
+        result ^= op2ex & mask;
+        op1 = (op1 >> 1) & 0x7f7f7f7f;
+        op2ex <<= 1;
+    }
+    return result;
+}
+
 #define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0
 NEON_VOP(tst_u8, neon_u8, 4)
 NEON_VOP(tst_u16, neon_u16, 2)
@@ -1053,6 +1223,33 @@ 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)
+{
+    uint16_t s;
+    uint8_t d;
+    uint32_t res = 0;
+#define SAT8(n) \
+    s = x >> n; \
+    if (s & 0x8000) { \
+        SET_QC(); \
+    } else { \
+        if (s > 0xff) { \
+            d = 0xff; \
+            SET_QC(); \
+        } else  { \
+            d = s; \
+        } \
+        res |= (uint32_t)d << (n / 2); \
+    }
+
+    SAT8(0);
+    SAT8(16);
+    SAT8(32);
+    SAT8(48);
+#undef SAT8
+    return res;
+}
+
 uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
 {
     uint16_t s;
@@ -1099,6 +1296,29 @@ 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 high;
+    uint32_t low;
+    low = x;
+    if (low & 0x80000000) {
+        low = 0;
+        SET_QC();
+    } else if (low > 0xffff) {
+        low = 0xffff;
+        SET_QC();
+    }
+    high = x >> 32;
+    if (high & 0x80000000) {
+        high = 0;
+        SET_QC();
+    } else if (high > 0xffff) {
+        high = 0xffff;
+        SET_QC();
+    }
+    return low | (high << 16);
+}
+
 uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
 {
     uint32_t high;
@@ -1133,6 +1353,19 @@ 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)
+{
+    if (x & 0x8000000000000000ull) {
+        SET_QC();
+        return 0;
+    }
+    if (x > 0xffffffffu) {
+        SET_QC();
+        return 0xffffffffu;
+    }
+    return x;
+}
+
 uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
 {
     if (x > 0xffffffffu) {
@@ -1146,7 +1379,7 @@ uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x)
 {
     if ((int64_t)x != (int32_t)x) {
         SET_QC();
-        return (x >> 63) ^ 0x7fffffff;
+        return ((int64_t)x >> 63) ^ 0x7fffffff;
     }
     return x;
 }
@@ -1283,9 +1516,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)
 
@@ -1293,12 +1530,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;
 }
@@ -1307,12 +1544,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;
 }
@@ -1321,8 +1558,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);
 }
 
@@ -1330,22 +1567,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
@@ -1421,7 +1658,6 @@ uint64_t HELPER(neon_negl_u16)(uint64_t x)
     return result;
 }
 
-#include <stdio.h>
 uint64_t HELPER(neon_negl_u32)(uint64_t x)
 {
     uint32_t low = -x;
@@ -1536,68 +1772,246 @@ 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;
-}
-
-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;
-}
-
-uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b)
+uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b, void *fpstp)
 {
-    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));
+    float_status *fpst = fpstp;
+    return float32_val(float32_min(make_float32(a), make_float32(b), fpst));
 }
 
-uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b)
+uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b, void *fpstp)
 {
-    return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS));
+    float_status *fpst = fpstp;
+    return float32_val(float32_max(make_float32(a), make_float32(b), fpst));
 }
 
-uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b)
+uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b, void *fpstp)
 {
-    return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS));
+    float_status *fpst = fpstp;
+    float32 f0 = make_float32(a);
+    float32 f1 = make_float32(b);
+    return float32_val(float32_abs(float32_sub(f0, f1, fpst)));
 }
 
-uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b)
+/* Floating point comparisons produce an integer result.
+ * Note that EQ doesn't signal InvalidOp for QNaNs but GE and GT do.
+ * Softfloat routines return 0/1, which we convert to the 0/-1 Neon requires.
+ */
+uint32_t HELPER(neon_ceq_f32)(uint32_t a, uint32_t b, void *fpstp)
 {
-    return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS));
-}
-
-/* Floating point comparisons produce an integer result.  */
-#define NEON_VOP_FCMP(name, cmp) \
-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; \
+    float_status *fpst = fpstp;
+    return -float32_eq_quiet(make_float32(a), make_float32(b), fpst);
 }
 
-NEON_VOP_FCMP(ceq_f32, ==)
-NEON_VOP_FCMP(cge_f32, >=)
-NEON_VOP_FCMP(cgt_f32, >)
-
-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;
-}
+uint32_t HELPER(neon_cge_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return -float32_le(make_float32(b), make_float32(a), fpst);
+}
+
+uint32_t HELPER(neon_cgt_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return -float32_lt(make_float32(b), make_float32(a), fpst);
+}
 
-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;
+uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    return -float32_le(f1, f0, fpst);
+}
+
+uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    return -float32_lt(f1, f0, fpst);
+}
+
+#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
+
+void HELPER(neon_qunzip8)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zd0, 2, 8) << 8)
+        | (ELEM(zd0, 4, 8) << 16) | (ELEM(zd0, 6, 8) << 24)
+        | (ELEM(zd1, 0, 8) << 32) | (ELEM(zd1, 2, 8) << 40)
+        | (ELEM(zd1, 4, 8) << 48) | (ELEM(zd1, 6, 8) << 56);
+    uint64_t d1 = ELEM(zm0, 0, 8) | (ELEM(zm0, 2, 8) << 8)
+        | (ELEM(zm0, 4, 8) << 16) | (ELEM(zm0, 6, 8) << 24)
+        | (ELEM(zm1, 0, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+        | (ELEM(zm1, 4, 8) << 48) | (ELEM(zm1, 6, 8) << 56);
+    uint64_t m0 = ELEM(zd0, 1, 8) | (ELEM(zd0, 3, 8) << 8)
+        | (ELEM(zd0, 5, 8) << 16) | (ELEM(zd0, 7, 8) << 24)
+        | (ELEM(zd1, 1, 8) << 32) | (ELEM(zd1, 3, 8) << 40)
+        | (ELEM(zd1, 5, 8) << 48) | (ELEM(zd1, 7, 8) << 56);
+    uint64_t m1 = ELEM(zm0, 1, 8) | (ELEM(zm0, 3, 8) << 8)
+        | (ELEM(zm0, 5, 8) << 16) | (ELEM(zm0, 7, 8) << 24)
+        | (ELEM(zm1, 1, 8) << 32) | (ELEM(zm1, 3, 8) << 40)
+        | (ELEM(zm1, 5, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qunzip16)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zd0, 2, 16) << 16)
+        | (ELEM(zd1, 0, 16) << 32) | (ELEM(zd1, 2, 16) << 48);
+    uint64_t d1 = ELEM(zm0, 0, 16) | (ELEM(zm0, 2, 16) << 16)
+        | (ELEM(zm1, 0, 16) << 32) | (ELEM(zm1, 2, 16) << 48);
+    uint64_t m0 = ELEM(zd0, 1, 16) | (ELEM(zd0, 3, 16) << 16)
+        | (ELEM(zd1, 1, 16) << 32) | (ELEM(zd1, 3, 16) << 48);
+    uint64_t m1 = ELEM(zm0, 1, 16) | (ELEM(zm0, 3, 16) << 16)
+        | (ELEM(zm1, 1, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qunzip32)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zd1, 0, 32) << 32);
+    uint64_t d1 = ELEM(zm0, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+    uint64_t m0 = ELEM(zd0, 1, 32) | (ELEM(zd1, 1, 32) << 32);
+    uint64_t m1 = ELEM(zm0, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zd, 2, 8) << 8)
+        | (ELEM(zd, 4, 8) << 16) | (ELEM(zd, 6, 8) << 24)
+        | (ELEM(zm, 0, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+        | (ELEM(zm, 4, 8) << 48) | (ELEM(zm, 6, 8) << 56);
+    uint64_t m0 = ELEM(zd, 1, 8) | (ELEM(zd, 3, 8) << 8)
+        | (ELEM(zd, 5, 8) << 16) | (ELEM(zd, 7, 8) << 24)
+        | (ELEM(zm, 1, 8) << 32) | (ELEM(zm, 3, 8) << 40)
+        | (ELEM(zm, 5, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zd, 2, 16) << 16)
+        | (ELEM(zm, 0, 16) << 32) | (ELEM(zm, 2, 16) << 48);
+    uint64_t m0 = ELEM(zd, 1, 16) | (ELEM(zd, 3, 16) << 16)
+        | (ELEM(zm, 1, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_qzip8)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zm0, 0, 8) << 8)
+        | (ELEM(zd0, 1, 8) << 16) | (ELEM(zm0, 1, 8) << 24)
+        | (ELEM(zd0, 2, 8) << 32) | (ELEM(zm0, 2, 8) << 40)
+        | (ELEM(zd0, 3, 8) << 48) | (ELEM(zm0, 3, 8) << 56);
+    uint64_t d1 = ELEM(zd0, 4, 8) | (ELEM(zm0, 4, 8) << 8)
+        | (ELEM(zd0, 5, 8) << 16) | (ELEM(zm0, 5, 8) << 24)
+        | (ELEM(zd0, 6, 8) << 32) | (ELEM(zm0, 6, 8) << 40)
+        | (ELEM(zd0, 7, 8) << 48) | (ELEM(zm0, 7, 8) << 56);
+    uint64_t m0 = ELEM(zd1, 0, 8) | (ELEM(zm1, 0, 8) << 8)
+        | (ELEM(zd1, 1, 8) << 16) | (ELEM(zm1, 1, 8) << 24)
+        | (ELEM(zd1, 2, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+        | (ELEM(zd1, 3, 8) << 48) | (ELEM(zm1, 3, 8) << 56);
+    uint64_t m1 = ELEM(zd1, 4, 8) | (ELEM(zm1, 4, 8) << 8)
+        | (ELEM(zd1, 5, 8) << 16) | (ELEM(zm1, 5, 8) << 24)
+        | (ELEM(zd1, 6, 8) << 32) | (ELEM(zm1, 6, 8) << 40)
+        | (ELEM(zd1, 7, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qzip16)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zm0, 0, 16) << 16)
+        | (ELEM(zd0, 1, 16) << 32) | (ELEM(zm0, 1, 16) << 48);
+    uint64_t d1 = ELEM(zd0, 2, 16) | (ELEM(zm0, 2, 16) << 16)
+        | (ELEM(zd0, 3, 16) << 32) | (ELEM(zm0, 3, 16) << 48);
+    uint64_t m0 = ELEM(zd1, 0, 16) | (ELEM(zm1, 0, 16) << 16)
+        | (ELEM(zd1, 1, 16) << 32) | (ELEM(zm1, 1, 16) << 48);
+    uint64_t m1 = ELEM(zd1, 2, 16) | (ELEM(zm1, 2, 16) << 16)
+        | (ELEM(zd1, 3, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qzip32)(CPUState *env, 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]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zm0, 0, 32) << 32);
+    uint64_t d1 = ELEM(zd0, 1, 32) | (ELEM(zm0, 1, 32) << 32);
+    uint64_t m0 = ELEM(zd1, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+    uint64_t m1 = ELEM(zd1, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zm, 0, 8) << 8)
+        | (ELEM(zd, 1, 8) << 16) | (ELEM(zm, 1, 8) << 24)
+        | (ELEM(zd, 2, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+        | (ELEM(zd, 3, 8) << 48) | (ELEM(zm, 3, 8) << 56);
+    uint64_t m0 = ELEM(zd, 4, 8) | (ELEM(zm, 4, 8) << 8)
+        | (ELEM(zd, 5, 8) << 16) | (ELEM(zm, 5, 8) << 24)
+        | (ELEM(zd, 6, 8) << 32) | (ELEM(zm, 6, 8) << 40)
+        | (ELEM(zd, 7, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_zip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zm, 0, 16) << 16)
+        | (ELEM(zd, 1, 16) << 32) | (ELEM(zm, 1, 16) << 48);
+    uint64_t m0 = ELEM(zd, 2, 16) | (ELEM(zm, 2, 16) << 16)
+        | (ELEM(zd, 3, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
 }
index c02c92adfa2ba8b3b853ee3a38eafe62f274ff54..ca4a1893c3fc366d93f2ccd6c447a735a06d6a41 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 CodeSourcery.
  * Written by Paul Brook
  *
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
  */
 
 #ifdef ARITH_GE
index 3de261034888326f1f0700a7c1d70ec76f667c83..1892b35ecc2db3fc09a8ea5baac2355013c44567 100644 (file)
  * 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 "exec.h"
-#include "helpers.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
 
-void raise_exception(int tt)
+#if !defined(CONFIG_USER_ONLY)
+static void raise_exception(int tt)
 {
     env->exception_index = tt;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
+#endif
 
 uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
                           uint32_t rn, uint32_t maxindex)
@@ -52,6 +55,8 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
 
 #if !defined(CONFIG_USER_ONLY)
 
+#include "softmmu_exec.h"
+
 #define MMUSUFFIX _mmu
 
 #define SHIFT 0
@@ -70,18 +75,17 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
@@ -90,7 +94,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);
@@ -234,13 +238,13 @@ void HELPER(wfi)(void)
 {
     env->exception_index = EXCP_HLT;
     env->halted = 1;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void HELPER(exception)(uint32_t excp)
 {
     env->exception_index = excp;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 uint32_t HELPER(cpsr_read)(void)
index 514954300dcbf5a1d1bd05942a3a1383726b91c9..0f35b60946907bf20fba5e094589e8e7efd697b1 100644 (file)
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #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,28 +128,12 @@ void arm_translate_init(void)
 #endif
 
 #define GEN_HELPER 2
-#include "helpers.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--;
+#include "helper.h"
 }
 
 static inline TCGv load_cpu_offset(int offset)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_ld_i32(tmp, cpu_env, offset);
     return tmp;
 }
@@ -156,7 +143,7 @@ static inline TCGv load_cpu_offset(int offset)
 static inline void store_cpu_offset(TCGv var, int offset)
 {
     tcg_gen_st_i32(var, cpu_env, offset);
-    dead_tmp(var);
+    tcg_temp_free_i32(var);
 }
 
 #define store_cpu_field(var, name) \
@@ -181,7 +168,7 @@ static void load_reg_var(DisasContext *s, TCGv var, int 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();
+    TCGv tmp = tcg_temp_new_i32();
     load_reg_var(s, tmp, reg);
     return tmp;
 }
@@ -195,7 +182,7 @@ static void store_reg(DisasContext *s, int reg, TCGv var)
         s->is_jmp = DISAS_JUMP;
     }
     tcg_gen_mov_i32(cpu_R[reg], var);
-    dead_tmp(var);
+    tcg_temp_free_i32(var);
 }
 
 /* Value extensions.  */
@@ -219,37 +206,37 @@ static inline void gen_set_cpsr(TCGv var, uint32_t mask)
 
 static void gen_exception(int excp)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_movi_i32(tmp, excp);
     gen_helper_exception(tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 static void gen_smul_dual(TCGv a, TCGv b)
 {
-    TCGv tmp1 = new_tmp();
-    TCGv tmp2 = new_tmp();
+    TCGv tmp1 = tcg_temp_new_i32();
+    TCGv tmp2 = tcg_temp_new_i32();
     tcg_gen_ext16s_i32(tmp1, a);
     tcg_gen_ext16s_i32(tmp2, b);
     tcg_gen_mul_i32(tmp1, tmp1, tmp2);
-    dead_tmp(tmp2);
+    tcg_temp_free_i32(tmp2);
     tcg_gen_sari_i32(a, a, 16);
     tcg_gen_sari_i32(b, b, 16);
     tcg_gen_mul_i32(b, b, a);
     tcg_gen_mov_i32(a, tmp1);
-    dead_tmp(tmp1);
+    tcg_temp_free_i32(tmp1);
 }
 
 /* Byteswap each halfword.  */
 static void gen_rev16(TCGv var)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_shri_i32(tmp, var, 8);
     tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
     tcg_gen_shli_i32(var, var, 8);
     tcg_gen_andi_i32(var, var, 0xff00ff00);
     tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* Byteswap low halfword and sign extend.  */
@@ -298,7 +285,7 @@ static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
     TCGv_i64 tmp64 = tcg_temp_new_i64();
 
     tcg_gen_extu_i32_i64(tmp64, b);
-    dead_tmp(b);
+    tcg_temp_free_i32(b);
     tcg_gen_shli_i64(tmp64, tmp64, 32);
     tcg_gen_add_i64(a, tmp64, a);
 
@@ -312,7 +299,7 @@ static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
     TCGv_i64 tmp64 = tcg_temp_new_i64();
 
     tcg_gen_extu_i32_i64(tmp64, b);
-    dead_tmp(b);
+    tcg_temp_free_i32(b);
     tcg_gen_shli_i64(tmp64, tmp64, 32);
     tcg_gen_sub_i64(a, tmp64, a);
 
@@ -329,9 +316,9 @@ static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
     TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_extu_i32_i64(tmp1, a);
-    dead_tmp(a);
+    tcg_temp_free_i32(a);
     tcg_gen_extu_i32_i64(tmp2, b);
-    dead_tmp(b);
+    tcg_temp_free_i32(b);
     tcg_gen_mul_i64(tmp1, tmp1, tmp2);
     tcg_temp_free_i64(tmp2);
     return tmp1;
@@ -343,9 +330,9 @@ static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
     TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_ext_i32_i64(tmp1, a);
-    dead_tmp(a);
+    tcg_temp_free_i32(a);
     tcg_gen_ext_i32_i64(tmp2, b);
-    dead_tmp(b);
+    tcg_temp_free_i32(b);
     tcg_gen_mul_i64(tmp1, tmp1, tmp2);
     tcg_temp_free_i64(tmp2);
     return tmp1;
@@ -354,11 +341,11 @@ static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
 /* Swap low and high halfwords.  */
 static void gen_swap_half(TCGv var)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_shri_i32(tmp, var, 16);
     tcg_gen_shli_i32(var, var, 16);
     tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* Dual 16-bit add.  Result placed in t0 and t1 is marked as dead.
@@ -370,15 +357,15 @@ static void gen_swap_half(TCGv var)
 
 static void gen_add16(TCGv t0, TCGv t1)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_xor_i32(tmp, t0, t1);
     tcg_gen_andi_i32(tmp, tmp, 0x8000);
     tcg_gen_andi_i32(t0, t0, ~0x8000);
     tcg_gen_andi_i32(t1, t1, ~0x8000);
     tcg_gen_add_i32(t0, t0, t1);
     tcg_gen_xor_i32(t0, t0, tmp);
-    dead_tmp(tmp);
-    dead_tmp(t1);
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(t1);
 }
 
 #define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
@@ -386,10 +373,10 @@ static void gen_add16(TCGv t0, TCGv t1)
 /* Set CF to the top bit of var.  */
 static void gen_set_CF_bit31(TCGv var)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_shri_i32(tmp, var, 31);
     gen_set_CF(tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* Set N and Z flags from var.  */
@@ -406,7 +393,7 @@ static void gen_adc(TCGv t0, TCGv t1)
     tcg_gen_add_i32(t0, t0, t1);
     tmp = load_cpu_field(CF);
     tcg_gen_add_i32(t0, t0, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* dest = T0 + T1 + CF. */
@@ -416,7 +403,7 @@ static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
     tcg_gen_add_i32(dest, t0, t1);
     tmp = load_cpu_field(CF);
     tcg_gen_add_i32(dest, dest, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* dest = T0 - T1 + CF - 1.  */
@@ -427,7 +414,7 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
     tmp = load_cpu_field(CF);
     tcg_gen_add_i32(dest, dest, tmp);
     tcg_gen_subi_i32(dest, dest, 1);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* FIXME:  Implement this natively.  */
@@ -435,7 +422,7 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
 
 static void shifter_out_im(TCGv var, int shift)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     if (shift == 0) {
         tcg_gen_andi_i32(tmp, var, 1);
     } else {
@@ -444,7 +431,7 @@ static void shifter_out_im(TCGv var, int shift)
             tcg_gen_andi_i32(tmp, tmp, 1);
     }
     gen_set_CF(tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* Shift by immediate.  Includes special handling for shift == 0.  */
@@ -492,7 +479,7 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
             tcg_gen_shri_i32(var, var, 1);
             tcg_gen_shli_i32(tmp, tmp, 31);
             tcg_gen_or_i32(var, var, tmp);
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
         }
     }
 };
@@ -516,7 +503,7 @@ static inline void gen_arm_shift_reg(TCGv var, int shiftop,
                 tcg_gen_rotr_i32(var, var, shift); break;
         }
     }
-    dead_tmp(shift);
+    tcg_temp_free_i32(shift);
 }
 
 #define PAS_OP(pfx) \
@@ -655,7 +642,7 @@ static void gen_test_cc(int cc, int label)
         inv = gen_new_label();
         tmp = load_cpu_field(CF);
         tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         tmp = load_cpu_field(ZF);
         tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
         gen_set_label(inv);
@@ -663,7 +650,7 @@ static void gen_test_cc(int cc, int label)
     case 9: /* ls: !C || Z */
         tmp = load_cpu_field(CF);
         tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         tmp = load_cpu_field(ZF);
         tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
         break;
@@ -671,43 +658,43 @@ static void gen_test_cc(int cc, int label)
         tmp = load_cpu_field(VF);
         tmp2 = load_cpu_field(NF);
         tcg_gen_xor_i32(tmp, tmp, tmp2);
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(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_temp_free_i32(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);
+        tcg_temp_free_i32(tmp);
         tmp = load_cpu_field(VF);
         tmp2 = load_cpu_field(NF);
         tcg_gen_xor_i32(tmp, tmp, tmp2);
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(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);
+        tcg_temp_free_i32(tmp);
         tmp = load_cpu_field(VF);
         tmp2 = load_cpu_field(NF);
         tcg_gen_xor_i32(tmp, tmp, tmp2);
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(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);
+    tcg_temp_free_i32(tmp);
 }
 
 static const uint8_t table_logic_cc[16] = {
@@ -736,10 +723,10 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
 
     s->is_jmp = DISAS_UPDATE;
     if (s->thumb != (addr & 1)) {
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, addr & 1);
         tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
     }
     tcg_gen_movi_i32(cpu_R[15], addr & ~1);
 }
@@ -766,33 +753,47 @@ 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 = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_qemu_ld8s(tmp, addr, index);
     return tmp;
 }
 static inline TCGv gen_ld8u(TCGv addr, int index)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_qemu_ld8u(tmp, addr, index);
     return tmp;
 }
 static inline TCGv gen_ld16s(TCGv addr, int index)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_qemu_ld16s(tmp, addr, index);
     return tmp;
 }
 static inline TCGv gen_ld16u(TCGv addr, int index)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_qemu_ld16u(tmp, addr, index);
     return tmp;
 }
 static inline TCGv gen_ld32(TCGv addr, int index)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_qemu_ld32u(tmp, addr, index);
     return tmp;
 }
@@ -805,17 +806,17 @@ static inline TCGv_i64 gen_ld64(TCGv addr, int index)
 static inline void gen_st8(TCGv val, TCGv addr, int index)
 {
     tcg_gen_qemu_st8(val, addr, index);
-    dead_tmp(val);
+    tcg_temp_free_i32(val);
 }
 static inline void gen_st16(TCGv val, TCGv addr, int index)
 {
     tcg_gen_qemu_st16(val, addr, index);
-    dead_tmp(val);
+    tcg_temp_free_i32(val);
 }
 static inline void gen_st32(TCGv val, TCGv addr, int index)
 {
     tcg_gen_qemu_st32(val, addr, index);
-    dead_tmp(val);
+    tcg_temp_free_i32(val);
 }
 static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
 {
@@ -859,7 +860,7 @@ static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
             tcg_gen_sub_i32(var, var, offset);
         else
             tcg_gen_add_i32(var, var, offset);
-        dead_tmp(offset);
+        tcg_temp_free_i32(offset);
     }
 }
 
@@ -887,17 +888,33 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
             tcg_gen_sub_i32(var, var, offset);
         else
             tcg_gen_add_i32(var, var, offset);
-        dead_tmp(offset);
+        tcg_temp_free_i32(offset);
+    }
+}
+
+static TCGv_ptr get_fpstatus_ptr(int neon)
+{
+    TCGv_ptr statusptr = tcg_temp_new_ptr();
+    int offset;
+    if (neon) {
+        offset = offsetof(CPUState, vfp.standard_fp_status);
+    } else {
+        offset = offsetof(CPUState, vfp.fp_status);
     }
+    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
+    return statusptr;
 }
 
 #define VFP_OP2(name)                                                 \
 static inline void gen_vfp_##name(int dp)                             \
 {                                                                     \
-    if (dp)                                                           \
-        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \
-    else                                                              \
-        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \
+    TCGv_ptr fpst = get_fpstatus_ptr(0);                              \
+    if (dp) {                                                         \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, fpst);    \
+    } else {                                                          \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, fpst);    \
+    }                                                                 \
+    tcg_temp_free_ptr(fpst);                                          \
 }
 
 VFP_OP2(add)
@@ -907,6 +924,28 @@ VFP_OP2(div)
 
 #undef VFP_OP2
 
+static inline void gen_vfp_F1_mul(int dp)
+{
+    /* Like gen_vfp_mul() but put result in F1 */
+    TCGv_ptr fpst = get_fpstatus_ptr(0);
+    if (dp) {
+        gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
+    } else {
+        gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
+    }
+    tcg_temp_free_ptr(fpst);
+}
+
+static inline void gen_vfp_F1_neg(int dp)
+{
+    /* Like gen_vfp_neg() but put result in F1 */
+    if (dp) {
+        gen_helper_vfp_negd(cpu_F1d, cpu_F0d);
+    } else {
+        gen_helper_vfp_negs(cpu_F1s, cpu_F0s);
+    }
+}
+
 static inline void gen_vfp_abs(int dp)
 {
     if (dp)
@@ -955,63 +994,52 @@ static inline void gen_vfp_F1_ld0(int dp)
         tcg_gen_movi_i32(cpu_F1s, 0);
 }
 
-static inline void gen_vfp_uito(int dp)
-{
-    if (dp)
-        gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env);
-    else
-        gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env);
-}
-
-static inline void gen_vfp_sito(int dp)
-{
-    if (dp)
-        gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env);
-    else
-        gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env);
-}
-
-static inline void gen_vfp_toui(int dp)
-{
-    if (dp)
-        gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env);
-    else
-        gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env);
+#define VFP_GEN_ITOF(name) \
+static inline void gen_vfp_##name(int dp, int neon) \
+{ \
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
+    } \
+    tcg_temp_free_ptr(statusptr); \
 }
 
-static inline void gen_vfp_touiz(int dp)
-{
-    if (dp)
-        gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env);
-    else
-        gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env);
-}
+VFP_GEN_ITOF(uito)
+VFP_GEN_ITOF(sito)
+#undef VFP_GEN_ITOF
 
-static inline void gen_vfp_tosi(int dp)
-{
-    if (dp)
-        gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env);
-    else
-        gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env);
+#define VFP_GEN_FTOI(name) \
+static inline void gen_vfp_##name(int dp, int neon) \
+{ \
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
+    } \
+    tcg_temp_free_ptr(statusptr); \
 }
 
-static inline void gen_vfp_tosiz(int dp)
-{
-    if (dp)
-        gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
-    else
-        gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env);
-}
+VFP_GEN_FTOI(toui)
+VFP_GEN_FTOI(touiz)
+VFP_GEN_FTOI(tosi)
+VFP_GEN_FTOI(tosiz)
+#undef VFP_GEN_FTOI
 
 #define VFP_GEN_FIX(name) \
-static inline void gen_vfp_##name(int dp, int shift) \
+static inline void gen_vfp_##name(int dp, int shift, int neon) \
 { \
     TCGv tmp_shift = tcg_const_i32(shift); \
-    if (dp) \
-        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, cpu_env);\
-    else \
-        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, cpu_env);\
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
+    } \
     tcg_temp_free_i32(tmp_shift); \
+    tcg_temp_free_ptr(statusptr); \
 }
 VFP_GEN_FIX(tosh)
 VFP_GEN_FIX(tosl)
@@ -1065,7 +1093,7 @@ neon_reg_offset (int reg, int n)
 
 static TCGv neon_load_reg(int reg, int pass)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
     return tmp;
 }
@@ -1073,7 +1101,7 @@ static TCGv neon_load_reg(int reg, int pass)
 static void neon_store_reg(int reg, int pass, TCGv var)
 {
     tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
-    dead_tmp(var);
+    tcg_temp_free_i32(var);
 }
 
 static inline void neon_load_reg64(TCGv_i64 var, int reg)
@@ -1129,7 +1157,7 @@ static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
 
 static inline TCGv iwmmxt_load_creg(int reg)
 {
-    TCGv var = new_tmp();
+    TCGv var = tcg_temp_new_i32();
     tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
     return var;
 }
@@ -1137,7 +1165,7 @@ static inline TCGv iwmmxt_load_creg(int reg)
 static inline void iwmmxt_store_creg(int reg, TCGv var)
 {
     tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
-    dead_tmp(var);
+    tcg_temp_free_i32(var);
 }
 
 static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
@@ -1268,7 +1296,7 @@ static void gen_op_iwmmxt_set_cup(void)
 
 static void gen_op_iwmmxt_setpsr_nz(void)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
     store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
 }
@@ -1300,7 +1328,7 @@ static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest)
         if (insn & (1 << 21))
             store_reg(s, rd, tmp);
         else
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
     } else if (insn & (1 << 21)) {
         /* Post indexed */
         tcg_gen_mov_i32(dest, tmp);
@@ -1326,17 +1354,17 @@ static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest)
             tmp = iwmmxt_load_creg(rd);
         }
     } else {
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         iwmmxt_load_reg(cpu_V0, rd);
         tcg_gen_trunc_i64_i32(tmp, cpu_V0);
     }
     tcg_gen_andi_i32(tmp, tmp, mask);
     tcg_gen_mov_i32(dest, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
     return 0;
 }
 
-/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occured
+/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
    (ie. an undefined instruction).  */
 static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
 {
@@ -1364,14 +1392,14 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         }
 
         wrd = (insn >> 12) & 0xf;
-        addr = new_tmp();
+        addr = tcg_temp_new_i32();
         if (gen_iwmmxt_address(s, insn, addr)) {
-            dead_tmp(addr);
+            tcg_temp_free_i32(addr);
             return 1;
         }
         if (insn & ARM_CP_RW_BIT) {
             if ((insn >> 28) == 0xf) {                 /* WLDRW wCx */
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
                 iwmmxt_store_creg(wrd, tmp);
             } else {
@@ -1392,7 +1420,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
                 }
                 if (i) {
                     tcg_gen_extu_i32_i64(cpu_M0, tmp);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                 }
                 gen_op_iwmmxt_movq_wRn_M0(wrd);
             }
@@ -1402,10 +1430,10 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
                 gen_st32(tmp, addr, IS_USER(s));
             } else {
                 gen_op_iwmmxt_movq_M0_wRn(wrd);
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 if (insn & (1 << 8)) {
                     if (insn & (1 << 22)) {            /* WSTRD */
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp);
                         tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
                     } else {                           /* WSTRW wRd */
                         tcg_gen_trunc_i64_i32(tmp, cpu_M0);
@@ -1422,7 +1450,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
                 }
             }
         }
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         return 0;
     }
 
@@ -1457,7 +1485,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             tmp = iwmmxt_load_creg(wrd);
             tmp2 = load_reg(s, rd);
             tcg_gen_andc_i32(tmp, tmp, tmp2);
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             iwmmxt_store_creg(wrd, tmp);
             break;
         case ARM_IWMMXT_wCGR0:
@@ -1670,7 +1698,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         tcg_gen_andi_i32(tmp, tmp, 7);
         iwmmxt_load_reg(cpu_V1, rd1);
         gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         break;
@@ -1701,7 +1729,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
         tcg_temp_free(tmp3);
         tcg_temp_free(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         break;
@@ -1711,7 +1739,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         if (rd == 15 || ((insn >> 22) & 3) == 3)
             return 1;
         gen_op_iwmmxt_movq_M0_wRn(wrd);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         switch ((insn >> 22) & 3) {
         case 0:
             tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
@@ -1755,7 +1783,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         }
         tcg_gen_shli_i32(tmp, tmp, 28);
         gen_set_nzcv(tmp);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         break;
     case 0x401: case 0x405: case 0x409: case 0x40d:    /* TBCST */
         if (((insn >> 6) & 3) == 3)
@@ -1774,7 +1802,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
             break;
         }
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         break;
@@ -1782,7 +1810,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
             return 1;
         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
-        tmp2 = new_tmp();
+        tmp2 = tcg_temp_new_i32();
         tcg_gen_mov_i32(tmp2, tmp);
         switch ((insn >> 22) & 3) {
         case 0:
@@ -1803,8 +1831,8 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             break;
         }
         gen_set_nzcv(tmp);
-        dead_tmp(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
         break;
     case 0x01c: case 0x41c: case 0x81c: case 0xc1c:    /* WACC */
         wrd = (insn >> 12) & 0xf;
@@ -1830,7 +1858,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
             return 1;
         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
-        tmp2 = new_tmp();
+        tmp2 = tcg_temp_new_i32();
         tcg_gen_mov_i32(tmp2, tmp);
         switch ((insn >> 22) & 3) {
         case 0:
@@ -1851,8 +1879,8 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             break;
         }
         gen_set_nzcv(tmp);
-        dead_tmp(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
         break;
     case 0x103: case 0x503: case 0x903: case 0xd03:    /* TMOVMSK */
         rd = (insn >> 12) & 0xf;
@@ -1860,7 +1888,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
             return 1;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         switch ((insn >> 22) & 3) {
         case 0:
             gen_helper_iwmmxt_msbb(tmp, cpu_M0);
@@ -1975,9 +2003,9 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         wrd = (insn >> 12) & 0xf;
         rd0 = (insn >> 16) & 0xf;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             return 1;
         }
         switch ((insn >> 22) & 3) {
@@ -1991,7 +2019,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         }
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         gen_op_iwmmxt_set_cup();
@@ -2003,9 +2031,9 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         wrd = (insn >> 12) & 0xf;
         rd0 = (insn >> 16) & 0xf;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             return 1;
         }
         switch ((insn >> 22) & 3) {
@@ -2019,7 +2047,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         }
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         gen_op_iwmmxt_set_cup();
@@ -2031,9 +2059,9 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         wrd = (insn >> 12) & 0xf;
         rd0 = (insn >> 16) & 0xf;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             return 1;
         }
         switch ((insn >> 22) & 3) {
@@ -2047,7 +2075,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         }
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         gen_op_iwmmxt_set_cup();
@@ -2059,31 +2087,31 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         wrd = (insn >> 12) & 0xf;
         rd0 = (insn >> 16) & 0xf;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         switch ((insn >> 22) & 3) {
         case 1:
             if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
                 return 1;
             }
             gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         case 2:
             if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
                 return 1;
             }
             gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         case 3:
             if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
                 return 1;
             }
             gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
             break;
         }
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         gen_op_iwmmxt_set_cup();
@@ -2324,12 +2352,12 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
             gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
             break;
         default:
-            dead_tmp(tmp2);
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp2);
+            tcg_temp_free_i32(tmp);
             return 1;
         }
-        dead_tmp(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
         break;
@@ -2340,7 +2368,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
     return 0;
 }
 
-/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occured
+/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
    (ie. an undefined instruction).  */
 static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
 {
@@ -2378,8 +2406,8 @@ static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
         default:
             return 1;
         }
-        dead_tmp(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
 
         gen_op_iwmmxt_movq_wRn_M0(acc);
         return 0;
@@ -2425,7 +2453,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
         if (!env->cp[cp].cp_read)
             return 1;
         gen_set_pc_im(s->pc);
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         tmp2 = tcg_const_i32(insn);
         gen_helper_get_cp(tmp, cpu_env, tmp2);
         tcg_temp_free(tmp2);
@@ -2438,28 +2466,38 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
         tmp2 = tcg_const_i32(insn);
         gen_helper_set_cp(cpu_env, tmp2, tmp);
         tcg_temp_free(tmp2);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
     }
     return 0;
 }
 
-static int cp15_user_ok(uint32_t insn)
+static int cp15_user_ok(CPUState *env, uint32_t insn)
 {
     int cpn = (insn >> 16) & 0xf;
     int cpm = insn & 0xf;
     int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
 
+    if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) {
+        /* Performance monitor registers fall into three categories:
+         *  (a) always UNDEF in usermode
+         *  (b) UNDEF only if PMUSERENR.EN is 0
+         *  (c) always read OK and UNDEF on write (PMUSERENR only)
+         */
+        if ((cpm == 12 && (op < 6)) ||
+            (cpm == 13 && (op < 3))) {
+            return env->cp15.c9_pmuserenr;
+        } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) {
+            /* PMUSERENR, read only */
+            return 1;
+        }
+        return 0;
+    }
+
     if (cpn == 13 && cpm == 0) {
         /* TLS register.  */
         if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
             return 1;
     }
-    if (cpn == 7) {
-        /* ISB, DSB, DMB.  */
-        if ((cpm == 5 && op == 4)
-                || (cpm == 10 && (op == 4 || op == 5)))
-            return 1;
-    }
     return 0;
 }
 
@@ -2505,7 +2543,7 @@ static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, ui
             store_cpu_field(tmp, cp15.c13_tls3);
             break;
         default:
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             return 0;
         }
     }
@@ -2535,16 +2573,62 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
         /* cdp */
         return 1;
     }
-    if (IS_USER(s) && !cp15_user_ok(insn)) {
-        return 1;
-    }
-    if ((insn & 0x0fff0fff) == 0x0e070f90
-        || (insn & 0x0fff0fff) == 0x0e070f58) {
-        /* Wait for interrupt.  */
-        gen_set_pc_im(s->pc);
-        s->is_jmp = DISAS_WFI;
+    /* We special case a number of cp15 instructions which were used
+     * for things which are real instructions in ARMv7. This allows
+     * them to work in linux-user mode which doesn't provide functional
+     * get_cp15/set_cp15 helpers, and is more efficient anyway.
+     */
+    switch ((insn & 0x0fff0fff)) {
+    case 0x0e070f90:
+        /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
+         * In v7, this must NOP.
+         */
+        if (IS_USER(s)) {
+            return 1;
+        }
+        if (!arm_feature(env, ARM_FEATURE_V7)) {
+            /* Wait for interrupt.  */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_WFI;
+        }
         return 0;
+    case 0x0e070f58:
+        /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
+         * so this is slightly over-broad.
+         */
+        if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
+            /* Wait for interrupt.  */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_WFI;
+            return 0;
+        }
+        /* Otherwise continue to handle via helper function.
+         * In particular, on v7 and some v6 cores this is one of
+         * the VA-PA registers.
+         */
+        break;
+    case 0x0e070f3d:
+        /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return IS_USER(s) ? 1 : 0;
+        }
+        break;
+    case 0x0e070f95: /* 0,c7,c5,4 : ISB */
+    case 0x0e070f9a: /* 0,c7,c10,4: DSB */
+    case 0x0e070fba: /* 0,c7,c10,5: DMB */
+        /* Barriers in both v6 and v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return 0;
+        }
+        break;
+    default:
+        break;
     }
+
+    if (IS_USER(s) && !cp15_user_ok(env, insn)) {
+        return 1;
+    }
+
     rd = (insn >> 12) & 0xf;
 
     if (cp15_tls_load_store(env, s, insn, rd))
@@ -2552,17 +2636,17 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
 
     tmp2 = tcg_const_i32(insn);
     if (insn & ARM_CP_RW_BIT) {
-        tmp = new_tmp();
+        tmp = tcg_temp_new_i32();
         gen_helper_get_cp15(tmp, cpu_env, tmp2);
         /* If the destination register is r15 then sets condition codes.  */
         if (rd != 15)
             store_reg(s, rd, tmp);
         else
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
     } else {
         tmp = load_reg(s, rd);
         gen_helper_set_cp15(cpu_env, tmp2, tmp);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
         /* Normally we would always end the TB here, but Linux
          * arch/arm/mach-pxa/sleep.S expects two instructions following
          * an MMU enable to execute from cache.  Imitate this behaviour.  */
@@ -2597,7 +2681,7 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
 /* Move between integer and VFP cores.  */
 static TCGv gen_vfp_mrs(void)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_mov_i32(tmp, cpu_F0s);
     return tmp;
 }
@@ -2605,12 +2689,12 @@ static TCGv gen_vfp_mrs(void)
 static void gen_vfp_msr(TCGv tmp)
 {
     tcg_gen_mov_i32(cpu_F0s, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 static void gen_neon_dup_u8(TCGv var, int shift)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     if (shift)
         tcg_gen_shri_i32(var, var, shift);
     tcg_gen_ext8u_i32(var, var);
@@ -2618,28 +2702,50 @@ static void gen_neon_dup_u8(TCGv var, int shift)
     tcg_gen_or_i32(var, var, tmp);
     tcg_gen_shli_i32(tmp, var, 16);
     tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 static void gen_neon_dup_low16(TCGv var)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_ext16u_i32(var, var);
     tcg_gen_shli_i32(tmp, var, 16);
     tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 static void gen_neon_dup_high16(TCGv var)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_andi_i32(var, var, 0xffff0000);
     tcg_gen_shri_i32(tmp, var, 16);
     tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    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
+/* Disassemble a VFP instruction.  Returns nonzero if an error occurred
    (ie. an undefined instruction).  */
 static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
 {
@@ -2731,7 +2837,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             gen_neon_dup_low16(tmp);
                         }
                         for (n = 0; n <= pass * 2; n++) {
-                            tmp2 = new_tmp();
+                            tmp2 = tcg_temp_new_i32();
                             tcg_gen_mov_i32(tmp2, tmp);
                             neon_store_reg(rn, n, tmp2);
                         }
@@ -2742,12 +2848,12 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         case 0:
                             tmp2 = neon_load_reg(rn, pass);
                             gen_bfi(tmp, tmp2, tmp, offset, 0xff);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                             break;
                         case 1:
                             tmp2 = neon_load_reg(rn, pass);
                             gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                             break;
                         case 2:
                             break;
@@ -2793,7 +2899,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
                                 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
                             } else {
-                                tmp = new_tmp();
+                                tmp = tcg_temp_new_i32();
                                 gen_helper_vfp_get_fpscr(tmp, cpu_env);
                             }
                             break;
@@ -2814,7 +2920,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     if (rd == 15) {
                         /* Set the 4 flag bits in the CPSR.  */
                         gen_set_nzcv(tmp);
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp);
                     } else {
                         store_reg(s, rd, tmp);
                     }
@@ -2832,7 +2938,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             break;
                         case ARM_VFP_FPSCR:
                             gen_helper_vfp_set_fpscr(cpu_env, tmp);
-                            dead_tmp(tmp);
+                            tcg_temp_free_i32(tmp);
                             gen_lookup_tb(s);
                             break;
                         case ARM_VFP_FPEXC:
@@ -2965,6 +3071,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     /* Source and destination the same.  */
                     gen_mov_F0_vreg(dp, rd);
                     break;
+                case 4:
+                case 5:
+                case 6:
+                case 7:
+                    /* VCVTB, VCVTT: only present with the halfprec extension,
+                     * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
+                     */
+                    if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
+                        return 1;
+                    }
+                    /* Otherwise fall through */
                 default:
                     /* One source operand.  */
                     gen_mov_F0_vreg(dp, rm);
@@ -2979,27 +3096,34 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
             for (;;) {
                 /* Perform the calculation.  */
                 switch (op) {
-                case 0: /* mac: fd + (fn * fm) */
-                    gen_vfp_mul(dp);
-                    gen_mov_F1_vreg(dp, rd);
+                case 0: /* VMLA: fd + (fn * fm) */
+                    /* Note that order of inputs to the add matters for NaNs */
+                    gen_vfp_F1_mul(dp);
+                    gen_mov_F0_vreg(dp, rd);
                     gen_vfp_add(dp);
                     break;
-                case 1: /* nmac: fd - (fn * fm) */
+                case 1: /* VMLS: fd + -(fn * fm) */
                     gen_vfp_mul(dp);
-                    gen_vfp_neg(dp);
-                    gen_mov_F1_vreg(dp, rd);
+                    gen_vfp_F1_neg(dp);
+                    gen_mov_F0_vreg(dp, rd);
                     gen_vfp_add(dp);
                     break;
-                case 2: /* msc: -fd + (fn * fm) */
-                    gen_vfp_mul(dp);
-                    gen_mov_F1_vreg(dp, rd);
-                    gen_vfp_sub(dp);
+                case 2: /* VNMLS: -fd + (fn * fm) */
+                    /* Note that it isn't valid to replace (-A + B) with (B - A)
+                     * or similar plausible looking simplifications
+                     * because this will give wrong results for NaNs.
+                     */
+                    gen_vfp_F1_mul(dp);
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_neg(dp);
+                    gen_vfp_add(dp);
                     break;
-                case 3: /* nmsc: -fd - (fn * fm)  */
+                case 3: /* VNMLA: -fd + -(fn * fm) */
                     gen_vfp_mul(dp);
+                    gen_vfp_F1_neg(dp);
+                    gen_mov_F0_vreg(dp, rd);
                     gen_vfp_neg(dp);
-                    gen_mov_F1_vreg(dp, rd);
-                    gen_vfp_sub(dp);
+                    gen_vfp_add(dp);
                     break;
                 case 4: /* mul: fn * fm */
                     gen_vfp_mul(dp);
@@ -3017,6 +3141,57 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 case 8: /* div: fn / fm */
                     gen_vfp_div(dp);
                     break;
+                case 10: /* VFNMA : fd = muladd(-fd,  fn, fm) */
+                case 11: /* VFNMS : fd = muladd(-fd, -fn, fm) */
+                case 12: /* VFMA  : fd = muladd( fd,  fn, fm) */
+                case 13: /* VFMS  : fd = muladd( fd, -fn, fm) */
+                    /* These are fused multiply-add, and must be done as one
+                     * floating point operation with no rounding between the
+                     * multiplication and addition steps.
+                     * NB that doing the negations here as separate steps is
+                     * correct : an input NaN should come out with its sign bit
+                     * flipped if it is a negated-input.
+                     */
+                    if (!arm_feature(env, ARM_FEATURE_VFP4)) {
+                        return 1;
+                    }
+                    if (dp) {
+                        TCGv_ptr fpst;
+                        TCGv_i64 frd;
+                        if (op & 1) {
+                            /* VFNMS, VFMS */
+                            gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
+                        }
+                        frd = tcg_temp_new_i64();
+                        tcg_gen_ld_f64(frd, cpu_env, vfp_reg_offset(dp, rd));
+                        if (op & 2) {
+                            /* VFNMA, VFNMS */
+                            gen_helper_vfp_negd(frd, frd);
+                        }
+                        fpst = get_fpstatus_ptr(0);
+                        gen_helper_vfp_muladdd(cpu_F0d, cpu_F0d,
+                                               cpu_F1d, frd, fpst);
+                        tcg_temp_free_ptr(fpst);
+                        tcg_temp_free_i64(frd);
+                    } else {
+                        TCGv_ptr fpst;
+                        TCGv_i32 frd;
+                        if (op & 1) {
+                            /* VFNMS, VFMS */
+                            gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
+                        }
+                        frd = tcg_temp_new_i32();
+                        tcg_gen_ld_f32(frd, cpu_env, vfp_reg_offset(dp, rd));
+                        if (op & 2) {
+                            gen_helper_vfp_negs(frd, frd);
+                        }
+                        fpst = get_fpstatus_ptr(0);
+                        gen_helper_vfp_muladds(cpu_F0s, cpu_F0s,
+                                               cpu_F1s, frd, fpst);
+                        tcg_temp_free_ptr(fpst);
+                        tcg_temp_free_i32(frd);
+                    }
+                    break;
                 case 14: /* fconst */
                     if (!arm_feature(env, ARM_FEATURE_VFP3))
                       return 1;
@@ -3054,44 +3229,36 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_vfp_sqrt(dp);
                         break;
                     case 4: /* vcvtb.f32.f16 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = gen_vfp_mrs();
                         tcg_gen_ext16u_i32(tmp, tmp);
                         gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp);
                         break;
                     case 5: /* vcvtt.f32.f16 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = gen_vfp_mrs();
                         tcg_gen_shri_i32(tmp, tmp, 16);
                         gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp);
                         break;
                     case 6: /* vcvtb.f16.f32 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                         gen_mov_F0_vreg(0, rd);
                         tmp2 = gen_vfp_mrs();
                         tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                         tcg_gen_or_i32(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         gen_vfp_msr(tmp);
                         break;
                     case 7: /* vcvtt.f16.f32 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                         tcg_gen_shli_i32(tmp, tmp, 16);
                         gen_mov_F0_vreg(0, rd);
                         tmp2 = gen_vfp_mrs();
                         tcg_gen_ext16u_i32(tmp2, tmp2);
                         tcg_gen_or_i32(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         gen_vfp_msr(tmp);
                         break;
                     case 8: /* cmp */
@@ -3114,70 +3281,68 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
                         break;
                     case 16: /* fuito */
-                        gen_vfp_uito(dp);
+                        gen_vfp_uito(dp, 0);
                         break;
                     case 17: /* fsito */
-                        gen_vfp_sito(dp);
+                        gen_vfp_sito(dp, 0);
                         break;
                     case 20: /* fshto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_shto(dp, 16 - rm);
+                        gen_vfp_shto(dp, 16 - rm, 0);
                         break;
                     case 21: /* fslto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_slto(dp, 32 - rm);
+                        gen_vfp_slto(dp, 32 - rm, 0);
                         break;
                     case 22: /* fuhto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_uhto(dp, 16 - rm);
+                        gen_vfp_uhto(dp, 16 - rm, 0);
                         break;
                     case 23: /* fulto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_ulto(dp, 32 - rm);
+                        gen_vfp_ulto(dp, 32 - rm, 0);
                         break;
                     case 24: /* ftoui */
-                        gen_vfp_toui(dp);
+                        gen_vfp_toui(dp, 0);
                         break;
                     case 25: /* ftouiz */
-                        gen_vfp_touiz(dp);
+                        gen_vfp_touiz(dp, 0);
                         break;
                     case 26: /* ftosi */
-                        gen_vfp_tosi(dp);
+                        gen_vfp_tosi(dp, 0);
                         break;
                     case 27: /* ftosiz */
-                        gen_vfp_tosiz(dp);
+                        gen_vfp_tosiz(dp, 0);
                         break;
                     case 28: /* ftosh */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_tosh(dp, 16 - rm);
+                        gen_vfp_tosh(dp, 16 - rm, 0);
                         break;
                     case 29: /* ftosl */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_tosl(dp, 32 - rm);
+                        gen_vfp_tosl(dp, 32 - rm, 0);
                         break;
                     case 30: /* ftouh */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_touh(dp, 16 - rm);
+                        gen_vfp_touh(dp, 16 - rm, 0);
                         break;
                     case 31: /* ftoul */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_toul(dp, 32 - rm);
+                        gen_vfp_toul(dp, 32 - rm, 0);
                         break;
                     default: /* undefined */
-                        printf ("rn:%d\n", rn);
                         return 1;
                     }
                     break;
                 default: /* undefined */
-                    printf ("op:%d\n", op);
                     return 1;
                 }
 
@@ -3232,7 +3397,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
         break;
     case 0xc:
     case 0xd:
-        if (dp && (insn & 0x03e00000) == 0x00400000) {
+        if ((insn & 0x03e00000) == 0x00400000) {
             /* two-register transfer */
             rn = (insn >> 16) & 0xf;
             rd = (insn >> 12) & 0xf;
@@ -3254,10 +3419,10 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 } else {
                     gen_mov_F0_vreg(0, rm);
                     tmp = gen_vfp_mrs();
-                    store_reg(s, rn, tmp);
+                    store_reg(s, rd, tmp);
                     gen_mov_F0_vreg(0, rm + 1);
                     tmp = gen_vfp_mrs();
-                    store_reg(s, rd, tmp);
+                    store_reg(s, rn, tmp);
                 }
             } else {
                 /* arm->vfp */
@@ -3269,10 +3434,10 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     gen_vfp_msr(tmp);
                     gen_mov_vreg_F0(0, rm * 2 + 1);
                 } else {
-                    tmp = load_reg(s, rn);
+                    tmp = load_reg(s, rd);
                     gen_vfp_msr(tmp);
                     gen_mov_vreg_F0(0, rm);
-                    tmp = load_reg(s, rd);
+                    tmp = load_reg(s, rn);
                     gen_vfp_msr(tmp);
                     gen_mov_vreg_F0(0, rm + 1);
                 }
@@ -3284,17 +3449,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 VFP_DREG_D(rd, insn);
             else
                 rd = VFP_SREG_D(insn);
-            if (s->thumb && rn == 15) {
-                addr = new_tmp();
-                tcg_gen_movi_i32(addr, s->pc & ~2);
-            } else {
-                addr = load_reg(s, rn);
-            }
             if ((insn & 0x01200000) == 0x01000000) {
                 /* Single load/store */
                 offset = (insn & 0xff) << 2;
                 if ((insn & (1 << 23)) == 0)
                     offset = -offset;
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
                 tcg_gen_addi_i32(addr, addr, offset);
                 if (insn & (1 << 20)) {
                     gen_vfp_ld(s, dp, addr);
@@ -3303,14 +3469,37 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     gen_mov_F0_vreg(dp, rd);
                     gen_vfp_st(s, dp, addr);
                 }
-                dead_tmp(addr);
+                tcg_temp_free_i32(addr);
             } else {
                 /* load/store multiple */
+                int w = insn & (1 << 21);
                 if (dp)
                     n = (insn >> 1) & 0x7f;
                 else
                     n = insn & 0xff;
 
+                if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
+                    /* P == U , W == 1  => UNDEF */
+                    return 1;
+                }
+                if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
+                    /* UNPREDICTABLE cases for bad immediates: we choose to
+                     * UNDEF to avoid generating huge numbers of TCG ops
+                     */
+                    return 1;
+                }
+                if (rn == 15 && w) {
+                    /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
+                    return 1;
+                }
+
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
                 if (insn & (1 << 24)) /* pre-decrement */
                     tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
 
@@ -3330,7 +3519,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     }
                     tcg_gen_addi_i32(addr, addr, offset);
                 }
-                if (insn & (1 << 21)) {
+                if (w) {
                     /* writeback */
                     if (insn & (1 << 24))
                         offset = -offset * n;
@@ -3343,7 +3532,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         tcg_gen_addi_i32(addr, addr, offset);
                     store_reg(s, rn, addr);
                 } else {
-                    dead_tmp(addr);
+                    tcg_temp_free_i32(addr);
                 }
             }
         }
@@ -3363,7 +3552,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);
@@ -3412,6 +3601,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))
@@ -3442,7 +3635,7 @@ static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
     } else {
         gen_set_cpsr(t0, mask);
     }
-    dead_tmp(t0);
+    tcg_temp_free_i32(t0);
     gen_lookup_tb(s);
     return 0;
 }
@@ -3451,7 +3644,7 @@ static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
 static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
 {
     TCGv tmp;
-    tmp = new_tmp();
+    tmp = tcg_temp_new_i32();
     tcg_gen_movi_i32(tmp, val);
     return gen_set_psr(s, mask, spsr, tmp);
 }
@@ -3463,7 +3656,7 @@ static void gen_exception_return(DisasContext *s, TCGv pc)
     store_reg(s, 15, pc);
     tmp = load_cpu_field(spsr);
     gen_set_cpsr(tmp, 0xffffffff);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
     s->is_jmp = DISAS_UPDATE;
 }
 
@@ -3471,7 +3664,7 @@ static void gen_exception_return(DisasContext *s, TCGv pc)
 static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
 {
     gen_set_cpsr(cpsr, 0xffffffff);
-    dead_tmp(cpsr);
+    tcg_temp_free_i32(cpsr);
     store_reg(s, 15, pc);
     s->is_jmp = DISAS_UPDATE;
 }
@@ -3481,7 +3674,7 @@ gen_set_condexec (DisasContext *s)
 {
     if (s->condexec_mask) {
         uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
-        TCGv tmp = new_tmp();
+        TCGv tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, val);
         store_cpu_field(tmp, condexec_bits);
     }
@@ -3512,15 +3705,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)
@@ -3587,7 +3779,7 @@ static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
 
 static TCGv neon_load_scratch(int scratch)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
     return tmp;
 }
@@ -3595,7 +3787,7 @@ static TCGv neon_load_scratch(int scratch)
 static void neon_store_scratch(int scratch, TCGv var)
 {
     tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
-    dead_tmp(var);
+    tcg_temp_free_i32(var);
 }
 
 static inline TCGv neon_get_scalar(int size, int reg)
@@ -3614,144 +3806,112 @@ static inline TCGv neon_get_scalar(int size, int reg)
     return tmp;
 }
 
-static void gen_neon_unzip_u8(TCGv t0, TCGv t1)
-{
-    TCGv rd, rm, tmp;
-
-    rd = new_tmp();
-    rm = new_tmp();
-    tmp = new_tmp();
-
-    tcg_gen_andi_i32(rd, t0, 0xff);
-    tcg_gen_shri_i32(tmp, t0, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff00);
-    tcg_gen_or_i32(rd, rd, tmp);
-    tcg_gen_shli_i32(tmp, t1, 16);
-    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
-    tcg_gen_or_i32(rd, rd, tmp);
-    tcg_gen_shli_i32(tmp, t1, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff000000);
-    tcg_gen_or_i32(rd, rd, tmp);
-
-    tcg_gen_shri_i32(rm, t0, 8);
-    tcg_gen_andi_i32(rm, rm, 0xff);
-    tcg_gen_shri_i32(tmp, t0, 16);
-    tcg_gen_andi_i32(tmp, tmp, 0xff00);
-    tcg_gen_or_i32(rm, rm, tmp);
-    tcg_gen_shli_i32(tmp, t1, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
-    tcg_gen_or_i32(rm, rm, tmp);
-    tcg_gen_andi_i32(tmp, t1, 0xff000000);
-    tcg_gen_or_i32(t1, rm, tmp);
-    tcg_gen_mov_i32(t0, rd);
-
-    dead_tmp(tmp);
-    dead_tmp(rm);
-    dead_tmp(rd);
-}
-
-static void gen_neon_zip_u8(TCGv t0, TCGv t1)
-{
-    TCGv rd, rm, tmp;
-
-    rd = new_tmp();
-    rm = new_tmp();
-    tmp = new_tmp();
-
-    tcg_gen_andi_i32(rd, t0, 0xff);
-    tcg_gen_shli_i32(tmp, t1, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff00);
-    tcg_gen_or_i32(rd, rd, tmp);
-    tcg_gen_shli_i32(tmp, t0, 16);
-    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
-    tcg_gen_or_i32(rd, rd, tmp);
-    tcg_gen_shli_i32(tmp, t1, 24);
-    tcg_gen_andi_i32(tmp, tmp, 0xff000000);
-    tcg_gen_or_i32(rd, rd, tmp);
-
-    tcg_gen_andi_i32(rm, t1, 0xff000000);
-    tcg_gen_shri_i32(tmp, t0, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
-    tcg_gen_or_i32(rm, rm, tmp);
-    tcg_gen_shri_i32(tmp, t1, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0xff00);
-    tcg_gen_or_i32(rm, rm, tmp);
-    tcg_gen_shri_i32(tmp, t0, 16);
-    tcg_gen_andi_i32(tmp, tmp, 0xff);
-    tcg_gen_or_i32(t1, rm, tmp);
-    tcg_gen_mov_i32(t0, rd);
-
-    dead_tmp(tmp);
-    dead_tmp(rm);
-    dead_tmp(rd);
-}
-
-static void gen_neon_zip_u16(TCGv t0, TCGv t1)
+static int gen_neon_unzip(int rd, int rm, int size, int q)
 {
     TCGv tmp, tmp2;
-
-    tmp = new_tmp();
-    tmp2 = new_tmp();
-
-    tcg_gen_andi_i32(tmp, t0, 0xffff);
-    tcg_gen_shli_i32(tmp2, t1, 16);
-    tcg_gen_or_i32(tmp, tmp, tmp2);
-    tcg_gen_andi_i32(t1, t1, 0xffff0000);
-    tcg_gen_shri_i32(tmp2, t0, 16);
-    tcg_gen_or_i32(t1, t1, tmp2);
-    tcg_gen_mov_i32(t0, tmp);
-
-    dead_tmp(tmp2);
-    dead_tmp(tmp);
-}
-
-static void gen_neon_unzip(int reg, int q, int tmp, int size)
-{
-    int n;
-    TCGv t0, t1;
-
-    for (n = 0; n < q + 1; n += 2) {
-        t0 = neon_load_reg(reg, n);
-        t1 = neon_load_reg(reg, n + 1);
+    if (!q && size == 2) {
+        return 1;
+    }
+    tmp = tcg_const_i32(rd);
+    tmp2 = tcg_const_i32(rm);
+    if (q) {
         switch (size) {
-        case 0: gen_neon_unzip_u8(t0, t1); break;
-        case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same.  */
-        case 2: /* no-op */; break;
-        default: abort();
+        case 0:
+            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
+            break;
+        case 2:
+            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    } else {
+        switch (size) {
+        case 0:
+            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
         }
-        neon_store_scratch(tmp + n, t0);
-        neon_store_scratch(tmp + n + 1, t1);
     }
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(tmp2);
+    return 0;
 }
 
-static void gen_neon_trn_u8(TCGv t0, TCGv t1)
+static int gen_neon_zip(int rd, int rm, int size, int q)
 {
-    TCGv rd, tmp;
-
-    rd = new_tmp();
-    tmp = new_tmp();
-
-    tcg_gen_shli_i32(rd, t0, 8);
-    tcg_gen_andi_i32(rd, rd, 0xff00ff00);
-    tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
-    tcg_gen_or_i32(rd, rd, tmp);
-
-    tcg_gen_shri_i32(t1, t1, 8);
-    tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
-    tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
+    TCGv tmp, tmp2;
+    if (!q && size == 2) {
+        return 1;
+    }
+    tmp = tcg_const_i32(rd);
+    tmp2 = tcg_const_i32(rm);
+    if (q) {
+        switch (size) {
+        case 0:
+            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
+            break;
+        case 2:
+            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    } else {
+        switch (size) {
+        case 0:
+            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    }
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(tmp2);
+    return 0;
+}
+
+static void gen_neon_trn_u8(TCGv t0, TCGv t1)
+{
+    TCGv rd, tmp;
+
+    rd = tcg_temp_new_i32();
+    tmp = tcg_temp_new_i32();
+
+    tcg_gen_shli_i32(rd, t0, 8);
+    tcg_gen_andi_i32(rd, rd, 0xff00ff00);
+    tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
+    tcg_gen_or_i32(rd, rd, tmp);
+
+    tcg_gen_shri_i32(t1, t1, 8);
+    tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
+    tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
     tcg_gen_or_i32(t1, t1, tmp);
     tcg_gen_mov_i32(t0, rd);
 
-    dead_tmp(tmp);
-    dead_tmp(rd);
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(rd);
 }
 
 static void gen_neon_trn_u16(TCGv t0, TCGv t1)
 {
     TCGv rd, tmp;
 
-    rd = new_tmp();
-    tmp = new_tmp();
+    rd = tcg_temp_new_i32();
+    tmp = tcg_temp_new_i32();
 
     tcg_gen_shli_i32(rd, t0, 16);
     tcg_gen_andi_i32(tmp, t1, 0xffff);
@@ -3761,8 +3921,8 @@ static void gen_neon_trn_u16(TCGv t0, TCGv t1)
     tcg_gen_or_i32(t1, t1, tmp);
     tcg_gen_mov_i32(t0, rd);
 
-    dead_tmp(tmp);
-    dead_tmp(rd);
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(rd);
 }
 
 
@@ -3811,18 +3971,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 = new_tmp();
     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++) {
@@ -3863,11 +4038,11 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             tcg_gen_addi_i32(addr, addr, stride);
                             tcg_gen_shli_i32(tmp2, tmp2, 16);
                             tcg_gen_or_i32(tmp, tmp, tmp2);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                             neon_store_reg(rd, pass, tmp);
                         } else {
                             tmp = neon_load_reg(rd, pass);
-                            tmp2 = new_tmp();
+                            tmp2 = tcg_temp_new_i32();
                             tcg_gen_shri_i32(tmp2, tmp, 16);
                             gen_st16(tmp, addr, IS_USER(s));
                             tcg_gen_addi_i32(addr, addr, stride);
@@ -3885,14 +4060,14 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 } else {
                                     tcg_gen_shli_i32(tmp, tmp, n * 8);
                                     tcg_gen_or_i32(tmp2, tmp2, tmp);
-                                    dead_tmp(tmp);
+                                    tcg_temp_free_i32(tmp);
                                 }
                             }
                             neon_store_reg(rd, pass, tmp2);
                         } else {
                             tmp2 = neon_load_reg(rd, pass);
                             for (n = 0; n < 4; n++) {
-                                tmp = new_tmp();
+                                tmp = tcg_temp_new_i32();
                                 if (n == 0) {
                                     tcg_gen_mov_i32(tmp, tmp2);
                                 } else {
@@ -3901,52 +4076,68 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 gen_st8(tmp, addr, IS_USER(s));
                                 tcg_gen_addi_i32(addr, addr, stride);
                             }
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                     }
                 }
             }
             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 = new_tmp();
-                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:
@@ -3965,6 +4156,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) {
@@ -3984,7 +4209,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     if (size != 2) {
                         tmp2 = neon_load_reg(rd, pass);
                         gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                     }
                     neon_store_reg(rd, pass, tmp);
                 } else { /* Store */
@@ -4006,10 +4231,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);
         }
     }
-    dead_tmp(addr);
     if (rm != 15) {
         TCGv base;
 
@@ -4020,7 +4245,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
             TCGv index;
             index = load_reg(s, rm);
             tcg_gen_add_i32(base, base, index);
-            dead_tmp(index);
+            tcg_temp_free_i32(index);
         }
         store_reg(s, rn, base);
     }
@@ -4065,6 +4290,16 @@ 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;
+    default: abort();
+    }
+}
+
 static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
                                          int q, int u)
 {
@@ -4085,8 +4320,8 @@ static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
     } else {
         if (u) {
             switch (size) {
-            case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
-            case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
+            case 1: gen_helper_neon_shl_u16(var, var, shift); break;
+            case 2: gen_helper_neon_shl_u32(var, var, shift); break;
             default: abort();
             }
         } else {
@@ -4116,7 +4351,7 @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
         default: abort();
         }
     }
-    dead_tmp(src);
+    tcg_temp_free_i32(src);
 }
 
 static inline void gen_neon_addl(int size)
@@ -4170,10 +4405,12 @@ static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
     case 4:
         tmp = gen_muls_i64_i32(a, b);
         tcg_gen_mov_i64(dest, tmp);
+        tcg_temp_free_i64(tmp);
         break;
     case 5:
         tmp = gen_mulu_i64_i32(a, b);
         tcg_gen_mov_i64(dest, tmp);
+        tcg_temp_free_i64(tmp);
         break;
     default: abort();
     }
@@ -4181,11 +4418,205 @@ static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
     /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
        Don't forget to clean them now.  */
     if (size < 2) {
-      dead_tmp(a);
-      dead_tmp(b);
+        tcg_temp_free_i32(a);
+        tcg_temp_free_i32(b);
+    }
+}
+
+static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
+{
+    if (op) {
+        if (u) {
+            gen_neon_unarrow_sats(size, dest, src);
+        } else {
+            gen_neon_narrow(size, dest, src);
+        }
+    } else {
+        if (u) {
+            gen_neon_narrow_satu(size, dest, src);
+        } else {
+            gen_neon_narrow_sats(size, dest, 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_VFM 25 /* VFMA, VFMS : float fused multiply-add */
+#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_VFM] = 0x5, /* size bit 1 encodes op */
+    [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.
@@ -4202,7 +4633,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;
@@ -4218,14 +4648,23 @@ 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);
@@ -4234,7 +4673,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                                  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);
@@ -4243,14 +4682,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                                  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);
@@ -4259,14 +4698,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                                  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);
@@ -4275,7 +4714,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                                   cpu_V1, cpu_V0);
                     }
                     break;
-                case 16:
+                case NEON_3R_VADD_VSUB:
                     if (u) {
                         tcg_gen_sub_i64(CPU_V001);
                     } else {
@@ -4289,50 +4728,81 @@ 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 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 30: /* VPMIN/VPMAX (float) */
-            pairwise = u;
+        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;
+        case NEON_3R_VFM:
+            if (!arm_feature(env, ARM_FEATURE_VFP4) || u) {
+                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.  */
@@ -4340,16 +4810,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 */
+        case NEON_3R_VQADD:
             GEN_NEON_INTEGER_OP_ENV(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);
@@ -4369,97 +4839,96 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             case 5: /* VBSL */
                 tmp3 = neon_load_reg(rd, pass);
                 gen_neon_bsl(tmp, tmp, tmp2, tmp3);
-                dead_tmp(tmp3);
+                tcg_temp_free_i32(tmp3);
                 break;
             case 6: /* VBIT */
                 tmp3 = neon_load_reg(rd, pass);
                 gen_neon_bsl(tmp, tmp, tmp3, tmp2);
-                dead_tmp(tmp3);
+                tcg_temp_free_i32(tmp3);
                 break;
             case 7: /* VBIF */
                 tmp3 = neon_load_reg(rd, pass);
                 gen_neon_bsl(tmp, tmp3, tmp, tmp2);
-                dead_tmp(tmp3);
+                tcg_temp_free_i32(tmp3);
                 break;
             }
             break;
-        case 4: /* VHSUB */
+        case NEON_3R_VHSUB:
             GEN_NEON_INTEGER_OP(hsub);
             break;
-        case 5: /* VQSUB */
+        case NEON_3R_VQSUB:
             GEN_NEON_INTEGER_OP_ENV(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 */
+        case NEON_3R_VQSHL:
             GEN_NEON_INTEGER_OP_ENV(qshl);
             break;
-        case 10: /* VRSHL */
+        case NEON_3R_VRSHL:
             GEN_NEON_INTEGER_OP(rshl);
             break;
-        case 11: /* VQRSHL */
+        case NEON_3R_VQRSHL:
             GEN_NEON_INTEGER_OP_ENV(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);
-            dead_tmp(tmp2);
+            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();
             }
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             tmp2 = neon_load_reg(rd, pass);
             if (u) { /* VMLS */
                 gen_neon_rsb(size, tmp, tmp2);
@@ -4467,7 +4936,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 */
@@ -4475,105 +4944,144 @@ 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, cpu_env, tmp, tmp2);
+                    break;
+                case 2:
+                    gen_helper_neon_qdmulh_s32(tmp, cpu_env, 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, cpu_env, tmp, tmp2);
+                    break;
+                case 2:
+                    gen_helper_neon_qrdmulh_s32(tmp, cpu_env, 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. */
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
             switch ((u << 2) | size) {
             case 0: /* VADD */
-                gen_helper_neon_add_f32(tmp, tmp, tmp2);
+            case 4: /* VPADD */
+                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
                 break;
             case 2: /* VSUB */
-                gen_helper_neon_sub_f32(tmp, tmp, tmp2);
-                break;
-            case 4: /* VPADD */
-                gen_helper_neon_add_f32(tmp, tmp, tmp2);
+                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
                 break;
             case 6: /* VABD */
-                gen_helper_neon_abd_f32(tmp, tmp, tmp2);
+                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
                 break;
             default:
-                return 1;
+                abort();
             }
+            tcg_temp_free_ptr(fpstatus);
             break;
-        case 27: /* Float multiply.  */
-            gen_helper_neon_mul_f32(tmp, tmp, tmp2);
+        }
+        case NEON_3R_FLOAT_MULTIPLY:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
             if (!u) {
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 tmp2 = neon_load_reg(rd, pass);
                 if (size == 0) {
-                    gen_helper_neon_add_f32(tmp, tmp, tmp2);
+                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
                 } else {
-                    gen_helper_neon_sub_f32(tmp, tmp2, tmp);
+                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
                 }
             }
+            tcg_temp_free_ptr(fpstatus);
             break;
-        case 28: /* Float compare.  */
+        }
+        case NEON_3R_FLOAT_CMP:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
             if (!u) {
-                gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
+                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
             } else {
-                if (size == 0)
-                    gen_helper_neon_cge_f32(tmp, tmp, tmp2);
-                else
-                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
+                if (size == 0) {
+                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
+                } else {
+                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
+                }
             }
+            tcg_temp_free_ptr(fpstatus);
             break;
-        case 29: /* Float compare absolute.  */
-            if (!u)
-                return 1;
-            if (size == 0)
-                gen_helper_neon_acge_f32(tmp, tmp, tmp2);
-            else
-                gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
+        }
+        case NEON_3R_FLOAT_ACMP:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            if (size == 0) {
+                gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
+            } else {
+                gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
+            }
+            tcg_temp_free_ptr(fpstatus);
             break;
-        case 30: /* Float min/max.  */
-            if (size == 0)
-                gen_helper_neon_max_f32(tmp, tmp, tmp2);
-            else
-                gen_helper_neon_min_f32(tmp, tmp, tmp2);
+        }
+        case NEON_3R_FLOAT_MINMAX:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            if (size == 0) {
+                gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
+            } else {
+                gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
+            }
+            tcg_temp_free_ptr(fpstatus);
             break;
-        case 31:
+        }
+        case NEON_3R_VRECPS_VRSQRTS:
             if (size == 0)
                 gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
             else
                 gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
             break;
+        case NEON_3R_VFM:
+        {
+            /* VFMA, VFMS: fused multiply-add */
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            TCGv_i32 tmp3 = neon_load_reg(rd, pass);
+            if (size) {
+                /* VFMS */
+                gen_helper_vfp_negs(tmp, tmp);
+            }
+            gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus);
+            tcg_temp_free_i32(tmp3);
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
         default:
             abort();
         }
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(tmp2);
 
         /* Save the result.  For elementwise operations we can put it
            straight into the destination register.  For pairwise operations
@@ -4597,7 +5105,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;
@@ -4610,6 +5121,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)
@@ -4657,20 +5174,12 @@ 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_env,
+                                                      cpu_V0, cpu_V1);
                             break;
                         case 7: /* VQSHL */
                             if (u) {
@@ -4688,13 +5197,25 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
                         } else if (op == 4 || (op == 5 && u)) {
                             /* Insert */
-                            cpu_abort(env, "VS[LR]I.64 not implemented");
+                            neon_load_reg64(cpu_V1, rd + pass);
+                            uint64_t mask;
+                            if (shift < -63 || shift > 63) {
+                                mask = 0;
+                            } else {
+                                if (op == 4) {
+                                    mask = 0xffffffffffffffffull >> -shift;
+                                } else {
+                                    mask = 0xffffffffffffffffull << shift;
+                                }
+                            }
+                            tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
+                            tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                         }
                         neon_store_reg64(cpu_V0, rd + pass);
                     } else { /* size < 3 */
                         /* Operands in T0 and T1.  */
                         tmp = neon_load_reg(rm, pass);
-                        tmp2 = new_tmp();
+                        tmp2 = tcg_temp_new_i32();
                         tcg_gen_movi_i32(tmp2, imm);
                         switch (op) {
                         case 0:  /* VSHR */
@@ -4706,22 +5227,15 @@ 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,
@@ -4736,20 +5250,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                                           tmp, tmp2);
                                 break;
                             default:
-                                return 1;
+                                abort();
                             }
                             break;
                         case 7: /* VQSHL */
                             GEN_NEON_INTEGER_OP_ENV(qshl);
                             break;
                         }
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
 
                         if (op == 1 || op == 3) {
                             /* Accumulate.  */
                             tmp2 = neon_load_reg(rd, pass);
                             gen_neon_add(size, tmp, tmp2);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         } else if (op == 4 || (op == 5 && u)) {
                             /* Insert */
                             switch (size) {
@@ -4785,7 +5299,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             tcg_gen_andi_i32(tmp, tmp, mask);
                             tcg_gen_andi_i32(tmp2, tmp2, ~mask);
                             tcg_gen_or_i32(tmp, tmp, tmp2);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         neon_store_reg(rd, pass, tmp);
                     }
@@ -4793,71 +5307,81 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             } else if (op < 10) {
                 /* 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++;
-                switch (size) {
-                case 1:
-                    imm = (uint16_t)shift;
-                    imm |= imm << 16;
-                    tmp2 = tcg_const_i32(imm);
-                    TCGV_UNUSED_I64(tmp64);
-                    break;
-                case 2:
-                    imm = (uint32_t)shift;
-                    tmp2 = tcg_const_i32(imm);
-                    TCGV_UNUSED_I64(tmp64);
-                    break;
-                case 3:
+                if (size == 3) {
                     tmp64 = tcg_const_i64(shift);
-                    TCGV_UNUSED(tmp2);
-                    break;
-                default:
-                    abort();
-                }
-
-                for (pass = 0; pass < 2; pass++) {
-                    if (size == 3) {
-                        neon_load_reg64(cpu_V0, rm + pass);
+                    neon_load_reg64(cpu_V0, rm);
+                    neon_load_reg64(cpu_V1, rm + 1);
+                    for (pass = 0; pass < 2; pass++) {
+                        TCGv_i64 in;
+                        if (pass == 0) {
+                            in = cpu_V0;
+                        } else {
+                            in = cpu_V1;
+                        }
                         if (q) {
-                          if (u)
-                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64);
-                          else
-                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64);
+                            if (input_unsigned) {
+                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
+                            } else {
+                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
+                            }
                         } else {
-                          if (u)
-                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64);
-                          else
-                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64);
+                            if (input_unsigned) {
+                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
+                            } else {
+                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
+                            }
                         }
-                    } else {
-                        tmp = neon_load_reg(rm + pass, 0);
-                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
-                        tmp3 = neon_load_reg(rm + pass, 1);
-                        gen_neon_shift_narrow(size, tmp3, tmp2, q, u);
-                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
-                        dead_tmp(tmp);
-                        dead_tmp(tmp3);
-                    }
-                    tmp = new_tmp();
-                    if (op == 8 && !u) {
-                        gen_neon_narrow(size - 1, tmp, cpu_V0);
-                    } else {
-                        if (op == 8)
-                            gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
-                        else
-                            gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
-                    }
-                    neon_store_reg(rd, pass, tmp);
-                } /* for pass */
-                if (size == 3) {
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
+                        neon_store_reg(rd, pass, tmp);
+                    } /* for pass */
                     tcg_temp_free_i64(tmp64);
                 } else {
+                    if (size == 1) {
+                        imm = (uint16_t)shift;
+                        imm |= imm << 16;
+                    } else {
+                        /* size == 2 */
+                        imm = (uint32_t)shift;
+                    }
+                    tmp2 = tcg_const_i32(imm);
+                    tmp4 = neon_load_reg(rm + 1, 0);
+                    tmp5 = neon_load_reg(rm + 1, 1);
+                    for (pass = 0; pass < 2; pass++) {
+                        if (pass == 0) {
+                            tmp = neon_load_reg(rm, 0);
+                        } else {
+                            tmp = tmp4;
+                        }
+                        gen_neon_shift_narrow(size, tmp, tmp2, q,
+                                              input_unsigned);
+                        if (pass == 0) {
+                            tmp3 = neon_load_reg(rm, 1);
+                        } else {
+                            tmp3 = tmp5;
+                        }
+                        gen_neon_shift_narrow(size, tmp3, tmp2, q,
+                                              input_unsigned);
+                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
+                        tcg_temp_free_i32(tmp);
+                        tcg_temp_free_i32(tmp3);
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
+                        neon_store_reg(rd, pass, tmp);
+                    } /* for pass */
                     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++) {
@@ -4870,22 +5394,37 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         /* The shift is less than the width of the source
                            type, so we can just shift the whole register.  */
                         tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
+                        /* Widen the result of shift: we need to clear
+                         * the potential overflow bits resulting from
+                         * left bits of the narrow input appearing as
+                         * right bits of left the neighbour narrow
+                         * input.  */
                         if (size < 2 || !u) {
                             uint64_t imm64;
                             if (size == 0) {
                                 imm = (0xffu >> (8 - shift));
                                 imm |= imm << 16;
-                            } else {
+                            } else if (size == 1) {
                                 imm = 0xffff >> (16 - shift);
+                            } else {
+                                /* size == 2 */
+                                imm = 0xffffffff >> (32 - shift);
+                            }
+                            if (size < 2) {
+                                imm64 = imm | (((uint64_t)imm) << 32);
+                            } else {
+                                imm64 = imm;
                             }
-                            imm64 = imm | (((uint64_t)imm) << 32);
-                            tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
+                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
                         }
                     }
                     neon_store_reg64(cpu_V0, rd + pass);
                 }
             } 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.
                  */
@@ -4894,14 +5433,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
                     if (!(op & 1)) {
                         if (u)
-                            gen_vfp_ulto(0, shift);
+                            gen_vfp_ulto(0, shift, 1);
                         else
-                            gen_vfp_slto(0, shift);
+                            gen_vfp_slto(0, shift, 1);
                     } else {
                         if (u)
-                            gen_vfp_toul(0, shift);
+                            gen_vfp_toul(0, shift, 1);
                         else
-                            gen_vfp_tosl(0, shift);
+                            gen_vfp_tosl(0, shift, 1);
                     }
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
                 }
@@ -4910,11 +5449,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 */
@@ -4946,6 +5492,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;
@@ -4965,8 +5514,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     }
                 } else {
                     /* VMOV, VMVN.  */
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     if (op == 14 && invert) {
+                        int n;
                         uint32_t val;
                         val = 0;
                         for (n = 0; n < 4; n++) {
@@ -4989,31 +5539,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
@@ -5082,48 +5648,49 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             break;
                         default: abort();
                         }
-                        dead_tmp(tmp2);
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp2);
+                        tcg_temp_free_i32(tmp);
                         break;
                     case 8: case 9: case 10: case 11: case 12: case 13:
                         /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
                         gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
                         break;
                     case 14: /* Polynomial VMULL */
-                        cpu_abort(env, "Polynomial VMULL not implemented");
-
-                    default: /* 15 is RESERVED.  */
-                        return 1;
+                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        tcg_temp_free_i32(tmp);
+                        break;
+                    default: /* 15 is RESERVED: caught earlier  */
+                        abort();
                     }
-                    if (op == 5 || op == 13 || (op >= 8 && op <= 11)) {
+                    if (op == 13) {
+                        /* VQDMULL */
+                        gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    } else if (op == 5 || (op >= 8 && op <= 11)) {
                         /* Accumulate.  */
-                        if (op == 10 || op == 11) {
-                            gen_neon_negl(cpu_V0, size);
-                        }
-
-                        if (op != 13) {
-                            neon_load_reg64(cpu_V1, rd + pass);
-                        }
-
+                        neon_load_reg64(cpu_V1, rd + pass);
                         switch (op) {
-                        case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
+                        case 10: /* VMLSL */
+                            gen_neon_negl(cpu_V0, size);
+                            /* Fall through */
+                        case 5: case 8: /* VABAL, VMLAL */
                             gen_neon_addl(size);
                             break;
                         case 9: case 11: /* VQDMLAL, VQDMLSL */
                             gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                            if (op == 11) {
+                                gen_neon_negl(cpu_V0, size);
+                            }
                             gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                             break;
-                            /* Fall through.  */
-                        case 13: /* VQDMULL */
-                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
-                            break;
                         default:
                             abort();
                         }
                         neon_store_reg64(cpu_V0, rd + pass);
                     } else if (op == 4 || op == 6) {
                         /* Narrowing operation.  */
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         if (!u) {
                             switch (size) {
                             case 0:
@@ -5166,16 +5733,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++) {
@@ -5194,16 +5774,18 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
                             }
                         } else if (op & 1) {
-                            gen_helper_neon_mul_f32(tmp, tmp, tmp2);
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free_ptr(fpstatus);
                         } else {
                             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();
                             }
                         }
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         if (op < 8) {
                             /* Accumulate.  */
                             tmp2 = neon_load_reg(rd, pass);
@@ -5212,35 +5794,47 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 gen_neon_add(size, tmp, tmp2);
                                 break;
                             case 1:
-                                gen_helper_neon_add_f32(tmp, tmp, tmp2);
+                            {
+                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
+                                tcg_temp_free_ptr(fpstatus);
                                 break;
+                            }
                             case 4:
                                 gen_neon_rsb(size, tmp, tmp2);
                                 break;
                             case 5:
-                                gen_helper_neon_sub_f32(tmp, tmp2, tmp);
+                            {
+                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
+                                tcg_temp_free_ptr(fpstatus);
                                 break;
+                            }
                             default:
                                 abort();
                             }
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         neon_store_reg(rd, pass, tmp);
                     }
-                    break;
+                    break;
+                case 3: /* VQDMLAL scalar */
+                case 7: /* VQDMLSL scalar */
+                case 11: /* VQDMULL scalar */
+                    if (u == 1) {
+                        return 1;
+                    }
+                    /* fall through */
                 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 (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.  */
-                    tmp4 = new_tmp();
+                    tmp4 = tcg_temp_new_i32();
                     tcg_gen_mov_i32(tmp4, tmp2);
                     tmp3 = neon_load_reg(rn, 1);
 
@@ -5252,18 +5846,21 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             tmp2 = tmp4;
                         }
                         gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
-                        if (op == 6 || op == 7) {
-                            gen_neon_negl(cpu_V0, size);
-                        }
                         if (op != 11) {
                             neon_load_reg64(cpu_V1, rd + pass);
                         }
                         switch (op) {
-                        case 2: case 6:
+                        case 6:
+                            gen_neon_negl(cpu_V0, size);
+                            /* Fall through */
+                        case 2:
                             gen_neon_addl(size);
                             break;
                         case 3: case 7:
                             gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                            if (op == 7) {
+                                gen_neon_negl(cpu_V0, size);
+                            }
                             gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                             break;
                         case 10:
@@ -5292,6 +5889,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) {
@@ -5340,10 +5941,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);
@@ -5366,10 +5973,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);
@@ -5381,7 +5986,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);
@@ -5389,8 +5994,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);
@@ -5401,73 +6007,27 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         goto elementwise;
                     }
                     break;
-                case 34: /* VUZP */
-                    /* Reg  Before       After
-                       Rd   A3 A2 A1 A0  B2 B0 A2 A0
-                       Rm   B3 B2 B1 B0  B3 B1 A3 A1
-                     */
-                    if (size == 3)
+                case NEON_2RM_VUZP:
+                    if (gen_neon_unzip(rd, rm, size, q)) {
                         return 1;
-                    gen_neon_unzip(rd, q, 0, size);
-                    gen_neon_unzip(rm, q, 4, size);
-                    if (q) {
-                        static int unzip_order_q[8] =
-                            {0, 2, 4, 6, 1, 3, 5, 7};
-                        for (n = 0; n < 8; n++) {
-                            int reg = (n < 4) ? rd : rm;
-                            tmp = neon_load_scratch(unzip_order_q[n]);
-                            neon_store_reg(reg, n % 4, tmp);
-                        }
-                    } else {
-                        static int unzip_order[4] =
-                            {0, 4, 1, 5};
-                        for (n = 0; n < 4; n++) {
-                            int reg = (n < 2) ? rd : rm;
-                            tmp = neon_load_scratch(unzip_order[n]);
-                            neon_store_reg(reg, n % 2, tmp);
-                        }
                     }
                     break;
-                case 35: /* VZIP */
-                    /* Reg  Before       After
-                       Rd   A3 A2 A1 A0  B1 A1 B0 A0
-                       Rm   B3 B2 B1 B0  B3 A3 B2 A2
-                     */
-                    if (size == 3)
+                case NEON_2RM_VZIP:
+                    if (gen_neon_zip(rd, rm, size, q)) {
                         return 1;
-                    count = (q ? 4 : 2);
-                    for (n = 0; n < count; n++) {
-                        tmp = neon_load_reg(rd, n);
-                        tmp2 = neon_load_reg(rd, n);
-                        switch (size) {
-                        case 0: gen_neon_zip_u8(tmp, tmp2); break;
-                        case 1: gen_neon_zip_u16(tmp, tmp2); break;
-                        case 2: /* no-op */; break;
-                        default: abort();
-                        }
-                        neon_store_scratch(n * 2, tmp);
-                        neon_store_scratch(n * 2 + 1, tmp2);
-                    }
-                    for (n = 0; n < count * 2; n++) {
-                        int reg = (n < count) ? rd : rm;
-                        tmp = neon_load_scratch(n);
-                        neon_store_reg(reg, n % count, tmp);
                     }
                     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 = new_tmp();
-                        if (op == 36 && q == 0) {
-                            gen_neon_narrow(size, tmp, cpu_V0);
-                        } else if (q) {
-                            gen_neon_narrow_satu(size, tmp, cpu_V0);
-                        } else {
-                            gen_neon_narrow_sats(size, tmp, cpu_V0);
-                        }
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
+                                           tmp, cpu_V0);
                         if (pass == 0) {
                             tmp2 = tmp;
                         } else {
@@ -5476,9 +6036,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++) {
@@ -5489,54 +6050,58 @@ 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;
-                    tmp = new_tmp();
-                    tmp2 = new_tmp();
+                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));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                     tcg_gen_shli_i32(tmp2, tmp2, 16);
                     tcg_gen_or_i32(tmp2, tmp2, tmp);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                     neon_store_reg(rd, 0, tmp2);
-                    tmp2 = new_tmp();
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    tmp2 = tcg_temp_new_i32();
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                     tcg_gen_shli_i32(tmp2, tmp2, 16);
                     tcg_gen_or_i32(tmp2, tmp2, tmp);
                     neon_store_reg(rd, 1, tmp2);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     break;
-                case 46: /* VCVT.F32.F16 */
-                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                      return 1;
-                    tmp3 = new_tmp();
+                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);
                     tcg_gen_ext16u_i32(tmp3, tmp);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                     tcg_gen_shri_i32(tmp3, tmp, 16);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     tcg_gen_ext16u_i32(tmp3, tmp2);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                     tcg_gen_shri_i32(tmp3, tmp2, 16);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
-                    dead_tmp(tmp2);
-                    dead_tmp(tmp3);
+                    tcg_temp_free_i32(tmp2);
+                    tcg_temp_free_i32(tmp3);
                     break;
                 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);
@@ -5544,177 +6109,210 @@ 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, 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: 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, 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: 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:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                             tmp2 = tcg_const_i32(0);
-                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
+                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
                             tcg_temp_free(tmp2);
-                            if (op == 27)
-                                tcg_gen_not_i32(tmp, tmp);
+                            tcg_temp_free_ptr(fpstatus);
                             break;
-                        case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
+                        }
+                        case NEON_2RM_VCGE0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                             tmp2 = tcg_const_i32(0);
-                            gen_helper_neon_cge_f32(tmp, tmp, tmp2);
+                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
                             tcg_temp_free(tmp2);
-                            if (op == 28)
-                                tcg_gen_not_i32(tmp, tmp);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCEQ0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCLE0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
                             break;
-                        case 26: /* Float VCEQ #0 */
+                        }
+                        case NEON_2RM_VCLT0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                             tmp2 = tcg_const_i32(0);
-                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
+                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
                             tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
                             break;
-                        case 30: /* Float VABS */
+                        }
+                        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 */
-                            gen_vfp_sito(0);
+                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
+                            gen_vfp_sito(0, 1);
                             break;
-                        case 61: /* VCVT.F32.U32 */
-                            gen_vfp_uito(0);
+                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
+                            gen_vfp_uito(0, 1);
                             break;
-                        case 62: /* VCVT.S32.F32 */
-                            gen_vfp_tosiz(0);
+                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
+                            gen_vfp_tosiz(0, 1);
                             break;
-                        case 63: /* VCVT.U32.F32 */
-                            gen_vfp_touiz(0);
+                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
+                            gen_vfp_touiz(0, 1);
                             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 {
@@ -5725,22 +6323,29 @@ 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 {
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp, 0);
                 }
                 tmp2 = neon_load_reg(rm, 0);
                 tmp4 = tcg_const_i32(rn);
                 tmp5 = tcg_const_i32(n);
                 gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5);
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
                 if (insn & (1 << 6)) {
                     tmp = neon_load_reg(rd, 1);
                 } else {
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp, 0);
                 }
                 tmp3 = neon_load_reg(rm, 1);
@@ -5749,9 +6354,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 tcg_temp_free_i32(tmp4);
                 neon_store_reg(rd, 0, tmp2);
                 neon_store_reg(rd, 1, tmp3);
-                dead_tmp(tmp);
+                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 {
@@ -5766,11 +6374,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_neon_dup_low16(tmp);
                 }
                 for (pass = 0; pass < (q ? 4 : 2); pass++) {
-                    tmp2 = new_tmp();
+                    tmp2 = tcg_temp_new_i32();
                     tcg_gen_mov_i32(tmp2, tmp);
                     neon_store_reg(rd, pass, tmp2);
                 }
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
             } else {
                 return 1;
             }
@@ -5788,6 +6396,34 @@ static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
     int rt = (insn >> 12) & 0xf;
     TCGv tmp;
 
+    /* Minimal set of debug registers, since we don't support debug */
+    if (op1 == 0 && crn == 0 && op2 == 0) {
+        switch (crm) {
+        case 0:
+            /* DBGDIDR: just RAZ. In particular this means the
+             * "debug architecture version" bits will read as
+             * a reserved value, which should cause Linux to
+             * not try to use the debug hardware.
+             */
+            tmp = tcg_const_i32(0);
+            store_reg(s, rt, tmp);
+            return 0;
+        case 1:
+        case 2:
+            /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we
+             * don't implement memory mapped debug components
+             */
+            if (ENABLE_ARCH_7) {
+                tmp = tcg_const_i32(0);
+                store_reg(s, rt, tmp);
+                return 0;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
     if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
         if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
             /* TEECR */
@@ -5806,8 +6442,6 @@ static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
             return 0;
         }
     }
-    fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
-            op1, crn, crm, op2);
     return 1;
 }
 
@@ -5827,7 +6461,7 @@ static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
                 return 1;
             tmp = load_reg(s, rt);
             gen_helper_set_teecr(cpu_env, tmp);
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             return 0;
         }
         if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
@@ -5839,8 +6473,6 @@ static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
             return 0;
         }
     }
-    fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
-            op1, crn, crm, op2);
     return 1;
 }
 
@@ -5888,10 +6520,10 @@ static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
 static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
 {
     TCGv tmp;
-    tmp = new_tmp();
+    tmp = tcg_temp_new_i32();
     tcg_gen_trunc_i64_i32(tmp, val);
     store_reg(s, rlow, tmp);
-    tmp = new_tmp();
+    tmp = tcg_temp_new_i32();
     tcg_gen_shri_i64(val, val, 32);
     tcg_gen_trunc_i64_i32(tmp, val);
     store_reg(s, rhigh, tmp);
@@ -5907,7 +6539,7 @@ static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
     tmp = tcg_temp_new_i64();
     tmp2 = load_reg(s, rlow);
     tcg_gen_extu_i32_i64(tmp, tmp2);
-    dead_tmp(tmp2);
+    tcg_temp_free_i32(tmp2);
     tcg_gen_add_i64(val, val, tmp);
     tcg_temp_free_i64(tmp);
 }
@@ -5924,8 +6556,8 @@ static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
     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_temp_free_i32(tmpl);
+    tcg_temp_free_i32(tmph);
     tcg_gen_add_i64(val, val, tmp);
     tcg_temp_free_i64(tmp);
 }
@@ -5933,10 +6565,10 @@ static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
 /* Set N and Z flags from a 64-bit value.  */
 static void gen_logicq_cc(TCGv_i64 val)
 {
-    TCGv tmp = new_tmp();
+    TCGv tmp = tcg_temp_new_i32();
     gen_helper_logicq_cc(tmp, val);
     gen_logic_CC(tmp);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 /* Load/Store exclusive instructions are implemented by remembering
@@ -5970,10 +6602,10 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
     tcg_gen_mov_i32(cpu_exclusive_val, tmp);
     store_reg(s, rt, tmp);
     if (size == 3) {
-        TCGv tmp2 = new_tmp();
+        TCGv tmp2 = tcg_temp_new_i32();
         tcg_gen_addi_i32(tmp2, addr, 4);
         tmp = gen_ld32(tmp2, IS_USER(s));
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(tmp2);
         tcg_gen_mov_i32(cpu_exclusive_high, tmp);
         store_reg(s, rt2, tmp);
     }
@@ -6026,14 +6658,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
         abort();
     }
     tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
-    dead_tmp(tmp);
+    tcg_temp_free_i32(tmp);
     if (size == 3) {
-        TCGv tmp2 = new_tmp();
+        TCGv tmp2 = tcg_temp_new_i32();
         tcg_gen_addi_i32(tmp2, addr, 4);
         tmp = gen_ld32(tmp2, IS_USER(s));
-        dead_tmp(tmp2);
+        tcg_temp_free_i32(tmp2);
         tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
     }
     tmp = load_reg(s, rt);
     switch (size) {
@@ -6081,6 +6713,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.  */
@@ -6100,9 +6738,32 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             return;
         }
-        if ((insn & 0x0d70f000) == 0x0550f000)
-            return; /* PLD */
-        else if ((insn & 0x0ffffdff) == 0x01010000) {
+        if (((insn & 0x0f30f000) == 0x0510f000) ||
+            ((insn & 0x0f30f010) == 0x0710f000)) {
+            if ((insn & (1 << 22)) == 0) {
+                /* PLDW; v7MP */
+                if (!arm_feature(env, ARM_FEATURE_V7MP)) {
+                    goto illegal_op;
+                }
+            }
+            /* Otherwise PLD; v5TE+ */
+            ARCH(5TE);
+            return;
+        }
+        if (((insn & 0x0f70f000) == 0x0450f000) ||
+            ((insn & 0x0f70f010) == 0x0650f000)) {
+            ARCH(7);
+            return; /* PLI; V7 */
+        }
+        if (((insn & 0x0f700000) == 0x04100000) ||
+            ((insn & 0x0f700010) == 0x06100000)) {
+            if (!arm_feature(env, ARM_FEATURE_V7MP)) {
+                goto illegal_op;
+            }
+            return; /* v7MP: Unallocated memory hint: must NOP */
+        }
+
+        if ((insn & 0x0ffffdff) == 0x01010000) {
             ARCH(6);
             /* setend */
             if (insn & (1 << 9)) {
@@ -6132,7 +6793,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             ARCH(6);
             op1 = (insn & 0x1f);
-            addr = new_tmp();
+            addr = tcg_temp_new_i32();
             tmp = tcg_const_i32(op1);
             gen_helper_get_r13_banked(addr, cpu_env, tmp);
             tcg_temp_free_i32(tmp);
@@ -6165,9 +6826,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 tmp = tcg_const_i32(op1);
                 gen_helper_set_r13_banked(cpu_env, tmp, addr);
                 tcg_temp_free_i32(tmp);
-                dead_tmp(addr);
+                tcg_temp_free_i32(addr);
             } else {
-                dead_tmp(addr);
+                tcg_temp_free_i32(addr);
             }
             return;
         } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
@@ -6205,7 +6866,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     tcg_gen_addi_i32(addr, addr, offset);
                 store_reg(s, rn, addr);
             } else {
-                dead_tmp(addr);
+                tcg_temp_free_i32(addr);
             }
             gen_rfe(s, tmp, tmp2);
             return;
@@ -6214,7 +6875,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             int32_t offset;
 
             val = (uint32_t)s->pc;
-            tmp = new_tmp();
+            tmp = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp, val);
             store_reg(s, 14, tmp);
             /* Sign-extend the 24-bit offset */
@@ -6223,6 +6884,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) {
@@ -6234,6 +6896,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) {
@@ -6278,7 +6941,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
             if ((insn & (1 << 22)) == 0) {
                 /* MOVW */
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_movi_i32(tmp, val);
             } else {
                 /* MOVT */
@@ -6325,7 +6988,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         goto illegal_op;
                     tmp = load_cpu_field(spsr);
                 } else {
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     gen_helper_cpsr_read(tmp);
                 }
                 store_reg(s, rd, tmp);
@@ -6334,10 +6997,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);
@@ -6360,14 +7025,16 @@ 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 = new_tmp();
+            tmp2 = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp2, s->pc);
             store_reg(s, 14, tmp2);
             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);
@@ -6378,7 +7045,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 gen_helper_sub_saturate(tmp, tmp, tmp2);
             else
                 gen_helper_add_saturate(tmp, tmp, tmp2);
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             store_reg(s, rd, tmp);
             break;
         case 7:
@@ -6389,12 +7056,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;
@@ -6408,13 +7077,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     gen_sxth(tmp2);
                 tmp64 = gen_muls_i64_i32(tmp, tmp2);
                 tcg_gen_shri_i64(tmp64, tmp64, 16);
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_trunc_i64_i32(tmp, tmp64);
                 tcg_temp_free_i64(tmp64);
                 if ((sh & 2) == 0) {
                     tmp2 = load_reg(s, rn);
                     gen_helper_add_setq(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                 }
                 store_reg(s, rd, tmp);
             } else {
@@ -6422,11 +7091,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 tmp = load_reg(s, rm);
                 tmp2 = load_reg(s, rs);
                 gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 if (op1 == 2) {
                     tmp64 = tcg_temp_new_i64();
                     tcg_gen_ext_i32_i64(tmp64, tmp);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     gen_addq(s, tmp64, rn, rd);
                     gen_storeq_reg(s, rn, rd, tmp64);
                     tcg_temp_free_i64(tmp64);
@@ -6434,7 +7103,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     if (op1 == 0) {
                         tmp2 = load_reg(s, rn);
                         gen_helper_add_setq(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                     }
                     store_reg(s, rd, tmp);
                 }
@@ -6460,7 +7129,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             if (shift) {
                 val = (val >> shift) | (val << (32 - shift));
             }
-            tmp2 = new_tmp();
+            tmp2 = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp2, val);
             if (logic_cc && shift) {
                 gen_set_CF_bit31(tmp2);
@@ -6563,26 +7232,26 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 tcg_gen_and_i32(tmp, tmp, tmp2);
                 gen_logic_CC(tmp);
             }
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             break;
         case 0x09:
             if (set_cc) {
                 tcg_gen_xor_i32(tmp, tmp, tmp2);
                 gen_logic_CC(tmp);
             }
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             break;
         case 0x0a:
             if (set_cc) {
                 gen_helper_sub_cc(tmp, tmp, tmp2);
             }
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             break;
         case 0x0b:
             if (set_cc) {
                 gen_helper_add_cc(tmp, tmp, tmp2);
             }
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             break;
         case 0x0c:
             tcg_gen_or_i32(tmp, tmp, tmp2);
@@ -6622,7 +7291,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             break;
         }
         if (op1 != 0x0f && op1 != 0x0d) {
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
         }
     } else {
         /* other instructions */
@@ -6645,18 +7314,18 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tmp = load_reg(s, rs);
                         tmp2 = load_reg(s, rm);
                         tcg_gen_mul_i32(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         if (insn & (1 << 22)) {
                             /* Subtract (mls) */
                             ARCH(6T2);
                             tmp2 = load_reg(s, rn);
                             tcg_gen_sub_i32(tmp, tmp2, tmp);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         } else if (insn & (1 << 21)) {
                             /* Add */
                             tmp2 = load_reg(s, rn);
                             tcg_gen_add_i32(tmp, tmp, tmp2);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         if (insn & (1 << 20))
                             gen_logic_CC(tmp);
@@ -6760,7 +7429,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tmp2 = gen_ld32(addr, IS_USER(s));
                             gen_st32(tmp, addr, IS_USER(s));
                         }
-                        dead_tmp(addr);
+                        tcg_temp_free_i32(addr);
                         store_reg(s, rd, tmp2);
                     }
                 }
@@ -6790,6 +7459,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     load = 1;
                 } else if (sh & 2) {
+                    ARCH(5TE);
                     /* doubleword */
                     if (sh & 1) {
                         /* store */
@@ -6827,7 +7497,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tcg_gen_addi_i32(addr, addr, address_offset);
                     store_reg(s, rn, addr);
                 } else {
-                    dead_tmp(addr);
+                    tcg_temp_free_i32(addr);
                 }
                 if (load) {
                     /* Complete the load.  */
@@ -6856,7 +7526,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                         goto illegal_op;
                     gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                     store_reg(s, rd, tmp);
                     break;
                 case 1:
@@ -6880,7 +7550,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                         }
                         tcg_gen_or_i32(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         store_reg(s, rd, tmp);
                     } else if ((insn & 0x00200020) == 0x00200000) {
                         /* [us]sat */
@@ -6916,16 +7586,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         /* Select bytes.  */
                         tmp = load_reg(s, rn);
                         tmp2 = load_reg(s, rm);
-                        tmp3 = new_tmp();
+                        tmp3 = tcg_temp_new_i32();
                         tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
                         gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
-                        dead_tmp(tmp3);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp3);
+                        tcg_temp_free_i32(tmp2);
                         store_reg(s, rd, tmp);
                     } else if ((insn & 0x000003e0) == 0x00000060) {
                         tmp = load_reg(s, rm);
                         shift = (insn >> 10) & 3;
-                        /* ??? In many cases it's not neccessary to do a
+                        /* ??? In many cases it's not necessary to do a
                            rotate, a shift is sufficient.  */
                         if (shift != 0)
                             tcg_gen_rotri_i32(tmp, tmp, shift * 8);
@@ -6945,7 +7615,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                                 gen_add16(tmp, tmp2);
                             } else {
                                 tcg_gen_add_i32(tmp, tmp, tmp2);
-                                dead_tmp(tmp2);
+                                tcg_temp_free_i32(tmp2);
                             }
                         }
                         store_reg(s, rd, tmp);
@@ -6971,11 +7641,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     break;
                 case 2: /* Multiplies (Type 3).  */
-                    tmp = load_reg(s, rm);
-                    tmp2 = load_reg(s, rs);
-                    if (insn & (1 << 20)) {
+                    switch ((insn >> 20) & 0x7) {
+                    case 5:
+                        if (((insn >> 6) ^ (insn >> 7)) & 1) {
+                            /* op2 not 00x or 11x : UNDEF */
+                            goto illegal_op;
+                        }
                         /* Signed multiply most significant [accumulate].
                            (SMMUL, SMMLA, SMMLS) */
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
                         tmp64 = gen_muls_i64_i32(tmp, tmp2);
 
                         if (rd != 15) {
@@ -6990,26 +7665,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                         }
                         tcg_gen_shri_i64(tmp64, tmp64, 32);
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         tcg_gen_trunc_i64_i32(tmp, tmp64);
                         tcg_temp_free_i64(tmp64);
                         store_reg(s, rn, tmp);
-                    } else {
+                        break;
+                    case 0:
+                    case 4:
+                        /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */
+                        if (insn & (1 << 7)) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
                         if (insn & (1 << 5))
                             gen_swap_half(tmp2);
                         gen_smul_dual(tmp, tmp2);
-                        /* This addition cannot overflow.  */
                         if (insn & (1 << 6)) {
+                            /* This subtraction cannot overflow. */
                             tcg_gen_sub_i32(tmp, tmp, tmp2);
                         } else {
-                            tcg_gen_add_i32(tmp, tmp, tmp2);
+                            /* This addition cannot overflow 32 bits;
+                             * however it may overflow considered as a signed
+                             * operation, in which case we must set the Q flag.
+                             */
+                            gen_helper_add_setq(tmp, tmp, tmp2);
                         }
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         if (insn & (1 << 22)) {
                             /* smlald, smlsld */
                             tmp64 = tcg_temp_new_i64();
                             tcg_gen_ext_i32_i64(tmp64, tmp);
-                            dead_tmp(tmp);
+                            tcg_temp_free_i32(tmp);
                             gen_addq(s, tmp64, rd, rn);
                             gen_storeq_reg(s, rd, rn, tmp64);
                             tcg_temp_free_i64(tmp64);
@@ -7019,10 +7706,32 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                               {
                                 tmp2 = load_reg(s, rd);
                                 gen_helper_add_setq(tmp, tmp, tmp2);
-                                dead_tmp(tmp2);
+                                tcg_temp_free_i32(tmp2);
                               }
                             store_reg(s, rn, tmp);
                         }
+                        break;
+                    case 1:
+                    case 3:
+                        /* SDIV, UDIV */
+                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+                            goto illegal_op;
+                        }
+                        if (((insn >> 5) & 7) || (rd != 15)) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
+                        if (insn & (1 << 21)) {
+                            gen_helper_udiv(tmp, tmp, tmp2);
+                        } else {
+                            gen_helper_sdiv(tmp, tmp, tmp2);
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rn, tmp);
+                        break;
+                    default:
+                        goto illegal_op;
                     }
                     break;
                 case 3:
@@ -7033,11 +7742,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tmp = load_reg(s, rm);
                         tmp2 = load_reg(s, rs);
                         gen_helper_usad8(tmp, tmp, tmp2);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         if (rd != 15) {
                             tmp2 = load_reg(s, rd);
                             tcg_gen_add_i32(tmp, tmp, tmp2);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         store_reg(s, rn, tmp);
                         break;
@@ -7048,7 +7757,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         i = (insn >> 16) & 0x1f;
                         i = i + 1 - shift;
                         if (rm == 15) {
-                            tmp = new_tmp();
+                            tmp = tcg_temp_new_i32();
                             tcg_gen_movi_i32(tmp, 0);
                         } else {
                             tmp = load_reg(s, rm);
@@ -7056,7 +7765,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         if (i != 32) {
                             tmp2 = load_reg(s, rd);
                             gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         store_reg(s, rd, tmp);
                         break;
@@ -7122,14 +7831,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             } else if (insn & (1 << 21)) {
                 store_reg(s, rn, tmp2);
             } else {
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
             }
             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:
@@ -7182,28 +7888,26 @@ 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);
-                                dead_tmp(tmp);
+                                tcg_temp_free_i32(tmp);
                             } else if (i == rn) {
                                 loaded_var = tmp;
                                 loaded_base = 1;
                             } else {
-                                store_reg(s, i, tmp);
+                                store_reg_from_load(env, s, i, tmp);
                             }
                         } else {
                             /* store */
                             if (i == 15) {
                                 /* special case: r15 = PC + 8 */
                                 val = (long)s->pc + 4;
-                                tmp = new_tmp();
+                                tmp = tcg_temp_new_i32();
                                 tcg_gen_movi_i32(tmp, val);
                             } else if (user) {
-                                tmp = new_tmp();
+                                tmp = tcg_temp_new_i32();
                                 tmp2 = tcg_const_i32(i);
                                 gen_helper_get_user_reg(tmp, tmp2);
                                 tcg_temp_free_i32(tmp2);
@@ -7239,7 +7943,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     store_reg(s, rn, addr);
                 } else {
-                    dead_tmp(addr);
+                    tcg_temp_free_i32(addr);
                 }
                 if (loaded_base) {
                     store_reg(s, rn, loaded_var);
@@ -7248,7 +7952,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     /* Restore CPSR from SPSR.  */
                     tmp = load_cpu_field(spsr);
                     gen_set_cpsr(tmp, 0xffffffff);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     s->is_jmp = DISAS_UPDATE;
                 }
             }
@@ -7261,7 +7965,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 /* branch (and link) */
                 val = (int32_t)s->pc;
                 if (insn & (1 << 24)) {
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp, val);
                     store_reg(s, 14, tmp);
                 }
@@ -7323,8 +8027,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG
         logic_cc = conds;
         break;
     case 3: /* orn */
-        tcg_gen_not_i32(t1, t1);
-        tcg_gen_or_i32(t0, t0, t1);
+        tcg_gen_orc_i32(t0, t0, t1);
         logic_cc = conds;
         break;
     case 4: /* eor */
@@ -7394,13 +8097,14 @@ 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);
             tcg_gen_addi_i32(tmp, tmp, offset);
             tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
 
-            tmp2 = new_tmp();
+            tmp2 = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp2, s->pc | 1);
             store_reg(s, 14, tmp2);
             gen_bx(s, tmp);
@@ -7412,7 +8116,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             tmp = load_reg(s, 14);
             tcg_gen_addi_i32(tmp, tmp, offset);
 
-            tmp2 = new_tmp();
+            tmp2 = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp2, s->pc | 1);
             store_reg(s, 14, tmp2);
             gen_bx(s, tmp);
@@ -7451,7 +8155,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             if (insn & 0x01200000) {
                 /* Load/store doubleword.  */
                 if (rn == 15) {
-                    addr = new_tmp();
+                    addr = tcg_temp_new_i32();
                     tcg_gen_movi_i32(addr, s->pc & ~3);
                 } else {
                     addr = load_reg(s, rn);
@@ -7485,7 +8189,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     tcg_gen_addi_i32(addr, addr, offset - 4);
                     store_reg(s, rn, addr);
                 } else {
-                    dead_tmp(addr);
+                    tcg_temp_free_i32(addr);
                 }
             } else if ((insn & (1 << 23)) == 0) {
                 /* Load/store exclusive word.  */
@@ -7501,7 +8205,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             } else if ((insn & (1 << 6)) == 0) {
                 /* Table Branch.  */
                 if (rn == 15) {
-                    addr = new_tmp();
+                    addr = tcg_temp_new_i32();
                     tcg_gen_movi_i32(addr, s->pc);
                 } else {
                     addr = load_reg(s, rn);
@@ -7511,13 +8215,13 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 if (insn & (1 << 4)) {
                     /* tbh */
                     tcg_gen_add_i32(addr, addr, tmp);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     tmp = gen_ld16u(addr, IS_USER(s));
                 } else { /* tbb */
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     tmp = gen_ld8u(addr, IS_USER(s));
                 }
-                dead_tmp(addr);
+                tcg_temp_free_i32(addr);
                 tcg_gen_shli_i32(tmp, tmp, 1);
                 tcg_gen_addi_i32(tmp, tmp, s->pc);
                 store_reg(s, 15, tmp);
@@ -7561,13 +8265,13 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         }
                         store_reg(s, rn, addr);
                     } else {
-                        dead_tmp(addr);
+                        tcg_temp_free_i32(addr);
                     }
                     gen_rfe(s, tmp, tmp2);
                 } else {
                     /* srs */
                     op = (insn & 0x1f);
-                    addr = new_tmp();
+                    addr = tcg_temp_new_i32();
                     tmp = tcg_const_i32(op);
                     gen_helper_get_r13_banked(addr, cpu_env, tmp);
                     tcg_temp_free_i32(tmp);
@@ -7577,7 +8281,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     tmp = load_reg(s, 14);
                     gen_st32(tmp, addr, 0);
                     tcg_gen_addi_i32(addr, addr, 4);
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     gen_helper_cpsr_read(tmp);
                     gen_st32(tmp, addr, 0);
                     if (insn & (1 << 21)) {
@@ -7590,11 +8294,12 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         gen_helper_set_r13_banked(cpu_env, tmp, addr);
                         tcg_temp_free_i32(tmp);
                     } else {
-                        dead_tmp(addr);
+                        tcg_temp_free_i32(addr);
                     }
                 }
             } else {
-                int i;
+                int i, loaded_base = 0;
+                TCGv loaded_var;
                 /* Load/store multiple.  */
                 addr = load_reg(s, rn);
                 offset = 0;
@@ -7606,6 +8311,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;
@@ -7614,6 +8320,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);
                         }
@@ -7624,6 +8333,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)) {
@@ -7634,7 +8346,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         goto illegal_op;
                     store_reg(s, rn, addr);
                 } else {
-                    dead_tmp(addr);
+                    tcg_temp_free_i32(addr);
                 }
             }
         }
@@ -7662,12 +8374,12 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
             }
             tcg_gen_or_i32(tmp, tmp, tmp2);
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             store_reg(s, rd, tmp);
         } else {
             /* Data processing register constant shift.  */
             if (rn == 15) {
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_movi_i32(tmp, 0);
             } else {
                 tmp = load_reg(s, rn);
@@ -7681,11 +8393,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
             if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
                 goto illegal_op;
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             if (rd != 15) {
                 store_reg(s, rd, tmp);
             } else {
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
             }
         }
         break;
@@ -7709,7 +8421,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
         case 1: /* Sign/zero extend.  */
             tmp = load_reg(s, rm);
             shift = (insn >> 4) & 3;
-            /* ??? In many cases it's not neccessary to do a
+            /* ??? In many cases it's not necessary to do a
                rotate, a shift is sufficient.  */
             if (shift != 0)
                 tcg_gen_rotri_i32(tmp, tmp, shift * 8);
@@ -7729,7 +8441,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     gen_add16(tmp, tmp2);
                 } else {
                     tcg_gen_add_i32(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                 }
             }
             store_reg(s, rd, tmp);
@@ -7742,7 +8454,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             tmp = load_reg(s, rn);
             tmp2 = load_reg(s, rm);
             gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             store_reg(s, rd, tmp);
             break;
         case 3: /* Other data processing.  */
@@ -7757,7 +8469,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     gen_helper_sub_saturate(tmp, tmp2, tmp);
                 else
                     gen_helper_add_saturate(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
             } else {
                 tmp = load_reg(s, rn);
                 switch (op) {
@@ -7775,11 +8487,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     break;
                 case 0x10: /* sel */
                     tmp2 = load_reg(s, rm);
-                    tmp3 = new_tmp();
+                    tmp3 = tcg_temp_new_i32();
                     tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
                     gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
-                    dead_tmp(tmp3);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp3);
+                    tcg_temp_free_i32(tmp2);
                     break;
                 case 0x18: /* clz */
                     gen_helper_clz(tmp, tmp);
@@ -7797,23 +8509,23 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             switch ((insn >> 20) & 7) {
             case 0: /* 32 x 32 -> 32 */
                 tcg_gen_mul_i32(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 if (rs != 15) {
                     tmp2 = load_reg(s, rs);
                     if (op)
                         tcg_gen_sub_i32(tmp, tmp2, tmp);
                     else
                         tcg_gen_add_i32(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                 }
                 break;
             case 1: /* 16 x 16 -> 32 */
                 gen_mulxy(tmp, tmp2, op & 2, op & 1);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 if (rs != 15) {
                     tmp2 = load_reg(s, rs);
                     gen_helper_add_setq(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                 }
                 break;
             case 2: /* Dual multiply add.  */
@@ -7821,18 +8533,22 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 if (op)
                     gen_swap_half(tmp2);
                 gen_smul_dual(tmp, tmp2);
-                /* This addition cannot overflow.  */
                 if (insn & (1 << 22)) {
+                    /* This subtraction cannot overflow. */
                     tcg_gen_sub_i32(tmp, tmp, tmp2);
                 } else {
-                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                    /* This addition cannot overflow 32 bits;
+                     * however it may overflow considered as a signed
+                     * operation, in which case we must set the Q flag.
+                     */
+                    gen_helper_add_setq(tmp, tmp, tmp2);
                 }
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 if (rs != 15)
                   {
                     tmp2 = load_reg(s, rs);
                     gen_helper_add_setq(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                   }
                 break;
             case 3: /* 32 * 16 -> 32msb */
@@ -7842,14 +8558,14 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     gen_sxth(tmp2);
                 tmp64 = gen_muls_i64_i32(tmp, tmp2);
                 tcg_gen_shri_i64(tmp64, tmp64, 16);
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_trunc_i64_i32(tmp, tmp64);
                 tcg_temp_free_i64(tmp64);
                 if (rs != 15)
                   {
                     tmp2 = load_reg(s, rs);
                     gen_helper_add_setq(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                   }
                 break;
             case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
@@ -7866,17 +8582,17 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                 }
                 tcg_gen_shri_i64(tmp64, tmp64, 32);
-                tmp = new_tmp();
+                tmp = tcg_temp_new_i32();
                 tcg_gen_trunc_i64_i32(tmp, tmp64);
                 tcg_temp_free_i64(tmp64);
                 break;
             case 7: /* Unsigned sum of absolute differences.  */
                 gen_helper_usad8(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 if (rs != 15) {
                     tmp2 = load_reg(s, rs);
                     tcg_gen_add_i32(tmp, tmp, tmp2);
-                    dead_tmp(tmp2);
+                    tcg_temp_free_i32(tmp2);
                 }
                 break;
             }
@@ -7888,13 +8604,14 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             tmp2 = load_reg(s, rm);
             if ((op & 0x50) == 0x10) {
                 /* sdiv, udiv */
-                if (!arm_feature(env, ARM_FEATURE_DIV))
+                if (!arm_feature(env, ARM_FEATURE_THUMB_DIV)) {
                     goto illegal_op;
+                }
                 if (op & 0x20)
                     gen_helper_udiv(tmp, tmp, tmp2);
                 else
                     gen_helper_sdiv(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 store_reg(s, rd, tmp);
             } else if ((op & 0xe) == 0xc) {
                 /* Dual multiply accumulate long.  */
@@ -7906,11 +8623,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 } else {
                     tcg_gen_add_i32(tmp, tmp, tmp2);
                 }
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 /* BUGFIX */
                 tmp64 = tcg_temp_new_i64();
                 tcg_gen_ext_i32_i64(tmp64, tmp);
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp);
                 gen_addq(s, tmp64, rs, rd);
                 gen_storeq_reg(s, rs, rd, tmp64);
                 tcg_temp_free_i64(tmp64);
@@ -7922,10 +8639,10 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     if (op & 8) {
                         /* smlalxy */
                         gen_mulxy(tmp, tmp2, op & 2, op & 1);
-                        dead_tmp(tmp2);
+                        tcg_temp_free_i32(tmp2);
                         tmp64 = tcg_temp_new_i64();
                         tcg_gen_ext_i32_i64(tmp64, tmp);
-                        dead_tmp(tmp);
+                        tcg_temp_free_i32(tmp);
                     } else {
                         /* Signed 64-bit multiply  */
                         tmp64 = gen_muls_i64_i32(tmp, tmp2);
@@ -7949,7 +8666,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
         /* Coprocessor.  */
         if (((insn >> 24) & 3) == 3) {
             /* Translate into the equivalent ARM encoding.  */
-            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4);
+            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
             if (disas_neon_data_insn(env, s, insn))
                 goto illegal_op;
         } else {
@@ -7986,6 +8703,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) {
@@ -8005,7 +8723,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                             addr = tcg_const_i32(insn & 0xff);
                             gen_helper_v7m_msr(cpu_env, addr, tmp);
                             tcg_temp_free_i32(addr);
-                            dead_tmp(tmp);
+                            tcg_temp_free_i32(tmp);
                             gen_lookup_tb(s);
                             break;
                         }
@@ -8079,7 +8797,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         gen_exception_return(s, tmp);
                         break;
                     case 6: /* mrs cpsr.  */
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         if (IS_M(env)) {
                             addr = tcg_const_i32(insn & 0xff);
                             gen_helper_v7m_mrs(tmp, cpu_env, addr);
@@ -8131,7 +8849,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     imm = insn & 0x1f;
                     shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
                     if (rn == 15) {
-                        tmp = new_tmp();
+                        tmp = tcg_temp_new_i32();
                         tcg_gen_movi_i32(tmp, 0);
                     } else {
                         tmp = load_reg(s, rn);
@@ -8158,7 +8876,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         if (imm != 32) {
                             tmp2 = load_reg(s, rd);
                             gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
-                            dead_tmp(tmp2);
+                            tcg_temp_free_i32(tmp2);
                         }
                         break;
                     case 7:
@@ -8201,7 +8919,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                             tcg_gen_ori_i32(tmp, tmp, imm << 16);
                         } else {
                             /* movw */
-                            tmp = new_tmp();
+                            tmp = tcg_temp_new_i32();
                             tcg_gen_movi_i32(tmp, imm);
                         }
                     } else {
@@ -8212,7 +8930,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                                 offset -= imm;
                             else
                                 offset += imm;
-                            tmp = new_tmp();
+                            tmp = tcg_temp_new_i32();
                             tcg_gen_movi_i32(tmp, offset);
                         } else {
                             tmp = load_reg(s, rn);
@@ -8251,11 +8969,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     shifter_out = 1;
                     break;
                 }
-                tmp2 = new_tmp();
+                tmp2 = tcg_temp_new_i32();
                 tcg_gen_movi_i32(tmp2, imm);
                 rn = (insn >> 16) & 0xf;
                 if (rn == 15) {
-                    tmp = new_tmp();
+                    tmp = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp, 0);
                 } else {
                     tmp = load_reg(s, rn);
@@ -8264,12 +8982,12 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
                                        shifter_out, tmp, tmp2))
                     goto illegal_op;
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 rd = (insn >> 8) & 0xf;
                 if (rd != 15) {
                     store_reg(s, rd, tmp);
                 } else {
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                 }
             }
         }
@@ -8284,9 +9002,45 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 goto illegal_op;
             break;
         }
+        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
+        if (rs == 15) {
+            if (!(insn & (1 << 20))) {
+                goto illegal_op;
+            }
+            if (op != 2) {
+                /* Byte or halfword load space with dest == r15 : memory hints.
+                 * Catch them early so we don't emit pointless addressing code.
+                 * This space is a mix of:
+                 *  PLD/PLDW/PLI,  which we implement as NOPs (note that unlike
+                 *     the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
+                 *     cores)
+                 *  unallocated hints, which must be treated as NOPs
+                 *  UNPREDICTABLE space, which we NOP or UNDEF depending on
+                 *     which is easiest for the decoding logic
+                 *  Some space which must UNDEF
+                 */
+                int op1 = (insn >> 23) & 3;
+                int op2 = (insn >> 6) & 0x3f;
+                if (op & 2) {
+                    goto illegal_op;
+                }
+                if (rn == 15) {
+                    /* UNPREDICTABLE or unallocated hint */
+                    return 0;
+                }
+                if (op1 & 1) {
+                    return 0; /* PLD* or unallocated hint */
+                }
+                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
+                    return 0; /* PLD* or unallocated hint */
+                }
+                /* UNDEF space, or an UNPREDICTABLE */
+                return 1;
+            }
+        }
         user = IS_USER(s);
         if (rn == 15) {
-            addr = new_tmp();
+            addr = tcg_temp_new_i32();
             /* PC relative.  */
             /* s->pc has already been incremented by 4.  */
             imm = s->pc & 0xfffffffc;
@@ -8302,77 +9056,74 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 imm = insn & 0xfff;
                 tcg_gen_addi_i32(addr, addr, imm);
             } else {
-                op = (insn >> 8) & 7;
                 imm = insn & 0xff;
-                switch (op) {
-                case 0: case 8: /* Shifted Register.  */
+                switch ((insn >> 8) & 0xf) {
+                case 0x0: /* Shifted Register.  */
                     shift = (insn >> 4) & 0xf;
-                    if (shift > 3)
+                    if (shift > 3) {
+                        tcg_temp_free_i32(addr);
                         goto illegal_op;
+                    }
                     tmp = load_reg(s, rm);
                     if (shift)
                         tcg_gen_shli_i32(tmp, tmp, shift);
                     tcg_gen_add_i32(addr, addr, tmp);
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
                     break;
-                case 4: /* Negative offset.  */
+                case 0xc: /* Negative offset.  */
                     tcg_gen_addi_i32(addr, addr, -imm);
                     break;
-                case 6: /* User privilege.  */
+                case 0xe: /* User privilege.  */
                     tcg_gen_addi_i32(addr, addr, imm);
                     user = 1;
                     break;
-                case 1: /* Post-decrement.  */
+                case 0x9: /* Post-decrement.  */
                     imm = -imm;
                     /* Fall through.  */
-                case 3: /* Post-increment.  */
+                case 0xb: /* Post-increment.  */
                     postinc = 1;
                     writeback = 1;
                     break;
-                case 5: /* Pre-decrement.  */
+                case 0xd: /* Pre-decrement.  */
                     imm = -imm;
                     /* Fall through.  */
-                case 7: /* Pre-increment.  */
+                case 0xf: /* Pre-increment.  */
                     tcg_gen_addi_i32(addr, addr, imm);
                     writeback = 1;
                     break;
                 default:
+                    tcg_temp_free_i32(addr);
                     goto illegal_op;
                 }
             }
         }
-        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
         if (insn & (1 << 20)) {
             /* Load.  */
-            if (rs == 15 && op != 2) {
-                if (op & 2)
-                    goto illegal_op;
-                /* Memory hint.  Implemented as NOP.  */
+            switch (op) {
+            case 0: tmp = gen_ld8u(addr, user); break;
+            case 4: tmp = gen_ld8s(addr, user); break;
+            case 1: tmp = gen_ld16u(addr, user); break;
+            case 5: tmp = gen_ld16s(addr, user); break;
+            case 2: tmp = gen_ld32(addr, user); break;
+            default:
+                tcg_temp_free_i32(addr);
+                goto illegal_op;
+            }
+            if (rs == 15) {
+                gen_bx(s, tmp);
             } else {
-                switch (op) {
-                case 0: tmp = gen_ld8u(addr, user); break;
-                case 4: tmp = gen_ld8s(addr, user); break;
-                case 1: tmp = gen_ld16u(addr, user); break;
-                case 5: tmp = gen_ld16s(addr, user); break;
-                case 2: tmp = gen_ld32(addr, user); break;
-                default: goto illegal_op;
-                }
-                if (rs == 15) {
-                    gen_bx(s, tmp);
-                } else {
-                    store_reg(s, rs, tmp);
-                }
+                store_reg(s, rs, tmp);
             }
         } else {
             /* Store.  */
-            if (rs == 15)
-                goto illegal_op;
             tmp = load_reg(s, rs);
             switch (op) {
             case 0: gen_st8(tmp, addr, user); break;
             case 1: gen_st16(tmp, addr, user); break;
             case 2: gen_st32(tmp, addr, user); break;
-            default: goto illegal_op;
+            default:
+                tcg_temp_free_i32(addr);
+                goto illegal_op;
             }
         }
         if (postinc)
@@ -8380,7 +9131,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
         if (writeback) {
             store_reg(s, rn, addr);
         } else {
-            dead_tmp(addr);
+            tcg_temp_free_i32(addr);
         }
         }
         break;
@@ -8424,7 +9175,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, rn);
             if (insn & (1 << 10)) {
                 /* immediate */
-                tmp2 = new_tmp();
+                tmp2 = tcg_temp_new_i32();
                 tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
             } else {
                 /* reg */
@@ -8442,7 +9193,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 else
                     gen_helper_add_cc(tmp, tmp, tmp2);
             }
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp2);
             store_reg(s, rd, tmp);
         } else {
             /* shift immediate */
@@ -8460,27 +9211,27 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         op = (insn >> 11) & 3;
         rd = (insn >> 8) & 0x7;
         if (op == 0) { /* mov */
-            tmp = new_tmp();
+            tmp = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp, insn & 0xff);
             if (!s->condexec_mask)
                 gen_logic_CC(tmp);
             store_reg(s, rd, tmp);
         } else {
             tmp = load_reg(s, rd);
-            tmp2 = new_tmp();
+            tmp2 = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp2, insn & 0xff);
             switch (op) {
             case 1: /* cmp */
                 gen_helper_sub_cc(tmp, tmp, tmp2);
-                dead_tmp(tmp);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp);
+                tcg_temp_free_i32(tmp2);
                 break;
             case 2: /* add */
                 if (s->condexec_mask)
                     tcg_gen_add_i32(tmp, tmp, tmp2);
                 else
                     gen_helper_add_cc(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 store_reg(s, rd, tmp);
                 break;
             case 3: /* sub */
@@ -8488,7 +9239,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                     tcg_gen_sub_i32(tmp, tmp, tmp2);
                 else
                     gen_helper_sub_cc(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 store_reg(s, rd, tmp);
                 break;
             }
@@ -8500,10 +9251,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             /* load pc-relative.  Bit 1 of PC is ignored.  */
             val = s->pc + 2 + ((insn & 0xff) * 4);
             val &= ~(uint32_t)2;
-            addr = new_tmp();
+            addr = tcg_temp_new_i32();
             tcg_gen_movi_i32(addr, val);
             tmp = gen_ld32(addr, IS_USER(s));
-            dead_tmp(addr);
+            tcg_temp_free_i32(addr);
             store_reg(s, rd, tmp);
             break;
         }
@@ -8517,15 +9268,15 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 tmp = load_reg(s, rd);
                 tmp2 = load_reg(s, rm);
                 tcg_gen_add_i32(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
                 store_reg(s, rd, tmp);
                 break;
             case 1: /* cmp */
                 tmp = load_reg(s, rd);
                 tmp2 = load_reg(s, rm);
                 gen_helper_sub_cc(tmp, tmp, tmp2);
-                dead_tmp(tmp2);
-                dead_tmp(tmp);
+                tcg_temp_free_i32(tmp2);
+                tcg_temp_free_i32(tmp);
                 break;
             case 2: /* mov/cpy */
                 tmp = load_reg(s, rm);
@@ -8534,11 +9285,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 = new_tmp();
+                    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;
             }
@@ -8560,7 +9313,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         }
 
         if (op == 9) { /* neg */
-            tmp = new_tmp();
+            tmp = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp, 0);
         } else if (op != 0xf) { /* mvn doesn't read its first operand */
             tmp = load_reg(s, rd);
@@ -8671,14 +9424,14 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             if (val) {
                 store_reg(s, rm, tmp2);
                 if (op != 0xf)
-                    dead_tmp(tmp);
+                    tcg_temp_free_i32(tmp);
             } else {
                 store_reg(s, rd, tmp);
-                dead_tmp(tmp2);
+                tcg_temp_free_i32(tmp2);
             }
         } else {
-            dead_tmp(tmp);
-            dead_tmp(tmp2);
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
         }
         break;
 
@@ -8691,7 +9444,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         addr = load_reg(s, rn);
         tmp = load_reg(s, rm);
         tcg_gen_add_i32(addr, addr, tmp);
-        dead_tmp(tmp);
+        tcg_temp_free_i32(tmp);
 
         if (op < 3) /* store */
             tmp = load_reg(s, rd);
@@ -8724,7 +9477,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         }
         if (op >= 3) /* load */
             store_reg(s, rd, tmp);
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         break;
 
     case 6:
@@ -8744,7 +9497,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, rd);
             gen_st32(tmp, addr, IS_USER(s));
         }
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         break;
 
     case 7:
@@ -8764,7 +9517,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, rd);
             gen_st8(tmp, addr, IS_USER(s));
         }
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         break;
 
     case 8:
@@ -8784,7 +9537,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, rd);
             gen_st16(tmp, addr, IS_USER(s));
         }
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         break;
 
     case 9:
@@ -8803,7 +9556,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, rd);
             gen_st32(tmp, addr, IS_USER(s));
         }
-        dead_tmp(addr);
+        tcg_temp_free_i32(addr);
         break;
 
     case 10:
@@ -8814,7 +9567,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             tmp = load_reg(s, 13);
         } else {
             /* PC. bit 1 is ignored.  */
-            tmp = new_tmp();
+            tmp = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
         }
         val = (insn & 0xff) * 4;
@@ -8898,8 +9651,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 */
@@ -8911,7 +9665,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
             else
                 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
-            dead_tmp(tmp);
+            tcg_temp_free_i32(tmp);
             offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
             val = (uint32_t)s->pc + 2;
             val += offset;
@@ -8930,6 +9684,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             break;
 
         case 0xe: /* bkpt */
+            ARCH(5);
             gen_exception_insn(s, 2, EXCP_BKPT);
             break;
 
@@ -8982,7 +9737,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++) {
@@ -8990,7 +9748,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);
@@ -9000,14 +9762,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 {
-            dead_tmp(addr);
+            /* 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;
@@ -9076,8 +9842,6 @@ static inline void gen_intermediate_code_internal(CPUState *env,
     int max_insns;
 
     /* generate intermediate code */
-    num_temps = 0;
-
     pc_start = tb->pc;
 
     dc->tb = tb;
@@ -9114,6 +9878,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
 
     gen_icount_start();
 
+    tcg_clear_temp_count();
+
     /* A note on handling of the condexec (IT) bits:
      *
      * We want to avoid the overhead of having to write the updated condexec
@@ -9136,8 +9902,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
@@ -9149,7 +9915,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
        complications trying to do it at the end of the block.  */
     if (dc->condexec_mask || dc->condexec_cond)
       {
-        TCGv tmp = new_tmp();
+        TCGv tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, 0);
         store_cpu_field(tmp, condexec_bits);
       }
@@ -9218,15 +9984,16 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         } else {
             disas_arm_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;
         }
+
+        if (tcg_check_temp_count()) {
+            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
+        }
+
         /* 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
@@ -9401,8 +10168,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 d9087759d303ece8a915d56eb72d3f4b37dea0b0..453afbb66e080e6d40a9c5e42de48f69bb54cc47 100644 (file)
@@ -36,6 +36,9 @@
 #define EXCP_IRQ        4
 #define EXCP_BREAK      5
 
+/* CRIS-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+
 /* Register aliases. R0 - R15 */
 #define R_FP  8
 #define R_SP  14
@@ -64,6 +67,8 @@
 #define Q_FLAG 0x80000000
 #define M_FLAG 0x40000000
 #define PFIX_FLAG 0x800      /* CRISv10 Only.  */
+#define F_FLAG_V10 0x400
+#define P_FLAG_V10 0x200
 #define S_FLAG 0x200
 #define R_FLAG 0x100
 #define P_FLAG 0x80
@@ -101,7 +106,7 @@ typedef struct CPUCRISState {
        /* P0 - P15 are referred to as special registers in the docs.  */
        uint32_t pregs[16];
 
-       /* Pseudo register for the PC. Not directly accessable on CRIS.  */
+       /* Pseudo register for the PC. Not directly accessible on CRIS.  */
        uint32_t pc;
 
        /* Pseudo register for the kernel stack.  */
@@ -223,7 +228,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_cris_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
@@ -265,4 +270,15 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 #define cpu_list cris_cpu_list
 void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
 #endif
index 2a4403b847f0e7f5b4bb255059ac64a222c5e86d..5bc6d810cb64d13b9eb1df6fa1db4002f105a11e 100644 (file)
@@ -24,7 +24,6 @@
 #include "config.h"
 #include "cpu.h"
 #include "mmu.h"
-#include "exec-all.h"
 #include "host-utils.h"
 
 
@@ -48,7 +47,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                             int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
        env->exception_index = 0xaa;
        env->pregs[PR_EDA] = address;
@@ -69,7 +68,7 @@ static void cris_shift_ccs(CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
        struct cris_mmu_result res;
        int prot, miss;
@@ -105,10 +104,9 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 r = 0;
        }
        if (r > 0)
-               D_LOG("%s returns %d irqreq=%x addr=%x"
-                         " phy=%x ismmu=%d vec=%x pc=%x\n", 
-                         __func__, r, env->interrupt_request, 
-                         address, res.phy, is_softmmu, res.bf_vec, env->pc);
+            D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
+                  __func__, r, env->interrupt_request, address, res.phy,
+                  res.bf_vec, env->pc);
        return r;
 }
 
@@ -159,6 +157,7 @@ static void do_interruptv10(CPUState *env)
        /* Now that we are in kernel mode, load the handlers address.  */
        env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
        env->locked_irq = 1;
+       env->pregs[PR_CCS] |= F_FLAG_V10; /* set F.  */
 
        qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 
                      __func__, env->pc, ex_vec, 
index 1243745598e6f6914529ae0af07a42b9d4ae0457..d481e39352d282be7d03cc64b5f9f4418d069806 100644 (file)
@@ -27,7 +27,6 @@
 #include "config.h"
 #include "cpu.h"
 #include "mmu.h"
-#include "exec-all.h"
 
 #ifdef DEBUG
 #define D(x) x
index be9eb06fd06a29fd19e4e2bd3db2cc13d2dde281..1eacc5fd7f91a44ff310ed11e7d5b9010486061e 100644 (file)
@@ -18,7 +18,8 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "mmu.h"
 #include "helper.h"
 #include "host-utils.h"
@@ -35,6 +36,7 @@
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
 
 #define MMUSUFFIX _mmu
 
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__, 
             env->pc, env->debug1, retaddr);
-    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
@@ -77,13 +78,13 @@ 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();
             }
         }
-        cpu_loop_exit();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
@@ -93,7 +94,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 void helper_raise_exception(uint32_t index)
 {
        env->exception_index = index;
-       cpu_loop_exit();
+        cpu_loop_exit(env);
 }
 
 void helper_tlb_flush_pid(uint32_t pid)
index 8d4749debef695b85c6b1a1e76225e3d036629e2..779d4aab7042dd1bd512dbde088e0146f77d768f 100644 (file)
@@ -29,8 +29,8 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 /* Registers.  */
 #define MAX_REG (15)
-#define REG_SP (14)
-#define REG_PC (15)
+#define CRIS_REG_SP (14)
+#define CRIS_REG_PC (15)
 
 /* CPU version control of disassembly and assembly of instructions.
    May affect how the instruction is assembled, at least the size of
@@ -138,7 +138,7 @@ extern const struct cris_cond15 cris_conds15[];
 
 #define BDAP_INDIR_OPCODE (BDAP_INDIR_HIGH * 0x0100 + BDAP_INDIR_LOW)
 #define BDAP_INDIR_Z_BITS (BDAP_INDIR_HIGH_Z * 0x100 + BDAP_INDIR_LOW_Z)
-#define BDAP_PC_LOW      (BDAP_INDIR_LOW + REG_PC)
+#define BDAP_PC_LOW      (BDAP_INDIR_LOW + CRIS_REG_PC)
 #define BDAP_INCR_HIGH   (BDAP_INDIR_HIGH + AUTOINCR_BIT)
 
 /* No prefix must have this code for its "match" bits in the
@@ -192,16 +192,16 @@ extern const char *const cris_cc_strings[];
 #define JUMP_INDIR_OPCODE (0x0930)
 #define JUMP_INDIR_Z_BITS (0xf2c0)
 #define JUMP_PC_INCR_OPCODE \
- (JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + REG_PC)
+ (JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + CRIS_REG_PC)
 
 #define MOVE_M_TO_PREG_OPCODE 0x0a30
 #define MOVE_M_TO_PREG_ZBITS 0x01c0
 
 /* BDAP.D N,PC.  */
 #define MOVE_PC_INCR_OPCODE_PREFIX \
- (((BDAP_INCR_HIGH | (REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4))
+ (((BDAP_INCR_HIGH | (CRIS_REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4))
 #define MOVE_PC_INCR_OPCODE_SUFFIX \
- (MOVE_M_TO_PREG_OPCODE | REG_PC | (AUTOINCR_BIT << 8))
+ (MOVE_M_TO_PREG_OPCODE | CRIS_REG_PC | (AUTOINCR_BIT << 8))
 
 #define JUMP_PC_INCR_OPCODE_V32 (0x0DBF)
 
index b4648a01dee396d47051027a303ea63384d09a0a..70abf8a095efed4fb9f5c44f8873a7ab99a63aa6 100644 (file)
@@ -30,7 +30,6 @@
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "helper.h"
@@ -596,7 +595,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);
@@ -3517,7 +3516,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
        static int tcg_initialized = 0;
        int i;
 
-       env = qemu_mallocz(sizeof(CPUCRISState));
+       env = g_malloc0(sizeof(CPUCRISState));
 
        env->pregs[PR_VR] = vr_by_name(cpu_model);
        cpu_exec_init(env);
@@ -3604,8 +3603,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 41db158965fd38c5b2219bb9f1318841a604f2b2..95053b64fbe322063b598f539d9027519be518bc 100644 (file)
@@ -62,6 +62,65 @@ static inline void cris_illegal_insn(DisasContext *dc)
     t_gen_raise_exception(EXCP_BREAK);
 }
 
+static void gen_store_v10_conditional(DisasContext *dc, TCGv addr, TCGv val,
+                       unsigned int size, int mem_index)
+{
+    int l1 = gen_new_label();
+    TCGv taddr = tcg_temp_local_new();
+    TCGv tval = tcg_temp_local_new();
+    TCGv t1 = tcg_temp_local_new();
+    dc->postinc = 0;
+    cris_evaluate_flags(dc);
+
+    tcg_gen_mov_tl(taddr, addr);
+    tcg_gen_mov_tl(tval, val);
+
+    /* Store only if F flag isn't set */
+    tcg_gen_andi_tl(t1, cpu_PR[PR_CCS], F_FLAG_V10);
+    tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+    if (size == 1) {
+        tcg_gen_qemu_st8(tval, taddr, mem_index);
+    } else if (size == 2) {
+        tcg_gen_qemu_st16(tval, taddr, mem_index);
+    } else {
+        tcg_gen_qemu_st32(tval, taddr, mem_index);
+    }
+    gen_set_label(l1);
+    tcg_gen_shri_tl(t1, t1, 1);  /* shift F to P position */
+    tcg_gen_or_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], t1); /*P=F*/
+    tcg_temp_free(t1);
+    tcg_temp_free(tval);
+    tcg_temp_free(taddr);
+}
+
+static void gen_store_v10(DisasContext *dc, TCGv addr, TCGv val,
+                       unsigned int size)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+
+    /* If we get a fault on a delayslot we must keep the jmp state in
+       the cpu-state to be able to re-execute the jmp.  */
+    if (dc->delayed_branch == 1) {
+        cris_store_direct_jmp(dc);
+    }
+
+    /* Conditional writes. We only support the kind were X is known
+       at translation time.  */
+    if (dc->flagx_known && dc->flags_x) {
+        gen_store_v10_conditional(dc, addr, val, size, mem_index);
+        return;
+    }
+
+    if (size == 1) {
+        tcg_gen_qemu_st8(val, addr, mem_index);
+    } else if (size == 2) {
+        tcg_gen_qemu_st16(val, addr, mem_index);
+    } else {
+        tcg_gen_qemu_st32(val, addr, mem_index);
+    }
+}
+
+
 /* Prefix flag and register are used to handle the more complex
    addressing modes.  */
 static void cris_set_prefix(DisasContext *dc)
@@ -262,9 +321,6 @@ static unsigned int dec10_quick_imm(DisasContext *dc)
             break;
 
         case CRISV10_QIMM_BCC_R0:
-            if (!dc->ir) {
-                cpu_abort(dc->env, "opcode zero\n");
-            }
         case CRISV10_QIMM_BCC_R1:
         case CRISV10_QIMM_BCC_R2:
         case CRISV10_QIMM_BCC_R3:
@@ -316,7 +372,8 @@ static unsigned int dec10_setclrf(DisasContext *dc)
     if (set) {
         tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
     } else {
-        tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
+        tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS],
+                        ~(flags|F_FLAG_V10|P_FLAG_V10));
     }
 
     dc->flags_uptodate = 1;
@@ -726,7 +783,7 @@ static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size)
     LOG_DIS("move.%d $r%d, [$r%d]\n", dc->size, dc->src, dc->dst);
     addr = tcg_temp_new();
     crisv10_prepare_memaddr(dc, addr, size);
-    gen_store(dc, addr, cpu_R[dc->dst], size);
+    gen_store_v10(dc, addr, cpu_R[dc->dst], size);
     insn_len += crisv10_post_memaddr(dc, size);
 
     return insn_len;
@@ -770,10 +827,10 @@ static unsigned int dec10_ind_move_pr_m(DisasContext *dc)
         t0 = tcg_temp_new();
         cris_evaluate_flags(dc);
         tcg_gen_andi_tl(t0, cpu_PR[PR_CCS], ~PFIX_FLAG);
-        gen_store(dc, addr, t0, size);
+        gen_store_v10(dc, addr, t0, size);
         tcg_temp_free(t0);
     } else {
-        gen_store(dc, addr, cpu_PR[dc->dst], size);
+        gen_store_v10(dc, addr, cpu_PR[dc->dst], size);
     }
     t0 = tcg_temp_new();
     insn_len += crisv10_post_memaddr(dc, size);
@@ -796,9 +853,9 @@ static void dec10_movem_r_m(DisasContext *dc)
     tcg_gen_mov_tl(t0, addr);
     for (i = dc->dst; i >= 0; i--) {
         if ((pfix && dc->mode == CRISV10_MODE_AUTOINC) && dc->src == i) {
-            gen_store(dc, addr, t0, 4);
+            gen_store_v10(dc, addr, t0, 4);
         } else {
-            gen_store(dc, addr, cpu_R[i], 4);
+            gen_store_v10(dc, addr, cpu_R[i], 4);
         }
         tcg_gen_addi_tl(addr, addr, 4);
     }
@@ -956,7 +1013,7 @@ static int dec10_bdap_m(DisasContext *dc, int size)
         return insn_len;
     }
 #endif
-    /* Now the rest of the modes are truely indirect.  */
+    /* Now the rest of the modes are truly indirect.  */
     insn_len += dec10_prep_move_m(dc, 1, size, cpu_PR[PR_PREFIX]);
     tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_PR[PR_PREFIX], cpu_R[rd]);
     cris_set_prefix(dc);
index af701a441229a0cfec0ad36506ec1240844597f4..a08ce9d8734d07314d190ef2b4382ef25a69564e 100644 (file)
 #define MSR_IA32_APICBASE_BSP           (1<<8)
 #define MSR_IA32_APICBASE_ENABLE        (1<<11)
 #define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+#define MSR_IA32_TSCDEADLINE            0x6e0
 
 #define MSR_MTRRcap                    0xfe
 #define MSR_MTRRcap_VCNT               8
 
 #define MSR_IA32_PERF_STATUS            0x198
 
+#define MSR_IA32_MISC_ENABLE           0x1a0
+/* Indicates good rep/movs microcode on some processors: */
+#define MSR_IA32_MISC_ENABLE_DEFAULT    1
+
 #define MSR_MTRRphysBase(reg)          (0x200 + 2 * (reg))
 #define MSR_MTRRphysMask(reg)          (0x200 + 2 * (reg) + 1)
 
 #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
 
 #define CPUID_VENDOR_AMD_1   0x68747541 /* "Auth" */
-#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */ 
+#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */
 #define CPUID_VENDOR_AMD_3   0x444d4163 /* "cAMD" */
 
+#define CPUID_VENDOR_VIA_1   0x746e6543 /* "Cent" */
+#define CPUID_VENDOR_VIA_2   0x48727561 /* "aurH" */
+#define CPUID_VENDOR_VIA_3   0x736c7561 /* "auls" */
+
 #define CPUID_MWAIT_IBE     (1 << 1) /* Interrupts can exit capability */
 #define CPUID_MWAIT_EMX     (1 << 0) /* enumeration supported */
 
 #define EXCP_SYSCALL    0x100 /* only happens in user only emulation
                                  for syscall instruction */
 
+/* i386-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_SMI       CPU_INTERRUPT_TGT_EXT_2
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+#define CPU_INTERRUPT_MCE       CPU_INTERRUPT_TGT_EXT_4
+#define CPU_INTERRUPT_VIRQ      CPU_INTERRUPT_TGT_INT_0
+#define CPU_INTERRUPT_INIT      CPU_INTERRUPT_TGT_INT_1
+#define CPU_INTERRUPT_SIPI      CPU_INTERRUPT_TGT_INT_2
+
+
 enum {
     CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
     CC_OP_EFLAGS,  /* all cc are explicitly computed, CC_SRC = flags */
@@ -523,16 +541,6 @@ enum {
     CC_OP_NB,
 };
 
-#ifdef FLOATX80
-#define USE_X86LDOUBLE
-#endif
-
-#ifdef USE_X86LDOUBLE
-typedef floatx80 CPU86_LDouble;
-#else
-typedef float64 CPU86_LDouble;
-#endif
-
 typedef struct SegmentCache {
     uint32_t selector;
     target_ulong base;
@@ -585,11 +593,7 @@ typedef union {
 #define MMX_Q(n) q
 
 typedef union {
-#ifdef USE_X86LDOUBLE
-    CPU86_LDouble d __attribute__((aligned(16)));
-#else
-    CPU86_LDouble d;
-#endif
+    floatx80 d __attribute__((aligned(16)));
     MMXReg mmx;
 } FPReg;
 
@@ -642,10 +646,14 @@ typedef struct CPUX86State {
     uint16_t fpuc;
     uint8_t fptags[8];   /* 0 = valid, 1 = empty */
     FPReg fpregs[8];
+    /* KVM-only so far */
+    uint16_t fpop;
+    uint64_t fpip;
+    uint64_t fpdp;
 
     /* emulator internal variables */
     float_status fp_status;
-    CPU86_LDouble ft0;
+    floatx80 ft0;
 
     float_status mmx_status; /* for 3DNow! float ops */
     float_status sse_status;
@@ -684,8 +692,10 @@ typedef struct CPUX86State {
     uint64_t async_pf_en_msr;
 
     uint64_t tsc;
+    uint64_t tsc_deadline;
 
-    uint64_t pat;
+    uint64_t mcg_status;
+    uint64_t msr_ia32_misc_enable;
 
     /* exception/interrupt handling */
     int error_code;
@@ -705,6 +715,8 @@ typedef struct CPUX86State {
 
     CPU_COMMON
 
+    uint64_t pat;
+
     /* processor features (e.g. for CPUID insn) */
     uint32_t cpuid_level;
     uint32_t cpuid_vendor1;
@@ -719,6 +731,9 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext3_features;
     uint32_t cpuid_apic_id;
     int cpuid_vendor_override;
+    /* Store the results of Centaur's CPUID instructions */
+    uint32_t cpuid_xlevel2;
+    uint32_t cpuid_ext4_features;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
@@ -734,13 +749,14 @@ typedef struct CPUX86State {
     uint32_t sipi_vector;
     uint32_t cpuid_kvm_features;
     uint32_t cpuid_svm_features;
+    bool tsc_valid;
+    int tsc_khz;
     
     /* in order to simplify APIC support, we leave this pointer to the
        user */
     struct DeviceState *apic_state;
 
     uint64_t mcg_cap;
-    uint64_t mcg_status;
     uint64_t mcg_ctl;
     uint64_t mce_banks[MCE_BANKS_DEF*4];
 
@@ -854,8 +870,8 @@ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
 
 /* op_helper.c */
 /* used for debug or cpu save/restore */
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f);
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper);
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
 
 /* cpu-exec.c */
 /* the following helpers are only usable in user mode simulation as
@@ -881,7 +897,7 @@ void host_cpuid(uint32_t function, uint32_t count,
 
 /* helper.c */
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write, int mmu_idx, int is_softmmu);
+                             int is_write, int mmu_idx);
 #define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
 void cpu_x86_set_a20(CPUX86State *env, int a20_state);
 
@@ -949,14 +965,39 @@ static inline int cpu_mmu_index (CPUState *env)
     return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
 }
 
+#undef EAX
+#define EAX (env->regs[R_EAX])
+#undef ECX
+#define ECX (env->regs[R_ECX])
+#undef EDX
+#define EDX (env->regs[R_EDX])
+#undef EBX
+#define EBX (env->regs[R_EBX])
+#undef ESP
+#define ESP (env->regs[R_ESP])
+#undef EBP
+#define EBP (env->regs[R_EBP])
+#undef ESI
+#define ESI (env->regs[R_ESI])
+#undef EDI
+#define EDI (env->regs[R_EDI])
+#undef EIP
+#define EIP (env->eip)
+#define DF  (env->df)
+
+#define CC_SRC (env->cc_src)
+#define CC_DST (env->cc_dst)
+#define CC_OP  (env->cc_op)
+
+/* float macros */
+#define FT0    (env->ft0)
+#define ST0    (env->fpregs[env->fpstt].d)
+#define ST(n)  (env->fpregs[(env->fpstt + (n)) & 7].d)
+#define ST1    ST(1)
+
 /* translate.c */
 void optimize_flags_init(void);
 
-typedef struct CCTable {
-    int (*compute_all)(void); /* return all the flags */
-    int (*compute_c)(void);  /* return the C flag */
-} CCTable;
-
 #if defined(CONFIG_USER_ONLY)
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
@@ -973,6 +1014,23 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #include "hw/apic.h"
 #endif
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->eflags & IF_MASK)) ||
+           (env->interrupt_request & (CPU_INTERRUPT_NMI |
+                                      CPU_INTERRUPT_INIT |
+                                      CPU_INTERRUPT_SIPI |
+                                      CPU_INTERRUPT_MCE));
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->eip = tb->pc - tb->cs_base;
+}
+
 static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
                                         target_ulong *cs_base, int *flags)
 {
@@ -984,4 +1042,25 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 
 void do_cpu_init(CPUState *env);
 void do_cpu_sipi(CPUState *env);
+
+#define MCE_INJECT_BROADCAST    1
+#define MCE_INJECT_UNCOND_AO    2
+
+void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
+                        uint64_t status, uint64_t mcg_status, uint64_t addr,
+                        uint64_t misc, int flags);
+
+/* op_helper.c */
+void do_interrupt(CPUState *env);
+void do_interrupt_x86_hardirq(CPUState *env, int intno, int is_hw);
+void QEMU_NORETURN raise_exception_env(int exception_index, CPUState *nenv);
+void QEMU_NORETURN raise_exception_err_env(CPUState *nenv, int exception_index,
+                                           int error_code);
+
+void do_smm_enter(CPUState *env1);
+
+void svm_check_intercept(CPUState *env1, uint32_t type);
+
+uint32_t cpu_cc_compute_all(CPUState *env1, int op);
+
 #endif /* CPU_I386_H */
index 5382a283f59c46efebde0acea9eb6b70057b235e..0b3af9060ce5c6149a168662051477b6781ed3fd 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,
@@ -222,12 +224,16 @@ typedef struct x86_def_t {
     int family;
     int model;
     int stepping;
+    int tsc_khz;
     uint32_t features, ext_features, ext2_features, ext3_features;
     uint32_t kvm_features, svm_features;
     uint32_t xlevel;
     char model_id[48];
     int vendor_override;
     uint32_t flags;
+    /* Store the results of Centaur's CPUID instructions */
+    uint32_t ext4_features;
+    uint32_t xlevel2;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -520,6 +526,18 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
     cpu_x86_fill_model_id(x86_cpu_def->model_id);
     x86_cpu_def->vendor_override = 0;
 
+    /* Call Centaur's CPUID instruction. */
+    if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+        x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+        x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+        host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+        if (eax >= 0xC0000001) {
+            /* Support VIA max extended level */
+            x86_cpu_def->xlevel2 = eax;
+            host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+            x86_cpu_def->ext4_features = edx;
+        }
+    }
 
     /*
      * Every SVM feature requires emulation support in KVM - so we can't just
@@ -582,7 +600,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
     unsigned int i;
     x86_def_t *def;
 
-    char *s = strdup(cpu_model);
+    char *s = g_strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
     /* Features to be added*/
     uint32_t plus_features = 0, plus_ext_features = 0;
@@ -595,9 +613,9 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
     uint32_t numvalue;
 
     for (def = x86_defs; def; def = def->next)
-        if (!strcmp(name, def->name))
+        if (name && !strcmp(name, def->name))
             break;
-    if (kvm_enabled() && strcmp(name, "host") == 0) {
+    if (kvm_enabled() && name && strcmp(name, "host") == 0) {
         cpu_x86_fill_host(x86_cpu_def);
     } else if (!def) {
         goto error;
@@ -687,6 +705,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
             } else if (!strcmp(featurestr, "model_id")) {
                 pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
                         val);
+            } else if (!strcmp(featurestr, "tsc_freq")) {
+                int64_t tsc_freq;
+                char *err;
+
+                tsc_freq = strtosz_suffix_unit(val, &err,
+                                               STRTOSZ_DEFSUFFIX_B, 1000);
+                if (tsc_freq < 0 || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -717,11 +746,11 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
             goto error;
     }
-    free(s);
+    g_free(s);
     return 0;
 
 error:
-    free(s);
+    g_free(s);
     return -1;
 }
 
@@ -847,13 +876,15 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16);
     env->cpuid_version |= def->stepping;
     env->cpuid_features = def->features;
-    env->pat = 0x0007040600070406ULL;
     env->cpuid_ext_features = def->ext_features;
     env->cpuid_ext2_features = def->ext2_features;
     env->cpuid_ext3_features = def->ext3_features;
     env->cpuid_xlevel = def->xlevel;
     env->cpuid_kvm_features = def->kvm_features;
     env->cpuid_svm_features = def->svm_features;
+    env->cpuid_ext4_features = def->ext4_features;
+    env->cpuid_xlevel2 = def->xlevel2;
+    env->tsc_khz = def->tsc_khz;
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
         env->cpuid_ext_features &= TCG_EXT_FEATURES;
@@ -938,7 +969,8 @@ static int cpudef_setfield(const char *name, const char *str, void *opaque)
     int err = 0;
 
     if (!strcmp(name, "name")) {
-        def->name = strdup(str);
+        g_free((void *)def->name);
+        def->name = g_strdup(str);
     } else if (!strcmp(name, "model_id")) {
         strncpy(def->model_id, str, sizeof (def->model_id));
     } else if (!strcmp(name, "level")) {
@@ -978,7 +1010,7 @@ static int cpudef_setfield(const char *name, const char *str, void *opaque)
  */
 static int cpudef_register(QemuOpts *opts, void *opaque)
 {
-    x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
+    x86_def_t *def = g_malloc0(sizeof (x86_def_t));
 
     qemu_opt_foreach(opts, cpudef_setfield, def, 1);
     def->next = x86_defs;
@@ -1034,8 +1066,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
 {
     /* test if maximum index reached */
     if (index & 0x80000000) {
-        if (index > env->cpuid_xlevel)
-            index = env->cpuid_level;
+        if (index > env->cpuid_xlevel) {
+            if (env->cpuid_xlevel2 > 0) {
+                /* Handle the Centaur's CPUID instruction. */
+                if (index > env->cpuid_xlevel2) {
+                    index = env->cpuid_xlevel2;
+                } else if (index < 0xC0000000) {
+                    index = env->cpuid_xlevel;
+                }
+            } else {
+                index =  env->cpuid_xlevel;
+            }
+        }
     } else {
         if (index > env->cpuid_level)
             index = env->cpuid_level;
@@ -1114,6 +1156,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *ecx = 0;
         *edx = 0;
         break;
+    case 7:
+        if (kvm_enabled()) {
+            KVMState *s = env->kvm_state;
+
+            *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
+            *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
+            *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
+            *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
+        } else {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+        }
+        break;
     case 9:
         /* Direct Cache Access Information Leaf */
         *eax = 0; /* Bits 0-31 in DCA_CAP MSR */
@@ -1138,10 +1195,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
             break;
         }
         if (kvm_enabled()) {
-            *eax = kvm_arch_get_supported_cpuid(env, 0xd, count, R_EAX);
-            *ebx = kvm_arch_get_supported_cpuid(env, 0xd, count, R_EBX);
-            *ecx = kvm_arch_get_supported_cpuid(env, 0xd, count, R_ECX);
-            *edx = kvm_arch_get_supported_cpuid(env, 0xd, count, R_EDX);
+            KVMState *s = env->kvm_state;
+
+            *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX);
+            *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX);
+            *ecx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_ECX);
+            *edx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EDX);
         } else {
             *eax = 0;
             *ebx = 0;
@@ -1230,6 +1289,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                *edx = 0;
        }
         break;
+    case 0xC0000000:
+        *eax = env->cpuid_xlevel2;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0xC0000001:
+        /* Support for VIA CPU's CPUID instruction */
+        *eax = env->cpuid_version;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = env->cpuid_ext4_features;
+        break;
+    case 0xC0000002:
+    case 0xC0000003:
+    case 0xC0000004:
+        /* Reserved for the future, and now filled with zero */
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
     default:
         /* reserved values: zero */
         *eax = 0;
diff --git a/target-i386/hax-all.c b/target-i386/hax-all.c
new file mode 100644 (file)
index 0000000..6c3354a
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ * HAX common code for both windows and darwin
+ * some code from KVM side
+ */
+
+#include "target-i386/hax-i386.h"
+
+#define HAX_EMUL_ONE    0x1
+#define HAX_EMUL_REAL   0x2
+#define HAX_EMUL_HLT    0x4
+#define HAX_EMUL_EXITLOOP    0x5
+
+#define HAX_EMULATE_STATE_MMIO  0x1
+#define HAX_EMULATE_STATE_REAL  0x2
+#define HAX_EMULATE_STATE_NONE  0x3
+#define HAX_EMULATE_STATE_INITIAL       0x4
+
+struct hax_state hax_global;
+
+int hax_support = -1;
+
+/* Called after hax_init */
+int hax_enabled(void)
+{
+    return (!hax_disabled && hax_support);
+}
+
+/* Currently non-PG modes are emulated by QEMU */
+int hax_vcpu_emulation_mode(CPUState *env)
+{
+    return !(env->cr[0] & CR0_PG_MASK);
+}
+
+static int hax_prepare_emulation(CPUState *env)
+{
+    /* Flush all emulation states */
+    tlb_flush(env, 1);
+    tb_flush(env);
+    /* Sync the vcpu state from hax kernel module */
+    hax_vcpu_sync_state(env, 0);
+    return 0;
+}
+
+/*
+ * Check whether to break the translation block loop
+ * break tbloop after one MMIO emulation, or after finish emulation mode
+ */
+static int hax_stop_tbloop(CPUState *env)
+{
+    switch (env->hax_vcpu->emulation_state)
+    {
+        case HAX_EMULATE_STATE_MMIO:
+            return 1;
+            break;
+        case HAX_EMULATE_STATE_INITIAL:
+        case HAX_EMULATE_STATE_REAL:
+            if (!hax_vcpu_emulation_mode(env))
+                return 1;
+            break;
+        default:
+            dprint("Invalid emulation state in hax_sto_tbloop state %x\n",
+              env->hax_vcpu->emulation_state);
+            break;
+    }
+
+    return 0;
+}
+
+int hax_stop_emulation(CPUState *env)
+{
+    if (hax_stop_tbloop(env))
+    {
+        env->hax_vcpu->emulation_state =  HAX_EMULATE_STATE_NONE;
+        /*
+         * QEMU emulation changes vcpu state,
+         * Sync the vcpu state to HAX kernel module
+         */
+        hax_vcpu_sync_state(env, 1);
+        return 1;
+    }
+
+    return 0;
+}
+
+int hax_stop_translate(CPUState *env)
+{
+    struct hax_vcpu_state *vstate;
+
+    vstate = env->hax_vcpu;
+    assert(vstate->emulation_state);
+    if (vstate->emulation_state == HAX_EMULATE_STATE_MMIO )
+        return 1;
+
+    return 0;
+}
+
+int valid_hax_tunnel_size(uint16_t size)
+{
+    return size >= sizeof(struct hax_tunnel);
+}
+
+hax_fd hax_vcpu_get_fd(CPUState *env)
+{
+    struct hax_vcpu_state *vcpu = env->hax_vcpu;
+    if (!vcpu)
+        return HAX_INVALID_FD;
+    return vcpu->fd;
+}
+
+/* Current version */
+uint32_t hax_cur_version = 0x1;
+/* Least HAX kernel version */
+uint32_t hax_lest_version = 0x1;
+
+static int hax_get_capability(struct hax_state *hax)
+{
+       int ret;
+       struct hax_capabilityinfo capinfo, *cap = &capinfo;
+
+       ret = hax_capability(hax, cap);
+       if (ret)
+               return ret;
+
+       if ( ((cap->wstatus & HAX_CAP_WORKSTATUS_MASK) ==
+            HAX_CAP_STATUS_NOTWORKING ))
+       {
+               if (cap->winfo & HAX_CAP_FAILREASON_VT)
+                       dprint("VTX feature is not enabled. which will cause HAX driver not working.\n");
+               else if (cap->winfo & HAX_CAP_FAILREASON_NX)
+                       dprint("NX feature is not enabled, which will cause HAX driver not working.\n");
+               return -ENXIO;
+       }
+
+       if (cap->wstatus & HAX_CAP_MEMQUOTA)
+       {
+               if (cap->mem_quota < hax->mem_quota)
+               {
+                       dprint("The memory needed by this VM exceeds the driver limit.\n");
+                       return -ENOSPC;
+               }
+       }
+       return 0;
+}
+
+static int hax_version_support(struct hax_state *hax)
+{
+    int ret;
+    struct hax_module_version version;
+
+    ret = hax_mod_version(hax, &version);
+    if (ret < 0)
+        return 0;
+
+    if ( (hax_lest_version > version.cur_version) ||
+         (hax_cur_version < version.compat_version) )
+        return 0;
+
+    return 1;
+}
+
+int hax_vcpu_create(int id)
+{
+    struct hax_vcpu_state *vcpu = NULL;
+    int ret;
+
+    if (!hax_global.vm)
+    {
+        dprint("vcpu %x created failed, vm is null\n", id);
+        return -1;
+    }
+
+    if (hax_global.vm->vcpus[id])
+    {
+        dprint("vcpu %x allocated already\n", id);
+        return 0;
+    }
+
+    vcpu = g_malloc(sizeof(struct hax_vcpu_state));
+    if (!vcpu)
+    {
+        dprint("Failed to alloc vcpu state\n");
+        return -ENOMEM;
+    }
+
+    memset(vcpu, 0, sizeof(struct hax_vcpu_state));
+
+    ret = hax_host_create_vcpu(hax_global.vm->fd, id);
+    if (ret)
+    {
+        dprint("Failed to create vcpu %x\n", id);
+        goto error;
+    }
+
+    vcpu->fd = hax_host_open_vcpu(hax_global.vm->id, id);
+    if (hax_invalid_fd(vcpu->fd))
+    {
+        dprint("Failed to open the vcpu\n");
+        ret = -ENODEV;
+        goto error;
+    }
+
+    hax_global.vm->vcpus[id] = vcpu;
+
+    ret = hax_host_setup_vcpu_channel(vcpu);
+    if (ret)
+    {
+        dprint("Invalid hax tunnel size \n");
+        ret = -EINVAL;
+        goto error;
+    }
+    return 0;
+
+error:
+    /* vcpu and tunnel will be closed automatically */
+    if (vcpu && !hax_invalid_fd(vcpu->fd))
+        hax_close_fd(vcpu->fd);
+
+    hax_global.vm->vcpus[id] = NULL;
+    g_free(vcpu);
+    return -1;
+}
+
+int hax_vcpu_destroy(CPUState *env)
+{
+    struct hax_vcpu_state *vcpu = env->hax_vcpu;
+
+    if (!hax_global.vm)
+    {
+        dprint("vcpu %x destroy failed, vm is null\n", vcpu->vcpu_id);
+        return -1;
+    }
+
+    if (!vcpu)
+        return 0;
+
+    /*
+     * 1. The hax_tunnel is also destroied when vcpu destroy
+     * 2. close fd will cause hax module vcpu be cleaned
+     */
+    hax_close_fd(vcpu->fd);
+    hax_global.vm->vcpus[vcpu->vcpu_id] = NULL;
+    g_free(vcpu);
+    return 0;
+}
+
+int hax_init_vcpu(CPUState *env)
+{
+    int ret;
+
+    ret = hax_vcpu_create(env->cpu_index);
+    if (ret < 0)
+    {
+        dprint("Failed to create HAX vcpu\n");
+        exit(-1);
+    }
+
+    env->hax_vcpu = hax_global.vm->vcpus[env->cpu_index];
+    env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_INITIAL;
+    env->hax_vcpu_dirty = 1;
+    qemu_register_reset(hax_reset_vcpu_state, env);
+
+    return ret;
+}
+
+struct hax_vm *hax_vm_create(struct hax_state *hax)
+{
+    struct hax_vm *vm;
+    int vm_id = 0, ret;
+    char *vm_name = NULL;
+
+    if (hax_invalid_fd(hax->fd))
+        return NULL;
+
+    if (hax->vm)
+        return hax->vm;
+
+    vm = g_malloc(sizeof(struct hax_vm));
+    if (!vm)
+        return NULL;
+    memset(vm, 0, sizeof(struct hax_vm));
+    ret = hax_host_create_vm(hax, &vm_id);
+    if (ret) {
+        dprint("Failed to create vm %x\n", ret);
+        goto error;
+    }
+    vm->id = vm_id;
+    vm->fd = hax_host_open_vm(hax, vm_id);
+    if (hax_invalid_fd(vm->fd))
+    {
+        dprint("Open the vm devcie error:%s\n", vm_name);
+        goto error;
+    }
+
+    hax->vm = vm;
+    dprint("End of VM create, id %d\n", vm->id);
+    return vm;
+
+error:
+    g_free(vm);
+    hax->vm = NULL;
+    return NULL;
+}
+
+int hax_vm_destroy(struct hax_vm *vm)
+{
+    int i;
+
+    for (i = 0; i < HAX_MAX_VCPU; i++)
+        if (vm->vcpus[i])
+        {
+            dprint("VCPU should be cleaned before vm clean\n");
+            return -1;
+        }
+    hax_close_fd(vm->fd);
+    g_free(vm);
+    hax_global.vm = NULL;
+    return 0;
+}
+
+static void hax_client_set_memory(struct CPUPhysMemoryClient *client,
+                                  target_phys_addr_t start_addr,
+                                  ram_addr_t size, ram_addr_t phys_offset,
+                                  bool log_dirty)
+{
+    hax_set_phys_mem(start_addr, size, phys_offset);
+}
+
+/* currently we fake the dirty bitmap sync, always dirty */
+
+static int hax_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+                                        target_phys_addr_t start_addr,
+                                        target_phys_addr_t end_addr)
+{
+    ram_addr_t size = end_addr - start_addr;
+    ram_addr_t ram_addr;
+    unsigned long page_number, addr, c;
+    unsigned int len = ((size /TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) /
+                       HOST_LONG_BITS;
+    unsigned long bitmap[len];
+    unsigned long map;
+    int i, j;
+
+
+    for (i = 0; i < len; i++) {
+       map = bitmap[i] = 1;
+       c = leul_to_cpu(bitmap[i]);
+       do {
+           j = ffsl(c) - 1;
+           c &= ~(1ul << j);
+           page_number = i * HOST_LONG_BITS + j;
+           addr = page_number * TARGET_PAGE_SIZE;
+           ram_addr = cpu_get_physical_page_desc(addr);
+           cpu_physical_memory_set_dirty(ram_addr);
+       } while (c != 0);
+    }
+
+    return 0;
+}
+
+static int hax_client_migration_log(struct CPUPhysMemoryClient *client,
+                                    int enable)
+{
+    return 0;
+}
+
+static int hax_log_start(CPUPhysMemoryClient *client,
+                         target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    return 0;
+}
+
+static int hax_log_stop(CPUPhysMemoryClient *client,
+                        target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    return 0;
+}
+
+static CPUPhysMemoryClient hax_cpu_phys_memory_client = {
+    .set_memory = hax_client_set_memory,
+    .sync_dirty_bitmap = hax_client_sync_dirty_bitmap,
+    .migration_log = hax_client_migration_log,
+    .log_start = hax_log_start,
+    .log_stop = hax_log_stop,
+};
+
+static void hax_handle_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+
+    if (!qemu_cpu_is_self(env)) {
+        qemu_cpu_kick(env);
+    }
+}
+
+int hax_pre_init(ram_addr_t ram_size)
+{
+       struct hax_state *hax = NULL;
+
+       dprint("hax_disabled %d\n", hax_disabled);
+       if (hax_disabled)
+               return 0;
+       hax = &hax_global;
+       memset(hax, 0, sizeof(struct hax_state));
+       hax->mem_quota = ram_size;
+       dprint("ram_size %lx\n", ram_size);
+       return 0;
+}
+
+int hax_init(void)
+{
+    struct hax_state *hax = NULL;
+    int ret;
+
+    hax_support = 0;
+
+    hax = &hax_global;
+
+
+    hax->fd = hax_mod_open();
+    if (hax_invalid_fd(hax->fd))
+    {
+        hax->fd = 0;
+        ret = -ENODEV;
+        goto error;
+    }
+
+    ret = hax_get_capability(hax);
+
+    if (ret)
+    {
+       if (ret != -ENOSPC)
+           ret = -EINVAL;
+       goto error;
+    }
+
+    if (!hax_version_support(hax))
+    {
+        dprint("Incompat Hax version. Qemu current version %x ", hax_cur_version );
+        dprint("requires least HAX version %x\n", hax_lest_version);
+        ret = -EINVAL;
+        goto error;
+    }
+
+    hax->vm = hax_vm_create(hax);
+    if (!hax->vm)
+    {
+        dprint("Failed to create HAX VM\n");
+        ret = -EINVAL;
+        goto error;
+    }
+
+    cpu_register_phys_memory_client(&hax_cpu_phys_memory_client);
+
+    hax_support = 1;
+
+    return ret;
+error:
+    if (hax->vm)
+        hax_vm_destroy(hax->vm);
+    if (hax->fd)
+        hax_mod_close(hax);
+
+    return ret;
+}
+
+int hax_handle_io(CPUState *env, uint32_t df, uint16_t port, int direction,
+  int size, int count, void *buffer)
+{
+    uint8_t *ptr;
+    int i;
+
+    if (!df)
+        ptr = (uint8_t *)buffer;
+    else
+        ptr = buffer + size * count - size;
+    for (i = 0; i < count; i++)
+    {
+        if (direction == HAX_EXIT_IO_IN) {
+            switch (size) {
+                case 1:
+                    stb_p(ptr, cpu_inb(port));
+                    break;
+                case 2:
+                    stw_p(ptr, cpu_inw(port));
+                    break;
+                case 4:
+                    stl_p(ptr, cpu_inl(port));
+                    break;
+            }
+        } else {
+            switch (size) {
+                case 1:
+                    cpu_outb(port, ldub_p(ptr));
+                    break;
+                case 2:
+                    cpu_outw(port, lduw_p(ptr));
+                    break;
+                case 4:
+                    cpu_outl(port, ldl_p(ptr));
+                    break;
+            }
+        }
+        if (!df)
+            ptr += size;
+        else
+            ptr -= size;
+    }
+
+    return 0;
+}
+
+static int hax_vcpu_interrupt(CPUState *env)
+{
+    struct hax_vcpu_state *vcpu = env->hax_vcpu;
+    struct hax_tunnel *ht = vcpu->tunnel;
+
+    /*
+     * Try to inject an interrupt if the guest can accept it
+     * Unlike KVM, HAX kernel check for the eflags, instead of qemu
+     */
+    if (ht->ready_for_interrupt_injection &&
+      (env->interrupt_request & CPU_INTERRUPT_HARD))
+    {
+        int irq;
+
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+        irq = cpu_get_pic_interrupt(env);
+        if (irq >= 0) {
+            hax_inject_interrupt(env, irq);
+        }
+    }
+
+    /* If we have an interrupt but the guest is not ready to receive an
+     * interrupt, request an interrupt window exit.  This will
+     * cause a return to userspace as soon as the guest is ready to
+     * receive interrupts. */
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD))
+        ht->request_interrupt_window = 1;
+    else
+        ht->request_interrupt_window = 0;
+    return 0;
+}
+
+void hax_raise_event(CPUState *env)
+{
+    struct hax_vcpu_state *vcpu = env->hax_vcpu;
+
+    if (!vcpu)
+        return;
+    vcpu->tunnel->user_event_pending = 1;
+}
+
+/*
+ * Ask hax kernel module to run the CPU for us till:
+ * 1. Guest crash or shutdown
+ * 2. Need QEMU's emulation like guest execute MMIO instruction or guest
+ *    enter emulation mode (non-PG mode)
+ * 3. Guest execute HLT
+ * 4. Qemu have Signal/event pending
+ * 5. An unknown VMX exit happens
+ */
+extern void qemu_system_reset_request(void);
+static int hax_vcpu_hax_exec(CPUState *env)
+{
+    int ret = 0;
+    struct hax_vcpu_state *vcpu = env->hax_vcpu;
+    struct hax_tunnel *ht = vcpu->tunnel;
+
+    if (hax_vcpu_emulation_mode(env))
+    {
+        dprint("Trying to vcpu execute at eip:%lx\n", env->eip);
+        return  HAX_EMUL_EXITLOOP;
+    }
+
+    
+    hax_cpu_synchronize_state(env);
+
+    do {
+        int hax_ret;
+
+       
+        if (env->exit_request) {
+            ret = HAX_EMUL_EXITLOOP ;
+            break;
+        }
+
+       if (env->hax_vcpu_dirty) {
+               hax_vcpu_sync_state(env, 1);
+               env->hax_vcpu_dirty = 0;
+       }
+
+        hax_vcpu_interrupt(env);
+
+        hax_ret = hax_vcpu_run(vcpu);
+
+        /* Simply continue the vcpu_run if system call interrupted */
+        if (hax_ret == -EINTR || hax_ret == -EAGAIN) {
+            dprint("io window interrupted\n");
+            continue;
+        }
+
+        if (hax_ret < 0)
+        {
+            dprint("vcpu run failed for vcpu  %x\n", vcpu->vcpu_id);
+            abort();
+        }
+        switch (ht->_exit_status)
+        {
+            case HAX_EXIT_IO:
+                {
+                      ret = hax_handle_io(env, ht->pio._df, ht->pio._port,
+                      ht->pio._direction,
+                      ht->pio._size, ht->pio._count, vcpu->iobuf);
+                }
+                break;
+            case HAX_EXIT_MMIO:
+                ret = HAX_EMUL_ONE;
+                break;
+            case HAX_EXIT_REAL:
+                ret = HAX_EMUL_REAL;
+                break;
+                /* Guest state changed, currently only for shutdown */
+            case HAX_EXIT_STATECHANGE:
+               dprint("VCPU shutdown request\n");
+                qemu_system_reset_request();
+                hax_prepare_emulation(env);
+                cpu_dump_state(env, stderr, fprintf, 0);
+                ret = HAX_EMUL_EXITLOOP;
+                break;
+            case HAX_EXIT_UNKNOWN_VMEXIT:
+                dprint("Unknown VMX exit %x from guest\n", ht->_exit_reason);
+                qemu_system_reset_request();
+                hax_prepare_emulation(env);
+                cpu_dump_state(env, stderr, fprintf, 0);
+                ret = HAX_EMUL_EXITLOOP;
+                break;
+            case HAX_EXIT_HLT:
+                if (!(env->interrupt_request & CPU_INTERRUPT_HARD) &&
+                  !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
+                    /* hlt instruction with interrupt disabled is shutdown */
+                    env->eflags |= IF_MASK;
+                    env->halted = 1;
+                    env->exception_index = EXCP_HLT;
+                    ret = HAX_EMUL_HLT;
+                }
+                break;
+                /* these situation will continue to hax module */
+            case HAX_EXIT_INTERRUPT:
+            case HAX_EXIT_PAUSED:
+                break;
+            default:
+                dprint("Unknow exit %x from hax\n", ht->_exit_status);
+                qemu_system_reset_request();
+                hax_prepare_emulation(env);
+                cpu_dump_state(env, stderr, fprintf, 0);
+                ret = HAX_EMUL_EXITLOOP;
+                break;
+        }
+    }while (!ret);
+
+    if (env->exit_request) {
+        env->exit_request = 0;
+        env->exception_index = EXCP_INTERRUPT;
+    }
+    return ret;
+}
+
+static void do_hax_cpu_synchronize_state(void *_env)
+{
+       CPUState *env = _env;
+       if (!env->hax_vcpu_dirty) {
+               hax_vcpu_sync_state(env, 0);
+               env->hax_vcpu_dirty = 1;
+       }
+}
+
+void hax_cpu_synchronize_state(CPUState *env)
+{
+       if (!env->hax_vcpu_dirty) {
+               run_on_cpu(env, do_hax_cpu_synchronize_state, env);
+       }
+}
+
+void hax_cpu_synchronize_post_reset(CPUState *env)
+{
+       hax_vcpu_sync_state(env, 1);
+       env->hax_vcpu_dirty = 0;
+}
+
+void hax_cpu_synchronize_post_init(CPUState *env)
+{
+       hax_vcpu_sync_state(env, 1);
+       env->hax_vcpu_dirty = 0;
+}
+
+/*
+ * return 1 when need emulate, 0 when need exit loop
+ */
+int hax_vcpu_exec(CPUState *env)
+{
+    int next = 0, ret = 0;
+    struct hax_vcpu_state *vcpu;
+
+    if (env->hax_vcpu->emulation_state != HAX_EMULATE_STATE_NONE)
+        return 1;
+
+    vcpu = env->hax_vcpu;
+    next = hax_vcpu_hax_exec(env);
+    switch (next)
+    {
+        case HAX_EMUL_ONE:
+            ret = 1;
+            env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_MMIO;
+            hax_prepare_emulation(env);
+            break;
+        case HAX_EMUL_REAL:
+            ret = 1;
+            env->hax_vcpu->emulation_state =
+              HAX_EMULATE_STATE_REAL;
+            hax_prepare_emulation(env);
+            break;
+        case HAX_EMUL_HLT:
+        case HAX_EMUL_EXITLOOP:
+            break;
+        default:
+            dprint("Unknown hax vcpu exec return %x\n", next);
+            abort();
+    }
+
+    return ret;
+}
+
+#define HAX_RAM_INFO_ROM 0x1
+
+static void set_v8086_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
+{
+    memset(lhs, 0, sizeof(struct segment_desc_t ));
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = 3;
+    lhs->present = 1;
+    lhs->dpl = 3;
+    lhs->operand_size = 0;
+    lhs->desc = 1;
+    lhs->long_mode = 0;
+    lhs->granularity = 0;
+    lhs->available = 0;
+}
+
+static void get_seg(SegmentCache *lhs, const struct segment_desc_t *rhs)
+{
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->flags =
+      (rhs->type << DESC_TYPE_SHIFT)
+      | (rhs->present * DESC_P_MASK)
+      | (rhs->dpl << DESC_DPL_SHIFT)
+      | (rhs->operand_size << DESC_B_SHIFT)
+      | (rhs->desc * DESC_S_MASK)
+      | (rhs->long_mode << DESC_L_SHIFT)
+      | (rhs->granularity * DESC_G_MASK)
+      | (rhs->available * DESC_AVL_MASK);
+}
+
+static void set_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
+{
+    unsigned flags = rhs->flags;
+
+    memset(lhs, 0, sizeof(struct segment_desc_t));
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
+    lhs->present = (flags & DESC_P_MASK) != 0;
+    lhs->dpl = rhs->selector & 3;
+    lhs->operand_size = (flags >> DESC_B_SHIFT) & 1;
+    lhs->desc = (flags & DESC_S_MASK) != 0;
+    lhs->long_mode = (flags >> DESC_L_SHIFT) & 1;
+    lhs->granularity = (flags & DESC_G_MASK) != 0;
+    lhs->available = (flags & DESC_AVL_MASK) != 0;
+}
+
+static void hax_getput_reg(uint64_t *hax_reg, target_ulong *qemu_reg, int set)
+{
+    target_ulong reg = *hax_reg;
+
+    if (set)
+        *hax_reg = *qemu_reg;
+    else
+        *qemu_reg = reg;
+}
+
+/* The sregs has been synced with HAX kernel already before this call */
+static int hax_get_segments(CPUState *env, struct vcpu_state_t *sregs)
+{
+    get_seg(&env->segs[R_CS], &sregs->_cs);
+    get_seg(&env->segs[R_DS], &sregs->_ds);
+    get_seg(&env->segs[R_ES], &sregs->_es);
+    get_seg(&env->segs[R_FS], &sregs->_fs);
+    get_seg(&env->segs[R_GS], &sregs->_gs);
+    get_seg(&env->segs[R_SS], &sregs->_ss);
+
+    get_seg(&env->tr, &sregs->_tr);
+    get_seg(&env->ldt, &sregs->_ldt);
+    env->idt.limit = sregs->_idt.limit;
+    env->idt.base = sregs->_idt.base;
+    env->gdt.limit = sregs->_gdt.limit;
+    env->gdt.base = sregs->_gdt.base;
+    return 0;
+}
+
+static int hax_set_segments(CPUState *env, struct vcpu_state_t *sregs)
+{
+    if ((env->eflags & VM_MASK)) {
+        set_v8086_seg(&sregs->_cs, &env->segs[R_CS]);
+        set_v8086_seg(&sregs->_ds, &env->segs[R_DS]);
+        set_v8086_seg(&sregs->_es, &env->segs[R_ES]);
+        set_v8086_seg(&sregs->_fs, &env->segs[R_FS]);
+        set_v8086_seg(&sregs->_gs, &env->segs[R_GS]);
+        set_v8086_seg(&sregs->_ss, &env->segs[R_SS]);
+    } else {
+        set_seg(&sregs->_cs, &env->segs[R_CS]);
+        set_seg(&sregs->_ds, &env->segs[R_DS]);
+        set_seg(&sregs->_es, &env->segs[R_ES]);
+        set_seg(&sregs->_fs, &env->segs[R_FS]);
+        set_seg(&sregs->_gs, &env->segs[R_GS]);
+        set_seg(&sregs->_ss, &env->segs[R_SS]);
+
+        if (env->cr[0] & CR0_PE_MASK) {
+            /* force ss cpl to cs cpl */
+            sregs->_ss.selector = (sregs->_ss.selector & ~3) |
+              (sregs->_cs.selector & 3);
+            sregs->_ss.dpl = sregs->_ss.selector & 3;
+        }
+    }
+
+    set_seg(&sregs->_tr, &env->tr);
+    set_seg(&sregs->_ldt, &env->ldt);
+    sregs->_idt.limit = env->idt.limit;
+    sregs->_idt.base = env->idt.base;
+    sregs->_gdt.limit = env->gdt.limit;
+    sregs->_gdt.base = env->gdt.base;
+    return 0;
+}
+
+/*
+ * After get the state from the kernel module, some
+ * qemu emulator state need be updated also
+ */
+static int hax_setup_qemu_emulator(CPUState *env)
+{
+
+#define HFLAG_COPY_MASK ~( \
+  HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
+  HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
+  HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
+  HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
+
+    uint32_t hflags;
+
+    hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+    hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
+    hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
+      (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
+    hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
+    hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
+      (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+    if (env->efer & MSR_EFER_LMA) {
+        hflags |= HF_LMA_MASK;
+    }
+
+    if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) {
+        hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+    } else {
+        hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >>
+          (DESC_B_SHIFT - HF_CS32_SHIFT);
+        hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >>
+          (DESC_B_SHIFT - HF_SS32_SHIFT);
+        if (!(env->cr[0] & CR0_PE_MASK) ||
+          (env->eflags & VM_MASK) ||
+          !(hflags & HF_CS32_MASK)) {
+            hflags |= HF_ADDSEG_MASK;
+        } else {
+            hflags |= ((env->segs[R_DS].base |
+                  env->segs[R_ES].base |
+                  env->segs[R_SS].base) != 0) <<
+              HF_ADDSEG_SHIFT;
+        }
+    }
+    env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+    return 0;
+}
+
+static int hax_sync_vcpu_register(CPUState *env, int set)
+{
+    struct vcpu_state_t regs;
+    int ret;
+    memset(&regs, 0, sizeof(struct vcpu_state_t));
+
+    if (!set)
+    {
+        ret = hax_sync_vcpu_state(env, &regs, 0);
+        if (ret < 0)
+            return -1;
+    }
+
+    /*generic register */
+    hax_getput_reg(&regs._rax, &env->regs[R_EAX], set);
+    hax_getput_reg(&regs._rbx, &env->regs[R_EBX], set);
+    hax_getput_reg(&regs._rcx, &env->regs[R_ECX], set);
+    hax_getput_reg(&regs._rdx, &env->regs[R_EDX], set);
+    hax_getput_reg(&regs._rsi, &env->regs[R_ESI], set);
+    hax_getput_reg(&regs._rdi, &env->regs[R_EDI], set);
+    hax_getput_reg(&regs._rsp, &env->regs[R_ESP], set);
+    hax_getput_reg(&regs._rbp, &env->regs[R_EBP], set);
+
+    hax_getput_reg(&regs._rflags, &env->eflags, set);
+    hax_getput_reg(&regs._rip, &env->eip, set);
+
+    if (set)
+    {
+
+        regs._cr0 = env->cr[0];
+        regs._cr2 = env->cr[2];
+        regs._cr3 = env->cr[3];
+        regs._cr4 = env->cr[4];
+        hax_set_segments(env, &regs);
+    }
+    else
+    {
+        env->cr[0] = regs._cr0;
+        env->cr[2] = regs._cr2;
+        env->cr[3] = regs._cr3;
+        env->cr[4] = regs._cr4;
+        hax_get_segments(env, &regs);
+    }
+
+    if (set)
+    {
+        ret = hax_sync_vcpu_state(env, &regs, 1);
+        if (ret < 0)
+            return -1;
+    }
+    if (!set)
+        hax_setup_qemu_emulator(env);
+    return 0;
+}
+
+static void hax_msr_entry_set(struct vmx_msr *item,
+  uint32_t index, uint64_t value)
+{
+    item->entry = index;
+    item->value = value;
+}
+
+static int hax_get_msrs(CPUState *env)
+{
+    struct hax_msr_data md;
+    struct vmx_msr *msrs = md.entries;
+    int ret, i, n;
+
+    n = 0;
+    msrs[n++].entry = MSR_IA32_SYSENTER_CS;
+    msrs[n++].entry = MSR_IA32_SYSENTER_ESP;
+    msrs[n++].entry = MSR_IA32_SYSENTER_EIP;
+    msrs[n++].entry = MSR_IA32_TSC;
+    md.nr_msr = n;
+    ret = hax_sync_msr(env, &md, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < md.done; i++) {
+        switch (msrs[i].entry) {
+            case MSR_IA32_SYSENTER_CS:
+                env->sysenter_cs = msrs[i].value;
+                break;
+            case MSR_IA32_SYSENTER_ESP:
+                env->sysenter_esp = msrs[i].value;
+                break;
+            case MSR_IA32_SYSENTER_EIP:
+                env->sysenter_eip = msrs[i].value;
+                break;
+            case MSR_IA32_TSC:
+                env->tsc = msrs[i].value;
+                break;
+        }
+    }
+
+    return 0;
+}
+
+static int hax_set_msrs(CPUState *env)
+{
+    struct hax_msr_data md;
+    struct vmx_msr *msrs;
+    msrs = md.entries;
+    int n = 0;
+
+    memset(&md, 0, sizeof(struct hax_msr_data));
+    hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
+    hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
+    hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+    hax_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+    md.nr_msr = n;
+    md.done = 0;
+
+    return hax_sync_msr(env, &md, 1);
+
+}
+
+static int hax_get_fpu(CPUState *env)
+{
+    struct fx_layout fpu;
+    int i, ret;
+
+    ret = hax_sync_fpu(env, &fpu, 0);
+    if (ret < 0)
+        return ret;
+
+    env->fpstt = (fpu.fsw >> 11) & 7;
+    env->fpus = fpu.fsw;
+    env->fpuc = fpu.fcw;
+    for (i = 0; i < 8; ++i)
+        env->fptags[i] = !((fpu.ftw >> i) & 1);
+    memcpy(env->fpregs, fpu.st_mm, sizeof(env->fpregs));
+
+    memcpy(env->xmm_regs, fpu.mmx_1, sizeof(fpu.mmx_1));
+    memcpy((XMMReg *)(env->xmm_regs) + 8, fpu.mmx_2, sizeof(fpu.mmx_2));
+    env->mxcsr = fpu.mxcsr;
+
+    return 0;
+}
+
+static int hax_set_fpu(CPUState *env)
+{
+    struct fx_layout fpu;
+    int i;
+
+    memset(&fpu, 0, sizeof(fpu));
+    fpu.fsw = env->fpus & ~(7 << 11);
+    fpu.fsw |= (env->fpstt & 7) << 11;
+    fpu.fcw = env->fpuc;
+
+    for (i = 0; i < 8; ++i)
+        fpu.ftw |= (!env->fptags[i]) << i;
+
+    memcpy(fpu.st_mm, env->fpregs, sizeof (env->fpregs));
+    memcpy(fpu.mmx_1, env->xmm_regs, sizeof (fpu.mmx_1));
+    memcpy(fpu.mmx_2, (XMMReg *)(env->xmm_regs) + 8, sizeof (fpu.mmx_2));
+
+    fpu.mxcsr = env->mxcsr;
+
+    return hax_sync_fpu(env, &fpu, 1);
+}
+
+int hax_arch_get_registers(CPUState *env)
+{
+    int ret;
+
+    ret = hax_sync_vcpu_register(env, 0);
+    if (ret < 0)
+        return ret;
+
+    ret = hax_get_fpu(env);
+    if (ret < 0)
+        return ret;
+
+    ret = hax_get_msrs(env);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int hax_arch_set_registers(CPUState *env)
+{
+    int ret;
+    ret = hax_sync_vcpu_register(env, 1);
+
+    if (ret < 0)
+    {
+        dprint("Failed to sync vcpu reg\n");
+        return ret;
+    }
+    ret = hax_set_fpu(env);
+    if (ret < 0)
+    {
+        dprint("FPU failed\n");
+        return ret;
+    }
+    ret = hax_set_msrs(env);
+    if (ret < 0)
+    {
+        dprint("MSR failed\n");
+        return ret;
+    }
+
+    return 0;
+}
+
+void hax_vcpu_sync_state(CPUState *env, int modified)
+{
+    if (hax_enabled()) {
+        if (modified)
+            hax_arch_set_registers(env);
+        else
+            hax_arch_get_registers(env);
+    }
+}
+
+/*
+ * much simpler than kvm, at least in first stage because:
+ * We don't need consider the device pass-through, we don't need
+ * consider the framebuffer, and we may even remove the bios at all
+ */
+int hax_sync_vcpus(void)
+{
+    if (hax_enabled())
+    {
+        CPUState *env;
+
+        env = first_cpu;
+        if (!env)
+            return 0;
+
+        for (; env != NULL; env = env->next_cpu) {
+            int ret;
+
+            ret = hax_arch_set_registers(env);
+            if (ret < 0)
+            {
+                dprint("Failed to sync HAX vcpu context\n");
+                exit(1);
+            }
+        }
+    }
+
+    return 0;
+}
+void hax_reset_vcpu_state(void *opaque)
+{
+       CPUState *env = opaque;
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+       {
+               dprint("*********ReSet hax_vcpu->emulation_state \n");
+               env->hax_vcpu->emulation_state  = HAX_EMULATE_STATE_INITIAL;
+               env->hax_vcpu->tunnel->user_event_pending = 0;
+               env->hax_vcpu->tunnel->ready_for_interrupt_injection = 0;
+
+       }
+
+}
+
+
diff --git a/target-i386/hax-i386.h b/target-i386/hax-i386.h
new file mode 100644 (file)
index 0000000..4d7a083
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _HAX_I386_H
+#define _HAX_I386_H
+
+//#include "android/utils/debug.h"
+#include "hax.h"
+
+#ifdef CONFIG_DARWIN
+typedef int hax_fd;
+#endif
+
+#ifdef CONFIG_WIN32
+typedef HANDLE hax_fd;
+#endif
+
+extern struct hax_state hax_global;
+struct hax_vcpu_state
+{
+    hax_fd fd;
+    int vcpu_id;
+    int emulation_state;
+    struct hax_tunnel *tunnel;
+    unsigned char *iobuf;
+};
+
+struct hax_state
+{
+    hax_fd fd; /* the global hax device interface */
+    uint32_t version;
+    struct hax_vm *vm;
+    uint64_t mem_quota;
+};
+
+#define HAX_MAX_VCPU 0x10
+#define MAX_VM_ID 0x40
+#define MAX_VCPU_ID 0x40
+
+struct hax_vm
+{
+    hax_fd fd;
+    int id;
+    struct hax_vcpu_state *vcpus[HAX_MAX_VCPU];
+};
+
+#ifdef NEED_CPU_H
+/* Functions exported to host specific mode */
+hax_fd hax_vcpu_get_fd(CPUState *env);
+int valid_hax_tunnel_size(uint16_t size);
+
+/* Host specific functions */
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version);
+int hax_inject_interrupt(CPUState *env, int vector);
+struct hax_vm *hax_vm_create(struct hax_state *hax);
+int hax_vcpu_run(struct hax_vcpu_state *vcpu);
+int hax_vcpu_create(int id);
+int hax_sync_vcpu_state(CPUState *env, struct vcpu_state_t *state, int set);
+int hax_sync_msr(CPUState *env, struct hax_msr_data *msrs, int set);
+int hax_sync_fpu(CPUState *env, struct fx_layout *fl, int set);
+#endif
+
+int hax_vm_destroy(struct hax_vm *vm);
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap);
+
+/* Common host function */
+int hax_host_create_vm(struct hax_state *hax, int *vm_id);
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id);
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid);
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid);
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu);
+hax_fd hax_mod_open(void);
+
+
+#ifdef CONFIG_DARWIN
+#include "target-i386/hax-darwin.h"
+#endif
+
+#ifdef CONFIG_WIN32
+#include "target-i386/hax-windows.h"
+#endif
+
+#include "target-i386/hax-interface.h"
+
+#endif
diff --git a/target-i386/hax-interface.h b/target-i386/hax-interface.h
new file mode 100644 (file)
index 0000000..b912690
--- /dev/null
@@ -0,0 +1,335 @@
+/* Interface with HAX kernel module */
+
+#ifndef _HAX_INTERFACE_H
+#define _HAX_INTERFACE_H
+
+/* fx_layout has 3 formats table 3-56, 512bytes */
+struct fx_layout {
+    uint16_t    fcw;
+    uint16_t    fsw;
+    uint8       ftw;
+    uint8       res1;
+    uint16_t    fop;
+    union {
+        struct {
+            uint32      fip;
+            uint16_t    fcs;
+            uint16_t    res2;
+        };
+        uint64  fpu_ip;
+    };
+    union {
+        struct {
+            uint32      fdp;
+            uint16_t    fds;
+            uint16_t    res3;
+        };
+        uint64 fpu_dp;
+    };
+    uint32      mxcsr;
+    uint32      mxcsr_mask;
+    uint8       st_mm[8][16];
+    uint8       mmx_1[8][16];
+    uint8       mmx_2[8][16];
+    uint8       pad[96];
+};
+
+struct vmx_msr {
+    uint64 entry;
+    uint64 value;
+};
+
+/*
+ * Fixed array is not good, but it makes Mac support a bit easier by avoiding
+ * memory map or copyin staff.
+ */
+#define HAX_MAX_MSR_ARRAY 0x20
+struct hax_msr_data
+{
+    uint16_t nr_msr;
+    uint16_t done;
+    uint16_t pad[2];
+    struct vmx_msr entries[HAX_MAX_MSR_ARRAY];
+};
+
+union interruptibility_state_t {
+    uint32 raw;
+    struct {
+        uint32 sti_blocking   : 1;
+        uint32 movss_blocking : 1;
+        uint32 smi_blocking   : 1;
+        uint32 nmi_blocking   : 1;
+        uint32 reserved       : 28;
+    };
+    uint64_t pad;
+};
+
+typedef union interruptibility_state_t interruptibility_state_t;
+
+// Segment descriptor
+struct segment_desc_t {
+    uint16_t selector;
+    uint16_t _dummy;
+    uint32 limit;
+    uint64 base;
+    union {
+        struct {
+            uint32 type             : 4;
+            uint32 desc             : 1;
+            uint32 dpl              : 2;
+            uint32 present          : 1;
+            uint32                  : 4;
+            uint32 available        : 1;
+            uint32 long_mode        : 1;
+            uint32 operand_size     : 1;
+            uint32 granularity      : 1;
+            uint32 null             : 1;
+            uint32                  : 15;
+        };
+        uint32 ar;
+    };
+    uint32 ipad;
+};
+
+typedef struct segment_desc_t segment_desc_t;
+
+struct vcpu_state_t
+{
+    union {
+        uint64 _regs[16];
+        struct {
+            union {
+                struct {
+                    uint8 _al,
+                          _ah;
+                };
+                uint16_t    _ax;
+                uint32    _eax;
+                uint64    _rax;
+            };
+            union {
+                struct {
+                    uint8 _cl,
+                          _ch;
+                };
+                uint16_t    _cx;
+                uint32    _ecx;
+                uint64    _rcx;
+            };
+            union {
+                struct {
+                    uint8 _dl,
+                          _dh;
+                };
+                uint16_t    _dx;
+                uint32    _edx;
+                uint64    _rdx;
+            };
+            union {
+                struct {
+                    uint8 _bl,
+                          _bh;
+                };
+                uint16_t    _bx;
+                uint32    _ebx;
+                uint64    _rbx;
+            };
+            union {
+                uint16_t    _sp;
+                uint32    _esp;
+                uint64    _rsp;
+            };
+            union {
+                uint16_t    _bp;
+                uint32    _ebp;
+                uint64    _rbp;
+            };
+            union {
+                uint16_t    _si;
+                uint32    _esi;
+                uint64    _rsi;
+            };
+            union {
+                uint16_t    _di;
+                uint32    _edi;
+                uint64    _rdi;
+            };
+
+            uint64 _r8;
+            uint64 _r9;
+            uint64 _r10;
+            uint64 _r11;
+            uint64 _r12;
+            uint64 _r13;
+            uint64 _r14;
+            uint64 _r15;
+        };
+    };
+
+    union {
+        uint32 _eip;
+        uint64 _rip;
+    };
+
+    union {
+        uint32 _eflags;
+        uint64 _rflags;
+    };
+
+    segment_desc_t _cs;
+    segment_desc_t _ss;
+    segment_desc_t _ds;
+    segment_desc_t _es;
+    segment_desc_t _fs;
+    segment_desc_t _gs;
+    segment_desc_t _ldt;
+    segment_desc_t _tr;
+
+    segment_desc_t _gdt;
+    segment_desc_t _idt;
+
+    uint64 _cr0;
+    uint64 _cr2;
+    uint64 _cr3;
+    uint64 _cr4;
+
+    uint64 _dr0;
+    uint64 _dr1;
+    uint64 _dr2;
+    uint64 _dr3;
+    uint64 _dr6;
+    uint64 _dr7;
+    uint64 _pde;
+
+    uint32 _efer;
+
+    uint32 _sysenter_cs;
+    uint64 _sysenter_eip;
+    uint64 _sysenter_esp;
+
+    uint32 _activity_state;
+    uint32 pad;
+    interruptibility_state_t _interruptibility_state;
+};
+
+
+/* Seems there are some difference between Xiaohui/Yunhong's implementation */
+
+enum exit_status {
+    /* IO port request */
+    HAX_EXIT_IO = 1,
+    /* MMIO instruction emulation */
+    HAX_EXIT_MMIO,
+    /* QEMU emulation mode request, currently means guest enter non-PG mode */
+    HAX_EXIT_REAL,
+    /*
+     * Interrupt window open, qemu can inject interrupt now
+     * Also used when signal pending since at that time qemu usually need
+     * check interrupt
+     */
+    HAX_EXIT_INTERRUPT,
+    /* Unknown vmexit, mostly trigger reboot */
+    HAX_EXIT_UNKNOWN_VMEXIT,
+    /* HALT from guest */
+    HAX_EXIT_HLT,
+    /* Reboot request, like because of tripple fault in guest */
+    HAX_EXIT_STATECHANGE,
+    /* the vcpu is now only paused when destroy, so simply return to hax */
+    HAX_EXIT_PAUSED,
+};
+
+/* The interface definition:
+   1. vcpu_run execute will return 0 on success, otherwise mean failed
+   2. exit_status return the exit reason, as stated in enum exit_status
+   3. exit_reason is the vmx exit reason (WHY do we need this? )
+   4. exit_flag, who knows what's it for!
+ */
+struct hax_tunnel
+{
+    uint32_t _exit_reason;
+    uint32_t _exit_flag;
+    uint32_t _exit_status;
+    uint32_t user_event_pending;
+    int ready_for_interrupt_injection;
+    int request_interrupt_window;
+    union {
+        struct {
+            /* 0: read, 1: write */
+#define HAX_EXIT_IO_IN  1
+#define HAX_EXIT_IO_OUT 0
+            uint8_t _direction;
+            uint8_t _df;
+            uint16_t _size;
+            uint16_t _port;
+            uint16_t _count;
+            uint8_t _flags;
+            uint8_t _pad0;
+            uint16_t _pad1;
+            uint32_t _pad2;
+            uint64_t _vaddr;
+        } pio;
+        struct {
+            uint64_t gla;
+        } mmio;
+        struct {
+        } state;
+    };
+};
+
+struct hax_module_version
+{
+    uint32_t compat_version;
+    uint32_t cur_version;
+};
+
+/* The mac specfic interface to qemu, mostly is ioctl related */
+struct hax_tunnel_info
+{
+    uint64_t va;
+    uint64_t io_va;
+    uint16_t size;
+    uint16_t pad[3];
+};
+
+struct hax_alloc_ram_info
+{
+    uint32_t size;
+    uint32_t pad;
+    uint64_t va;
+};
+#define HAX_RAM_INFO_ROM 0x1
+struct hax_set_ram_info
+{
+    uint64_t pa_start;
+    uint32_t size;
+    uint8_t flags;
+    uint8_t pad[3];
+    uint64_t va;
+};
+
+#define HAX_CAP_STATUS_WORKING  0x1
+#define HAX_CAP_STATUS_NOTWORKING  0x0
+#define HAX_CAP_WORKSTATUS_MASK 0x1
+
+#define HAX_CAP_FAILREASON_VT   0x1
+#define HAX_CAP_FAILREASON_NX   0x2
+
+#define HAX_CAP_MEMQUOTA       0x2
+
+struct hax_capabilityinfo
+{
+    /* bit 0: 1 - working
+     *        0 - not working, possibly because NT/NX disabled
+     * bit 1: 1 - memory limitation working
+     *        0 - no memory limitation
+     */
+    uint16_t wstatus;
+    /* valid when not working
+     * bit 0: VT not enabeld
+     * bit 1: NX not enabled*/
+    uint16_t winfo;
+    uint32_t pad;
+    uint64_t mem_quota;
+};
+
+#endif
diff --git a/target-i386/hax-windows.c b/target-i386/hax-windows.c
new file mode 100644 (file)
index 0000000..bfa3f95
--- /dev/null
@@ -0,0 +1,490 @@
+#include "target-i386/hax-i386.h"
+
+/*
+ * return 0 when success, -1 when driver not loaded,
+ * other negative value for other failure
+ */
+static int hax_open_device(hax_fd *fd)
+{
+    uint32_t errNum = 0;
+    HANDLE hDevice;
+
+    if (!fd)
+        return -2;
+
+    hDevice = CreateFile( "\\\\.\\HAX",
+      GENERIC_READ | GENERIC_WRITE,
+      0,
+      NULL,
+      CREATE_ALWAYS,
+      FILE_ATTRIBUTE_NORMAL,
+      NULL);
+
+    if (hDevice == INVALID_HANDLE_VALUE)
+    {
+        dprint("Failed to open the HAX device!\n");
+        errNum = GetLastError();
+        if (errNum == ERROR_FILE_NOT_FOUND)
+            return -1;
+        return -2;
+    }
+    *fd = hDevice;
+    dprint("device fd:%d\n", *fd);
+    return 0;
+}
+
+/* This need changes after more investigation on driver loading*/
+hax_fd hax_mod_open(void)
+{
+    int ret;
+    hax_fd fd;
+
+    ret = hax_open_device(&fd);
+    if (ret != 0)
+        dprint("Open HAX device failed\n");
+
+    return fd;
+}
+
+int hax_populate_ram(uint64_t va, uint32_t size)
+{
+    int ret;
+    struct hax_alloc_ram_info info;
+    HANDLE hDeviceVM;
+    DWORD dSize = 0;
+
+    if (!hax_global.vm || !hax_global.vm->fd)
+    {
+        dprint("Allocate memory before vm create?\n");
+        return -EINVAL;
+    }
+
+    info.size = size;
+    info.va = va;
+
+    hDeviceVM = hax_global.vm->fd;
+
+    ret = DeviceIoControl(hDeviceVM,
+      HAX_VM_IOCTL_ALLOC_RAM,
+      &info, sizeof(info),
+      NULL, 0,
+      &dSize,
+      (LPOVERLAPPED) NULL);
+
+    if (!ret) {
+        dprint("Failed to allocate %x memory\n", size);
+        return ret;
+    }
+
+    return 0;
+}
+
+
+/*
+ * much simpler than kvm, at least in first stage because:
+ * We don't need consider the device pass-through, we don't need
+ * consider the framebuffer, and we may even remove the bios at all
+ */
+
+int hax_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t phys_offset)
+{
+    struct hax_set_ram_info info, *pinfo = &info;
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    HANDLE hDeviceVM;
+    DWORD dSize = 0;
+    int ret = 0;
+
+    /* We only care for the  RAM and ROM */
+    if (flags >= IO_MEM_UNASSIGNED)
+        return 0;
+
+    if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK))
+    {
+        dprint(
+          "set_phys_mem %x %lx requires page aligned addr and size\n",
+          start_addr, size);
+        return -1;
+    }
+
+    info.pa_start = start_addr;
+    info.size = size;
+    info.va = (uint64_t)qemu_get_ram_ptr(phys_offset);
+    info.flags = (flags & IO_MEM_ROM) ? 1 : 0;
+
+    hDeviceVM = hax_global.vm->fd;
+
+    ret = DeviceIoControl(hDeviceVM,
+      HAX_VM_IOCTL_SET_RAM,
+      pinfo, sizeof(*pinfo),
+      NULL, 0,
+      &dSize,
+      (LPOVERLAPPED) NULL);
+
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
+
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
+{
+    int ret;
+    HANDLE hDevice = hax->fd;   //handle to hax module
+    DWORD dSize = 0;
+    DWORD err = 0;
+
+    if (hax_invalid_fd(hDevice)) {
+        dprint("Invalid fd for hax device!\n");
+        return -ENODEV;
+    }
+
+    ret = DeviceIoControl(hDevice,
+      HAX_IOCTL_CAPABILITY,
+      NULL, 0,
+      cap, sizeof(*cap),
+      &dSize,
+      (LPOVERLAPPED) NULL);
+
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_INSUFFICIENT_BUFFER ||
+            err == ERROR_MORE_DATA)
+            dprint("hax capability is too long to hold.\n");
+        dprint("Failed to get Hax capability:%d\n", err);
+        return -EFAULT;
+    } else
+        return 0;
+
+}
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
+{
+    int ret;
+    HANDLE hDevice = hax->fd;   //handle to hax module
+    DWORD dSize = 0;
+    DWORD err = 0;
+
+    if (hax_invalid_fd(hDevice)) {
+        dprint("Invalid fd for hax device!\n");
+        return -ENODEV;
+    }
+
+    ret = DeviceIoControl(hDevice,
+      HAX_IOCTL_VERSION,
+      NULL, 0,
+      version, sizeof(*version),
+      &dSize,
+      (LPOVERLAPPED) NULL);
+
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_INSUFFICIENT_BUFFER ||
+            err == ERROR_MORE_DATA)
+            dprint("hax module verion is too long to hold.\n");
+        dprint("Failed to get Hax module version:%d\n", err);
+        return -EFAULT;
+    } else
+        return 0;
+}
+
+static char *hax_vm_devfs_string(int vm_id)
+{
+    char *name;
+
+    if (vm_id > MAX_VM_ID)
+    {
+        dprint("Too big VM id\n");
+        return NULL;
+    }
+
+    name = g_strdup("\\\\.\\hax_vmxx");
+    if (!name)
+        return NULL;
+    sprintf(name, "\\\\.\\hax_vm%02d", vm_id);
+
+    return name;
+}
+
+static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
+{
+    char *name;
+
+    if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID)
+    {
+        dprint("Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
+        return NULL;
+    }
+    name = g_strdup("\\\\.\\hax_vmxx_vcpuxx");
+    if (!name)
+        return NULL;
+    sprintf(name, "\\\\.\\hax_vm%02d_vcpu%02d", vm_id, vcpu_id);
+
+    return name;
+}
+
+int hax_host_create_vm(struct hax_state *hax, int *vmid)
+{
+    int ret;
+    int vm_id = 0;
+    DWORD dSize = 0;
+
+    if (hax_invalid_fd(hax->fd))
+        return -EINVAL;
+
+    if (hax->vm)
+        return 0;
+
+    ret = DeviceIoControl(hax->fd,
+      HAX_IOCTL_CREATE_VM,
+      NULL, 0,
+      &vm_id, sizeof(vm_id),
+      &dSize,
+      (LPOVERLAPPED) NULL);
+    if (!ret) {
+        dprint("error code:%d", GetLastError());
+        return -1;
+    }
+    *vmid = vm_id;
+    return 0;
+}
+
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id)
+{
+    char *vm_name = NULL;
+    hax_fd hDeviceVM;
+
+    vm_name = hax_vm_devfs_string(vm_id);
+    if (!vm_name) {
+        dprint("Incorrect name\n");
+        return INVALID_HANDLE_VALUE;
+    }
+
+    hDeviceVM = CreateFile(vm_name,
+      GENERIC_READ | GENERIC_WRITE,
+      0,
+      NULL,
+      CREATE_ALWAYS,
+      FILE_ATTRIBUTE_NORMAL,
+      NULL);
+    if (hDeviceVM == INVALID_HANDLE_VALUE)
+        dprint("Open the vm devcie error:%s, ec:%d\n", vm_name, GetLastError());
+
+    g_free(vm_name);
+    return hDeviceVM;
+}
+
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid)
+{
+    int ret;
+    DWORD dSize = 0;
+
+    ret = DeviceIoControl(vm_fd,
+      HAX_VM_IOCTL_VCPU_CREATE,
+      &vcpuid, sizeof(vcpuid),
+      NULL, 0,
+      &dSize,
+      (LPOVERLAPPED) NULL);
+    if (!ret)
+    {
+        dprint("Failed to create vcpu %x\n", vcpuid);
+        return -1;
+    }
+
+    return 0;
+}
+
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+    char *devfs_path = NULL;
+    hax_fd hDeviceVCPU;
+
+    devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+    if (!devfs_path)
+    {
+        dprint("Failed to get the devfs\n");
+        return INVALID_HANDLE_VALUE;
+    }
+
+    hDeviceVCPU = CreateFile( devfs_path,
+      GENERIC_READ | GENERIC_WRITE,
+      0,
+      NULL,
+      CREATE_ALWAYS,
+      FILE_ATTRIBUTE_NORMAL,
+      NULL);
+
+    if (hDeviceVCPU == INVALID_HANDLE_VALUE)
+        dprint("Failed to open the vcpu devfs\n");
+    g_free(devfs_path);
+    return hDeviceVCPU;
+}
+
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+{
+    hax_fd hDeviceVCPU = vcpu->fd;
+    int ret;
+    struct hax_tunnel_info info;
+    DWORD dSize = 0;
+
+    ret = DeviceIoControl(hDeviceVCPU,
+      HAX_VCPU_IOCTL_SETUP_TUNNEL,
+      NULL, 0,
+      &info, sizeof(info),
+      &dSize,
+      (LPOVERLAPPED) NULL);
+    if (!ret)
+    {
+        dprint("Failed to setup the hax tunnel\n");
+        return -1;
+    }
+
+    if (!valid_hax_tunnel_size(info.size))
+    {
+        dprint("Invalid hax tunnel size %x\n", info.size);
+        ret = -EINVAL;
+        return ret;
+    }
+    vcpu->tunnel = (struct hax_tunnel *)(info.va);
+    vcpu->iobuf = (unsigned char *)(info.io_va);
+    return 0;
+}
+
+int hax_vcpu_run(struct hax_vcpu_state* vcpu)
+{
+    int ret;
+    HANDLE hDeviceVCPU = vcpu->fd;
+    DWORD dSize = 0;
+
+    ret = DeviceIoControl(hDeviceVCPU,
+      HAX_VCPU_IOCTL_RUN,
+      NULL, 0,
+      NULL, 0,
+      &dSize,
+      (LPOVERLAPPED) NULL);
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
+
+int hax_sync_fpu(CPUState *env, struct fx_layout *fl, int set)
+{
+    int ret;
+    hax_fd fd;
+    HANDLE hDeviceVCPU;
+    DWORD dSize = 0;
+
+    fd = hax_vcpu_get_fd(env);
+    if (hax_invalid_fd(fd))
+        return -1;
+
+    hDeviceVCPU = fd;
+
+    if (set)
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_IOCTL_SET_FPU,
+          fl, sizeof(*fl),
+          NULL, 0,
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    else
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_IOCTL_GET_FPU,
+          NULL, 0,
+          fl, sizeof(*fl),
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
+
+int hax_sync_msr(CPUState *env, struct hax_msr_data *msrs, int set)
+{
+    int ret;
+    hax_fd fd;
+    HANDLE hDeviceVCPU;
+    DWORD dSize = 0;
+
+    fd = hax_vcpu_get_fd(env);
+    if (hax_invalid_fd(fd))
+        return -1;
+    hDeviceVCPU = fd;
+
+    if (set)
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_IOCTL_SET_MSRS,
+          msrs, sizeof(*msrs),
+          msrs, sizeof(*msrs),
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    else
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_IOCTL_GET_MSRS,
+          msrs, sizeof(*msrs),
+          msrs, sizeof(*msrs),
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
+
+int hax_sync_vcpu_state(CPUState *env, struct vcpu_state_t *state, int set)
+{
+    int ret;
+    hax_fd fd;
+    HANDLE hDeviceVCPU;
+    DWORD dSize;
+
+    fd = hax_vcpu_get_fd(env);
+    if (hax_invalid_fd(fd))
+        return -1;
+
+    hDeviceVCPU = fd;
+
+    if (set)
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_SET_REGS,
+          state, sizeof(*state),
+          NULL, 0,
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    else
+        ret = DeviceIoControl(hDeviceVCPU,
+          HAX_VCPU_GET_REGS,
+          NULL, 0,
+          state, sizeof(*state),
+          &dSize,
+          (LPOVERLAPPED) NULL);
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
+
+int hax_inject_interrupt(CPUState *env, int vector)
+{
+    int ret;
+    hax_fd fd;
+    HANDLE hDeviceVCPU;
+    DWORD dSize;
+
+    fd = hax_vcpu_get_fd(env);
+    if (hax_invalid_fd(fd))
+        return -1;
+
+    hDeviceVCPU = fd;
+
+    ret = DeviceIoControl(hDeviceVCPU,
+      HAX_VCPU_IOCTL_INTERRUPT,
+      &vector, sizeof(vector),
+      NULL, 0,
+      &dSize,
+      (LPOVERLAPPED) NULL);
+    if (!ret)
+        return -EFAULT;
+    else
+        return 0;
+}
diff --git a/target-i386/hax-windows.h b/target-i386/hax-windows.h
new file mode 100644 (file)
index 0000000..48569cd
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __HAX_WINDOWS_H
+#define __HAX_WINDOWS_H
+
+#include <windows.h>
+#include <memory.h>
+#include <malloc.h>
+#include <winioctl.h>
+#include <string.h>
+#include <stdio.h>
+#include <windef.h>
+
+#define HAX_INVALID_FD INVALID_HANDLE_VALUE
+
+static inline void hax_mod_close(struct hax_state *hax)
+{
+    CloseHandle(hax->fd);
+}
+
+static inline void hax_close_fd(hax_fd fd)
+{
+    CloseHandle(fd);
+}
+
+static inline int hax_invalid_fd(hax_fd fd)
+{
+    return (fd == INVALID_HANDLE_VALUE);
+}
+
+
+#define HAX_DEVICE_TYPE 0x4000
+
+#define HAX_IOCTL_VERSION       CTL_CODE(HAX_DEVICE_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_IOCTL_CREATE_VM     CTL_CODE(HAX_DEVICE_TYPE, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_IOCTL_CAPABILITY    CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VM_IOCTL_VCPU_CREATE   CTL_CODE(HAX_DEVICE_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_ALLOC_RAM     CTL_CODE(HAX_DEVICE_TYPE, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_SET_RAM       CTL_CODE(HAX_DEVICE_TYPE, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VM_IOCTL_VCPU_DESTROY       CTL_CODE(HAX_DEVICE_TYPE, 0x905, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VCPU_IOCTL_RUN      CTL_CODE(HAX_DEVICE_TYPE, 0x906, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_SET_MSRS CTL_CODE(HAX_DEVICE_TYPE, 0x907, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_GET_MSRS CTL_CODE(HAX_DEVICE_TYPE, 0x908, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VCPU_IOCTL_SET_FPU  CTL_CODE(HAX_DEVICE_TYPE, 0x909, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_GET_FPU  CTL_CODE(HAX_DEVICE_TYPE, 0x90a, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define HAX_VCPU_IOCTL_SETUP_TUNNEL      CTL_CODE(HAX_DEVICE_TYPE, 0x90b, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_IOCTL_INTERRUPT        CTL_CODE(HAX_DEVICE_TYPE, 0x90c, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_SET_REGS               CTL_CODE(HAX_DEVICE_TYPE, 0x90d, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_VCPU_GET_REGS               CTL_CODE(HAX_DEVICE_TYPE, 0x90e, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif
index f0c546df5cff18a51ace6485fa3f821e56039020..2586aff700d178bc7b05fc7d59da7f06691ce7fd 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
-#include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "qemu-common.h"
 #include "kvm.h"
-#include "kvm_x86.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu.h"
+#include "monitor.h"
+#endif
 
 //#define DEBUG_MMU
 
@@ -96,18 +97,19 @@ void cpu_reset(CPUX86State *env)
 
     env->mxcsr = 0x1f80;
 
+    env->pat = 0x0007040600070406ULL;
+    env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
+
     memset(env->dr, 0, sizeof(env->dr));
     env->dr[6] = DR6_FIXED_1;
     env->dr[7] = DR7_FIXED_1;
     cpu_breakpoint_remove_all(env, BP_CPU);
     cpu_watchpoint_remove_all(env, BP_CPU);
-
-    env->mcg_status = 0;
 }
 
 void cpu_x86_close(CPUX86State *env)
 {
-    qemu_free(env);
+    g_free(env);
 }
 
 static void cpu_x86_version(CPUState *env, int *family, int *model)
@@ -400,21 +402,10 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     fptag,
                     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);
-#else
-            cpu_fprintf(f, "FPR%d=%016" PRIx64,
-                        i, env->fpregs[i].mmx.q);
-#endif
+                        i, u.l.lower, u.l.upper);
             if ((i & 1) == 1)
                 cpu_fprintf(f, "\n");
             else
@@ -556,7 +547,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 #if defined(CONFIG_USER_ONLY)
 
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write, int mmu_idx, int is_softmmu)
+                             int is_write, int mmu_idx)
 {
     /* user mode only emulation */
     is_write &= 1;
@@ -583,7 +574,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
    1  = generate PF fault
 */
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write1, int mmu_idx, int is_softmmu)
+                             int is_write1, int mmu_idx)
 {
     uint64_t ptep, pte;
     target_ulong pde_addr, pte_addr;
@@ -1037,8 +1028,6 @@ int check_hw_breakpoints(CPUState *env, int force_dr6_update)
 
 static CPUDebugExcpHandler *prev_debug_excp_handler;
 
-void raise_exception_env(int exception_index, CPUState *env);
-
 static void breakpoint_handler(CPUState *env)
 {
     CPUBreakpoint *bp;
@@ -1065,91 +1054,138 @@ static void breakpoint_handler(CPUState *env)
         prev_debug_excp_handler(env);
 }
 
-/* This should come from sysemu.h - if we could include it here... */
-void qemu_system_reset_request(void);
-
-static void qemu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc)
+typedef struct MCEInjectionParams {
+    Monitor *mon;
+    CPUState *env;
+    int bank;
+    uint64_t status;
+    uint64_t mcg_status;
+    uint64_t addr;
+    uint64_t misc;
+    int flags;
+} MCEInjectionParams;
+
+static void do_inject_x86_mce(void *data)
 {
-    uint64_t mcg_cap = cenv->mcg_cap;
-    uint64_t *banks = cenv->mce_banks;
+    MCEInjectionParams *params = data;
+    CPUState *cenv = params->env;
+    uint64_t *banks = cenv->mce_banks + 4 * params->bank;
+
+    cpu_synchronize_state(cenv);
 
     /*
-     * if MSR_MCG_CTL is not all 1s, the uncorrected error
-     * reporting is disabled
-     */
-    if ((status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) &&
-        cenv->mcg_ctl != ~(uint64_t)0)
-        return;
-    banks += 4 * bank;
-    /*
-     * if MSR_MCi_CTL is not all 1s, the uncorrected error
-     * reporting is disabled for the bank
+     * If there is an MCE exception being processed, ignore this SRAO MCE
+     * unless unconditional injection was requested.
      */
-    if ((status & MCI_STATUS_UC) && banks[0] != ~(uint64_t)0)
+    if (!(params->flags & MCE_INJECT_UNCOND_AO)
+        && !(params->status & MCI_STATUS_AR)
+        && (cenv->mcg_status & MCG_STATUS_MCIP)) {
         return;
-    if (status & MCI_STATUS_UC) {
+    }
+
+    if (params->status & MCI_STATUS_UC) {
+        /*
+         * if MSR_MCG_CTL is not all 1s, the uncorrected error
+         * reporting is disabled
+         */
+        if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
+            monitor_printf(params->mon,
+                           "CPU %d: Uncorrected error reporting disabled\n",
+                           cenv->cpu_index);
+            return;
+        }
+
+        /*
+         * if MSR_MCi_CTL is not all 1s, the uncorrected error
+         * reporting is disabled for the bank
+         */
+        if (banks[0] != ~(uint64_t)0) {
+            monitor_printf(params->mon,
+                           "CPU %d: Uncorrected error reporting disabled for"
+                           " bank %d\n",
+                           cenv->cpu_index, params->bank);
+            return;
+        }
+
         if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
             !(cenv->cr[4] & CR4_MCE_MASK)) {
-            fprintf(stderr, "injects mce exception while previous "
-                    "one is in progress!\n");
+            monitor_printf(params->mon,
+                           "CPU %d: Previous MCE still in progress, raising"
+                           " triple fault\n",
+                           cenv->cpu_index);
             qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
             qemu_system_reset_request();
             return;
         }
-        if (banks[1] & MCI_STATUS_VAL)
-            status |= MCI_STATUS_OVER;
-        banks[2] = addr;
-        banks[3] = misc;
-        cenv->mcg_status = mcg_status;
-        banks[1] = status;
+        if (banks[1] & MCI_STATUS_VAL) {
+            params->status |= MCI_STATUS_OVER;
+        }
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        cenv->mcg_status = params->mcg_status;
+        banks[1] = params->status;
         cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
     } else if (!(banks[1] & MCI_STATUS_VAL)
                || !(banks[1] & MCI_STATUS_UC)) {
-        if (banks[1] & MCI_STATUS_VAL)
-            status |= MCI_STATUS_OVER;
-        banks[2] = addr;
-        banks[3] = misc;
-        banks[1] = status;
-    } else
+        if (banks[1] & MCI_STATUS_VAL) {
+            params->status |= MCI_STATUS_OVER;
+        }
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        banks[1] = params->status;
+    } else {
         banks[1] |= MCI_STATUS_OVER;
+    }
 }
 
-void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int broadcast)
+void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
+                        uint64_t status, uint64_t mcg_status, uint64_t addr,
+                        uint64_t misc, int flags)
 {
+    MCEInjectionParams params = {
+        .mon = mon,
+        .env = cenv,
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+        .flags = flags,
+    };
     unsigned bank_num = cenv->mcg_cap & 0xff;
     CPUState *env;
-    int flag = 0;
 
-    if (bank >= bank_num || !(status & MCI_STATUS_VAL)) {
+    if (!cenv->mcg_cap) {
+        monitor_printf(mon, "MCE injection not supported\n");
         return;
     }
-
-    if (broadcast) {
-        if (!cpu_x86_support_mca_broadcast(cenv)) {
-            fprintf(stderr, "Current CPU does not support broadcast\n");
-            return;
-        }
+    if (bank >= bank_num) {
+        monitor_printf(mon, "Invalid MCE bank number\n");
+        return;
+    }
+    if (!(status & MCI_STATUS_VAL)) {
+        monitor_printf(mon, "Invalid MCE status code\n");
+        return;
+    }
+    if ((flags & MCE_INJECT_BROADCAST)
+        && !cpu_x86_support_mca_broadcast(cenv)) {
+        monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
+        return;
     }
 
-    if (kvm_enabled()) {
-        if (broadcast) {
-            flag |= MCE_BROADCAST;
-        }
-
-        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
-    } else {
-        qemu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
-        if (broadcast) {
-            for (env = first_cpu; env != NULL; env = env->next_cpu) {
-                if (cenv == env) {
-                    continue;
-                }
-                qemu_inject_x86_mce(env, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
-                                    MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0);
+    run_on_cpu(cenv, do_inject_x86_mce, &params);
+    if (flags & MCE_INJECT_BROADCAST) {
+        params.bank = 1;
+        params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
+        params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        params.addr = 0;
+        params.misc = 0;
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (cenv == env) {
+                continue;
             }
+            params.env = env;
+            run_on_cpu(cenv, do_inject_x86_mce, &params);
         }
     }
 }
@@ -1157,15 +1193,16 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
 
 static void mce_init(CPUX86State *cenv)
 {
-    unsigned int bank, bank_num;
+    unsigned int bank;
 
-    if (((cenv->cpuid_version >> 8)&0xf) >= 6
-        && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)) {
+    if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+        && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
+            (CPUID_MCE | CPUID_MCA)) {
         cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
         cenv->mcg_ctl = ~(uint64_t)0;
-        bank_num = MCE_BANKS_DEF;
-        for (bank = 0; bank < bank_num; bank++)
-            cenv->mce_banks[bank*4] = ~(uint64_t)0;
+        for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
+            cenv->mce_banks[bank * 4] = ~(uint64_t)0;
+        }
     }
 }
 
@@ -1203,12 +1240,12 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
     CPUX86State *env;
     static int inited;
 
-    env = qemu_mallocz(sizeof(CPUX86State));
+    env = g_malloc0(sizeof(CPUX86State));
     cpu_exec_init(env);
     env->cpu_model_str = cpu_model;
 
-    /* init various static tables */
-    if (!inited) {
+    /* init various static tables used in TCG mode */
+    if (tcg_enabled() && !inited) {
         inited = 1;
         optimize_flags_init();
 #ifndef CONFIG_USER_ONLY
@@ -1220,6 +1257,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
         cpu_x86_close(env);
         return NULL;
     }
+    env->cpuid_apic_id = env->cpu_index;
     mce_init(env);
 
     qemu_init_vcpu(env);
@@ -1231,8 +1269,11 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
 void do_cpu_init(CPUState *env)
 {
     int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
+    uint64_t pat = env->pat;
+
     cpu_reset(env);
     env->interrupt_request = sipi;
+    env->pat = pat;
     apic_init_reset(env->apic_state);
     env->halted = !cpu_is_bsp(env);
 }
index e3a2f5612975a951c5764c431834774b7bf2fcb9..6b518ad89f9a74d0bcac7062bbceec9ced54938a 100644 (file)
@@ -85,9 +85,6 @@ DEF_HELPER_0(rdpmc, void)
 DEF_HELPER_0(rdmsr, void)
 DEF_HELPER_0(wrmsr, void)
 
-/* opengl support by okdear */
-DEF_HELPER_0(opengl99, void)
-
 DEF_HELPER_1(check_iob, void, i32)
 DEF_HELPER_1(check_iow, void, i32)
 DEF_HELPER_1(check_iol, void, i32)
index 05010bbc38dd790ec7719954eaecfeec7a6bf359..5bfc21fc53748d2468c96a08d8f15f7d4e465d71 100644 (file)
@@ -18,6 +18,7 @@
 #include <sys/utsname.h>
 
 #include <linux/kvm.h>
+#include <linux/kvm_para.h>
 
 #include "qemu-common.h"
 #include "sysemu.h"
 #include "hw/pc.h"
 #include "hw/apic.h"
 #include "ioport.h"
-#include "kvm_x86.h"
 
-#ifdef CONFIG_KVM_PARA
-#include <linux/kvm_para.h>
-#endif
-//
 //#define DEBUG_KVM
 
 #ifdef DEBUG_KVM
@@ -63,9 +59,9 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 
 static bool has_msr_star;
 static bool has_msr_hsave_pa;
-#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ASYNC_PF)
+static bool has_msr_tsc_deadline;
 static bool has_msr_async_pf_en;
-#endif
+static bool has_msr_misc_enable;
 static int lm_capable_kernel;
 
 static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
@@ -74,7 +70,7 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
     int r, size;
 
     size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
-    cpuid = (struct kvm_cpuid2 *)qemu_mallocz(size);
+    cpuid = (struct kvm_cpuid2 *)g_malloc0(size);
     cpuid->nent = max;
     r = kvm_ioctl(s, KVM_GET_SUPPORTED_CPUID, cpuid);
     if (r == 0 && cpuid->nent >= max) {
@@ -82,7 +78,7 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
     }
     if (r < 0) {
         if (r == -E2BIG) {
-            qemu_free(cpuid);
+            g_free(cpuid);
             return NULL;
         } else {
             fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
@@ -93,22 +89,51 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
     return cpuid;
 }
 
-uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+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 },
+    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+    { -1, -1 }
+};
+
+static int get_para_features(KVMState *s)
+{
+    int i, features = 0;
+
+    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
+        if (kvm_check_extension(s, para_features[i].cap)) {
+            features |= (1 << para_features[i].feature);
+        }
+    }
+
+    return features;
+}
+
+
+uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
                                       uint32_t index, int reg)
 {
     struct kvm_cpuid2 *cpuid;
     int i, max;
     uint32_t ret = 0;
     uint32_t cpuid_1_edx;
+    int has_kvm_features = 0;
 
     max = 1;
-    while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
+    while ((cpuid = try_get_cpuid(s, max)) == NULL) {
         max *= 2;
     }
 
     for (i = 0; i < cpuid->nent; ++i) {
         if (cpuid->entries[i].function == function &&
             cpuid->entries[i].index == index) {
+            if (cpuid->entries[i].function == KVM_CPUID_FEATURES) {
+                has_kvm_features = 1;
+            }
             switch (reg) {
             case R_EAX:
                 ret = cpuid->entries[i].eax;
@@ -130,7 +155,7 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
                     /* On Intel, kvm returns cpuid according to the Intel spec,
                      * so add missing bits according to the AMD spec:
                      */
-                    cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, 0, R_EDX);
+                    cpuid_1_edx = kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
                     ret |= cpuid_1_edx & 0x183f7ff;
                     break;
                 }
@@ -139,42 +164,49 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
         }
     }
 
-    qemu_free(cpuid);
+    g_free(cpuid);
+
+    /* fallback for older kernels */
+    if (!has_kvm_features && (function == KVM_CPUID_FEATURES)) {
+        ret = get_para_features(s);
+    }
 
     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 }
-};
+typedef struct HWPoisonPage {
+    ram_addr_t ram_addr;
+    QLIST_ENTRY(HWPoisonPage) list;
+} HWPoisonPage;
+
+static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
+    QLIST_HEAD_INITIALIZER(hwpoison_page_list);
 
-static int get_para_features(CPUState *env)
+static void kvm_unpoison_all(void *param)
 {
-    int i, features = 0;
+    HWPoisonPage *page, *next_page;
 
-    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);
+    QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
+        QLIST_REMOVE(page, list);
+        qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
+        g_free(page);
+    }
+}
+
+static void kvm_hwpoison_page_add(ram_addr_t ram_addr)
+{
+    HWPoisonPage *page;
+
+    QLIST_FOREACH(page, &hwpoison_page_list, list) {
+        if (page->ram_addr == ram_addr) {
+            return;
         }
     }
-#ifdef KVM_CAP_ASYNC_PF
-    has_msr_async_pf_en = features & (1 << KVM_FEATURE_ASYNC_PF);
-#endif
-    return features;
+    page = g_malloc(sizeof(HWPoisonPage));
+    page->ram_addr = ram_addr;
+    QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
 }
-#endif
 
-#ifdef KVM_CAP_MCE
 static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
                                      int *max_banks)
 {
@@ -188,117 +220,129 @@ static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
     return -ENOSYS;
 }
 
-static int kvm_setup_mce(CPUState *env, uint64_t *mcg_cap)
+static void kvm_mce_inject(CPUState *env, target_phys_addr_t paddr, int code)
 {
-    return kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, mcg_cap);
-}
+    uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
+                      MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S;
+    uint64_t mcg_status = MCG_STATUS_MCIP;
 
-static int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m)
-{
-    return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
+    if (code == BUS_MCEERR_AR) {
+        status |= MCI_STATUS_AR | 0x134;
+        mcg_status |= MCG_STATUS_EIPV;
+    } else {
+        status |= 0xc0;
+        mcg_status |= MCG_STATUS_RIPV;
+    }
+    cpu_x86_inject_mce(NULL, env, 9, status, mcg_status, paddr,
+                       (MCM_ADDR_PHYS << 6) | 0xc,
+                       cpu_x86_support_mca_broadcast(env) ?
+                       MCE_INJECT_BROADCAST : 0);
 }
 
-static int kvm_get_msr(CPUState *env, struct kvm_msr_entry *msrs, int n)
+static void hardware_memory_error(void)
 {
-    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
-    int r;
-
-    kmsrs->nmsrs = n;
-    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
-    r = kvm_vcpu_ioctl(env, KVM_GET_MSRS, kmsrs);
-    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
-    free(kmsrs);
-    return r;
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
 }
 
-/* FIXME: kill this and kvm_get_msr, use env->mcg_status instead */
-static int kvm_mce_in_progress(CPUState *env)
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
 {
-    struct kvm_msr_entry msr_mcg_status = {
-        .index = MSR_MCG_STATUS,
-    };
-    int r;
+    ram_addr_t ram_addr;
+    target_phys_addr_t paddr;
 
-    r = kvm_get_msr(env, &msr_mcg_status, 1);
-    if (r == -1 || r == 0) {
-        fprintf(stderr, "Failed to get MCE status\n");
-        return 0;
+    if ((env->mcg_cap & MCG_SER_P) && addr
+        && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) {
+        if (qemu_ram_addr_from_host(addr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr,
+                                               &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!\n");
+            /* Hope we are lucky for AO MCE */
+            if (code == BUS_MCEERR_AO) {
+                return 0;
+            } else {
+                hardware_memory_error();
+            }
+        }
+        kvm_hwpoison_page_add(ram_addr);
+        kvm_mce_inject(env, paddr, code);
+    } else {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
     }
-    return !!(msr_mcg_status.data & MCG_STATUS_MCIP);
+    return 0;
 }
 
-struct kvm_x86_mce_data
-{
-    CPUState *env;
-    struct kvm_x86_mce *mce;
-    int abort_on_error;
-};
-
-static void kvm_do_inject_x86_mce(void *_data)
+int kvm_arch_on_sigbus(int code, void *addr)
 {
-    struct kvm_x86_mce_data *data = _data;
-    int r;
+    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
+        ram_addr_t ram_addr;
+        target_phys_addr_t paddr;
 
-    /* If there is an MCE exception being processed, ignore this SRAO MCE */
-    if ((data->env->mcg_cap & MCG_SER_P) &&
-        !(data->mce->status & MCI_STATUS_AR)) {
-        if (kvm_mce_in_progress(data->env)) {
-            return;
+        /* Hope we are lucky for AO MCE */
+        if (qemu_ram_addr_from_host(addr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr,
+                                               &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!: %p\n", addr);
+            return 0;
         }
-    }
-
-    r = kvm_set_mce(data->env, data->mce);
-    if (r < 0) {
-        perror("kvm_set_mce FAILED");
-        if (data->abort_on_error) {
-            abort();
+        kvm_hwpoison_page_add(ram_addr);
+        kvm_mce_inject(first_cpu, paddr, code);
+    } else {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
         }
     }
+    return 0;
 }
 
-static void kvm_inject_x86_mce_on(CPUState *env, struct kvm_x86_mce *mce,
-                                  int flag)
+static int kvm_inject_mce_oldstyle(CPUState *env)
 {
-    struct kvm_x86_mce_data data = {
-        .env = env,
-        .mce = mce,
-        .abort_on_error = (flag & ABORT_ON_ERROR),
-    };
-
-    if (!env->mcg_cap) {
-        fprintf(stderr, "MCE support is not enabled!\n");
-        return;
-    }
+    if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) {
+        unsigned int bank, bank_num = env->mcg_cap & 0xff;
+        struct kvm_x86_mce mce;
 
-    run_on_cpu(env, kvm_do_inject_x86_mce, &data);
-}
+        env->exception_injected = -1;
 
-static void kvm_mce_broadcast_rest(CPUState *env);
-#endif
+        /*
+         * There must be at least one bank in use if an MCE is pending.
+         * Find it and use its values for the event injection.
+         */
+        for (bank = 0; bank < bank_num; bank++) {
+            if (env->mce_banks[bank * 4 + 1] & MCI_STATUS_VAL) {
+                break;
+            }
+        }
+        assert(bank < bank_num);
 
-void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int flag)
-{
-#ifdef KVM_CAP_MCE
-    struct kvm_x86_mce mce = {
-        .bank = bank,
-        .status = status,
-        .mcg_status = mcg_status,
-        .addr = addr,
-        .misc = misc,
-    };
+        mce.bank = bank;
+        mce.status = env->mce_banks[bank * 4 + 1];
+        mce.mcg_status = env->mcg_status;
+        mce.addr = env->mce_banks[bank * 4 + 2];
+        mce.misc = env->mce_banks[bank * 4 + 3];
 
-    if (flag & MCE_BROADCAST) {
-        kvm_mce_broadcast_rest(cenv);
+        return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce);
     }
+    return 0;
+}
 
-    kvm_inject_x86_mce_on(cenv, &mce, flag);
-#else
-    if (flag & ABORT_ON_ERROR) {
-        abort();
+static void cpu_update_state(void *opaque, int running, RunState state)
+{
+    CPUState *env = opaque;
+
+    if (running) {
+        env->tsc_valid = false;
     }
-#endif
 }
 
 int kvm_arch_init_vcpu(CPUState *env)
@@ -306,31 +350,29 @@ int kvm_arch_init_vcpu(CPUState *env)
     struct {
         struct kvm_cpuid2 cpuid;
         struct kvm_cpuid_entry2 entries[100];
-    } __attribute__((packed)) cpuid_data;
+    } QEMU_PACKED cpuid_data;
+    KVMState *s = env->kvm_state;
     uint32_t limit, i, j, cpuid_i;
     uint32_t unused;
     struct kvm_cpuid_entry2 *c;
-#ifdef CONFIG_KVM_PARA
     uint32_t signature[3];
-#endif
+    int r;
 
-    env->cpuid_features &= kvm_arch_get_supported_cpuid(env, 1, 0, R_EDX);
+    env->cpuid_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
 
     i = env->cpuid_ext_features & CPUID_EXT_HYPERVISOR;
-    env->cpuid_ext_features &= kvm_arch_get_supported_cpuid(env, 1, 0, R_ECX);
+    env->cpuid_ext_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX);
     env->cpuid_ext_features |= i;
 
-    env->cpuid_ext2_features &= kvm_arch_get_supported_cpuid(env, 0x80000001,
+    env->cpuid_ext2_features &= kvm_arch_get_supported_cpuid(s, 0x80000001,
                                                              0, R_EDX);
-    env->cpuid_ext3_features &= kvm_arch_get_supported_cpuid(env, 0x80000001,
+    env->cpuid_ext3_features &= kvm_arch_get_supported_cpuid(s, 0x80000001,
                                                              0, R_ECX);
-    env->cpuid_svm_features  &= kvm_arch_get_supported_cpuid(env, 0x8000000A,
+    env->cpuid_svm_features  &= kvm_arch_get_supported_cpuid(s, 0x8000000A,
                                                              0, R_EDX);
 
-
     cpuid_i = 0;
 
-#ifdef CONFIG_KVM_PARA
     /* Paravirtualization CPUIDs */
     memcpy(signature, "KVMKVMKVM\0\0\0", 12);
     c = &cpuid_data.entries[cpuid_i++];
@@ -344,8 +386,10 @@ 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);
-#endif
+    c->eax = env->cpuid_kvm_features &
+        kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+
+    has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
 
     cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
 
@@ -375,6 +419,9 @@ int kvm_arch_init_vcpu(CPUState *env)
         case 0xb:
         case 0xd:
             for (j = 0; ; j++) {
+                if (i == 0xd && j == 64) {
+                    break;
+                }
                 c->function = i;
                 c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                 c->index = j;
@@ -387,7 +434,7 @@ int kvm_arch_init_vcpu(CPUState *env)
                     break;
                 }
                 if (i == 0xd && c->eax == 0) {
-                    break;
+                    continue;
                 }
                 c = &cpuid_data.entries[cpuid_i++];
             }
@@ -409,32 +456,67 @@ int kvm_arch_init_vcpu(CPUState *env)
         cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
     }
 
+    /* Call Centaur's CPUID instructions they are supported. */
+    if (env->cpuid_xlevel2 > 0) {
+        env->cpuid_ext4_features &=
+            kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
+        cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+        for (i = 0xC0000000; i <= limit; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+
+            c->function = i;
+            c->flags = 0;
+            cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+        }
+    }
+
     cpuid_data.cpuid.nent = cpuid_i;
 
-#ifdef KVM_CAP_MCE
     if (((env->cpuid_version >> 8)&0xF) >= 6
         && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
         && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {
         uint64_t mcg_cap;
         int banks;
+        int ret;
 
-        if (kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks)) {
-            perror("kvm_get_mce_cap_supported FAILED");
-        } else {
-            if (banks > MCE_BANKS_DEF)
-                banks = MCE_BANKS_DEF;
-            mcg_cap &= MCE_CAP_DEF;
-            mcg_cap |= banks;
-            if (kvm_setup_mce(env, &mcg_cap)) {
-                perror("kvm_setup_mce FAILED");
-            } else {
-                env->mcg_cap = mcg_cap;
-            }
+        ret = kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks);
+        if (ret < 0) {
+            fprintf(stderr, "kvm_get_mce_cap_supported: %s", strerror(-ret));
+            return ret;
+        }
+
+        if (banks > MCE_BANKS_DEF) {
+            banks = MCE_BANKS_DEF;
         }
+        mcg_cap &= MCE_CAP_DEF;
+        mcg_cap |= banks;
+        ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
+            return ret;
+        }
+
+        env->mcg_cap = mcg_cap;
     }
-#endif
 
-    return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
+    qemu_add_vm_change_state_handler(cpu_update_state, env);
+
+    r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
+    if (r) {
+        return r;
+    }
+
+    r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL);
+    if (r && env->tsc_khz) {
+        r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz);
+        if (r < 0) {
+            fprintf(stderr, "KVM_SET_TSC_KHZ failed\n");
+            return r;
+        }
+    }
+
+    return 0;
 }
 
 void kvm_arch_reset_vcpu(CPUState *env)
@@ -470,7 +552,7 @@ static int kvm_get_supported_msrs(KVMState *s)
         }
         /* Old kernel modules had a bug and could write beyond the provided
            memory. Allocate at least a safe amount of 1K. */
-        kvm_msr_list = qemu_mallocz(MAX(1024, sizeof(msr_list) +
+        kvm_msr_list = g_malloc0(MAX(1024, sizeof(msr_list) +
                                               msr_list.nmsrs *
                                               sizeof(msr_list.indices[0])));
 
@@ -488,10 +570,18 @@ static int kvm_get_supported_msrs(KVMState *s)
                     has_msr_hsave_pa = true;
                     continue;
                 }
+                if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) {
+                    has_msr_tsc_deadline = true;
+                    continue;
+                }
+                if (kvm_msr_list->indices[i] == MSR_IA32_MISC_ENABLE) {
+                    has_msr_misc_enable = true;
+                    continue;
+                }
             }
         }
 
-        free(kvm_msr_list);
+        g_free(kvm_msr_list);
     }
 
     return ret;
@@ -522,7 +612,6 @@ int kvm_arch_init(KVMState *s)
      * that case we need to stick with the default, i.e. a 256K maximum BIOS
      * size.
      */
-#ifdef KVM_CAP_SET_IDENTITY_MAP_ADDR
     if (kvm_check_extension(s, KVM_CAP_SET_IDENTITY_MAP_ADDR)) {
         /* Allows up to 16M BIOSes. */
         identity_base = 0xfeffc000;
@@ -532,7 +621,7 @@ int kvm_arch_init(KVMState *s)
             return ret;
         }
     }
-#endif
+
     /* Set TSS base one page after EPT identity map. */
     ret = kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, identity_base + 0x1000);
     if (ret < 0) {
@@ -545,6 +634,7 @@ int kvm_arch_init(KVMState *s)
         fprintf(stderr, "e820_add_entry() table is full\n");
         return ret;
     }
+    qemu_register_reset(kvm_unpoison_all, NULL);
 
     return 0;
 }
@@ -656,6 +746,9 @@ static int kvm_put_fpu(CPUState *env)
     fpu.fsw = env->fpus & ~(7 << 11);
     fpu.fsw |= (env->fpstt & 7) << 11;
     fpu.fcw = env->fpuc;
+    fpu.last_opcode = env->fpop;
+    fpu.last_ip = env->fpip;
+    fpu.last_dp = env->fpdp;
     for (i = 0; i < 8; ++i) {
         fpu.ftwx |= (!env->fptags[i]) << i;
     }
@@ -666,7 +759,6 @@ static int kvm_put_fpu(CPUState *env)
     return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu);
 }
 
-#ifdef KVM_CAP_XSAVE
 #define XSAVE_CWD_RIP     2
 #define XSAVE_CWD_RDP     4
 #define XSAVE_MXCSR       6
@@ -674,14 +766,12 @@ static int kvm_put_fpu(CPUState *env)
 #define XSAVE_XMM_SPACE   40
 #define XSAVE_XSTATE_BV   128
 #define XSAVE_YMMH_SPACE  144
-#endif
 
 static int kvm_put_xsave(CPUState *env)
 {
-#ifdef KVM_CAP_XSAVE
     int i, r;
     struct kvm_xsave* xsave;
-    uint16_t cwd, swd, twd, fop;
+    uint16_t cwd, swd, twd;
 
     if (!kvm_has_xsave()) {
         return kvm_put_fpu(env);
@@ -689,7 +779,7 @@ static int kvm_put_xsave(CPUState *env)
 
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     memset(xsave, 0, sizeof(struct kvm_xsave));
-    cwd = swd = twd = fop = 0;
+    twd = 0;
     swd = env->fpus & ~(7 << 11);
     swd |= (env->fpstt & 7) << 11;
     cwd = env->fpuc;
@@ -697,7 +787,9 @@ static int kvm_put_xsave(CPUState *env)
         twd |= (!env->fptags[i]) << i;
     }
     xsave->region[0] = (uint32_t)(swd << 16) + cwd;
-    xsave->region[1] = (uint32_t)(fop << 16) + twd;
+    xsave->region[1] = (uint32_t)(env->fpop << 16) + twd;
+    memcpy(&xsave->region[XSAVE_CWD_RIP], &env->fpip, sizeof(env->fpip));
+    memcpy(&xsave->region[XSAVE_CWD_RDP], &env->fpdp, sizeof(env->fpdp));
     memcpy(&xsave->region[XSAVE_ST_SPACE], env->fpregs,
             sizeof env->fpregs);
     memcpy(&xsave->region[XSAVE_XMM_SPACE], env->xmm_regs,
@@ -707,16 +799,12 @@ static int kvm_put_xsave(CPUState *env)
     memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs,
             sizeof env->ymmh_regs);
     r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
-    qemu_free(xsave);
+    g_free(xsave);
     return r;
-#else
-    return kvm_put_fpu(env);
-#endif
 }
 
 static int kvm_put_xcrs(CPUState *env)
 {
-#ifdef KVM_CAP_XCRS
     struct kvm_xcrs xcrs;
 
     if (!kvm_has_xcrs()) {
@@ -728,9 +816,6 @@ static int kvm_put_xcrs(CPUState *env)
     xcrs.xcrs[0].xcr = 0;
     xcrs.xcrs[0].value = env->xcr0;
     return kvm_vcpu_ioctl(env, KVM_SET_XCRS, &xcrs);
-#else
-    return 0;
-#endif
 }
 
 static int kvm_put_sregs(CPUState *env)
@@ -799,12 +884,20 @@ static int kvm_put_msrs(CPUState *env, int level)
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+    kvm_msr_entry_set(&msrs[n++], MSR_PAT, env->pat);
     if (has_msr_star) {
         kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
     }
     if (has_msr_hsave_pa) {
         kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
     }
+    if (has_msr_tsc_deadline) {
+        kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline);
+    }
+    if (has_msr_misc_enable) {
+        kvm_msr_entry_set(&msrs[n++], MSR_IA32_MISC_ENABLE,
+                          env->msr_ia32_misc_enable);
+    }
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -833,28 +926,20 @@ static int kvm_put_msrs(CPUState *env, int level)
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
                           env->system_time_msr);
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
-#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ASYNC_PF)
         if (has_msr_async_pf_en) {
             kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
                               env->async_pf_en_msr);
         }
-#endif
     }
-#ifdef KVM_CAP_MCE
     if (env->mcg_cap) {
         int i;
 
-        if (level == KVM_PUT_RESET_STATE) {
-            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
-        } else if (level == KVM_PUT_FULL_STATE) {
-            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
-            kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
-            for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) {
-                kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
-            }
+        kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+        kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
+        for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) {
+            kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
         }
     }
-#endif
 
     msr_data.info.nmsrs = n;
 
@@ -876,6 +961,9 @@ static int kvm_get_fpu(CPUState *env)
     env->fpstt = (fpu.fsw >> 11) & 7;
     env->fpus = fpu.fsw;
     env->fpuc = fpu.fcw;
+    env->fpop = fpu.last_opcode;
+    env->fpip = fpu.last_ip;
+    env->fpdp = fpu.last_dp;
     for (i = 0; i < 8; ++i) {
         env->fptags[i] = !((fpu.ftwx >> i) & 1);
     }
@@ -888,10 +976,9 @@ static int kvm_get_fpu(CPUState *env)
 
 static int kvm_get_xsave(CPUState *env)
 {
-#ifdef KVM_CAP_XSAVE
     struct kvm_xsave* xsave;
     int ret, i;
-    uint16_t cwd, swd, twd, fop;
+    uint16_t cwd, swd, twd;
 
     if (!kvm_has_xsave()) {
         return kvm_get_fpu(env);
@@ -900,20 +987,22 @@ static int kvm_get_xsave(CPUState *env)
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave);
     if (ret < 0) {
-        qemu_free(xsave);
+        g_free(xsave);
         return ret;
     }
 
     cwd = (uint16_t)xsave->region[0];
     swd = (uint16_t)(xsave->region[0] >> 16);
     twd = (uint16_t)xsave->region[1];
-    fop = (uint16_t)(xsave->region[1] >> 16);
+    env->fpop = (uint16_t)(xsave->region[1] >> 16);
     env->fpstt = (swd >> 11) & 7;
     env->fpus = swd;
     env->fpuc = cwd;
     for (i = 0; i < 8; ++i) {
         env->fptags[i] = !((twd >> i) & 1);
     }
+    memcpy(&env->fpip, &xsave->region[XSAVE_CWD_RIP], sizeof(env->fpip));
+    memcpy(&env->fpdp, &xsave->region[XSAVE_CWD_RDP], sizeof(env->fpdp));
     env->mxcsr = xsave->region[XSAVE_MXCSR];
     memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE],
             sizeof env->fpregs);
@@ -922,16 +1011,12 @@ static int kvm_get_xsave(CPUState *env)
     env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV];
     memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE],
             sizeof env->ymmh_regs);
-    qemu_free(xsave);
+    g_free(xsave);
     return 0;
-#else
-    return kvm_get_fpu(env);
-#endif
 }
 
 static int kvm_get_xcrs(CPUState *env)
 {
-#ifdef KVM_CAP_XCRS
     int i, ret;
     struct kvm_xcrs xcrs;
 
@@ -952,9 +1037,6 @@ static int kvm_get_xcrs(CPUState *env)
         }
     }
     return 0;
-#else
-    return 0;
-#endif
 }
 
 static int kvm_get_sregs(CPUState *env)
@@ -1055,13 +1137,25 @@ static int kvm_get_msrs(CPUState *env)
     msrs[n++].index = MSR_IA32_SYSENTER_CS;
     msrs[n++].index = MSR_IA32_SYSENTER_ESP;
     msrs[n++].index = MSR_IA32_SYSENTER_EIP;
+    msrs[n++].index = MSR_PAT;
     if (has_msr_star) {
         msrs[n++].index = MSR_STAR;
     }
     if (has_msr_hsave_pa) {
         msrs[n++].index = MSR_VM_HSAVE_PA;
     }
-    msrs[n++].index = MSR_IA32_TSC;
+    if (has_msr_tsc_deadline) {
+        msrs[n++].index = MSR_IA32_TSCDEADLINE;
+    }
+    if (has_msr_misc_enable) {
+        msrs[n++].index = MSR_IA32_MISC_ENABLE;
+    }
+
+    if (!env->tsc_valid) {
+        msrs[n++].index = MSR_IA32_TSC;
+        env->tsc_valid = !runstate_is_running();
+    }
+
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         msrs[n++].index = MSR_CSTAR;
@@ -1072,13 +1166,10 @@ static int kvm_get_msrs(CPUState *env)
 #endif
     msrs[n++].index = MSR_KVM_SYSTEM_TIME;
     msrs[n++].index = MSR_KVM_WALL_CLOCK;
-#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ASYNC_PF)
     if (has_msr_async_pf_en) {
         msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
     }
-#endif
 
-#ifdef KVM_CAP_MCE
     if (env->mcg_cap) {
         msrs[n++].index = MSR_MCG_STATUS;
         msrs[n++].index = MSR_MCG_CTL;
@@ -1086,7 +1177,6 @@ static int kvm_get_msrs(CPUState *env)
             msrs[n++].index = MSR_MC0_CTL + i;
         }
     }
-#endif
 
     msr_data.info.nmsrs = n;
     ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data);
@@ -1105,6 +1195,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_SYSENTER_EIP:
             env->sysenter_eip = msrs[i].data;
             break;
+        case MSR_PAT:
+            env->pat = msrs[i].data;
+            break;
         case MSR_STAR:
             env->star = msrs[i].data;
             break;
@@ -1125,6 +1218,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_IA32_TSCDEADLINE:
+            env->tsc_deadline = msrs[i].data;
+            break;
         case MSR_VM_HSAVE_PA:
             env->vm_hsave = msrs[i].data;
             break;
@@ -1134,27 +1230,24 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_KVM_WALL_CLOCK:
             env->wall_clock_msr = msrs[i].data;
             break;
-#ifdef KVM_CAP_MCE
         case MSR_MCG_STATUS:
             env->mcg_status = msrs[i].data;
             break;
         case MSR_MCG_CTL:
             env->mcg_ctl = msrs[i].data;
             break;
-#endif
+        case MSR_IA32_MISC_ENABLE:
+            env->msr_ia32_misc_enable = msrs[i].data;
+            break;
         default:
-#ifdef KVM_CAP_MCE
             if (msrs[i].index >= MSR_MC0_CTL &&
                 msrs[i].index < MSR_MC0_CTL + (env->mcg_cap & 0xff) * 4) {
                 env->mce_banks[msrs[i].index - MSR_MC0_CTL] = msrs[i].data;
             }
-#endif
             break;
-#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ASYNC_PF)
         case MSR_KVM_ASYNC_PF_EN:
             env->async_pf_en_msr = msrs[i].data;
             break;
-#endif
         }
     }
 
@@ -1186,7 +1279,6 @@ static int kvm_get_mp_state(CPUState *env)
 
 static int kvm_put_vcpu_events(CPUState *env, int level)
 {
-#ifdef KVM_CAP_VCPU_EVENTS
     struct kvm_vcpu_events events;
 
     if (!kvm_has_vcpu_events()) {
@@ -1215,14 +1307,10 @@ static int kvm_put_vcpu_events(CPUState *env, int level)
     }
 
     return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events);
-#else
-    return 0;
-#endif
 }
 
 static int kvm_get_vcpu_events(CPUState *env)
 {
-#ifdef KVM_CAP_VCPU_EVENTS
     struct kvm_vcpu_events events;
     int ret;
 
@@ -1252,7 +1340,6 @@ static int kvm_get_vcpu_events(CPUState *env)
     }
 
     env->sipi_vector = events.sipi_vector;
-#endif
 
     return 0;
 }
@@ -1260,7 +1347,6 @@ static int kvm_get_vcpu_events(CPUState *env)
 static int kvm_guest_debug_workarounds(CPUState *env)
 {
     int ret = 0;
-#ifdef KVM_CAP_SET_GUEST_DEBUG
     unsigned long reinject_trap = 0;
 
     if (!kvm_has_vcpu_events()) {
@@ -1284,13 +1370,11 @@ static int kvm_guest_debug_workarounds(CPUState *env)
         (!kvm_has_robust_singlestep() && env->singlestep_enabled)) {
         ret = kvm_update_guest_debug(env, reinject_trap);
     }
-#endif /* KVM_CAP_SET_GUEST_DEBUG */
     return ret;
 }
 
 static int kvm_put_debugregs(CPUState *env)
 {
-#ifdef KVM_CAP_DEBUGREGS
     struct kvm_debugregs dbgregs;
     int i;
 
@@ -1306,14 +1390,10 @@ static int kvm_put_debugregs(CPUState *env)
     dbgregs.flags = 0;
 
     return kvm_vcpu_ioctl(env, KVM_SET_DEBUGREGS, &dbgregs);
-#else
-    return 0;
-#endif
 }
 
 static int kvm_get_debugregs(CPUState *env)
 {
-#ifdef KVM_CAP_DEBUGREGS
     struct kvm_debugregs dbgregs;
     int i, ret;
 
@@ -1330,7 +1410,6 @@ static int kvm_get_debugregs(CPUState *env)
     }
     env->dr[4] = env->dr[6] = dbgregs.dr6;
     env->dr[5] = env->dr[7] = dbgregs.dr7;
-#endif
 
     return 0;
 }
@@ -1339,7 +1418,7 @@ int kvm_arch_put_registers(CPUState *env, int level)
 {
     int ret;
 
-    assert(cpu_is_stopped(env) || qemu_cpu_self(env));
+    assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
 
     ret = kvm_getput_regs(env, 1);
     if (ret < 0) {
@@ -1357,6 +1436,11 @@ int kvm_arch_put_registers(CPUState *env, int level)
     if (ret < 0) {
         return ret;
     }
+    /* must be before kvm_put_msrs */
+    ret = kvm_inject_mce_oldstyle(env);
+    if (ret < 0) {
+        return ret;
+    }
     ret = kvm_put_msrs(env, level);
     if (ret < 0) {
         return ret;
@@ -1387,7 +1471,7 @@ int kvm_arch_get_registers(CPUState *env)
 {
     int ret;
 
-    assert(cpu_is_stopped(env) || qemu_cpu_self(env));
+    assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
 
     ret = kvm_getput_regs(env, 0);
     if (ret < 0) {
@@ -1424,49 +1508,65 @@ int kvm_arch_get_registers(CPUState *env)
     return 0;
 }
 
-int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
 {
+    int ret;
+
     /* Inject NMI */
     if (env->interrupt_request & CPU_INTERRUPT_NMI) {
         env->interrupt_request &= ~CPU_INTERRUPT_NMI;
         DPRINTF("injected NMI\n");
-        kvm_vcpu_ioctl(env, KVM_NMI);
-    }
-
-    /* Try to inject an interrupt if the guest can accept it */
-    if (run->ready_for_interrupt_injection &&
-        (env->interrupt_request & CPU_INTERRUPT_HARD) &&
-        (env->eflags & IF_MASK)) {
-        int irq;
-
-        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-        irq = cpu_get_pic_interrupt(env);
-        if (irq >= 0) {
-            struct kvm_interrupt intr;
-            intr.irq = irq;
-            /* FIXME: errors */
-            DPRINTF("injected interrupt %d\n", irq);
-            kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr);
+        ret = kvm_vcpu_ioctl(env, KVM_NMI);
+        if (ret < 0) {
+            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+                    strerror(-ret));
         }
     }
 
-    /* If we have an interrupt but the guest is not ready to receive an
-     * interrupt, request an interrupt window exit.  This will
-     * cause a return to userspace as soon as the guest is ready to
-     * receive interrupts. */
-    if ((env->interrupt_request & CPU_INTERRUPT_HARD)) {
-        run->request_interrupt_window = 1;
-    } else {
-        run->request_interrupt_window = 0;
-    }
+    if (!kvm_irqchip_in_kernel()) {
+        /* Force the VCPU out of its inner loop to process the INIT request */
+        if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+            env->exit_request = 1;
+        }
+
+        /* Try to inject an interrupt if the guest can accept it */
+        if (run->ready_for_interrupt_injection &&
+            (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->eflags & IF_MASK)) {
+            int irq;
+
+            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+            irq = cpu_get_pic_interrupt(env);
+            if (irq >= 0) {
+                struct kvm_interrupt intr;
+
+                intr.irq = irq;
+                DPRINTF("injected interrupt %d\n", irq);
+                ret = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr);
+                if (ret < 0) {
+                    fprintf(stderr,
+                            "KVM: injection failed, interrupt lost (%s)\n",
+                            strerror(-ret));
+                }
+            }
+        }
 
-    DPRINTF("setting tpr\n");
-    run->cr8 = cpu_get_apic_tpr(env->apic_state);
+        /* If we have an interrupt but the guest is not ready to receive an
+         * interrupt, request an interrupt window exit.  This will
+         * cause a return to userspace as soon as the guest is ready to
+         * receive interrupts. */
+        if ((env->interrupt_request & CPU_INTERRUPT_HARD)) {
+            run->request_interrupt_window = 1;
+        } else {
+            run->request_interrupt_window = 0;
+        }
 
-    return 0;
+        DPRINTF("setting tpr\n");
+        run->cr8 = cpu_get_apic_tpr(env->apic_state);
+    }
 }
 
-int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
     if (run->if_flag) {
         env->eflags |= IF_MASK;
@@ -1475,18 +1575,46 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
     }
     cpu_set_apic_tpr(env->apic_state, run->cr8);
     cpu_set_apic_base(env->apic_state, run->apic_base);
-
-    return 0;
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
+    if (env->interrupt_request & CPU_INTERRUPT_MCE) {
+        /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */
+        assert(env->mcg_cap);
+
+        env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+
+        kvm_cpu_synchronize_state(env);
+
+        if (env->exception_injected == EXCP08_DBLE) {
+            /* this means triple fault */
+            qemu_system_reset_request();
+            env->exit_request = 1;
+            return 0;
+        }
+        env->exception_injected = EXCP12_MCHK;
+        env->has_error_code = 0;
+
+        env->halted = 0;
+        if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) {
+            env->mp_state = KVM_MP_STATE_RUNNABLE;
+        }
+    }
+
+    if (kvm_irqchip_in_kernel()) {
+        return 0;
+    }
+
+    if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+         (env->eflags & IF_MASK)) ||
+        (env->interrupt_request & CPU_INTERRUPT_NMI)) {
+        env->halted = 0;
+    }
     if (env->interrupt_request & CPU_INTERRUPT_INIT) {
         kvm_cpu_synchronize_state(env);
         do_cpu_init(env);
-        env->exception_index = EXCP_HALTED;
     }
-
     if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
         kvm_cpu_synchronize_state(env);
         do_cpu_sipi(env);
@@ -1501,68 +1629,12 @@ static int kvm_handle_halt(CPUState *env)
           (env->eflags & IF_MASK)) &&
         !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
         env->halted = 1;
-        env->exception_index = EXCP_HLT;
-        return 0;
+        return EXCP_HLT;
     }
 
-    return 1;
-}
-
-static bool host_supports_vmx(void)
-{
-    uint32_t ecx, unused;
-
-    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
-    return ecx & CPUID_EXT_VMX;
-}
-
-#define VMX_INVALID_GUEST_STATE 0x80000021
-
-int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
-{
-    uint64_t code;
-    int ret = 0;
-
-    switch (run->exit_reason) {
-    case KVM_EXIT_HLT:
-        DPRINTF("handle_hlt\n");
-        ret = kvm_handle_halt(env);
-        break;
-    case KVM_EXIT_SET_TPR:
-        ret = 1;
-        break;
-    case KVM_EXIT_FAIL_ENTRY:
-        code = run->fail_entry.hardware_entry_failure_reason;
-        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
-                code);
-        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
-            fprintf(stderr,
-                    "\nIf you're runnning a guest on an Intel machine without "
-                        "unrestricted mode\n"
-                    "support, the failure can be most likely due to the guest "
-                        "entering an invalid\n"
-                    "state for Intel VT. For example, the guest maybe running "
-                        "in big real mode\n"
-                    "which is not supported on less recent Intel processors."
-                        "\n\n");
-        }
-        ret = -1;
-        break;
-    case KVM_EXIT_EXCEPTION:
-        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
-                run->ex.exception, run->ex.error_code);
-        ret = -1;
-        break;
-    default:
-        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
-        ret = -1;
-        break;
-    }
-
-    return ret;
+    return 0;
 }
 
-#ifdef KVM_CAP_SET_GUEST_DEBUG
 int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t int3 = 0xcc;
@@ -1669,31 +1741,31 @@ void kvm_arch_remove_all_hw_breakpoints(void)
 
 static CPUWatchpoint hw_watchpoint;
 
-int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
+static int kvm_handle_debug(struct kvm_debug_exit_arch *arch_info)
 {
-    int handle = 0;
+    int ret = 0;
     int n;
 
     if (arch_info->exception == 1) {
         if (arch_info->dr6 & (1 << 14)) {
             if (cpu_single_env->singlestep_enabled) {
-                handle = 1;
+                ret = EXCP_DEBUG;
             }
         } else {
             for (n = 0; n < 4; n++) {
                 if (arch_info->dr6 & (1 << n)) {
                     switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) {
                     case 0x0:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         break;
                     case 0x1:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         cpu_single_env->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_WRITE;
                         break;
                     case 0x3:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         cpu_single_env->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_ACCESS;
@@ -1703,17 +1775,18 @@ int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
             }
         }
     } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) {
-        handle = 1;
+        ret = EXCP_DEBUG;
     }
-    if (!handle) {
+    if (ret == 0) {
         cpu_synchronize_state(cpu_single_env);
         assert(cpu_single_env->exception_injected == -1);
 
+        /* pass to guest */
         cpu_single_env->exception_injected = arch_info->exception;
         cpu_single_env->has_error_code = 0;
     }
 
-    return handle;
+    return ret;
 }
 
 void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
@@ -1742,180 +1815,67 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
         }
     }
 }
-#endif /* KVM_CAP_SET_GUEST_DEBUG */
-
-bool kvm_arch_stop_on_emulation_error(CPUState *env)
-{
-    return !(env->cr[0] & CR0_PE_MASK) ||
-           ((env->segs[R_CS].selector  & 3) != 3);
-}
-
-static void hardware_memory_error(void)
-{
-    fprintf(stderr, "Hardware memory error!\n");
-    exit(1);
-}
-
-#ifdef KVM_CAP_MCE
-static void kvm_mce_broadcast_rest(CPUState *env)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 1,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = 0,
-        .misc = 0,
-    };
-    CPUState *cenv;
-
-    /* Broadcast MCA signal for processor version 06H_EH and above */
-    if (cpu_x86_support_mca_broadcast(env)) {
-        for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
-            if (cenv == env) {
-                continue;
-            }
-            kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR);
-        }
-    }
-}
-
-static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | MCI_STATUS_AR | 0x134,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
-    int r;
-
-    r = kvm_set_mce(env, &mce);
-    if (r < 0) {
-        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
-        abort();
-    }
-    kvm_mce_broadcast_rest(env);
-}
 
-static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | 0xc0,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
-    int r;
-
-    r = kvm_set_mce(env, &mce);
-    if (r < 0) {
-        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
-        abort();
-    }
-    kvm_mce_broadcast_rest(env);
-}
-
-static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr)
+static bool host_supports_vmx(void)
 {
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | 0xc0,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
+    uint32_t ecx, unused;
 
-    kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR);
-    kvm_mce_broadcast_rest(env);
+    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
+    return ecx & CPUID_EXT_VMX;
 }
 
-#endif
+#define VMX_INVALID_GUEST_STATE 0x80000021
 
-int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
 {
-#if defined(KVM_CAP_MCE)
-    void *vaddr;
-    ram_addr_t ram_addr;
-    target_phys_addr_t paddr;
-
-    if ((env->mcg_cap & MCG_SER_P) && addr
-        && (code == BUS_MCEERR_AR
-            || code == BUS_MCEERR_AO)) {
-        vaddr = (void *)addr;
-        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
-            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) {
-            fprintf(stderr, "Hardware memory error for memory used by "
-                    "QEMU itself instead of guest system!\n");
-            /* Hope we are lucky for AO MCE */
-            if (code == BUS_MCEERR_AO) {
-                return 0;
-            } else {
-                hardware_memory_error();
-            }
-        }
+    uint64_t code;
+    int ret;
 
-        if (code == BUS_MCEERR_AR) {
-            /* Fake an Intel architectural Data Load SRAR UCR */
-            kvm_mce_inj_srar_dataload(env, paddr);
-        } else {
-            /*
-             * If there is an MCE excpetion being processed, ignore
-             * this SRAO MCE
-             */
-            if (!kvm_mce_in_progress(env)) {
-                /* Fake an Intel architectural Memory scrubbing UCR */
-                kvm_mce_inj_srao_memscrub(env, paddr);
-            }
-        }
-    } else
-#endif
-    {
-        if (code == BUS_MCEERR_AO) {
-            return 0;
-        } else if (code == BUS_MCEERR_AR) {
-            hardware_memory_error();
-        } else {
-            return 1;
+    switch (run->exit_reason) {
+    case KVM_EXIT_HLT:
+        DPRINTF("handle_hlt\n");
+        ret = kvm_handle_halt(env);
+        break;
+    case KVM_EXIT_SET_TPR:
+        ret = 0;
+        break;
+    case KVM_EXIT_FAIL_ENTRY:
+        code = run->fail_entry.hardware_entry_failure_reason;
+        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
+                code);
+        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
+            fprintf(stderr,
+                    "\nIf you're running a guest on an Intel machine without "
+                        "unrestricted mode\n"
+                    "support, the failure can be most likely due to the guest "
+                        "entering an invalid\n"
+                    "state for Intel VT. For example, the guest maybe running "
+                        "in big real mode\n"
+                    "which is not supported on less recent Intel processors."
+                        "\n\n");
         }
+        ret = -1;
+        break;
+    case KVM_EXIT_EXCEPTION:
+        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
+                run->ex.exception, run->ex.error_code);
+        ret = -1;
+        break;
+    case KVM_EXIT_DEBUG:
+        DPRINTF("kvm_exit_debug\n");
+        ret = kvm_handle_debug(&run->debug.arch);
+        break;
+    default:
+        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
+        ret = -1;
+        break;
     }
-    return 0;
+
+    return ret;
 }
 
-int kvm_on_sigbus(int code, void *addr)
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
-#if defined(KVM_CAP_MCE)
-    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
-        void *vaddr;
-        ram_addr_t ram_addr;
-        target_phys_addr_t paddr;
-
-        /* Hope we are lucky for AO MCE */
-        vaddr = addr;
-        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
-            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, &paddr)) {
-            fprintf(stderr, "Hardware memory error for memory used by "
-                    "QEMU itself instead of guest system!: %p\n", addr);
-            return 0;
-        }
-        kvm_mce_inj_srao_memscrub2(first_cpu, paddr);
-    } else
-#endif
-    {
-        if (code == BUS_MCEERR_AO) {
-            return 0;
-        } else if (code == BUS_MCEERR_AR) {
-            hardware_memory_error();
-        } else {
-            return 1;
-        }
-    }
-    return 0;
+    return !(env->cr[0] & CR0_PE_MASK) ||
+           ((env->segs[R_CS].selector  & 3) != 3);
 }
index 1b75b1cf4efe90ecdc6cc7685c7a4d132f919875..d6e98ff37b329fc76426559ec60c0277553719e5 100644 (file)
@@ -3,24 +3,9 @@
 #include "hw/pc.h"
 #include "hw/isa.h"
 
-#include "exec-all.h"
+#include "cpu.h"
 #include "kvm.h"
 
-//int sensor_update(int x, int y, int z);
-int compass_update(int x, int y, int z, int temp);
-/*
-int sensor_update(int x, int y, int z)
-{
-       return 0;
-}
-*/
-/*
-int compass_update(int x, int y, int z, int temp)
-{
-       return 0;
-}
-*/
-
 static const VMStateDescription vmstate_segment = {
     .name = "segment",
     .version_id = 1,
@@ -99,7 +84,6 @@ static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size)
     exit(0);
 }
 
-#ifdef USE_X86LDOUBLE
 /* XXX: add that in a FPU generic layer */
 union x86_longdouble {
     uint64_t mant;
@@ -217,102 +201,6 @@ static bool fpregs_is_1_no_mmx(void *opaque, int version_id)
     VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_mmx, vmstate_fpreg_1_mmx, FPReg), \
     VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_no_mmx, vmstate_fpreg_1_no_mmx, FPReg)
 
-#else
-static int get_fpreg(QEMUFile *f, void *opaque, size_t size)
-{
-    FPReg *fp_reg = opaque;
-
-    qemu_get_be64s(f, &fp_reg->mmx.MMX_Q(0));
-    return 0;
-}
-
-static void put_fpreg(QEMUFile *f, void *opaque, size_t size)
-{
-    FPReg *fp_reg = opaque;
-    /* if we use doubles for float emulation, we save the doubles to
-       avoid losing information in case of MMX usage. It can give
-       problems if the image is restored on a CPU where long
-       doubles are used instead. */
-    qemu_put_be64s(f, &fp_reg->mmx.MMX_Q(0));
-}
-
-const VMStateInfo vmstate_fpreg = {
-    .name = "fpreg",
-    .get  = get_fpreg,
-    .put  = put_fpreg,
-};
-
-static int get_fpreg_0_mmx(QEMUFile *f, void *opaque, size_t size)
-{
-    FPReg *fp_reg = opaque;
-    uint64_t mant;
-    uint16_t exp;
-
-    qemu_get_be64s(f, &mant);
-    qemu_get_be16s(f, &exp);
-    fp_reg->mmx.MMX_Q(0) = mant;
-    return 0;
-}
-
-const VMStateInfo vmstate_fpreg_0_mmx = {
-    .name = "fpreg_0_mmx",
-    .get  = get_fpreg_0_mmx,
-    .put  = put_fpreg_error,
-};
-
-static int get_fpreg_0_no_mmx(QEMUFile *f, void *opaque, size_t size)
-{
-    FPReg *fp_reg = opaque;
-    uint64_t mant;
-    uint16_t exp;
-
-    qemu_get_be64s(f, &mant);
-    qemu_get_be16s(f, &exp);
-
-    fp_reg->d = cpu_set_fp80(mant, exp);
-    return 0;
-}
-
-const VMStateInfo vmstate_fpreg_0_no_mmx = {
-    .name = "fpreg_0_no_mmx",
-    .get  = get_fpreg_0_no_mmx,
-    .put  = put_fpreg_error,
-};
-
-static bool fpregs_is_1(void *opaque, int version_id)
-{
-    CPUState *env = opaque;
-
-    return env->fpregs_format_vmstate == 1;
-}
-
-static bool fpregs_is_0_mmx(void *opaque, int version_id)
-{
-    CPUState *env = opaque;
-    int guess_mmx;
-
-    guess_mmx = ((env->fptag_vmstate == 0xff) &&
-                 (env->fpus_vmstate & 0x3800) == 0);
-    return guess_mmx && env->fpregs_format_vmstate == 0;
-}
-
-static bool fpregs_is_0_no_mmx(void *opaque, int version_id)
-{
-    CPUState *env = opaque;
-    int guess_mmx;
-
-    guess_mmx = ((env->fptag_vmstate == 0xff) &&
-                 (env->fpus_vmstate & 0x3800) == 0);
-    return !guess_mmx && env->fpregs_format_vmstate == 0;
-}
-
-#define VMSTATE_FP_REGS(_field, _state, _n)                               \
-    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1, vmstate_fpreg, FPReg), \
-    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_mmx, vmstate_fpreg_0_mmx, FPReg), \
-    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_no_mmx, vmstate_fpreg_0_no_mmx, FPReg)
-
-#endif /* USE_X86LDOUBLE */
-
 static bool version_is_5(void *opaque, int version_id)
 {
     return version_id == 5;
@@ -359,11 +247,7 @@ static void cpu_pre_save(void *opaque)
         env->fptag_vmstate |= ((!env->fptags[i]) << i);
     }
 
-#ifdef USE_X86LDOUBLE
     env->fpregs_format_vmstate = 0;
-#else
-    env->fpregs_format_vmstate = 1;
-#endif
 }
 
 static int cpu_post_load(void *opaque, int version_id)
@@ -388,6 +272,80 @@ static int cpu_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static bool async_pf_msr_needed(void *opaque)
+{
+    CPUState *cpu = opaque;
+
+    return cpu->async_pf_en_msr != 0;
+}
+
+static const VMStateDescription vmstate_async_pf_msr = {
+    .name = "cpu/async_pf_msr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(async_pf_en_msr, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool fpop_ip_dp_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0;
+}
+
+static const VMStateDescription vmstate_fpop_ip_dp = {
+    .name = "cpu/fpop_ip_dp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(fpop, CPUState),
+        VMSTATE_UINT64(fpip, CPUState),
+        VMSTATE_UINT64(fpdp, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool tscdeadline_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->tsc_deadline != 0;
+}
+
+static const VMStateDescription vmstate_msr_tscdeadline = {
+    .name = "cpu/msr_tscdeadline",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(tsc_deadline, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool misc_enable_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->msr_ia32_misc_enable != MSR_IA32_MISC_ENABLE_DEFAULT;
+}
+
+static const VMStateDescription vmstate_msr_ia32_misc_enable = {
+    .name = "cpu/msr_ia32_misc_enable",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(msr_ia32_misc_enable, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_cpu = {
     .name = "cpu",
     .version_id = CPU_SAVE_VERSION,
@@ -490,6 +448,23 @@ static const VMStateDescription vmstate_cpu = {
         VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_async_pf_msr,
+            .needed = async_pf_msr_needed,
+        } , {
+            .vmsd = &vmstate_fpop_ip_dp,
+            .needed = fpop_ip_dp_needed,
+        }, {
+            .vmsd = &vmstate_msr_tscdeadline,
+            .needed = tscdeadline_needed,
+        }, {
+            .vmsd = &vmstate_msr_ia32_misc_enable,
+            .needed = misc_enable_needed,
+        } , {
+            /* empty */
+        }
     }
 };
 
index 3232abd9657c2f1189a160fbdb27b7ef2d4b361d..47dde78f898672ff937ceb3b68d93ff186f5577f 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)
@@ -849,51 +859,51 @@ void helper_insertq_i(XMMReg *d, int index, int length)
 void helper_haddps(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1);
-    r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3);
-    r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1);
-    r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3);
+    r.XMM_S(0) = float32_add(d->XMM_S(0), d->XMM_S(1), &env->sse_status);
+    r.XMM_S(1) = float32_add(d->XMM_S(2), d->XMM_S(3), &env->sse_status);
+    r.XMM_S(2) = float32_add(s->XMM_S(0), s->XMM_S(1), &env->sse_status);
+    r.XMM_S(3) = float32_add(s->XMM_S(2), s->XMM_S(3), &env->sse_status);
     *d = r;
 }
 
 void helper_haddpd(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1);
-    r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1);
+    r.XMM_D(0) = float64_add(d->XMM_D(0), d->XMM_D(1), &env->sse_status);
+    r.XMM_D(1) = float64_add(s->XMM_D(0), s->XMM_D(1), &env->sse_status);
     *d = r;
 }
 
 void helper_hsubps(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1);
-    r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3);
-    r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1);
-    r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3);
+    r.XMM_S(0) = float32_sub(d->XMM_S(0), d->XMM_S(1), &env->sse_status);
+    r.XMM_S(1) = float32_sub(d->XMM_S(2), d->XMM_S(3), &env->sse_status);
+    r.XMM_S(2) = float32_sub(s->XMM_S(0), s->XMM_S(1), &env->sse_status);
+    r.XMM_S(3) = float32_sub(s->XMM_S(2), s->XMM_S(3), &env->sse_status);
     *d = r;
 }
 
 void helper_hsubpd(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1);
-    r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1);
+    r.XMM_D(0) = float64_sub(d->XMM_D(0), d->XMM_D(1), &env->sse_status);
+    r.XMM_D(1) = float64_sub(s->XMM_D(0), s->XMM_D(1), &env->sse_status);
     *d = r;
 }
 
 void helper_addsubps(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0);
-    d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1);
-    d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2);
-    d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3);
+    d->XMM_S(0) = float32_sub(d->XMM_S(0), s->XMM_S(0), &env->sse_status);
+    d->XMM_S(1) = float32_add(d->XMM_S(1), s->XMM_S(1), &env->sse_status);
+    d->XMM_S(2) = float32_sub(d->XMM_S(2), s->XMM_S(2), &env->sse_status);
+    d->XMM_S(3) = float32_add(d->XMM_S(3), s->XMM_S(3), &env->sse_status);
 }
 
 void helper_addsubpd(XMMReg *d, XMMReg *s)
 {
-    d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0);
-    d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1);
+    d->XMM_D(0) = float64_sub(d->XMM_D(0), s->XMM_D(0), &env->sse_status);
+    d->XMM_D(1) = float64_add(d->XMM_D(1), s->XMM_D(1), &env->sse_status);
 }
 
 /* XXX: unordered */
@@ -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);
 }
@@ -1984,11 +1996,13 @@ void glue(helper_pcmpestrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
 
     if ((ctrl >> 6) & 1) {
         if (ctrl & 1)
-            for (i = 0; i <= 8; i--, res >>= 1)
+            for (i = 0; i < 8; i++, res >>= 1) {
                 d->W(i) = (res & 1) ? ~0 : 0;
+            }
         else
-            for (i = 0; i <= 16; i--, res >>= 1)
+            for (i = 0; i < 16; i++, res >>= 1) {
                 d->B(i) = (res & 1) ? ~0 : 0;
+            }
     } else {
         d->Q(1) = 0;
         d->Q(0) = res;
@@ -2016,11 +2030,13 @@ void glue(helper_pcmpistrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
 
     if ((ctrl >> 6) & 1) {
         if (ctrl & 1)
-            for (i = 0; i <= 8; i--, res >>= 1)
+            for (i = 0; i < 8; i++, res >>= 1) {
                 d->W(i) = (res & 1) ? ~0 : 0;
+            }
         else
-            for (i = 0; i <= 16; i--, res >>= 1)
+            for (i = 0; i < 16; i++, res >>= 1) {
                 d->B(i) = (res & 1) ? ~0 : 0;
+            }
     } else {
         d->Q(1) = 0;
         d->Q(0) = res;
index a224aead1730c00189c42cc437aea93ac4988162..04193ed60f2b9a31bdf6f4a6a15cf8b1a6681ee3 100644 (file)
 
 #define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
 
-struct __attribute__ ((__packed__)) vmcb_control_area {
+struct QEMU_PACKED vmcb_control_area {
        uint16_t intercept_cr_read;
        uint16_t intercept_cr_write;
        uint16_t intercept_dr_read;
@@ -162,14 +162,14 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        uint8_t reserved_5[832];
 };
 
-struct __attribute__ ((__packed__)) vmcb_seg {
+struct QEMU_PACKED vmcb_seg {
        uint16_t selector;
        uint16_t attrib;
        uint32_t limit;
        uint64_t base;
 };
 
-struct __attribute__ ((__packed__)) vmcb_save_area {
+struct QEMU_PACKED vmcb_save_area {
        struct vmcb_seg es;
        struct vmcb_seg cs;
        struct vmcb_seg ss;
@@ -214,7 +214,7 @@ struct __attribute__ ((__packed__)) vmcb_save_area {
        uint64_t last_excp_to;
 };
 
-struct __attribute__ ((__packed__)) vmcb {
+struct QEMU_PACKED vmcb {
        struct vmcb_control_area control;
        struct vmcb_save_area save;
 };
index df66f720e64f6245c0ff6738fd892ca0999db84d..475614c31be0c8c266f28ec351fd54f460c7ba60 100644 (file)
 #include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 
 #include "helper.h"
 #define GEN_HELPER 1
 #include "helper.h"
+#include "hax.h"
 
 #define PREFIX_REPZ   0x01
 #define PREFIX_REPNZ  0x02
@@ -274,28 +274,16 @@ static inline void gen_op_andl_A0_ffff(void)
 
 static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
 {
-    TCGv tmp;
-
     switch(ot) {
     case OT_BYTE:
-        tmp = tcg_temp_new();
-        tcg_gen_ext8u_tl(tmp, t0);
         if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
-            tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xff);
-            tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
+            tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 8);
         } else {
-            tcg_gen_shli_tl(tmp, tmp, 8);
-            tcg_gen_andi_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], ~0xff00);
-            tcg_gen_or_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], tmp);
+            tcg_gen_deposit_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], t0, 8, 8);
         }
-        tcg_temp_free(tmp);
         break;
     case OT_WORD:
-        tmp = tcg_temp_new();
-        tcg_gen_ext16u_tl(tmp, t0);
-        tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
-        tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
-        tcg_temp_free(tmp);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 16);
         break;
     default: /* XXX this shouldn't be reached;  abort? */
     case OT_LONG:
@@ -323,15 +311,9 @@ static inline void gen_op_mov_reg_T1(int ot, int reg)
 
 static inline void gen_op_mov_reg_A0(int size, int reg)
 {
-    TCGv tmp;
-
     switch(size) {
     case 0:
-        tmp = tcg_temp_new();
-        tcg_gen_ext16u_tl(tmp, cpu_A0);
-        tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
-        tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
-        tcg_temp_free(tmp);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_A0, 0, 16);
         break;
     default: /* XXX this shouldn't be reached;  abort? */
     case 1:
@@ -389,7 +371,7 @@ static inline void gen_op_addq_A0_im(int64_t val)
     tcg_gen_addi_tl(cpu_A0, cpu_A0, val);
 }
 #endif
-
+    
 static void gen_add_A0_im(DisasContext *s, int val)
 {
 #ifdef TARGET_X86_64
@@ -415,9 +397,7 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
     switch(size) {
     case 0:
         tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
-        tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
-        tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
-        tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
         break;
     case 1:
         tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
@@ -439,9 +419,7 @@ static inline void gen_op_add_reg_T0(int size, int reg)
     switch(size) {
     case 0:
         tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
-        tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
-        tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
-        tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
         break;
     case 1:
         tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
@@ -665,7 +643,7 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s)
     }
 }
 
-static inline void gen_op_movl_T0_Dshift(int ot)
+static inline void gen_op_movl_T0_Dshift(int ot) 
 {
     tcg_gen_ld32s_tl(cpu_T[0], cpu_env, offsetof(CPUState, df));
     tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot);
@@ -791,12 +769,6 @@ static inline void gen_update_cc_op(DisasContext *s)
     }
 }
 
-extern void helper_int99(void);
-void  helper_opengl99(void)
-{
-       helper_int99();
-}
-
 static void gen_op_update1_cc(void)
 {
     tcg_gen_discard_tl(cpu_cc_src);
@@ -962,7 +934,7 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
     case CC_OP_SUBW:
     case CC_OP_SUBL:
     case CC_OP_SUBQ:
-
+        
         size = cc_op - CC_OP_SUBB;
         switch(jcc_op) {
         case JCC_Z:
@@ -993,28 +965,28 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
             switch(size) {
             case 0:
                 tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80);
-                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
                                    0, l1);
                 break;
             case 1:
                 tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000);
-                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
                                    0, l1);
                 break;
 #ifdef TARGET_X86_64
             case 2:
                 tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000);
-                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
                                    0, l1);
                 break;
 #endif
             default:
-                tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst,
+                tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst, 
                                    0, l1);
                 break;
             }
             break;
-
+            
         case JCC_B:
             cond = inv ? TCG_COND_GEU : TCG_COND_LTU;
             goto fast_jcc_b;
@@ -1046,7 +1018,7 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
             }
             tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
             break;
-
+            
         case JCC_L:
             cond = inv ? TCG_COND_GE : TCG_COND_LT;
             goto fast_jcc_l;
@@ -1078,48 +1050,48 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
             }
             tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
             break;
-
+            
         default:
             goto slow_jcc;
         }
         break;
-
+        
         /* some jumps are easy to compute */
     case CC_OP_ADDB:
     case CC_OP_ADDW:
     case CC_OP_ADDL:
     case CC_OP_ADDQ:
-
+        
     case CC_OP_ADCB:
     case CC_OP_ADCW:
     case CC_OP_ADCL:
     case CC_OP_ADCQ:
-
+        
     case CC_OP_SBBB:
     case CC_OP_SBBW:
     case CC_OP_SBBL:
     case CC_OP_SBBQ:
-
+        
     case CC_OP_LOGICB:
     case CC_OP_LOGICW:
     case CC_OP_LOGICL:
     case CC_OP_LOGICQ:
-
+        
     case CC_OP_INCB:
     case CC_OP_INCW:
     case CC_OP_INCL:
     case CC_OP_INCQ:
-
+        
     case CC_OP_DECB:
     case CC_OP_DECW:
     case CC_OP_DECL:
     case CC_OP_DECQ:
-
+        
     case CC_OP_SHLB:
     case CC_OP_SHLW:
     case CC_OP_SHLL:
     case CC_OP_SHLQ:
-
+        
     case CC_OP_SARB:
     case CC_OP_SARW:
     case CC_OP_SARL:
@@ -1138,7 +1110,7 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
     default:
     slow_jcc:
         gen_setcc_slow_T0(s, jcc_op);
-        tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE,
+        tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, 
                            cpu_T[0], 0, l1);
         break;
     }
@@ -1430,82 +1402,96 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c)
     tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
 }
 
-static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
+static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, 
                             int is_right, int is_arith)
 {
     target_ulong mask;
     int shift_label;
-    TCGv t0, t1;
+    TCGv t0, t1, t2;
 
-    if (ot == OT_QUAD)
+    if (ot == OT_QUAD) {
         mask = 0x3f;
-    else
+    } else {
         mask = 0x1f;
+    }
 
     /* load */
-    if (op1 == OR_TMP0)
+    if (op1 == OR_TMP0) {
         gen_op_ld_T0_A0(ot + s->mem_index);
-    else
+    } else {
         gen_op_mov_TN_reg(ot, 0, op1);
+    }
 
-    tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
 
-    tcg_gen_addi_tl(cpu_tmp5, cpu_T[1], -1);
+    tcg_gen_andi_tl(t2, cpu_T[1], mask);
 
     if (is_right) {
         if (is_arith) {
             gen_exts(ot, cpu_T[0]);
-            tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-            tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+            tcg_gen_mov_tl(t0, cpu_T[0]);
+            tcg_gen_sar_tl(cpu_T[0], cpu_T[0], t2);
         } else {
             gen_extu(ot, cpu_T[0]);
-            tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-            tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+            tcg_gen_mov_tl(t0, cpu_T[0]);
+            tcg_gen_shr_tl(cpu_T[0], cpu_T[0], t2);
         }
     } else {
-        tcg_gen_shl_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-        tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        tcg_gen_mov_tl(t0, cpu_T[0]);
+        tcg_gen_shl_tl(cpu_T[0], cpu_T[0], t2);
     }
 
     /* store */
-    if (op1 == OR_TMP0)
+    if (op1 == OR_TMP0) {
         gen_op_st_T0_A0(ot + s->mem_index);
-    else
+    } else {
         gen_op_mov_reg_T0(ot, op1);
+    }
 
     /* update eflags if non zero shift */
-    if (s->cc_op != CC_OP_DYNAMIC)
+    if (s->cc_op != CC_OP_DYNAMIC) {
         gen_op_set_cc_op(s->cc_op);
+    }
 
-    /* XXX: inefficient */
-    t0 = tcg_temp_local_new();
-    t1 = tcg_temp_local_new();
-
-    tcg_gen_mov_tl(t0, cpu_T[0]);
-    tcg_gen_mov_tl(t1, cpu_T3);
+    tcg_gen_mov_tl(t1, cpu_T[0]);
 
     shift_label = gen_new_label();
-    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_T[1], 0, shift_label);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, shift_label);
 
-    tcg_gen_mov_tl(cpu_cc_src, t1);
-    tcg_gen_mov_tl(cpu_cc_dst, t0);
-    if (is_right)
+    tcg_gen_addi_tl(t2, t2, -1);
+    tcg_gen_mov_tl(cpu_cc_dst, t1);
+
+    if (is_right) {
+        if (is_arith) {
+            tcg_gen_sar_tl(cpu_cc_src, t0, t2);
+        } else {
+            tcg_gen_shr_tl(cpu_cc_src, t0, t2);
+        }
+    } else {
+        tcg_gen_shl_tl(cpu_cc_src, t0, t2);
+    }
+
+    if (is_right) {
         tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
-    else
+    } else {
         tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
+    }
 
     gen_set_label(shift_label);
     s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
 
     tcg_temp_free(t0);
     tcg_temp_free(t1);
+    tcg_temp_free(t2);
 }
 
 static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
                             int is_right, int is_arith)
 {
     int mask;
-
+    
     if (ot == OT_QUAD)
         mask = 0x3f;
     else
@@ -1540,7 +1526,7 @@ static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
         gen_op_st_T0_A0(ot + s->mem_index);
     else
         gen_op_mov_reg_T0(ot, op1);
-
+        
     /* update eflags if non zero shift */
     if (op2 != 0) {
         tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
@@ -1560,7 +1546,7 @@ static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2)
         tcg_gen_shri_tl(ret, arg1, -arg2);
 }
 
-static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
+static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, 
                           int is_right)
 {
     target_ulong mask;
@@ -1594,12 +1580,12 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
        shifts. */
     label1 = gen_new_label();
     tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1);
-
+    
     if (ot <= OT_WORD)
         tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1);
     else
         tcg_gen_mov_tl(cpu_tmp0, t1);
-
+    
     gen_extu(ot, t0);
     tcg_gen_mov_tl(t2, t0);
 
@@ -1624,7 +1610,7 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
     } else {
         gen_op_mov_reg_v(ot, op1, t0);
     }
-
+    
     /* update eflags */
     if (s->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(s->cc_op);
@@ -1643,10 +1629,10 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
     }
     tcg_gen_andi_tl(t0, t0, CC_C);
     tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
-
+    
     tcg_gen_discard_tl(cpu_cc_dst);
     tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
-
+        
     gen_set_label(label2);
     s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
 
@@ -1734,7 +1720,7 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2,
 }
 
 /* XXX: add faster immediate = 1 case */
-static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
+static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, 
                            int is_right)
 {
     int label1;
@@ -1747,7 +1733,7 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
         gen_op_ld_T0_A0(ot + s->mem_index);
     else
         gen_op_mov_TN_reg(ot, 0, op1);
-
+    
     if (is_right) {
         switch (ot) {
         case 0: gen_helper_rcrb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
@@ -1780,13 +1766,13 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
     tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp);
     tcg_gen_discard_tl(cpu_cc_dst);
     tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
-
+        
     gen_set_label(label1);
     s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
 }
 
 /* XXX: add faster immediate case */
-static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
+static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, 
                                 int is_right)
 {
     int label1, label2, data_bits;
@@ -1820,7 +1806,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
        shifts. */
     label1 = gen_new_label();
     tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
-
+    
     tcg_gen_addi_tl(cpu_tmp5, t2, -1);
     if (ot == OT_WORD) {
         /* Note: we implement the Intel behaviour for shift count > 16 */
@@ -1831,7 +1817,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
             tcg_gen_ext32u_tl(t0, t0);
 
             tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
-
+            
             /* only needed if count > 16, but a test would complicate */
             tcg_gen_subfi_tl(cpu_tmp5, 32, t2);
             tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5);
@@ -1845,7 +1831,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
             tcg_gen_shli_tl(t1, t1, 16);
             tcg_gen_or_tl(t1, t1, t0);
             tcg_gen_ext32u_tl(t1, t1);
-
+            
             tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
             tcg_gen_subfi_tl(cpu_tmp0, 32, cpu_tmp5);
             tcg_gen_shr_tl(cpu_tmp5, t1, cpu_tmp0);
@@ -1868,13 +1854,13 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
             tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
             tcg_gen_shl_tl(t1, t1, cpu_tmp5);
             tcg_gen_or_tl(t0, t0, t1);
-
+            
         } else {
             if (ot == OT_LONG)
                 tcg_gen_ext32u_tl(t1, t1);
 
             tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
-
+            
             tcg_gen_shl_tl(t0, t0, t2);
             tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
             tcg_gen_shr_tl(t1, t1, cpu_tmp5);
@@ -1890,7 +1876,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
     } else {
         gen_op_mov_reg_v(ot, op1, t0);
     }
-
+    
     /* update eflags */
     if (s->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(s->cc_op);
@@ -2289,21 +2275,6 @@ static inline int insn_const_size(unsigned int ot)
         return 4;
 }
 
-#ifdef CONFIG_EXEC_PROFILE
-/* generation of TB execution profiling  */
-static inline void gen_prof_tbexec(DisasContext *s, int tb_num)
-{
-    tcg_gen_movi_tl(cpu_T[0], (target_ulong)((void *)s->tb +
-                                             offsetof(TranslationBlock, tbexec_count) +
-                                             sizeof (uint32_t) * (tb_num & 0x1)));
-    tcg_gen_ld32s_tl(cpu_T[1], cpu_T[0], 0);
-    tcg_gen_addi_i32(cpu_T[1], cpu_T[1], 1);
-    tcg_gen_st32_tl(cpu_T[1], cpu_T[0], 0);
-}
-#else
-# define gen_prof_tbexec(s, tb_num)
-#endif  /* CONFIG_EXEC_PROFILE */
-
 static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
 {
     TranslationBlock *tb;
@@ -2314,12 +2285,10 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
     /* NOTE: we handle the case where the TB spans two pages here */
     if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
         (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
-        /* profile TB execution, yklee 20111112 */
-        gen_prof_tbexec(s, tb_num);
         /* 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);
@@ -2337,7 +2306,7 @@ static inline void gen_jcc(DisasContext *s, int b,
     if (s->jmp_opt) {
         l1 = gen_new_label();
         gen_jcc1(s, cc_op, b, l1);
-
+        
         gen_goto_tb(s, 0, next_eip);
 
         gen_set_label(l1);
@@ -2390,17 +2359,17 @@ static void gen_setcc(DisasContext *s, int b)
 
 static inline void gen_op_movl_T0_seg(int seg_reg)
 {
-    tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
+    tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
                      offsetof(CPUX86State,segs[seg_reg].selector));
 }
 
 static inline void gen_op_movl_seg_T0_vm(int seg_reg)
 {
     tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff);
-    tcg_gen_st32_tl(cpu_T[0], cpu_env,
+    tcg_gen_st32_tl(cpu_T[0], cpu_env, 
                     offsetof(CPUX86State,segs[seg_reg].selector));
     tcg_gen_shli_tl(cpu_T[0], cpu_T[0], 4);
-    tcg_gen_st_tl(cpu_T[0], cpu_env,
+    tcg_gen_st_tl(cpu_T[0], cpu_env, 
                   offsetof(CPUX86State,segs[seg_reg].base));
 }
 
@@ -2695,37 +2664,17 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
     s->is_jmp = DISAS_TB_JUMP;
 }
 
-extern int enable_gl;
 /* an interrupt is different from an exception because of the
    privilege checks */
 static void gen_interrupt(DisasContext *s, int intno,
                           target_ulong cur_eip, target_ulong next_eip)
 {
-       /* opengl patch by okdear.park */
-       if (enable_gl && intno == 0x99)
-       {
-               if (s->cc_op != CC_OP_DYNAMIC)
-                       gen_op_set_cc_op(s->cc_op);
-               gen_jmp_im(cur_eip);
-
-               gen_helper_opengl99();
-               //gen_helper_cpuid();
-
-               //gen_op_int99(); -- okdearpjs
-       }
-       /* opengl patch end */
-       else {
-
-               if (s->cc_op != CC_OP_DYNAMIC)
-                       gen_op_set_cc_op(s->cc_op);
-               gen_jmp_im(cur_eip);
-               //gen_heler_test_interrupt();
-               gen_helper_raise_interrupt(tcg_const_i32(intno),
-                               tcg_const_i32(next_eip - cur_eip));
-               s->is_jmp = DISAS_TB_JUMP;
-       }
-
-
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_jmp_im(cur_eip);
+    gen_helper_raise_interrupt(tcg_const_i32(intno), 
+                               tcg_const_i32(next_eip - cur_eip));
+    s->is_jmp = DISAS_TB_JUMP;
 }
 
 static void gen_debug(DisasContext *s, target_ulong cur_eip)
@@ -2754,7 +2703,6 @@ static void gen_eob(DisasContext *s)
     } else if (s->tf) {
        gen_helper_single_step();
     } else {
-        gen_prof_tbexec(s, 0);
         tcg_gen_exit_tb(0);
     }
     s->is_jmp = DISAS_TB_JUMP;
@@ -3236,7 +3184,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
 #endif
             {
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
-                tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
                                  offsetof(CPUX86State,fpregs[reg].mmx));
                 tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
                 gen_helper_movl_mm_T0_mmx(cpu_ptr0, cpu_tmp2_i32);
@@ -3246,14 +3194,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
 #ifdef TARGET_X86_64
             if (s->dflag == 2) {
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
-                tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
                                  offsetof(CPUX86State,xmm_regs[reg]));
                 gen_helper_movq_mm_T0_xmm(cpu_ptr0, cpu_T[0]);
             } else
 #endif
             {
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
-                tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
                                  offsetof(CPUX86State,xmm_regs[reg]));
                 tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
                 gen_helper_movl_mm_T0_xmm(cpu_ptr0, cpu_tmp2_i32);
@@ -3404,13 +3352,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
         case 0x7e: /* movd ea, mm */
 #ifdef TARGET_X86_64
             if (s->dflag == 2) {
-                tcg_gen_ld_i64(cpu_T[0], cpu_env,
+                tcg_gen_ld_i64(cpu_T[0], cpu_env, 
                                offsetof(CPUX86State,fpregs[reg].mmx));
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
             } else
 #endif
             {
-                tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
                                  offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0)));
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
             }
@@ -3418,13 +3366,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
         case 0x17e: /* movd ea, xmm */
 #ifdef TARGET_X86_64
             if (s->dflag == 2) {
-                tcg_gen_ld_i64(cpu_T[0], cpu_env,
+                tcg_gen_ld_i64(cpu_T[0], cpu_env, 
                                offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
             } else
 #endif
             {
-                tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
                                  offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
             }
@@ -3543,7 +3491,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
             break;
         case 0x050: /* movmskps */
             rm = (modrm & 7) | REX_B(s);
-            tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
                              offsetof(CPUX86State,xmm_regs[rm]));
             gen_helper_movmskps(cpu_tmp2_i32, cpu_ptr0);
             tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
@@ -3551,7 +3499,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
             break;
         case 0x150: /* movmskpd */
             rm = (modrm & 7) | REX_B(s);
-            tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
                              offsetof(CPUX86State,xmm_regs[rm]));
             gen_helper_movmskpd(cpu_tmp2_i32, cpu_ptr0);
             tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
@@ -4692,12 +4640,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                 gen_jmp_im(pc_start - s->cs_base);
                 tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
                 gen_helper_lcall_protected(cpu_tmp2_i32, cpu_T[1],
-                                           tcg_const_i32(dflag),
+                                           tcg_const_i32(dflag), 
                                            tcg_const_i32(s->pc - pc_start));
             } else {
                 tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
                 gen_helper_lcall_real(cpu_tmp2_i32, cpu_T[1],
-                                      tcg_const_i32(dflag),
+                                      tcg_const_i32(dflag), 
                                       tcg_const_i32(s->pc - s->cs_base));
             }
             gen_eob(s);
@@ -4923,20 +4871,23 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
             gen_extu(ot, t2);
             tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
+            label2 = gen_new_label();
             if (mod == 3) {
-                label2 = gen_new_label();
                 gen_op_mov_reg_v(ot, R_EAX, t0);
                 tcg_gen_br(label2);
                 gen_set_label(label1);
                 gen_op_mov_reg_v(ot, rm, t1);
-                gen_set_label(label2);
             } else {
-                tcg_gen_mov_tl(t1, t0);
+                /* perform no-op store cycle like physical cpu; must be
+                   before changing accumulator to ensure idempotency if
+                   the store faults and the instruction is restarted */
+                gen_op_st_v(ot + s->mem_index, t0, a0);
                 gen_op_mov_reg_v(ot, R_EAX, t0);
+                tcg_gen_br(label2);
                 gen_set_label(label1);
-                /* always store */
                 gen_op_st_v(ot + s->mem_index, t1, a0);
             }
+            gen_set_label(label2);
             tcg_gen_mov_tl(cpu_cc_src, t0);
             tcg_gen_mov_tl(cpu_cc_dst, t2);
             s->cc_op = CC_OP_SUBB + ot;
@@ -4961,7 +4912,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_helper_cmpxchg16b(cpu_A0);
         } else
-#endif
+#endif        
         {
             if (!(s->cpuid_features & CPUID_CX8))
                 goto illegal_op;
@@ -5537,7 +5488,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                         gen_helper_fildl_FT0(cpu_tmp2_i32);
                         break;
                     case 2:
-                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
+                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
                                           (s->mem_index >> 2) - 1);
                         gen_helper_fldl_FT0(cpu_tmp1_i64);
                         break;
@@ -5576,7 +5527,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                         gen_helper_fildl_ST0(cpu_tmp2_i32);
                         break;
                     case 2:
-                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
+                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
                                           (s->mem_index >> 2) - 1);
                         gen_helper_fldl_ST0(cpu_tmp1_i64);
                         break;
@@ -5598,7 +5549,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                         break;
                     case 2:
                         gen_helper_fisttll_ST0(cpu_tmp1_i64);
-                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
+                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
                                           (s->mem_index >> 2) - 1);
                         break;
                     case 3:
@@ -5624,7 +5575,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                         break;
                     case 2:
                         gen_helper_fstl_ST0(cpu_tmp1_i64);
-                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
+                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
                                           (s->mem_index >> 2) - 1);
                         break;
                     case 3:
@@ -5706,13 +5657,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                 gen_helper_fpop();
                 break;
             case 0x3d: /* fildll */
-                tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
+                tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
                                   (s->mem_index >> 2) - 1);
                 gen_helper_fildll_ST0(cpu_tmp1_i64);
                 break;
             case 0x3f: /* fistpll */
                 gen_helper_fistll_ST0(cpu_tmp1_i64);
-                tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
+                tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
                                   (s->mem_index >> 2) - 1);
                 gen_helper_fpop();
                 break;
@@ -6100,7 +6051,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             ot = dflag ? OT_LONG : OT_WORD;
         gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
         gen_op_andl_T0_ffff();
-        gen_check_io(s, ot, pc_start - s->cs_base,
+        gen_check_io(s, ot, pc_start - s->cs_base, 
                      SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
         if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
             gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
@@ -6169,7 +6120,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
         if (use_icount)
             gen_io_start();
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
-        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         if (use_icount) {
@@ -6212,7 +6162,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
         if (use_icount)
             gen_io_start();
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
-        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         if (use_icount) {
@@ -6291,7 +6240,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
             gen_jmp_im(pc_start - s->cs_base);
-            gen_helper_iret_protected(tcg_const_i32(s->dflag),
+            gen_helper_iret_protected(tcg_const_i32(s->dflag), 
                                       tcg_const_i32(s->pc - s->cs_base));
             s->cc_op = CC_OP_EFLAGS;
         }
@@ -7178,7 +7127,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                     break;
                 case 4: /* STGI */
                     if ((!(s->flags & HF_SVME_MASK) &&
-                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
+                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
                         !s->pe)
                         goto illegal_op;
                     if (s->cpl != 0) {
@@ -7199,8 +7148,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                     }
                     break;
                 case 6: /* SKINIT */
-                    if ((!(s->flags & HF_SVME_MASK) &&
-                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
+                    if ((!(s->flags & HF_SVME_MASK) && 
+                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
                         !s->pe)
                         goto illegal_op;
                     gen_helper_skinit();
@@ -7604,7 +7553,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             break;
         case 5: /* lfence */
         case 6: /* mfence */
-            if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
+            if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
                 goto illegal_op;
             break;
         case 7: /* sfence / clflush */
@@ -7694,11 +7643,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
 
 void optimize_flags_init(void)
 {
-#if TCG_TARGET_REG_BITS == 32
-    assert(sizeof(CCTable) == (1 << 3));
-#else
-    assert(sizeof(CCTable) == (1 << 4));
-#endif
     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
     cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0,
                                        offsetof(CPUState, cc_op), "cc_op");
@@ -7884,6 +7828,14 @@ static inline void gen_intermediate_code_internal(CPUState *env,
 
         pc_ptr = disas_insn(dc, pc_ptr);
         num_insns++;
+#ifdef CONFIG_HAX
+        if (hax_enabled() && hax_stop_translate(env))
+        {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
+#endif
         /* stop translation if indicated */
         if (dc->is_jmp)
             break;
@@ -7956,8 +7908,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
@@ -7969,8 +7920,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
diff --git a/target-lm32/README b/target-lm32/README
new file mode 100644 (file)
index 0000000..a1c2c7e
--- /dev/null
@@ -0,0 +1,46 @@
+LatticeMico32 target
+--------------------
+
+General
+-------
+All opcodes including the JUART CSRs are supported.
+
+
+JTAG UART
+---------
+JTAG UART is routed to a serial console device. For the current boards it
+is the second one. Ie to enable it in the qemu virtual console window use
+the following command line parameters:
+  -serial vc -serial vc
+This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
+available as virtual consoles.
+
+
+Programmatically terminate the emulator
+----------------------------------------
+Originally neither the LatticeMico32 nor its peripherals support a
+mechanism to shut down the machine. Emulation aware programs can write to a
+to a special register within the system control block to shut down the
+virtual machine.  For more details see hw/lm32_sys.c. The lm32-evr is the
+first BSP which instantiate this model. A (32 bit) write to 0xfff0000
+causes a vm shutdown.
+
+
+Special instructions
+--------------------
+The translation recognizes one special instruction to halt the cpu:
+  and r0, r0, r0
+On real hardware this instruction is a nop. It is not used by GCC and
+should (hopefully) not be used within hand-crafted assembly.
+Insert this instruction in your idle loop to reduce the cpu load on the
+host.
+
+
+Ignoring the MSB of the address bus
+-----------------------------------
+Some SoC ignores the MSB on the address bus. Thus creating a shadow memory
+area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+0x80000000-0xffffffff is not cached and used to access IO devices. This
+behaviour can be enabled with:
+  cpu_lm32_set_phys_msb_ignore(env, 1);
+
diff --git a/target-lm32/TODO b/target-lm32/TODO
new file mode 100644 (file)
index 0000000..b9ea0c8
--- /dev/null
@@ -0,0 +1,3 @@
+* disassembler (lm32-dis.c)
+* linux-user emulation
+* native bp/wp emulation (?)
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
new file mode 100644 (file)
index 0000000..037ef52
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ *  LatticeMico32 virtual CPU header.
+ *
+ *  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/>.
+ */
+
+#ifndef CPU_LM32_H
+#define CPU_LM32_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPULM32State
+
+#include "qemu-common.h"
+#include "cpu-defs.h"
+struct CPULM32State;
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_LATTICEMICO32
+
+#define NB_MMU_MODES 1
+#define TARGET_PAGE_BITS 12
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return 0;
+}
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+/* Exceptions indices */
+enum {
+    EXCP_RESET = 0,
+    EXCP_BREAKPOINT,
+    EXCP_INSN_BUS_ERROR,
+    EXCP_WATCHPOINT,
+    EXCP_DATA_BUS_ERROR,
+    EXCP_DIVIDE_BY_ZERO,
+    EXCP_IRQ,
+    EXCP_SYSTEMCALL
+};
+
+/* Registers */
+enum {
+    R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10,
+    R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20,
+    R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30,
+    R_R31
+};
+
+/* Register aliases */
+enum {
+    R_GP = R_R26,
+    R_FP = R_R27,
+    R_SP = R_R28,
+    R_RA = R_R29,
+    R_EA = R_R30,
+    R_BA = R_R31
+};
+
+/* IE flags */
+enum {
+    IE_IE  = (1<<0),
+    IE_EIE = (1<<1),
+    IE_BIE = (1<<2),
+};
+
+/* DC flags */
+enum {
+    DC_SS  = (1<<0),
+    DC_RE  = (1<<1),
+    DC_C0  = (1<<2),
+    DC_C1  = (1<<3),
+    DC_C2  = (1<<4),
+    DC_C3  = (1<<5),
+};
+
+/* CFG mask */
+enum {
+    CFG_M         = (1<<0),
+    CFG_D         = (1<<1),
+    CFG_S         = (1<<2),
+    CFG_U         = (1<<3),
+    CFG_X         = (1<<4),
+    CFG_CC        = (1<<5),
+    CFG_IC        = (1<<6),
+    CFG_DC        = (1<<7),
+    CFG_G         = (1<<8),
+    CFG_H         = (1<<9),
+    CFG_R         = (1<<10),
+    CFG_J         = (1<<11),
+    CFG_INT_SHIFT = 12,
+    CFG_BP_SHIFT  = 18,
+    CFG_WP_SHIFT  = 22,
+    CFG_REV_SHIFT = 26,
+};
+
+/* CSRs */
+enum {
+    CSR_IE   = 0x00,
+    CSR_IM   = 0x01,
+    CSR_IP   = 0x02,
+    CSR_ICC  = 0x03,
+    CSR_DCC  = 0x04,
+    CSR_CC   = 0x05,
+    CSR_CFG  = 0x06,
+    CSR_EBA  = 0x07,
+    CSR_DC   = 0x08,
+    CSR_DEBA = 0x09,
+    CSR_JTX  = 0x0e,
+    CSR_JRX  = 0x0f,
+    CSR_BP0  = 0x10,
+    CSR_BP1  = 0x11,
+    CSR_BP2  = 0x12,
+    CSR_BP3  = 0x13,
+    CSR_WP0  = 0x18,
+    CSR_WP1  = 0x19,
+    CSR_WP2  = 0x1a,
+    CSR_WP3  = 0x1b,
+};
+
+enum {
+    LM32_FEATURE_MULTIPLY     =  1,
+    LM32_FEATURE_DIVIDE       =  2,
+    LM32_FEATURE_SHIFT        =  4,
+    LM32_FEATURE_SIGN_EXTEND  =  8,
+    LM32_FEATURE_I_CACHE      = 16,
+    LM32_FEATURE_D_CACHE      = 32,
+    LM32_FEATURE_CYCLE_COUNT  = 64,
+};
+
+enum {
+    LM32_FLAG_IGNORE_MSB = 1,
+};
+
+typedef struct CPULM32State {
+    /* general registers */
+    uint32_t regs[32];
+
+    /* special registers */
+    uint32_t pc;        /* program counter */
+    uint32_t ie;        /* interrupt enable */
+    uint32_t icc;       /* instruction cache control */
+    uint32_t dcc;       /* data cache control */
+    uint32_t cc;        /* cycle counter */
+    uint32_t cfg;       /* configuration */
+
+    /* debug registers */
+    uint32_t dc;        /* debug control */
+    uint32_t bp[4];     /* breakpoint addresses */
+    uint32_t wp[4];     /* watchpoint addresses */
+
+    CPU_COMMON
+
+    uint32_t eba;       /* exception base address */
+    uint32_t deba;      /* debug exception base address */
+
+    /* interrupt controller handle for callbacks */
+    DeviceState *pic_state;
+    /* JTAG UART handle for callbacks */
+    DeviceState *juart_state;
+
+    /* processor core features */
+    uint32_t features;
+    uint32_t flags;
+    uint8_t num_bps;
+    uint8_t num_wps;
+
+} CPULM32State;
+
+
+CPUState *cpu_lm32_init(const char *cpu_model);
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_lm32_exec(CPUState *s);
+void cpu_lm32_close(CPUState *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
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_lm32_signal_handler(int host_signum, void *pinfo,
+                          void *puc);
+void lm32_translate_init(void);
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value);
+
+#define cpu_list cpu_lm32_list
+#define cpu_init cpu_lm32_init
+#define cpu_exec cpu_lm32_exec
+#define cpu_gen_code cpu_lm32_gen_code
+#define cpu_signal_handler cpu_lm32_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx);
+#define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->regs[R_SP] = newsp;
+    }
+    env->regs[R_R1] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env)
+{
+    return env->ie & IE_IE;
+}
+
+#include "cpu-all.h"
+
+static inline target_ulong cpu_get_pc(CPUState *env)
+{
+    return env->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
new file mode 100644 (file)
index 0000000..fc0b444
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  LatticeMico32 helper routines.
+ *
+ *  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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "host-utils.h"
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx)
+{
+    int prot;
+
+    address &= TARGET_PAGE_MASK;
+    prot = PAGE_BITS;
+    if (env->flags & LM32_FLAG_IGNORE_MSB) {
+        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
+                TARGET_PAGE_SIZE);
+    } else {
+        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+    }
+
+    return 0;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr & TARGET_PAGE_MASK;
+}
+
+void do_interrupt(CPUState *env)
+{
+    qemu_log_mask(CPU_LOG_INT,
+            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
+
+    switch (env->exception_index) {
+    case EXCP_INSN_BUS_ERROR:
+    case EXCP_DATA_BUS_ERROR:
+    case EXCP_DIVIDE_BY_ZERO:
+    case EXCP_IRQ:
+    case EXCP_SYSTEMCALL:
+        /* non-debug exceptions */
+        env->regs[R_EA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_EIE : 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);
+        }
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    case EXCP_BREAKPOINT:
+    case EXCP_WATCHPOINT:
+        /* debug exceptions */
+        env->regs[R_BA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
+        env->ie &= ~IE_IE;
+        env->pc = env->deba + (env->exception_index * 32);
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    default:
+        cpu_abort(env, "unhandled exception type=%d\n",
+                  env->exception_index);
+        break;
+    }
+}
+
+typedef struct {
+    const char *name;
+    uint32_t revision;
+    uint8_t num_interrupts;
+    uint8_t num_breakpoints;
+    uint8_t num_watchpoints;
+    uint32_t features;
+} LM32Def;
+
+static const LM32Def lm32_defs[] = {
+    {
+        .name = "lm32-basic",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-standard",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-full",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_D_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    }
+};
+
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        cpu_fprintf(f, "  %s\n", lm32_defs[i].name);
+    }
+}
+
+static const LM32Def *cpu_lm32_find_by_name(const char *name)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        if (strcasecmp(name, lm32_defs[i].name) == 0) {
+            return &lm32_defs[i];
+        }
+    }
+
+    return NULL;
+}
+
+static uint32_t cfg_by_def(const LM32Def *def)
+{
+    uint32_t cfg = 0;
+
+    if (def->features & LM32_FEATURE_MULTIPLY) {
+        cfg |= CFG_M;
+    }
+
+    if (def->features & LM32_FEATURE_DIVIDE) {
+        cfg |= CFG_D;
+    }
+
+    if (def->features & LM32_FEATURE_SHIFT) {
+        cfg |= CFG_S;
+    }
+
+    if (def->features & LM32_FEATURE_SIGN_EXTEND) {
+        cfg |= CFG_X;
+    }
+
+    if (def->features & LM32_FEATURE_I_CACHE) {
+        cfg |= CFG_IC;
+    }
+
+    if (def->features & LM32_FEATURE_D_CACHE) {
+        cfg |= CFG_DC;
+    }
+
+    if (def->features & LM32_FEATURE_CYCLE_COUNT) {
+        cfg |= CFG_CC;
+    }
+
+    cfg |= (def->num_interrupts << CFG_INT_SHIFT);
+    cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
+    cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
+    cfg |= (def->revision << CFG_REV_SHIFT);
+
+    return cfg;
+}
+
+CPUState *cpu_lm32_init(const char *cpu_model)
+{
+    CPUState *env;
+    const LM32Def *def;
+    static int tcg_initialized;
+
+    def = cpu_lm32_find_by_name(cpu_model);
+    if (!def) {
+        return NULL;
+    }
+
+    env = g_malloc0(sizeof(CPUState));
+
+    env->features = def->features;
+    env->num_bps = def->num_breakpoints;
+    env->num_wps = def->num_watchpoints;
+    env->cfg = cfg_by_def(def);
+    env->flags = 0;
+
+    cpu_exec_init(env);
+    cpu_reset(env);
+    qemu_init_vcpu(env);
+
+    if (!tcg_initialized) {
+        tcg_initialized = 1;
+        lm32_translate_init();
+    }
+
+    return env;
+}
+
+/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
+ * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+ * 0x80000000-0xffffffff is not cached and used to access IO devices. */
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value)
+{
+    if (value) {
+        env->flags |= LM32_FLAG_IGNORE_MSB;
+    } else {
+        env->flags &= ~LM32_FLAG_IGNORE_MSB;
+    }
+}
+
+void cpu_reset(CPUState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    tlb_flush(env, 1);
+
+    /* reset cpu state */
+    memset(env, 0, offsetof(CPULM32State, breakpoints));
+}
+
diff --git a/target-lm32/helper.h b/target-lm32/helper.h
new file mode 100644 (file)
index 0000000..9d335ef
--- /dev/null
@@ -0,0 +1,14 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(hlt, void)
+DEF_HELPER_1(wcsr_im, void, i32)
+DEF_HELPER_1(wcsr_ip, void, i32)
+DEF_HELPER_1(wcsr_jtx, void, i32)
+DEF_HELPER_1(wcsr_jrx, void, i32)
+DEF_HELPER_0(rcsr_im, i32)
+DEF_HELPER_0(rcsr_ip, i32)
+DEF_HELPER_0(rcsr_jtx, i32)
+DEF_HELPER_0(rcsr_jrx, i32)
+
+#include "def-helper.h"
diff --git a/target-lm32/machine.c b/target-lm32/machine.c
new file mode 100644 (file)
index 0000000..70ca52a
--- /dev/null
@@ -0,0 +1,33 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = CPU_SAVE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, CPUState, 32),
+        VMSTATE_UINT32(pc, CPUState),
+        VMSTATE_UINT32(ie, CPUState),
+        VMSTATE_UINT32(icc, CPUState),
+        VMSTATE_UINT32(dcc, CPUState),
+        VMSTATE_UINT32(cc, CPUState),
+        VMSTATE_UINT32(eba, CPUState),
+        VMSTATE_UINT32(dc, CPUState),
+        VMSTATE_UINT32(deba, CPUState),
+        VMSTATE_UINT32_ARRAY(bp, CPUState, 4),
+        VMSTATE_UINT32_ARRAY(wp, CPUState, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
new file mode 100644 (file)
index 0000000..02be134
--- /dev/null
@@ -0,0 +1,106 @@
+#include <assert.h>
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+#include "host-utils.h"
+
+#include "hw/lm32_pic.h"
+#include "hw/lm32_juart.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#define MMUSUFFIX _mmu
+#define SHIFT 0
+#include "softmmu_template.h"
+#define SHIFT 1
+#include "softmmu_template.h"
+#define SHIFT 2
+#include "softmmu_template.h"
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void helper_raise_exception(uint32_t index)
+{
+    env->exception_index = index;
+    cpu_loop_exit(env);
+}
+
+void helper_hlt(void)
+{
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit(env);
+}
+
+void helper_wcsr_im(uint32_t im)
+{
+    lm32_pic_set_im(env->pic_state, im);
+}
+
+void helper_wcsr_ip(uint32_t im)
+{
+    lm32_pic_set_ip(env->pic_state, im);
+}
+
+void helper_wcsr_jtx(uint32_t jtx)
+{
+    lm32_juart_set_jtx(env->juart_state, jtx);
+}
+
+void helper_wcsr_jrx(uint32_t jrx)
+{
+    lm32_juart_set_jrx(env->juart_state, jrx);
+}
+
+uint32_t helper_rcsr_im(void)
+{
+    return lm32_pic_get_im(env->pic_state);
+}
+
+uint32_t helper_rcsr_ip(void)
+{
+    return lm32_pic_get_ip(env->pic_state);
+}
+
+uint32_t helper_rcsr_jtx(void)
+{
+    return lm32_juart_get_jtx(env->juart_state);
+}
+
+uint32_t helper_rcsr_jrx(void)
+{
+    return lm32_juart_get_jrx(env->juart_state);
+}
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    saved_env = env;
+    env = env1;
+
+    ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+#endif
+
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
new file mode 100644 (file)
index 0000000..0be105d
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ *  LatticeMico32 main translation routines.
+ *
+ *  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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "helper.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#include "hw/lm32_pic.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define DISAS_LM32 1
+#if DISAS_LM32
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+#define EXTRACT_FIELD(src, start, end) \
+            (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+#define MEM_INDEX 0
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[32];
+static TCGv cpu_pc;
+static TCGv cpu_ie;
+static TCGv cpu_icc;
+static TCGv cpu_dcc;
+static TCGv cpu_cc;
+static TCGv cpu_cfg;
+static TCGv cpu_eba;
+static TCGv cpu_dc;
+static TCGv cpu_deba;
+static TCGv cpu_bp[4];
+static TCGv cpu_wp[4];
+
+#include "gen-icount.h"
+
+enum {
+    OP_FMT_RI,
+    OP_FMT_RR,
+    OP_FMT_CR,
+    OP_FMT_I
+};
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+    CPUState *env;
+    target_ulong pc;
+
+    /* Decoder.  */
+    int format;
+    uint32_t ir;
+    uint8_t opcode;
+    uint8_t r0, r1, r2, csr;
+    uint16_t imm5;
+    uint16_t imm16;
+    uint32_t imm26;
+
+    unsigned int delayed_branch;
+    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
+    int is_jmp;
+
+    int nr_nops;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+static const char *regnames[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26/gp", "r27/fp", "r28/sp", "r29/ra",
+    "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0",
+    "wp1", "wp2", "wp3"
+};
+
+static inline int zero_extend(unsigned int val, int width)
+{
+    return val & ((1 << width) - 1);
+}
+
+static inline int sign_extend(unsigned int val, int width)
+{
+    int sval;
+
+    /* LSL.  */
+    val <<= 32 - width;
+    sval = val;
+    /* ASR.  */
+    sval >>= 32 - width;
+
+    return sval;
+}
+
+static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
+{
+    TCGv_i32 tmp = tcg_const_i32(index);
+
+    gen_helper_raise_exception(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+
+    tb = dc->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+            likely(!dc->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_pc, dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dest);
+        if (dc->singlestep_enabled) {
+            t_gen_raise_exception(dc, EXCP_DEBUG);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void dec_add(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        if (dc->r0 == R_R0) {
+            if (dc->r1 == R_R0 && dc->imm16 == 0) {
+                LOG_DIS("nop\n");
+            } else {
+                LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16));
+            }
+        } else {
+            LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0,
+                    sign_extend(dc->imm16, 16));
+        }
+    } else {
+        LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_and(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else  {
+        if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+            gen_helper_hlt();
+        } else {
+            tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+        }
+    }
+}
+
+static void dec_andhi(DisasContext *dc)
+{
+    LOG_DIS("andhi r%d, r%d, %d\n", dc->r2, dc->r0, dc->imm16);
+
+    tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_b(DisasContext *dc)
+{
+    if (dc->r0 == R_RA) {
+        LOG_DIS("ret\n");
+    } else if (dc->r0 == R_EA) {
+        LOG_DIS("eret\n");
+    } else if (dc->r0 == R_BA) {
+        LOG_DIS("bret\n");
+    } else {
+        LOG_DIS("b r%d\n", dc->r0);
+    }
+
+    /* restore IE.IE in case of an eret */
+    if (dc->r0 == R_EA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_EIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    } else if (dc->r0 == R_BA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_BIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    }
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_bi(DisasContext *dc)
+{
+    LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26));
+
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_cond_branch(DisasContext *dc, int cond)
+{
+    int l1;
+
+    l1 = gen_new_label();
+    tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1);
+    gen_goto_tb(dc, 0, dc->pc + 4);
+    gen_set_label(l1);
+    gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16)));
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static void dec_be(DisasContext *dc)
+{
+    LOG_DIS("be r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_EQ);
+}
+
+static void dec_bg(DisasContext *dc)
+{
+    LOG_DIS("bg r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16 * 4));
+
+    gen_cond_branch(dc, TCG_COND_GT);
+}
+
+static void dec_bge(DisasContext *dc)
+{
+    LOG_DIS("bge r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GE);
+}
+
+static void dec_bgeu(DisasContext *dc)
+{
+    LOG_DIS("bgeu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GEU);
+}
+
+static void dec_bgu(DisasContext *dc)
+{
+    LOG_DIS("bgu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GTU);
+}
+
+static void dec_bne(DisasContext *dc)
+{
+    LOG_DIS("bne r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_NE);
+}
+
+static void dec_call(DisasContext *dc)
+{
+    LOG_DIS("call r%d\n", dc->r0);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_calli(DisasContext *dc)
+{
+    LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_compare(DisasContext *dc, int cond)
+{
+    int rX = (dc->format == OP_FMT_RR) ? dc->r2 : dc->r1;
+    int rY = (dc->format == OP_FMT_RR) ? dc->r0 : dc->r0;
+    int rZ = (dc->format == OP_FMT_RR) ? dc->r1 : -1;
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_setcondi_tl(cond, cpu_R[rX], cpu_R[rY],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_setcond_tl(cond, cpu_R[rX], cpu_R[rY], cpu_R[rZ]);
+    }
+}
+
+static void dec_cmpe(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_EQ);
+}
+
+static void dec_cmpg(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GT);
+}
+
+static void dec_cmpge(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GE);
+}
+
+static void dec_cmpgeu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GEU);
+}
+
+static void dec_cmpgu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GTU);
+}
+
+static void dec_cmpne(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_NE);
+}
+
+static void dec_divu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_lb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lbu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lhu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16));
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_modu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_mul(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("muli r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
+        cpu_abort(dc->env, "hardware multiplier is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_nor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("nori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16));
+        tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_or(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_orhi(DisasContext *dc)
+{
+    if (dc->r0 == R_R0) {
+        LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16);
+    } else {
+        LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
+    }
+
+    tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_scall(DisasContext *dc)
+{
+    if (dc->imm5 == 7) {
+        LOG_DIS("scall\n");
+    } else if (dc->imm5 == 2) {
+        LOG_DIS("break\n");
+    } else {
+        cpu_abort(dc->env, "invalid opcode\n");
+    }
+
+    if (dc->imm5 == 7) {
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_BREAKPOINT);
+    }
+}
+
+static void dec_rcsr(DisasContext *dc)
+{
+    LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie);
+        break;
+    case CSR_IM:
+        gen_helper_rcsr_im(cpu_R[dc->r2]);
+        break;
+    case CSR_IP:
+        gen_helper_rcsr_ip(cpu_R[dc->r2]);
+        break;
+    case CSR_CC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc);
+        break;
+    case CSR_CFG:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg);
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba);
+        break;
+    case CSR_JTX:
+        gen_helper_rcsr_jtx(cpu_R[dc->r2]);
+        break;
+    case CSR_JRX:
+        gen_helper_rcsr_jrx(cpu_R[dc->r2]);
+        break;
+    case CSR_ICC:
+    case CSR_DCC:
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_sb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sextb(DisasContext *dc)
+{
+    LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sexth(DisasContext *dc)
+{
+    LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sl(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        cpu_abort(dc->env, "hardware shifter is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sr(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sru(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sub(DisasContext *dc)
+{
+    LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_sw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_user(DisasContext *dc)
+{
+    LOG_DIS("user");
+
+    cpu_abort(dc->env, "user insn undefined\n");
+}
+
+static void dec_wcsr(DisasContext *dc)
+{
+    int no;
+
+    LOG_DIS("wcsr r%d, %d\n", dc->r1, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IM:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_im(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IP:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_ip(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_ICC:
+        /* TODO */
+        break;
+    case CSR_DCC:
+        /* TODO */
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]);
+        break;
+    case CSR_JTX:
+        gen_helper_wcsr_jtx(cpu_R[dc->r1]);
+        break;
+    case CSR_JRX:
+        gen_helper_wcsr_jrx(cpu_R[dc->r1]);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
+        break;
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+        no = dc->csr - CSR_BP0;
+        if (dc->env->num_bps <= no) {
+            cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        no = dc->csr - CSR_WP0;
+        if (dc->env->num_wps <= no) {
+            cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_CC:
+    case CSR_CFG:
+        cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_xnor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xnori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+        tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]);
+    } else {
+        tcg_gen_eqv_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_xor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+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_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;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+        tcg_gen_debug_insn_start(dc->pc);
+    }
+
+    dc->ir = ir = ldl_code(dc->pc);
+    LOG_DIS("%8.8x\t", dc->ir);
+
+    /* try guessing 'empty' instruction memory, although it may be a valid
+     * instruction sequence (eg. srui r0, r0, 0) */
+    if (dc->ir) {
+        dc->nr_nops = 0;
+    } else {
+        LOG_DIS("nr_nops=%d\t", dc->nr_nops);
+        dc->nr_nops++;
+        if (dc->nr_nops > 4) {
+            cpu_abort(dc->env, "fetching nop sequence\n");
+        }
+    }
+
+    dc->opcode = EXTRACT_FIELD(ir, 26, 31);
+
+    dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
+    dc->imm16 = EXTRACT_FIELD(ir, 0, 15);
+    dc->imm26 = EXTRACT_FIELD(ir, 0, 25);
+
+    dc->csr = EXTRACT_FIELD(ir, 21, 25);
+    dc->r0 = EXTRACT_FIELD(ir, 21, 25);
+    dc->r1 = EXTRACT_FIELD(ir, 16, 20);
+    dc->r2 = EXTRACT_FIELD(ir, 11, 15);
+
+    /* bit 31 seems to indicate insn type.  */
+    if (ir & (1 << 31)) {
+        dc->format = OP_FMT_RR;
+    } else {
+        dc->format = OP_FMT_RI;
+    }
+
+    assert(ARRAY_SIZE(decinfo) == 64);
+    assert(dc->opcode < 64);
+
+    decinfo[dc->opcode](dc);
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_tl(cpu_pc, dc->pc);
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+static void gen_intermediate_code_internal(CPUState *env,
+        TranslationBlock *tb, int search_pc)
+{
+    struct DisasContext ctx, *dc = &ctx;
+    uint16_t *gen_opc_end;
+    uint32_t pc_start;
+    int j, lj;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    qemu_log_try_set_file(stderr);
+
+    pc_start = tb->pc;
+    dc->env = env;
+    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->nr_nops = 0;
+
+    if (pc_start & 3) {
+        cpu_abort(env, "LM32: unaligned PC=%x\n", pc_start);
+    }
+
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("-----------------------------------------\n");
+        log_cpu_state(env, 0);
+    }
+
+    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 {
+        check_breakpoint(env, dc);
+
+        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;
+        }
+
+        /* Pretty disas.  */
+        LOG_DIS("%8.8x:\t", dc->pc);
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        decode(dc);
+        dc->pc += 4;
+        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) {
+        gen_io_end();
+    }
+
+    if (unlikely(env->singlestep_enabled)) {
+        if (dc->is_jmp == DISAS_NEXT) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc);
+        }
+        t_gen_raise_exception(dc, EXCP_DEBUG);
+    } else {
+        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;
+        }
+    }
+
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    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;
+    }
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("\n");
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\nisize=%d osize=%td\n",
+            dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+    }
+#endif
+}
+
+void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    int i;
+
+    if (!env || !f) {
+        return;
+    }
+
+    cpu_fprintf(f, "IN: PC=%x %s\n",
+                env->pc, lookup_symbol(env->pc));
+
+    cpu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n",
+             env->ie,
+             (env->ie & IE_IE) ? 1 : 0,
+             (env->ie & IE_EIE) ? 1 : 0,
+             (env->ie & IE_BIE) ? 1 : 0,
+             lm32_pic_get_im(env->pic_state),
+             lm32_pic_get_ip(env->pic_state));
+    cpu_fprintf(f, "eba=%8.8x deba=%8.8x\n",
+             env->eba,
+             env->deba);
+
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
+        if ((i + 1) % 4 == 0) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+    cpu_fprintf(f, "\n\n");
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
+
+void lm32_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
+        cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, regs[i]),
+                          regnames[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpu_bp); i++) {
+        cpu_bp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, bp[i]),
+                          regnames[32+i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) {
+        cpu_wp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, wp[i]),
+                          regnames[36+i]);
+    }
+
+    cpu_pc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, pc),
+                    "pc");
+    cpu_ie = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, ie),
+                    "ie");
+    cpu_icc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, icc),
+                    "icc");
+    cpu_dcc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dcc),
+                    "dcc");
+    cpu_cc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cc),
+                    "cc");
+    cpu_cfg = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cfg),
+                    "cfg");
+    cpu_eba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, eba),
+                    "eba");
+    cpu_dc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dc),
+                    "dc");
+    cpu_deba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, deba),
+                    "deba");
+}
+
index b025b6689d6f100ff11d70aea7e8c340fda2cef3..0667f8214ad85239acb95627e8e96dbb3d8a0f88 100644 (file)
@@ -119,7 +119,8 @@ void m68k_tcg_init(void);
 CPUM68KState *cpu_m68k_init(const char *cpu_model);
 int cpu_m68k_exec(CPUM68KState *s);
 void cpu_m68k_close(CPUM68KState *s);
-void do_interrupt(int is_hw);
+void do_interrupt(CPUState *env1);
+void do_interrupt_m68k_hardirq(CPUState *env1);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
@@ -230,7 +231,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_m68k_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_m68k_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
@@ -254,4 +255,16 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
             | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
 }
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
 #endif
index 514b03904f3118b9e9b613195ccac7b7fb5d9635..674c8e6f071d86d557d5bc957098ba27902133b1 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "config.h"
 #include "cpu.h"
-#include "exec-all.h"
 #include "qemu-common.h"
 #include "gdbstub.h"
 
@@ -173,7 +172,7 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
     CPUM68KState *env;
     static int inited;
 
-    env = qemu_mallocz(sizeof(CPUM68KState));
+    env = g_malloc0(sizeof(CPUM68KState));
     cpu_exec_init(env);
     if (!inited) {
         inited = 1;
@@ -194,7 +193,7 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
 
 void cpu_m68k_close(CPUM68KState *env)
 {
-    qemu_free(env);
+    g_free(env);
 }
 
 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
@@ -345,7 +344,7 @@ void m68k_switch_sp(CPUM68KState *env)
 #if defined(CONFIG_USER_ONLY)
 
 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     env->exception_index = EXCP_ACCESS;
     env->mmu.ar = address;
@@ -363,7 +362,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 }
 
 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     int prot;
 
@@ -714,7 +713,7 @@ void HELPER(macsats)(CPUState *env, uint32_t acc)
     if (env->macsr & MACSR_V) {
         env->macsr |= MACSR_PAV0 << acc;
         if (env->macsr & MACSR_OMC) {
-            /* The result is saturated to 32 bits, despite overflow occuring
+            /* The result is saturated to 32 bits, despite overflow occurring
                at 48 bits.  Seems weird, but that's what the hardware docs
                say.  */
             result = (result >> 63) ^ 0x7fffffff;
index 07111073f81af975e90ed6f190feba3ecbf4e53c..2f7fe6bc4e0411a01088a4104d0131c995916dc9 100644 (file)
  * 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 "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "helpers.h"
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_interrupt(int is_hw)
+void do_interrupt(CPUState *env1)
+{
+    env1->exception_index = -1;
+}
+
+void do_interrupt_m68k_hardirq(CPUState *env1)
 {
-    env->exception_index = -1;
 }
 
 #else
 
 extern int semihosting_enabled;
 
+#include "softmmu_exec.h"
+
 #define MMUSUFFIX _mmu
 
 #define SHIFT 0
@@ -48,18 +55,17 @@ extern int semihosting_enabled;
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
@@ -68,10 +74,10 @@ 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();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
@@ -90,7 +96,7 @@ static void do_rte(void)
     env->aregs[7] = sp + 8;
 }
 
-void do_interrupt(int is_hw)
+static void do_interrupt_all(int is_hw)
 {
     uint32_t sp;
     uint32_t fmt;
@@ -118,7 +124,7 @@ void do_interrupt(int is_hw)
             }
             env->halted = 1;
             env->exception_index = EXCP_HLT;
-            cpu_loop_exit();
+            cpu_loop_exit(env);
             return;
         }
         if (env->exception_index >= EXCP_TRAP0
@@ -155,12 +161,31 @@ void do_interrupt(int is_hw)
     env->pc = ldl_kernel(env->vbr + vector);
 }
 
+void do_interrupt(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(0);
+    env = saved_env;
+}
+
+void do_interrupt_m68k_hardirq(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(1);
+    env = saved_env;
+}
 #endif
 
 static void raise_exception(int tt)
 {
     env->exception_index = tt;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void HELPER(raise_exception)(uint32_t tt)
index 6f72a2bdd2fc4ccd5270aa6bfb0c6118a590025b..0e7f1fe2c76e3979d4d067d2c04422997c7b2dbd 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "config.h"
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-log.h"
@@ -171,9 +170,6 @@ typedef void (*disas_proc)(DisasContext *, uint16_t);
   static void disas_##name (DisasContext *s, uint16_t insn)
 #endif
 
-/* FIXME: Remove this.  */
-#define gen_im32(val) tcg_const_i32(val)
-
 /* Generate a load from the specified address.  Narrow values are
    sign extended to full register width.  */
 static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
@@ -339,7 +335,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
         if ((ext & 0x80) == 0) {
             /* base not suppressed */
             if (IS_NULL_QREG(base)) {
-                base = gen_im32(offset + bd);
+                base = tcg_const_i32(offset + bd);
                 bd = 0;
             }
             if (!IS_NULL_QREG(add)) {
@@ -355,7 +351,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
                 add = tmp;
             }
         } else {
-            add = gen_im32(bd);
+            add = tcg_const_i32(bd);
         }
         if ((ext & 3) != 0) {
             /* memory indirect */
@@ -536,15 +532,15 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize)
         case 0: /* Absolute short.  */
             offset = ldsw_code(s->pc);
             s->pc += 2;
-            return gen_im32(offset);
+            return tcg_const_i32(offset);
         case 1: /* Absolute long.  */
             offset = read_im32(s);
-            return gen_im32(offset);
+            return tcg_const_i32(offset);
         case 2: /* pc displacement  */
             offset = s->pc;
             offset += ldsw_code(s->pc);
             s->pc += 2;
-            return gen_im32(offset);
+            return tcg_const_i32(offset);
         case 3: /* pc index+displacement.  */
             return gen_lea_indexed(s, opsize, NULL_QREG);
         case 4: /* Immediate.  */
@@ -861,7 +857,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);
@@ -1209,16 +1205,16 @@ DISAS_INSN(arith_im)
         break;
     case 2: /* subi */
         tcg_gen_mov_i32(dest, src1);
-        gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+        gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
         tcg_gen_subi_i32(dest, dest, im);
-        gen_update_cc_add(dest, gen_im32(im));
+        gen_update_cc_add(dest, tcg_const_i32(im));
         s->cc_op = CC_OP_SUB;
         break;
     case 3: /* addi */
         tcg_gen_mov_i32(dest, src1);
         tcg_gen_addi_i32(dest, dest, im);
-        gen_update_cc_add(dest, gen_im32(im));
-        gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+        gen_update_cc_add(dest, tcg_const_i32(im));
+        gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
         s->cc_op = CC_OP_ADD;
         break;
     case 5: /* eori */
@@ -1228,7 +1224,7 @@ DISAS_INSN(arith_im)
     case 6: /* cmpi */
         tcg_gen_mov_i32(dest, src1);
         tcg_gen_subi_i32(dest, dest, im);
-        gen_update_cc_add(dest, gen_im32(im));
+        gen_update_cc_add(dest, tcg_const_i32(im));
         s->cc_op = CC_OP_SUB;
         break;
     default:
@@ -1324,8 +1320,8 @@ DISAS_INSN(clr)
     default:
         abort();
     }
-    DEST_EA(insn, opsize, gen_im32(0), NULL);
-    gen_logic_cc(s, gen_im32(0));
+    DEST_EA(insn, opsize, tcg_const_i32(0), NULL);
+    gen_logic_cc(s, tcg_const_i32(0));
 }
 
 static TCGv gen_get_ccr(DisasContext *s)
@@ -1589,7 +1585,7 @@ DISAS_INSN(jump)
     }
     if ((insn & 0x40) == 0) {
         /* jsr */
-        gen_push(s, gen_im32(s->pc));
+        gen_push(s, tcg_const_i32(s->pc));
     }
     gen_jmp(s, tmp);
 }
@@ -1617,7 +1613,7 @@ DISAS_INSN(addsubq)
             tcg_gen_addi_i32(dest, dest, val);
         }
     } else {
-        src2 = gen_im32(val);
+        src2 = tcg_const_i32(val);
         if (insn & 0x0100) {
             gen_helper_xflag_lt(QREG_CC_X, dest, src2);
             tcg_gen_subi_i32(dest, dest, val);
@@ -1666,7 +1662,7 @@ DISAS_INSN(branch)
     }
     if (op == 1) {
         /* bsr */
-        gen_push(s, gen_im32(s->pc));
+        gen_push(s, tcg_const_i32(s->pc));
     }
     gen_flush_cc_op(s);
     if (op > 1) {
@@ -1757,7 +1753,7 @@ DISAS_INSN(mov3q)
     val = (insn >> 9) & 7;
     if (val == 0)
         val = -1;
-    src = gen_im32(val);
+    src = tcg_const_i32(val);
     gen_logic_cc(s, src);
     DEST_EA(insn, OS_LONG, src, NULL);
 }
@@ -1883,7 +1879,7 @@ DISAS_INSN(shift_im)
     tmp = (insn >> 9) & 7;
     if (tmp == 0)
         tmp = 8;
-    shift = gen_im32(tmp);
+    shift = tcg_const_i32(tmp);
     /* No need to flush flags becuse we know we will set C flag.  */
     if (insn & 0x100) {
         gen_helper_shl_cc(reg, cpu_env, reg, shift);
@@ -2191,7 +2187,7 @@ DISAS_INSN(fpu)
         switch ((ext >> 10) & 7) {
         case 4: /* FPCR */
             /* Not implemented.  Always return zero.  */
-            tmp32 = gen_im32(0);
+            tmp32 = tcg_const_i32(0);
             break;
         case 1: /* FPIAR */
         case 2: /* FPSR */
@@ -2592,7 +2588,7 @@ DISAS_INSN(mac)
         /* Skip the accumulate if the value is already saturated.  */
         l1 = gen_new_label();
         tmp = tcg_temp_new();
-        gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+        gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
         gen_op_jmp_nz32(tmp, l1);
     }
 #endif
@@ -2626,7 +2622,7 @@ DISAS_INSN(mac)
             /* Skip the accumulate if the value is already saturated.  */
             l1 = gen_new_label();
             tmp = tcg_temp_new();
-            gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+            gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
             gen_op_jmp_nz32(tmp, l1);
         }
 #endif
@@ -3113,8 +3109,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 3aa28bfd40ae83eb9bb21ddb24811b2f0f8f1208..35302863cb95fb210370532cb3e4d7c6c3971361 100644 (file)
@@ -41,6 +41,9 @@ struct CPUMBState;
 #define EXCP_HW_BREAK   5
 #define EXCP_HW_EXCP    6
 
+/* MicroBlaze-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+
 /* Register aliases. R0 - R15 */
 #define R_SP     1
 #define SR_PC    0
@@ -62,6 +65,7 @@ struct CPUMBState;
 #define MSR_DCE (1<<7) /* 0x080 */
 #define MSR_EE  (1<<8) /* 0x100 */
 #define MSR_EIP (1<<9) /* 0x200 */
+#define MSR_PVR (1<<10) /* 0x400 */
 #define MSR_CC  (1<<31)
 
 /* Machine State Register (MSR) Fields */
@@ -79,6 +83,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 +97,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 */
@@ -110,6 +117,9 @@ struct CPUMBState;
 #define PVR0_USE_ICACHE_MASK            0x02000000
 #define PVR0_USE_DCACHE_MASK            0x01000000
 #define PVR0_USE_MMU                    0x00800000      /* new */
+#define PVR0_USE_BTC                   0x00400000
+#define PVR0_ENDI                      0x00200000
+#define PVR0_FAULT                     0x00100000
 #define PVR0_VERSION_MASK               0x0000FF00
 #define PVR0_USER1_MASK                 0x000000FF
 
@@ -169,6 +179,7 @@ struct CPUMBState;
 #define PVR5_DCACHE_ALLOW_WR_MASK       0x01000000
 #define PVR5_DCACHE_LINE_LEN_MASK       0x00E00000
 #define PVR5_DCACHE_BYTE_SIZE_MASK      0x001F0000
+#define PVR5_DCACHE_WRITEBACK_MASK      0x00004000
 
 /* ICache base address PVR mask */
 #define PVR6_ICACHE_BASEADDR_MASK       0xFFFFFFFF
@@ -190,7 +201,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
 
@@ -207,6 +218,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;
@@ -292,7 +310,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_mb_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu);
+                            int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mb_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
@@ -330,7 +348,20 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 }
 
 #if !defined(CONFIG_USER_ONLY)
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size);
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size);
 #endif
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->sregs[SR_PC] = tb->pc;
+}
+
 #endif
index 5230b52c18eb378466ce278cb79406602aa129dc..2cf28022bd22b55cd4f55dffe9becb9cb44f7f5a 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "config.h"
 #include "cpu.h"
-#include "exec-all.h"
 #include "host-utils.h"
 
 #define D(x)
@@ -38,7 +37,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                             int mmu_idx, int is_softmmu)
+                            int mmu_idx)
 {
     env->exception_index = 0xaa;
     cpu_dump_state(env, stderr, fprintf, 0);
@@ -48,7 +47,7 @@ int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
 #else /* !CONFIG_USER_ONLY */
 
 int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     unsigned int hit;
     unsigned int mmu_available;
@@ -117,7 +116,7 @@ void do_interrupt(CPUState *env)
 {
     uint32_t t;
 
-    /* IMM flag cannot propagate accross a branch and into the dslot.  */
+    /* IMM flag cannot propagate across a branch and into the dslot.  */
     assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
     assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
 /*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
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 b38f7d98b76257a45d5102165ed1ee2ec6809d11..281fc8d8c45224dc23221e34beb888abff90c223 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "config.h"
 #include "cpu.h"
-#include "exec-all.h"
 
 #define D(x)
 
index d75a53cc547396d7eaf88b4c536dcfcec9a5bbf6..7433cec2911a4753c6cbf9a5b25257cf39e0325f 100644 (file)
  */
 
 #include <assert.h>
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "helper.h"
 #include "host-utils.h"
 
 #define D(x)
 
 #if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+
 #define MMUSUFFIX _mmu
 #define SHIFT 0
 #include "softmmu_template.h"
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
-    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
@@ -60,19 +62,54 @@ 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();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
 #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;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_debug(void)
@@ -303,7 +340,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 +386,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);
 
@@ -453,20 +490,14 @@ void helper_mmu_write(uint32_t rn, uint32_t v)
     mmu_write(env, rn, v);
 }
 
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
 {
     CPUState *saved_env;
 
-    if (!cpu_single_env) {
-        /* XXX: ???   */
-        return;
-    }
-
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
+
     qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
              addr, is_write, is_exec);
     if (!(env->sregs[SR_MSR] & MSR_EE)) {
index 220743195cb66dd49c2cc2815ec7031c63fa712e..366fd3e607859ef3740fc097e434345db34c2586 100644 (file)
@@ -25,7 +25,6 @@
 #include <assert.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "helper.h"
@@ -146,7 +145,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);
@@ -425,10 +424,15 @@ static inline void msr_read(DisasContext *dc, TCGv d)
 
 static inline void msr_write(DisasContext *dc, TCGv v)
 {
+    TCGv t;
+
+    t = tcg_temp_new();
     dc->cpustate_changed = 1;
-    tcg_gen_mov_tl(cpu_SR[SR_MSR], v);
-    /* PVR, we have a processor version register.  */
-    tcg_gen_ori_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], (1 << 10));
+    /* PVR bit is not writable.  */
+    tcg_gen_andi_tl(t, v, ~MSR_PVR);
+    tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
+    tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
+    tcg_temp_free(t);
 }
 
 static void dec_msr(DisasContext *dc)
@@ -923,7 +927,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 +1480,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 +1540,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}
 };
 
@@ -1715,9 +1756,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
     t_sync_flags(dc);
 
     if (unlikely(env->singlestep_enabled)) {
-        t_gen_raise_exception(dc, EXCP_DEBUG);
-        if (dc->is_jmp == DISAS_NEXT)
+        TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
+
+        if (dc->is_jmp != DISAS_JUMP) {
             tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+        }
+        gen_helper_raise_exception(tmp);
+        tcg_temp_free_i32(tmp);
     } else {
         switch(dc->is_jmp) {
             case DISAS_NEXT:
@@ -1806,10 +1851,11 @@ CPUState *cpu_mb_init (const char *cpu_model)
     static int tcg_initialized = 0;
     int i;
 
-    env = qemu_mallocz(sizeof(CPUState));
+    env = g_malloc0(sizeof(CPUState));
 
     cpu_exec_init(env);
     cpu_reset(env);
+    qemu_init_vcpu(env);
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 
     if (tcg_initialized)
@@ -1899,8 +1945,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..79e25583ff381c115d6e14e50417077eec5ed275 100644 (file)
@@ -1,6 +1,8 @@
 #if !defined (__MIPS_CPU_H__)
 #define __MIPS_CPU_H__
 
+//#define DEBUG_OP
+
 #define TARGET_HAS_ICE 1
 
 #define ELF_MACHINE    EM_MIPS
@@ -63,7 +65,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
@@ -493,8 +495,8 @@ void r4k_helper_tlbwr (void);
 void r4k_helper_tlbp (void);
 void r4k_helper_tlbr (void);
 
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int unused, int size);
+void cpu_unassigned_access(CPUState *env, target_phys_addr_t addr,
+                           int is_write, int is_exec, int unused, int size);
 #endif
 
 void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
@@ -535,6 +537,10 @@ static inline int cpu_mips_hw_interrupts_pending(CPUState *env)
     if (!(env->CP0_Status & (1 << CP0St_IE)) ||
         (env->CP0_Status & (1 << CP0St_EXL)) ||
         (env->CP0_Status & (1 << CP0St_ERL)) ||
+        /* Note that the TCStatus IXMT field is initialized to zero,
+           and only MT capable cores can set it to one. So we don't
+           need to check for MT capabilities here.  */
+        (env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT)) ||
         (env->hflags & MIPS_HFLAG_DM)) {
         /* Interrupts are disabled */
         return 0;
@@ -616,6 +622,14 @@ enum {
 /* Dummy exception for conditional stores.  */
 #define EXCP_SC 0x100
 
+/*
+ * This is an interrnally generated WAKE request line.
+ * It is driven by the CPU itself. Raised when the MT
+ * block wants to wake a VPE from an inactive state and
+ * cleared when VPE goes from active to inactive.
+ */
+#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
+
 int cpu_mips_exec(CPUMIPSState *s);
 CPUMIPSState *cpu_mips_init(const char *cpu_model);
 //~ uint32_t cpu_mips_get_clock (void);
@@ -634,7 +648,7 @@ void cpu_mips_soft_irq(CPUState *env, int irq, int level);
 
 /* helper.c */
 int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu);
+                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
 void do_interrupt (CPUState *env);
 #if !defined(CONFIG_USER_ONLY)
@@ -656,4 +670,71 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
     env->tls_value = newtls;
 }
 
+static inline int mips_vpe_active(CPUState *env)
+{
+    int active = 1;
+
+    /* Check that the VPE is enabled.  */
+    if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) {
+        active = 0;
+    }
+    /* Check that the VPE is actived.  */
+    if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) {
+        active = 0;
+    }
+
+    /* Now verify that there are active thread contexts in the VPE.
+
+       This assumes the CPU model will internally reschedule threads
+       if the active one goes to sleep. If there are no threads available
+       the active one will be in a sleeping state, and we can turn off
+       the entire VPE.  */
+    if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
+        /* TC is not activated.  */
+        active = 0;
+    }
+    if (env->active_tc.CP0_TCHalt & 1) {
+        /* TC is in halt state.  */
+        active = 0;
+    }
+
+    return active;
+}
+
+static inline int cpu_has_work(CPUState *env)
+{
+    int has_work = 0;
+
+    /* It is implementation dependent if non-enabled interrupts
+       wake-up the CPU, however most of the implementations only
+       check for interrupts that can be taken. */
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        cpu_mips_hw_interrupts_pending(env)) {
+        has_work = 1;
+    }
+
+    /* MIPS-MT has the ability to halt the CPU.  */
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        /* The QEMU model will issue an _WAKE request whenever the CPUs
+           should be woken up.  */
+        if (env->interrupt_request & CPU_INTERRUPT_WAKE) {
+            has_work = 1;
+        }
+
+        if (!mips_vpe_active(env)) {
+            has_work = 0;
+        }
+    }
+    return has_work;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->active_tc.PC = tb->pc;
+    env->hflags &= ~MIPS_HFLAG_BMASK;
+    env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
+}
+
 #endif /* !defined (__MIPS_CPU_H__) */
index bdc1e53669e83743ef5761473fd6b18b2b15f46b..1c58e0cc210088f8275ddcaa3fc0d4916e548e94 100644 (file)
@@ -24,7 +24,6 @@
 #include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 
 enum {
     TLBRET_DIRTY = -4,
@@ -267,39 +266,37 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 #endif
 
 int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
 #if !defined(CONFIG_USER_ONLY)
     target_phys_addr_t physical;
     int prot;
-#endif
     int access_type;
+#endif
     int ret = 0;
 
 #if 0
     log_cpu_state(env, 0);
 #endif
-    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
-              __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
+    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d\n",
+              __func__, env->active_tc.PC, address, rw, mmu_idx);
 
     rw &= 1;
 
     /* data access */
+#if !defined(CONFIG_USER_ONLY)
     /* XXX: put correct access by using cpu_restore_state()
        correctly */
     access_type = ACCESS_INT;
-#if defined(CONFIG_USER_ONLY)
-    ret = TLBRET_NOMATCH;
-#else
     ret = get_physical_address(env, &physical, &prot,
                                address, rw, access_type);
     qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n",
               __func__, address, ret, physical, prot);
     if (ret == TLBRET_MATCH) {
-       tlb_set_page(env, address & TARGET_PAGE_MASK,
-                    physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
-                    mmu_idx, TARGET_PAGE_SIZE);
-       ret = 0;
+        tlb_set_page(env, address & TARGET_PAGE_MASK,
+                     physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
+                     mmu_idx, TARGET_PAGE_SIZE);
+        ret = 0;
     } else if (ret < 0)
 #endif
     {
@@ -485,18 +482,18 @@ void do_interrupt (CPUState *env)
             unsigned int vector;
             unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
 
+            pending &= env->CP0_Status >> 8;
             /* Compute the Vector Spacing.  */
             spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
             spacing <<= 5;
 
             if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
                 /* For VInt mode, the MIPS computes the vector internally.  */
-                for (vector = 0; vector < 8; vector++) {
-                    if (pending & 1) {
+                for (vector = 7; vector > 0; vector--) {
+                    if (pending & (1 << vector)) {
                         /* Found it.  */
                         break;
                     }
-                    pending >>= 1;
                 }
             } else {
                 /* For VEIC mode, the external interrupt controller feeds the
index 297ab64bda85576d7a13cf7f317f6a83a30e3e5e..442f684697fd8691d021fe342ec23813d574e220 100644 (file)
@@ -52,6 +52,8 @@ DEF_HELPER_2(msachiu, tl, tl, tl)
 DEF_HELPER_0(mfc0_mvpcontrol, tl)
 DEF_HELPER_0(mfc0_mvpconf0, tl)
 DEF_HELPER_0(mfc0_mvpconf1, tl)
+DEF_HELPER_0(mftc0_vpecontrol, tl)
+DEF_HELPER_0(mftc0_vpeconf0, tl)
 DEF_HELPER_0(mfc0_random, tl)
 DEF_HELPER_0(mfc0_tcstatus, tl)
 DEF_HELPER_0(mftc0_tcstatus, tl)
@@ -70,6 +72,10 @@ DEF_HELPER_0(mftc0_tcschefback, tl)
 DEF_HELPER_0(mfc0_count, tl)
 DEF_HELPER_0(mftc0_entryhi, tl)
 DEF_HELPER_0(mftc0_status, tl)
+DEF_HELPER_0(mftc0_cause, tl)
+DEF_HELPER_0(mftc0_epc, tl)
+DEF_HELPER_0(mftc0_ebase, tl)
+DEF_HELPER_1(mftc0_configx, tl, tl)
 DEF_HELPER_0(mfc0_lladdr, tl)
 DEF_HELPER_1(mfc0_watchlo, tl, i32)
 DEF_HELPER_1(mfc0_watchhi, tl, i32)
@@ -88,7 +94,9 @@ DEF_HELPER_1(dmfc0_watchlo, tl, i32)
 DEF_HELPER_1(mtc0_index, void, tl)
 DEF_HELPER_1(mtc0_mvpcontrol, void, tl)
 DEF_HELPER_1(mtc0_vpecontrol, void, tl)
+DEF_HELPER_1(mttc0_vpecontrol, void, tl)
 DEF_HELPER_1(mtc0_vpeconf0, void, tl)
+DEF_HELPER_1(mttc0_vpeconf0, void, tl)
 DEF_HELPER_1(mtc0_vpeconf1, void, tl)
 DEF_HELPER_1(mtc0_yqmask, void, tl)
 DEF_HELPER_1(mtc0_vpeopt, void, tl)
@@ -127,7 +135,9 @@ DEF_HELPER_1(mttc0_status, void, tl)
 DEF_HELPER_1(mtc0_intctl, void, tl)
 DEF_HELPER_1(mtc0_srsctl, void, tl)
 DEF_HELPER_1(mtc0_cause, void, tl)
+DEF_HELPER_1(mttc0_cause, void, tl)
 DEF_HELPER_1(mtc0_ebase, void, tl)
+DEF_HELPER_1(mttc0_ebase, void, tl)
 DEF_HELPER_1(mtc0_config0, void, tl)
 DEF_HELPER_1(mtc0_config2, void, tl)
 DEF_HELPER_1(mtc0_lladdr, void, tl)
index 9ffac711ce52b8c6987aacf3f09bc58e62b32851..be72b36de6a5a835ff0c78d9811d99bed4096c53 100644 (file)
@@ -1,7 +1,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 
-#include "exec-all.h"
+#include "cpu.h"
 
 static void save_tc(QEMUFile *f, TCState *tc)
 {
index 669faf17ae17be5d6418cbfb5db26a75a5db4b3d..c51b9cb6f0e950f4edc94252cc98df322f0c762b 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include <stdlib.h>
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 
 #include "host-utils.h"
 
 #include "helper.h"
 
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
 #ifndef CONFIG_USER_ONLY
 static inline void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 #endif
 
+static inline void compute_hflags(CPUState *env)
+{
+    env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
+                     MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
+                     MIPS_HFLAG_UX);
+    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+        !(env->CP0_Status & (1 << CP0St_ERL)) &&
+        !(env->hflags & MIPS_HFLAG_DM)) {
+        env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
+    }
+#if defined(TARGET_MIPS64)
+    if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
+        (env->CP0_Status & (1 << CP0St_PX)) ||
+        (env->CP0_Status & (1 << CP0St_UX))) {
+        env->hflags |= MIPS_HFLAG_64;
+    }
+    if (env->CP0_Status & (1 << CP0St_UX)) {
+        env->hflags |= MIPS_HFLAG_UX;
+    }
+#endif
+    if ((env->CP0_Status & (1 << CP0St_CU0)) ||
+        !(env->hflags & MIPS_HFLAG_KSU)) {
+        env->hflags |= MIPS_HFLAG_CP0;
+    }
+    if (env->CP0_Status & (1 << CP0St_CU1)) {
+        env->hflags |= MIPS_HFLAG_FPU;
+    }
+    if (env->CP0_Status & (1 << CP0St_FR)) {
+        env->hflags |= MIPS_HFLAG_F64;
+    }
+    if (env->insn_flags & ISA_MIPS32R2) {
+        if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
+            env->hflags |= MIPS_HFLAG_COP1X;
+        }
+    } else if (env->insn_flags & ISA_MIPS32) {
+        if (env->hflags & MIPS_HFLAG_64) {
+            env->hflags |= MIPS_HFLAG_COP1X;
+        }
+    } else if (env->insn_flags & ISA_MIPS4) {
+        /* All supported MIPS IV CPUs use the XX (CU3) to enable
+           and disable the MIPS IV extensions to the MIPS III ISA.
+           Some other MIPS IV CPUs ignore the bit, so the check here
+           would be too restrictive for them.  */
+        if (env->CP0_Status & (1 << CP0St_CU3)) {
+            env->hflags |= MIPS_HFLAG_COP1X;
+        }
+    }
+}
+
 /*****************************************************************************/
 /* Exceptions processing helpers */
 
@@ -38,7 +92,7 @@ void helper_raise_exception_err (uint32_t exception, int error_code)
 #endif
     env->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_raise_exception (uint32_t exception)
@@ -54,7 +108,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
@@ -277,7 +331,7 @@ static inline target_phys_addr_t do_translate_address(target_ulong address, int
     lladdr = cpu_mips_translate_address(env, address, rw);
 
     if (lladdr == -1LL) {
-        cpu_loop_exit();
+        cpu_loop_exit(env);
     } else {
         return lladdr;
     }
@@ -695,6 +749,163 @@ void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
 #endif
 
 #ifndef CONFIG_USER_ONLY
+/* SMP helpers.  */
+static int mips_vpe_is_wfi(CPUState *c)
+{
+    /* If the VPE is halted but otherwise active, it means it's waiting for
+       an interrupt.  */
+    return c->halted && mips_vpe_active(c);
+}
+
+static inline void mips_vpe_wake(CPUState *c)
+{
+    /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
+       because there might be other conditions that state that c should
+       be sleeping.  */
+    cpu_interrupt(c, CPU_INTERRUPT_WAKE);
+}
+
+static inline void mips_vpe_sleep(CPUState *c)
+{
+    /* The VPE was shut off, really go to bed.
+       Reset any old _WAKE requests.  */
+    c->halted = 1;
+    cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
+}
+
+static inline void mips_tc_wake(CPUState *c, int tc)
+{
+    /* FIXME: TC reschedule.  */
+    if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) {
+        mips_vpe_wake(c);
+    }
+}
+
+static inline void mips_tc_sleep(CPUState *c, int tc)
+{
+    /* FIXME: TC reschedule.  */
+    if (!mips_vpe_active(c)) {
+        mips_vpe_sleep(c);
+    }
+}
+
+/* tc should point to an int with the value of the global TC index.
+   This function will transform it into a local index within the
+   returned CPUState.
+
+   FIXME: This code assumes that all VPEs have the same number of TCs,
+          which depends on runtime setup. Can probably be fixed by
+          walking the list of CPUStates.  */
+static CPUState *mips_cpu_map_tc(int *tc)
+{
+    CPUState *other;
+    int vpe_idx, nr_threads = env->nr_threads;
+    int tc_idx = *tc;
+
+    if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
+        /* Not allowed to address other CPUs.  */
+        *tc = env->current_tc;
+        return env;
+    }
+
+    vpe_idx = tc_idx / nr_threads;
+    *tc = tc_idx % nr_threads;
+    other = qemu_get_cpu(vpe_idx);
+    return other ? other : env;
+}
+
+/* The per VPE CP0_Status register shares some fields with the per TC
+   CP0_TCStatus registers. These fields are wired to the same registers,
+   so changes to either of them should be reflected on both registers.
+
+   Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
+
+   These helper call synchronizes the regs for a given cpu.  */
+
+/* Called for updates to CP0_Status.  */
+static void sync_c0_status(CPUState *cpu, int tc)
+{
+    int32_t tcstatus, *tcst;
+    uint32_t v = cpu->CP0_Status;
+    uint32_t cu, mx, asid, ksu;
+    uint32_t mask = ((1 << CP0TCSt_TCU3)
+                       | (1 << CP0TCSt_TCU2)
+                       | (1 << CP0TCSt_TCU1)
+                       | (1 << CP0TCSt_TCU0)
+                       | (1 << CP0TCSt_TMX)
+                       | (3 << CP0TCSt_TKSU)
+                       | (0xff << CP0TCSt_TASID));
+
+    cu = (v >> CP0St_CU0) & 0xf;
+    mx = (v >> CP0St_MX) & 0x1;
+    ksu = (v >> CP0St_KSU) & 0x3;
+    asid = env->CP0_EntryHi & 0xff;
+
+    tcstatus = cu << CP0TCSt_TCU0;
+    tcstatus |= mx << CP0TCSt_TMX;
+    tcstatus |= ksu << CP0TCSt_TKSU;
+    tcstatus |= asid;
+
+    if (tc == cpu->current_tc) {
+        tcst = &cpu->active_tc.CP0_TCStatus;
+    } else {
+        tcst = &cpu->tcs[tc].CP0_TCStatus;
+    }
+
+    *tcst &= ~mask;
+    *tcst |= tcstatus;
+    compute_hflags(cpu);
+}
+
+/* Called for updates to CP0_TCStatus.  */
+static void sync_c0_tcstatus(CPUState *cpu, int tc, target_ulong v)
+{
+    uint32_t status;
+    uint32_t tcu, tmx, tasid, tksu;
+    uint32_t mask = ((1 << CP0St_CU3)
+                       | (1 << CP0St_CU2)
+                       | (1 << CP0St_CU1)
+                       | (1 << CP0St_CU0)
+                       | (1 << CP0St_MX)
+                       | (3 << CP0St_KSU));
+
+    tcu = (v >> CP0TCSt_TCU0) & 0xf;
+    tmx = (v >> CP0TCSt_TMX) & 0x1;
+    tasid = v & 0xff;
+    tksu = (v >> CP0TCSt_TKSU) & 0x3;
+
+    status = tcu << CP0St_CU0;
+    status |= tmx << CP0St_MX;
+    status |= tksu << CP0St_KSU;
+
+    cpu->CP0_Status &= ~mask;
+    cpu->CP0_Status |= status;
+
+    /* Sync the TASID with EntryHi.  */
+    cpu->CP0_EntryHi &= ~0xff;
+    cpu->CP0_EntryHi = tasid;
+
+    compute_hflags(cpu);
+}
+
+/* Called for updates to CP0_EntryHi.  */
+static void sync_c0_entryhi(CPUState *cpu, int tc)
+{
+    int32_t *tcst;
+    uint32_t asid, v = cpu->CP0_EntryHi;
+
+    asid = v & 0xff;
+
+    if (tc == cpu->current_tc) {
+        tcst = &cpu->active_tc.CP0_TCStatus;
+    } else {
+        tcst = &cpu->tcs[tc].CP0_TCStatus;
+    }
+
+    *tcst &= ~0xff;
+    *tcst |= asid;
+}
+
 /* CP0 helpers */
 target_ulong helper_mfc0_mvpcontrol (void)
 {
@@ -724,11 +935,12 @@ target_ulong helper_mfc0_tcstatus (void)
 target_ulong helper_mftc0_tcstatus(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCStatus;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCStatus;
     else
-        return env->tcs[other_tc].CP0_TCStatus;
+        return other->tcs[other_tc].CP0_TCStatus;
 }
 
 target_ulong helper_mfc0_tcbind (void)
@@ -739,11 +951,12 @@ target_ulong helper_mfc0_tcbind (void)
 target_ulong helper_mftc0_tcbind(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCBind;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCBind;
     else
-        return env->tcs[other_tc].CP0_TCBind;
+        return other->tcs[other_tc].CP0_TCBind;
 }
 
 target_ulong helper_mfc0_tcrestart (void)
@@ -754,11 +967,12 @@ target_ulong helper_mfc0_tcrestart (void)
 target_ulong helper_mftc0_tcrestart(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.PC;
+    if (other_tc == other->current_tc)
+        return other->active_tc.PC;
     else
-        return env->tcs[other_tc].PC;
+        return other->tcs[other_tc].PC;
 }
 
 target_ulong helper_mfc0_tchalt (void)
@@ -769,11 +983,12 @@ target_ulong helper_mfc0_tchalt (void)
 target_ulong helper_mftc0_tchalt(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCHalt;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCHalt;
     else
-        return env->tcs[other_tc].CP0_TCHalt;
+        return other->tcs[other_tc].CP0_TCHalt;
 }
 
 target_ulong helper_mfc0_tccontext (void)
@@ -784,11 +999,12 @@ target_ulong helper_mfc0_tccontext (void)
 target_ulong helper_mftc0_tccontext(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCContext;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCContext;
     else
-        return env->tcs[other_tc].CP0_TCContext;
+        return other->tcs[other_tc].CP0_TCContext;
 }
 
 target_ulong helper_mfc0_tcschedule (void)
@@ -799,11 +1015,12 @@ target_ulong helper_mfc0_tcschedule (void)
 target_ulong helper_mftc0_tcschedule(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCSchedule;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCSchedule;
     else
-        return env->tcs[other_tc].CP0_TCSchedule;
+        return other->tcs[other_tc].CP0_TCSchedule;
 }
 
 target_ulong helper_mfc0_tcschefback (void)
@@ -814,11 +1031,12 @@ target_ulong helper_mfc0_tcschefback (void)
 target_ulong helper_mftc0_tcschefback(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.CP0_TCScheFBack;
+    if (other_tc == other->current_tc)
+        return other->active_tc.CP0_TCScheFBack;
     else
-        return env->tcs[other_tc].CP0_TCScheFBack;
+        return other->tcs[other_tc].CP0_TCScheFBack;
 }
 
 target_ulong helper_mfc0_count (void)
@@ -829,33 +1047,32 @@ target_ulong helper_mfc0_count (void)
 target_ulong helper_mftc0_entryhi(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    int32_t tcstatus;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        tcstatus = env->active_tc.CP0_TCStatus;
-    else
-        tcstatus = env->tcs[other_tc].CP0_TCStatus;
-
-    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
+    return other->CP0_EntryHi;
 }
 
-target_ulong helper_mftc0_status(void)
+target_ulong helper_mftc0_cause(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    target_ulong t0;
-    int32_t tcstatus;
+    int32_t tccause;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        tcstatus = env->active_tc.CP0_TCStatus;
-    else
-        tcstatus = env->tcs[other_tc].CP0_TCStatus;
+    if (other_tc == other->current_tc) {
+        tccause = other->CP0_Cause;
+    } else {
+        tccause = other->CP0_Cause;
+    }
 
-    t0 = env->CP0_Status & ~0xf1000018;
-    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
-    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
-    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
+    return tccause;
+}
 
-    return t0;
+target_ulong helper_mftc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    return other->CP0_Status;
 }
 
 target_ulong helper_mfc0_lladdr (void)
@@ -886,14 +1103,15 @@ target_ulong helper_mftc0_debug(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
     int32_t tcstatus;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        tcstatus = env->active_tc.CP0_Debug_tcstatus;
+    if (other_tc == other->current_tc)
+        tcstatus = other->active_tc.CP0_Debug_tcstatus;
     else
-        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
+        tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
 
     /* XXX: Might be wrong, check with EJTAG spec. */
-    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+    return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
             (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
 }
 
@@ -980,6 +1198,38 @@ void helper_mtc0_vpecontrol (target_ulong arg1)
     env->CP0_VPEControl = newval;
 }
 
+void helper_mttc0_vpecontrol(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+    uint32_t mask;
+    uint32_t newval;
+
+    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
+           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
+    newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
+
+    /* TODO: Enable/disable TCs.  */
+
+    other->CP0_VPEControl = newval;
+}
+
+target_ulong helper_mftc0_vpecontrol(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+    /* FIXME: Mask away return zero on read bits.  */
+    return other->CP0_VPEControl;
+}
+
+target_ulong helper_mftc0_vpeconf0(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    return other->CP0_VPEConf0;
+}
+
 void helper_mtc0_vpeconf0 (target_ulong arg1)
 {
     uint32_t mask = 0;
@@ -997,6 +1247,20 @@ void helper_mtc0_vpeconf0 (target_ulong arg1)
     env->CP0_VPEConf0 = newval;
 }
 
+void helper_mttc0_vpeconf0(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+    newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
+
+    /* TODO: TC exclusive handling due to ERL/EXL.  */
+    other->CP0_VPEConf0 = newval;
+}
+
 void helper_mtc0_vpeconf1 (target_ulong arg1)
 {
     uint32_t mask = 0;
@@ -1040,21 +1304,20 @@ void helper_mtc0_tcstatus (target_ulong arg1)
 
     newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
 
-    // TODO: Sync with CP0_Status.
-
     env->active_tc.CP0_TCStatus = newval;
+    sync_c0_tcstatus(env, env->current_tc, newval);
 }
 
 void helper_mttc0_tcstatus (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    // TODO: Sync with CP0_Status.
-
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCStatus = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_TCStatus = arg1;
     else
-        env->tcs[other_tc].CP0_TCStatus = arg1;
+        other->tcs[other_tc].CP0_TCStatus = arg1;
+    sync_c0_tcstatus(other, other_tc, arg1);
 }
 
 void helper_mtc0_tcbind (target_ulong arg1)
@@ -1073,15 +1336,16 @@ void helper_mttc0_tcbind (target_ulong arg1)
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
     uint32_t mask = (1 << CP0TCBd_TBE);
     uint32_t newval;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+    if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
         mask |= (1 << CP0TCBd_CurVPE);
-    if (other_tc == env->current_tc) {
-        newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
-        env->active_tc.CP0_TCBind = newval;
+    if (other_tc == other->current_tc) {
+        newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
+        other->active_tc.CP0_TCBind = newval;
     } else {
-        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
-        env->tcs[other_tc].CP0_TCBind = newval;
+        newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
+        other->tcs[other_tc].CP0_TCBind = newval;
     }
 }
 
@@ -1096,16 +1360,17 @@ void helper_mtc0_tcrestart (target_ulong arg1)
 void helper_mttc0_tcrestart (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc) {
-        env->active_tc.PC = arg1;
-        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
-        env->lladdr = 0ULL;
+    if (other_tc == other->current_tc) {
+        other->active_tc.PC = arg1;
+        other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        other->lladdr = 0ULL;
         /* MIPS16 not implemented. */
     } else {
-        env->tcs[other_tc].PC = arg1;
-        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
-        env->lladdr = 0ULL;
+        other->tcs[other_tc].PC = arg1;
+        other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        other->lladdr = 0ULL;
         /* MIPS16 not implemented. */
     }
 }
@@ -1115,18 +1380,30 @@ void helper_mtc0_tchalt (target_ulong arg1)
     env->active_tc.CP0_TCHalt = arg1 & 0x1;
 
     // TODO: Halt TC / Restart (if allocated+active) TC.
+    if (env->active_tc.CP0_TCHalt & 1) {
+        mips_tc_sleep(env, env->current_tc);
+    } else {
+        mips_tc_wake(env, env->current_tc);
+    }
 }
 
 void helper_mttc0_tchalt (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
     // TODO: Halt TC / Restart (if allocated+active) TC.
 
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCHalt = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_TCHalt = arg1;
     else
-        env->tcs[other_tc].CP0_TCHalt = arg1;
+        other->tcs[other_tc].CP0_TCHalt = arg1;
+
+    if (arg1 & 1) {
+        mips_tc_sleep(other, other_tc);
+    } else {
+        mips_tc_wake(other, other_tc);
+    }
 }
 
 void helper_mtc0_tccontext (target_ulong arg1)
@@ -1137,11 +1414,12 @@ void helper_mtc0_tccontext (target_ulong arg1)
 void helper_mttc0_tccontext (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCContext = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_TCContext = arg1;
     else
-        env->tcs[other_tc].CP0_TCContext = arg1;
+        other->tcs[other_tc].CP0_TCContext = arg1;
 }
 
 void helper_mtc0_tcschedule (target_ulong arg1)
@@ -1152,11 +1430,12 @@ void helper_mtc0_tcschedule (target_ulong arg1)
 void helper_mttc0_tcschedule (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCSchedule = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_TCSchedule = arg1;
     else
-        env->tcs[other_tc].CP0_TCSchedule = arg1;
+        other->tcs[other_tc].CP0_TCSchedule = arg1;
 }
 
 void helper_mtc0_tcschefback (target_ulong arg1)
@@ -1167,11 +1446,12 @@ void helper_mtc0_tcschefback (target_ulong arg1)
 void helper_mttc0_tcschefback (target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCScheFBack = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_TCScheFBack = arg1;
     else
-        env->tcs[other_tc].CP0_TCScheFBack = arg1;
+        other->tcs[other_tc].CP0_TCScheFBack = arg1;
 }
 
 void helper_mtc0_entrylo1 (target_ulong arg1)
@@ -1252,8 +1532,7 @@ void helper_mtc0_entryhi (target_ulong arg1)
     old = env->CP0_EntryHi;
     env->CP0_EntryHi = val;
     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
-        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
-        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
+        sync_c0_entryhi(env, env->current_tc);
     }
     /* If the ASID changes, flush qemu's TLB.  */
     if ((old & 0xFF) != (val & 0xFF))
@@ -1263,16 +1542,10 @@ void helper_mtc0_entryhi (target_ulong arg1)
 void helper_mttc0_entryhi(target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    int32_t tcstatus;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
-    if (other_tc == env->current_tc) {
-        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
-        env->active_tc.CP0_TCStatus = tcstatus;
-    } else {
-        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
-        env->tcs[other_tc].CP0_TCStatus = tcstatus;
-    }
+    other->CP0_EntryHi = arg1;
+    sync_c0_entryhi(other, other_tc);
 }
 
 void helper_mtc0_compare (target_ulong arg1)
@@ -1288,7 +1561,12 @@ void helper_mtc0_status (target_ulong arg1)
     val = arg1 & mask;
     old = env->CP0_Status;
     env->CP0_Status = (env->CP0_Status & ~mask) | val;
-    compute_hflags(env);
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        sync_c0_status(env, env->current_tc);
+    } else {
+        compute_hflags(env);
+    }
+
     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
         qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
                 old, old & env->CP0_Cause & CP0Ca_IP_mask,
@@ -1306,22 +1584,16 @@ void helper_mtc0_status (target_ulong arg1)
 void helper_mttc0_status(target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
-
-    env->CP0_Status = arg1 & ~0xf1000018;
-    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
-    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
-    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_TCStatus = tcstatus;
-    else
-        env->tcs[other_tc].CP0_TCStatus = tcstatus;
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    other->CP0_Status = arg1 & ~0xf1000018;
+    sync_c0_status(other, other_tc);
 }
 
 void helper_mtc0_intctl (target_ulong arg1)
 {
     /* vectored interrupts not implemented, no performance counters. */
-    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
+    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
 }
 
 void helper_mtc0_srsctl (target_ulong arg1)
@@ -1330,38 +1602,95 @@ void helper_mtc0_srsctl (target_ulong arg1)
     env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
 }
 
-void helper_mtc0_cause (target_ulong arg1)
+static void mtc0_cause(CPUState *cpu, target_ulong arg1)
 {
     uint32_t mask = 0x00C00300;
-    uint32_t old = env->CP0_Cause;
+    uint32_t old = cpu->CP0_Cause;
     int i;
 
-    if (env->insn_flags & ISA_MIPS32R2)
+    if (cpu->insn_flags & ISA_MIPS32R2) {
         mask |= 1 << CP0Ca_DC;
+    }
 
-    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
+    cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
 
-    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
-        if (env->CP0_Cause & (1 << CP0Ca_DC))
-            cpu_mips_stop_count(env);
-        else
-            cpu_mips_start_count(env);
+    if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
+        if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
+            cpu_mips_stop_count(cpu);
+        } else {
+            cpu_mips_start_count(cpu);
+        }
     }
 
     /* Set/reset software interrupts */
     for (i = 0 ; i < 2 ; i++) {
-        if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
-            cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+        if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+            cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
         }
     }
 }
 
+void helper_mtc0_cause(target_ulong arg1)
+{
+    mtc0_cause(env, arg1);
+}
+
+void helper_mttc0_cause(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    mtc0_cause(other, arg1);
+}
+
+target_ulong helper_mftc0_epc(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    return other->CP0_EPC;
+}
+
+target_ulong helper_mftc0_ebase(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    return other->CP0_EBase;
+}
+
 void helper_mtc0_ebase (target_ulong arg1)
 {
     /* vectored interrupts not implemented */
     env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
 }
 
+void helper_mttc0_ebase(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+    other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
+}
+
+target_ulong helper_mftc0_configx(target_ulong idx)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
+
+    switch (idx) {
+    case 0: return other->CP0_Config0;
+    case 1: return other->CP0_Config1;
+    case 2: return other->CP0_Config2;
+    case 3: return other->CP0_Config3;
+    /* 4 and 5 are reserved.  */
+    case 6: return other->CP0_Config6;
+    case 7: return other->CP0_Config7;
+    default:
+        break;
+    }
+    return 0;
+}
+
 void helper_mtc0_config0 (target_ulong arg1)
 {
     env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
@@ -1417,13 +1746,15 @@ void helper_mttc0_debug(target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
     uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
     /* XXX: Might be wrong, check with EJTAG spec. */
-    if (other_tc == env->current_tc)
-        env->active_tc.CP0_Debug_tcstatus = val;
+    if (other_tc == other->current_tc)
+        other->active_tc.CP0_Debug_tcstatus = val;
     else
-        env->tcs[other_tc].CP0_Debug_tcstatus = val;
-    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+        other->tcs[other_tc].CP0_Debug_tcstatus = val;
+    other->CP0_Debug = (other->CP0_Debug &
+                     ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
                      (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
 }
 
@@ -1456,101 +1787,111 @@ void helper_mtc0_datahi (target_ulong arg1)
 target_ulong helper_mftgpr(uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.gpr[sel];
+    if (other_tc == other->current_tc)
+        return other->active_tc.gpr[sel];
     else
-        return env->tcs[other_tc].gpr[sel];
+        return other->tcs[other_tc].gpr[sel];
 }
 
 target_ulong helper_mftlo(uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.LO[sel];
+    if (other_tc == other->current_tc)
+        return other->active_tc.LO[sel];
     else
-        return env->tcs[other_tc].LO[sel];
+        return other->tcs[other_tc].LO[sel];
 }
 
 target_ulong helper_mfthi(uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.HI[sel];
+    if (other_tc == other->current_tc)
+        return other->active_tc.HI[sel];
     else
-        return env->tcs[other_tc].HI[sel];
+        return other->tcs[other_tc].HI[sel];
 }
 
 target_ulong helper_mftacx(uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.ACX[sel];
+    if (other_tc == other->current_tc)
+        return other->active_tc.ACX[sel];
     else
-        return env->tcs[other_tc].ACX[sel];
+        return other->tcs[other_tc].ACX[sel];
 }
 
 target_ulong helper_mftdsp(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        return env->active_tc.DSPControl;
+    if (other_tc == other->current_tc)
+        return other->active_tc.DSPControl;
     else
-        return env->tcs[other_tc].DSPControl;
+        return other->tcs[other_tc].DSPControl;
 }
 
 void helper_mttgpr(target_ulong arg1, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.gpr[sel] = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.gpr[sel] = arg1;
     else
-        env->tcs[other_tc].gpr[sel] = arg1;
+        other->tcs[other_tc].gpr[sel] = arg1;
 }
 
 void helper_mttlo(target_ulong arg1, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.LO[sel] = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.LO[sel] = arg1;
     else
-        env->tcs[other_tc].LO[sel] = arg1;
+        other->tcs[other_tc].LO[sel] = arg1;
 }
 
 void helper_mtthi(target_ulong arg1, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.HI[sel] = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.HI[sel] = arg1;
     else
-        env->tcs[other_tc].HI[sel] = arg1;
+        other->tcs[other_tc].HI[sel] = arg1;
 }
 
 void helper_mttacx(target_ulong arg1, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.ACX[sel] = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.ACX[sel] = arg1;
     else
-        env->tcs[other_tc].ACX[sel] = arg1;
+        other->tcs[other_tc].ACX[sel] = arg1;
 }
 
 void helper_mttdsp(target_ulong arg1)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    CPUState *other = mips_cpu_map_tc(&other_tc);
 
-    if (other_tc == env->current_tc)
-        env->active_tc.DSPControl = arg1;
+    if (other_tc == other->current_tc)
+        other->active_tc.DSPControl = arg1;
     else
-        env->tcs[other_tc].DSPControl = arg1;
+        other->tcs[other_tc].DSPControl = arg1;
 }
 
 /* MIPS MT functions */
@@ -1568,14 +1909,36 @@ target_ulong helper_emt(void)
 
 target_ulong helper_dvpe(void)
 {
-    // TODO
-    return 0;
+    CPUState *other_cpu = first_cpu;
+    target_ulong prev = env->mvp->CP0_MVPControl;
+
+    do {
+        /* Turn off all VPEs except the one executing the dvpe.  */
+        if (other_cpu != env) {
+            other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
+            mips_vpe_sleep(other_cpu);
+        }
+        other_cpu = other_cpu->next_cpu;
+    } while (other_cpu);
+    return prev;
 }
 
 target_ulong helper_evpe(void)
 {
-    // TODO
-    return 0;
+    CPUState *other_cpu = first_cpu;
+    target_ulong prev = env->mvp->CP0_MVPControl;
+
+    do {
+        if (other_cpu != env
+           /* If the VPE is WFI, dont distrub it's sleep.  */
+           && !mips_vpe_is_wfi(other_cpu)) {
+            /* Enable the VPE.  */
+            other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
+            mips_vpe_wake(other_cpu); /* And wake it up.  */
+        }
+        other_cpu = other_cpu->next_cpu;
+    } while (other_cpu);
+    return prev;
 }
 #endif /* !CONFIG_USER_ONLY */
 
@@ -1923,6 +2286,7 @@ void helper_pmon (int function)
 void helper_wait (void)
 {
     env->halted = 1;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
     helper_raise_exception(EXCP_HLT);
 }
 
@@ -1952,18 +2316,17 @@ static void do_unaligned_access (target_ulong addr, int is_write, int is_user, v
     helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
 }
 
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         if (retaddr) {
             /* now we have a real cpu fault */
@@ -1972,7 +2335,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);
@@ -1980,9 +2343,11 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     env = saved_env;
 }
 
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int unused, int size)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int unused, int size)
 {
+    env = env1;
+
     if (is_exec)
         helper_raise_exception(EXCP_IBE);
     else
@@ -2077,22 +2442,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)
@@ -2282,6 +2652,7 @@ uint64_t helper_float_roundl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2295,6 +2666,7 @@ uint64_t helper_float_roundl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2308,6 +2680,7 @@ uint32_t helper_float_roundw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2321,6 +2694,7 @@ uint32_t helper_float_roundw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2334,6 +2708,7 @@ uint64_t helper_float_truncl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2345,6 +2720,7 @@ uint64_t helper_float_truncl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2356,6 +2732,7 @@ uint32_t helper_float_truncw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2367,6 +2744,7 @@ uint32_t helper_float_truncw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2378,6 +2756,7 @@ uint64_t helper_float_ceill_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2391,6 +2770,7 @@ uint64_t helper_float_ceill_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2404,6 +2784,7 @@ uint32_t helper_float_ceilw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2417,6 +2798,7 @@ uint32_t helper_float_ceilw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2430,6 +2812,7 @@ uint64_t helper_float_floorl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2443,6 +2826,7 @@ uint64_t helper_float_floorl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2456,6 +2840,7 @@ uint32_t helper_float_floorw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2469,6 +2854,7 @@ uint32_t helper_float_floorw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2853,7 +3239,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);                      \
@@ -2863,6 +3251,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;                                                  \
@@ -2873,45 +3262,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);                      \
@@ -2921,6 +3298,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;                                                  \
@@ -2931,51 +3309,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);                       \
@@ -2988,13 +3354,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);                       \
@@ -3007,38 +3374,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..d5b1c765fb9d701662baa7b178afb1fa95e198d3 100644 (file)
@@ -27,7 +27,6 @@
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-common.h"
@@ -2686,7 +2685,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) {
@@ -5538,6 +5537,19 @@ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd,
         tcg_gen_movi_tl(t0, -1);
     else if (u == 0) {
         switch (rt) {
+        case 1:
+            switch (sel) {
+            case 1:
+                gen_helper_mftc0_vpecontrol(t0);
+                break;
+            case 2:
+                gen_helper_mftc0_vpeconf0(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
         case 2:
             switch (sel) {
             case 1:
@@ -5584,6 +5596,46 @@ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd,
                 gen_mfc0(env, ctx, t0, rt, sel);
                 break;
             }
+        case 13:
+            switch (sel) {
+            case 0:
+                gen_helper_mftc0_cause(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
+        case 14:
+            switch (sel) {
+            case 0:
+                gen_helper_mftc0_epc(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
+        case 15:
+            switch (sel) {
+            case 1:
+                gen_helper_mftc0_ebase(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
+        case 16:
+            switch (sel) {
+            case 0 ... 7:
+                gen_helper_mftc0_configx(t0, tcg_const_tl(sel));
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
         case 23:
             switch (sel) {
             case 0:
@@ -5703,6 +5755,19 @@ static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt,
         /* NOP */ ;
     else if (u == 0) {
         switch (rd) {
+        case 1:
+            switch (sel) {
+            case 1:
+                gen_helper_mttc0_vpecontrol(t0);
+                break;
+            case 2:
+                gen_helper_mttc0_vpeconf0(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
         case 2:
             switch (sel) {
             case 1:
@@ -5749,6 +5814,26 @@ static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt,
                 gen_mtc0(env, ctx, t0, rd, sel);
                 break;
             }
+        case 13:
+            switch (sel) {
+            case 0:
+                gen_helper_mttc0_cause(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
+        case 15:
+            switch (sel) {
+            case 1:
+                gen_helper_mttc0_ebase(t0);
+                break;
+            default:
+                goto die;
+                break;
+            }
+            break;
         case 23:
             switch (sel) {
             case 0:
@@ -12619,7 +12704,7 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
     def = cpu_mips_find_by_name(cpu_model);
     if (!def)
         return NULL;
-    env = qemu_mallocz(sizeof(CPUMIPSState));
+    env = g_malloc0(sizeof(CPUMIPSState));
     env->cpu_model = def;
     env->cpu_model_str = cpu_model;
 
@@ -12728,6 +12813,32 @@ void cpu_reset (CPUMIPSState *env)
     /* Count register increments in debug mode, EJTAG version 1 */
     env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
     env->hflags = MIPS_HFLAG_CP0;
+
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        int i;
+
+        /* Only TC0 on VPE 0 starts as active.  */
+        for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
+            env->tcs[i].CP0_TCBind = env->cpu_index << CP0TCBd_CurVPE;
+            env->tcs[i].CP0_TCHalt = 1;
+        }
+        env->active_tc.CP0_TCHalt = 1;
+        env->halted = 1;
+
+        if (!env->cpu_index) {
+            /* VPE0 starts up enabled.  */
+            env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
+            env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+
+            /* TC0 starts up unhalted.  */
+            env->halted = 0;
+            env->active_tc.CP0_TCHalt = 0;
+            env->tcs[0].CP0_TCHalt = 0;
+            /* With thread 0 active.  */
+            env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
+            env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
+        }
+    }
 #endif
 #if defined(TARGET_MIPS64)
     if (env->cpu_model->insn_flags & ISA_MIPS3) {
@@ -12737,8 +12848,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 590e092a1dbb453cdd34a3b1e7f3862cffc2c2b9..c39138f3c53467156f9bb8716b6ae47cc81f340e 100644 (file)
@@ -38,7 +38,7 @@
 ((1 << CP0C2_M))
 
 /* No config4, no DSP ASE, no large physaddr (PABITS),
-   no external interrupt controller, no vectored interupts,
+   no external interrupt controller, no vectored interrupts,
    no 1kb pages, no SmartMIPS ASE, no trace logic */
 #define MIPS_CONFIG3                                              \
 ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) |          \
@@ -274,7 +274,7 @@ static const mips_def_t mips_defs[] =
                        (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
                        (1 << CP0C1_CA),
         .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT),
+        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_VInt) | (1 << CP0C3_MT),
         .CP0_LLAddr_rw_bitmask = 0,
         .CP0_LLAddr_shift = 0,
         .SYNCI_Step = 32,
@@ -477,7 +477,7 @@ static const mips_def_t mips_defs[] =
       .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
       .SYNCI_Step = 16,
       .CCRes = 2,
-      .CP0_Status_rw_bitmask = 0xF5D0FF1F,   /*bit5:7 not writeable*/
+      .CP0_Status_rw_bitmask = 0xF5D0FF1F,   /*bit5:7 not writable*/
       .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
       .SEGBITS = 40,
       .PABITS = 40,
@@ -535,7 +535,7 @@ static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def)
 
 static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
 {
-    env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext));
+    env->tlb = g_malloc0(sizeof(CPUMIPSTLBContext));
 
     switch (def->mmu_type) {
         case MMU_TYPE_NONE:
@@ -568,7 +568,7 @@ static void fpu_init (CPUMIPSState *env, const mips_def_t *def)
 
 static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
 {
-    env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext));
+    env->mvp = g_malloc0(sizeof(CPUMIPSMVPContext));
 
     /* MVPConf1 implemented, TLB sharable, no gating storage support,
        programmable cache partitioning implemented, number of allocatable
@@ -580,7 +580,7 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
 //                             (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) |
 //                             (0x04 << CP0MVPC0_PTC);
                              (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) |
-                             (0x04 << CP0MVPC0_PTC);
+                             (0x00 << CP0MVPC0_PTC);
 #if !defined(CONFIG_USER_ONLY)
     /* Usermode has no TLB support */
     env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE);
index 32e7ffa49323a68cc8f77458f89f568b02461998..c8e9018bfcd79f4c5fdd28c9f7acc56e14ade46e 100644 (file)
@@ -11,7 +11,7 @@ INSN: instruction set.
 SPR:  special purpose registers set
       OK => all SPR registered (but some may be fake)
       KO => some SPR are missing or should be removed
-      ?  => uncheked
+      ?  => unchecked
 MSR:  MSR bits definitions
       OK => all MSR bits properly defined
       KO => MSR definition is incorrect
index deb8d7c9c50c7832fb2ac63d71681929f4b05800..e84108c49a1a2bbbb3f81d4c6c96fa35a552bc15 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
@@ -64,7 +66,7 @@
 #define TARGET_PAGE_BITS 12
 #endif /* defined(TARGET_PPCEMB) */
 
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 
 #endif /* defined (TARGET_PPC64) */
@@ -73,8 +75,6 @@
 
 #include "cpu-defs.h"
 
-#include <setjmp.h>
-
 #include "softfloat.h"
 
 #define TARGET_HAS_ICE 1
@@ -106,16 +106,19 @@ enum powerpc_mmu_t {
     POWERPC_MMU_MPC8xx     = 0x00000007,
     /* BookE MMU model                                         */
     POWERPC_MMU_BOOKE      = 0x00000008,
-    /* BookE FSL MMU model                                     */
-    POWERPC_MMU_BOOKE_FSL  = 0x00000009,
+    /* BookE 2.06 MMU model                                    */
+    POWERPC_MMU_BOOKE206   = 0x00000009,
     /* PowerPC 601 MMU model (specific BATs format)            */
     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 +154,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) */
 };
 
@@ -218,7 +223,7 @@ enum {
     /* 970FX specific exceptions                                             */
     POWERPC_EXCP_SOFTP    = 88, /* Soft patch exception                      */
     POWERPC_EXCP_MAINT    = 89, /* Maintenance exception                     */
-    /* Freescale embeded cores specific exceptions                           */
+    /* Freescale embedded cores specific exceptions                          */
     POWERPC_EXCP_MEXTBR   = 90, /* Maskable external breakpoint              */
     POWERPC_EXCP_NMEXTBR  = 91, /* Non maskable external breakpoint          */
     POWERPC_EXCP_ITLBE    = 92, /* Instruction TLB error                     */
@@ -286,6 +291,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               */
@@ -351,18 +358,71 @@ struct ppcemb_tlb_t {
     uint32_t attr; /* Storage attributes */
 };
 
+typedef struct ppcmas_tlb_t {
+     uint32_t mas8;
+     uint32_t mas1;
+     uint64_t mas2;
+     uint64_t mas7_3;
+} ppcmas_tlb_t;
+
 union ppc_tlb_t {
-    ppc6xx_tlb_t tlb6;
-    ppcemb_tlb_t tlbe;
+    ppc6xx_tlb_t *tlb6;
+    ppcemb_tlb_t *tlbe;
+    ppcmas_tlb_t *tlbm;
 };
+
+/* possible TLB variants */
+#define TLB_NONE               0
+#define TLB_6XX                1
+#define TLB_EMB                2
+#define TLB_MAS                3
 #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 */
@@ -372,6 +432,7 @@ struct ppc_slb_t {
 #define MSR_CM   31 /* Computation mode for BookE                     hflags */
 #define MSR_ICM  30 /* Interrupt computation mode for BookE                  */
 #define MSR_THV  29 /* hypervisor state for 32 bits PowerPC           hflags */
+#define MSR_GS   28 /* guest state for BookE                                 */
 #define MSR_UCLE 26 /* User-mode cache lock enable for BookE                 */
 #define MSR_VR   25 /* altivec available                            x hflags */
 #define MSR_SPE  25 /* SPE enable for BookE                         x hflags */
@@ -409,6 +470,7 @@ struct ppc_slb_t {
 #define msr_cm   ((env->msr >> MSR_CM)   & 1)
 #define msr_icm  ((env->msr >> MSR_ICM)  & 1)
 #define msr_thv  ((env->msr >> MSR_THV)  & 1)
+#define msr_gs   ((env->msr >> MSR_GS)   & 1)
 #define msr_ucle ((env->msr >> MSR_UCLE) & 1)
 #define msr_vr   ((env->msr >> MSR_VR)   & 1)
 #define msr_spe  ((env->msr >> MSR_SPE)  & 1)
@@ -454,7 +516,22 @@ struct ppc_slb_t {
 #endif
 
 /* Exception state register bits definition                                  */
-#define ESR_ST    23    /* Exception was caused by a store type access.      */
+#define ESR_PIL   (1 << (63 - 36)) /* Illegal Instruction                    */
+#define ESR_PPR   (1 << (63 - 37)) /* Privileged Instruction                 */
+#define ESR_PTR   (1 << (63 - 38)) /* Trap                                   */
+#define ESR_FP    (1 << (63 - 39)) /* Floating-Point Operation               */
+#define ESR_ST    (1 << (63 - 40)) /* Store Operation                        */
+#define ESR_AP    (1 << (63 - 44)) /* Auxiliary Processor Operation          */
+#define ESR_PUO   (1 << (63 - 45)) /* Unimplemented Operation                */
+#define ESR_BO    (1 << (63 - 46)) /* Byte Ordering                          */
+#define ESR_PIE   (1 << (63 - 47)) /* Imprecise exception                    */
+#define ESR_DATA  (1 << (63 - 53)) /* Data Access (Embedded page table)      */
+#define ESR_TLBI  (1 << (63 - 54)) /* TLB Ineligible (Embedded page table)   */
+#define ESR_PT    (1 << (63 - 55)) /* Page Table (Embedded page table)       */
+#define ESR_SPV   (1 << (63 - 56)) /* SPE/VMX operation                      */
+#define ESR_EPID  (1 << (63 - 57)) /* External Process ID operation          */
+#define ESR_VLEMI (1 << (63 - 58)) /* VLE operation                          */
+#define ESR_MIF   (1 << (63 - 62)) /* Misaligned instruction (VLE)           */
 
 enum {
     POWERPC_FLAG_NONE     = 0x00000000,
@@ -478,6 +555,8 @@ enum {
     /* Decrementer clock: RTC clock (POWER, 601) or bus clock                */
     POWERPC_FLAG_RTC_CLK  = 0x00010000,
     POWERPC_FLAG_BUS_CLK  = 0x00020000,
+    /* Has CFAR                                                              */
+    POWERPC_FLAG_CFAR     = 0x00040000,
 };
 
 /*****************************************************************************/
@@ -557,10 +636,244 @@ enum {
 #define vscr_nj                (((env->vscr) >> VSCR_NJ)       & 0x1)
 #define vscr_sat       (((env->vscr) >> VSCR_SAT)      & 0x1)
 
+/*****************************************************************************/
+/* BookE e500 MMU registers */
+
+#define MAS0_NV_SHIFT      0
+#define MAS0_NV_MASK       (0xfff << MAS0_NV_SHIFT)
+
+#define MAS0_WQ_SHIFT      12
+#define MAS0_WQ_MASK       (3 << MAS0_WQ_SHIFT)
+/* Write TLB entry regardless of reservation */
+#define MAS0_WQ_ALWAYS     (0 << MAS0_WQ_SHIFT)
+/* Write TLB entry only already in use */
+#define MAS0_WQ_COND       (1 << MAS0_WQ_SHIFT)
+/* Clear TLB entry */
+#define MAS0_WQ_CLR_RSRV   (2 << MAS0_WQ_SHIFT)
+
+#define MAS0_HES_SHIFT     14
+#define MAS0_HES           (1 << MAS0_HES_SHIFT)
+
+#define MAS0_ESEL_SHIFT    16
+#define MAS0_ESEL_MASK     (0xfff << MAS0_ESEL_SHIFT)
+
+#define MAS0_TLBSEL_SHIFT  28
+#define MAS0_TLBSEL_MASK   (3 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB0   (0 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB1   (1 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB2   (2 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB3   (3 << MAS0_TLBSEL_SHIFT)
+
+#define MAS0_ATSEL_SHIFT   31
+#define MAS0_ATSEL         (1 << MAS0_ATSEL_SHIFT)
+#define MAS0_ATSEL_TLB     0
+#define MAS0_ATSEL_LRAT    MAS0_ATSEL
+
+#define MAS1_TSIZE_SHIFT   7
+#define MAS1_TSIZE_MASK    (0x1f << MAS1_TSIZE_SHIFT)
+
+#define MAS1_TS_SHIFT      12
+#define MAS1_TS            (1 << MAS1_TS_SHIFT)
+
+#define MAS1_IND_SHIFT     13
+#define MAS1_IND           (1 << MAS1_IND_SHIFT)
+
+#define MAS1_TID_SHIFT     16
+#define MAS1_TID_MASK      (0x3fff << MAS1_TID_SHIFT)
+
+#define MAS1_IPROT_SHIFT   30
+#define MAS1_IPROT         (1 << MAS1_IPROT_SHIFT)
+
+#define MAS1_VALID_SHIFT   31
+#define MAS1_VALID         0x80000000
+
+#define MAS2_EPN_SHIFT     12
+#define MAS2_EPN_MASK      (0xfffff << MAS2_EPN_SHIFT)
+
+#define MAS2_ACM_SHIFT     6
+#define MAS2_ACM           (1 << MAS2_ACM_SHIFT)
+
+#define MAS2_VLE_SHIFT     5
+#define MAS2_VLE           (1 << MAS2_VLE_SHIFT)
+
+#define MAS2_W_SHIFT       4
+#define MAS2_W             (1 << MAS2_W_SHIFT)
+
+#define MAS2_I_SHIFT       3
+#define MAS2_I             (1 << MAS2_I_SHIFT)
+
+#define MAS2_M_SHIFT       2
+#define MAS2_M             (1 << MAS2_M_SHIFT)
+
+#define MAS2_G_SHIFT       1
+#define MAS2_G             (1 << MAS2_G_SHIFT)
+
+#define MAS2_E_SHIFT       0
+#define MAS2_E             (1 << MAS2_E_SHIFT)
+
+#define MAS3_RPN_SHIFT     12
+#define MAS3_RPN_MASK      (0xfffff << MAS3_RPN_SHIFT)
+
+#define MAS3_U0                 0x00000200
+#define MAS3_U1                 0x00000100
+#define MAS3_U2                 0x00000080
+#define MAS3_U3                 0x00000040
+#define MAS3_UX                 0x00000020
+#define MAS3_SX                 0x00000010
+#define MAS3_UW                 0x00000008
+#define MAS3_SW                 0x00000004
+#define MAS3_UR                 0x00000002
+#define MAS3_SR                 0x00000001
+#define MAS3_SPSIZE_SHIFT       1
+#define MAS3_SPSIZE_MASK        (0x3e << MAS3_SPSIZE_SHIFT)
+
+#define MAS4_TLBSELD_SHIFT      MAS0_TLBSEL_SHIFT
+#define MAS4_TLBSELD_MASK       MAS0_TLBSEL_MASK
+#define MAS4_TIDSELD_MASK       0x00030000
+#define MAS4_TIDSELD_PID0       0x00000000
+#define MAS4_TIDSELD_PID1       0x00010000
+#define MAS4_TIDSELD_PID2       0x00020000
+#define MAS4_TIDSELD_PIDZ       0x00030000
+#define MAS4_INDD               0x00008000      /* Default IND */
+#define MAS4_TSIZED_SHIFT       MAS1_TSIZE_SHIFT
+#define MAS4_TSIZED_MASK        MAS1_TSIZE_MASK
+#define MAS4_ACMD               0x00000040
+#define MAS4_VLED               0x00000020
+#define MAS4_WD                 0x00000010
+#define MAS4_ID                 0x00000008
+#define MAS4_MD                 0x00000004
+#define MAS4_GD                 0x00000002
+#define MAS4_ED                 0x00000001
+#define MAS4_WIMGED_MASK        0x0000001f      /* Default WIMGE */
+#define MAS4_WIMGED_SHIFT       0
+
+#define MAS5_SGS                0x80000000
+#define MAS5_SLPID_MASK         0x00000fff
+
+#define MAS6_SPID0              0x3fff0000
+#define MAS6_SPID1              0x00007ffe
+#define MAS6_ISIZE(x)           MAS1_TSIZE(x)
+#define MAS6_SAS                0x00000001
+#define MAS6_SPID               MAS6_SPID0
+#define MAS6_SIND               0x00000002      /* Indirect page */
+#define MAS6_SIND_SHIFT         1
+#define MAS6_SPID_MASK          0x3fff0000
+#define MAS6_SPID_SHIFT         16
+#define MAS6_ISIZE_MASK         0x00000f80
+#define MAS6_ISIZE_SHIFT        7
+
+#define MAS7_RPN                0xffffffff
+
+#define MAS8_TGS                0x80000000
+#define MAS8_VF                 0x40000000
+#define MAS8_TLBPID             0x00000fff
+
+/* Bit definitions for MMUCFG */
+#define MMUCFG_MAVN     0x00000003      /* MMU Architecture Version Number */
+#define MMUCFG_MAVN_V1  0x00000000      /* v1.0 */
+#define MMUCFG_MAVN_V2  0x00000001      /* v2.0 */
+#define MMUCFG_NTLBS    0x0000000c      /* Number of TLBs */
+#define MMUCFG_PIDSIZE  0x000007c0      /* PID Reg Size */
+#define MMUCFG_TWC      0x00008000      /* TLB Write Conditional (v2.0) */
+#define MMUCFG_LRAT     0x00010000      /* LRAT Supported (v2.0) */
+#define MMUCFG_RASIZE   0x00fe0000      /* Real Addr Size */
+#define MMUCFG_LPIDSIZE 0x0f000000      /* LPID Reg Size */
+
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI  0x00000002      /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI  0x00000004      /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI  0x00000040      /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI  0x00000020      /* TLB3 Flash invalidate */
+#define MMUCSR0_TLBFI   (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+                         MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+#define MMUCSR0_TLB0PS  0x00000780      /* TLB0 Page Size */
+#define MMUCSR0_TLB1PS  0x00007800      /* TLB1 Page Size */
+#define MMUCSR0_TLB2PS  0x00078000      /* TLB2 Page Size */
+#define MMUCSR0_TLB3PS  0x00780000      /* TLB3 Page Size */
+
+/* TLBnCFG encoding */
+#define TLBnCFG_N_ENTRY         0x00000fff      /* number of entries */
+#define TLBnCFG_HES             0x00002000      /* HW select supported */
+#define TLBnCFG_AVAIL           0x00004000      /* variable page size */
+#define TLBnCFG_IPROT           0x00008000      /* IPROT supported */
+#define TLBnCFG_GTWE            0x00010000      /* Guest can write */
+#define TLBnCFG_IND             0x00020000      /* IND entries supported */
+#define TLBnCFG_PT              0x00040000      /* Can load from page table */
+#define TLBnCFG_MINSIZE         0x00f00000      /* Minimum Page Size (v1.0) */
+#define TLBnCFG_MINSIZE_SHIFT   20
+#define TLBnCFG_MAXSIZE         0x000f0000      /* Maximum Page Size (v1.0) */
+#define TLBnCFG_MAXSIZE_SHIFT   16
+#define TLBnCFG_ASSOC           0xff000000      /* Associativity */
+#define TLBnCFG_ASSOC_SHIFT     24
+
+/* TLBnPS encoding */
+#define TLBnPS_4K               0x00000004
+#define TLBnPS_8K               0x00000008
+#define TLBnPS_16K              0x00000010
+#define TLBnPS_32K              0x00000020
+#define TLBnPS_64K              0x00000040
+#define TLBnPS_128K             0x00000080
+#define TLBnPS_256K             0x00000100
+#define TLBnPS_512K             0x00000200
+#define TLBnPS_1M               0x00000400
+#define TLBnPS_2M               0x00000800
+#define TLBnPS_4M               0x00001000
+#define TLBnPS_8M               0x00002000
+#define TLBnPS_16M              0x00004000
+#define TLBnPS_32M              0x00008000
+#define TLBnPS_64M              0x00010000
+#define TLBnPS_128M             0x00020000
+#define TLBnPS_256M             0x00040000
+#define TLBnPS_512M             0x00080000
+#define TLBnPS_1G               0x00100000
+#define TLBnPS_2G               0x00200000
+#define TLBnPS_4G               0x00400000
+#define TLBnPS_8G               0x00800000
+#define TLBnPS_16G              0x01000000
+#define TLBnPS_32G              0x02000000
+#define TLBnPS_64G              0x04000000
+#define TLBnPS_128G             0x08000000
+#define TLBnPS_256G             0x10000000
+
+/* tlbilx action encoding */
+#define TLBILX_T_ALL                    0
+#define TLBILX_T_TID                    1
+#define TLBILX_T_FULLMATCH              3
+#define TLBILX_T_CLASS0                 4
+#define TLBILX_T_CLASS1                 5
+#define TLBILX_T_CLASS2                 6
+#define TLBILX_T_CLASS3                 7
+
+/* BookE 2.06 helper defines */
+
+#define BOOKE206_FLUSH_TLB0    (1 << 0)
+#define BOOKE206_FLUSH_TLB1    (1 << 1)
+#define BOOKE206_FLUSH_TLB2    (1 << 2)
+#define BOOKE206_FLUSH_TLB3    (1 << 3)
+
+/* number of possible TLBs */
+#define BOOKE206_MAX_TLBN      4
+
 /*****************************************************************************/
 /* The whole PowerPC CPU context */
 #define NB_MMU_MODES 3
 
+struct ppc_def_t {
+    const char *name;
+    uint32_t pvr;
+    uint32_t svr;
+    uint64_t insns_flags;
+    uint64_t insns_flags2;
+    uint64_t msr_mask;
+    powerpc_mmu_t   mmu_model;
+    powerpc_excp_t  excp_model;
+    powerpc_input_t bus_model;
+    uint32_t flags;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
+    int  (*check_pow)(CPUPPCState *env);
+};
+
 struct CPUPPCState {
     /* First are the most commonly used resources
      * during translated code execution
@@ -577,6 +890,10 @@ struct CPUPPCState {
     target_ulong ctr;
     /* condition register */
     uint32_t crf[8];
+#if defined(TARGET_PPC64)
+    /* CFAR */
+    target_ulong cfar;
+#endif
     /* XER */
     target_ulong xer;
     /* Reservation address */
@@ -619,22 +936,28 @@ 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];
     target_ulong IBAT[2][8];
-    /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
+    /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
     int nb_tlb;      /* Total number of TLB                                  */
     int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
     int nb_ways;     /* Number of ways in the TLB set                        */
     int last_way;    /* Last used way used to allocate TLB in a LRU way      */
     int id_tlbs;     /* If 1, MMU has separated TLBs for instructions & data */
     int nb_pids;     /* Number of available PID registers                    */
-    ppc_tlb_t *tlb;  /* TLB is optional. Allocate them only if needed        */
+    int tlb_type;    /* Type of TLB we're dealing with                       */
+    ppc_tlb_t tlb;   /* TLB is optional. Allocate them only if needed        */
     /* 403 dedicated access protection registers */
     target_ulong pb[4];
+    bool tlb_dirty;   /* Set to non-zero when modifying TLB                  */
+    bool kvm_sw_tlb;  /* non-zero if KVM SW TLB API is active                */
 #endif
 
     /* Other registers */
@@ -669,6 +992,14 @@ struct CPUPPCState {
     int bfd_mach;
     uint32_t flags;
     uint64_t insns_flags;
+    uint64_t insns_flags2;
+
+#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;
@@ -703,8 +1034,35 @@ struct CPUPPCState {
 #if !defined(CONFIG_USER_ONLY)
     void *load_info;    /* Holds boot loading state.  */
 #endif
+
+    /* booke timers */
+
+    /* Specifies bit locations of the Time Base used to signal a fixed timer
+     * exception on a transition from 0 to 1. (watchdog or fixed-interval timer)
+     *
+     * 0 selects the least significant bit.
+     * 63 selects the most significant bit.
+     */
+    uint8_t fit_period[4];
+    uint8_t wdt_period[4];
 };
 
+#define SET_FIT_PERIOD(a_, b_, c_, d_)          \
+do {                                            \
+    env->fit_period[0] = (a_);                  \
+    env->fit_period[1] = (b_);                  \
+    env->fit_period[2] = (c_);                  \
+    env->fit_period[3] = (d_);                  \
+ } while (0)
+
+#define SET_WDT_PERIOD(a_, b_, c_, d_)          \
+do {                                            \
+    env->wdt_period[0] = (a_);                  \
+    env->wdt_period[1] = (b_);                  \
+    env->wdt_period[2] = (c_);                  \
+    env->wdt_period[3] = (d_);                  \
+ } while (0)
+
 #if !defined(CONFIG_USER_ONLY)
 /* Context used internally during MMU translations */
 typedef struct mmu_ctx_t mmu_ctx_t;
@@ -712,7 +1070,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          */
@@ -730,7 +1088,7 @@ void cpu_ppc_close (CPUPPCState *s);
 int cpu_ppc_signal_handler (int host_signum, void *pinfo,
                             void *puc);
 int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
 #if !defined(CONFIG_USER_ONLY)
 int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong vaddr,
@@ -755,7 +1113,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) */
@@ -763,6 +1123,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 
+const ppc_def_t *ppc_find_by_pvr(uint32_t pvr);
 const ppc_def_t *cpu_ppc_find_by_name (const char *name);
 int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
 
@@ -793,6 +1154,14 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
 void store_40x_sler (CPUPPCState *env, uint32_t val);
 void store_booke_tcr (CPUPPCState *env, target_ulong val);
 void store_booke_tsr (CPUPPCState *env, target_ulong val);
+void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot);
+target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb);
+int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
+                     target_phys_addr_t *raddrp, target_ulong address,
+                     uint32_t pid, int ext, int i);
+int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                     target_phys_addr_t *raddrp, target_ulong address,
+                     uint32_t pid);
 void ppc_tlb_invalidate_all (CPUPPCState *env);
 void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
 #if defined(TARGET_PPC64)
@@ -885,6 +1254,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_601_UDECR         (0x006)
 #define SPR_LR                (0x008)
 #define SPR_CTR               (0x009)
+#define SPR_DSCR              (0x011)
 #define SPR_DSISR             (0x012)
 #define SPR_DAR               (0x013) /* DAE for PowerPC 601 */
 #define SPR_601_RTCU          (0x014)
@@ -893,6 +1263,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_SDR1              (0x019)
 #define SPR_SRR0              (0x01A)
 #define SPR_SRR1              (0x01B)
+#define SPR_CFAR              (0x01C)
 #define SPR_AMR               (0x01D)
 #define SPR_BOOKE_PID         (0x030)
 #define SPR_BOOKE_DECAR       (0x036)
@@ -956,6 +1327,8 @@ 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_BOOKE_EPCR        (0x133)
+#define SPR_SPURR             (0x134)
 #define SPR_BOOKE_DBCR0       (0x134)
 #define SPR_IBCR              (0x135)
 #define SPR_PURR              (0x135)
@@ -1480,6 +1853,43 @@ enum {
     PPC_DCRX           = 0x2000000000000000ULL,
     /* user-mode DCR access, implemented in PowerPC 460                      */
     PPC_DCRUX          = 0x4000000000000000ULL,
+    /* popcntw and popcntd instructions                                      */
+    PPC_POPCNTWD       = 0x8000000000000000ULL,
+
+#define PPC_TCG_INSNS  (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
+                        | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
+                        | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
+                        | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \
+                        | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
+                        | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \
+                        | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \
+                        | PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX \
+                        | PPC_ALTIVEC | PPC_SPE | PPC_SPE_SINGLE \
+                        | PPC_SPE_DOUBLE | PPC_MEM_TLBIA \
+                        | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC \
+                        | PPC_MEM_SYNC | PPC_MEM_EIEIO \
+                        | PPC_CACHE | PPC_CACHE_ICBI \
+                        | PPC_CACHE_DCBZ | PPC_CACHE_DCBZT \
+                        | PPC_CACHE_DCBA | PPC_CACHE_LOCK \
+                        | PPC_EXTERN | PPC_SEGMENT | PPC_6xx_TLB \
+                        | PPC_74xx_TLB | PPC_40x_TLB | PPC_SEGMENT_64B \
+                        | PPC_SLBI | PPC_WRTEE | PPC_40x_EXCP \
+                        | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \
+                        | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \
+                        | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \
+                        | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \
+                        | PPC_POPCNTWD)
+
+    /* extended type values */
+
+    /* BookE 2.06 PowerPC specification                                      */
+    PPC2_BOOKE206      = 0x0000000000000001ULL,
+    /* VSX (extensions to Altivec / VMX)                                     */
+    PPC2_VSX           = 0x0000000000000002ULL,
+    /* Decimal Floating Point (DFP)                                          */
+    PPC2_DFP           = 0x0000000000000004ULL,
+
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206)
 };
 
 /*****************************************************************************/
@@ -1578,6 +1988,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 +2042,91 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
 #endif
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm)
+{
+    uintptr_t tlbml = (uintptr_t)tlbm;
+    uintptr_t tlbl = (uintptr_t)env->tlb.tlbm;
+
+    return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]);
+}
+
+static inline int booke206_tlb_size(CPUState *env, int tlbn)
+{
+    uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+    int r = tlbncfg & TLBnCFG_N_ENTRY;
+    return r;
+}
+
+static inline int booke206_tlb_ways(CPUState *env, int tlbn)
+{
+    uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+    int r = tlbncfg >> TLBnCFG_ASSOC_SHIFT;
+    return r;
+}
+
+static inline int booke206_tlbm_to_tlbn(CPUState *env, ppcmas_tlb_t *tlbm)
+{
+    int id = booke206_tlbm_id(env, tlbm);
+    int end = 0;
+    int i;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        end += booke206_tlb_size(env, i);
+        if (id < end) {
+            return i;
+        }
+    }
+
+    cpu_abort(env, "Unknown TLBe: %d\n", id);
+    return 0;
+}
+
+static inline int booke206_tlbm_to_way(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    int tlbid = booke206_tlbm_id(env, tlb);
+    return tlbid & (booke206_tlb_ways(env, tlbn) - 1);
+}
+
+static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
+                                              target_ulong ea, int way)
+{
+    int r;
+    uint32_t ways = booke206_tlb_ways(env, tlbn);
+    int ways_bits = ffs(ways) - 1;
+    int tlb_bits = ffs(booke206_tlb_size(env, tlbn)) - 1;
+    int i;
+
+    way &= ways - 1;
+    ea >>= MAS2_EPN_SHIFT;
+    ea &= (1 << (tlb_bits - ways_bits)) - 1;
+    r = (ea << ways_bits) | way;
+
+    /* bump up to tlbn index */
+    for (i = 0; i < tlbn; i++) {
+        r += booke206_tlb_size(env, i);
+    }
+
+    return &env->tlb.tlbm[r];
+}
+
+#endif
+
+extern void (*cpu_ppc_hypercall)(CPUState *);
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->nip = tb->pc;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
+
 #endif /* !defined (__CPU_PPC_H__) */
index 4b491012d726cede9bd49ae5d267d0fbc1dcc459..137a494201ba4ffa2dcfc0901f5fa09813c2fe60 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
-#include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "helper_regs.h"
 #include "qemu-common.h"
 #include "kvm.h"
+#include "kvm_ppc.h"
+#include "cpus.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_BATS
 #  define LOG_EXCP(...) do { } while (0)
 #endif
 
+/*****************************************************************************/
+/* PowerPC Hypercall emulation */
+
+void (*cpu_ppc_hypercall)(CPUState *);
 
 /*****************************************************************************/
 /* PowerPC MMU emulation */
 
 #if defined(CONFIG_USER_ONLY)
 int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     int exception, error_code;
 
@@ -320,7 +324,7 @@ static inline void ppc6xx_tlb_invalidate_all(CPUState *env)
     if (env->id_tlbs == 1)
         max *= 2;
     for (nr = 0; nr < max; nr++) {
-        tlb = &env->tlb[nr].tlb6;
+        tlb = &env->tlb.tlb6[nr];
         pte_invalidate(&tlb->pte0);
     }
     tlb_flush(env, 1);
@@ -337,7 +341,7 @@ static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env,
     /* Invalidate ITLB + DTLB, all ways */
     for (way = 0; way < env->nb_ways; way++) {
         nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
-        tlb = &env->tlb[nr].tlb6;
+        tlb = &env->tlb.tlb6[nr];
         if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
             LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
                       env->nb_tlb, eaddr);
@@ -364,7 +368,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
     int nr;
 
     nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
-    tlb = &env->tlb[nr].tlb6;
+    tlb = &env->tlb.tlb6[nr];
     LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
               " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
     /* Invalidate any pending reference in Qemu for this virtual address */
@@ -388,7 +392,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
     for (way = 0; way < env->nb_ways; way++) {
         nr = ppc6xx_tlb_getnum(env, eaddr, way,
                                access_type == ACCESS_CODE ? 1 : 0);
-        tlb = &env->tlb[nr].tlb6;
+        tlb = &env->tlb.tlb6[nr];
         /* This test "emulates" the PTE index match for hardware TLBs */
         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
             LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
@@ -431,7 +435,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
         LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
                   ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
         /* Update page flags */
-        pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
+        pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
     }
 
     return ret;
@@ -551,7 +555,7 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
                 BEPIl = *BATu & 0x0FFE0000;
                 bl = (*BATu & 0x00001FFC) << 15;
                 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
-                         " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " "
+                         " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
                          TARGET_FMT_lx " " TARGET_FMT_lx "\n",
                          __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
                          *BATu, *BATl, BEPIu, BEPIl, bl);
@@ -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_off + (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_off + (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)
+static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 {
-    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)
-{
-    ppc_slb_t *entry = &env->slb[nr];
-
-    if (slb == entry)
-        return;
-
-    entry->tmp64 = slb->tmp64;
-    entry->tmp = slb->tmp;
-}
+    uint64_t esid_256M, esid_1T;
+    int n;
 
-static inline int slb_is_valid(ppc_slb_t *slb)
-{
-    return (int)(slb->tmp64 & 0x0000000008000000ULL);
-}
+    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
 
-static inline void slb_invalidate(ppc_slb_t *slb)
-{
-    slb->tmp64 &= ~0x0000000008000000ULL;
-}
+    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
 
-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;
-
-    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 */
     }
-    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
-            TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
+    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
+        return -1; /* 1T segment on MMU that doesn't support it */
+    }
+
+    /* Mask out the slot number as we store the entry */
+    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
+    slb->vsid = rs;
 
-    return rt;
+    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,20 @@ 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 "\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)
@@ -999,8 +950,24 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
             ret = -3;
         }
     } else {
+        target_ulong sr;
         LOG_MMU("direct store...\n");
         /* Direct-store segment : absolutely *BUGGY* for now */
+
+        /* Direct-store implies a 32-bit MMU.
+         * Check the Segment Register's bus unit ID (BUID).
+         */
+        sr = env->sr[eaddr >> 28];
+        if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+            /* Memory-forced I/O controller interface access */
+            /* If T=1 and BUID=x'07F', the 601 performs a memory access
+             * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+             */
+            ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+            return 0;
+        }
+
         switch (type) {
         case ACCESS_INT:
             /* Integer load/store : only access allowed */
@@ -1041,10 +1008,10 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
 }
 
 /* Generic TLB check function for embedded PowerPC implementations */
-static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
-                                   target_phys_addr_t *raddrp,
-                                   target_ulong address, uint32_t pid, int ext,
-                                   int i)
+int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
+                     target_phys_addr_t *raddrp,
+                     target_ulong address, uint32_t pid, int ext,
+                     int i)
 {
     target_ulong mask;
 
@@ -1054,8 +1021,8 @@ static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
     }
     mask = ~(tlb->size - 1);
     LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
-              " " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN,
-              mask, (uint32_t)tlb->PID);
+              " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
+              mask, (uint32_t)tlb->PID, tlb->prot);
     /* Check PID */
     if (tlb->PID != 0 && tlb->PID != pid)
         return -1;
@@ -1083,7 +1050,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
     /* Default return value is no match */
     ret = -1;
     for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->tlb[i].tlbe;
+        tlb = &env->tlb.tlbe[i];
         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
             ret = i;
             break;
@@ -1100,7 +1067,7 @@ static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
     int i;
 
     for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->tlb[i].tlbe;
+        tlb = &env->tlb.tlbe[i];
         tlb->prot &= ~PAGE_VALID;
     }
     tlb_flush(env, 1);
@@ -1116,7 +1083,7 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
     int i;
 
     for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->tlb[i].tlbe;
+        tlb = &env->tlb.tlbe[i];
         if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
             end = tlb->EPN + tlb->size;
             for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
@@ -1141,7 +1108,7 @@ static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
     raddr = (target_phys_addr_t)-1ULL;
     pr = msr_pr;
     for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->tlb[i].tlbe;
+        tlb = &env->tlb.tlbe[i];
         if (ppcemb_tlb_check(env, tlb, &raddr, address,
                              env->spr[SPR_40x_PID], 0, i) < 0)
             continue;
@@ -1201,52 +1168,394 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
     env->spr[SPR_405_SLER] = val;
 }
 
+static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
+                                      target_phys_addr_t *raddr, int *prot,
+                                      target_ulong address, int rw,
+                                      int access_type, int i)
+{
+    int ret, _prot;
+
+    if (ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID],
+                         !env->nb_pids, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID1] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID2] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    LOG_SWTLB("%s: TLB entry not found\n", __func__);
+    return -1;
+
+found_tlb:
+
+    if (msr_pr != 0) {
+        _prot = tlb->prot & 0xF;
+    } else {
+        _prot = (tlb->prot >> 4) & 0xF;
+    }
+
+    /* Check the address space */
+    if (access_type == ACCESS_CODE) {
+        if (msr_ir != (tlb->attr & 1)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if (_prot & PAGE_EXEC) {
+            LOG_SWTLB("%s: good TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+        ret = -3;
+    } else {
+        if (msr_dr != (tlb->attr & 1)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+            LOG_SWTLB("%s: found TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+        ret = -2;
+    }
+
+    return ret;
+}
+
 static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                                           target_ulong address, int rw,
                                           int access_type)
 {
     ppcemb_tlb_t *tlb;
     target_phys_addr_t raddr;
-    int i, prot, ret;
+    int i, ret;
 
     ret = -1;
     raddr = (target_phys_addr_t)-1ULL;
     for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->tlb[i].tlbe;
-        if (ppcemb_tlb_check(env, tlb, &raddr, address,
-                             env->spr[SPR_BOOKE_PID], 1, i) < 0)
-            continue;
-        if (msr_pr != 0)
-            prot = tlb->prot & 0xF;
-        else
-            prot = (tlb->prot >> 4) & 0xF;
-        /* Check the address space */
-        if (access_type == ACCESS_CODE) {
-            if (msr_ir != (tlb->attr & 1))
-                continue;
-            ctx->prot = prot;
-            if (prot & PAGE_EXEC) {
-                ret = 0;
-                break;
+        tlb = &env->tlb.tlbe[i];
+        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+                                 access_type, i);
+        if (!ret) {
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
+
+    return ret;
+}
+
+void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
+{
+    int tlb_size;
+    int i, j;
+    ppcmas_tlb_t *tlb = env->tlb.tlbm;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        if (flags & (1 << i)) {
+            tlb_size = booke206_tlb_size(env, i);
+            for (j = 0; j < tlb_size; j++) {
+                if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
+                    tlb[j].mas1 &= ~MAS1_VALID;
+                }
             }
-            ret = -3;
-        } else {
-            if (msr_dr != (tlb->attr & 1))
-                continue;
-            ctx->prot = prot;
-            if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
-                ret = 0;
-                break;
+        }
+        tlb += booke206_tlb_size(env, i);
+    }
+
+    tlb_flush(env, 1);
+}
+
+target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    uint32_t tlbncfg;
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    int tlbm_size;
+
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+
+    if (tlbncfg & TLBnCFG_AVAIL) {
+        tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+    } else {
+        tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+        tlbm_size <<= 1;
+    }
+
+    return 1024ULL << tlbm_size;
+}
+
+/* TLB check function for MAS based SoftTLBs */
+int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                     target_phys_addr_t *raddrp,
+                     target_ulong address, uint32_t pid)
+{
+    target_ulong mask;
+    uint32_t tlb_pid;
+
+    /* Check valid flag */
+    if (!(tlb->mas1 & MAS1_VALID)) {
+        return -1;
+    }
+
+    mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+    LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
+              PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
+              __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
+              tlb->mas8);
+
+    /* Check PID */
+    tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
+    if (tlb_pid != 0 && tlb_pid != pid) {
+        return -1;
+    }
+
+    /* Check effective address */
+    if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
+        return -1;
+    }
+    *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+
+    return 0;
+}
+
+static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb,
+                                 target_phys_addr_t *raddr, int *prot,
+                                 target_ulong address, int rw,
+                                 int access_type)
+{
+    int ret;
+    int _prot = 0;
+
+    if (ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID]) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID1] &&
+        ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID1]) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID2] &&
+        ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID2]) >= 0) {
+        goto found_tlb;
+    }
+
+    LOG_SWTLB("%s: TLB entry not found\n", __func__);
+    return -1;
+
+found_tlb:
+
+    if (msr_pr != 0) {
+        if (tlb->mas7_3 & MAS3_UR) {
+            _prot |= PAGE_READ;
+        }
+        if (tlb->mas7_3 & MAS3_UW) {
+            _prot |= PAGE_WRITE;
+        }
+        if (tlb->mas7_3 & MAS3_UX) {
+            _prot |= PAGE_EXEC;
+        }
+    } else {
+        if (tlb->mas7_3 & MAS3_SR) {
+            _prot |= PAGE_READ;
+        }
+        if (tlb->mas7_3 & MAS3_SW) {
+            _prot |= PAGE_WRITE;
+        }
+        if (tlb->mas7_3 & MAS3_SX) {
+            _prot |= PAGE_EXEC;
+        }
+    }
+
+    /* Check the address space and permissions */
+    if (access_type == ACCESS_CODE) {
+        if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if (_prot & PAGE_EXEC) {
+            LOG_SWTLB("%s: good TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+        ret = -3;
+    } else {
+        if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+            LOG_SWTLB("%s: found TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+        ret = -2;
+    }
+
+    return ret;
+}
+
+static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
+                                            target_ulong address, int rw,
+                                            int access_type)
+{
+    ppcmas_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, j, ret;
+
+    ret = -1;
+    raddr = (target_phys_addr_t)-1ULL;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int ways = booke206_tlb_ways(env, i);
+
+        for (j = 0; j < ways; j++) {
+            tlb = booke206_get_tlbm(env, i, address, j);
+            ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
+                                        rw, access_type);
+            if (ret != -1) {
+                goto found_tlb;
             }
-            ret = -2;
         }
     }
-    if (ret >= 0)
+
+found_tlb:
+
+    if (ret >= 0) {
         ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
 
     return ret;
 }
 
+static const char *book3e_tsize_to_str[32] = {
+    "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
+    "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
+    "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
+    "1T", "2T"
+};
+
+static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
+                                     CPUState *env, int tlbn, int offset,
+                                     int tlbsize)
+{
+    ppcmas_tlb_t *entry;
+    int i;
+
+    cpu_fprintf(f, "\nTLB%d:\n", tlbn);
+    cpu_fprintf(f, "Effective          Physical           Size TID   TS SRWX URWX WIMGE U0123\n");
+
+    entry = &env->tlb.tlbm[offset];
+    for (i = 0; i < tlbsize; i++, entry++) {
+        target_phys_addr_t ea, pa, size;
+        int tsize;
+
+        if (!(entry->mas1 & MAS1_VALID)) {
+            continue;
+        }
+
+        tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+        size = 1024ULL << tsize;
+        ea = entry->mas2 & ~(size - 1);
+        pa = entry->mas7_3 & ~(size - 1);
+
+        cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
+                    (uint64_t)ea, (uint64_t)pa,
+                    book3e_tsize_to_str[tsize],
+                    (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
+                    (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
+                    entry->mas7_3 & MAS3_SR ? 'R' : '-',
+                    entry->mas7_3 & MAS3_SW ? 'W' : '-',
+                    entry->mas7_3 & MAS3_SX ? 'X' : '-',
+                    entry->mas7_3 & MAS3_UR ? 'R' : '-',
+                    entry->mas7_3 & MAS3_UW ? 'W' : '-',
+                    entry->mas7_3 & MAS3_UX ? 'X' : '-',
+                    entry->mas2 & MAS2_W ? 'W' : '-',
+                    entry->mas2 & MAS2_I ? 'I' : '-',
+                    entry->mas2 & MAS2_M ? 'M' : '-',
+                    entry->mas2 & MAS2_G ? 'G' : '-',
+                    entry->mas2 & MAS2_E ? 'E' : '-',
+                    entry->mas7_3 & MAS3_U0 ? '0' : '-',
+                    entry->mas7_3 & MAS3_U1 ? '1' : '-',
+                    entry->mas7_3 & MAS3_U2 ? '2' : '-',
+                    entry->mas7_3 & MAS3_U3 ? '3' : '-');
+    }
+}
+
+static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
+                                 CPUState *env)
+{
+    int offset = 0;
+    int i;
+
+    if (kvm_enabled() && !env->kvm_sw_tlb) {
+        cpu_fprintf(f, "Cannot access KVM TLB\n");
+        return;
+    }
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int size = booke206_tlb_size(env, i);
+
+        if (size == 0) {
+            continue;
+        }
+
+        mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
+        offset += size;
+    }
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    switch (env->mmu_model) {
+    case POWERPC_MMU_BOOKE206:
+        mmubooke206_dump_mmu(f, cpu_fprintf, env);
+        break;
+    default:
+        cpu_fprintf(f, "%s: unimplemented\n", __func__);
+    }
+}
+
 static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
                                  target_ulong eaddr, int rw)
 {
@@ -1268,6 +1577,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;
@@ -1301,9 +1611,8 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
         /* XXX: TODO */
         cpu_abort(env, "MPC8xx MMU model is not implemented\n");
         break;
-    case POWERPC_MMU_BOOKE_FSL:
-        /* XXX: TODO */
-        cpu_abort(env, "BookE FSL MMU model not implemented\n");
+    case POWERPC_MMU_BOOKE206:
+        cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
         break;
     default:
         cpu_abort(env, "Unknown or invalid MMU model\n");
@@ -1328,6 +1637,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
                IS and DS bits only affect the address space.  */
             ret = mmubooke_get_physical_address(env, ctx, eaddr,
                                                 rw, access_type);
+        } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+            ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+                                                   access_type);
         } else {
             /* No address translation.  */
             ret = check_physical(env, ctx, eaddr, rw);
@@ -1345,6 +1657,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 */
@@ -1360,14 +1673,14 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
             ret = mmubooke_get_physical_address(env, ctx, eaddr,
                                                 rw, access_type);
             break;
+        case POWERPC_MMU_BOOKE206:
+            ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+                                               access_type);
+            break;
         case POWERPC_MMU_MPC8xx:
             /* XXX: TODO */
             cpu_abort(env, "MPC8xx MMU model is not implemented\n");
             break;
-        case POWERPC_MMU_BOOKE_FSL:
-            /* XXX: TODO */
-            cpu_abort(env, "BookE FSL MMU model not implemented\n");
-            return -1;
         case POWERPC_MMU_REAL:
             cpu_abort(env, "PowerPC in real mode do not do any translation\n");
             return -1;
@@ -1394,9 +1707,49 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
     return ctx.raddr & TARGET_PAGE_MASK;
 }
 
+static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
+                                     int rw)
+{
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+    env->spr[SPR_BOOKE_MAS3] = 0;
+    env->spr[SPR_BOOKE_MAS6] = 0;
+    env->spr[SPR_BOOKE_MAS7] = 0;
+
+    /* AS */
+    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
+    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
+
+    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
+    case MAS4_TIDSELD_PID0:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID1:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID2:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
+        break;
+    }
+
+    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= booke206_tlb_ways(env, 0) - 1;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
 /* Perform address translation */
 int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     mmu_ctx_t ctx;
     int access_type;
@@ -1444,19 +1797,19 @@ 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;
                     break;
+                case POWERPC_MMU_BOOKE206:
+                    booke206_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
                 case POWERPC_MMU_BOOKE:
                     env->exception_index = POWERPC_EXCP_ITLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
                     return -1;
-                case POWERPC_MMU_BOOKE_FSL:
-                    /* XXX: TODO */
-                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
-                    return -1;
                 case POWERPC_MMU_MPC8xx:
                     /* XXX: TODO */
                     cpu_abort(env, "MPC8xx MMU model is not implemented\n");
@@ -1477,7 +1830,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 break;
             case -3:
                 /* No execute protection violation */
-                if (env->mmu_model == POWERPC_MMU_BOOKE) {
+                if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                    (env->mmu_model == POWERPC_MMU_BOOKE206)) {
                     env->spr[SPR_BOOKE_ESR] = 0x00000000;
                 }
                 env->exception_index = POWERPC_EXCP_ISI;
@@ -1520,8 +1874,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 +1907,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;
@@ -1564,15 +1921,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     /* XXX: TODO */
                     cpu_abort(env, "MPC8xx MMU model is not implemented\n");
                     break;
+                case POWERPC_MMU_BOOKE206:
+                    booke206_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
                 case POWERPC_MMU_BOOKE:
                     env->exception_index = POWERPC_EXCP_DTLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
-                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
-                    return -1;
-                case POWERPC_MMU_BOOKE_FSL:
-                    /* XXX: TODO */
-                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
+                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
                     return -1;
                 case POWERPC_MMU_REAL:
                     cpu_abort(env, "PowerPC in real mode should never raise "
@@ -1593,9 +1949,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     if (rw) {
                         env->spr[SPR_40x_ESR] |= 0x00800000;
                     }
-                } else if (env->mmu_model == POWERPC_MMU_BOOKE) {
+                } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                           (env->mmu_model == POWERPC_MMU_BOOKE206)) {
                     env->spr[SPR_BOOKE_DEAR] = address;
-                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
+                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
                 } else {
                     env->spr[SPR_DAR] = address;
                     if (rw == 1) {
@@ -1864,16 +2221,15 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
     case POWERPC_MMU_BOOKE:
         tlb_flush(env, 1);
         break;
-    case POWERPC_MMU_BOOKE_FSL:
-        /* XXX: TODO */
-        if (!kvm_enabled())
-            cpu_abort(env, "BookE MMU model is not implemented\n");
+    case POWERPC_MMU_BOOKE206:
+        booke206_flush_tlb(env, -1, 0);
         break;
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
 #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;
@@ -1910,9 +2266,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
         /* XXX: TODO */
         cpu_abort(env, "BookE MMU model is not implemented\n");
         break;
-    case POWERPC_MMU_BOOKE_FSL:
+    case POWERPC_MMU_BOOKE206:
         /* XXX: TODO */
-        cpu_abort(env, "BookE FSL MMU model is not implemented\n");
+        cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
         break;
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
@@ -1941,6 +2297,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 +2331,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);
     }
 }
@@ -2009,7 +2381,7 @@ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
         /* VSID = VSID */
         rs |= (value & 0xfffffff) << 12;
         /* flags = flags */
-        rs |= ((value >> 27) & 0xf) << 9;
+        rs |= ((value >> 27) & 0xf) << 8;
 
         ppc_store_slb(env, rb, rs);
     } else
@@ -2203,16 +2575,19 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00080000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
             break;
         case POWERPC_EXCP_PRIV:
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00040000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
             break;
         case POWERPC_EXCP_TRAP:
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00020000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
             break;
         default:
             /* Should never occur */
@@ -2228,6 +2603,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;
@@ -2271,16 +2650,19 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
         cpu_abort(env, "Debug exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_current;
     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
         /* XXX: TODO */
         cpu_abort(env, "Embedded floating point data exception "
                   "is not implemented yet !\n");
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
         /* XXX: TODO */
         cpu_abort(env, "Embedded floating point round exception "
                   "is not implemented yet !\n");
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
         /* XXX: TODO */
@@ -2610,7 +2992,8 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
     env->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 
-    if (env->mmu_model == POWERPC_MMU_BOOKE) {
+    if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+        (env->mmu_model == POWERPC_MMU_BOOKE206)) {
         /* XXX: The BookE changes address space when switching modes,
                 we should probably implement that as different MMU indexes,
                 but for the moment we do it the slow way and flush all.  */
@@ -2803,9 +3186,20 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
     if (!def)
         return NULL;
 
-    env = qemu_mallocz(sizeof(CPUPPCState));
+    env = g_malloc0(sizeof(CPUPPCState));
     cpu_exec_init(env);
-    ppc_translate_init();
+    if (tcg_enabled()) {
+        ppc_translate_init();
+    }
+    /* Adjust cpu index for SMT */
+#if !defined(CONFIG_USER_ONLY)
+    if (kvm_enabled()) {
+        int smt = kvmppc_smt_threads();
+
+        env->cpu_index = (env->cpu_index / smp_threads)*smt
+            + (env->cpu_index % smp_threads);
+    }
+#endif /* !CONFIG_USER_ONLY */
     env->cpu_model_str = cpu_model;
     cpu_ppc_register_internal(env, def);
 
@@ -2817,5 +3211,5 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
 void cpu_ppc_close (CPUPPCState *env)
 {
     /* Should also remove all opcode tables... */
-    qemu_free(env);
+    g_free(env);
 }
index 2bf9283486c8ef684947e5c2ad5751a824088555..470e42f676ea405678d3f6ba9cae70704dcea440 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
 
@@ -50,9 +51,7 @@ DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
 DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 
 DEF_HELPER_0(float_check_status, void)
-#ifdef CONFIG_SOFTFLOAT
 DEF_HELPER_0(reset_fpstatus, void)
-#endif
 DEF_HELPER_2(compute_fprf, i32, i64, i32)
 DEF_HELPER_2(store_fpscr, void, i64, i32)
 DEF_HELPER_1(fpscr_clrbit, void, i32)
@@ -333,6 +332,12 @@ DEF_HELPER_1(4xx_tlbsx, tl, tl)
 DEF_HELPER_2(440_tlbre, tl, i32, tl)
 DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
 DEF_HELPER_1(440_tlbsx, tl, tl)
+DEF_HELPER_0(booke206_tlbre, void)
+DEF_HELPER_0(booke206_tlbwe, void)
+DEF_HELPER_1(booke206_tlbsx, void, tl)
+DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbflush, void, i32)
+DEF_HELPER_2(booke_setpid, void, i32, tl)
 DEF_HELPER_1(6xx_tlbd, void, tl)
 DEF_HELPER_1(6xx_tlbi, void, tl)
 DEF_HELPER_1(74xx_tlbd, void, tl)
@@ -340,8 +345,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 +381,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 710eca1dcaefffb9957a02ed21984d6c535f4ee1..0410901b56aadab45d1080bfdecd60fc971f9a0b 100644 (file)
@@ -2,6 +2,7 @@
  * PowerPC implementation of KVM hooks
  *
  * Copyright IBM Corp. 2007
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
  *
  * Authors:
  *  Jerone Young <jyoung5@us.ibm.com>
@@ -13,6 +14,7 @@
  *
  */
 
+#include <dirent.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include "kvm_ppc.h"
 #include "cpu.h"
 #include "device_tree.h"
+#include "hw/sysbus.h"
+#include "hw/spapr.h"
+
+#include "hw/sysbus.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
 
 //#define DEBUG_KVM
 
     do { } while (0)
 #endif
 
+#define PROC_DEVTREE_CPU      "/proc/device-tree/cpus/"
+
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
 
 static int cap_interrupt_unset = false;
 static int cap_interrupt_level = false;
+static int cap_segstate;
+static int cap_booke_sregs;
+static int cap_ppc_smt;
+static int cap_ppc_rma;
+static int cap_spapr_tce;
 
 /* XXX We have a race condition where we actually have a level triggered
  *     interrupt, but the infrastructure can't expose that yet, so the guest
@@ -62,12 +77,13 @@ static void kvm_kick_env(void *env)
 
 int kvm_arch_init(KVMState *s)
 {
-#ifdef KVM_CAP_PPC_UNSET_IRQ
     cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
-#endif
-#ifdef KVM_CAP_PPC_IRQ_LEVEL
     cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
-#endif
+    cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
+    cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
+    cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
+    cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
+    cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
 
     if (!cap_interrupt_level) {
         fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
@@ -77,15 +93,98 @@ int kvm_arch_init(KVMState *s)
     return 0;
 }
 
-int kvm_arch_init_vcpu(CPUState *cenv)
+static int kvm_arch_sync_sregs(CPUState *cenv)
 {
-    int ret = 0;
     struct kvm_sregs sregs;
+    int ret;
+
+    if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
+        /* What we're really trying to say is "if we're on BookE, we use
+           the native PVR for now". This is the only sane way to check
+           it though, so we potentially confuse users that they can run
+           BookE guests on BookS. Let's hope nobody dares enough :) */
+        return 0;
+    } else {
+        if (!cap_segstate) {
+            fprintf(stderr, "kvm error: missing PVR setting capability\n");
+            return -ENOSYS;
+        }
+    }
+
+    ret = kvm_vcpu_ioctl(cenv, KVM_GET_SREGS, &sregs);
+    if (ret) {
+        return ret;
+    }
 
     sregs.pvr = cenv->spr[SPR_PVR];
-    ret = kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
+    return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
+}
 
-    idle_timer = qemu_new_timer(vm_clock, kvm_kick_env, cenv);
+/* Set up a shared TLB array with KVM */
+static int kvm_booke206_tlb_init(CPUState *env)
+{
+    struct kvm_book3e_206_tlb_params params = {};
+    struct kvm_config_tlb cfg = {};
+    struct kvm_enable_cap encap = {};
+    unsigned int entries = 0;
+    int ret, i;
+
+    if (!kvm_enabled() ||
+        !kvm_check_extension(env->kvm_state, KVM_CAP_SW_TLB)) {
+        return 0;
+    }
+
+    assert(ARRAY_SIZE(params.tlb_sizes) == BOOKE206_MAX_TLBN);
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        params.tlb_sizes[i] = booke206_tlb_size(env, i);
+        params.tlb_ways[i] = booke206_tlb_ways(env, i);
+        entries += params.tlb_sizes[i];
+    }
+
+    assert(entries == env->nb_tlb);
+    assert(sizeof(struct kvm_book3e_206_tlb_entry) == sizeof(ppcmas_tlb_t));
+
+    env->tlb_dirty = true;
+
+    cfg.array = (uintptr_t)env->tlb.tlbm;
+    cfg.array_len = sizeof(ppcmas_tlb_t) * entries;
+    cfg.params = (uintptr_t)&params;
+    cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
+
+    encap.cap = KVM_CAP_SW_TLB;
+    encap.args[0] = (uintptr_t)&cfg;
+
+    ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &encap);
+    if (ret < 0) {
+        fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
+                __func__, strerror(-ret));
+        return ret;
+    }
+
+    env->kvm_sw_tlb = true;
+    return 0;
+}
+
+int kvm_arch_init_vcpu(CPUState *cenv)
+{
+    int ret;
+
+    ret = kvm_arch_sync_sregs(cenv);
+    if (ret) {
+        return ret;
+    }
+
+    idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_env, cenv);
+
+    /* Some targets support access to KVM's guest TLB. */
+    switch (cenv->mmu_model) {
+    case POWERPC_MMU_BOOKE206:
+        ret = kvm_booke206_tlb_init(cenv);
+        break;
+    default:
+        break;
+    }
 
     return ret;
 }
@@ -94,6 +193,31 @@ void kvm_arch_reset_vcpu(CPUState *env)
 {
 }
 
+static void kvm_sw_tlb_put(CPUState *env)
+{
+    struct kvm_dirty_tlb dirty_tlb;
+    unsigned char *bitmap;
+    int ret;
+
+    if (!env->kvm_sw_tlb) {
+        return;
+    }
+
+    bitmap = g_malloc((env->nb_tlb + 7) / 8);
+    memset(bitmap, 0xFF, (env->nb_tlb + 7) / 8);
+
+    dirty_tlb.bitmap = (uintptr_t)bitmap;
+    dirty_tlb.num_dirty = env->nb_tlb;
+
+    ret = kvm_vcpu_ioctl(env, KVM_DIRTY_TLB, &dirty_tlb);
+    if (ret) {
+        fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n",
+                __func__, strerror(-ret));
+    }
+
+    g_free(bitmap);
+}
+
 int kvm_arch_put_registers(CPUState *env, int level)
 {
     struct kvm_regs regs;
@@ -122,6 +246,8 @@ int kvm_arch_put_registers(CPUState *env, int level)
     regs.sprg6 = env->spr[SPR_SPRG6];
     regs.sprg7 = env->spr[SPR_SPRG7];
 
+    regs.pid = env->spr[SPR_BOOKE_PID];
+
     for (i = 0;i < 32; i++)
         regs.gpr[i] = env->gpr[i];
 
@@ -129,6 +255,11 @@ int kvm_arch_put_registers(CPUState *env, int level)
     if (ret < 0)
         return ret;
 
+    if (env->tlb_dirty) {
+        kvm_sw_tlb_put(env);
+        env->tlb_dirty = false;
+    }
+
     return ret;
 }
 
@@ -136,15 +267,18 @@ int kvm_arch_get_registers(CPUState *env)
 {
     struct kvm_regs regs;
     struct kvm_sregs sregs;
+    uint32_t cr;
     int i, ret;
 
     ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
     if (ret < 0)
         return ret;
 
-    ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
-    if (ret < 0)
-        return ret;
+    cr = regs.cr;
+    for (i = 7; i >= 0; i--) {
+        env->crf[i] = cr & 15;
+        cr >>= 4;
+    }
 
     env->ctr = regs.ctr;
     env->lr = regs.lr;
@@ -164,12 +298,122 @@ int kvm_arch_get_registers(CPUState *env)
     env->spr[SPR_SPRG6] = regs.sprg6;
     env->spr[SPR_SPRG7] = regs.sprg7;
 
+    env->spr[SPR_BOOKE_PID] = regs.pid;
+
     for (i = 0;i < 32; i++)
         env->gpr[i] = regs.gpr[i];
 
-#ifdef KVM_CAP_PPC_SEGSTATE
-    if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_SEGSTATE)) {
-        env->sdr1 = sregs.u.s.sdr1;
+    if (cap_booke_sregs) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_BASE) {
+            env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
+            env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
+            env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
+            env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
+            env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
+            env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
+            env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
+            env->spr[SPR_DECR] = sregs.u.e.dec;
+            env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
+            env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
+            env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
+            env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
+            env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
+            env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
+            env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
+            env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_64) {
+            env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
+            env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
+            env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
+            env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
+            env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
+            env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
+            env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
+            env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
+            env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
+            env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
+            env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
+            env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
+            env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
+            env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
+            env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
+            env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
+            env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
+            env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
+
+            if (sregs.u.e.features & KVM_SREGS_E_SPE) {
+                env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
+                env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
+                env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
+            }
+
+            if (sregs.u.e.features & KVM_SREGS_E_PM) {
+                env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
+            }
+
+            if (sregs.u.e.features & KVM_SREGS_E_PC) {
+                env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
+                env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
+            }
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
+            env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
+            env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
+            env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
+            env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
+            env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
+            env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
+            env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
+            env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
+            env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
+            env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_EXP) {
+            env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_PD) {
+            env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
+            env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
+        }
+
+        if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
+            env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
+            env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
+            env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
+
+            if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
+                env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
+                env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
+            }
+        }
+    }
+
+    if (cap_segstate) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ppc_store_sdr1(env, sregs.u.s.sdr1);
 
         /* Sync SLB */
 #ifdef TARGET_PPC64
@@ -192,7 +436,6 @@ int kvm_arch_get_registers(CPUState *env)
             env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
         }
     }
-#endif
 
     return 0;
 }
@@ -222,7 +465,7 @@ int kvmppc_set_interrupt(CPUState *env, int irq, int level)
 #define PPC_INPUT_INT PPC6xx_INPUT_INT
 #endif
 
-int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
 {
     int r;
     unsigned irq;
@@ -246,24 +489,22 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
             printf("cpu %d fail inject %x\n", env->cpu_index, irq);
 
         /* Always wake up soon in case the interrupt was level based */
-        qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) +
+        qemu_mod_timer(idle_timer, qemu_get_clock_ns(vm_clock) +
                        (get_ticks_per_sec() / 50));
     }
 
     /* We don't know if there are more interrupts pending after this. However,
      * the guest will return to userspace in the course of handling this one
      * anyways, so we will get a chance to deliver the rest. */
-    return 0;
 }
 
-int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
-    return 0;
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
-    return 0;
+    return env->halted;
 }
 
 static int kvmppc_handle_halt(CPUState *env)
@@ -273,7 +514,7 @@ static int kvmppc_handle_halt(CPUState *env)
         env->exception_index = EXCP_HLT;
     }
 
-    return 1;
+    return 0;
 }
 
 /* map dcr access to existing qemu dcr emulation */
@@ -282,7 +523,7 @@ static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)
     if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
         fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
 
-    return 1;
+    return 0;
 }
 
 static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
@@ -290,12 +531,12 @@ static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
     if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
         fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
 
-    return 1;
+    return 0;
 }
 
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
 {
-    int ret = 0;
+    int ret;
 
     switch (run->exit_reason) {
     case KVM_EXIT_DCR:
@@ -311,6 +552,14 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
         dprintf("handle halt\n");
         ret = kvmppc_handle_halt(env);
         break;
+#ifdef CONFIG_PSERIES
+    case KVM_EXIT_PAPR_HCALL:
+        dprintf("handle PAPR hypercall\n");
+        run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
+                                              run->papr_hcall.args);
+        ret = 1;
+        break;
+#endif
     default:
         fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
         ret = -1;
@@ -368,11 +617,97 @@ uint32_t kvmppc_get_tbfreq(void)
     return retval;
 }
 
+/* Try to find a device tree node for a CPU with clock-frequency property */
+static int kvmppc_find_cpu_dt(char *buf, int buf_len)
+{
+    struct dirent *dirp;
+    DIR *dp;
+
+    if ((dp = opendir(PROC_DEVTREE_CPU)) == NULL) {
+        printf("Can't open directory " PROC_DEVTREE_CPU "\n");
+        return -1;
+    }
+
+    buf[0] = '\0';
+    while ((dirp = readdir(dp)) != NULL) {
+        FILE *f;
+        snprintf(buf, buf_len, "%s%s/clock-frequency", PROC_DEVTREE_CPU,
+                 dirp->d_name);
+        f = fopen(buf, "r");
+        if (f) {
+            snprintf(buf, buf_len, "%s%s", PROC_DEVTREE_CPU, dirp->d_name);
+            fclose(f);
+            break;
+        }
+        buf[0] = '\0';
+    }
+    closedir(dp);
+    if (buf[0] == '\0') {
+        printf("Unknown host!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* Read a CPU node property from the host device tree that's a single
+ * integer (32-bit or 64-bit).  Returns 0 if anything goes wrong
+ * (can't find or open the property, or doesn't understand the
+ * format) */
+static uint64_t kvmppc_read_int_cpu_dt(const char *propname)
+{
+    char buf[PATH_MAX];
+    union {
+        uint32_t v32;
+        uint64_t v64;
+    } u;
+    FILE *f;
+    int len;
+
+    if (kvmppc_find_cpu_dt(buf, sizeof(buf))) {
+        return -1;
+    }
+
+    strncat(buf, "/", sizeof(buf) - strlen(buf));
+    strncat(buf, propname, sizeof(buf) - strlen(buf));
+
+    f = fopen(buf, "rb");
+    if (!f) {
+        return -1;
+    }
+
+    len = fread(&u, 1, sizeof(u), f);
+    fclose(f);
+    switch (len) {
+    case 4:
+        /* property is a 32-bit quantity */
+        return be32_to_cpu(u.v32);
+    case 8:
+        return be64_to_cpu(u.v64);
+    }
+
+    return 0;
+}
+
+uint64_t kvmppc_get_clockfreq(void)
+{
+    return kvmppc_read_int_cpu_dt("clock-frequency");
+}
+
+uint32_t kvmppc_get_vmx(void)
+{
+    return kvmppc_read_int_cpu_dt("ibm,vmx");
+}
+
+uint32_t kvmppc_get_dfp(void)
+{
+    return kvmppc_read_int_cpu_dt("ibm,dfp");
+}
+
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
 {
     uint32_t *hc = (uint32_t*)buf;
 
-#ifdef KVM_CAP_PPC_GET_PVINFO
     struct kvm_ppc_pvinfo pvinfo;
 
     if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
@@ -381,7 +716,6 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
 
         return 0;
     }
-#endif
 
     /*
      * Fallback to always fail hypercalls:
@@ -400,7 +734,216 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
     return 0;
 }
 
+void kvmppc_set_papr(CPUState *env)
+{
+    struct kvm_enable_cap cap = {};
+    struct kvm_one_reg reg = {};
+    struct kvm_sregs sregs = {};
+    int ret;
+
+    cap.cap = KVM_CAP_PPC_PAPR;
+    ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
+
+    if (ret) {
+        goto fail;
+    }
+
+    /*
+     * XXX We set HIOR here. It really should be a qdev property of
+     *     the CPU node, but we don't have CPUs converted to qdev yet.
+     *
+     *     Once we have qdev CPUs, move HIOR to a qdev property and
+     *     remove this chunk.
+     */
+    reg.id = KVM_ONE_REG_PPC_HIOR;
+    reg.u.reg64 = env->spr[SPR_HIOR];
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        goto fail;
+    }
+
+    /* Set SDR1 so kernel space finds the HTAB */
+    ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+    if (ret) {
+        goto fail;
+    }
+
+    sregs.u.s.sdr1 = env->spr[SPR_SDR1];
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
+    if (ret) {
+        goto fail;
+    }
+
+    return;
+
+fail:
+    cpu_abort(env, "This KVM version does not support PAPR\n");
+}
+
+int kvmppc_smt_threads(void)
+{
+    return cap_ppc_smt ? cap_ppc_smt : 1;
+}
+
+off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
+{
+    void *rma;
+    off_t size;
+    int fd;
+    struct kvm_allocate_rma ret;
+    MemoryRegion *rma_region;
+
+    /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported
+     * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but
+     *                      not necessary on this hardware
+     * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware
+     *
+     * FIXME: We should allow the user to force contiguous RMA
+     * allocation in the cap_ppc_rma==1 case.
+     */
+    if (cap_ppc_rma < 2) {
+        return 0;
+    }
+
+    fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret);
+    if (fd < 0) {
+        fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n",
+                strerror(errno));
+        return -1;
+    }
+
+    size = MIN(ret.rma_size, 256ul << 20);
+
+    rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (rma == MAP_FAILED) {
+        fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno));
+        return -1;
+    };
+
+    rma_region = g_new(MemoryRegion, 1);
+    memory_region_init_ram_ptr(rma_region, NULL, name, size, rma);
+    memory_region_add_subregion(sysmem, 0, rma_region);
+
+    return size;
+}
+
+void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
+{
+    struct kvm_create_spapr_tce args = {
+        .liobn = liobn,
+        .window_size = window_size,
+    };
+    long len;
+    int fd;
+    void *table;
+
+    /* Must set fd to -1 so we don't try to munmap when called for
+     * destroying the table, which the upper layers -will- do
+     */
+    *pfd = -1;
+    if (!cap_spapr_tce) {
+        return NULL;
+    }
+
+    fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args);
+    if (fd < 0) {
+        fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n",
+                liobn);
+        return NULL;
+    }
+
+    len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE);
+    /* FIXME: round this up to page size */
+
+    table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (table == MAP_FAILED) {
+        fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n",
+                liobn);
+        close(fd);
+        return NULL;
+    }
+
+    *pfd = fd;
+    return table;
+}
+
+int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
+{
+    long len;
+
+    if (fd < 0) {
+        return -1;
+    }
+
+    len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE);
+    if ((munmap(table, len) < 0) ||
+        (close(fd) < 0)) {
+        fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
+                strerror(errno));
+        /* Leak the table */
+    }
+
+    return 0;
+}
+
+static inline uint32_t mfpvr(void)
+{
+    uint32_t pvr;
+
+    asm ("mfpvr %0"
+         : "=r"(pvr));
+    return pvr;
+}
+
+static void alter_insns(uint64_t *word, uint64_t flags, bool on)
+{
+    if (on) {
+        *word |= flags;
+    } else {
+        *word &= ~flags;
+    }
+}
+
+const ppc_def_t *kvmppc_host_cpu_def(void)
+{
+    uint32_t host_pvr = mfpvr();
+    const ppc_def_t *base_spec;
+    ppc_def_t *spec;
+    uint32_t vmx = kvmppc_get_vmx();
+    uint32_t dfp = kvmppc_get_dfp();
+
+    base_spec = ppc_find_by_pvr(host_pvr);
+
+    spec = g_malloc0(sizeof(*spec));
+    memcpy(spec, base_spec, sizeof(*spec));
+
+    /* Now fix up the spec with information we can query from the host */
+
+    if (vmx != -1) {
+        /* Only override when we know what the host supports */
+        alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0);
+        alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1);
+    }
+    if (dfp != -1) {
+        /* Only override when we know what the host supports */
+        alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
+    }
+
+    return spec;
+}
+
 bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return true;
 }
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
index 6f0468cdecc24ad8d6bf13286b5de9fd4285d8b3..24fc6bce3b86c34b74649199c95b6bcc7e1e2007 100644 (file)
 static QEMUTimer *kvmppc_timer;
 static unsigned int kvmppc_timer_rate;
 
-#ifdef CONFIG_FDT
-int kvmppc_read_host_property(const char *node_path, const char *prop,
-                                     void *val, size_t len)
-{
-    char *path;
-    FILE *f;
-    int ret = 0;
-    int pathlen;
-
-    pathlen = snprintf(NULL, 0, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop)
-              + 1;
-    path = qemu_malloc(pathlen);
-
-    snprintf(path, pathlen, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop);
-
-    f = fopen(path, "rb");
-    if (f == NULL) {
-        ret = errno;
-        goto free;
-    }
-
-    len = fread(val, len, 1, f);
-    if (len != 1) {
-        ret = ferror(f);
-        goto close;
-    }
-
-close:
-    fclose(f);
-free:
-    free(path);
-    return ret;
-}
-
-static int kvmppc_copy_host_cell(void *fdt, const char *node, const char *prop)
-{
-    uint32_t cell;
-    int ret;
-
-    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
-    if (ret < 0) {
-        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
-        goto out;
-    }
-
-    ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
-        goto out;
-    }
-
-out:
-    return ret;
-}
-
-void kvmppc_fdt_update(void *fdt)
-{
-    /* Copy data from the host device tree into the guest. Since the guest can
-     * directly access the timebase without host involvement, we must expose
-     * the correct frequencies. */
-    kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "clock-frequency");
-    kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "timebase-frequency");
-}
-#endif
-
 static void kvmppc_timer_hack(void *opaque)
 {
-    qemu_service_io();
-    qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
+    qemu_notify_event();
+    qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
 }
 
 void kvmppc_init(void)
@@ -99,7 +34,7 @@ void kvmppc_init(void)
      * run. So, until Qemu gains IO threads, we create this timer to ensure
      * that the device model gets a chance to run. */
     kvmppc_timer_rate = get_ticks_per_sec() / 10;
-    kvmppc_timer = qemu_new_timer(vm_clock, &kvmppc_timer_hack, NULL);
-    qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
+    kvmppc_timer = qemu_new_timer_ns(vm_clock, &kvmppc_timer_hack, NULL);
+    qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
 }
 
index 911b19e378b499a1a4b5d8381c1aa5e8640e2cc6..f9c019831154abb3e76433a15544a54be0e92417 100644 (file)
 #ifndef __KVM_PPC_H__
 #define __KVM_PPC_H__
 
+#include "memory.h"
+
 void kvmppc_init(void);
-void kvmppc_fdt_update(void *fdt);
-int kvmppc_read_host_property(const char *node_path, const char *prop,
-                                     void *val, size_t len);
+
+#ifdef CONFIG_KVM
 
 uint32_t kvmppc_get_tbfreq(void);
+uint64_t kvmppc_get_clockfreq(void);
+uint32_t kvmppc_get_vmx(void);
+uint32_t kvmppc_get_dfp(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 int kvmppc_set_interrupt(CPUState *env, int irq, int level);
+void kvmppc_set_papr(CPUState *env);
+int kvmppc_smt_threads(void);
+#ifndef CONFIG_USER_ONLY
+off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
+void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
+int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
+#endif /* !CONFIG_USER_ONLY */
+const ppc_def_t *kvmppc_host_cpu_def(void);
+
+#else
+
+static inline uint32_t kvmppc_get_tbfreq(void)
+{
+    return 0;
+}
+
+static inline uint64_t kvmppc_get_clockfreq(void)
+{
+    return 0;
+}
+
+static inline uint32_t kvmppc_get_vmx(void)
+{
+    return 0;
+}
+
+static inline uint32_t kvmppc_get_dfp(void)
+{
+    return 0;
+}
+
+static inline int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
+{
+    return -1;
+}
+
+static inline int kvmppc_set_interrupt(CPUState *env, int irq, int level)
+{
+    return -1;
+}
+
+static inline void kvmppc_set_papr(CPUState *env)
+{
+}
+
+static inline int kvmppc_smt_threads(void)
+{
+    return 1;
+}
+
+#ifndef CONFIG_USER_ONLY
+static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
+{
+    return 0;
+}
+
+static inline void *kvmppc_create_spapr_tce(uint32_t liobn,
+                                            uint32_t window_size, int *fd)
+{
+    return NULL;
+}
+
+static inline int kvmppc_remove_spapr_tce(void *table, int pfd,
+                                          uint32_t window_size)
+{
+    return -1;
+}
+#endif /* !CONFIG_USER_ONLY */
+
+static inline const ppc_def_t *kvmppc_host_cpu_def(void)
+{
+    return NULL;
+}
+
+#endif
+
+#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
index 67de951959aa01d605d9a7b7e0b705deb1be348a..1c40d4358a2b5cabd7d17acdd1c1b73c57e9a45a 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++)
@@ -52,12 +52,12 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_sbe32s(f, &env->last_way);
     qemu_put_sbe32s(f, &env->id_tlbs);
     qemu_put_sbe32s(f, &env->nb_pids);
-    if (env->tlb) {
+    if (env->tlb.tlb6) {
         // XXX assumes 6xx
         for (i = 0; i < env->nb_tlb; i++) {
-            qemu_put_betls(f, &env->tlb[i].tlb6.pte0);
-            qemu_put_betls(f, &env->tlb[i].tlb6.pte1);
-            qemu_put_betls(f, &env->tlb[i].tlb6.EPN);
+            qemu_put_betls(f, &env->tlb.tlb6[i].pte0);
+            qemu_put_betls(f, &env->tlb.tlb6[i].pte1);
+            qemu_put_betls(f, &env->tlb.tlb6[i].EPN);
         }
     }
     for (i = 0; i < 4; 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++)
@@ -139,12 +140,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_sbe32s(f, &env->last_way);
     qemu_get_sbe32s(f, &env->id_tlbs);
     qemu_get_sbe32s(f, &env->nb_pids);
-    if (env->tlb) {
+    if (env->tlb.tlb6) {
         // XXX assumes 6xx
         for (i = 0; i < env->nb_tlb; i++) {
-            qemu_get_betls(f, &env->tlb[i].tlb6.pte0);
-            qemu_get_betls(f, &env->tlb[i].tlb6.pte1);
-            qemu_get_betls(f, &env->tlb[i].tlb6.EPN);
+            qemu_get_betls(f, &env->tlb.tlb6[i].pte0);
+            qemu_get_betls(f, &env->tlb.tlb6[i].pte1);
+            qemu_get_betls(f, &env->tlb.tlb6[i].EPN);
         }
     }
     for (i = 0; i < 4; 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..134b0c65876bcd56028b8b4cc5a7c50330e5314f 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include <string.h>
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "host-utils.h"
 #include "helper.h"
 
 #include "helper_regs.h"
 
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
 //#define DEBUG_OP
 //#define DEBUG_EXCEPTIONS
 //#define DEBUG_SOFTWARE_TLB
@@ -44,7 +49,7 @@ void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
 #endif
     env->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_raise_exception (uint32_t exception)
@@ -86,6 +91,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);
@@ -355,7 +367,6 @@ void helper_icbi(target_ulong addr)
      * do the load "by hand".
      */
     ldl(addr);
-    tb_invalidate_page_range(addr, addr + env->icache_line_size);
 }
 
 // XXX: to be tested
@@ -492,6 +503,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 +543,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
@@ -932,7 +976,6 @@ void helper_store_fpscr (uint64_t arg, uint32_t mask)
 
 void helper_float_check_status (void)
 {
-#ifdef CONFIG_SOFTFLOAT
     if (env->exception_index == POWERPC_EXCP_PROGRAM &&
         (env->error_code & POWERPC_EXCP_FP)) {
         /* Differred floating-point exception after target FPR update */
@@ -950,22 +993,12 @@ void helper_float_check_status (void)
             float_inexact_excp();
         }
     }
-#else
-    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
-        (env->error_code & POWERPC_EXCP_FP)) {
-        /* Differred floating-point exception after target FPR update */
-        if (msr_fe0 != 0 || msr_fe1 != 0)
-            helper_raise_exception_err(env->exception_index, env->error_code);
-    }
-#endif
 }
 
-#ifdef CONFIG_SOFTFLOAT
 void helper_reset_fpstatus (void)
 {
     set_float_exception_flags(0, &env->fp_status);
 }
-#endif
 
 /* fadd - fadd. */
 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
@@ -1247,7 +1280,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 +1295,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 +1320,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 +1335,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 +1359,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 +1374,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 +1401,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 +1416,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 +3336,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 +3344,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 +3352,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 +3360,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 +3671,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)
@@ -3701,18 +3714,17 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
@@ -3721,7 +3733,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 +3758,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)
+{
+    if (ppc_store_slb(env, rb, rs) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+}
+
+target_ulong helper_load_slb_esid (target_ulong rb)
 {
-    return ppc_load_slb(env, slb_nr);
+    target_ulong rt;
+
+    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
 }
 
-void helper_store_slb (target_ulong rb, target_ulong rs)
+target_ulong helper_load_slb_vsid (target_ulong rb)
 {
-    ppc_store_slb(env, rb, rs);
+    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)
@@ -3934,7 +3963,7 @@ target_ulong helper_4xx_tlbre_hi (target_ulong entry)
     int size;
 
     entry &= PPC4XX_TLB_ENTRY_MASK;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     ret = tlb->EPN;
     if (tlb->prot & PAGE_VALID) {
         ret |= PPC4XX_TLBHI_V;
@@ -3954,7 +3983,7 @@ target_ulong helper_4xx_tlbre_lo (target_ulong entry)
     target_ulong ret;
 
     entry &= PPC4XX_TLB_ENTRY_MASK;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     ret = tlb->RPN;
     if (tlb->prot & PAGE_EXEC) {
         ret |= PPC4XX_TLBLO_EX;
@@ -3973,7 +4002,7 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
     LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
               val);
     entry &= PPC4XX_TLB_ENTRY_MASK;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     /* Invalidate previous TLB (if it's valid) */
     if (tlb->prot & PAGE_VALID) {
         end = tlb->EPN + tlb->size;
@@ -4031,7 +4060,7 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
     LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
               val);
     entry &= PPC4XX_TLB_ENTRY_MASK;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
     tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
     tlb->prot = PAGE_READ;
@@ -4066,7 +4095,7 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
               __func__, word, (int)entry, value);
     do_flush_tlbs = 0;
     entry &= 0x3F;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     switch (word) {
     default:
         /* Just here to please gcc */
@@ -4125,7 +4154,7 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
     int size;
 
     entry &= 0x3F;
-    tlb = &env->tlb[entry].tlbe;
+    tlb = &env->tlb.tlbe[entry];
     switch (word) {
     default:
         /* Just here to please gcc */
@@ -4169,4 +4198,216 @@ target_ulong helper_440_tlbsx (target_ulong address)
     return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
 }
 
+/* PowerPC BookE 2.06 TLB management */
+
+static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env)
+{
+    uint32_t tlbncfg = 0;
+    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
+    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
+    int tlb;
+
+    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
+
+    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
+        cpu_abort(env, "we don't support HES yet\n");
+    }
+
+    return booke206_get_tlbm(env, tlb, ea, esel);
+}
+
+void helper_booke_setpid(uint32_t pidn, target_ulong pid)
+{
+    env->spr[pidn] = pid;
+    /* changing PIDs mean we're in a different address space now */
+    tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbwe(void)
+{
+    uint32_t tlbncfg, tlbn;
+    ppcmas_tlb_t *tlb;
+
+    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
+    case MAS0_WQ_ALWAYS:
+        /* good to go, write that entry */
+        break;
+    case MAS0_WQ_COND:
+        /* XXX check if reserved */
+        if (0) {
+            return;
+        }
+        break;
+    case MAS0_WQ_CLR_RSRV:
+        /* XXX clear entry */
+        return;
+    default:
+        /* no idea what to do */
+        return;
+    }
+
+    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
+         !msr_gs) {
+        /* XXX we don't support direct LRAT setting yet */
+        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
+        return;
+    }
+
+    tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+
+    tlb = booke206_cur_tlb(env);
+
+    if (msr_gs) {
+        cpu_abort(env, "missing HV implementation\n");
+    }
+    tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
+                  env->spr[SPR_BOOKE_MAS3];
+    tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+    /* XXX needs to change when supporting 64-bit e500 */
+    tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
+
+    if (!(tlbncfg & TLBnCFG_IPROT)) {
+        /* no IPROT supported by TLB */
+        tlb->mas1 &= ~MAS1_IPROT;
+    }
+
+    if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
+        tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
+    } else {
+        tlb_flush(env, 1);
+    }
+}
+
+static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    int way = booke206_tlbm_to_way(env, tlb);
+
+    env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
+    env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+
+    env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
+    env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
+    env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
+    env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
+}
+
+void helper_booke206_tlbre(void)
+{
+    ppcmas_tlb_t *tlb = NULL;
+
+    tlb = booke206_cur_tlb(env);
+    booke206_tlb_to_mas(env, tlb);
+}
+
+void helper_booke206_tlbsx(target_ulong address)
+{
+    ppcmas_tlb_t *tlb = NULL;
+    int i, j;
+    target_phys_addr_t raddr;
+    uint32_t spid, sas;
+
+    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
+    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int ways = booke206_tlb_ways(env, i);
+
+        for (j = 0; j < ways; j++) {
+            tlb = booke206_get_tlbm(env, i, address, j);
+
+            if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
+                continue;
+            }
+
+            if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+                continue;
+            }
+
+            booke206_tlb_to_mas(env, tlb);
+            return;
+        }
+    }
+
+    /* no entry found, fill with defaults */
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+    env->spr[SPR_BOOKE_MAS3] = 0;
+    env->spr[SPR_BOOKE_MAS7] = 0;
+
+    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
+                                << MAS1_TID_SHIFT;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= booke206_tlb_ways(env, 0) - 1;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
+                                              uint32_t ea)
+{
+    int i;
+    int ways = booke206_tlb_ways(env, tlbn);
+    target_ulong mask;
+
+    for (i = 0; i < ways; i++) {
+        ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+        mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+        if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
+            !(tlb->mas1 & MAS1_IPROT)) {
+            tlb->mas1 &= ~MAS1_VALID;
+        }
+    }
+}
+
+void helper_booke206_tlbivax(target_ulong address)
+{
+    if (address & 0x4) {
+        /* flush all entries */
+        if (address & 0x8) {
+            /* flush all of TLB1 */
+            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
+        } else {
+            /* flush all of TLB0 */
+            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
+        }
+        return;
+    }
+
+    if (address & 0x8) {
+        /* flush TLB1 entries */
+        booke206_invalidate_ea_tlb(env, 1, address);
+        tlb_flush(env, 1);
+    } else {
+        /* flush TLB0 entries */
+        booke206_invalidate_ea_tlb(env, 0, address);
+        tlb_flush_page(env, address & MAS2_EPN_MASK);
+    }
+}
+
+void helper_booke206_tlbflush(uint32_t type)
+{
+    int flags = 0;
+
+    if (type & 2) {
+        flags |= BOOKE206_FLUSH_TLB1;
+    }
+
+    if (type & 4) {
+        flags |= BOOKE206_FLUSH_TLB0;
+    }
+
+    booke206_flush_tlb(env, flags, 1);
+}
+
 #endif /* !CONFIG_USER_ONLY */
index 89413c5395e7c0839d9f7152e97c8e9498d94682..66eae302098ea5d0dc331f417eca57446fc18bde 100644 (file)
@@ -2,6 +2,7 @@
  *  PowerPC emulation for qemu: main translation routines.
  *
  *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *  Copyright (C) 2011 Freescale Semiconductor, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,7 +24,6 @@
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-common.h"
@@ -69,6 +69,9 @@ static TCGv cpu_nip;
 static TCGv cpu_msr;
 static TCGv cpu_ctr;
 static TCGv cpu_lr;
+#if defined(TARGET_PPC64)
+static TCGv cpu_cfar;
+#endif
 static TCGv cpu_xer;
 static TCGv cpu_reserve;
 static TCGv_i32 cpu_fpscr;
@@ -154,6 +157,11 @@ void ppc_translate_init(void)
     cpu_lr = tcg_global_mem_new(TCG_AREG0,
                                 offsetof(CPUState, lr), "lr");
 
+#if defined(TARGET_PPC64)
+    cpu_cfar = tcg_global_mem_new(TCG_AREG0,
+                                  offsetof(CPUState, cfar), "cfar");
+#endif
+
     cpu_xer = tcg_global_mem_new(TCG_AREG0,
                                  offsetof(CPUState, xer), "xer");
 
@@ -187,6 +195,7 @@ typedef struct DisasContext {
     int le_mode;
 #if defined(TARGET_PPC64)
     int sf_mode;
+    int has_cfar;
 #endif
     int fpu_enabled;
     int altivec_enabled;
@@ -196,10 +205,14 @@ typedef struct DisasContext {
 } DisasContext;
 
 struct opc_handler_t {
-    /* invalid bits */
-    uint32_t inval;
+    /* invalid bits for instruction 1 (Rc(opcode) == 0) */
+    uint32_t inval1;
+    /* invalid bits for instruction 2 (Rc(opcode) == 1) */
+    uint32_t inval2;
     /* instruction type */
     uint64_t type;
+    /* extended instruction type */
+    uint64_t type2;
     /* handler */
     void (*handler)(DisasContext *ctx);
 #if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
@@ -212,9 +225,7 @@ struct opc_handler_t {
 
 static inline void gen_reset_fpstatus(void)
 {
-#ifdef CONFIG_SOFTFLOAT
     gen_helper_reset_fpstatus();
-#endif
 }
 
 static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc)
@@ -287,8 +298,10 @@ static inline void gen_debug_exception(DisasContext *ctx)
 {
     TCGv_i32 t0;
 
-    if (ctx->exception != POWERPC_EXCP_BRANCH)
+    if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
+        (ctx->exception != POWERPC_EXCP_SYNC)) {
         gen_update_nip(ctx, ctx->nip);
+    }
     t0 = tcg_const_i32(EXCP_DEBUG);
     gen_helper_raise_exception(t0);
     tcg_temp_free_i32(t0);
@@ -313,10 +326,16 @@ static inline void gen_sync_exception(DisasContext *ctx)
 }
 
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
-GEN_OPCODE(name, opc1, opc2, opc3, inval, type)
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER_E(name, opc1, opc2, opc3, inval, type, type2)             \
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, type2)
 
 #define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type)               \
-GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type)
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2)      \
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
 
 typedef struct opcode_t {
     unsigned char opc1, opc2, opc3;
@@ -456,57 +475,92 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
 /* PowerPC instructions table                                                */
 
 #if defined(DO_PPC_STATISTICS)
-#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval1  = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+        .oname = stringify(name),                                             \
+    },                                                                        \
+    .oname = stringify(name),                                                 \
+}
+#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2)       \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
     .opc3 = op3,                                                              \
     .pad  = { 0, },                                                           \
     .handler = {                                                              \
-        .inval   = invl,                                                      \
+        .inval1  = invl1,                                                     \
+        .inval2  = invl2,                                                     \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
         .oname = stringify(name),                                             \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
-#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
     .opc3 = op3,                                                              \
     .pad  = { 0, },                                                           \
     .handler = {                                                              \
-        .inval   = invl,                                                      \
+        .inval1  = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
         .oname = onam,                                                        \
     },                                                                        \
     .oname = onam,                                                            \
 }
 #else
-#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
     .opc3 = op3,                                                              \
     .pad  = { 0, },                                                           \
     .handler = {                                                              \
-        .inval   = invl,                                                      \
+        .inval1  = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
-#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2)       \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
     .opc3 = op3,                                                              \
     .pad  = { 0, },                                                           \
     .handler = {                                                              \
-        .inval   = invl,                                                      \
+        .inval1  = invl1,                                                     \
+        .inval2  = invl2,                                                     \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+    },                                                                        \
+    .oname = stringify(name),                                                 \
+}
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval1  = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
     },                                                                        \
     .oname = onam,                                                            \
@@ -531,8 +585,10 @@ static void gen_invalid(DisasContext *ctx)
 }
 
 static opc_handler_t invalid_handler = {
-    .inval   = 0xFFFFFFFF,
+    .inval1  = 0xFFFFFFFF,
+    .inval2  = 0xFFFFFFFF,
     .type    = PPC_NONE,
+    .type2   = PPC_NONE,
     .handler = gen_invalid,
 };
 
@@ -1483,13 +1539,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. */
@@ -3326,6 +3390,14 @@ static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
 /* stfiwx */
 GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
 
+static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->has_cfar)
+        tcg_gen_movi_tl(cpu_cfar, nip);
+#endif
+}
+
 /***                                Branch                                 ***/
 static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 {
@@ -3339,7 +3411,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)) {
@@ -3388,6 +3460,7 @@ static void gen_b(DisasContext *ctx)
         target = li;
     if (LK(ctx->opcode))
         gen_setlr(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip);
     gen_goto_tb(ctx, 0, target);
 }
 
@@ -3450,6 +3523,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         }
         tcg_temp_free_i32(temp);
     }
+    gen_update_cfar(ctx, ctx->nip);
     if (type == BCOND_IM) {
         target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
         if (likely(AA(ctx->opcode) == 0)) {
@@ -3561,6 +3635,7 @@ static void gen_rfi(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
         return;
     }
+    gen_update_cfar(ctx, ctx->nip);
     gen_helper_rfi();
     gen_sync_exception(ctx);
 #endif
@@ -3577,6 +3652,7 @@ static void gen_rfid(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
         return;
     }
+    gen_update_cfar(ctx, ctx->nip);
     gen_helper_rfid();
     gen_sync_exception(ctx);
 #endif
@@ -3858,24 +3934,19 @@ static void gen_mtmsr(DisasContext *ctx)
         tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
         tcg_temp_free(t0);
     } else {
+        TCGv msr = tcg_temp_new();
+
         /* XXX: we need to update nip before the store
          *      if we enter power saving mode, we will exit the loop
          *      directly from ppc_store_msr
          */
         gen_update_nip(ctx, ctx->nip);
 #if defined(TARGET_PPC64)
-        if (!ctx->sf_mode) {
-            TCGv t0 = tcg_temp_new();
-            TCGv t1 = tcg_temp_new();
-            tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL);
-            tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]);
-            tcg_gen_or_tl(t0, t0, t1);
-            tcg_temp_free(t1);
-            gen_helper_store_msr(t0);
-            tcg_temp_free(t0);
-        } else
+        tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32);
+#else
+        tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]);
 #endif
-            gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
+        gen_helper_store_msr(msr);
         /* Must stop the translation as machine state (may have) changed */
         /* Note that mtmsr is not always defined as context-synchronizing */
         gen_stop_exception(ctx);
@@ -4227,6 +4298,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                      ***/
@@ -5939,6 +6037,80 @@ static void gen_tlbwe_440(DisasContext *ctx)
 #endif
 }
 
+/* TLB management - PowerPC BookE 2.06 implementation */
+
+/* tlbre */
+static void gen_tlbre_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    gen_helper_booke206_tlbre();
+#endif
+}
+
+/* tlbsx - tlbsx. */
+static void gen_tlbsx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    if (rA(ctx->opcode)) {
+        t0 = tcg_temp_new();
+        tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]);
+    } else {
+        t0 = tcg_const_tl(0);
+    }
+
+    tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
+    gen_helper_booke206_tlbsx(t0);
+#endif
+}
+
+/* tlbwe */
+static void gen_tlbwe_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_booke206_tlbwe();
+#endif
+}
+
+static void gen_tlbivax_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+
+    gen_helper_booke206_tlbivax(t0);
+#endif
+}
+
+
 /* wrtee */
 static void gen_wrtee(DisasContext *ctx)
 {
@@ -6502,6 +6674,39 @@ GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
 /***                           SPE extension                               ***/
 /* Register moves */
 
+
+static inline void gen_evmra(DisasContext *ctx)
+{
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+#if defined(TARGET_PPC64)
+    /* rD := rA */
+    tcg_gen_mov_i64(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+
+    /* spe_acc := rA */
+    tcg_gen_st_i64(cpu_gpr[rA(ctx->opcode)],
+                   cpu_env,
+                   offsetof(CPUState, spe_acc));
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* tmp := rA_lo + rA_hi << 32 */
+    tcg_gen_concat_i32_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+
+    /* spe_acc := tmp */
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+    tcg_temp_free_i64(tmp);
+
+    /* rD := rA */
+    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+#endif
+}
+
 static inline void gen_load_gpr64(TCGv_i64 t, int reg)
 {
 #if defined(TARGET_PPC64)
@@ -6524,7 +6729,7 @@ static inline void gen_store_gpr64(int reg, TCGv_i64 t)
 #endif
 }
 
-#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
+#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type)         \
 static void glue(gen_, name0##_##name1)(DisasContext *ctx)                    \
 {                                                                             \
     if (Rc(ctx->opcode))                                                      \
@@ -6545,7 +6750,7 @@ static inline void gen_speundef(DisasContext *ctx)
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6556,7 +6761,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6581,7 +6786,7 @@ GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl);
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6602,7 +6807,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],               \
@@ -6622,7 +6827,7 @@ GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32);
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6643,7 +6848,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);               \
@@ -6681,7 +6886,7 @@ GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6707,7 +6912,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6785,7 +6990,7 @@ GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
 static inline void gen_evmergehi(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -6814,7 +7019,7 @@ GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6835,7 +7040,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
@@ -6853,7 +7058,7 @@ GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     int l1 = gen_new_label();                                                 \
@@ -6893,7 +7098,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     int l1 = gen_new_label();                                                 \
@@ -6936,13 +7141,13 @@ static inline void gen_brinc(DisasContext *ctx)
 static inline void gen_evmergelo(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #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);
@@ -6955,13 +7160,13 @@ static inline void gen_evmergelo(DisasContext *ctx)
 static inline void gen_evmergehilo(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #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);
@@ -6974,7 +7179,7 @@ static inline void gen_evmergehilo(DisasContext *ctx)
 static inline void gen_evmergelohi(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7050,14 +7255,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
@@ -7090,31 +7295,192 @@ static void gen_evsel3(DisasContext *ctx)
     gen_evsel(ctx);
 }
 
-GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE);
-GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE);
-GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE); //
-GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE);
-GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE);
-GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE); //
-GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE);
-GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE); ////
-GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE); ////
-GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE); ////
-GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE); ////
+/* Multiply */
+
+static inline void gen_evmwumi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32u_tl(t1, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#endif
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwumia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    gen_evmwumi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwumiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc;
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    gen_evmwumi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#endif
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwsmia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    gen_evmwsmi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc = tcg_temp_new_i64();
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    gen_evmwsmi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); //
+GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); //
+GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE);
+GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); ////
 
 /* SPE load and stores */
 static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
@@ -7437,7 +7803,7 @@ static void glue(gen_, name)(DisasContext *ctx)
 {                                                                             \
     TCGv t0;                                                                  \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_set_access_type(ctx, ACCESS_INT);                                     \
@@ -7473,78 +7839,74 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2);
 
 /* Multiply and add - TODO */
 #if 0
-GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0x00000000, PPC_SPE);
-
-GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0x00000000, PPC_SPE);
-
-GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, PPC_SPE);
-GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, PPC_SPE);
-GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, PPC_SPE);
-GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, PPC_SPE);
-GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, PPC_SPE);
-GEN_SPE(evmra,          speundef,      0x07, 0x13, 0x0000F800, PPC_SPE);
-
-GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);//
+GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
 #endif
 
 /***                      SPE floating-point extension                     ***/
@@ -7599,7 +7961,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
     TCGv_i32 t0, t1;                                                          \
     TCGv_i64 t2;                                                              \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i32();                                                  \
@@ -7620,7 +7982,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
@@ -7631,7 +7993,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     TCGv_i32 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i32();                                                  \
@@ -7646,7 +8008,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
@@ -7687,7 +8049,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
@@ -7698,7 +8060,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     TCGv_i64 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i64();                                                  \
@@ -7714,7 +8076,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
@@ -7725,7 +8087,7 @@ static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     TCGv_i64 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i64();                                                  \
@@ -7747,7 +8109,7 @@ GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
 static inline void gen_evfsabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7760,7 +8122,7 @@ static inline void gen_evfsabs(DisasContext *ctx)
 static inline void gen_evfsnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7773,7 +8135,7 @@ static inline void gen_evfsnabs(DisasContext *ctx)
 static inline void gen_evfsneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7805,20 +8167,20 @@ GEN_SPEFPUOP_COMP_64(evfststlt);
 GEN_SPEFPUOP_COMP_64(evfststeq);
 
 /* Opcodes definitions */
-GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsadd,   evfssub,   0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsabs,   evfsnabs,  0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(evfsneg,   speundef,  0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfsmul,   evfsdiv,   0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpeq, speundef,  0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfui,  evfscfsi,  0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfuf,  evfscfsf,  0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctui,  evfsctsi,  0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuf,  evfsctsf,  0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuiz, speundef,  0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctsiz, speundef,  0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfststeq, speundef,  0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
 
 /* Single precision floating-point operations */
 /* Arithmetic */
@@ -7829,7 +8191,7 @@ GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
 static inline void gen_efsabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
@@ -7837,7 +8199,7 @@ static inline void gen_efsabs(DisasContext *ctx)
 static inline void gen_efsnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
@@ -7845,7 +8207,7 @@ static inline void gen_efsnabs(DisasContext *ctx)
 static inline void gen_efsneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
@@ -7873,20 +8235,20 @@ GEN_SPEFPUOP_COMP_32(efststlt);
 GEN_SPEFPUOP_COMP_32(efststeq);
 
 /* Opcodes definitions */
-GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efsadd,   efssub,   0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efsabs,   efsnabs,  0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(efsneg,   speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efsmul,   efsdiv,   0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpeq, efscfd,   0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfui,  efscfsi,  0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfuf,  efscfsf,  0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctui,  efsctsi,  0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuf,  efsctsf,  0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
 
 /* Double precision floating-point operations */
 /* Arithmetic */
@@ -7897,7 +8259,7 @@ GEN_SPEFPUOP_ARITH2_64_64(efddiv);
 static inline void gen_efdabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7910,7 +8272,7 @@ static inline void gen_efdabs(DisasContext *ctx)
 static inline void gen_efdnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7923,7 +8285,7 @@ static inline void gen_efdnabs(DisasContext *ctx)
 static inline void gen_efdneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7960,22 +8322,22 @@ GEN_SPEFPUOP_COMP_64(efdtstlt);
 GEN_SPEFPUOP_COMP_64(efdtsteq);
 
 /* Opcodes definitions */
-GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
-GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
-GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdadd,    efdsub,    0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuid,  efdcfsid,  0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdabs,    efdnabs,   0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); //
+GEN_SPE(efdneg,    speundef,  0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdmul,    efddiv,    0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpgt,  efdcmplt,  0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpeq,  efdcfs,    0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfui,   efdcfsi,   0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuf,   efdcfsf,   0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctui,   efdctsi,   0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuf,   efdctsf,   0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuiz,  speundef,  0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctsiz,  speundef,  0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtstgt,  efdtstlt,  0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtsteq,  speundef,  0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
 
 static opcode_t opcodes[] = {
 GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
@@ -8009,7 +8371,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),
@@ -8110,7 +8474,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),
@@ -8191,7 +8557,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
 GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
 GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
 GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
-GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
+GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE206),
 GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI),
 GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI),
 GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB),
@@ -8200,12 +8566,23 @@ GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB),
 GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE),
 GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE),
 GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE),
+GEN_HANDLER2_E(tlbre_booke206, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbsx_booke206, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
-GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE),
-GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
-GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE),
+GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
+              PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
+              PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
+               PPC_BOOKE, PPC2_BOOKE206),
 GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
 GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
 GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
@@ -8729,80 +9106,84 @@ GEN_VAFORM_PAIRED(vsel, vperm, 21),
 GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23),
 
 #undef GEN_SPE
-#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
-GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)
-GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE),
-GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE),
-GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE),
-GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE),
-GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE),
-GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE),
-GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE),
-
-GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE),
-
-GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE),
-
-GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE),
-GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE),
-GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
-GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
+#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \
+    GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE)
+GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE),
+GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
+GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
+GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
+GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
+GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE),
+
+GEN_SPE(evfsadd,     evfssub,     0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfsabs,     evfsnabs,    0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(evfsneg,     speundef,    0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfsmul,     evfsdiv,     0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpgt,   evfscmplt,   0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpeq,   speundef,    0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfscfui,    evfscfsi,    0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfscfuf,    evfscfsf,    0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctui,    evfsctsi,    0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuf,    evfsctsf,    0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuiz,   speundef,    0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfsctsiz,   speundef,    0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfststgt,   evfststlt,   0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfststeq,   speundef,    0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+
+GEN_SPE(efsadd,      efssub,      0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efsabs,      efsnabs,     0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(efsneg,      speundef,    0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efsmul,      efsdiv,      0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpgt,    efscmplt,    0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpeq,    efscfd,      0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efscfui,     efscfsi,     0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efscfuf,     efscfsf,     0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctui,     efsctsi,     0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuf,     efsctsf,     0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuiz,    speundef,    0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efsctsiz,    speundef,    0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efststgt,    efststlt,    0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efststeq,    speundef,    0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+
+GEN_SPE(efdadd,      efdsub,      0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuid,    efdcfsid,    0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdabs,      efdnabs,     0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE),
+GEN_SPE(efdneg,      speundef,    0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdmul,      efddiv,      0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuidz,   efdctsidz,   0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpgt,    efdcmplt,    0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpeq,    efdcfs,      0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfui,     efdcfsi,     0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuf,     efdcfsf,     0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctui,     efdctsi,     0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuf,     efdctsf,     0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuiz,    speundef,    0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdctsiz,    speundef,    0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdtstgt,    efdtstlt,    0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdtsteq,    speundef,    0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
 
 #undef GEN_SPEOP_LDST
 #define GEN_SPEOP_LDST(name, opc2, sh)                                        \
@@ -8891,9 +9272,90 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
     }
     cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
 #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);
+    cpu_fprintf(f, " SRR0 " TARGET_FMT_lx "  SRR1 " TARGET_FMT_lx
+                   "    PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
+                env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+                env->spr[SPR_PVR], env->spr[SPR_VRSAVE]);
+
+    cpu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx
+                   "  SPRG2 " TARGET_FMT_lx "  SPRG3 " TARGET_FMT_lx "\n",
+                env->spr[SPR_SPRG0], env->spr[SPR_SPRG1],
+                env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]);
+
+    cpu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx
+                   "  SPRG6 " TARGET_FMT_lx "  SPRG7 " TARGET_FMT_lx "\n",
+                env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
+                env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
+
+    if (env->excp_model == POWERPC_EXCP_BOOKE) {
+        cpu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
+                       " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
+                    env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
+
+        cpu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
+                       "    ESR " TARGET_FMT_lx "   DEAR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR],
+                    env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
+
+        cpu_fprintf(f, "  PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx
+                       "   IVPR " TARGET_FMT_lx "   EPCR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR],
+                    env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]);
+
+        cpu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx
+                       "    EPR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8],
+                    env->spr[SPR_BOOKE_EPR]);
+
+        /* FSL-specific */
+        cpu_fprintf(f, " MCAR " TARGET_FMT_lx "  PID1 " TARGET_FMT_lx
+                       "   PID2 " TARGET_FMT_lx "    SVR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1],
+                    env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]);
+
+        /*
+         * IVORs are left out as they are large and do not change often --
+         * they can be read with "p $ivor0", "p $ivor1", etc.
+         */
+    }
+
+#if defined(TARGET_PPC64)
+    if (env->flags & POWERPC_FLAG_CFAR) {
+        cpu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar);
+    }
+#endif
+
+    switch (env->mmu_model) {
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_601:
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_620:
+    case POWERPC_MMU_64B:
+#endif
+        cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
+        break;
+    case POWERPC_MMU_BOOKE206:
+        cpu_fprintf(f, " MAS0 " TARGET_FMT_lx "  MAS1 " TARGET_FMT_lx
+                       "   MAS2 " TARGET_FMT_lx "   MAS3 " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],
+                    env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]);
+
+        cpu_fprintf(f, " MAS4 " TARGET_FMT_lx "  MAS6 " TARGET_FMT_lx
+                       "   MAS7 " TARGET_FMT_lx "    PID " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6],
+                    env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]);
+
+        cpu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx
+                       " TLB1CFG " TARGET_FMT_lx "\n",
+                    env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG],
+                    env->spr[SPR_BOOKE_TLB1CFG]);
+        break;
+    default:
+        break;
+    }
 #endif
 
 #undef RGPL
@@ -8972,6 +9434,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
     ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
 #if defined(TARGET_PPC64)
     ctx.sf_mode = msr_sf;
+    ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
 #endif
     ctx.fpu_enabled = msr_fp;
     if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
@@ -9057,11 +9520,19 @@ static inline void gen_intermediate_code_internal(CPUState *env,
                          opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
             }
         } else {
-            if (unlikely((ctx.opcode & handler->inval) != 0)) {
+            uint32_t inval;
+
+            if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) && Rc(ctx.opcode))) {
+                inval = handler->inval2;
+            } else {
+                inval = handler->inval1;
+            }
+
+            if (unlikely((ctx.opcode & inval) != 0)) {
                 if (qemu_log_enabled()) {
                     qemu_log("invalid bits: %08x for opcode: "
                              "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n",
-                             ctx.opcode & handler->inval, opc1(ctx.opcode),
+                             ctx.opcode & inval, opc1(ctx.opcode),
                              opc2(ctx.opcode), opc3(ctx.opcode),
                              ctx.opcode, ctx.nip - 4);
                 }
@@ -9134,8 +9605,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 dfcd94980f85eba9bd07093914af2920ba05befb..8a7233fc820ce3e2f1b050d5c9c9679276b3c516 100644 (file)
@@ -24,6 +24,8 @@
 
 #include "dis-asm.h"
 #include "gdbstub.h"
+#include <kvm.h>
+#include "kvm_ppc.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
 #define TODO_USER_ONLY 1
 #endif
 
-struct ppc_def_t {
-    const char *name;
-    uint32_t pvr;
-    uint32_t svr;
-    uint64_t insns_flags;
-    uint64_t msr_mask;
-    powerpc_mmu_t   mmu_model;
-    powerpc_excp_t  excp_model;
-    powerpc_input_t bus_model;
-    uint32_t flags;
-    int bfd_mach;
-    void (*init_proc)(CPUPPCState *env);
-    int  (*check_pow)(CPUPPCState *env);
-};
-
 /* For user-mode emulation, we don't emulate any IRQ controller */
 #if defined(CONFIG_USER_ONLY)
 #define PPC_IRQ_INIT_FN(name)                                                 \
@@ -61,6 +48,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:
@@ -71,7 +59,7 @@ static void spr_read_generic (void *opaque, int gprn, int sprn)
     gen_load_spr(cpu_gpr[gprn], sprn);
 #ifdef PPC_DUMP_SPR_ACCESSES
     {
-        TCGv t0 = tcg_const_i32(sprn);
+        TCGv_i32 t0 = tcg_const_i32(sprn);
         gen_helper_load_dump_spr(t0);
         tcg_temp_free_i32(t0);
     }
@@ -83,7 +71,7 @@ static void spr_write_generic (void *opaque, int sprn, int gprn)
     gen_store_spr(sprn, cpu_gpr[gprn]);
 #ifdef PPC_DUMP_SPR_ACCESSES
     {
-        TCGv t0 = tcg_const_i32(sprn);
+        TCGv_i32 t0 = tcg_const_i32(sprn);
         gen_helper_store_dump_spr(t0);
         tcg_temp_free_i32(t0);
     }
@@ -127,6 +115,19 @@ static void spr_write_lr (void *opaque, int sprn, int gprn)
     tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
 }
 
+/* CFAR */
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+static void spr_read_cfar (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar);
+}
+
+static void spr_write_cfar (void *opaque, int sprn, int gprn)
+{
+    tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]);
+}
+#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
+
 /* CTR */
 static void spr_read_ctr (void *opaque, int gprn, int sprn)
 {
@@ -154,12 +155,26 @@ static void spr_read_ureg (void *opaque, int gprn, int sprn)
 #if !defined(CONFIG_USER_ONLY)
 static void spr_read_decr (void *opaque, int gprn, int sprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_load_decr(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 
 static void spr_write_decr (void *opaque, int sprn, int gprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_store_decr(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 #endif
 
@@ -167,12 +182,26 @@ static void spr_write_decr (void *opaque, int sprn, int gprn)
 /* Time base */
 static void spr_read_tbl (void *opaque, int gprn, int sprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_load_tbl(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 
 static void spr_read_tbu (void *opaque, int gprn, int sprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_load_tbu(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 
 __attribute__ (( unused ))
@@ -190,12 +219,26 @@ static void spr_read_atbu (void *opaque, int gprn, int sprn)
 #if !defined(CONFIG_USER_ONLY)
 static void spr_write_tbl (void *opaque, int sprn, int gprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_store_tbl(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 
 static void spr_write_tbu (void *opaque, int sprn, int gprn)
 {
+    if (use_icount) {
+        gen_io_start();
+    }
     gen_helper_store_tbu(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
 }
 
 __attribute__ (( unused ))
@@ -209,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)
@@ -293,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]);
@@ -621,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);
 }
 
@@ -797,6 +843,7 @@ static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
     env->nb_tlb = nb_tlbs;
     env->nb_ways = nb_ways;
     env->id_tlbs = 1;
+    env->tlb_type = TLB_6XX;
     spr_register(env, SPR_DMISS, "DMISS",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
@@ -1290,6 +1337,7 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
     env->nb_tlb = nb_tlbs;
     env->nb_ways = nb_ways;
     env->id_tlbs = 1;
+    env->tlb_type = TLB_6XX;
     /* XXX : not implemented */
     spr_register(env, SPR_PTEHI, "PTEHI",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -1308,6 +1356,31 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
 #endif
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256);
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
+}
+
+static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(sprn);
+    gen_helper_booke206_tlbflush(t0);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(sprn);
+    gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+#endif
+
 static void gen_spr_usprgh (CPUPPCState *env)
 {
     spr_register(env, SPR_USPRG4, "USPRG4",
@@ -1447,7 +1520,7 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
     }
     spr_register(env, SPR_BOOKE_PID, "PID",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_booke_pid,
                  0x00000000);
     spr_register(env, SPR_BOOKE_TCR, "TCR",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -1489,8 +1562,19 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
                  0x00000000);
 }
 
-/* FSL storage control registers */
-static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
+static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
+                                   uint32_t maxsize, uint32_t flags,
+                                   uint32_t nentries)
+{
+    return (assoc << TLBnCFG_ASSOC_SHIFT) |
+           (minsize << TLBnCFG_MINSIZE_SHIFT) |
+           (maxsize << TLBnCFG_MAXSIZE_SHIFT) |
+           flags | nentries;
+}
+
+/* BookE 2.06 storage control registers */
+static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
+                              uint32_t *tlbncfg)
 {
 #if !defined(CONFIG_USER_ONLY)
     const char *mas_names[8] = {
@@ -1516,14 +1600,14 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
         /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_PID1, "PID1",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_booke_pid,
                      0x00000000);
     }
     if (env->nb_pids > 2) {
         /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_PID2, "PID2",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_booke_pid,
                      0x00000000);
     }
     /* XXX : not implemented */
@@ -1531,45 +1615,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
                  0x00000000); /* TOFIX */
-    /* XXX : not implemented */
-    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000); /* TOFIX */
     switch (env->nb_ways) {
     case 4:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[3]);
         /* Fallthru */
     case 3:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[2]);
         /* Fallthru */
     case 2:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[1]);
         /* Fallthru */
     case 1:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[0]);
         /* Fallthru */
     case 0:
     default:
         break;
     }
 #endif
+
+    gen_spr_usprgh(env);
 }
 
 /* SPR specific to PowerPC 440 implementation */
@@ -3086,6 +3163,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
 
 /*****************************************************************************/
@@ -3126,6 +3232,7 @@ static int check_pow_hid0_74xx (CPUPPCState *env)
                               PPC_CACHE_DCBZ |                                \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401   (PPC_NONE)
 #define POWERPC_MSRM_401     (0x00000000000FD201ULL)
 #define POWERPC_MMU_401      (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_401     (POWERPC_EXCP_40x)
@@ -3145,6 +3252,9 @@ static void init_proc_401 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 401x2                                                             */
@@ -3155,6 +3265,7 @@ static void init_proc_401 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x2 (PPC_NONE)
 #define POWERPC_MSRM_401x2   (0x00000000001FD231ULL)
 #define POWERPC_MMU_401x2    (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_401x2   (POWERPC_EXCP_40x)
@@ -3175,12 +3286,16 @@ static void init_proc_401x2 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_4xx_softmmu(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 401x3                                                             */
@@ -3191,6 +3306,7 @@ static void init_proc_401x2 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x3 (PPC_NONE)
 #define POWERPC_MSRM_401x3   (0x00000000001FD631ULL)
 #define POWERPC_MMU_401x3    (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_401x3   (POWERPC_EXCP_40x)
@@ -3213,6 +3329,9 @@ static void init_proc_401x3 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* IOP480                                                                    */
@@ -3223,6 +3342,7 @@ static void init_proc_401x3 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_IOP480 (PPC_NONE)
 #define POWERPC_MSRM_IOP480  (0x00000000001FD231ULL)
 #define POWERPC_MMU_IOP480   (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_IOP480  (POWERPC_EXCP_40x)
@@ -3243,12 +3363,16 @@ static void init_proc_IOP480 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_4xx_softmmu(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 403                                                               */
@@ -3258,6 +3382,7 @@ static void init_proc_IOP480 (CPUPPCState *env)
                               PPC_CACHE_DCBZ |                                \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403   (PPC_NONE)
 #define POWERPC_MSRM_403     (0x000000000007D00DULL)
 #define POWERPC_MMU_403      (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_403     (POWERPC_EXCP_40x)
@@ -3278,6 +3403,9 @@ static void init_proc_403 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 403 GCX                                                           */
@@ -3288,6 +3416,7 @@ static void init_proc_403 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403GCX (PPC_NONE)
 #define POWERPC_MSRM_403GCX  (0x000000000007D00DULL)
 #define POWERPC_MMU_403GCX   (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_403GCX  (POWERPC_EXCP_40x)
@@ -3320,12 +3449,16 @@ static void init_proc_403GCX (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_4xx_softmmu(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 405                                                               */
@@ -3336,6 +3469,7 @@ static void init_proc_403GCX (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP)
+#define POWERPC_INSNS2_405   (PPC_NONE)
 #define POWERPC_MSRM_405     (0x000000000006E630ULL)
 #define POWERPC_MMU_405      (POWERPC_MMU_SOFT_4xx)
 #define POWERPC_EXCP_405     (POWERPC_EXCP_40x)
@@ -3367,12 +3501,16 @@ static void init_proc_405 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_4xx_softmmu(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 440 EP                                                            */
@@ -3383,6 +3521,7 @@ static void init_proc_405 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440EP (PPC_NONE)
 #define POWERPC_MSRM_440EP   (0x000000000006D630ULL)
 #define POWERPC_MMU_440EP    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440EP   (POWERPC_EXCP_BOOKE)
@@ -3448,11 +3587,15 @@ static void init_proc_440EP (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440 GP                                                            */
@@ -3463,6 +3606,7 @@ static void init_proc_440EP (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB |       \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440GP (PPC_NONE)
 #define POWERPC_MSRM_440GP   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440GP    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440GP   (POWERPC_EXCP_BOOKE)
@@ -3510,11 +3654,15 @@ static void init_proc_440GP (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440x4                                                             */
@@ -3525,6 +3673,7 @@ static void init_proc_440GP (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440x4 (PPC_NONE)
 #define POWERPC_MSRM_440x4   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440x4    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440x4   (POWERPC_EXCP_BOOKE)
@@ -3572,11 +3721,15 @@ static void init_proc_440x4 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440x5                                                             */
@@ -3587,6 +3740,7 @@ static void init_proc_440x4 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440x5 (PPC_NONE)
 #define POWERPC_MSRM_440x5   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440x5    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440x5   (POWERPC_EXCP_BOOKE)
@@ -3651,11 +3805,15 @@ static void init_proc_440x5 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 460 (guessed)                                                     */
@@ -3667,6 +3825,7 @@ static void init_proc_440x5 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_460   (PPC_NONE)
 #define POWERPC_MSRM_460     (0x000000000006FF30ULL)
 #define POWERPC_MMU_460      (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_460     (POWERPC_EXCP_BOOKE)
@@ -3737,11 +3896,15 @@ static void init_proc_460 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 460F (guessed)                                                    */
@@ -3756,6 +3919,7 @@ static void init_proc_460 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_460F  (PPC_NONE)
 #define POWERPC_MSRM_460     (0x000000000006FF30ULL)
 #define POWERPC_MMU_460F     (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_460F    (POWERPC_EXCP_BOOKE)
@@ -3826,11 +3990,15 @@ static void init_proc_460F (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* Freescale 5xx cores (aka RCPU) */
@@ -3838,6 +4006,7 @@ static void init_proc_460F (CPUPPCState *env)
                               PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
                               PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \
                               PPC_MFTB)
+#define POWERPC_INSNS2_MPC5xx (PPC_NONE)
 #define POWERPC_MSRM_MPC5xx  (0x000000000001FF43ULL)
 #define POWERPC_MMU_MPC5xx   (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_MPC5xx  (POWERPC_EXCP_603)
@@ -3864,6 +4033,7 @@ static void init_proc_MPC5xx (CPUPPCState *env)
 #define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING  |                  \
                               PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
                               PPC_CACHE_ICBI | PPC_MFTB)
+#define POWERPC_INSNS2_MPC8xx (PPC_NONE)
 #define POWERPC_MSRM_MPC8xx  (0x000000000001F673ULL)
 #define POWERPC_MMU_MPC8xx   (POWERPC_MMU_MPC8xx)
 #define POWERPC_EXCP_MPC8xx  (POWERPC_EXCP_603)
@@ -3895,6 +4065,7 @@ static void init_proc_MPC8xx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2    (PPC_NONE)
 #define POWERPC_MSRM_G2      (0x000000000006FFF2ULL)
 #define POWERPC_MMU_G2       (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_G2      (POWERPC_EXCP_G2)
@@ -3952,6 +4123,7 @@ static void init_proc_G2 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2LE  (PPC_NONE)
 #define POWERPC_MSRM_G2LE    (0x000000000007FFF3ULL)
 #define POWERPC_MMU_G2LE     (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_G2LE    (POWERPC_EXCP_G2)
@@ -4018,8 +4190,9 @@ static void init_proc_G2LE (CPUPPCState *env)
                               PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
                               PPC_MEM_TLBSYNC | PPC_TLBIVAX |                 \
                               PPC_BOOKE)
+#define POWERPC_INSNS2_e200  (PPC_NONE)
 #define POWERPC_MSRM_e200    (0x000000000606FF30ULL)
-#define POWERPC_MMU_e200     (POWERPC_MMU_BOOKE_FSL)
+#define POWERPC_MMU_e200     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e200    (POWERPC_EXCP_BOOKE)
 #define POWERPC_INPUT_e200   (PPC_FLAGS_INPUT_BookE)
 #define POWERPC_BFDM_e200    (bfd_mach_ppc_860)
@@ -4040,7 +4213,7 @@ static void init_proc_e200 (CPUPPCState *env)
                  &spr_read_spefscr, &spr_write_spefscr,
                  0x00000000);
     /* Memory management */
-    gen_spr_BookE_FSL(env, 0x0000005D);
+    gen_spr_BookE206(env, 0x0000005D, NULL);
     /* XXX : not implemented */
     spr_register(env, SPR_HID0, "HID0",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4111,6 +4284,11 @@ static void init_proc_e200 (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
     spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
@@ -4123,6 +4301,7 @@ static void init_proc_e200 (CPUPPCState *env)
     env->nb_tlb = 64;
     env->nb_ways = 1;
     env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
 #endif
     init_excp_e200(env);
     env->dcache_line_size = 32;
@@ -4138,6 +4317,7 @@ static void init_proc_e200 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_e300  (PPC_NONE)
 #define POWERPC_MSRM_e300    (0x000000000007FFF3ULL)
 #define POWERPC_MMU_e300     (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_e300    (POWERPC_EXCP_603)
@@ -4187,10 +4367,10 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
-                                PPC_BOOKE)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206)
 #define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
-#define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE_FSL)
+#define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e500v1    (POWERPC_EXCP_BOOKE)
 #define POWERPC_INPUT_e500v1   (PPC_FLAGS_INPUT_BookE)
 #define POWERPC_BFDM_e500v1    (bfd_mach_ppc_860)
@@ -4198,7 +4378,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 POWERPC_FLAG_UBLE | POWERPC_FLAG_DE |   \
                                 POWERPC_FLAG_BUS_CLK)
 #define check_pow_e500v1       check_pow_hid0
-#define init_proc_e500v1       init_proc_e500
+#define init_proc_e500v1       init_proc_e500v1
 
 /* e500v2 core                                                               */
 #define POWERPC_INSNS_e500v2   (PPC_INSNS_BASE | PPC_ISEL |             \
@@ -4206,10 +4386,10 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
-                                PPC_BOOKE)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206)
 #define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
-#define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE_FSL)
+#define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e500v2    (POWERPC_EXCP_BOOKE)
 #define POWERPC_INPUT_e500v2   (PPC_FLAGS_INPUT_BookE)
 #define POWERPC_BFDM_e500v2    (bfd_mach_ppc_860)
@@ -4217,13 +4397,23 @@ static void init_proc_e300 (CPUPPCState *env)
                                 POWERPC_FLAG_UBLE | POWERPC_FLAG_DE |   \
                                 POWERPC_FLAG_BUS_CLK)
 #define check_pow_e500v2       check_pow_hid0
-#define init_proc_e500v2       init_proc_e500
+#define init_proc_e500v2       init_proc_e500v2
 
-static void init_proc_e500 (CPUPPCState *env)
+static void init_proc_e500 (CPUPPCState *env, int version)
 {
+    uint32_t tlbncfg[2];
+#if !defined(CONFIG_USER_ONLY)
+    int i;
+#endif
+
     /* Time base */
     gen_tbl(env);
-    gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+    /*
+     * XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
+     *     complain when accessing them.
+     * gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+     */
+    gen_spr_BookE(env, 0x0000000F0000FFFFULL);
     /* Processor identification */
     spr_register(env, SPR_BOOKE_PIR, "PIR",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4237,8 +4427,24 @@ static void init_proc_e500 (CPUPPCState *env)
     /* Memory management */
 #if !defined(CONFIG_USER_ONLY)
     env->nb_pids = 3;
+    env->nb_ways = 2;
+    env->id_tlbs = 0;
+    switch (version) {
+    case 1:
+        /* e500v1 */
+        tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+        break;
+    case 2:
+        /* e500v2 */
+        tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+        break;
+    default:
+        cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
+    }
 #endif
-    gen_spr_BookE_FSL(env, 0x0000005F);
+    gen_spr_BookE206(env, 0x000000DF, tlbncfg);
     /* XXX : not implemented */
     spr_register(env, SPR_HID0, "HID0",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4287,23 +4493,13 @@ static void init_proc_e500 (CPUPPCState *env)
     /* XXX : not implemented */
     spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_e500_l1csr0,
                  0x00000000);
     /* XXX : not implemented */
     spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
-    /* XXX : not implemented */
-    spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
-    /* XXX : not implemented */
-    spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
     spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
@@ -4312,11 +4508,19 @@ static void init_proc_e500 (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke206_mmucsr0,
+                 0x00000000);
+
 #if !defined(CONFIG_USER_ONLY)
-    env->nb_tlb = 64;
-    env->nb_ways = 1;
-    env->id_tlbs = 0;
+    env->nb_tlb = 0;
+    env->tlb_type = TLB_MAS;
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        env->nb_tlb += booke206_tlb_size(env, i);
+    }
 #endif
+
     init_excp_e200(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
@@ -4324,6 +4528,16 @@ static void init_proc_e500 (CPUPPCState *env)
     ppce500_irq_init(env);
 }
 
+static void init_proc_e500v1(CPUPPCState *env)
+{
+    init_proc_e500(env, 1);
+}
+
+static void init_proc_e500v2(CPUPPCState *env)
+{
+    init_proc_e500(env, 2);
+}
+
 /* Non-embedded PowerPC                                                      */
 
 /* POWER : same as 601, without mfmsr, mfsr                                  */
@@ -4339,6 +4553,7 @@ static void init_proc_e500 (CPUPPCState *env)
                               PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601   (PPC_NONE)
 #define POWERPC_MSRM_601     (0x000000000000FD70ULL)
 #define POWERPC_MSRR_601     (0x0000000000001040ULL)
 //#define POWERPC_MMU_601      (POWERPC_MMU_601)
@@ -4391,6 +4606,7 @@ static void init_proc_601 (CPUPPCState *env)
                               PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601v  (PPC_NONE)
 #define POWERPC_MSRM_601v    (0x000000000000FD70ULL)
 #define POWERPC_MSRR_601v    (0x0000000000001040ULL)
 #define POWERPC_MMU_601v     (POWERPC_MMU_601)
@@ -4418,6 +4634,7 @@ static void init_proc_601v (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \
                               PPC_SEGMENT | PPC_602_SPEC)
+#define POWERPC_INSNS2_602   (PPC_NONE)
 #define POWERPC_MSRM_602     (0x0000000000C7FF73ULL)
 /* XXX: 602 MMU is quite specific. Should add a special case */
 #define POWERPC_MMU_602      (POWERPC_MMU_SOFT_6xx)
@@ -4463,6 +4680,7 @@ static void init_proc_602 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603   (PPC_NONE)
 #define POWERPC_MSRM_603     (0x000000000007FF73ULL)
 #define POWERPC_MMU_603      (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_603     (POWERPC_EXCP_603)
@@ -4507,6 +4725,7 @@ static void init_proc_603 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603E  (PPC_NONE)
 #define POWERPC_MSRM_603E    (0x000000000007FF73ULL)
 #define POWERPC_MMU_603E     (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_603E    (POWERPC_EXCP_603E)
@@ -4556,6 +4775,7 @@ static void init_proc_603E (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604   (PPC_NONE)
 #define POWERPC_MSRM_604     (0x000000000005FF77ULL)
 #define POWERPC_MMU_604      (POWERPC_MMU_32B)
 //#define POWERPC_EXCP_604     (POWERPC_EXCP_604)
@@ -4594,6 +4814,7 @@ static void init_proc_604 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604E  (PPC_NONE)
 #define POWERPC_MSRM_604E    (0x000000000005FF77ULL)
 #define POWERPC_MMU_604E     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_604E    (POWERPC_EXCP_604)
@@ -4652,6 +4873,7 @@ static void init_proc_604E (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_740   (PPC_NONE)
 #define POWERPC_MSRM_740     (0x000000000005FF77ULL)
 #define POWERPC_MMU_740      (POWERPC_MMU_32B)
 #define POWERPC_EXCP_740     (POWERPC_EXCP_7x0)
@@ -4697,6 +4919,7 @@ static void init_proc_740 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750   (PPC_NONE)
 #define POWERPC_MSRM_750     (0x000000000005FF77ULL)
 #define POWERPC_MMU_750      (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750     (POWERPC_EXCP_7x0)
@@ -4788,6 +5011,7 @@ static void init_proc_750 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cl (PPC_NONE)
 #define POWERPC_MSRM_750cl   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750cl    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750cl   (POWERPC_EXCP_7x0)
@@ -4926,6 +5150,7 @@ static void init_proc_750cl (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cx (PPC_NONE)
 #define POWERPC_MSRM_750cx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750cx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750cx   (POWERPC_EXCP_7x0)
@@ -4983,6 +5208,7 @@ static void init_proc_750cx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750fx (PPC_NONE)
 #define POWERPC_MSRM_750fx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750fx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750fx   (POWERPC_EXCP_7x0)
@@ -5045,6 +5271,7 @@ static void init_proc_750fx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750gx (PPC_NONE)
 #define POWERPC_MSRM_750gx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750gx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750gx   (POWERPC_EXCP_7x0)
@@ -5107,6 +5334,7 @@ static void init_proc_750gx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_745   (PPC_NONE)
 #define POWERPC_MSRM_745     (0x000000000005FF77ULL)
 #define POWERPC_MMU_745      (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_745     (POWERPC_EXCP_7x5)
@@ -5160,6 +5388,7 @@ static void init_proc_745 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_755   (PPC_NONE)
 #define POWERPC_MSRM_755     (0x000000000005FF77ULL)
 #define POWERPC_MMU_755      (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_755     (POWERPC_EXCP_7x5)
@@ -5228,6 +5457,7 @@ static void init_proc_755 (CPUPPCState *env)
                               PPC_MEM_TLBIA |                                 \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7400  (PPC_NONE)
 #define POWERPC_MSRM_7400    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7400     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_7400    (POWERPC_EXCP_74xx)
@@ -5280,6 +5510,7 @@ static void init_proc_7400 (CPUPPCState *env)
                               PPC_MEM_TLBIA |                                 \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7410  (PPC_NONE)
 #define POWERPC_MSRM_7410    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7410     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_7410    (POWERPC_EXCP_74xx)
@@ -5338,6 +5569,7 @@ static void init_proc_7410 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7440  (PPC_NONE)
 #define POWERPC_MSRM_7440    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7440     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7440    (POWERPC_EXCP_74xx)
@@ -5423,6 +5655,7 @@ static void init_proc_7440 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7450  (PPC_NONE)
 #define POWERPC_MSRM_7450    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7450     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7450    (POWERPC_EXCP_74xx)
@@ -5534,6 +5767,7 @@ static void init_proc_7450 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7445  (PPC_NONE)
 #define POWERPC_MSRM_7445    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7445     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7445    (POWERPC_EXCP_74xx)
@@ -5648,6 +5882,7 @@ static void init_proc_7445 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7455  (PPC_NONE)
 #define POWERPC_MSRM_7455    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7455     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7455    (POWERPC_EXCP_74xx)
@@ -5764,6 +5999,7 @@ static void init_proc_7455 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7457  (PPC_NONE)
 #define POWERPC_MSRM_7457    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7457     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7457    (POWERPC_EXCP_74xx)
@@ -5903,6 +6139,7 @@ static void init_proc_7457 (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970   (PPC_NONE)
 #define POWERPC_MSRM_970     (0x900000000204FF36ULL)
 #define POWERPC_MMU_970      (POWERPC_MMU_64B)
 //#define POWERPC_EXCP_970     (POWERPC_EXCP_970)
@@ -5998,6 +6235,7 @@ static void init_proc_970 (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970FX (PPC_NONE)
 #define POWERPC_MSRM_970FX   (0x800000000204FF36ULL)
 #define POWERPC_MMU_970FX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970FX   (POWERPC_EXCP_970)
@@ -6099,6 +6337,7 @@ static void init_proc_970FX (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970GX (PPC_NONE)
 #define POWERPC_MSRM_970GX   (0x800000000204FF36ULL)
 #define POWERPC_MMU_970GX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970GX   (POWERPC_EXCP_970)
@@ -6188,6 +6427,7 @@ static void init_proc_970GX (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970MP (PPC_NONE)
 #define POWERPC_MSRM_970MP   (0x900000000204FF36ULL)
 #define POWERPC_MMU_970MP    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970MP   (POWERPC_EXCP_970)
@@ -6267,6 +6507,87 @@ 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_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP)
+#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 | POWERPC_FLAG_CFAR)
+#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);
+    spr_register(env, SPR_CFAR, "SPR_CFAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_cfar, &spr_write_cfar,
+                 0x00000000);
+    spr_register(env, SPR_DSCR, "SPR_DSCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 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 |   \
@@ -6277,6 +6598,7 @@ static void init_proc_970MP (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_64B | PPC_SLBI)
+#define POWERPC_INSNS2_620   (PPC_NONE)
 #define POWERPC_MSRM_620     (0x800000000005FF77ULL)
 //#define POWERPC_MMU_620      (POWERPC_MMU_620)
 #define POWERPC_EXCP_620     (POWERPC_EXCP_970)
@@ -6312,6 +6634,7 @@ static void init_proc_620 (CPUPPCState *env)
 /* Default 32 bits PowerPC target will be 604 */
 #define CPU_POWERPC_PPC32     CPU_POWERPC_604
 #define POWERPC_INSNS_PPC32   POWERPC_INSNS_604
+#define POWERPC_INSNS2_PPC32  POWERPC_INSNS2_604
 #define POWERPC_MSRM_PPC32    POWERPC_MSRM_604
 #define POWERPC_MMU_PPC32     POWERPC_MMU_604
 #define POWERPC_EXCP_PPC32    POWERPC_EXCP_604
@@ -6324,6 +6647,7 @@ static void init_proc_620 (CPUPPCState *env)
 /* Default 64 bits PowerPC target will be 970 FX */
 #define CPU_POWERPC_PPC64     CPU_POWERPC_970FX
 #define POWERPC_INSNS_PPC64   POWERPC_INSNS_970FX
+#define POWERPC_INSNS2_PPC64  POWERPC_INSNS2_970FX
 #define POWERPC_MSRM_PPC64    POWERPC_MSRM_970FX
 #define POWERPC_MMU_PPC64     POWERPC_MMU_970FX
 #define POWERPC_EXCP_PPC64    POWERPC_EXCP_970FX
@@ -6335,27 +6659,29 @@ static void init_proc_620 (CPUPPCState *env)
 
 /* Default PowerPC target will be PowerPC 32 */
 #if defined (TARGET_PPC64) && 0 // XXX: TODO
-#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC64
-#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64
-#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC64
-#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC64
-#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC64
-#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64
-#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC64
-#define POWERPC_FLAG_DEFAULT  POWERPC_FLAG_PPC64
-#define check_pow_DEFAULT     check_pow_PPC64
-#define init_proc_DEFAULT     init_proc_PPC64
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC64
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC64
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC64
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC64
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC64
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC64
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC64
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC64
+#define check_pow_DEFAULT      check_pow_PPC64
+#define init_proc_DEFAULT      init_proc_PPC64
 #else
-#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC32
-#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32
-#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC32
-#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC32
-#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC32
-#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32
-#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC32
-#define POWERPC_FLAG_DEFAULT  POWERPC_FLAG_PPC32
-#define check_pow_DEFAULT     check_pow_PPC32
-#define init_proc_DEFAULT     init_proc_PPC32
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC32
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC32
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC32
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC32
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC32
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC32
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC32
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC32
+#define check_pow_DEFAULT      check_pow_PPC32
+#define init_proc_DEFAULT      init_proc_PPC32
 #endif
 
 /*****************************************************************************/
@@ -6989,6 +7315,10 @@ 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_POWER7_v21         = 0x003F0201,
+    CPU_POWERPC_POWER7_v23         = 0x003F0203,
     CPU_POWERPC_970                = 0x00390202,
 #define CPU_POWERPC_970FX            CPU_POWERPC_970FX_v31
     CPU_POWERPC_970FX_v10          = 0x00391100,
@@ -7202,18 +7532,19 @@ enum {
 /* PowerPC CPU definitions                                                   */
 #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type)                             \
     {                                                                         \
-        .name        = _name,                                                 \
-        .pvr         = _pvr,                                                  \
-        .svr         = _svr,                                                  \
-        .insns_flags = glue(POWERPC_INSNS_,_type),                            \
-        .msr_mask    = glue(POWERPC_MSRM_,_type),                             \
-        .mmu_model   = glue(POWERPC_MMU_,_type),                              \
-        .excp_model  = glue(POWERPC_EXCP_,_type),                             \
-        .bus_model   = glue(POWERPC_INPUT_,_type),                            \
-        .bfd_mach    = glue(POWERPC_BFDM_,_type),                             \
-        .flags       = glue(POWERPC_FLAG_,_type),                             \
-        .init_proc   = &glue(init_proc_,_type),                               \
-        .check_pow   = &glue(check_pow_,_type),                               \
+        .name         = _name,                                                \
+        .pvr          = _pvr,                                                 \
+        .svr          = _svr,                                                 \
+        .insns_flags  = glue(POWERPC_INSNS_,_type),                           \
+        .insns_flags2 = glue(POWERPC_INSNS2_,_type),                          \
+        .msr_mask     = glue(POWERPC_MSRM_,_type),                            \
+        .mmu_model    = glue(POWERPC_MMU_,_type),                             \
+        .excp_model   = glue(POWERPC_EXCP_,_type),                            \
+        .bus_model    = glue(POWERPC_INPUT_,_type),                           \
+        .bfd_mach     = glue(POWERPC_BFDM_,_type),                            \
+        .flags        = glue(POWERPC_FLAG_,_type),                            \
+        .init_proc    = &glue(init_proc_,_type),                              \
+        .check_pow    = &glue(check_pow_,_type),                              \
     }
 #define POWERPC_DEF(_name, _pvr, _type)                                       \
 POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type)
@@ -8791,6 +9122,11 @@ 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_DEF("POWER7_v2.1",   CPU_POWERPC_POWER7_v21,             POWER7),
+    POWERPC_DEF("POWER7_v2.3",   CPU_POWERPC_POWER7_v23,             POWER7),
     /* PowerPC 970                                                           */
     POWERPC_DEF("970",           CPU_POWERPC_970,                    970),
     /* PowerPC 970FX (G5)                                                    */
@@ -8897,7 +9233,7 @@ static const ppc_def_t ppc_defs[] = {
 };
 
 /*****************************************************************************/
-/* Generic CPU instanciation routine                                         */
+/* Generic CPU instantiation routine                                         */
 static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
 {
 #if !defined(CONFIG_USER_ONLY)
@@ -8914,6 +9250,7 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
     env->nb_BATs = 0;
     env->nb_tlb = 0;
     env->nb_ways = 0;
+    env->tlb_type = TLB_NONE;
 #endif
     /* Register SPR common to all PowerPC implementations */
     gen_spr_generic(env);
@@ -9038,7 +9375,17 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
         int nb_tlb = env->nb_tlb;
         if (env->id_tlbs != 0)
             nb_tlb *= 2;
-        env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+        switch (env->tlb_type) {
+        case TLB_6XX:
+            env->tlb.tlb6 = g_malloc0(nb_tlb * sizeof(ppc6xx_tlb_t));
+            break;
+        case TLB_EMB:
+            env->tlb.tlbe = g_malloc0(nb_tlb * sizeof(ppcemb_tlb_t));
+            break;
+        case TLB_MAS:
+            env->tlb.tlbm = g_malloc0(nb_tlb * sizeof(ppcmas_tlb_t));
+            break;
+        }
         /* Pre-compute some useful values */
         env->tlb_per_way = env->nb_tlb / env->nb_ways;
     }
@@ -9285,7 +9632,8 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
 
     fill_new_table(env->opcodes, 0x40);
     for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
-        if ((opc->handler.type & def->insns_flags) != 0) {
+        if (((opc->handler.type & def->insns_flags) != 0) ||
+            ((opc->handler.type2 & def->insns_flags2) != 0)) {
             if (register_insn(env->opcodes, opc) < 0) {
                 printf("*** ERROR initializing PowerPC instruction "
                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
@@ -9381,8 +9729,7 @@ static int gdb_get_float_reg(CPUState *env, uint8_t *mem_buf, int n)
         return 8;
     }
     if (n == 32) {
-        /* FPSCR not implemented  */
-        memset(mem_buf, 0, 4);
+        stl_p(mem_buf, env->fpscr);
         return 4;
     }
     return 0;
@@ -9498,6 +9845,23 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
     env->excp_model = def->excp_model;
     env->bus_model = def->bus_model;
     env->insns_flags = def->insns_flags;
+    env->insns_flags2 = def->insns_flags2;
+    if (!kvm_enabled()) {
+        /* TCG doesn't (yet) emulate some groups of instructions that
+         * are implemented on some otherwise supported CPUs (e.g. VSX
+         * and decimal floating point instructions on POWER7).  We
+         * remove unsupported instruction groups from the cpu state's
+         * instruction masks and hope the guest can cope.  For at
+         * least the pseries machine, the unavailability of these
+         * instructions can be advertise to the guest via the device
+         * tree.
+         *
+         * FIXME: we should have a similar masking for CPU features
+         * not accessible under KVM, but so far, there aren't any of
+         * those. */
+        env->insns_flags &= PPC_TCG_INSNS;
+        env->insns_flags2 &= PPC_TCG_INSNS2;
+    }
     env->flags = def->flags;
     env->bfd_mach = def->bfd_mach;
     env->check_pow = def->check_pow;
@@ -9547,8 +9911,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
         case POWERPC_MMU_BOOKE:
             mmu_model = "PowerPC BookE";
             break;
-        case POWERPC_MMU_BOOKE_FSL:
-            mmu_model = "PowerPC BookE FSL";
+        case POWERPC_MMU_BOOKE206:
+            mmu_model = "PowerPC BookE 2.06";
             break;
         case POWERPC_MMU_601:
             mmu_model = "PowerPC 601";
@@ -9683,42 +10047,34 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
     return 0;
 }
 
-static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr)
+static bool ppc_cpu_usable(const ppc_def_t *def)
 {
-    const ppc_def_t *ret;
-    uint32_t pvr_rev;
-    int i, best, match, best_match, max;
+#if defined(TARGET_PPCEMB)
+    /* When using the ppcemb target, we only support 440 style cores */
+    if (def->mmu_model != POWERPC_MMU_BOOKE) {
+        return false;
+    }
+#endif
 
-    ret = NULL;
-    max = ARRAY_SIZE(ppc_defs);
-    best = -1;
-    pvr_rev = pvr & 0xFFFF;
-    /* We want all specified bits to match */
-    best_match = 32 - ctz32(pvr_rev);
-    for (i = 0; i < max; i++) {
-        /* We check that the 16 higher bits are the same to ensure the CPU
-         * model will be the choosen one.
-         */
-        if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) {
-            /* We want as much as possible of the low-level 16 bits
-             * to be the same but we allow inexact matches.
-             */
-            match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF));
-            /* We check '>=' instead of '>' because the PPC_defs table
-             * is ordered by increasing revision.
-             * Then, we will match the higher revision compatible
-             * with the requested PVR
-             */
-            if (match >= best_match) {
-                best = i;
-                best_match = match;
-            }
+    return true;
+}
+
+const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
+        if (!ppc_cpu_usable(&ppc_defs[i])) {
+            continue;
+        }
+
+        /* If we have an exact match, we're done */
+        if (pvr == ppc_defs[i].pvr) {
+            return &ppc_defs[i];
         }
     }
-    if (best != -1)
-        ret = &ppc_defs[best];
 
-    return ret;
+    return NULL;
 }
 
 #include <ctype.h>
@@ -9729,6 +10085,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name)
     const char *p;
     int i, max, len;
 
+    if (kvm_enabled() && (strcasecmp(name, "host") == 0)) {
+        return kvmppc_host_cpu_def();
+    }
+
     /* Check if the given name is a PVR */
     len = strlen(name);
     if (len == 10 && name[0] == '0' && name[1] == 'x') {
@@ -9747,6 +10107,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name)
     ret = NULL;
     max = ARRAY_SIZE(ppc_defs);
     for (i = 0; i < max; i++) {
+        if (!ppc_cpu_usable(&ppc_defs[i])) {
+            continue;
+        }
+
         if (strcasecmp(name, ppc_defs[i].name) == 0) {
             ret = &ppc_defs[i];
             break;
@@ -9762,6 +10126,10 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
 
     max = ARRAY_SIZE(ppc_defs);
     for (i = 0; i < max; i++) {
+        if (!ppc_cpu_usable(&ppc_defs[i])) {
+            continue;
+        }
+
         (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
                        ppc_defs[i].name, ppc_defs[i].pvr);
     }
index e47c372fbd7307b24772e142ac1c35c96901a568..202c098ee087bd2907a4362ca2f8e4073856bf5b 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,42 +62,217 @@ 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_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];
+
+    int ext_index;
 
     CPU_COMMON
+
+    /* reset does memset(0) up to here */
+
+    int cpu_num;
+    uint8_t *storage_keys;
+
+    uint64_t tod_offset;
+    uint64_t tod_basetime;
+    QEMUTimer *tod_timer;
+
+    QEMUTimer *cpu_timer;
 } 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
@@ -94,44 +280,85 @@ void cpu_s390x_close(CPUS390XState *s);
 int cpu_s390x_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmuu);
+                                int mmu_idx);
 #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);
+
+#ifdef CONFIG_KVM
+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);
+#else
+static inline void kvm_s390_interrupt(CPUState *env, int type, uint32_t code)
+{
+}
+
+static inline void kvm_s390_virtio_irq(CPUState *env, int config_change,
+                                       uint64_t token)
+{
+}
+
+static inline void kvm_s390_interrupt_internal(CPUState *env, int type,
+                                               uint32_t parm, uint64_t parm64,
+                                               int vm)
+{
+}
+#endif
 CPUState *s390_cpu_addr2state(uint16_t cpu_addr);
+void s390_add_running_cpu(CPUState *env);
+unsigned s390_del_running_cpu(CPUState *env);
+
+/* from s390-virtio-bus */
+extern const target_phys_addr_t virtio_size;
+
+#else
+static inline void s390_add_running_cpu(CPUState *env)
+{
+}
+
+static inline unsigned s390_del_running_cpu(CPUState *env)
+{
+    return 0;
+}
 #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 +492,500 @@ 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 */
+} QEMU_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    */
+
+#define SK_C                    (0x1 << 1)
+#define SK_R                    (0x1 << 2)
+#define SK_F                    (0x1 << 3)
+#define SK_ACC_MASK             (0xf << 4)
+
+
+/* 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);
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (env->psw.mask & PSW_MASK_EXT);
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
+{
+    env->psw.addr = tb->pc;
+}
 
 #endif
index 4a5297be181ef9bf193327f2088844112edb0e6a..10cc9dd5fa54c8c1dfca5747e36b611b8b6dcbc4 100644 (file)
@@ -2,6 +2,7 @@
  *  S/390 helpers
  *
  *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2011 Alexander Graf
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <string.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "gdbstub.h"
 #include "qemu-common.h"
+#include "qemu-timer.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu.h"
+#endif
+
+//#define DEBUG_S390
+//#define DEBUG_S390_PTE
+//#define DEBUG_S390_STDOUT
+
+#ifdef DEBUG_S390
+#ifdef DEBUG_S390_STDOUT
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); \
+         qemu_log(fmt, ##__VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
+#endif
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
 
-#include <linux/kvm.h>
-#include "kvm.h"
+#ifdef DEBUG_S390_PTE
+#define PTE_DPRINTF DPRINTF
+#else
+#define PTE_DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#ifndef CONFIG_USER_ONLY
+static void s390x_tod_timer(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->pending_int |= INTERRUPT_TOD;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void s390x_cpu_timer(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->pending_int |= INTERRUPT_CPUTIMER;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
+#endif
 
 CPUS390XState *cpu_s390x_init(const char *cpu_model)
 {
     CPUS390XState *env;
+#if !defined (CONFIG_USER_ONLY)
+    struct tm tm;
+#endif
     static int inited = 0;
+    static int cpu_num = 0;
 
-    env = qemu_mallocz(sizeof(CPUS390XState));
+    env = g_malloc0(sizeof(CPUS390XState));
     cpu_exec_init(env);
-    if (!inited) {
+    if (tcg_enabled() && !inited) {
         inited = 1;
+        s390x_translate_init();
     }
 
+#if !defined(CONFIG_USER_ONLY)
+    qemu_get_timedate(&tm, 0);
+    env->tod_offset = TOD_UNIX_EPOCH +
+                      (time2tod(mktimegm(&tm)) * 1000000000ULL);
+    env->tod_basetime = 0;
+    env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
+    env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
+#endif
     env->cpu_model_str = cpu_model;
+    env->cpu_num = cpu_num++;
+    env->ext_index = -1;
     cpu_reset(env);
     qemu_init_vcpu(env);
     return env;
 }
 
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                                int mmu_idx)
+{
+    /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n",
+            __FUNCTION__, address, rw, mmu_idx); */
+    env->exception_index = EXCP_ADDR;
+    env->__excp_addr = address; /* FIXME: find out how this works on a real machine */
+    return 1;
+}
+
+#endif /* CONFIG_USER_ONLY */
+
 void cpu_reset(CPUS390XState *env)
 {
     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
@@ -56,29 +134,515 @@ void cpu_reset(CPUS390XState *env)
     memset(env, 0, offsetof(CPUS390XState, breakpoints));
     /* FIXME: reset vector? */
     tlb_flush(env, 1);
+    s390_add_running_cpu(env);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+/* Ensure to exit the TB after this call! */
+static void trigger_pgm_exception(CPUState *env, uint32_t code, uint32_t ilc)
+{
+    env->exception_index = EXCP_PGM;
+    env->int_pgm_code = code;
+    env->int_pgm_ilc = ilc;
+}
+
+static int trans_bits(CPUState *env, uint64_t mode)
+{
+    int bits = 0;
+
+    switch (mode) {
+    case PSW_ASC_PRIMARY:
+        bits = 1;
+        break;
+    case PSW_ASC_SECONDARY:
+        bits = 2;
+        break;
+    case PSW_ASC_HOME:
+        bits = 3;
+        break;
+    default:
+        cpu_abort(env, "unknown asc mode\n");
+        break;
+    }
+
+    return bits;
+}
+
+static void trigger_prot_fault(CPUState *env, target_ulong vaddr, uint64_t mode)
+{
+    int ilc = ILC_LATER_INC_2;
+    int bits = trans_bits(env, mode) | 4;
+
+    DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+
+    stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
+    trigger_pgm_exception(env, PGM_PROTECTION, ilc);
+}
+
+static void trigger_page_fault(CPUState *env, target_ulong vaddr, uint32_t type,
+                               uint64_t asc, int rw)
+{
+    int ilc = ILC_LATER;
+    int bits = trans_bits(env, asc);
+
+    if (rw == 2) {
+        /* code has is undefined ilc */
+        ilc = 2;
+    }
+
+    DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+
+    stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
+    trigger_pgm_exception(env, type, ilc);
 }
 
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+static int mmu_translate_asce(CPUState *env, target_ulong vaddr, uint64_t asc,
+                              uint64_t asce, int level, target_ulong *raddr,
+                              int *flags, int rw)
 {
+    uint64_t offs = 0;
+    uint64_t origin;
+    uint64_t new_asce;
+
+    PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce);
+
+    if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) ||
+        ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) {
+        /* XXX different regions have different faults */
+        DPRINTF("%s: invalid region\n", __FUNCTION__);
+        trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw);
+        return -1;
+    }
+
+    if ((level <= _ASCE_TYPE_MASK) && ((asce & _ASCE_TYPE_MASK) != level)) {
+        trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+        return -1;
+    }
+
+    if (asce & _ASCE_REAL_SPACE) {
+        /* direct mapping */
+
+        *raddr = vaddr;
+        return 0;
+    }
+
+    origin = asce & _ASCE_ORIGIN;
+
+    switch (level) {
+    case _ASCE_TYPE_REGION1 + 4:
+        offs = (vaddr >> 50) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION1:
+        offs = (vaddr >> 39) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION2:
+        offs = (vaddr >> 28) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION3:
+        offs = (vaddr >> 17) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_SEGMENT:
+        offs = (vaddr >> 9) & 0x07f8;
+        origin = asce & _SEGMENT_ENTRY_ORIGIN;
+        break;
+    }
+
+    /* XXX region protection flags */
+    /* *flags &= ~PAGE_WRITE */
+
+    new_asce = ldq_phys(origin + offs);
+    PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
+                __FUNCTION__, origin, offs, new_asce);
+
+    if (level != _ASCE_TYPE_SEGMENT) {
+        /* yet another region */
+        return mmu_translate_asce(env, vaddr, asc, new_asce, level - 4, raddr,
+                                  flags, rw);
+    }
+
+    /* PTE */
+    if (new_asce & _PAGE_INVALID) {
+        DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce);
+        trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw);
+        return -1;
+    }
+
+    if (new_asce & _PAGE_RO) {
+        *flags &= ~PAGE_WRITE;
+    }
+
+    *raddr = new_asce & _ASCE_ORIGIN;
+
+    PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce);
+
     return 0;
 }
 
-#ifndef CONFIG_USER_ONLY
+static int mmu_translate_asc(CPUState *env, target_ulong vaddr, uint64_t asc,
+                             target_ulong *raddr, int *flags, int rw)
+{
+    uint64_t asce = 0;
+    int level, new_level;
+    int r;
 
-int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                                int mmu_idx, int is_softmmu)
+    switch (asc) {
+    case PSW_ASC_PRIMARY:
+        PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__);
+        asce = env->cregs[1];
+        break;
+    case PSW_ASC_SECONDARY:
+        PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__);
+        asce = env->cregs[7];
+        break;
+    case PSW_ASC_HOME:
+        PTE_DPRINTF("%s: asc=home\n", __FUNCTION__);
+        asce = env->cregs[13];
+        break;
+    }
+
+    switch (asce & _ASCE_TYPE_MASK) {
+    case _ASCE_TYPE_REGION1:
+        break;
+    case _ASCE_TYPE_REGION2:
+        if (vaddr & 0xffe0000000000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xffe0000000000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    case _ASCE_TYPE_REGION3:
+        if (vaddr & 0xfffffc0000000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xfffffc0000000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    case _ASCE_TYPE_SEGMENT:
+        if (vaddr & 0xffffffff80000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xffffffff80000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    }
+
+    /* fake level above current */
+    level = asce & _ASCE_TYPE_MASK;
+    new_level = level + 4;
+    asce = (asce & ~_ASCE_TYPE_MASK) | (new_level & _ASCE_TYPE_MASK);
+
+    r = mmu_translate_asce(env, vaddr, asc, asce, new_level, raddr, flags, rw);
+
+    if ((rw == 1) && !(*flags & PAGE_WRITE)) {
+        trigger_prot_fault(env, vaddr, asc);
+        return -1;
+    }
+
+    return r;
+}
+
+int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc,
+                  target_ulong *raddr, int *flags)
+{
+    int r = -1;
+    uint8_t *sk;
+
+    *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    vaddr &= TARGET_PAGE_MASK;
+
+    if (!(env->psw.mask & PSW_MASK_DAT)) {
+        *raddr = vaddr;
+        r = 0;
+        goto out;
+    }
+
+    switch (asc) {
+    case PSW_ASC_PRIMARY:
+    case PSW_ASC_HOME:
+        r = mmu_translate_asc(env, vaddr, asc, raddr, flags, rw);
+        break;
+    case PSW_ASC_SECONDARY:
+        /*
+         * Instruction: Primary
+         * Data: Secondary
+         */
+        if (rw == 2) {
+            r = mmu_translate_asc(env, vaddr, PSW_ASC_PRIMARY, raddr, flags,
+                                  rw);
+            *flags &= ~(PAGE_READ | PAGE_WRITE);
+        } else {
+            r = mmu_translate_asc(env, vaddr, PSW_ASC_SECONDARY, raddr, flags,
+                                  rw);
+            *flags &= ~(PAGE_EXEC);
+        }
+        break;
+    case PSW_ASC_ACCREG:
+    default:
+        hw_error("guest switched to unknown asc mode\n");
+        break;
+    }
+
+out:
+    /* Convert real address -> absolute address */
+    if (*raddr < 0x2000) {
+        *raddr = *raddr + env->psa;
+    }
+
+    if (*raddr <= ram_size) {
+        sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE];
+        if (*flags & PAGE_READ) {
+            *sk |= SK_R;
+        }
+
+        if (*flags & PAGE_WRITE) {
+            *sk |= SK_C;
+        }
+    }
+
+    return r;
+}
+
+int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong _vaddr, int rw,
+                                int mmu_idx)
 {
-    target_ulong phys;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    target_ulong vaddr, raddr;
     int prot;
 
-    /* XXX: implement mmu */
+    DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n",
+            __FUNCTION__, _vaddr, rw, mmu_idx);
+
+    _vaddr &= TARGET_PAGE_MASK;
+    vaddr = _vaddr;
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        vaddr &= 0x7fffffff;
+    }
+
+    if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot)) {
+        /* Translation ended in exception */
+        return 1;
+    }
+
+    /* check out of RAM access */
+    if (raddr > (ram_size + virtio_size)) {
+        DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__,
+                (uint64_t)aaddr, (uint64_t)ram_size);
+        trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER);
+        return 1;
+    }
 
-    phys = address;
-    prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__,
+            (uint64_t)vaddr, (uint64_t)raddr, prot);
 
-    tlb_set_page(env, address & TARGET_PAGE_MASK,
-                 phys & TARGET_PAGE_MASK, prot,
+    tlb_set_page(env, _vaddr, raddr, prot,
                  mmu_idx, TARGET_PAGE_SIZE);
+
     return 0;
 }
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong vaddr)
+{
+    target_ulong raddr;
+    int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    int old_exc = env->exception_index;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        vaddr &= 0x7fffffff;
+    }
+
+    mmu_translate(env, vaddr, 2, asc, &raddr, &prot);
+    env->exception_index = old_exc;
+
+    return raddr;
+}
+
+void load_psw(CPUState *env, uint64_t mask, uint64_t addr)
+{
+    if (mask & PSW_MASK_WAIT) {
+        if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) {
+            if (s390_del_running_cpu(env) == 0) {
+#ifndef CONFIG_USER_ONLY
+                qemu_system_shutdown_request();
+#endif
+            }
+        }
+        env->halted = 1;
+        env->exception_index = EXCP_HLT;
+    }
+
+    env->psw.addr = addr;
+    env->psw.mask = mask;
+    env->cc_op = (mask >> 13) & 3;
+}
+
+static uint64_t get_psw_mask(CPUState *env)
+{
+    uint64_t r = env->psw.mask;
+
+    env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
+
+    r &= ~(3ULL << 13);
+    assert(!(env->cc_op & ~3));
+    r |= env->cc_op << 13;
+
+    return r;
+}
+
+static void do_svc_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
+    lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc);
+    lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc));
+    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
+    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    load_psw(env, mask, addr);
+}
+
+static void do_program_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+    int ilc = env->int_pgm_ilc;
+
+    switch (ilc) {
+    case ILC_LATER:
+        ilc = get_ilc(ldub_code(env->psw.addr));
+        break;
+    case ILC_LATER_INC:
+        ilc = get_ilc(ldub_code(env->psw.addr));
+        env->psw.addr += ilc * 2;
+        break;
+    case ILC_LATER_INC_2:
+        ilc = get_ilc(ldub_code(env->psw.addr)) * 2;
+        env->psw.addr += ilc;
+        break;
+    }
+
+    qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc);
+
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->pgm_ilc = cpu_to_be16(ilc);
+    lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
+    lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
+    mask = be64_to_cpu(lowcore->program_new_psw.mask);
+    addr = be64_to_cpu(lowcore->program_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+            env->int_pgm_code, ilc, env->psw.mask,
+            env->psw.addr);
+
+    load_psw(env, mask, addr);
+}
+
+#define VIRTIO_SUBCODE_64 0x0D00
+
+static void do_ext_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+    ExtQueue *q;
+
+    if (!(env->psw.mask & PSW_MASK_EXT)) {
+        cpu_abort(env, "Ext int w/o ext mask\n");
+    }
+
+    if (env->ext_index < 0 || env->ext_index > MAX_EXT_QUEUE) {
+        cpu_abort(env, "Ext queue overrun: %d\n", env->ext_index);
+    }
+
+    q = &env->ext_queue[env->ext_index];
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->ext_int_code = cpu_to_be16(q->code);
+    lowcore->ext_params = cpu_to_be32(q->param);
+    lowcore->ext_params2 = cpu_to_be64(q->param64);
+    lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
+    lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64);
+    mask = be64_to_cpu(lowcore->external_new_psw.mask);
+    addr = be64_to_cpu(lowcore->external_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    env->ext_index--;
+    if (env->ext_index == -1) {
+        env->pending_int &= ~INTERRUPT_EXT;
+    }
+
+    DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+            env->psw.mask, env->psw.addr);
+
+    load_psw(env, mask, addr);
+}
+
+void do_interrupt (CPUState *env)
+{
+    qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index,
+             env->psw.addr);
+
+    s390_add_running_cpu(env);
+    /* handle external interrupts */
+    if ((env->psw.mask & PSW_MASK_EXT) &&
+        env->exception_index == -1) {
+        if (env->pending_int & INTERRUPT_EXT) {
+            /* code is already in env */
+            env->exception_index = EXCP_EXT;
+        } else if (env->pending_int & INTERRUPT_TOD) {
+            cpu_inject_ext(env, 0x1004, 0, 0);
+            env->exception_index = EXCP_EXT;
+            env->pending_int &= ~INTERRUPT_EXT;
+            env->pending_int &= ~INTERRUPT_TOD;
+        } else if (env->pending_int & INTERRUPT_CPUTIMER) {
+            cpu_inject_ext(env, 0x1005, 0, 0);
+            env->exception_index = EXCP_EXT;
+            env->pending_int &= ~INTERRUPT_EXT;
+            env->pending_int &= ~INTERRUPT_TOD;
+        }
+    }
+
+    switch (env->exception_index) {
+    case EXCP_PGM:
+        do_program_interrupt(env);
+        break;
+    case EXCP_SVC:
+        do_svc_interrupt(env);
+        break;
+    case EXCP_EXT:
+        do_ext_interrupt(env);
+        break;
+    }
+    env->exception_index = -1;
+
+    if (!env->pending_int) {
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+}
+
 #endif /* CONFIG_USER_ONLY */
diff --git a/target-s390x/helpers.h b/target-s390x/helpers.h
new file mode 100644 (file)
index 0000000..01c8d0e
--- /dev/null
@@ -0,0 +1,152 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_3(nc, i32, i32, i64, i64)
+DEF_HELPER_3(oc, i32, i32, i64, i64)
+DEF_HELPER_3(xc, i32, i32, i64, i64)
+DEF_HELPER_3(mvc, void, i32, i64, i64)
+DEF_HELPER_3(clc, i32, i32, i64, i64)
+DEF_HELPER_2(mvcl, i32, i32, i32)
+DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32)
+DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64)
+DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32)
+DEF_HELPER_3(clm, i32, i32, i32, i64)
+DEF_HELPER_3(stcm, void, i32, i32, i64)
+DEF_HELPER_2(mlg, void, i32, i64)
+DEF_HELPER_2(dlg, void, i32, i64)
+DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64)
+DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32)
+DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64)
+DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32)
+DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_3(srst, i32, i32, i32, i32)
+DEF_HELPER_3(clst, i32, i32, i32, i32)
+DEF_HELPER_3(mvpg, void, i64, i64, i64)
+DEF_HELPER_3(mvst, void, i32, i32, i32)
+DEF_HELPER_3(csg, i32, i32, i64, i32)
+DEF_HELPER_3(cdsg, i32, i32, i64, i32)
+DEF_HELPER_3(cs, i32, i32, i64, i32)
+DEF_HELPER_4(ex, i32, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32)
+DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32)
+DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64)
+DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64)
+DEF_HELPER_3(stcmh, void, i32, i64, i32)
+DEF_HELPER_3(icmh, i32, i32, i64, i32)
+DEF_HELPER_2(ipm, void, i32, i32)
+DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_3(stam, void, i32, i64, i32)
+DEF_HELPER_3(lam, void, i32, i64, i32)
+DEF_HELPER_3(mvcle, i32, i32, i64, i32)
+DEF_HELPER_3(clcle, i32, i32, i64, i32)
+DEF_HELPER_3(slb, i32, i32, i32, i32)
+DEF_HELPER_4(slbg, i32, i32, i32, i64, i64)
+DEF_HELPER_2(cefbr, void, i32, s32)
+DEF_HELPER_2(cdfbr, void, i32, s32)
+DEF_HELPER_2(cxfbr, void, i32, s32)
+DEF_HELPER_2(cegbr, void, i32, s64)
+DEF_HELPER_2(cdgbr, void, i32, s64)
+DEF_HELPER_2(cxgbr, void, i32, s64)
+DEF_HELPER_2(adbr, i32, i32, i32)
+DEF_HELPER_2(aebr, i32, i32, i32)
+DEF_HELPER_2(sebr, i32, i32, i32)
+DEF_HELPER_2(sdbr, i32, i32, i32)
+DEF_HELPER_2(debr, void, i32, i32)
+DEF_HELPER_2(dxbr, void, i32, i32)
+DEF_HELPER_2(mdbr, void, i32, i32)
+DEF_HELPER_2(mxbr, void, i32, i32)
+DEF_HELPER_2(ldebr, void, i32, i32)
+DEF_HELPER_2(ldxbr, void, i32, i32)
+DEF_HELPER_2(lxdbr, void, i32, i32)
+DEF_HELPER_2(ledbr, void, i32, i32)
+DEF_HELPER_2(lexbr, void, i32, i32)
+DEF_HELPER_2(lpebr, i32, i32, i32)
+DEF_HELPER_2(lpdbr, i32, i32, i32)
+DEF_HELPER_2(lpxbr, i32, i32, i32)
+DEF_HELPER_2(ltebr, i32, i32, i32)
+DEF_HELPER_2(ltdbr, i32, i32, i32)
+DEF_HELPER_2(ltxbr, i32, i32, i32)
+DEF_HELPER_2(lcebr, i32, i32, i32)
+DEF_HELPER_2(lcdbr, i32, i32, i32)
+DEF_HELPER_2(lcxbr, i32, i32, i32)
+DEF_HELPER_2(aeb, void, i32, i32)
+DEF_HELPER_2(deb, void, i32, i32)
+DEF_HELPER_2(meeb, void, i32, i32)
+DEF_HELPER_2(cdb, i32, i32, i64)
+DEF_HELPER_2(adb, i32, i32, i64)
+DEF_HELPER_2(seb, void, i32, i32)
+DEF_HELPER_2(sdb, i32, i32, i64)
+DEF_HELPER_2(mdb, void, i32, i64)
+DEF_HELPER_2(ddb, void, i32, i64)
+DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_3(cgebr, i32, i32, i32, i32)
+DEF_HELPER_3(cgdbr, i32, i32, i32, i32)
+DEF_HELPER_3(cgxbr, i32, i32, i32, i32)
+DEF_HELPER_1(lzer, void, i32)
+DEF_HELPER_1(lzdr, void, i32)
+DEF_HELPER_1(lzxr, void, i32)
+DEF_HELPER_3(cfebr, i32, i32, i32, i32)
+DEF_HELPER_3(cfdbr, i32, i32, i32, i32)
+DEF_HELPER_3(cfxbr, i32, i32, i32, i32)
+DEF_HELPER_2(axbr, i32, i32, i32)
+DEF_HELPER_2(sxbr, i32, i32, i32)
+DEF_HELPER_2(meebr, void, i32, i32)
+DEF_HELPER_2(ddbr, void, i32, i32)
+DEF_HELPER_3(madb, void, i32, i64, i32)
+DEF_HELPER_3(maebr, void, i32, i32, i32)
+DEF_HELPER_3(madbr, void, i32, i32, i32)
+DEF_HELPER_3(msdbr, void, i32, i32, i32)
+DEF_HELPER_2(ldeb, void, i32, i64)
+DEF_HELPER_2(lxdb, void, i32, i64)
+DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_2(flogr, i32, i32, i64)
+DEF_HELPER_2(sqdbr, void, i32, i32)
+DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32)
+DEF_HELPER_3(unpk, void, i32, i64, i64)
+DEF_HELPER_3(tr, void, i32, i64, i64)
+
+DEF_HELPER_2(servc, i32, i32, i64)
+DEF_HELPER_3(diag, i64, i32, i64, i64)
+DEF_HELPER_2(load_psw, void, i64, i64)
+DEF_HELPER_1(program_interrupt, void, i32)
+DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64)
+DEF_HELPER_1(stck, i32, i64)
+DEF_HELPER_1(stcke, i32, i64)
+DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64)
+DEF_HELPER_3(stsi, i32, i64, i32, i32)
+DEF_HELPER_3(lctl, void, i32, i64, i32)
+DEF_HELPER_3(lctlg, void, i32, i64, i32)
+DEF_HELPER_3(stctl, void, i32, i64, i32)
+DEF_HELPER_3(stctg, void, i32, i64, i32)
+DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64)
+DEF_HELPER_FLAGS_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64)
+DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64)
+DEF_HELPER_2(csp, i32, i32, i32)
+DEF_HELPER_3(mvcs, i32, i64, i64, i64)
+DEF_HELPER_3(mvcp, i32, i64, i64, i64)
+DEF_HELPER_3(sigp, i32, i64, i32, i64)
+DEF_HELPER_1(sacf, void, i64)
+DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64)
+DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void)
+DEF_HELPER_2(lra, i32, i64, i32)
+DEF_HELPER_2(stura, void, i64, i32)
+DEF_HELPER_2(cksm, void, i32, i32)
+
+DEF_HELPER_FLAGS_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
+                   i32, i32, i64, i64, i64)
+
+#include "def-helper.h"
index 38823f54f732fc7ae1ddc23a3797f8ec61c3b489..b1404bfd2f07beff2466775b22cd5be0c174de24 100644 (file)
 #define DIAG_KVM_HYPERCALL              0x500
 #define DIAG_KVM_BREAKPOINT             0x501
 
-#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
-
 #define ICPT_INSTRUCTION                0x04
 #define ICPT_WAITPSW                    0x1c
 #define ICPT_SOFT_INTERCEPT             0x24
@@ -169,23 +162,21 @@ int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
 {
-    return 0;
 }
 
-int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
-    return 0;
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
-    return 0;
+    return env->halted;
 }
 
-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;
@@ -194,9 +185,6 @@ static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
         return;
     }
 
-    env->halted = 0;
-    env->exception_index = -1;
-
     kvmint.type = type;
     kvmint.parm = parm;
     kvmint.parm64 = parm64;
@@ -219,7 +207,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);
 }
@@ -229,16 +217,17 @@ static void enter_pgmcheck(CPUState *env, uint16_t code)
     kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
 }
 
-static void setcc(CPUState *env, uint64_t cc)
+static inline void setcc(CPUState *env, uint64_t cc)
 {
-    env->kvm_run->psw_mask &= ~(3ul << 44);
+    env->kvm_run->psw_mask &= ~(3ull << 44);
     env->kvm_run->psw_mask |= (cc & 3) << 44;
 
     env->psw.mask &= ~(3ul << 44);
     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;
@@ -248,35 +237,11 @@ static int sclp_service_call(CPUState *env, struct kvm_run *run, uint16_t ipbh0)
     sccb = env->regs[ipbh0 & 0xf];
     code = env->regs[(ipbh0 & 0xf0) >> 4];
 
-    dprintf("sclp(0x%x, 0x%lx)\n", sccb, code);
-
-    if (sccb & ~0x7ffffff8ul) {
-        fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
-        r = -1;
-        goto out;
-    }
-
-    switch(code) {
-        case SCLP_CMDW_READ_SCP_INFO:
-        case SCLP_CMDW_READ_SCP_INFO_FORCED:
-            stw_phys(sccb + SCP_MEM_CODE, ram_size >> 20);
-            stb_phys(sccb + SCP_INCREMENT, 1);
-            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
-            setcc(env, 0);
-
-            kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
-                                        sccb & ~3, 0, 1);
-            break;
-        default:
-            dprintf("KVM: invalid sclp call 0x%x / 0x%lx\n", sccb, code);
-            r = -1;
-            break;
-    }
-
-out:
-    if (r < 0) {
+    r = sclp_service_call(env, sccb, code);
+    if (r) {
         setcc(env, 3);
     }
+
     return 0;
 }
 
@@ -288,7 +253,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);
@@ -301,12 +266,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)
@@ -332,8 +295,7 @@ static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code)
 static int s390_cpu_restart(CPUState *env)
 {
     kvm_s390_interrupt(env, KVM_S390_RESTART, 0);
-    env->halted = 0;
-    env->exception_index = -1;
+    s390_add_running_cpu(env);
     qemu_cpu_kick(env);
     dprintf("DONE: SIGP cpu restart: %p\n", env);
     return 0;
@@ -410,7 +372,7 @@ static int handle_sigp(CPUState *env, struct kvm_run *run, uint8_t ipa1)
             r = s390_cpu_initial_reset(target_env);
             break;
         default:
-            fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", ipa1);
+            fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code);
             break;
     }
 
@@ -442,7 +404,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)
@@ -451,23 +413,23 @@ static int handle_intercept(CPUState *env)
     int icpt_code = run->s390_sieic.icptcode;
     int r = 0;
 
-    dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code, env->kvm_run->psw_addr);
+    dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code,
+            (long)env->kvm_run->psw_addr);
     switch (icpt_code) {
         case ICPT_INSTRUCTION:
             r = handle_instruction(env, run);
             break;
         case ICPT_WAITPSW:
-            /* XXX What to do on system shutdown? */
-            env->halted = 1;
-            env->exception_index = EXCP_HLT;
+        case ICPT_CPU_STOP:
+            if (s390_del_running_cpu(env) == 0) {
+                qemu_system_shutdown_request();
+            }
+            r = EXCP_HALTED;
             break;
         case ICPT_SOFT_INTERCEPT:
             fprintf(stderr, "KVM unimplemented icpt SOFT\n");
             exit(1);
             break;
-        case ICPT_CPU_STOP:
-            qemu_system_shutdown_request();
-            break;
         case ICPT_IO:
             fprintf(stderr, "KVM unimplemented icpt IO\n");
             exit(1);
@@ -498,6 +460,9 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
             break;
     }
 
+    if (ret == 0) {
+        ret = EXCP_INTERRUPT;
+    }
     return ret;
 }
 
@@ -505,3 +470,13 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return true;
 }
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
index 402df2d85e50819e71c754d361d68e5b1e00b56f..5ddc7b93caf7e681041c51b16d57c8ab7b517f8a 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  S/390 helper routines
  *
+ *  Copyright (c) 2009 Ulrich Hecht
  *  Copyright (c) 2009 Alexander Graf
  *
  * This library is free software; you can redistribute it and/or
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "host-utils.h"
+#include "helpers.h"
+#include <string.h>
+#include "kvm.h"
+#include "qemu-timer.h"
+#ifdef CONFIG_KVM
+#include <linux/kvm.h>
+#endif
+
+#if !defined (CONFIG_USER_ONLY)
+#include "sysemu.h"
+#endif
 
 /*****************************************************************************/
 /* Softmmu support */
 #if !defined (CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
 
 #define MMUSUFFIX _mmu
 
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
@@ -61,13 +75,2952 @@ 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 */
-        /* helper_raise_exception_err(env->exception_index, env->error_code); */
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
 
 #endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* raise an exception */
+void HELPER(exception)(uint32_t excp)
+{
+    HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void mvc_fast_memset(CPUState *env, uint32_t l, uint64_t dest,
+                            uint8_t byte)
+{
+    target_phys_addr_t dest_phys;
+    target_phys_addr_t len = l;
+    void *dest_p;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    int flags;
+
+    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+        stb(dest, byte);
+        cpu_abort(env, "should never reach here");
+    }
+    dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+
+    memset(dest_p, byte, len);
+
+    cpu_physical_memory_unmap(dest_p, 1, len, len);
+}
+
+static void mvc_fast_memmove(CPUState *env, uint32_t l, uint64_t dest,
+                             uint64_t src)
+{
+    target_phys_addr_t dest_phys;
+    target_phys_addr_t src_phys;
+    target_phys_addr_t len = l;
+    void *dest_p;
+    void *src_p;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    int flags;
+
+    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+        stb(dest, 0);
+        cpu_abort(env, "should never reach here");
+    }
+    dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+    if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
+        ldub(src);
+        cpu_abort(env, "should never reach here");
+    }
+    src_phys |= src & ~TARGET_PAGE_MASK;
+
+    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+    src_p = cpu_physical_memory_map(src_phys, &len, 0);
+
+    memmove(dest_p, src_p, len);
+
+    cpu_physical_memory_unmap(dest_p, 1, len, len);
+    cpu_physical_memory_unmap(src_p, 0, len, len);
+}
+#endif
+
+/* and on array */
+uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) & ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* xor on array */
+uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+    /* xor with itself is the same as memset(0) */
+    if ((l > 32) && (src == dest) &&
+        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
+        mvc_fast_memset(env, l + 1, dest, 0);
+        return 0;
+    }
+#else
+    if (src == dest) {
+        memset(g2h(dest), 0, l + 1);
+        return 0;
+    }
+#endif
+
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) ^ ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* or on array */
+uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) | ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* memmove */
+void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i = 0;
+    int x = 0;
+    uint32_t l_64 = (l + 1) / 8;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+    if ((l > 32) &&
+        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
+        (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
+        if (dest == (src + 1)) {
+            mvc_fast_memset(env, l + 1, dest, ldub(src));
+            return;
+        } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+            mvc_fast_memmove(env, l + 1, dest, src);
+            return;
+        }
+    }
+#else
+    if (dest == (src + 1)) {
+        memset(g2h(dest), ldub(src), l + 1);
+        return;
+    } else {
+        memmove(g2h(dest), g2h(src), l + 1);
+        return;
+    }
+#endif
+
+    /* handle the parts that fit into 8-byte loads/stores */
+    if (dest != (src + 1)) {
+        for (i = 0; i < l_64; i++) {
+            stq(dest + x, ldq(src + x));
+            x += 8;
+        }
+    }
+
+    /* slow version crossing pages with byte accesses */
+    for (i = x; i <= l; i++) {
+        stb(dest + i, ldub(src + i));
+    }
+}
+
+/* compare unsigned byte arrays */
+uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
+{
+    int i;
+    unsigned char x,y;
+    uint32_t cc;
+    HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
+               __FUNCTION__, l, s1, s2);
+    for (i = 0; i <= l; i++) {
+        x = ldub(s1 + i);
+        y = ldub(s2 + i);
+        HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
+        if (x < y) {
+            cc = 1;
+            goto done;
+        } else if (x > y) {
+            cc = 2;
+            goto done;
+        }
+    }
+    cc = 0;
+done:
+    HELPER_LOG("\n");
+    return cc;
+}
+
+/* compare logical under mask */
+uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
+{
+    uint8_t r,d;
+    uint32_t cc;
+    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1,
+               mask, addr);
+    cc = 0;
+    while (mask) {
+        if (mask & 8) {
+            d = ldub(addr);
+            r = (r1 & 0xff000000UL) >> 24;
+            HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
+                        addr);
+            if (r < d) {
+                cc = 1;
+                break;
+            } else if (r > d) {
+                cc = 2;
+                break;
+            }
+            addr++;
+        }
+        mask = (mask << 1) & 0xf;
+        r1 <<= 8;
+    }
+    HELPER_LOG("\n");
+    return cc;
+}
+
+/* store character under mask */
+void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
+{
+    uint8_t r;
+    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask,
+               addr);
+    while (mask) {
+        if (mask & 8) {
+            r = (r1 & 0xff000000UL) >> 24;
+            stb(addr, r);
+            HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
+            addr++;
+        }
+        mask = (mask << 1) & 0xf;
+        r1 <<= 8;
+    }
+    HELPER_LOG("\n");
+}
+
+/* 64/64 -> 128 unsigned multiplication */
+void HELPER(mlg)(uint32_t r1, uint64_t v2)
+{
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+    /* assuming 64-bit hosts have __uint128_t */
+    __uint128_t res = (__uint128_t)env->regs[r1 + 1];
+    res *= (__uint128_t)v2;
+    env->regs[r1] = (uint64_t)(res >> 64);
+    env->regs[r1 + 1] = (uint64_t)res;
+#else
+    mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
+#endif
+}
+
+/* 128 -> 64/64 unsigned division */
+void HELPER(dlg)(uint32_t r1, uint64_t v2)
+{
+    uint64_t divisor = v2;
+
+    if (!env->regs[r1]) {
+        /* 64 -> 64/64 case */
+        env->regs[r1] = env->regs[r1+1] % divisor;
+        env->regs[r1+1] = env->regs[r1+1] / divisor;
+        return;
+    } else {
+
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+        /* assuming 64-bit hosts have __uint128_t */
+        __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
+                               (env->regs[r1+1]);
+        __uint128_t quotient = dividend / divisor;
+        env->regs[r1+1] = quotient;
+        __uint128_t remainder = dividend % divisor;
+        env->regs[r1] = remainder;
+#else
+        /* 32-bit hosts would need special wrapper functionality - just abort if
+           we encounter such a case; it's very unlikely anyways. */
+        cpu_abort(env, "128 -> 64/64 division not implemented\n");
+#endif
+    }
+}
+
+static inline uint64_t get_address(int x2, int b2, int d2)
+{
+    uint64_t r = d2;
+
+    if (x2) {
+        r += env->regs[x2];
+    }
+
+    if (b2) {
+        r += env->regs[b2];
+    }
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        r &= 0x7fffffff;
+    }
+
+    return r;
+}
+
+static inline uint64_t get_address_31fix(int reg)
+{
+    uint64_t r = env->regs[reg];
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        r &= 0x7fffffff;
+    }
+
+    return r;
+}
+
+/* search string (c is byte to search, r2 is string, r1 end of string) */
+uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t i;
+    uint32_t cc = 2;
+    uint64_t str = get_address_31fix(r2);
+    uint64_t end = get_address_31fix(r1);
+
+    HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__,
+               c, env->regs[r1], env->regs[r2]);
+
+    for (i = str; i != end; i++) {
+        if (ldub(i) == c) {
+            env->regs[r1] = i;
+            cc = 1;
+            break;
+        }
+    }
+
+    return cc;
+}
+
+/* unsigned string compare (c is string terminator) */
+uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t s1 = get_address_31fix(r1);
+    uint64_t s2 = get_address_31fix(r2);
+    uint8_t v1, v2;
+    uint32_t cc;
+    c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+    if (!c) {
+        HELPER_LOG("%s: comparing '%s' and '%s'\n",
+                   __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2));
+    }
+#endif
+    for (;;) {
+        v1 = ldub(s1);
+        v2 = ldub(s2);
+        if ((v1 == c || v2 == c) || (v1 != v2)) {
+            break;
+        }
+        s1++;
+        s2++;
+    }
+
+    if (v1 == v2) {
+        cc = 0;
+    } else {
+        cc = (v1 < v2) ? 1 : 2;
+        /* FIXME: 31-bit mode! */
+        env->regs[r1] = s1;
+        env->regs[r2] = s2;
+    }
+    return cc;
+}
+
+/* move page */
+void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
+{
+    /* XXX missing r0 handling */
+#ifdef CONFIG_USER_ONLY
+    int i;
+
+    for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+        stb(r1 + i, ldub(r2 + i));
+    }
+#else
+    mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
+#endif
+}
+
+/* string copy (c is string terminator) */
+void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t src = get_address_31fix(r2);
+    uint8_t v;
+    c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+    if (!c) {
+        HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src),
+                   dest);
+    }
+#endif
+    for (;;) {
+        v = ldub(src);
+        stb(dest, v);
+        if (v == c) {
+            break;
+        }
+        src++;
+        dest++;
+    }
+    env->regs[r1] = dest; /* FIXME: 31-bit mode! */
+}
+
+/* compare and swap 64-bit */
+uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    uint64_t v2 = ldq(a2);
+    if (env->regs[r1] == v2) {
+        cc = 0;
+        stq(a2, env->regs[r3]);
+    } else {
+        cc = 1;
+        env->regs[r1] = v2;
+    }
+    return cc;
+}
+
+/* compare double and swap 64-bit */
+uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    uint64_t v2_hi = ldq(a2);
+    uint64_t v2_lo = ldq(a2 + 8);
+    uint64_t v1_hi = env->regs[r1];
+    uint64_t v1_lo = env->regs[r1 + 1];
+
+    if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
+        cc = 0;
+        stq(a2, env->regs[r3]);
+        stq(a2 + 8, env->regs[r3 + 1]);
+    } else {
+        cc = 1;
+        env->regs[r1] = v2_hi;
+        env->regs[r1 + 1] = v2_lo;
+    }
+
+    return cc;
+}
+
+/* compare and swap 32-bit */
+uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3);
+    uint32_t v2 = ldl(a2);
+    if (((uint32_t)env->regs[r1]) == v2) {
+        cc = 0;
+        stl(a2, (uint32_t)env->regs[r3]);
+    } else {
+        cc = 1;
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
+    }
+    return cc;
+}
+
+static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 24; /* top of the lower half of r1 */
+    uint64_t rmask = 0xff000000ULL;
+    uint8_t val = 0;
+    int ccd = 0;
+    uint32_t cc = 0;
+
+    while (mask) {
+        if (mask & 8) {
+            env->regs[r1] &= ~rmask;
+            val = ldub(address);
+            if ((val & 0x80) && !ccd) {
+                cc = 1;
+            }
+            ccd = 1;
+            if (val && cc == 0) {
+                cc = 2;
+            }
+            env->regs[r1] |= (uint64_t)val << pos;
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+        rmask >>= 8;
+    }
+
+    return cc;
+}
+
+/* execute instruction
+   this instruction executes an insn modified with the contents of r1
+   it does not change the executed instruction in memory
+   it does not change the program counter
+   in other words: tricky...
+   currently implemented by interpreting the cases it is most commonly used in
+ */
+uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
+{
+    uint16_t insn = lduw_code(addr);
+    HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr,
+             insn);
+    if ((insn & 0xf0ff) == 0xd000) {
+        uint32_t l, insn2, b1, b2, d1, d2;
+        l = v1 & 0xff;
+        insn2 = ldl_code(addr + 2);
+        b1 = (insn2 >> 28) & 0xf;
+        b2 = (insn2 >> 12) & 0xf;
+        d1 = (insn2 >> 16) & 0xfff;
+        d2 = insn2 & 0xfff;
+        switch (insn & 0xf00) {
+        case 0x200:
+            helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        case 0x500:
+            cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        case 0x700:
+            cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        case 0xc00:
+            helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        default:
+            goto abort;
+            break;
+        }
+    } else if ((insn & 0xff00) == 0x0a00) {
+        /* supervisor call */
+        HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff);
+        env->psw.addr = ret - 4;
+        env->int_svc_code = (insn|v1) & 0xff;
+        env->int_svc_ilc = 4;
+        helper_exception(EXCP_SVC);
+    } else if ((insn & 0xff00) == 0xbf00) {
+        uint32_t insn2, r1, r3, b2, d2;
+        insn2 = ldl_code(addr + 2);
+        r1 = (insn2 >> 20) & 0xf;
+        r3 = (insn2 >> 16) & 0xf;
+        b2 = (insn2 >> 12) & 0xf;
+        d2 = insn2 & 0xfff;
+        cc = helper_icm(r1, get_address(0, b2, d2), r3);
+    } else {
+abort:
+        cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
+                  insn);
+    }
+    return cc;
+}
+
+/* absolute value 32-bit */
+uint32_t HELPER(abs_i32)(int32_t val)
+{
+    if (val < 0) {
+        return -val;
+    } else {
+        return val;
+    }
+}
+
+/* negative absolute value 32-bit */
+int32_t HELPER(nabs_i32)(int32_t val)
+{
+    if (val < 0) {
+        return val;
+    } else {
+        return -val;
+    }
+}
+
+/* absolute value 64-bit */
+uint64_t HELPER(abs_i64)(int64_t val)
+{
+    HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val);
+
+    if (val < 0) {
+        return -val;
+    } else {
+        return val;
+    }
+}
+
+/* negative absolute value 64-bit */
+int64_t HELPER(nabs_i64)(int64_t val)
+{
+    if (val < 0) {
+        return val;
+    } else {
+        return -val;
+    }
+}
+
+/* add with carry 32-bit unsigned */
+uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
+{
+    uint32_t res;
+
+    res = v1 + v2;
+    if (cc & 2) {
+        res++;
+    }
+
+    return res;
+}
+
+/* store character under mask high operates on the upper half of r1 */
+void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 56; /* top of the upper half of r1 */
+
+    while (mask) {
+        if (mask & 8) {
+            stb(address, (env->regs[r1] >> pos) & 0xff);
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+    }
+}
+
+/* insert character under mask high; same as icm, but operates on the
+   upper half of r1 */
+uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 56; /* top of the upper half of r1 */
+    uint64_t rmask = 0xff00000000000000ULL;
+    uint8_t val = 0;
+    int ccd = 0;
+    uint32_t cc = 0;
+
+    while (mask) {
+        if (mask & 8) {
+            env->regs[r1] &= ~rmask;
+            val = ldub(address);
+            if ((val & 0x80) && !ccd) {
+                cc = 1;
+            }
+            ccd = 1;
+            if (val && cc == 0) {
+                cc = 2;
+            }
+            env->regs[r1] |= (uint64_t)val << pos;
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+        rmask >>= 8;
+    }
+
+    return cc;
+}
+
+/* insert psw mask and condition code into r1 */
+void HELPER(ipm)(uint32_t cc, uint32_t r1)
+{
+    uint64_t r = env->regs[r1];
+
+    r &= 0xffffffff00ffffffULL;
+    r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf );
+    env->regs[r1] = r;
+    HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__,
+               cc, env->psw.mask, r);
+}
+
+/* load access registers r1 to r3 from memory at a2 */
+void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->aregs[i] = ldl(a2);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* store access registers r1 to r3 in memory at a2 */
+void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stl(a2, env->aregs[i]);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* move long */
+uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
+{
+    uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
+    uint64_t src = get_address_31fix(r2);
+    uint8_t pad = src >> 24;
+    uint8_t v;
+    uint32_t cc;
+
+    if (destlen == srclen) {
+        cc = 0;
+    } else if (destlen < srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+        v = ldub(src);
+        stb(dest, v);
+    }
+
+    for (; destlen; dest++, destlen--) {
+        stb(dest, pad);
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    env->regs[r2 + 1] -= src - env->regs[r2];
+    env->regs[r1] = dest;
+    env->regs[r2] = src;
+
+    return cc;
+}
+
+/* move long extended another memcopy insn with more bells and whistles */
+uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uint64_t destlen = env->regs[r1 + 1];
+    uint64_t dest = env->regs[r1];
+    uint64_t srclen = env->regs[r3 + 1];
+    uint64_t src = env->regs[r3];
+    uint8_t pad = a2 & 0xff;
+    uint8_t v;
+    uint32_t cc;
+
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        destlen = (uint32_t)destlen;
+        srclen = (uint32_t)srclen;
+        dest &= 0x7fffffff;
+        src &= 0x7fffffff;
+    }
+
+    if (destlen == srclen) {
+        cc = 0;
+    } else if (destlen < srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+        v = ldub(src);
+        stb(dest, v);
+    }
+
+    for (; destlen; dest++, destlen--) {
+        stb(dest, pad);
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    /* FIXME: 31-bit mode! */
+    env->regs[r3 + 1] -= src - env->regs[r3];
+    env->regs[r1] = dest;
+    env->regs[r3] = src;
+
+    return cc;
+}
+
+/* compare logical long extended memcompare insn with padding */
+uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uint64_t destlen = env->regs[r1 + 1];
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t srclen = env->regs[r3 + 1];
+    uint64_t src = get_address_31fix(r3);
+    uint8_t pad = a2 & 0xff;
+    uint8_t v1 = 0,v2 = 0;
+    uint32_t cc = 0;
+
+    if (!(destlen || srclen)) {
+        return cc;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
+        v1 = srclen ? ldub(src) : pad;
+        v2 = destlen ? ldub(dest) : pad;
+        if (v1 != v2) {
+            cc = (v1 < v2) ? 1 : 2;
+            break;
+        }
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    env->regs[r3 + 1] -= src - env->regs[r3];
+    env->regs[r1] = dest;
+    env->regs[r3] = src;
+
+    return cc;
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
+{
+    uint32_t v1 = env->regs[r1];
+    uint32_t res = v1 + (~v2) + (cc >> 1);
+
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
+    if (cc & 2) {
+        /* borrow */
+        return v1 ? 1 : 0;
+    } else {
+        return v1 ? 3 : 2;
+    }
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
+{
+    uint64_t res = v1 + (~v2) + (cc >> 1);
+
+    env->regs[r1] = res;
+    if (cc & 2) {
+        /* borrow */
+        return v1 ? 1 : 0;
+    } else {
+        return v1 ? 3 : 2;
+    }
+}
+
+static inline int float_comp_to_cc(int float_compare)
+{
+    switch (float_compare) {
+    case float_relation_equal:
+        return 0;
+    case float_relation_less:
+        return 1;
+    case float_relation_greater:
+        return 2;
+    case float_relation_unordered:
+        return 3;
+    default:
+        cpu_abort(env, "unknown return value for float compare\n");
+    }
+}
+
+/* condition codes for binary FP ops */
+static uint32_t set_cc_f32(float32 v1, float32 v2)
+{
+    return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status));
+}
+
+static uint32_t set_cc_f64(float64 v1, float64 v2)
+{
+    return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status));
+}
+
+/* condition codes for unary FP ops */
+static uint32_t set_cc_nz_f32(float32 v)
+{
+    if (float32_is_any_nan(v)) {
+        return 3;
+    } else if (float32_is_zero(v)) {
+        return 0;
+    } else if (float32_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t set_cc_nz_f64(float64 v)
+{
+    if (float64_is_any_nan(v)) {
+        return 3;
+    } else if (float64_is_zero(v)) {
+        return 0;
+    } else if (float64_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t set_cc_nz_f128(float128 v)
+{
+    if (float128_is_any_nan(v)) {
+        return 3;
+    } else if (float128_is_zero(v)) {
+        return 0;
+    } else if (float128_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+/* convert 32-bit int to 64-bit float */
+void HELPER(cdfbr)(uint32_t f1, int32_t v2)
+{
+    HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 32-bit int to 128-bit float */
+void HELPER(cxfbr)(uint32_t f1, int32_t v2)
+{
+    CPU_QuadU v1;
+    v1.q = int32_to_float128(v2, &env->fpu_status);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* convert 64-bit int to 32-bit float */
+void HELPER(cegbr)(uint32_t f1, int64_t v2)
+{
+    HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 64-bit float */
+void HELPER(cdgbr)(uint32_t f1, int64_t v2)
+{
+    HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 128-bit float */
+void HELPER(cxgbr)(uint32_t f1, int64_t v2)
+{
+    CPU_QuadU x1;
+    x1.q = int64_to_float128(v2, &env->fpu_status);
+    HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2,
+               x1.ll.upper, x1.ll.lower);
+    env->fregs[f1].ll = x1.ll.upper;
+    env->fregs[f1 + 2].ll = x1.ll.lower;
+}
+
+/* convert 32-bit int to 32-bit float */
+void HELPER(cefbr)(uint32_t f1, int32_t v2)
+{
+    env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
+    HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2,
+               env->fregs[f1].l.upper, f1);
+}
+
+/* 32-bit FP addition RR */
+uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
+               env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP addition RR */
+uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__,
+               env->fregs[f2].d, env->fregs[f1].d, f1);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP subtraction RR */
+uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
+               env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP subtraction RR */
+uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+    HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
+               __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP division RR */
+void HELPER(debr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+}
+
+/* 128-bit FP division RR */
+void HELPER(dxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_div(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* 64-bit FP multiplication RR */
+void HELPER(mdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+}
+
+/* 128-bit FP multiplication RR */
+void HELPER(mxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 32-bit float to 64-bit float */
+void HELPER(ldebr)(uint32_t r1, uint32_t r2)
+{
+    env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
+                                          &env->fpu_status);
+}
+
+/* convert 128-bit float to 64-bit float */
+void HELPER(ldxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
+    HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU res;
+    res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 64-bit float to 32-bit float */
+void HELPER(ledbr)(uint32_t f1, uint32_t f2)
+{
+    float64 d2 = env->fregs[f2].d;
+    env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
+}
+
+/* convert 128-bit float to 32-bit float */
+void HELPER(lexbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
+    HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper);
+}
+
+/* absolute value of 32-bit float */
+uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2)
+{
+    float32 v1;
+    float32 v2 = env->fregs[f2].d;
+    v1 = float32_abs(v2);
+    env->fregs[f1].d = v1;
+    return set_cc_nz_f32(v1);
+}
+
+/* absolute value of 64-bit float */
+uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2)
+{
+    float64 v1;
+    float64 v2 = env->fregs[f2].d;
+    v1 = float64_abs(v2);
+    env->fregs[f1].d = v1;
+    return set_cc_nz_f64(v1);
+}
+
+/* absolute value of 128-bit float */
+uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    v1.q = float128_abs(v2.q);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+    return set_cc_nz_f128(v1.q);
+}
+
+/* load and test 64-bit float */
+uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = env->fregs[f2].d;
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load and test 32-bit float */
+uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = env->fregs[f2].l.upper;
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load and test 128-bit float */
+uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x;
+    x.ll.upper = env->fregs[f2].ll;
+    x.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].ll = x.ll.upper;
+    env->fregs[f1 + 2].ll = x.ll.lower;
+    return set_cc_nz_f128(x.q);
+}
+
+/* load complement of 32-bit float */
+uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load complement of 64-bit float */
+uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_chs(env->fregs[f2].d);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load complement of 128-bit float */
+uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x1, x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    x1.q = float128_chs(x2.q);
+    env->fregs[f1].ll = x1.ll.upper;
+    env->fregs[f1 + 2].ll = x1.ll.lower;
+    return set_cc_nz_f128(x1.q);
+}
+
+/* 32-bit FP addition RM */
+void HELPER(aeb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP division RM */
+void HELPER(deb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP multiplication RM */
+void HELPER(meeb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP compare RR */
+uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    float32 v2 = env->fregs[f2].l.upper;;
+    HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2);
+    return set_cc_f32(v1, v2);
+}
+
+/* 64-bit FP compare RR */
+uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
+{
+    float64 v1 = env->fregs[f1].d;
+    float64 v2 = env->fregs[f2].d;;
+    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__,
+               v1, f1, v2);
+    return set_cc_f64(v1, v2);
+}
+
+/* 128-bit FP compare RR */
+uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+
+    return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q,
+                            &env->fpu_status));
+}
+
+/* 64-bit FP compare RM */
+uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1,
+               f1, v2.d);
+    return set_cc_f64(v1, v2.d);
+}
+
+/* 64-bit FP addition RM */
+uint32_t HELPER(adb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
+    return set_cc_nz_f64(v1);
+}
+
+/* 32-bit FP subtraction RM */
+void HELPER(seb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
+}
+
+/* 64-bit FP subtraction RM */
+uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
+    return set_cc_nz_f64(v1);
+}
+
+/* 64-bit FP multiplication RM */
+void HELPER(mdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
+}
+
+/* 64-bit FP division RM */
+void HELPER(ddb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
+}
+
+static void set_round_mode(int m3)
+{
+    switch (m3) {
+    case 0:
+        /* current mode */
+        break;
+    case 1:
+        /* biased round no nearest */
+    case 4:
+        /* round to nearest */
+        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
+        break;
+    case 5:
+        /* round to zero */
+        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
+        break;
+    case 6:
+        /* round to +inf */
+        set_float_rounding_mode(float_round_up, &env->fpu_status);
+        break;
+    case 7:
+        /* round to -inf */
+        set_float_rounding_mode(float_round_down, &env->fpu_status);
+        break;
+    }
+}
+
+/* convert 32-bit float to 64-bit int */
+uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float32 v2 = env->fregs[f2].l.upper;
+    set_round_mode(m3);
+    env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
+    return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 64-bit int */
+uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float64 v2 = env->fregs[f2].d;
+    set_round_mode(m3);
+    env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
+    return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 64-bit int */
+uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    set_round_mode(m3);
+    env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
+    if (float128_is_any_nan(v2.q)) {
+        return 3;
+    } else if (float128_is_zero(v2.q)) {
+        return 0;
+    } else if (float128_is_neg(v2.q)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+/* convert 32-bit float to 32-bit int */
+uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float32 v2 = env->fregs[f2].l.upper;
+    set_round_mode(m3);
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float32_to_int32(v2, &env->fpu_status);
+    return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 32-bit int */
+uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float64 v2 = env->fregs[f2].d;
+    set_round_mode(m3);
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float64_to_int32(v2, &env->fpu_status);
+    return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 32-bit int */
+uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float128_to_int32(v2.q, &env->fpu_status);
+    return set_cc_nz_f128(v2.q);
+}
+
+/* load 32-bit FP zero */
+void HELPER(lzer)(uint32_t f1)
+{
+    env->fregs[f1].l.upper = float32_zero;
+}
+
+/* load 64-bit FP zero */
+void HELPER(lzdr)(uint32_t f1)
+{
+    env->fregs[f1].d = float64_zero;
+}
+
+/* load 128-bit FP zero */
+void HELPER(lzxr)(uint32_t f1)
+{
+    CPU_QuadU x;
+    x.q = float64_to_float128(float64_zero, &env->fpu_status);
+    env->fregs[f1].ll = x.ll.upper;
+    env->fregs[f1 + 1].ll = x.ll.lower;
+}
+
+/* 128-bit FP subtraction RR */
+uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+    return set_cc_nz_f128(res.q);
+}
+
+/* 128-bit FP addition RR */
+uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_add(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+    return set_cc_nz_f128(res.q);
+}
+
+/* 32-bit FP multiplication RR */
+void HELPER(meebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+}
+
+/* 64-bit FP division RR */
+void HELPER(ddbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RM */
+void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3)
+{
+    HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3);
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    env->fregs[f1].d = float64_add(env->fregs[f1].d,
+                                   float64_mul(v2.d, env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RR */
+void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
+    env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
+                                               env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 64-bit FP multiply and subtract RR */
+void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
+    env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
+                                               env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 32-bit FP multiply and add RR */
+void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+                                         float32_mul(env->fregs[f2].l.upper,
+                                                     env->fregs[f3].l.upper,
+                                                     &env->fpu_status),
+                                         &env->fpu_status);
+}
+
+/* convert 32-bit float to 64-bit float */
+void HELPER(ldeb)(uint32_t f1, uint64_t a2)
+{
+    uint32_t v2;
+    v2 = ldl(a2);
+    env->fregs[f1].d = float32_to_float64(v2,
+                                          &env->fpu_status);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdb)(uint32_t f1, uint64_t a2)
+{
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    CPU_QuadU v1;
+    v1.q = float64_to_float128(v2.d, &env->fpu_status);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* test data class 32-bit */
+uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    int neg = float32_is_neg(v1);
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg);
+    if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+        (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+        (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+        (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* test data class 64-bit */
+uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2)
+{
+    float64 v1 = env->fregs[f1].d;
+    int neg = float64_is_neg(v1);
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg);
+    if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+        (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+        (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+        (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* test data class 128-bit */
+uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2)
+{
+    CPU_QuadU v1;
+    uint32_t cc = 0;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+
+    int neg = float128_is_neg(v1.q);
+    if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
+        (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
+        (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
+        (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* find leftmost one */
+uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
+{
+    uint64_t res = 0;
+    uint64_t ov2 = v2;
+
+    while (!(v2 & 0x8000000000000000ULL) && v2) {
+        v2 <<= 1;
+        res++;
+    }
+
+    if (!v2) {
+        env->regs[r1] = 64;
+        env->regs[r1 + 1] = 0;
+        return 0;
+    } else {
+        env->regs[r1] = res;
+        env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
+        return 2;
+    }
+}
+
+/* square root 64-bit RR */
+void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
+}
+
+/* checksum */
+void HELPER(cksm)(uint32_t r1, uint32_t r2)
+{
+    uint64_t src = get_address_31fix(r2);
+    uint64_t src_len = env->regs[(r2 + 1) & 15];
+    uint64_t cksm = (uint32_t)env->regs[r1];
+
+    while (src_len >= 4) {
+        cksm += ldl(src);
+
+        /* move to next word */
+        src_len -= 4;
+        src += 4;
+    }
+
+    switch (src_len) {
+    case 0:
+        break;
+    case 1:
+        cksm += ldub(src) << 24;
+        break;
+    case 2:
+        cksm += lduw(src) << 16;
+        break;
+    case 3:
+        cksm += lduw(src) << 16;
+        cksm += ldub(src + 2) << 8;
+        break;
+    }
+
+    /* indicate we've processed everything */
+    env->regs[r2] = src + src_len;
+    env->regs[(r2 + 1) & 15] = 0;
+
+    /* store result */
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                    ((uint32_t)cksm + (cksm >> 32));
+}
+
+static inline uint32_t cc_calc_ltgt_32(CPUState *env, int32_t src,
+                                       int32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltgt0_32(CPUState *env, int32_t dst)
+{
+    return cc_calc_ltgt_32(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltgt_64(CPUState *env, int64_t src,
+                                       int64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltgt0_64(CPUState *env, int64_t dst)
+{
+    return cc_calc_ltgt_64(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltugtu_32(CPUState *env, uint32_t src,
+                                         uint32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltugtu_64(CPUState *env, uint64_t src,
+                                         uint64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_tm_32(CPUState *env, uint32_t val, uint32_t mask)
+{
+    HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask);
+    uint16_t r = val & mask;
+    if (r == 0 || mask == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        return 1;
+    }
+}
+
+/* set condition code for test under mask */
+static inline uint32_t cc_calc_tm_64(CPUState *env, uint64_t val, uint32_t mask)
+{
+    uint16_t r = val & mask;
+    HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r);
+    if (r == 0 || mask == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        while (!(mask & 0x8000)) {
+            mask <<= 1;
+            val <<= 1;
+        }
+        if (val & 0x8000) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_nz(CPUState *env, uint64_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_add_64(CPUState *env, int64_t a1, int64_t a2,
+                                      int64_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_addu_64(CPUState *env, uint64_t a1, uint64_t a2,
+                                       uint64_t ar)
+{
+    if (ar == 0) {
+        if (a1) {
+            return 2;
+        } else {
+            return 0;
+        }
+    } else {
+        if (ar < a1 || ar < a2) {
+          return 3;
+        } else {
+          return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_sub_64(CPUState *env, int64_t a1, int64_t a2,
+                                      int64_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_subu_64(CPUState *env, uint64_t a1, uint64_t a2,
+                                       uint64_t ar)
+{
+    if (ar == 0) {
+        return 2;
+    } else {
+        if (a2 > a1) {
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_abs_64(CPUState *env, int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static inline uint32_t cc_calc_nabs_64(CPUState *env, int64_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_64(CPUState *env, int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+
+static inline uint32_t cc_calc_add_32(CPUState *env, int32_t a1, int32_t a2,
+                                      int32_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_addu_32(CPUState *env, uint32_t a1, uint32_t a2,
+                                       uint32_t ar)
+{
+    if (ar == 0) {
+        if (a1) {
+          return 2;
+        } else {
+          return 0;
+        }
+    } else {
+        if (ar < a1 || ar < a2) {
+          return 3;
+        } else {
+          return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_sub_32(CPUState *env, int32_t a1, int32_t a2,
+                                      int32_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_subu_32(CPUState *env, uint32_t a1, uint32_t a2,
+                                       uint32_t ar)
+{
+    if (ar == 0) {
+        return 2;
+    } else {
+        if (a2 > a1) {
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_abs_32(CPUState *env, int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static inline uint32_t cc_calc_nabs_32(CPUState *env, int32_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_32(CPUState *env, int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+/* calculate condition code for insert character under mask insn */
+static inline uint32_t cc_calc_icm_32(CPUState *env, uint32_t mask, uint32_t val)
+{
+    HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val);
+    uint32_t cc;
+
+    if (mask == 0xf) {
+        if (!val) {
+            return 0;
+        } else if (val & 0x80000000) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    if (!val || !mask) {
+        cc = 0;
+    } else {
+        while (mask != 1) {
+            mask >>= 1;
+            val >>= 8;
+        }
+        if (val & 0x80) {
+            cc = 1;
+        } else {
+            cc = 2;
+        }
+    }
+    return cc;
+}
+
+static inline uint32_t cc_calc_slag(CPUState *env, uint64_t src, uint64_t shift)
+{
+    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
+    uint64_t match, r;
+
+    /* check if the sign bit stays the same */
+    if (src & (1ULL << 63)) {
+        match = mask;
+    } else {
+        match = 0;
+    }
+
+    if ((src & mask) != match) {
+        /* overflow */
+        return 3;
+    }
+
+    r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
+
+    if ((int64_t)r == 0) {
+        return 0;
+    } else if ((int64_t)r < 0) {
+        return 1;
+    }
+
+    return 2;
+}
+
+
+static inline uint32_t do_calc_cc(CPUState *env, uint32_t cc_op, uint64_t src,
+                                  uint64_t dst, uint64_t vr)
+{
+    uint32_t r = 0;
+
+    switch (cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* cc_op value _is_ cc */
+        r = cc_op;
+        break;
+    case CC_OP_LTGT0_32:
+        r = cc_calc_ltgt0_32(env, dst);
+        break;
+    case CC_OP_LTGT0_64:
+        r =  cc_calc_ltgt0_64(env, dst);
+        break;
+    case CC_OP_LTGT_32:
+        r =  cc_calc_ltgt_32(env, src, dst);
+        break;
+    case CC_OP_LTGT_64:
+        r =  cc_calc_ltgt_64(env, src, dst);
+        break;
+    case CC_OP_LTUGTU_32:
+        r =  cc_calc_ltugtu_32(env, src, dst);
+        break;
+    case CC_OP_LTUGTU_64:
+        r =  cc_calc_ltugtu_64(env, src, dst);
+        break;
+    case CC_OP_TM_32:
+        r =  cc_calc_tm_32(env, src, dst);
+        break;
+    case CC_OP_TM_64:
+        r =  cc_calc_tm_64(env, src, dst);
+        break;
+    case CC_OP_NZ:
+        r =  cc_calc_nz(env, dst);
+        break;
+    case CC_OP_ADD_64:
+        r =  cc_calc_add_64(env, src, dst, vr);
+        break;
+    case CC_OP_ADDU_64:
+        r =  cc_calc_addu_64(env, src, dst, vr);
+        break;
+    case CC_OP_SUB_64:
+        r =  cc_calc_sub_64(env, src, dst, vr);
+        break;
+    case CC_OP_SUBU_64:
+        r =  cc_calc_subu_64(env, src, dst, vr);
+        break;
+    case CC_OP_ABS_64:
+        r =  cc_calc_abs_64(env, dst);
+        break;
+    case CC_OP_NABS_64:
+        r =  cc_calc_nabs_64(env, dst);
+        break;
+    case CC_OP_COMP_64:
+        r =  cc_calc_comp_64(env, dst);
+        break;
+
+    case CC_OP_ADD_32:
+        r =  cc_calc_add_32(env, src, dst, vr);
+        break;
+    case CC_OP_ADDU_32:
+        r =  cc_calc_addu_32(env, src, dst, vr);
+        break;
+    case CC_OP_SUB_32:
+        r =  cc_calc_sub_32(env, src, dst, vr);
+        break;
+    case CC_OP_SUBU_32:
+        r =  cc_calc_subu_32(env, src, dst, vr);
+        break;
+    case CC_OP_ABS_32:
+        r =  cc_calc_abs_64(env, dst);
+        break;
+    case CC_OP_NABS_32:
+        r =  cc_calc_nabs_64(env, dst);
+        break;
+    case CC_OP_COMP_32:
+        r =  cc_calc_comp_32(env, dst);
+        break;
+
+    case CC_OP_ICM:
+        r =  cc_calc_icm_32(env, src, dst);
+        break;
+    case CC_OP_SLAG:
+        r =  cc_calc_slag(env, src, dst);
+        break;
+
+    case CC_OP_LTGT_F32:
+        r = set_cc_f32(src, dst);
+        break;
+    case CC_OP_LTGT_F64:
+        r = set_cc_f64(src, dst);
+        break;
+    case CC_OP_NZ_F32:
+        r = set_cc_nz_f32(dst);
+        break;
+    case CC_OP_NZ_F64:
+        r = set_cc_nz_f64(dst);
+        break;
+
+    default:
+        cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
+    }
+
+    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__,
+               cc_name(cc_op), src, dst, vr, r);
+    return r;
+}
+
+uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
+                         uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint64_t HELPER(cvd)(int32_t bin)
+{
+    /* positive 0 */
+    uint64_t dec = 0x0c;
+    int shift = 4;
+
+    if (bin < 0) {
+        bin = -bin;
+        dec = 0x0d;
+    }
+
+    for (shift = 4; (shift < 64) && bin; shift += 4) {
+        int current_number = bin % 10;
+
+        dec |= (current_number) << shift;
+        bin /= 10;
+    }
+
+    return dec;
+}
+
+void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
+{
+    int len_dest = len >> 4;
+    int len_src = len & 0xf;
+    uint8_t b;
+    int second_nibble = 0;
+
+    dest += len_dest;
+    src += len_src;
+
+    /* last byte is special, it only flips the nibbles */
+    b = ldub(src);
+    stb(dest, (b << 4) | (b >> 4));
+    src--;
+    len_src--;
+
+    /* now pad every nibble with 0xf0 */
+
+    while (len_dest > 0) {
+        uint8_t cur_byte = 0;
+
+        if (len_src > 0) {
+            cur_byte = ldub(src);
+        }
+
+        len_dest--;
+        dest--;
+
+        /* only advance one nibble at a time */
+        if (second_nibble) {
+            cur_byte >>= 4;
+            len_src--;
+            src--;
+        }
+        second_nibble = !second_nibble;
+
+        /* digit */
+        cur_byte = (cur_byte & 0xf);
+        /* zone bits */
+        cur_byte |= 0xf0;
+
+        stb(dest, cur_byte);
+    }
+}
+
+void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
+{
+    int i;
+
+    for (i = 0; i <= len; i++) {
+        uint8_t byte = ldub(array + i);
+        uint8_t new_byte = ldub(trans + byte);
+        stb(array + i, new_byte);
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+
+void HELPER(load_psw)(uint64_t mask, uint64_t addr)
+{
+    load_psw(env, mask, addr);
+    cpu_loop_exit(env);
+}
+
+static void program_interrupt(CPUState *env, uint32_t code, int ilc)
+{
+    qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
+
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
+#endif
+    } else {
+        env->int_pgm_code = code;
+        env->int_pgm_ilc = ilc;
+        env->exception_index = EXCP_PGM;
+        cpu_loop_exit(env);
+    }
+}
+
+static void ext_interrupt(CPUState *env, int type, uint32_t param,
+                          uint64_t param64)
+{
+    cpu_inject_ext(env, type, param, param64);
+}
+
+int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code)
+{
+    int r = 0;
+    int shift = 0;
+
+#ifdef DEBUG_HELPER
+    printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
+#endif
+
+    if (sccb & ~0x7ffffff8ul) {
+        fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
+        r = -1;
+        goto out;
+    }
+
+    switch(code) {
+        case SCLP_CMDW_READ_SCP_INFO:
+        case SCLP_CMDW_READ_SCP_INFO_FORCED:
+            while ((ram_size >> (20 + shift)) > 65535) {
+                shift++;
+            }
+            stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
+            stb_phys(sccb + SCP_INCREMENT, 1 << shift);
+            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
+
+            if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
+                                            sccb & ~3, 0, 1);
+#endif
+            } else {
+                env->psw.addr += 4;
+                ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
+            }
+            break;
+        default:
+#ifdef DEBUG_HELPER
+            printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
+#endif
+            r = -1;
+            break;
+    }
+
+out:
+    return r;
+}
+
+/* SCLP service call */
+uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
+{
+    if (sclp_service_call(env, r1, r2)) {
+        return 3;
+    }
+
+    return 0;
+}
+
+/* DIAG */
+uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
+{
+    uint64_t r;
+
+    switch (num) {
+    case 0x500:
+        /* KVM hypercall */
+        r = s390_virtio_hypercall(env, mem, code);
+        break;
+    case 0x44:
+        /* yield */
+        r = 0;
+        break;
+    case 0x308:
+        /* ipl */
+        r = 0;
+        break;
+    default:
+        r = -1;
+        break;
+    }
+
+    if (r) {
+        program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
+    }
+
+    return r;
+}
+
+/* Store CPU ID */
+void HELPER(stidp)(uint64_t a1)
+{
+    stq(a1, env->cpu_num);
+}
+
+/* Set Prefix */
+void HELPER(spx)(uint64_t a1)
+{
+    uint32_t prefix;
+
+    prefix = ldl(a1);
+    env->psa = prefix & 0xfffff000;
+    qemu_log("prefix: %#x\n", prefix);
+    tlb_flush_page(env, 0);
+    tlb_flush_page(env, TARGET_PAGE_SIZE);
+}
+
+/* Set Clock */
+uint32_t HELPER(sck)(uint64_t a1)
+{
+    /* XXX not implemented - is it necessary? */
+
+    return 0;
+}
+
+static inline uint64_t clock_value(CPUState *env)
+{
+    uint64_t time;
+
+    time = env->tod_offset +
+           time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
+
+    return time;
+}
+
+/* Store Clock */
+uint32_t HELPER(stck)(uint64_t a1)
+{
+    stq(a1, clock_value(env));
+
+    return 0;
+}
+
+/* Store Clock Extended */
+uint32_t HELPER(stcke)(uint64_t a1)
+{
+    stb(a1, 0);
+    /* basically the same value as stck */
+    stq(a1 + 1, clock_value(env) | env->cpu_num);
+    /* more fine grained than stck */
+    stq(a1 + 9, 0);
+    /* XXX programmable fields */
+    stw(a1 + 17, 0);
+
+
+    return 0;
+}
+
+/* Set Clock Comparator */
+void HELPER(sckc)(uint64_t a1)
+{
+    uint64_t time = ldq(a1);
+
+    if (time == -1ULL) {
+        return;
+    }
+
+    /* difference between now and then */
+    time -= clock_value(env);
+    /* nanoseconds */
+    time = (time * 125) >> 9;
+
+    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store Clock Comparator */
+void HELPER(stckc)(uint64_t a1)
+{
+    /* XXX implement */
+    stq(a1, 0);
+}
+
+/* Set CPU Timer */
+void HELPER(spt)(uint64_t a1)
+{
+    uint64_t time = ldq(a1);
+
+    if (time == -1ULL) {
+        return;
+    }
+
+    /* nanoseconds */
+    time = (time * 125) >> 9;
+
+    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store CPU Timer */
+void HELPER(stpt)(uint64_t a1)
+{
+    /* XXX implement */
+    stq(a1, 0);
+}
+
+/* Store System Information */
+uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
+{
+    int cc = 0;
+    int sel1, sel2;
+
+    if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
+        ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
+        /* valid function code, invalid reserved bits */
+        program_interrupt(env, PGM_SPECIFICATION, 2);
+    }
+
+    sel1 = r0 & STSI_R0_SEL1_MASK;
+    sel2 = r1 & STSI_R1_SEL2_MASK;
+
+    /* XXX: spec exception if sysib is not 4k-aligned */
+
+    switch (r0 & STSI_LEVEL_MASK) {
+    case STSI_LEVEL_1:
+        if ((sel1 == 1) && (sel2 == 1)) {
+            /* Basic Machine Configuration */
+            struct sysib_111 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            ebcdic_put(sysib.manuf, "QEMU            ", 16);
+            /* same as machine type number in STORE CPU ID */
+            ebcdic_put(sysib.type, "QEMU", 4);
+            /* same as model number in STORE CPU ID */
+            ebcdic_put(sysib.model, "QEMU            ", 16);
+            ebcdic_put(sysib.sequence, "QEMU            ", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 1)) {
+            /* Basic Machine CPU */
+            struct sysib_121 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            /* XXX make different for different CPUs? */
+            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            stw_p(&sysib.cpu_addr, env->cpu_num);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* Basic Machine CPUs */
+            struct sysib_122 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            stl_p(&sysib.capability, 0x443afc29);
+            /* XXX change when SMP comes */
+            stw_p(&sysib.total_cpus, 1);
+            stw_p(&sysib.active_cpus, 1);
+            stw_p(&sysib.standby_cpus, 0);
+            stw_p(&sysib.reserved_cpus, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    case STSI_LEVEL_2:
+    {
+        if ((sel1 == 2) && (sel2 == 1)) {
+            /* LPAR CPU */
+            struct sysib_221 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            /* XXX make different for different CPUs? */
+            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            stw_p(&sysib.cpu_addr, env->cpu_num);
+            stw_p(&sysib.cpu_id, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* LPAR CPUs */
+            struct sysib_222 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            stw_p(&sysib.lpar_num, 0);
+            sysib.lcpuc = 0;
+            /* XXX change when SMP comes */
+            stw_p(&sysib.total_cpus, 1);
+            stw_p(&sysib.conf_cpus, 1);
+            stw_p(&sysib.standby_cpus, 0);
+            stw_p(&sysib.reserved_cpus, 0);
+            ebcdic_put(sysib.name, "QEMU    ", 8);
+            stl_p(&sysib.caf, 1000);
+            stw_p(&sysib.dedicated_cpus, 0);
+            stw_p(&sysib.shared_cpus, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    }
+    case STSI_LEVEL_3:
+    {
+        if ((sel1 == 2) && (sel2 == 2)) {
+            /* VM CPUs */
+            struct sysib_322 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            sysib.count = 1;
+            /* XXX change when SMP comes */
+            stw_p(&sysib.vm[0].total_cpus, 1);
+            stw_p(&sysib.vm[0].conf_cpus, 1);
+            stw_p(&sysib.vm[0].standby_cpus, 0);
+            stw_p(&sysib.vm[0].reserved_cpus, 0);
+            ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
+            stl_p(&sysib.vm[0].caf, 1000);
+            ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    }
+    case STSI_LEVEL_CURRENT:
+        env->regs[0] = STSI_LEVEL_3;
+        break;
+    default:
+        cc = 3;
+        break;
+    }
+
+    return cc;
+}
+
+void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t src = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->cregs[i] = ldq(src);
+        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
+                   i, src, env->cregs[i]);
+        src += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    tlb_flush(env, 1);
+}
+
+void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t src = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
+        src += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    tlb_flush(env, 1);
+}
+
+void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t dest = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stq(dest, env->cregs[i]);
+        dest += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t dest = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stl(dest, env->cregs[i]);
+        dest += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
+{
+    /* XXX implement */
+
+    return 0;
+}
+
+/* insert storage key extended */
+uint64_t HELPER(iske)(uint64_t r2)
+{
+    uint64_t addr = get_address(0, 0, r2);
+
+    if (addr > ram_size) {
+        return 0;
+    }
+
+    return env->storage_keys[addr / TARGET_PAGE_SIZE];
+}
+
+/* set storage key extended */
+void HELPER(sske)(uint32_t r1, uint64_t r2)
+{
+    uint64_t addr = get_address(0, 0, r2);
+
+    if (addr > ram_size) {
+        return;
+    }
+
+    env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
+}
+
+/* reset reference bit extended */
+uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
+{
+    uint8_t re;
+    uint8_t key;
+    if (r2 > ram_size) {
+        return 0;
+    }
+
+    key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
+    re = key & (SK_R | SK_C);
+    env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
+
+    /*
+     * cc
+     *
+     * 0  Reference bit zero; change bit zero
+     * 1  Reference bit zero; change bit one
+     * 2  Reference bit one; change bit zero
+     * 3  Reference bit one; change bit one
+     */
+
+    return re >> 1;
+}
+
+/* compare and swap and purge */
+uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
+{
+    uint32_t cc;
+    uint32_t o1 = env->regs[r1];
+    uint64_t a2 = get_address_31fix(r2) & ~3ULL;
+    uint32_t o2 = ldl(a2);
+
+    if (o1 == o2) {
+        stl(a2, env->regs[(r1 + 1) & 15]);
+        if (env->regs[r2] & 0x3) {
+            /* flush TLB / ALB */
+            tlb_flush(env, 1);
+        }
+        cc = 0;
+    } else {
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
+        cc = 1;
+    }
+
+    return cc;
+}
+
+static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
+                        uint64_t mode2)
+{
+    target_ulong src, dest;
+    int flags, cc = 0, i;
+
+    if (!l) {
+        return 0;
+    } else if (l > 256) {
+        /* max 256 */
+        l = 256;
+        cc = 3;
+    }
+
+    if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
+        cpu_loop_exit(env);
+    }
+    dest |= a1 & ~TARGET_PAGE_MASK;
+
+    if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
+        cpu_loop_exit(env);
+    }
+    src |= a2 & ~TARGET_PAGE_MASK;
+
+    /* XXX replace w/ memcpy */
+    for (i = 0; i < l; i++) {
+        /* XXX be more clever */
+        if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
+            (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
+            mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
+            break;
+        }
+        stb_phys(dest + i, ldub_phys(src + i));
+    }
+
+    return cc;
+}
+
+uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
+{
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __FUNCTION__, l, a1, a2);
+
+    return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
+}
+
+uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
+{
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __FUNCTION__, l, a1, a2);
+
+    return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
+}
+
+uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
+{
+    int cc = 0;
+
+    HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
+               __FUNCTION__, order_code, r1, cpu_addr);
+
+    /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register"
+       as parameter (input). Status (output) is always R1. */
+
+    switch (order_code) {
+    case SIGP_SET_ARCH:
+        /* switch arch */
+        break;
+    case SIGP_SENSE:
+        /* enumerate CPU status */
+        if (cpu_addr) {
+            /* XXX implement when SMP comes */
+            return 3;
+        }
+        env->regs[r1] &= 0xffffffff00000000ULL;
+        cc = 1;
+        break;
+#if !defined (CONFIG_USER_ONLY)
+    case SIGP_RESTART:
+        qemu_system_reset_request();
+        cpu_loop_exit(env);
+        break;
+    case SIGP_STOP:
+        qemu_system_shutdown_request();
+        cpu_loop_exit(env);
+        break;
+#endif
+    default:
+        /* unknown sigp */
+        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
+        cc = 3;
+    }
+
+    return cc;
+}
+
+void HELPER(sacf)(uint64_t a1)
+{
+    HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1);
+
+    switch (a1 & 0xf00) {
+    case 0x000:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_PRIMARY;
+        break;
+    case 0x100:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_SECONDARY;
+        break;
+    case 0x300:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_HOME;
+        break;
+    default:
+        qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
+        program_interrupt(env, PGM_SPECIFICATION, 2);
+        break;
+    }
+}
+
+/* invalidate pte */
+void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
+{
+    uint64_t page = vaddr & TARGET_PAGE_MASK;
+    uint64_t pte = 0;
+
+    /* XXX broadcast to other CPUs */
+
+    /* XXX Linux is nice enough to give us the exact pte address.
+           According to spec we'd have to find it out ourselves */
+    /* XXX Linux is fine with overwriting the pte, the spec requires
+           us to only set the invalid bit */
+    stq_phys(pte_addr, pte | _PAGE_INVALID);
+
+    /* XXX we exploit the fact that Linux passes the exact virtual
+           address here - it's not obliged to! */
+    tlb_flush_page(env, page);
+
+    /* XXX 31-bit hack */
+    if (page & 0x80000000) {
+        tlb_flush_page(env, page & ~0x80000000);
+    } else {
+        tlb_flush_page(env, page | 0x80000000);
+    }
+}
+
+/* flush local tlb */
+void HELPER(ptlb)(void)
+{
+    tlb_flush(env, 1);
+}
+
+/* store using real address */
+void HELPER(stura)(uint64_t addr, uint32_t v1)
+{
+    stw_phys(get_address(0, 0, addr), v1);
+}
+
+/* load real address */
+uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
+{
+    uint32_t cc = 0;
+    int old_exc = env->exception_index;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    uint64_t ret;
+    int flags;
+
+    /* XXX incomplete - has more corner cases */
+    if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
+        program_interrupt(env, PGM_SPECIAL_OP, 2);
+    }
+
+    env->exception_index = old_exc;
+    if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
+        cc = 3;
+    }
+    if (env->exception_index == EXCP_PGM) {
+        ret = env->int_pgm_code | 0x80000000;
+    } else {
+        ret |= addr & ~TARGET_PAGE_MASK;
+    }
+    env->exception_index = old_exc;
+
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL);
+    } else {
+        env->regs[r1] = ret;
+    }
+
+    return cc;
+}
+
+#endif
index d33bfb1f310f60517f86f899f1f665c4a1942e98..ee156721857d089e2538e20263e94450a4df4f38 100644 (file)
@@ -2,6 +2,7 @@
  *  S/390 translation
  *
  *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2010 Alexander Graf
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+/* #define DEBUG_ILLEGAL_INSTRUCTIONS */
+/* #define DEBUG_INLINE_BRANCHES */
+#define S390X_DEBUG_DISAS
+/* #define S390X_DEBUG_DISAS_VERBOSE */
+
+#ifdef S390X_DEBUG_DISAS_VERBOSE
+#  define LOG_DISAS(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_DISAS(...) do { } while (0)
+#endif
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-log.h"
 
+/* global register indexes */
+static TCGv_ptr cpu_env;
+
+#include "gen-icount.h"
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext DisasContext;
+struct DisasContext {
+    uint64_t pc;
+    int is_jmp;
+    enum cc_op cc_op;
+    struct TranslationBlock *tb;
+};
+
+#define DISAS_EXCP 4
+
+static void gen_op_calc_cc(DisasContext *s);
+
+#ifdef DEBUG_INLINE_BRANCHES
+static uint64_t inline_branch_hit[CC_OP_MAX];
+static uint64_t inline_branch_miss[CC_OP_MAX];
+#endif
+
+static inline void debug_insn(uint64_t insn)
+{
+    LOG_DISAS("insn: 0x%" PRIx64 "\n", insn);
+}
+
+static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc)
+{
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        if (s->tb->flags & FLAG_MASK_32) {
+            return pc | 0x80000000;
+        }
+    }
+    return pc;
+}
+
 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int i;
+
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+
     for (i = 0; i < 16; i++) {
-        cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]);
+        cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]);
         if ((i % 4) == 3) {
             cpu_fprintf(f, "\n");
         } else {
             cpu_fprintf(f, " ");
         }
     }
+
+    cpu_fprintf(f, "\n");
+
+#ifndef CONFIG_USER_ONLY
     for (i = 0; i < 16; i++) {
-        cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i);
+        cpu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
         if ((i % 4) == 3) {
             cpu_fprintf(f, "\n");
         } else {
             cpu_fprintf(f, " ");
         }
     }
-    cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc);
+#endif
+
+    cpu_fprintf(f, "\n");
+
+    if (env->cc_op > 3) {
+        cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n",
+                    env->psw.mask, env->psw.addr, cc_name(env->cc_op));
+    } else {
+        cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n",
+                    env->psw.mask, env->psw.addr, env->cc_op);
+    }
+
+#ifdef DEBUG_INLINE_BRANCHES
+    for (i = 0; i < CC_OP_MAX; i++) {
+        cpu_fprintf(f, "  %15s = %10ld\t%10ld\n", cc_name(i),
+                    inline_branch_miss[i], inline_branch_hit[i]);
+    }
+#endif
 }
 
-void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+static TCGv_i64 psw_addr;
+static TCGv_i64 psw_mask;
+
+static TCGv_i32 cc_op;
+static TCGv_i64 cc_src;
+static TCGv_i64 cc_dst;
+static TCGv_i64 cc_vr;
+
+static char cpu_reg_names[10*3 + 6*4];
+static TCGv_i64 regs[16];
+
+static uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
+
+void s390x_translate_init(void)
+{
+    int i;
+    size_t cpu_reg_names_size = sizeof(cpu_reg_names);
+    char *p;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.addr),
+                                      "psw_addr");
+    psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.mask),
+                                      "psw_mask");
+
+    cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc_op),
+                                   "cc_op");
+    cc_src = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_src),
+                                    "cc_src");
+    cc_dst = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_dst),
+                                    "cc_dst");
+    cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_vr),
+                                   "cc_vr");
+
+    p = cpu_reg_names;
+    for (i = 0; i < 16; i++) {
+        snprintf(p, cpu_reg_names_size, "r%d", i);
+        regs[i] = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, regs[i]), p);
+        p += (i < 10) ? 3 : 4;
+        cpu_reg_names_size -= (i < 10) ? 3 : 4;
+    }
+}
+
+static inline TCGv_i64 load_reg(int reg)
 {
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_mov_i64(r, regs[reg]);
+    return r;
 }
 
-void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+static inline TCGv_i64 load_freg(int reg)
 {
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, fregs[reg].d));
+    return r;
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+static inline TCGv_i32 load_freg32(int reg)
 {
-    env->psw.addr = gen_opc_pc[pc_pos];
+    TCGv_i32 r = tcg_temp_new_i32();
+    tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].l.upper));
+    return r;
+}
+
+static inline TCGv_i32 load_reg32(int reg)
+{
+    TCGv_i32 r = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(r, regs[reg]);
+    return r;
+}
+
+static inline TCGv_i64 load_reg32_i64(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(r, regs[reg]);
+    return r;
+}
+
+static inline void store_reg(int reg, TCGv_i64 v)
+{
+    tcg_gen_mov_i64(regs[reg], v);
+}
+
+static inline void store_freg(int reg, TCGv_i64 v)
+{
+    tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, fregs[reg].d));
+}
+
+static inline void store_reg32(int reg, TCGv_i32 v)
+{
+#if HOST_LONG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v);
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(tmp, v);
+    /* 32 bit register writes keep the upper half */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 32);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void store_reg32_i64(int reg, TCGv_i64 v)
+{
+    /* 32 bit register writes keep the upper half */
+#if HOST_LONG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(regs[reg]), TCGV_LOW(v));
+#else
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32);
+#endif
+}
+
+static inline void store_reg16(int reg, TCGv_i32 v)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(tmp, v);
+    /* 16 bit register writes keep the upper bytes */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 16);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void store_reg8(int reg, TCGv_i64 v)
+{
+    /* 8 bit register writes keep the upper bytes */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 8);
+}
+
+static inline void store_freg32(int reg, TCGv_i32 v)
+{
+    tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, fregs[reg].l.upper));
+}
+
+static inline void update_psw_addr(DisasContext *s)
+{
+    /* psw.addr */
+    tcg_gen_movi_i64(psw_addr, s->pc);
+}
+
+static inline void potential_page_fault(DisasContext *s)
+{
+#ifndef CONFIG_USER_ONLY
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+#endif
+}
+
+static inline uint64_t ld_code2(uint64_t pc)
+{
+    return (uint64_t)lduw_code(pc);
+}
+
+static inline uint64_t ld_code4(uint64_t pc)
+{
+    return (uint64_t)ldl_code(pc);
+}
+
+static inline uint64_t ld_code6(uint64_t pc)
+{
+    uint64_t opc;
+    opc = (uint64_t)lduw_code(pc) << 32;
+    opc |= (uint64_t)(uint32_t)ldl_code(pc+2);
+    return opc;
+}
+
+static inline int get_mem_index(DisasContext *s)
+{
+    switch (s->tb->flags & FLAG_MASK_ASC) {
+    case PSW_ASC_PRIMARY >> 32:
+        return 0;
+    case PSW_ASC_SECONDARY >> 32:
+        return 1;
+    case PSW_ASC_HOME >> 32:
+        return 2;
+    default:
+        tcg_abort();
+        break;
+    }
+}
+
+static inline void gen_debug(DisasContext *s)
+{
+    TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+    s->is_jmp = DISAS_EXCP;
+}
+
+#ifdef CONFIG_USER_ONLY
+
+static void gen_illegal_opcode(DisasContext *s, int ilc)
+{
+    TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC);
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+    s->is_jmp = DISAS_EXCP;
+}
+
+#else /* CONFIG_USER_ONLY */
+
+static void debug_print_inst(DisasContext *s, int ilc)
+{
+#ifdef DEBUG_ILLEGAL_INSTRUCTIONS
+    uint64_t inst = 0;
+
+    switch (ilc & 3) {
+    case 1:
+        inst = ld_code2(s->pc);
+        break;
+    case 2:
+        inst = ld_code4(s->pc);
+        break;
+    case 3:
+        inst = ld_code6(s->pc);
+        break;
+    }
+
+    fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016"
+            PRIx64 "\n", ilc, s->pc, inst);
+#endif
+}
+
+static void gen_program_exception(DisasContext *s, int ilc, int code)
+{
+    TCGv_i32 tmp;
+
+    debug_print_inst(s, ilc);
+
+    /* remember what pgm exeption this was */
+    tmp = tcg_const_i32(code);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, int_pgm_code));
+    tcg_temp_free_i32(tmp);
+
+    tmp = tcg_const_i32(ilc);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, int_pgm_ilc));
+    tcg_temp_free_i32(tmp);
+
+    /* advance past instruction */
+    s->pc += (ilc * 2);
+    update_psw_addr(s);
+
+    /* save off cc */
+    gen_op_calc_cc(s);
+
+    /* trigger exception */
+    tmp = tcg_const_i32(EXCP_PGM);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+
+    /* end TB here */
+    s->is_jmp = DISAS_EXCP;
+}
+
+
+static void gen_illegal_opcode(DisasContext *s, int ilc)
+{
+    gen_program_exception(s, ilc, PGM_SPECIFICATION);
+}
+
+static void gen_privileged_exception(DisasContext *s, int ilc)
+{
+    gen_program_exception(s, ilc, PGM_PRIVILEGED);
+}
+
+static void check_privileged(DisasContext *s, int ilc)
+{
+    if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) {
+        gen_privileged_exception(s, ilc);
+    }
+}
+
+#endif /* CONFIG_USER_ONLY */
+
+static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
+{
+    TCGv_i64 tmp;
+
+    /* 31-bitify the immediate part; register contents are dealt with below */
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        d2 &= 0x7fffffffUL;
+    }
+
+    if (x2) {
+        if (d2) {
+            tmp = tcg_const_i64(d2);
+            tcg_gen_add_i64(tmp, tmp, regs[x2]);
+        } else {
+            tmp = load_reg(x2);
+        }
+        if (b2) {
+            tcg_gen_add_i64(tmp, tmp, regs[b2]);
+        }
+    } else if (b2) {
+        if (d2) {
+            tmp = tcg_const_i64(d2);
+            tcg_gen_add_i64(tmp, tmp, regs[b2]);
+        } else {
+            tmp = load_reg(b2);
+        }
+    } else {
+        tmp = tcg_const_i64(d2);
+    }
+
+    /* 31-bit mode mask if there are values loaded from registers */
+    if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) {
+        tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL);
+    }
+
+    return tmp;
+}
+
+static void gen_op_movi_cc(DisasContext *s, uint32_t val)
+{
+    s->cc_op = CC_OP_CONST0 + val;
+}
+
+static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst)
+{
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
+                                  TCGv_i32 dst)
+{
+    tcg_gen_extu_i32_i64(cc_src, src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst, TCGv_i64 vr)
+{
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_mov_i64(cc_vr, vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
+                                  TCGv_i32 dst, TCGv_i32 vr)
+{
+    tcg_gen_extu_i32_i64(cc_src, src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_extu_i32_i64(cc_vr, vr);
+    s->cc_op = op;
+}
+
+static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NZ, val);
+}
+
+static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ, val);
+}
+
+static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          enum cc_op cond)
+{
+    gen_op_update2_cc_i32(s, cond, v1, v2);
+}
+
+static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          enum cc_op cond)
+{
+    gen_op_update2_cc_i64(s, cond, v1, v2);
+}
+
+static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    cmp_32(s, v1, v2, CC_OP_LTGT_32);
+}
+
+static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    cmp_32(s, v1, v2, CC_OP_LTUGTU_32);
+}
+
+static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2)
+{
+    /* XXX optimize for the constant? put it in s? */
+    TCGv_i32 tmp = tcg_const_i32(v2);
+    cmp_32(s, v1, tmp, CC_OP_LTGT_32);
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2)
+{
+    TCGv_i32 tmp = tcg_const_i32(v2);
+    cmp_32(s, v1, tmp, CC_OP_LTUGTU_32);
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
+{
+    cmp_64(s, v1, v2, CC_OP_LTGT_64);
+}
+
+static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
+{
+    cmp_64(s, v1, v2, CC_OP_LTUGTU_64);
+}
+
+static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2)
+{
+    TCGv_i64 tmp = tcg_const_i64(v2);
+    cmp_s64(s, v1, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2)
+{
+    TCGv_i64 tmp = tcg_const_i64(v2);
+    cmp_u64(s, v1, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void set_cc_s32(DisasContext *s, TCGv_i32 val)
+{
+    gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val);
+}
+
+static inline void set_cc_s64(DisasContext *s, TCGv_i64 val)
+{
+    gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val);
+}
+
+static void set_cc_add64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADD_64, v1, v2, vr);
+}
+
+static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr);
+}
+
+static void set_cc_sub64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUB_64, v1, v2, vr);
+}
+
+static void set_cc_subu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUBU_64, v1, v2, vr);
+}
+
+static void set_cc_abs64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1);
+}
+
+static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1);
+}
+
+static void set_cc_add32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_ADD_32, v1, v2, vr);
+}
+
+static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr);
+}
+
+static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr);
+}
+
+static void set_cc_subu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_SUBU_32, v1, v2, vr);
+}
+
+static void set_cc_abs32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1);
+}
+
+static void set_cc_nabs32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NABS_32, v1);
+}
+
+static void set_cc_comp32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_COMP_32, v1);
+}
+
+static void set_cc_comp64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_COMP_64, v1);
+}
+
+static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2);
+}
+
+static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2)
+{
+    tcg_gen_extu_i32_i64(cc_src, v1);
+    tcg_gen_mov_i64(cc_dst, v2);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = CC_OP_LTGT_F32;
+}
+
+static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1);
+}
+
+static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1);
+}
+
+/* CC value is in env->cc_op */
+static inline void set_cc_static(DisasContext *s)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_discard_i64(cc_dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = CC_OP_STATIC;
+}
+
+static inline void gen_op_set_cc_op(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
+        tcg_gen_movi_i32(cc_op, s->cc_op);
+    }
+}
+
+static inline void gen_update_cc_op(DisasContext *s)
+{
+    gen_op_set_cc_op(s);
+}
+
+/* calculates cc into cc_op */
+static void gen_op_calc_cc(DisasContext *s)
+{
+    TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op);
+    TCGv_i64 dummy = tcg_const_i64(0);
+
+    switch (s->cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* s->cc_op is the cc value */
+        tcg_gen_movi_i32(cc_op, s->cc_op - CC_OP_CONST0);
+        break;
+    case CC_OP_STATIC:
+        /* env->cc_op already is the cc value */
+        break;
+    case CC_OP_NZ:
+    case CC_OP_ABS_64:
+    case CC_OP_NABS_64:
+    case CC_OP_ABS_32:
+    case CC_OP_NABS_32:
+    case CC_OP_LTGT0_32:
+    case CC_OP_LTGT0_64:
+    case CC_OP_COMP_32:
+    case CC_OP_COMP_64:
+    case CC_OP_NZ_F32:
+    case CC_OP_NZ_F64:
+        /* 1 argument */
+        gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy);
+        break;
+    case CC_OP_ICM:
+    case CC_OP_LTGT_32:
+    case CC_OP_LTGT_64:
+    case CC_OP_LTUGTU_32:
+    case CC_OP_LTUGTU_64:
+    case CC_OP_TM_32:
+    case CC_OP_TM_64:
+    case CC_OP_LTGT_F32:
+    case CC_OP_LTGT_F64:
+    case CC_OP_SLAG:
+        /* 2 arguments */
+        gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy);
+        break;
+    case CC_OP_ADD_64:
+    case CC_OP_ADDU_64:
+    case CC_OP_SUB_64:
+    case CC_OP_SUBU_64:
+    case CC_OP_ADD_32:
+    case CC_OP_ADDU_32:
+    case CC_OP_SUB_32:
+    case CC_OP_SUBU_32:
+        /* 3 arguments */
+        gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    case CC_OP_DYNAMIC:
+        /* unknown operation - assume 3 arguments and cc_op in env */
+        gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    tcg_temp_free_i32(local_cc_op);
+
+    /* We now have cc in cc_op as constant */
+    set_cc_static(s);
+}
+
+static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 4) & 0xf;
+    *r2 = insn & 0xf;
+}
+
+static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1,
+                                 int *x2, int *b2, int *d2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 20) & 0xf;
+    *x2 = (insn >> 16) & 0xf;
+    *b2 = (insn >> 12) & 0xf;
+    *d2 = insn & 0xfff;
+
+    return get_address(s, *x2, *b2, *d2);
+}
+
+static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3,
+                             int *b2, int *d2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 20) & 0xf;
+    /* aka m3 */
+    *r3 = (insn >> 16) & 0xf;
+    *b2 = (insn >> 12) & 0xf;
+    *d2 = insn & 0xfff;
+}
+
+static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2,
+                                 int *b1, int *d1)
+{
+    debug_insn(insn);
+
+    *i2 = (insn >> 16) & 0xff;
+    *b1 = (insn >> 12) & 0xf;
+    *d1 = insn & 0xfff;
+
+    return get_address(s, 0, *b1, *d1);
+}
+
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc)
+{
+    TranslationBlock *tb;
+
+    gen_update_cc_op(s);
+
+    tb = s->tb;
+    /* NOTE: we handle the case where the TB spans two pages here */
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
+        (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
+        /* jump to same page: we can use a direct jump */
+        tcg_gen_goto_tb(tb_num);
+        tcg_gen_movi_i64(psw_addr, pc);
+        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
+    } else {
+        /* jump to another page: currently not optimized */
+        tcg_gen_movi_i64(psw_addr, pc);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void account_noninline_branch(DisasContext *s, int cc_op)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_miss[cc_op]++;
+#endif
+}
+
+static inline void account_inline_branch(DisasContext *s)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_hit[s->cc_op]++;
+#endif
+}
+
+static void gen_jcc(DisasContext *s, uint32_t mask, int skip)
+{
+    TCGv_i32 tmp, tmp2, r;
+    TCGv_i64 tmp64;
+    int old_cc_op;
+
+    switch (s->cc_op) {
+    case CC_OP_LTGT0_32:
+        tmp = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* dst <= 0 */
+            tcg_gen_brcondi_i32(TCG_COND_GT, tmp, 0, skip);
+            break;
+        case 0x8 | 0x2: /* dst >= 0 */
+            tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, skip);
+            break;
+        case 0x8: /* dst == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            break;
+        case 0x7: /* dst != 0 */
+        case 0x6: /* dst != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            break;
+        case 0x4: /* dst < 0 */
+            tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, skip);
+            break;
+        case 0x2: /* dst > 0 */
+            tcg_gen_brcondi_i32(TCG_COND_LE, tmp, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        break;
+    case CC_OP_LTGT0_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* dst <= 0 */
+            tcg_gen_brcondi_i64(TCG_COND_GT, cc_dst, 0, skip);
+            break;
+        case 0x8 | 0x2: /* dst >= 0 */
+            tcg_gen_brcondi_i64(TCG_COND_LT, cc_dst, 0, skip);
+            break;
+        case 0x8: /* dst == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        case 0x7: /* dst != 0 */
+        case 0x6: /* dst != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        case 0x4: /* dst < 0 */
+            tcg_gen_brcondi_i64(TCG_COND_GE, cc_dst, 0, skip);
+            break;
+        case 0x2: /* dst > 0 */
+            tcg_gen_brcondi_i64(TCG_COND_LE, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_LTGT_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i32(TCG_COND_GT, tmp, tmp2, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i32(TCG_COND_LT, tmp, tmp2, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i32(TCG_COND_GE, tmp, tmp2, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i32(TCG_COND_LE, tmp, tmp2, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        break;
+    case CC_OP_LTGT_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i64(TCG_COND_GT, cc_src, cc_dst, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i64(TCG_COND_LT, cc_src, cc_dst, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i64(TCG_COND_GE, cc_src, cc_dst, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i64(TCG_COND_LE, cc_src, cc_dst, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_LTUGTU_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i32(TCG_COND_GTU, tmp, tmp2, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i32(TCG_COND_LTU, tmp, tmp2, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i32(TCG_COND_GEU, tmp, tmp2, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i32(TCG_COND_LEU, tmp, tmp2, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        break;
+    case CC_OP_LTUGTU_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i64(TCG_COND_GTU, cc_src, cc_dst, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i64(TCG_COND_LTU, cc_src, cc_dst, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i64(TCG_COND_GEU, cc_src, cc_dst, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i64(TCG_COND_LEU, cc_src, cc_dst, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_NZ:
+        switch (mask) {
+        /* dst == 0 || dst != 0 */
+        case 0x8 | 0x4:
+        case 0x8 | 0x4 | 0x2:
+        case 0x8 | 0x4 | 0x2 | 0x1:
+        case 0x8 | 0x4 | 0x1:
+            break;
+        /* dst == 0 */
+        case 0x8:
+        case 0x8 | 0x2:
+        case 0x8 | 0x2 | 0x1:
+        case 0x8 | 0x1:
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        /* dst != 0 */
+        case 0x4:
+        case 0x4 | 0x2:
+        case 0x4 | 0x2 | 0x1:
+        case 0x4 | 0x1:
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_TM_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        switch (mask) {
+        case 0x8: /* val & mask == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val & mask != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        account_inline_branch(s);
+        break;
+    case CC_OP_TM_64:
+        tmp64 = tcg_temp_new_i64();
+
+        tcg_gen_and_i64(tmp64, cc_src, cc_dst);
+        switch (mask) {
+        case 0x8: /* val & mask == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, tmp64, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val & mask != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i64(tmp64);
+            goto do_dynamic;
+        }
+        tcg_temp_free_i64(tmp64);
+        account_inline_branch(s);
+        break;
+    case CC_OP_ICM:
+        switch (mask) {
+        case 0x8: /* val == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val != 0 */
+        case 0x4 | 0x2: /* val != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_STATIC:
+        old_cc_op = s->cc_op;
+        goto do_dynamic_nocccalc;
+    case CC_OP_DYNAMIC:
+    default:
+do_dynamic:
+        old_cc_op = s->cc_op;
+        /* calculate cc value */
+        gen_op_calc_cc(s);
+
+do_dynamic_nocccalc:
+        /* jump based on cc */
+        account_noninline_branch(s, old_cc_op);
+
+        switch (mask) {
+        case 0x8 | 0x4 | 0x2 | 0x1:
+            /* always true */
+            break;
+        case 0x8 | 0x4 | 0x2: /* cc != 3 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 3, skip);
+            break;
+        case 0x8 | 0x4 | 0x1: /* cc != 2 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 2, skip);
+            break;
+        case 0x8 | 0x2 | 0x1: /* cc != 1 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 1, skip);
+            break;
+        case 0x8 | 0x2: /* cc == 0 || cc == 2 */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_andi_i32(tmp, cc_op, 1);
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x8 | 0x4: /* cc < 2 */
+            tcg_gen_brcondi_i32(TCG_COND_GEU, cc_op, 2, skip);
+            break;
+        case 0x8: /* cc == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* cc != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 0, skip);
+            break;
+        case 0x4 | 0x1: /* cc == 1 || cc == 3 */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_andi_i32(tmp, cc_op, 1);
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x4: /* cc == 1 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 1, skip);
+            break;
+        case 0x2 | 0x1: /* cc > 1 */
+            tcg_gen_brcondi_i32(TCG_COND_LEU, cc_op, 1, skip);
+            break;
+        case 0x2: /* cc == 2 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 2, skip);
+            break;
+        case 0x1: /* cc == 3 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 3, skip);
+            break;
+        default: /* cc is masked by something else */
+            tmp = tcg_const_i32(3);
+            /* 3 - cc */
+            tcg_gen_sub_i32(tmp, tmp, cc_op);
+            tmp2 = tcg_const_i32(1);
+            /* 1 << (3 - cc) */
+            tcg_gen_shl_i32(tmp2, tmp2, tmp);
+            r = tcg_const_i32(mask);
+            /* mask & (1 << (3 - cc)) */
+            tcg_gen_and_i32(r, r, tmp2);
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+
+            tcg_gen_brcondi_i32(TCG_COND_EQ, r, 0, skip);
+            tcg_temp_free_i32(r);
+            break;
+        }
+        break;
+    }
+}
+
+static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target,
+                    uint64_t offset)
+{
+    int skip;
+
+    if (mask == 0xf) {
+        /* unconditional */
+        tcg_gen_mov_i64(psw_addr, target);
+        tcg_gen_exit_tb(0);
+    } else if (mask == 0) {
+        /* ignore cc and never match */
+        gen_goto_tb(s, 0, offset + 2);
+    } else {
+        TCGv_i64 new_addr = tcg_temp_local_new_i64();
+
+        tcg_gen_mov_i64(new_addr, target);
+        skip = gen_new_label();
+        gen_jcc(s, mask, skip);
+        tcg_gen_mov_i64(psw_addr, new_addr);
+        tcg_temp_free_i64(new_addr);
+        tcg_gen_exit_tb(0);
+        gen_set_label(skip);
+        tcg_temp_free_i64(new_addr);
+        gen_goto_tb(s, 1, offset + 2);
+    }
+}
+
+static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset)
+{
+    int skip;
+
+    if (mask == 0xf) {
+        /* unconditional */
+        gen_goto_tb(s, 0, s->pc + offset);
+    } else if (mask == 0) {
+        /* ignore cc and never match */
+        gen_goto_tb(s, 0, s->pc + 4);
+    } else {
+        skip = gen_new_label();
+        gen_jcc(s, mask, skip);
+        gen_goto_tb(s, 0, s->pc + offset);
+        gen_set_label(skip);
+        gen_goto_tb(s, 1, s->pc + 4);
+    }
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
+{
+    TCGv_i64 tmp, tmp2;
+    int i;
+    int l_memset = gen_new_label();
+    int l_out = gen_new_label();
+    TCGv_i64 dest = tcg_temp_local_new_i64();
+    TCGv_i64 src = tcg_temp_local_new_i64();
+    TCGv_i32 vl;
+
+    /* Find out if we should use the inline version of mvc */
+    switch (l) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 11:
+    case 15:
+        /* use inline */
+        break;
+    default:
+        /* Fall back to helper */
+        vl = tcg_const_i32(l);
+        potential_page_fault(s);
+        gen_helper_mvc(vl, s1, s2);
+        tcg_temp_free_i32(vl);
+        return;
+    }
+
+    tcg_gen_mov_i64(dest, s1);
+    tcg_gen_mov_i64(src, s2);
+
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        /* XXX what if we overflow while moving? */
+        tcg_gen_andi_i64(dest, dest, 0x7fffffffUL);
+        tcg_gen_andi_i64(src, src, 0x7fffffffUL);
+    }
+
+    tmp = tcg_temp_new_i64();
+    tcg_gen_addi_i64(tmp, src, 1);
+    tcg_gen_brcond_i64(TCG_COND_EQ, dest, tmp, l_memset);
+    tcg_temp_free_i64(tmp);
+
+    switch (l) {
+    case 0:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 1:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld16u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st16(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 3:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st32(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 4:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s));
+        tcg_gen_addi_i64(src, src, 4);
+        tcg_gen_qemu_ld8u(tmp2, src, get_mem_index(s));
+        tcg_gen_qemu_st32(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 4);
+        tcg_gen_qemu_st8(tmp2, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 7:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld64(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        /* The inline version can become too big for too uneven numbers, only
+           use it on known good lengths */
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_const_i64(8);
+        for (i = 0; (i + 7) <= l; i += 8) {
+            tcg_gen_qemu_ld64(tmp, src, get_mem_index(s));
+            tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+
+            tcg_gen_add_i64(src, src, tmp2);
+            tcg_gen_add_i64(dest, dest, tmp2);
+        }
+
+        tcg_temp_free_i64(tmp2);
+        tmp2 = tcg_const_i64(1);
+
+        for (; i <= l; i++) {
+            tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+            tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+
+            tcg_gen_add_i64(src, src, tmp2);
+            tcg_gen_add_i64(dest, dest, tmp2);
+        }
+
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    }
+
+    tcg_gen_br(l_out);
+
+    gen_set_label(l_memset);
+    /* memset case (dest == (src + 1)) */
+
+    tmp = tcg_temp_new_i64();
+    tmp2 = tcg_temp_new_i64();
+    /* fill tmp with the byte */
+    tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+    tcg_gen_shli_i64(tmp2, tmp, 8);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_gen_shli_i64(tmp2, tmp, 16);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_gen_shli_i64(tmp2, tmp, 32);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_temp_free_i64(tmp2);
+
+    tmp2 = tcg_const_i64(8);
+
+    for (i = 0; (i + 7) <= l; i += 8) {
+        tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 8);
+    }
+
+    tcg_temp_free_i64(tmp2);
+    tmp2 = tcg_const_i64(1);
+
+    for (; i <= l; i++) {
+        tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 1);
+    }
+
+    tcg_temp_free_i64(tmp2);
+    tcg_temp_free_i64(tmp);
+
+    gen_set_label(l_out);
+
+    tcg_temp_free(dest);
+    tcg_temp_free(src);
+}
+
+static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
+{
+    TCGv_i64 tmp;
+    TCGv_i64 tmp2;
+    TCGv_i32 vl;
+
+    /* check for simple 32bit or 64bit match */
+    switch (l) {
+    case 0:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld8u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld8u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 1:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld16u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld16u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 3:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld32u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 7:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld64(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld64(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    }
+
+    potential_page_fault(s);
+    vl = tcg_const_i32(l);
+    gen_helper_clc(cc_op, vl, s1, s2);
+    tcg_temp_free_i32(vl);
+    set_cc_static(s);
+}
+
+static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
+{
+    TCGv_i64 addr, tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n",
+              op, r1, x2, b2, d2);
+    addr = get_address(s, x2, b2, d2);
+    switch (op) {
+    case 0x2: /* LTG R1,D2(X2,B2) [RXY] */
+    case 0x4: /* lg r1,d2(x2,b2) */
+        tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s));
+        if (op == 0x2) {
+            set_cc_s64(s, regs[r1]);
+        }
+        break;
+    case 0x12: /* LT R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_reg32(r1, tmp32_1);
+        set_cc_s32(s, tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xc: /* MSG      R1,D2(X2,B2)     [RXY] */
+    case 0x1c: /* MSGF     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0xc) {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        }
+        tcg_gen_mul_i64(regs[r1], regs[r1], tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xd: /* DSG      R1,D2(X2,B2)     [RXY] */
+    case 0x1d: /* DSGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x1d) {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1 + 1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_div_i64(tmp3, tmp4, tmp2);
+        store_reg(r1 + 1, tmp3);
+        tcg_gen_rem_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x8: /* AG      R1,D2(X2,B2)     [RXY] */
+    case 0xa: /* ALG      R1,D2(X2,B2)     [RXY] */
+    case 0x18: /* AGF       R1,D2(X2,B2)     [RXY] */
+    case 0x1a: /* ALGF      R1,D2(X2,B2)     [RXY] */
+        if (op == 0x1a) {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        } else if (op == 0x18) {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x8:
+        case 0x18:
+            set_cc_add64(s, tmp4, tmp2, tmp3);
+            break;
+        case 0xa:
+        case 0x1a:
+            set_cc_addu64(s, tmp4, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x9: /* SG      R1,D2(X2,B2)     [RXY] */
+    case 0xb: /* SLG      R1,D2(X2,B2)     [RXY] */
+    case 0x19: /* SGF      R1,D2(X2,B2)     [RXY] */
+    case 0x1b: /* SLGF     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x19) {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else if (op == 0x1b) {
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_sub_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x9:
+        case 0x19:
+            set_cc_sub64(s, tmp4, tmp2, tmp3);
+            break;
+        case 0xb:
+        case 0x1b:
+            set_cc_subu64(s, tmp4, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0xf: /* LRVG     R1,D2(X2,B2)     [RXE] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        tcg_gen_bswap64_i64(tmp2, tmp2);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x14: /* LGF      R1,D2(X2,B2)     [RXY] */
+    case 0x16: /* LLGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        if (op == 0x14) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x15: /* LGH     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s));
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x17: /* LLGT      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x1f: /* LRVH R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_bswap16_i32(tmp32_1, tmp32_1);
+        store_reg16(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x20: /* CG      R1,D2(X2,B2)     [RXY] */
+    case 0x21: /* CLG      R1,D2(X2,B2) */
+    case 0x30: /* CGF       R1,D2(X2,B2)     [RXY] */
+    case 0x31: /* CLGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        switch (op) {
+        case 0x20:
+        case 0x21:
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+            break;
+        case 0x30:
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+            break;
+        case 0x31:
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+            break;
+        default:
+            tcg_abort();
+        }
+        switch (op) {
+        case 0x20:
+        case 0x30:
+            cmp_s64(s, regs[r1], tmp2);
+            break;
+        case 0x21:
+        case 0x31:
+            cmp_u64(s, regs[r1], tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x24: /* stg r1, d2(x2,b2) */
+        tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x50: /* STY  R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x57: /* XY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_xor_i32(tmp32_2, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_2);
+        set_cc_nz_u32(s, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x58: /* LY R1,D2(X2,B2) [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5a: /* AY R1,D2(X2,B2) [RXY] */
+    case 0x5b: /* SY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_temp_free_i64(tmp2);
+        switch (op) {
+        case 0x5a:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        case 0x5b:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        switch (op) {
+        case 0x5a:
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5b:
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x71: /* LAY R1,D2(X2,B2) [RXY] */
+        store_reg(r1, addr);
+        break;
+    case 0x72: /* STCY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st8(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x73: /* ICY R1,D2(X2,B2) [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s));
+        store_reg8(r1, tmp3);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x76: /* LB R1,D2(X2,B2) [RXY] */
+    case 0x77: /* LGB R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8s(tmp2, addr, get_mem_index(s));
+        switch (op) {
+        case 0x76:
+            tcg_gen_ext8s_i64(tmp2, tmp2);
+            store_reg32_i64(r1, tmp2);
+            break;
+        case 0x77:
+            tcg_gen_ext8s_i64(tmp2, tmp2);
+            store_reg(r1, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x78: /* LHY R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x80: /* NG      R1,D2(X2,B2)     [RXY] */
+    case 0x81: /* OG      R1,D2(X2,B2)     [RXY] */
+    case 0x82: /* XG      R1,D2(X2,B2)     [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp3, addr, get_mem_index(s));
+        switch (op) {
+        case 0x80:
+            tcg_gen_and_i64(regs[r1], regs[r1], tmp3);
+            break;
+        case 0x81:
+            tcg_gen_or_i64(regs[r1], regs[r1], tmp3);
+            break;
+        case 0x82:
+            tcg_gen_xor_i64(regs[r1], regs[r1], tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        set_cc_nz_u64(s, regs[r1]);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x86: /* MLG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        gen_helper_mlg(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x87: /* DLG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        gen_helper_dlg(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x88: /* ALCG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        tcg_gen_extu_i32_i64(tmp3, cc_op);
+        tcg_gen_shri_i64(tmp3, tmp3, 1);
+        tcg_gen_andi_i64(tmp3, tmp3, 1);
+        tcg_gen_add_i64(tmp3, tmp2, tmp3);
+        tcg_gen_add_i64(tmp3, regs[r1], tmp3);
+        store_reg(r1, tmp3);
+        set_cc_addu64(s, regs[r1], tmp2, tmp3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x89: /* SLBG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x90: /* LLGC      R1,D2(X2,B2)     [RXY] */
+        tcg_gen_qemu_ld8u(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x91: /* LLGH      R1,D2(X2,B2)     [RXY] */
+        tcg_gen_qemu_ld16u(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x94: /* LLC     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x95: /* LLH     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x96: /* ML      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x97: /* DL     R1,D2(X2,B2)     [RXY] */
+        /* reg(r1) = reg(r1, r1+1) % ld32(addr) */
+        /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */
+        tmp = load_reg(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp3);
+
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        tcg_gen_div_i64(tmp, tmp, tmp2);
+        store_reg32_i64((r1 + 1) & 15, tmp);
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x98: /* ALC     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
+        set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x99: /* SLB     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal e3 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+    tcg_temp_free_i64(addr);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void disas_e5(DisasContext* s, uint64_t insn)
+{
+    TCGv_i64 tmp, tmp2;
+    int op = (insn >> 32) & 0xff;
+
+    tmp = get_address(s, 0, (insn >> 28) & 0xf, (insn >> 16) & 0xfff);
+    tmp2 = get_address(s, 0, (insn >> 12) & 0xf, insn & 0xfff);
+
+    LOG_DISAS("disas_e5: insn %" PRIx64 "\n", insn);
+    switch (op) {
+    case 0x01: /* TPROT    D1(B1),D2(B2)  [SSE] */
+        /* Test Protection */
+        potential_page_fault(s);
+        gen_helper_tprot(cc_op, tmp, tmp2);
+        set_cc_static(s);
+        break;
+    default:
+        LOG_DISAS("illegal e5 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+
+    tcg_temp_free_i64(tmp);
+    tcg_temp_free_i64(tmp2);
+}
+#endif
+
+static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2)
+{
+    TCGv_i64 tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2;
+    int i, stm_len;
+    int ilc = 3;
+
+    LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n",
+              op, r1, r3, b2, d2);
+    switch (op) {
+    case 0xc: /* SRLG     R1,R3,D2(B2)     [RSY] */
+    case 0xd: /* SLLG     R1,R3,D2(B2)     [RSY] */
+    case 0xa: /* SRAG     R1,R3,D2(B2)     [RSY] */
+    case 0xb: /* SLAG     R1,R3,D2(B2)     [RSY] */
+    case 0x1c: /* RLLG     R1,R3,D2(B2)     [RSY] */
+        if (b2) {
+            tmp = get_address(s, 0, b2, d2);
+            tcg_gen_andi_i64(tmp, tmp, 0x3f);
+        } else {
+            tmp = tcg_const_i64(d2 & 0x3f);
+        }
+        switch (op) {
+        case 0xc:
+            tcg_gen_shr_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xd:
+            tcg_gen_shl_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xa:
+            tcg_gen_sar_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xb:
+            tmp2 = tcg_temp_new_i64();
+            tmp3 = tcg_temp_new_i64();
+            gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp);
+            tcg_gen_shl_i64(tmp2, regs[r3], tmp);
+            /* override sign bit with source sign */
+            tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL);
+            tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL);
+            tcg_gen_or_i64(regs[r1], tmp2, tmp3);
+            tcg_temp_free_i64(tmp2);
+            tcg_temp_free_i64(tmp3);
+            break;
+        case 0x1c:
+            tcg_gen_rotl_i64(regs[r1], regs[r3], tmp);
+            break;
+        default:
+            tcg_abort();
+            break;
+        }
+        if (op == 0xa) {
+            set_cc_s64(s, regs[r1]);
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1d: /* RLL    R1,R3,D2(B2)        [RSY] */
+        if (b2) {
+            tmp = get_address(s, 0, b2, d2);
+            tcg_gen_andi_i64(tmp, tmp, 0x3f);
+        } else {
+            tmp = tcg_const_i64(d2 & 0x3f);
+        }
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r3);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        switch (op) {
+        case 0x1d:
+            tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1);
+            break;
+        default:
+            tcg_abort();
+            break;
+        }
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x4:  /* LMG      R1,R3,D2(B2)     [RSE] */
+    case 0x24: /* STMG     R1,R3,D2(B2)     [RSE] */
+        stm_len = 8;
+        goto do_mh;
+    case 0x26: /* STMH     R1,R3,D2(B2)     [RSE] */
+    case 0x96: /* LMH      R1,R3,D2(B2)     [RSE] */
+        stm_len = 4;
+do_mh:
+        /* Apparently, unrolling lmg/stmg of any size gains performance -
+           even for very long ones... */
+        tmp = get_address(s, 0, b2, d2);
+        tmp3 = tcg_const_i64(stm_len);
+        tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4);
+        for (i = r1;; i = (i + 1) % 16) {
+            switch (op) {
+            case 0x4:
+                tcg_gen_qemu_ld64(regs[i], tmp, get_mem_index(s));
+                break;
+            case 0x96:
+                tmp2 = tcg_temp_new_i64();
+#if HOST_LONG_BITS == 32
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2);
+#else
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_shl_i64(tmp2, tmp2, tmp4);
+                tcg_gen_ext32u_i64(regs[i], regs[i]);
+                tcg_gen_or_i64(regs[i], regs[i], tmp2);
+#endif
+                tcg_temp_free_i64(tmp2);
+                break;
+            case 0x24:
+                tcg_gen_qemu_st64(regs[i], tmp, get_mem_index(s));
+                break;
+            case 0x26:
+                tmp2 = tcg_temp_new_i64();
+                tcg_gen_shr_i64(tmp2, regs[i], tmp4);
+                tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+                tcg_temp_free_i64(tmp2);
+                break;
+            default:
+                tcg_abort();
+            }
+            if (i == r3) {
+                break;
+            }
+            tcg_gen_add_i64(tmp, tmp, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stcmh(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x2f: /* LCTLG     R1,R3,D2(B2)     [RSE] */
+        /* Load Control */
+        check_privileged(s, ilc);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lctlg(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x25: /* STCTG     R1,R3,D2(B2)     [RSE] */
+        /* Store Control */
+        check_privileged(s, ilc);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stctg(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#endif
+    case 0x30: /* CSG     R1,R3,D2(B2)     [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX rewrite in tcg */
+        gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX rewrite in tcg */
+        gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x51: /* TMY D1(B1),I2 [SIY] */
+        tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
+        tmp2 = tcg_const_i64((r1 << 4) | r3);
+        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
+        /* yes, this is a 32 bit operation with 64 bit tcg registers, because
+           that incurs less conversions */
+        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x52: /* MVIY D1(B1),I2 [SIY] */
+        tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
+        tmp2 = tcg_const_i64((r1 << 4) | r3);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x55: /* CLIY D1(B1),I2 [SIY] */
+        tmp3 = get_address(s, 0, b2, d2); /* SIY -> this is the 1st operand */
+        tmp = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld8u(tmp, tmp3, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        cmp_u32c(s, tmp32_1, (r1 << 4) | r3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x80: /* ICMH      R1,M3,D2(B2)     [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX split CC calculation out */
+        gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal eb operation 0x%x\n", op);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+}
+
+static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
+                     int r1b)
+{
+    TCGv_i32 tmp_r1, tmp32;
+    TCGv_i64 addr, tmp;
+    addr = get_address(s, x2, b2, d2);
+    tmp_r1 = tcg_const_i32(r1);
+    switch (op) {
+    case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */
+        potential_page_fault(s);
+        gen_helper_ldeb(tmp_r1, addr);
+        break;
+    case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */
+        potential_page_fault(s);
+        gen_helper_lxdb(tmp_r1, addr);
+        break;
+    case 0x9: /* CEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = load_freg32(r1);
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        set_cc_cmp_f32_i64(s, tmp32, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xa: /* AEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_aeb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+
+        tmp32 = load_freg32(r1);
+        set_cc_nz_f32(s, tmp32);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xb: /* SEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_seb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+
+        tmp32 = load_freg32(r1);
+        set_cc_nz_f32(s, tmp32);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xd: /* DEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_deb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0x10: /* TCEB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tceb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x11: /* TCDB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tcdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x12: /* TCXB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tcxb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x17: /* MEEB   R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_meeb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0x19: /* CDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_cdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1a: /* ADB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_adb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1b: /* SDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_sdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1c: /* MDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_mdb(tmp_r1, addr);
+        break;
+    case 0x1d: /* DDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_ddb(tmp_r1, addr);
+        break;
+    case 0x1e: /* MADB  R1,R3,D2(X2,B2) [RXF] */
+        /* for RXF insns, r1 is R3 and r1b is R1 */
+        tmp32 = tcg_const_i32(r1b);
+        potential_page_fault(s);
+        gen_helper_madb(tmp32, addr, tmp_r1);
+        tcg_temp_free_i32(tmp32);
+        break;
+    default:
+        LOG_DISAS("illegal ed operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        return;
+    }
+    tcg_temp_free_i32(tmp_r1);
+    tcg_temp_free_i64(addr);
+}
+
+static void disas_a5(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2;
+    TCGv_i32 tmp32;
+    LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2);
+    switch (op) {
+    case 0x0: /* IIHH     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1: /* IIHL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x2: /* IILH     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x3: /* IILL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* NIHH     R1,I2     [RI] */
+    case 0x8: /* OIHH     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x4:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 48)
+                               | 0x0000ffffffffffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x8:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 48);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp2, tmp, 48);
+        tcg_gen_trunc_i64_i32(tmp32, tmp2);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x5: /* NIHL     R1,I2     [RI] */
+    case 0x9: /* OIHL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x5:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 32)
+                               | 0xffff0000ffffffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x9:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 32);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp2, tmp, 32);
+        tcg_gen_trunc_i64_i32(tmp32, tmp2);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x6: /* NILH     R1,I2     [RI] */
+    case 0xa: /* OILH     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x6:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 16)
+                               | 0xffffffff0000ffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0xa:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 16);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp, tmp, 16);
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x7: /* NILL     R1,I2     [RI] */
+    case 0xb: /* OILL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x7:
+            tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0xb:
+            tmp2 = tcg_const_i64(i2);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);        /* signedness should not matter here */
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xc: /* LLIHH     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 48 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xd: /* LLIHL     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 32 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* LLILH     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 16 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xf: /* LLILL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal a5 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        return;
+    }
+}
+
+static void disas_a7(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    int l1;
+
+    LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2);
+    switch (op) {
+    case 0x0: /* TMLH or TMH     R1,I2     [RI] */
+    case 0x1: /* TMLL or TML     R1,I2     [RI] */
+    case 0x2: /* TMHH     R1,I2     [RI] */
+    case 0x3: /* TMHL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64((uint16_t)i2);
+        switch (op) {
+        case 0x0:
+            tcg_gen_shri_i64(tmp, tmp, 16);
+            break;
+        case 0x1:
+            break;
+        case 0x2:
+            tcg_gen_shri_i64(tmp, tmp, 48);
+            break;
+        case 0x3:
+            tcg_gen_shri_i64(tmp, tmp, 32);
+            break;
+        }
+        tcg_gen_andi_i64(tmp, tmp, 0xffff);
+        cmp_64(s, tmp, tmp2, CC_OP_TM_64);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4: /* brc m1, i2 */
+        gen_brc(r1, s, i2 * 2LL);
+        return;
+    case 0x5: /* BRAS     R1,I2     [RI] */
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 4));
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        gen_goto_tb(s, 0, s->pc + i2 * 2LL);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x6: /* BRCT     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1);
+        gen_goto_tb(s, 0, s->pc + (i2 * 2LL));
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 4);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x7: /* BRCTG     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tcg_gen_subi_i64(tmp, tmp, 1);
+        store_reg(r1, tmp);
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1);
+        gen_goto_tb(s, 0, s->pc + (i2 * 2LL));
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 4);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x8: /* lhi r1, i2 */
+        tmp32_1 = tcg_const_i32(i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x9: /* lghi r1, i2 */
+        tmp = tcg_const_i64(i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa: /* AHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_const_i32(i2);
+
+        if (i2 < 0) {
+            tcg_gen_subi_i32(tmp32_2, tmp32_1, -i2);
+        } else {
+            tcg_gen_add_i32(tmp32_2, tmp32_1, tmp32_3);
+        }
+
+        store_reg32(r1, tmp32_2);
+        set_cc_add32(s, tmp32_1, tmp32_3, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xb: /* aghi r1, i2 */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64(i2);
+
+        if (i2 < 0) {
+            tcg_gen_subi_i64(regs[r1], tmp, -i2);
+        } else {
+            tcg_gen_add_i64(regs[r1], tmp, tmp2);
+        }
+        set_cc_add64(s, tmp, tmp2, regs[r1]);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xc: /* MHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_muli_i32(tmp32_1, tmp32_1, i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xd: /* MGHI     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tcg_gen_muli_i64(tmp, tmp, i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* CHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        cmp_s32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xf: /* CGHI     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        cmp_s64c(s, tmp, i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal a7 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        return;
+    }
+}
+
+static void disas_b2(DisasContext *s, int op, uint32_t insn)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    int r1, r2;
+    int ilc = 2;
+#ifndef CONFIG_USER_ONLY
+    int r3, d2, b2;
+#endif
+
+    r1 = (insn >> 4) & 0xf;
+    r2 = insn & 0xf;
+
+    LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2);
+
+    switch (op) {
+    case 0x22: /* IPM    R1               [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_ipm(cc_op, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x41: /* CKSM    R1,R2     [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_cksm(tmp32_1, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        gen_op_movi_cc(s, 0);
+        break;
+    case 0x4e: /* SAR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, aregs[r1]));
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x4f: /* EAR     R1,R2     [RRE] */
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, aregs[r2]));
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x52: /* MSR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x54: /* MVPG     R1,R2     [RRE] */
+        tmp = load_reg(0);
+        tmp2 = load_reg(r1);
+        tmp3 = load_reg(r2);
+        potential_page_fault(s);
+        gen_helper_mvpg(tmp, tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        /* XXX check CCO bit and set CC accordingly */
+        gen_op_movi_cc(s, 0);
+        break;
+    case 0x55: /* MVST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        gen_op_movi_cc(s, 1);
+        break;
+    case 0x5d: /* CLST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x5e: /* SRST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+
+#ifndef CONFIG_USER_ONLY
+    case 0x02: /* STIDP     D2(B2)     [S] */
+        /* Store CPU ID */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stidp(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x04: /* SCK       D2(B2)     [S] */
+        /* Set Clock */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sck(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x05: /* STCK     D2(B2)     [S] */
+        /* Store Clock */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stck(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x06: /* SCKC     D2(B2)     [S] */
+        /* Set Clock Comparator */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sckc(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x07: /* STCKC    D2(B2)     [S] */
+        /* Store Clock Comparator */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stckc(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x08: /* SPT      D2(B2)     [S] */
+        /* Set CPU Timer */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_spt(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x09: /* STPT     D2(B2)     [S] */
+        /* Store CPU Timer */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stpt(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x0a: /* SPKA     D2(B2)     [S] */
+        /* Set PSW Key from Address */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_andi_i64(tmp2, psw_mask, ~PSW_MASK_KEY);
+        tcg_gen_shli_i64(tmp, tmp, PSW_SHIFT_KEY - 4);
+        tcg_gen_or_i64(psw_mask, tmp2, tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x0d: /* PTLB                [S] */
+        /* Purge TLB */
+        check_privileged(s, ilc);
+        gen_helper_ptlb();
+        break;
+    case 0x10: /* SPX      D2(B2)     [S] */
+        /* Set Prefix Register */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_spx(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x11: /* STPX     D2(B2)     [S] */
+        /* Store Prefix */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tmp2, cpu_env, offsetof(CPUState, psa));
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x12: /* STAP     D2(B2)     [S] */
+        /* Store CPU Address */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, cpu_num));
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x21: /* IPTE     R1,R2      [RRE] */
+        /* Invalidate PTE */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        gen_helper_ipte(tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x29: /* ISKE     R1,R2      [RRE] */
+        /* Insert Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp = load_reg(r2);
+        tmp2 = tcg_temp_new_i64();
+        gen_helper_iske(tmp2, tmp);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x2a: /* RRBE     R1,R2      [RRE] */
+        /* Set Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        gen_helper_rrbe(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x2b: /* SSKE     R1,R2      [RRE] */
+        /* Set Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        gen_helper_sske(tmp32_1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x34: /* STCH ? */
+        /* Store Subchannel */
+        check_privileged(s, ilc);
+        gen_op_movi_cc(s, 3);
+        break;
+    case 0x46: /* STURA    R1,R2      [RRE] */
+        /* Store Using Real Address */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        potential_page_fault(s);
+        gen_helper_stura(tmp, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x50: /* CSP      R1,R2      [RRE] */
+        /* Compare And Swap And Purge */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        gen_helper_csp(cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5f: /* CHSC ? */
+        /* Channel Subsystem Call */
+        check_privileged(s, ilc);
+        gen_op_movi_cc(s, 3);
+        break;
+    case 0x78: /* STCKE    D2(B2)     [S] */
+        /* Store Clock Extended */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stcke(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x79: /* SACF    D2(B2)     [S] */
+        /* Store Clock Extended */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sacf(tmp);
+        tcg_temp_free_i64(tmp);
+        /* addressing mode has changed, so end the block */
+        s->pc += ilc * 2;
+        update_psw_addr(s);
+        s->is_jmp = DISAS_EXCP;
+        break;
+    case 0x7d: /* STSI     D2,(B2)     [S] */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = load_reg32(1);
+        potential_page_fault(s);
+        gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x9d: /* LFPC      D2(B2)   [S] */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xb1: /* STFL     D2(B2)     [S] */
+        /* Store Facility List (CPU features) at 200 */
+        check_privileged(s, ilc);
+        tmp2 = tcg_const_i64(0xc0000000);
+        tmp = tcg_const_i64(200);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xb2: /* LPSWE    D2(B2)     [S] */
+        /* Load PSW Extended */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
+        tcg_gen_addi_i64(tmp, tmp, 8);
+        tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s));
+        gen_helper_load_psw(tmp2, tmp3);
+        /* we need to keep cc_op intact */
+        s->is_jmp = DISAS_JUMP;
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x20: /* SERVC     R1,R2     [RRE] */
+        /* SCLP Service call (PV hypercall) */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        tmp32_1 = load_reg32(r2);
+        tmp = load_reg(r1);
+        gen_helper_servc(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+#endif
+    default:
+        LOG_DISAS("illegal b2 operation 0x%x\n", op);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+}
+
+static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
+{
+    TCGv_i64 tmp;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2);
+#define FP_HELPER(i) \
+    tmp32_1 = tcg_const_i32(r1); \
+    tmp32_2 = tcg_const_i32(r2); \
+    gen_helper_ ## i (tmp32_1, tmp32_2); \
+    tcg_temp_free_i32(tmp32_1); \
+    tcg_temp_free_i32(tmp32_2);
+
+#define FP_HELPER_CC(i) \
+    tmp32_1 = tcg_const_i32(r1); \
+    tmp32_2 = tcg_const_i32(r2); \
+    gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \
+    set_cc_static(s); \
+    tcg_temp_free_i32(tmp32_1); \
+    tcg_temp_free_i32(tmp32_2);
+
+    switch (op) {
+    case 0x0: /* LPEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpebr);
+        break;
+    case 0x2: /* LTEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltebr);
+        break;
+    case 0x3: /* LCEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcebr);
+        break;
+    case 0x4: /* LDEBR       R1,R2             [RRE] */
+        FP_HELPER(ldebr);
+        break;
+    case 0x5: /* LXDBR       R1,R2             [RRE] */
+        FP_HELPER(lxdbr);
+        break;
+    case 0x9: /* CEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cebr);
+        break;
+    case 0xa: /* AEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(aebr);
+        break;
+    case 0xb: /* SEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sebr);
+        break;
+    case 0xd: /* DEBR        R1,R2             [RRE] */
+        FP_HELPER(debr);
+        break;
+    case 0x10: /* LPDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpdbr);
+        break;
+    case 0x12: /* LTDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltdbr);
+        break;
+    case 0x13: /* LCDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcdbr);
+        break;
+    case 0x15: /* SQBDR       R1,R2             [RRE] */
+        FP_HELPER(sqdbr);
+        break;
+    case 0x17: /* MEEBR       R1,R2             [RRE] */
+        FP_HELPER(meebr);
+        break;
+    case 0x19: /* CDBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cdbr);
+        break;
+    case 0x1a: /* ADBR        R1,R2             [RRE] */
+        FP_HELPER_CC(adbr);
+        break;
+    case 0x1b: /* SDBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sdbr);
+        break;
+    case 0x1c: /* MDBR        R1,R2             [RRE] */
+        FP_HELPER(mdbr);
+        break;
+    case 0x1d: /* DDBR        R1,R2             [RRE] */
+        FP_HELPER(ddbr);
+        break;
+    case 0xe: /* MAEBR  R1,R3,R2 [RRF] */
+    case 0x1e: /* MADBR R1,R3,R2 [RRF] */
+    case 0x1f: /* MSDBR R1,R3,R2 [RRF] */
+        /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */
+        tmp32_1 = tcg_const_i32(m3);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(r1);
+        switch (op) {
+        case 0xe:
+            gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        case 0x1e:
+            gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        case 0x1f:
+            gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x40: /* LPXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpxbr);
+        break;
+    case 0x42: /* LTXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltxbr);
+        break;
+    case 0x43: /* LCXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcxbr);
+        break;
+    case 0x44: /* LEDBR       R1,R2             [RRE] */
+        FP_HELPER(ledbr);
+        break;
+    case 0x45: /* LDXBR       R1,R2             [RRE] */
+        FP_HELPER(ldxbr);
+        break;
+    case 0x46: /* LEXBR       R1,R2             [RRE] */
+        FP_HELPER(lexbr);
+        break;
+    case 0x49: /* CXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cxbr);
+        break;
+    case 0x4a: /* AXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(axbr);
+        break;
+    case 0x4b: /* SXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sxbr);
+        break;
+    case 0x4c: /* MXBR        R1,R2             [RRE] */
+        FP_HELPER(mxbr);
+        break;
+    case 0x4d: /* DXBR        R1,R2             [RRE] */
+        FP_HELPER(dxbr);
+        break;
+    case 0x65: /* LXR         R1,R2             [RRE] */
+        tmp = load_freg(r2);
+        store_freg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        tmp = load_freg(r2 + 2);
+        store_freg(r1 + 2, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x74: /* LZER        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzer(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x75: /* LZDR        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzdr(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x76: /* LZXR        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzxr(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x84: /* SFPC        R1                [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x8c: /* EFPC        R1                [RRE] */
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x94: /* CEFBR       R1,R2             [RRE] */
+    case 0x95: /* CDFBR       R1,R2             [RRE] */
+    case 0x96: /* CXFBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = load_reg32(r2);
+        switch (op) {
+        case 0x94:
+            gen_helper_cefbr(tmp32_1, tmp32_2);
+            break;
+        case 0x95:
+            gen_helper_cdfbr(tmp32_1, tmp32_2);
+            break;
+        case 0x96:
+            gen_helper_cxfbr(tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x98: /* CFEBR       R1,R2             [RRE] */
+    case 0x99: /* CFDBR              R1,R2             [RRE] */
+    case 0x9a: /* CFXBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        switch (op) {
+        case 0x98:
+            gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x99:
+            gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x9a:
+            gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xa4: /* CEGBR       R1,R2             [RRE] */
+    case 0xa5: /* CDGBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        switch (op) {
+        case 0xa4:
+            gen_helper_cegbr(tmp32_1, tmp);
+            break;
+        case 0xa5:
+            gen_helper_cdgbr(tmp32_1, tmp);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa6: /* CXGBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        gen_helper_cxgbr(tmp32_1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa8: /* CGEBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xa9: /* CGDBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xaa: /* CGXBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    default:
+        LOG_DISAS("illegal b3 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        break;
+    }
+
+#undef FP_HELPER_CC
+#undef FP_HELPER
+}
+
+static void disas_b9(DisasContext *s, int op, int r1, int r2)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2);
+    switch (op) {
+    case 0x0: /* LPGR     R1,R2     [RRE] */
+    case 0x1: /* LNGR     R1,R2     [RRE] */
+    case 0x2: /* LTGR R1,R2 [RRE] */
+    case 0x3: /* LCGR     R1,R2     [RRE] */
+    case 0x10: /* LPGFR R1,R2 [RRE] */
+    case 0x11: /* LNFGR     R1,R2     [RRE] */
+    case 0x12: /* LTGFR R1,R2 [RRE] */
+    case 0x13: /* LCGFR    R1,R2     [RRE] */
+        if (op & 0x10) {
+            tmp = load_reg32_i64(r2);
+        } else {
+            tmp = load_reg(r2);
+        }
+        switch (op & 0xf) {
+        case 0x0: /* LP?GR */
+            set_cc_abs64(s, tmp);
+            gen_helper_abs_i64(tmp, tmp);
+            store_reg(r1, tmp);
+            break;
+        case 0x1: /* LN?GR */
+            set_cc_nabs64(s, tmp);
+            gen_helper_nabs_i64(tmp, tmp);
+            store_reg(r1, tmp);
+            break;
+        case 0x2: /* LT?GR */
+            if (r1 != r2) {
+                store_reg(r1, tmp);
+            }
+            set_cc_s64(s, tmp);
+            break;
+        case 0x3: /* LC?GR */
+            tcg_gen_neg_i64(regs[r1], tmp);
+            set_cc_comp64(s, regs[r1]);
+            break;
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* LGR R1,R2 [RRE] */
+        store_reg(r1, regs[r2]);
+        break;
+    case 0x6: /* LGBR R1,R2 [RRE] */
+        tmp2 = load_reg(r2);
+        tcg_gen_ext8s_i64(tmp2, tmp2);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x8: /* AGR     R1,R2     [RRE] */
+    case 0xa: /* ALGR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x8:
+            set_cc_add64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xa:
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x9: /* SGR     R1,R2     [RRE] */
+    case 0xb: /* SLGR     R1,R2     [RRE] */
+    case 0x1b: /* SLGFR     R1,R2     [RRE] */
+    case 0x19: /* SGFR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        switch (op) {
+        case 0x1b:
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+            break;
+        case 0x19:
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+            break;
+        default:
+            tmp2 = load_reg(r2);
+            break;
+        }
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_sub_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x9:
+        case 0x19:
+            set_cc_sub64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xb:
+        case 0x1b:
+            set_cc_subu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0xc: /* MSGR      R1,R2     [RRE] */
+    case 0x1c: /* MSGFR      R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        if (op == 0x1c) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        tcg_gen_mul_i64(tmp, tmp, tmp2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xd: /* DSGR      R1,R2     [RRE] */
+    case 0x1d: /* DSGFR      R1,R2     [RRE] */
+        tmp = load_reg(r1 + 1);
+        if (op == 0xd) {
+            tmp2 = load_reg(r2);
+        } else {
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+        }
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        store_reg(r1 + 1, tmp3);
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x14: /* LGFR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_ext_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x16: /* LLGFR      R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x17: /* LLGTR      R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0x7fffffffUL);
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x18: /* AGFR     R1,R2     [RRE] */
+    case 0x1a: /* ALGFR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x18) {
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+        } else {
+            tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tmp = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        if (op == 0x18) {
+            set_cc_add64(s, tmp, tmp2, tmp3);
+        } else {
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x0f: /* LRVGR    R1,R2     [RRE] */
+        tcg_gen_bswap64_i64(regs[r1], regs[r2]);
+        break;
+    case 0x1f: /* LRVR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x20: /* CGR      R1,R2     [RRE] */
+    case 0x30: /* CGFR     R1,R2     [RRE] */
+        tmp2 = load_reg(r2);
+        if (op == 0x30) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        tmp = load_reg(r1);
+        cmp_s64(s, tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x21: /* CLGR     R1,R2     [RRE] */
+    case 0x31: /* CLGFR    R1,R2     [RRE] */
+        tmp2 = load_reg(r2);
+        if (op == 0x31) {
+            tcg_gen_ext32u_i64(tmp2, tmp2);
+        }
+        tmp = load_reg(r1);
+        cmp_u64(s, tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x26: /* LBR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_ext8s_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x27: /* LHR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_ext16s_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x80: /* NGR R1,R2 [RRE] */
+    case 0x81: /* OGR R1,R2 [RRE] */
+    case 0x82: /* XGR R1,R2 [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        switch (op) {
+        case 0x80:
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x81:
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        case 0x82:
+            tcg_gen_xor_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        set_cc_nz_u64(s, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x83: /* FLOGR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_flogr(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x84: /* LLGCR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tcg_gen_andi_i64(tmp, tmp, 0xff);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x85: /* LLGHR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tcg_gen_andi_i64(tmp, tmp, 0xffff);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x87: /* DLGR      R1,R2     [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        gen_helper_dlg(tmp32_1, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x88: /* ALCGR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = tcg_temp_new_i64();
+        gen_op_calc_cc(s);
+        tcg_gen_extu_i32_i64(tmp3, cc_op);
+        tcg_gen_shri_i64(tmp3, tmp3, 1);
+        tcg_gen_andi_i64(tmp3, tmp3, 1);
+        tcg_gen_add_i64(tmp3, tmp2, tmp3);
+        tcg_gen_add_i64(tmp3, tmp, tmp3);
+        store_reg(r1, tmp3);
+        set_cc_addu64(s, tmp, tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x89: /* SLBGR   R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp32_1 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x94: /* LLCR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xff);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x95: /* LLHR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xffff);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x96: /* MLR     R1,R2     [RRE] */
+        /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x97: /* DLR     R1,R2     [RRE] */
+        /* reg(r1) = reg(r1, r1+1) % reg(r2) */
+        /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp3);
+
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        tcg_gen_div_i64(tmp, tmp, tmp2);
+        store_reg32_i64((r1 + 1) & 15, tmp);
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x98: /* ALCR    R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
+        set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x99: /* SLBR    R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp32_2 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal b9 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        break;
+    }
+}
+
+static void disas_c0(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp;
+    TCGv_i32 tmp32_1, tmp32_2;
+    uint64_t target = s->pc + i2 * 2LL;
+    int l1;
+
+    LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2);
+
+    switch (op) {
+    case 0: /* larl r1, i2 */
+        tmp = tcg_const_i64(target);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1: /* LGFI R1,I2 [RIL] */
+        tmp = tcg_const_i64((int64_t)i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* BRCL     M1,I2     [RIL] */
+        /* m1 & (1 << (3 - cc)) */
+        tmp32_1 = tcg_const_i32(3);
+        tmp32_2 = tcg_const_i32(1);
+        gen_op_calc_cc(s);
+        tcg_gen_sub_i32(tmp32_1, tmp32_1, cc_op);
+        tcg_gen_shl_i32(tmp32_2, tmp32_2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tmp32_1 = tcg_const_i32(r1); /* m1 == r1 */
+        tcg_gen_and_i32(tmp32_1, tmp32_1, tmp32_2);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1);
+        gen_goto_tb(s, 0, target);
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 6);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5: /* brasl r1, i2 */
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 6));
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        gen_goto_tb(s, 0, target);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x7: /* XILF R1,I2 [RIL] */
+    case 0xb: /* NILF R1,I2 [RIL] */
+    case 0xd: /* OILF R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        switch (op) {
+        case 0x7:
+            tcg_gen_xori_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        case 0xb:
+            tcg_gen_andi_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        case 0xd:
+            tcg_gen_ori_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x9: /* IILF R1,I2 [RIL] */
+        tmp32_1 = tcg_const_i32((uint32_t)i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xa: /* NIHF R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32)
+                                   | 0xffffffffULL);
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp, tmp, 32);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xe: /* LLIHF R1,I2 [RIL] */
+        tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xf: /* LLILF R1,I2 [RIL] */
+        tmp = tcg_const_i64((uint32_t)i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal c0 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+}
+
+static void disas_c2(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    switch (op) {
+    case 0x4: /* SLGFI R1,I2 [RIL] */
+    case 0xa: /* ALGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2);
+        tmp3 = tcg_temp_new_i64();
+        switch (op) {
+        case 0x4:
+            tcg_gen_sub_i64(tmp3, tmp, tmp2);
+            set_cc_subu64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xa:
+            tcg_gen_add_i64(tmp3, tmp, tmp2);
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5: /* SLFI R1,I2 [RIL] */
+    case 0xb: /* ALFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(i2);
+        tmp32_3 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x5:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0xb:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xc: /* CGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        cmp_s64c(s, tmp, (int64_t)i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* CLGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        cmp_u64c(s, tmp, (uint64_t)(uint32_t)i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xd: /* CFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        cmp_s32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xf: /* CLFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        cmp_u32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    default:
+        LOG_DISAS("illegal c2 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+}
+
+static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2)
+{
+    switch (opc & 0xf) {
+    case 0x4:
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        break;
+    case 0x6:
+        tcg_gen_or_i32(tmp, tmp, tmp2);
+        break;
+    case 0x7:
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void disas_s390_insn(DisasContext *s)
+{
+    TCGv_i64 tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4;
+    unsigned char opc;
+    uint64_t insn;
+    int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b;
+    TCGv_i32 vl;
+    int ilc;
+    int l1;
+
+    opc = ldub_code(s->pc);
+    LOG_DISAS("opc 0x%x\n", opc);
+
+    ilc = get_ilc(opc);
+
+    switch (opc) {
+#ifndef CONFIG_USER_ONLY
+    case 0x01: /* SAM */
+        insn = ld_code2(s->pc);
+        /* set addressing mode, but we only do 64bit anyways */
+        break;
+#endif
+    case 0x6: /* BCTR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+
+        if (r2) {
+            gen_update_cc_op(s);
+            l1 = gen_new_label();
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1);
+
+            /* not taking the branch, jump to after the instruction */
+            gen_goto_tb(s, 0, s->pc + 2);
+            gen_set_label(l1);
+
+            /* take the branch, move R2 into psw.addr */
+            tmp32_1 = load_reg32(r2);
+            tmp = tcg_temp_new_i64();
+            tcg_gen_extu_i32_i64(tmp, tmp32_1);
+            tcg_gen_mov_i64(psw_addr, tmp);
+            s->is_jmp = DISAS_JUMP;
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i64(tmp);
+        }
+        break;
+    case 0x7: /* BCR    M1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        if (r2) {
+            tmp = load_reg(r2);
+            gen_bcr(s, r1, tmp, s->pc);
+            tcg_temp_free_i64(tmp);
+            s->is_jmp = DISAS_TB_JUMP;
+        } else {
+            /* XXX: "serialization and checkpoint-synchronization function"? */
+        }
+        break;
+    case 0xa: /* SVC    I         [RR] */
+        insn = ld_code2(s->pc);
+        debug_insn(insn);
+        i = insn & 0xff;
+        update_psw_addr(s);
+        gen_op_calc_cc(s);
+        tmp32_1 = tcg_const_i32(i);
+        tmp32_2 = tcg_const_i32(ilc * 2);
+        tmp32_3 = tcg_const_i32(EXCP_SVC);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, int_svc_code));
+        tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUState, int_svc_ilc));
+        gen_helper_exception(tmp32_3);
+        s->is_jmp = DISAS_EXCP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xd: /* BASR   R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2));
+        store_reg(r1, tmp);
+        if (r2) {
+            tmp2 = load_reg(r2);
+            tcg_gen_mov_i64(psw_addr, tmp2);
+            tcg_temp_free_i64(tmp2);
+            s->is_jmp = DISAS_JUMP;
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* MVCL   R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_mvcl(cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x10: /* LPR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        set_cc_abs32(s, tmp32_1);
+        gen_helper_abs_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x11: /* LNR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        set_cc_nabs32(s, tmp32_1);
+        gen_helper_nabs_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x12: /* LTR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        if (r1 != r2) {
+            store_reg32(r1, tmp32_1);
+        }
+        set_cc_s32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x13: /* LCR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_neg_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        set_cc_comp32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x14: /* NR     R1,R2     [RR] */
+    case 0x16: /* OR     R1,R2     [RR] */
+    case 0x17: /* XR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_2 = load_reg32(r2);
+        tmp32_1 = load_reg32(r1);
+        gen_and_or_xor_i32(opc, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x18: /* LR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x15: /* CLR    R1,R2     [RR] */
+    case 0x19: /* CR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        if (opc == 0x15) {
+            cmp_u32(s, tmp32_1, tmp32_2);
+        } else {
+            cmp_s32(s, tmp32_1, tmp32_2);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x1a: /* AR     R1,R2     [RR] */
+    case 0x1e: /* ALR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_3);
+        if (opc == 0x1a) {
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+        } else {
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x1b: /* SR     R1,R2     [RR] */
+    case 0x1f: /* SLR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_3);
+        if (opc == 0x1b) {
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+        } else {
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x1c: /* MR     R1,R2     [RR] */
+        /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32s_i64(tmp2, tmp2);
+        tcg_gen_ext32s_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x1d: /* DR     R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+        tmp32_3 = load_reg32(r2);
+
+        tmp = tcg_temp_new_i64(); /* dividend */
+        tmp2 = tcg_temp_new_i64(); /* divisor */
+        tmp3 = tcg_temp_new_i64();
+
+        /* dividend is r(r1 << 32) | r(r1 + 1) */
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_2);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp2);
+
+        /* divisor is r(r2) */
+        tcg_gen_ext_i32_i64(tmp2, tmp32_3);
+
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        tcg_gen_rem_i64(tmp, tmp, tmp2);
+
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp3);
+
+        store_reg32(r1, tmp32_1); /* remainder */
+        store_reg32(r1 + 1, tmp32_2); /* quotient */
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x28: /* LDR    R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp = load_freg(r2);
+        store_freg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x38: /* LER    R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_freg32(r2);
+        store_freg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x40: /* STH    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x41:        /* la */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x42: /* STC    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x43: /* IC     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        store_reg8(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x44: /* EX     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tmp3 = tcg_const_i64(s->pc + 4);
+        update_psw_addr(s);
+        gen_op_calc_cc(s);
+        gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x46: /* BCT    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tcg_temp_free_i64(tmp);
+
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1);
+
+        /* not taking the branch, jump to after the instruction */
+        gen_goto_tb(s, 0, s->pc + 4);
+        gen_set_label(l1);
+
+        /* take the branch, move R2 into psw.addr */
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tcg_gen_mov_i64(psw_addr, tmp);
+        s->is_jmp = DISAS_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x47: /* BC     M1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        gen_bcr(s, r1, tmp, s->pc + 4);
+        tcg_temp_free_i64(tmp);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x48: /* LH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x49: /* CH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        cmp_s32(s, tmp32_1, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4a: /* AH     R1,D2(X2,B2)     [RX] */
+    case 0x4b: /* SH     R1,D2(X2,B2)     [RX] */
+    case 0x4c: /* MH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        switch (opc) {
+        case 0x4a:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x4b:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x4c:
+            tcg_gen_mul_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4d: /* BAS    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4));
+        store_reg(r1, tmp2);
+        tcg_gen_mov_i64(psw_addr, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        s->is_jmp = DISAS_JUMP;
+        break;
+    case 0x4e: /* CVD    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp32_1, regs[r1]);
+        gen_helper_cvd(tmp2, tmp32_1);
+        tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x50: /* st r1, d2(x2, b2) */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x55: /* CL     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r1);
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        cmp_u32(s, tmp32_2, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x54: /* N      R1,D2(X2,B2)     [RX] */
+    case 0x56: /* O      R1,D2(X2,B2)     [RX] */
+    case 0x57: /* X      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        gen_and_or_xor_i32(opc, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x58: /* l r1, d2(x2, b2) */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x59: /* C      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r1);
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        cmp_s32(s, tmp32_2, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5a: /* A      R1,D2(X2,B2)     [RX] */
+    case 0x5b: /* S      R1,D2(X2,B2)     [RX] */
+    case 0x5e: /* AL     R1,D2(X2,B2)     [RX] */
+    case 0x5f: /* SL     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp);
+        switch (opc) {
+        case 0x5a:
+        case 0x5e:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        case 0x5b:
+        case 0x5f:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        switch (opc) {
+        case 0x5a:
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5e:
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5b:
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5f:
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x5c: /* M      R1,D2(X2,B2)        [RX] */
+        /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32s_i64(tmp2, tmp2);
+        tcg_gen_ext32s_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5d: /* D      R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        /* dividend is r(r1 << 32) | r(r1 + 1) */
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_2);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp2);
+
+        /* divisor is in memory */
+        tcg_gen_qemu_ld32s(tmp2, tmp3, get_mem_index(s));
+
+        /* XXX divisor == 0 -> FixP divide exception */
+
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        tcg_gen_rem_i64(tmp, tmp, tmp2);
+
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp3);
+
+        store_reg32(r1, tmp32_1); /* remainder */
+        store_reg32(r1 + 1, tmp32_2); /* quotient */
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x60: /* STD    R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_freg(r1);
+        tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x68: /* LD    R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
+        store_freg(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x70: /* STE R1,D2(X2,B2) [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_freg32(r1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x71: /* MS      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x78: /* LE     R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_freg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x80: /* SSM      D2(B2)       [S] */
+        /* Set System Mask */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_andi_i64(tmp3, psw_mask, ~0xff00000000000000ULL);
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_shli_i64(tmp2, tmp2, 56);
+        tcg_gen_or_i64(psw_mask, tmp3, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x82: /* LPSW     D2(B2)       [S] */
+        /* Load PSW */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_addi_i64(tmp, tmp, 4);
+        tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s));
+        gen_helper_load_psw(tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        /* we need to keep cc_op intact */
+        s->is_jmp = DISAS_JUMP;
+        break;
+    case 0x83: /* DIAG     R1,R3,D2     [RS] */
+        /* Diagnose call (KVM hypercall) */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp32_1 = tcg_const_i32(insn & 0xfff);
+        tmp2 = load_reg(2);
+        tmp3 = load_reg(1);
+        gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3);
+        store_reg(2, tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+#endif
+    case 0x88: /* SRL    R1,D2(B2)        [RS] */
+    case 0x89: /* SLL    R1,D2(B2)        [RS] */
+    case 0x8a: /* SRA    R1,D2(B2)        [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp);
+        tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f);
+        switch (opc) {
+        case 0x88:
+            tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2);
+            break;
+        case 0x89:
+            tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2);
+            break;
+        case 0x8a:
+            tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2);
+            set_cc_s32(s, tmp32_1);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x8c: /* SRDL   R1,D2(B2)        [RS] */
+    case 0x8d: /* SLDL   R1,D2(B2)        [RS] */
+    case 0x8e: /* SRDA   R1,D2(B2)        [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2); /* shift */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+        tcg_gen_concat_i32_i64(tmp2, tmp32_2, tmp32_1); /* operand */
+        switch (opc) {
+        case 0x8c:
+            tcg_gen_shr_i64(tmp2, tmp2, tmp);
+            break;
+        case 0x8d:
+            tcg_gen_shl_i64(tmp2, tmp2, tmp);
+            break;
+        case 0x8e:
+            tcg_gen_sar_i64(tmp2, tmp2, tmp);
+            set_cc_s64(s, tmp2);
+            break;
+        }
+        tcg_gen_shri_i64(tmp, tmp2, 32);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        store_reg32(r1, tmp32_1);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        store_reg32(r1 + 1, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x98: /* LM     R1,R3,D2(B2)     [RS] */
+    case 0x90: /* STM    R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_const_i64(4);
+        tmp4 = tcg_const_i64(0xffffffff00000000ULL);
+        for (i = r1;; i = (i + 1) % 16) {
+            if (opc == 0x98) {
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_and_i64(regs[i], regs[i], tmp4);
+                tcg_gen_or_i64(regs[i], regs[i], tmp2);
+            } else {
+                tcg_gen_qemu_st32(regs[i], tmp, get_mem_index(s));
+            }
+            if (i == r3) {
+                break;
+            }
+            tcg_gen_add_i64(tmp, tmp, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x91: /* TM     D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_const_i64(i2);
+        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
+        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x92: /* MVI    D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_const_i64(i2);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x94: /* NI     D1(B1),I2        [SI] */
+    case 0x96: /* OI     D1(B1),I2        [SI] */
+    case 0x97: /* XI     D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        switch (opc) {
+        case 0x94:
+            tcg_gen_andi_i64(tmp2, tmp2, i2);
+            break;
+        case 0x96:
+            tcg_gen_ori_i64(tmp2, tmp2, i2);
+            break;
+        case 0x97:
+            tcg_gen_xori_i64(tmp2, tmp2, i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        set_cc_nz_u64(s, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x95: /* CLI    D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        cmp_u64c(s, tmp2, i2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x9a: /* LAM      R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lam(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x9b: /* STAM     R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stam(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xa5:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 20) & 0xf;
+        op = (insn >> 16) & 0xf;
+        i2 = insn & 0xffff;
+        disas_a5(s, op, r1, i2);
+        break;
+    case 0xa7:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 20) & 0xf;
+        op = (insn >> 16) & 0xf;
+        i2 = (short)insn;
+        disas_a7(s, op, r1, i2);
+        break;
+    case 0xa8: /* MVCLE   R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xa9: /* CLCLE   R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xac: /* STNSM   D1(B1),I2     [SI] */
+    case 0xad: /* STOSM   D1(B1),I2     [SI] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_shri_i64(tmp2, psw_mask, 56);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        if (opc == 0xac) {
+            tcg_gen_andi_i64(psw_mask, psw_mask,
+                    ((uint64_t)i2 << 56) | 0x00ffffffffffffffULL);
+        } else {
+            tcg_gen_ori_i64(psw_mask, psw_mask, (uint64_t)i2 << 56);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xae: /* SIGP   R1,R3,D2(B2)     [RS] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = load_reg(r3);
+        tmp32_1 = tcg_const_i32(r1);
+        potential_page_fault(s);
+        gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xb1: /* LRA    R1,D2(X2, B2)     [RX] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = tcg_const_i32(r1);
+        potential_page_fault(s);
+        gen_helper_lra(cc_op, tmp, tmp32_1);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+#endif
+    case 0xb2:
+        insn = ld_code4(s->pc);
+        op = (insn >> 16) & 0xff;
+        switch (op) {
+        case 0x9c: /* STFPC    D2(B2) [S] */
+            d2 = insn & 0xfff;
+            b2 = (insn >> 12) & 0xf;
+            tmp32_1 = tcg_temp_new_i32();
+            tmp = tcg_temp_new_i64();
+            tmp2 = get_address(s, 0, b2, d2);
+            tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+            tcg_gen_extu_i32_i64(tmp, tmp32_1);
+            tcg_gen_qemu_st32(tmp, tmp2, get_mem_index(s));
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i64(tmp2);
+            break;
+        default:
+            disas_b2(s, op, insn);
+            break;
+        }
+        break;
+    case 0xb3:
+        insn = ld_code4(s->pc);
+        op = (insn >> 16) & 0xff;
+        r3 = (insn >> 12) & 0xf; /* aka m3 */
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        disas_b3(s, op, r3, r1, r2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xb6: /* STCTL     R1,R3,D2(B2)     [RS] */
+        /* Store Control */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stctl(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xb7: /* LCTL      R1,R3,D2(B2)     [RS] */
+        /* Load Control */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lctl(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#endif
+    case 0xb9:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        op = (insn >> 16) & 0xff;
+        disas_b9(s, op, r1, r2);
+        break;
+    case 0xba: /* CS     R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbd: /* CLM    R1,M3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbe: /* STCM R1,M3,D2(B2) [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stcm(tmp32_1, tmp32_2, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbf: /* ICM    R1,M3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        if (r3 == 15) {
+            /* effectively a 32-bit load */
+            tmp = get_address(s, 0, b2, d2);
+            tmp32_1 = tcg_temp_new_i32();
+            tmp32_2 = tcg_const_i32(r3);
+            tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s));
+            store_reg32_i64(r1, tmp);
+            tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+            set_cc_icm(s, tmp32_2, tmp32_1);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i32(tmp32_2);
+        } else if (r3) {
+            uint32_t mask = 0x00ffffffUL;
+            uint32_t shift = 24;
+            int m3 = r3;
+            tmp = get_address(s, 0, b2, d2);
+            tmp2 = tcg_temp_new_i64();
+            tmp32_1 = load_reg32(r1);
+            tmp32_2 = tcg_temp_new_i32();
+            tmp32_3 = tcg_const_i32(r3);
+            tmp32_4 = tcg_const_i32(0);
+            while (m3) {
+                if (m3 & 8) {
+                    tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+                    tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+                    if (shift) {
+                        tcg_gen_shli_i32(tmp32_2, tmp32_2, shift);
+                    }
+                    tcg_gen_andi_i32(tmp32_1, tmp32_1, mask);
+                    tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2);
+                    tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2);
+                    tcg_gen_addi_i64(tmp, tmp, 1);
+                }
+                m3 = (m3 << 1) & 0xf;
+                mask = (mask >> 8) | 0xff000000UL;
+                shift -= 8;
+            }
+            store_reg32(r1, tmp32_1);
+            set_cc_icm(s, tmp32_3, tmp32_4);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i64(tmp2);
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i32(tmp32_2);
+            tcg_temp_free_i32(tmp32_3);
+            tcg_temp_free_i32(tmp32_4);
+        } else {
+            /* i.e. env->cc = 0 */
+            gen_op_movi_cc(s, 0);
+        }
+        break;
+    case 0xc0:
+    case 0xc2:
+        insn = ld_code6(s->pc);
+        r1 = (insn >> 36) & 0xf;
+        op = (insn >> 32) & 0xf;
+        i2 = (int)insn;
+        switch (opc) {
+        case 0xc0:
+            disas_c0(s, op, r1, i2);
+            break;
+        case 0xc2:
+            disas_c2(s, op, r1, i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        break;
+    case 0xd2: /* MVC    D1(L,B1),D2(B2)         [SS] */
+    case 0xd4: /* NC     D1(L,B1),D2(B2)         [SS] */
+    case 0xd5: /* CLC    D1(L,B1),D2(B2)         [SS] */
+    case 0xd6: /* OC     D1(L,B1),D2(B2)         [SS] */
+    case 0xd7: /* XC     D1(L,B1),D2(B2)         [SS] */
+    case 0xdc: /* TR     D1(L,B1),D2(B2)         [SS] */
+    case 0xf3: /* UNPK   D1(L1,B1),D2(L2,B2)     [SS] */
+        insn = ld_code6(s->pc);
+        vl = tcg_const_i32((insn >> 32) & 0xff);
+        b1 = (insn >> 28) & 0xf;
+        b2 = (insn >> 12) & 0xf;
+        d1 = (insn >> 16) & 0xfff;
+        d2 = insn & 0xfff;
+        tmp = get_address(s, 0, b1, d1);
+        tmp2 = get_address(s, 0, b2, d2);
+        switch (opc) {
+        case 0xd2:
+            gen_op_mvc(s, (insn >> 32) & 0xff, tmp, tmp2);
+            break;
+        case 0xd4:
+            potential_page_fault(s);
+            gen_helper_nc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xd5:
+            gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2);
+            break;
+        case 0xd6:
+            potential_page_fault(s);
+            gen_helper_oc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xd7:
+            potential_page_fault(s);
+            gen_helper_xc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xdc:
+            potential_page_fault(s);
+            gen_helper_tr(vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xf3:
+            potential_page_fault(s);
+            gen_helper_unpk(vl, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xda: /* MVCP     D1(R1,B1),D2(B2),R3   [SS] */
+    case 0xdb: /* MVCS     D1(R1,B1),D2(B2),R3   [SS] */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        insn = ld_code6(s->pc);
+        r1 = (insn >> 36) & 0xf;
+        r3 = (insn >> 32) & 0xf;
+        b1 = (insn >> 28) & 0xf;
+        d1 = (insn >> 16) & 0xfff;
+        b2 = (insn >> 12) & 0xf;
+        d2 = insn & 0xfff;
+        tmp = load_reg(r1);
+        /* XXX key in r3 */
+        tmp2 = get_address(s, 0, b1, d1);
+        tmp3 = get_address(s, 0, b2, d2);
+        if (opc == 0xda) {
+            gen_helper_mvcp(cc_op, tmp, tmp2, tmp3);
+        } else {
+            gen_helper_mvcs(cc_op, tmp, tmp2, tmp3);
+        }
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+#endif
+    case 0xe3:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        x2 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = ((int)((((insn >> 16) & 0xfff)
+           | ((insn << 4) & 0xff000)) << 12)) >> 12;
+        disas_e3(s, op,  r1, x2, b2, d2 );
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xe5:
+        /* Test Protection */
+        check_privileged(s, ilc);
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        disas_e5(s, insn);
+        break;
+#endif
+    case 0xeb:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        r3 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = ((int)((((insn >> 16) & 0xfff)
+           | ((insn << 4) & 0xff000)) << 12)) >> 12;
+        disas_eb(s, op, r1, r3, b2, d2);
+        break;
+    case 0xed:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        x2 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = (short)((insn >> 16) & 0xfff);
+        r1b = (insn >> 12) & 0xf;
+        disas_ed(s, op, r1, x2, b2, d2, r1b);
+        break;
+    default:
+        LOG_DISAS("unimplemented opcode 0x%x\n", opc);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+
+    /* Instruction length is encoded in the opcode */
+    s->pc += (ilc * 2);
+}
+
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext dc;
+    target_ulong pc_start;
+    uint64_t next_page_start;
+    uint16_t *gen_opc_end;
+    int j, lj = -1;
+    int num_insns, max_insns;
+    CPUBreakpoint *bp;
+
+    pc_start = tb->pc;
+
+    /* 31-bit mode */
+    if (!(tb->flags & FLAG_MASK_64)) {
+        pc_start &= 0x7fffffff;
+    }
+
+    dc.pc = pc_start;
+    dc.is_jmp = DISAS_NEXT;
+    dc.tb = tb;
+    dc.cc_op = CC_OP_DYNAMIC;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
+    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_debug(&dc);
+                    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_cc_op[lj] = dc.cc_op;
+            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();
+        }
+#if defined(S390X_DEBUG_DISAS_VERBOSE)
+        LOG_DISAS("pc " TARGET_FMT_lx "\n",
+                  dc.pc);
+#endif
+        disas_s390_insn(&dc);
+
+        num_insns++;
+        if (env->singlestep_enabled) {
+            gen_debug(&dc);
+        }
+    } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start
+             && num_insns < max_insns && !env->singlestep_enabled
+             && !singlestep);
+
+    if (!dc.is_jmp) {
+        update_psw_addr(&dc);
+    }
+
+    if (singlestep && dc.cc_op != CC_OP_DYNAMIC) {
+        gen_op_calc_cc(&dc);
+    } else {
+        /* next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type
+           is in env */
+        gen_op_set_cc_op(&dc);
+    }
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+    /* Generate the return instruction */
+    if (dc.is_jmp != DISAS_TB_JUMP) {
+        tcg_gen_exit_tb(0);
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    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;
+    }
+#if defined(S390X_DEBUG_DISAS)
+    log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0);
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc.pc - pc_start, 1);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    int cc_op;
+    env->psw.addr = gen_opc_pc[pc_pos];
+    cc_op = gen_opc_cc_op[pc_pos];
+    if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
+        env->cc_op = cc_op;
+    }
 }
index 789d1880b7249066e2892031ef4e848b2a9a9e2c..7d7fdde019b352cecd6a6c5129e398e98b4cc497 100644 (file)
@@ -184,7 +184,7 @@ typedef struct CPUSH4State {
     uint32_t cvr;              /* Cache Version Register */
 
     void *intc_handle;
-    int intr_at_halt;          /* SR_BL ignored during sleep */
+    int in_sleep;              /* SR_BL ignored during sleep */
     memory_content *movcal_backup;
     memory_content **movcal_backup_tail;
 } CPUSH4State;
@@ -194,7 +194,7 @@ int cpu_sh4_exec(CPUSH4State * s);
 int cpu_sh4_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu);
+                             int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
 void do_interrupt(CPUSH4State * env);
 
@@ -361,4 +361,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
             | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
 }
 
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+    env->flags = tb->flags;
+}
+
 #endif                         /* _CPU_SH4_H */
index d2038bd8422ee37f3b2fee26e6e70fcbb29bac31..5a1e15e63da0a64e2c883c2bd305e6cb2eaf1edd 100644 (file)
@@ -24,7 +24,6 @@
 #include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "hw/sh_intc.h"
 
 #if defined(CONFIG_USER_ONLY)
@@ -35,7 +34,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     env->tea = address;
     env->exception_index = -1;
@@ -90,11 +89,11 @@ void do_interrupt(CPUState * env)
         if (do_exp && env->exception_index != 0x1e0) {
             env->exception_index = 0x000; /* masked exception -> reset */
         }
-        if (do_irq && !env->intr_at_halt) {
+        if (do_irq && !env->in_sleep) {
             return; /* masked */
         }
-        env->intr_at_halt = 0;
     }
+    env->in_sleep = 0;
 
     if (do_irq) {
         irq_vector = sh_intc_get_pending_vector(env->intc_handle,
@@ -441,7 +440,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical,
 }
 
 int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     target_ulong physical;
     int prot, ret, access_type;
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 30f98422957d747e67bff7d063602496cca94c44..b2995766510c01caed1a1d52caf1b93cb41539d0 100644 (file)
@@ -18,7 +18,8 @@
  */
 #include <assert.h>
 #include <stdlib.h>
-#include "exec.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "helper.h"
 
 static void cpu_restore_state_from_retaddr(void *retaddr)
@@ -32,12 +33,13 @@ 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);
         }
     }
 }
 
 #ifndef CONFIG_USER_ONLY
+#include "softmmu_exec.h"
 
 #define MMUSUFFIX _mmu
 
@@ -53,20 +55,19 @@ static void cpu_restore_state_from_retaddr(void *retaddr)
 #define SHIFT 3
 #include "softmmu_template.h"
 
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     CPUState *saved_env;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
-    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    env = env1;
+    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         /* now we have a real cpu fault */
         cpu_restore_state_from_retaddr(retaddr);
-       cpu_loop_exit();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
@@ -87,7 +88,7 @@ static inline void raise_exception(int index, void *retaddr)
 {
     env->exception_index = index;
     cpu_restore_state_from_retaddr(retaddr);
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_raise_illegal_instruction(void)
@@ -113,15 +114,16 @@ void helper_raise_slot_fpu_disable(void)
 void helper_debug(void)
 {
     env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_sleep(uint32_t next_pc)
 {
     env->halted = 1;
+    env->in_sleep = 1;
     env->exception_index = EXCP_HLT;
     env->pc = next_pc;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_trapa(uint32_t tra)
@@ -481,58 +483,43 @@ static void update_fpscr(void *retaddr)
         if (cause & enable) {
             cpu_restore_state_from_retaddr(retaddr);
             env->exception_index = 0x120;
-            cpu_loop_exit();
+            cpu_loop_exit(env);
         }
     }
 }
 
-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) {
@@ -542,15 +529,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) {
@@ -560,15 +544,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) {
@@ -578,15 +559,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) {
@@ -596,176 +574,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..e04a6e0f5cc5005310481fff12055d93bffd937b 100644 (file)
@@ -27,7 +27,6 @@
 //#define SH4_SINGLE_STEP
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-common.h"
@@ -280,7 +279,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model)
     def = cpu_sh4_find_by_name(cpu_model);
     if (!def)
        return NULL;
-    env = qemu_mallocz(sizeof(CPUSH4State));
+    env = g_malloc0(sizeof(CPUSH4State));
     env->features = def->features;
     cpu_exec_init(env);
     env->movcal_backup_tail = &(env->movcal_backup);
@@ -302,7 +301,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)
@@ -1653,18 +1652,10 @@ static void _decode_opc(DisasContext * ctx)
        }
        return;
     case 0x00a3:               /* ocbp @Rn */
-       {
-           TCGv dummy = tcg_temp_new();
-           tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
-           tcg_temp_free(dummy);
-       }
-       return;
     case 0x00b3:               /* ocbwb @Rn */
-       {
-           TCGv dummy = tcg_temp_new();
-           tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
-           tcg_temp_free(dummy);
-       }
+        /* These instructions are supposed to do nothing in case of
+           a cache miss. Given that we only partially emulate caches
+           it is safe to simply ignore them. */
        return;
     case 0x0083:               /* pref @Rn */
        return;
@@ -2069,8 +2060,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];
diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c
new file mode 100644 (file)
index 0000000..04bd2cf
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Helpers for lazy condition code handling
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+static uint32_t compute_all_flags(CPUState *env)
+{
+    return env->psr & PSR_ICC;
+}
+
+static uint32_t compute_C_flags(CPUState *env)
+{
+    return env->psr & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_icc(int32_t dst)
+{
+    uint32_t ret = 0;
+
+    if (dst == 0) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_flags_xcc(CPUState *env)
+{
+    return env->xcc & PSR_ICC;
+}
+
+static uint32_t compute_C_flags_xcc(CPUState *env)
+{
+    return env->xcc & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_xcc(target_long dst)
+{
+    uint32_t ret = 0;
+
+    if (!dst) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+#endif
+
+static inline uint32_t get_V_div_icc(target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src2 != 0) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_div(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_V_div_icc(CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_div(CPUState *env)
+{
+    return 0;
+}
+
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
+                                     target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_add_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_add_xcc(CC_DST, CC_SRC);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add_xcc(CPUState *env)
+{
+    return get_C_add_xcc(CC_DST, CC_SRC);
+}
+#endif
+
+static uint32_t compute_all_add(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add(CPUState *env)
+{
+    return get_C_add_icc(CC_DST, CC_SRC);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_addx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_addx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if ((src1 | src2) & 0x3) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_tadd(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_taddtv(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    return ret;
+}
+
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
+                                     target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_sub_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub_xcc(CPUState *env)
+{
+    return get_C_sub_xcc(CC_SRC, CC_SRC2);
+}
+#endif
+
+static uint32_t compute_all_sub(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub(CPUState *env)
+{
+    return get_C_sub_icc(CC_SRC, CC_SRC2);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_subx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_subx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsub(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsubtv(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_logic(CPUState *env)
+{
+    return get_NZ_icc(CC_DST);
+}
+
+static uint32_t compute_C_logic(CPUState *env)
+{
+    return 0;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_logic_xcc(CPUState *env)
+{
+    return get_NZ_xcc(CC_DST);
+}
+#endif
+
+typedef struct CCTable {
+    uint32_t (*compute_all)(CPUState *env); /* return all the flags */
+    uint32_t (*compute_c)(CPUState *env);  /* return the C flag */
+} CCTable;
+
+static const CCTable icc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
+    [CC_OP_DIV] = { compute_all_div, compute_C_div },
+    [CC_OP_ADD] = { compute_all_add, compute_C_add },
+    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+    [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+    [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
+    [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
+    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+    [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+    [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
+    [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
+};
+
+#ifdef TARGET_SPARC64
+static const CCTable xcc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
+    [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
+    [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
+    [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
+    [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
+};
+#endif
+
+void helper_compute_psr(CPUState *env)
+{
+    uint32_t new_psr;
+
+    new_psr = icc_table[CC_OP].compute_all(env);
+    env->psr = new_psr;
+#ifdef TARGET_SPARC64
+    new_psr = xcc_table[CC_OP].compute_all(env);
+    env->xcc = new_psr;
+#endif
+    CC_OP = CC_OP_FLAGS;
+}
+
+uint32_t helper_compute_C_icc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
+    return ret;
+}
index 320530ec9f08adaeb74caefee340b5e0c7f10b5d..38a707466ccc74e3bacad6ed82c7393ea9bf372f 100644 (file)
@@ -3,16 +3,17 @@
 
 #include "config.h"
 #include "qemu-common.h"
+#include "bswap.h"
 
 #if !defined(TARGET_SPARC64)
 #define TARGET_LONG_BITS 32
-#define TARGET_FPREGS 32
+#define TARGET_DPREGS 16
 #define TARGET_PAGE_BITS 12 /* 4k */
 #define TARGET_PHYS_ADDR_SPACE_BITS 36
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 #else
 #define TARGET_LONG_BITS 64
-#define TARGET_FPREGS 64
+#define TARGET_DPREGS 32
 #define TARGET_PAGE_BITS 13 /* 8k */
 #define TARGET_PHYS_ADDR_SPACE_BITS 41
 # ifdef TARGET_ABI32
@@ -290,18 +291,72 @@ enum {
 #endif
 
 #define TTE_VALID_BIT       (1ULL << 63)
+#define TTE_NFO_BIT         (1ULL << 60)
 #define TTE_USED_BIT        (1ULL << 41)
 #define TTE_LOCKED_BIT      (1ULL <<  6)
+#define TTE_SIDEEFFECT_BIT  (1ULL <<  3)
+#define TTE_PRIV_BIT        (1ULL <<  2)
+#define TTE_W_OK_BIT        (1ULL <<  1)
 #define TTE_GLOBAL_BIT      (1ULL <<  0)
 
 #define TTE_IS_VALID(tte)   ((tte) & TTE_VALID_BIT)
+#define TTE_IS_NFO(tte)     ((tte) & TTE_NFO_BIT)
 #define TTE_IS_USED(tte)    ((tte) & TTE_USED_BIT)
 #define TTE_IS_LOCKED(tte)  ((tte) & TTE_LOCKED_BIT)
+#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
+#define TTE_IS_PRIV(tte)    ((tte) & TTE_PRIV_BIT)
+#define TTE_IS_W_OK(tte)    ((tte) & TTE_W_OK_BIT)
 #define TTE_IS_GLOBAL(tte)  ((tte) & TTE_GLOBAL_BIT)
 
 #define TTE_SET_USED(tte)   ((tte) |= TTE_USED_BIT)
 #define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
 
+#define TTE_PGSIZE(tte)     (((tte) >> 61) & 3ULL)
+#define TTE_PA(tte)         ((tte) & 0x1ffffffe000ULL)
+
+#define SFSR_NF_BIT         (1ULL << 24)   /* JPS1 NoFault */
+#define SFSR_TM_BIT         (1ULL << 15)   /* JPS1 TLB Miss */
+#define SFSR_FT_VA_IMMU_BIT (1ULL << 13)   /* USIIi VA out of range (IMMU) */
+#define SFSR_FT_VA_DMMU_BIT (1ULL << 12)   /* USIIi VA out of range (DMMU) */
+#define SFSR_FT_NFO_BIT     (1ULL << 11)   /* NFO page access */
+#define SFSR_FT_ILL_BIT     (1ULL << 10)   /* illegal LDA/STA ASI */
+#define SFSR_FT_ATOMIC_BIT  (1ULL <<  9)   /* atomic op on noncacheable area */
+#define SFSR_FT_NF_E_BIT    (1ULL <<  8)   /* NF access on side effect area */
+#define SFSR_FT_PRIV_BIT    (1ULL <<  7)   /* privilege violation */
+#define SFSR_PR_BIT         (1ULL <<  3)   /* privilege mode */
+#define SFSR_WRITE_BIT      (1ULL <<  2)   /* write access mode */
+#define SFSR_OW_BIT         (1ULL <<  1)   /* status overwritten */
+#define SFSR_VALID_BIT      (1ULL <<  0)   /* status valid */
+
+#define SFSR_ASI_SHIFT      16             /* 23:16 ASI value */
+#define SFSR_ASI_MASK       (0xffULL << SFSR_ASI_SHIFT)
+#define SFSR_CT_PRIMARY     (0ULL <<  4)   /* 5:4 context type */
+#define SFSR_CT_SECONDARY   (1ULL <<  4)
+#define SFSR_CT_NUCLEUS     (2ULL <<  4)
+#define SFSR_CT_NOTRANS     (3ULL <<  4)
+#define SFSR_CT_MASK        (3ULL <<  4)
+
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
 typedef struct SparcTLBEntry {
     uint64_t tag;
     uint64_t tte;
@@ -341,7 +396,7 @@ typedef struct CPUSPARCState {
 
     uint32_t psr;      /* processor state register */
     target_ulong fsr;      /* FPU state register */
-    float32 fpr[TARGET_FPREGS];  /* floating point registers */
+    CPU_DoubleU fpr[TARGET_DPREGS];  /* floating point registers */
     uint32_t cwp;      /* index of current register window (extracted
                           from PSR) */
 #if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
@@ -403,11 +458,12 @@ typedef struct CPUSPARCState {
     uint32_t mmuregs[32];
     uint64_t mxccdata[4];
     uint64_t mxccregs[8];
+    uint32_t mmubpctrv, mmubpctrc, mmubpctrs;
+    uint64_t mmubpaction;
     uint64_t mmubpregs[4];
     uint64_t prom_addr;
 #endif
     /* temporary float registers */
-    float64 dt0, dt1;
     float128 qt0, qt1;
     float_status fp_status;
 #if defined(TARGET_SPARC64)
@@ -443,30 +499,38 @@ typedef struct CPUSPARCState {
     sparc_def_t *def;
 
     void *irq_manager;
-    void (*qemu_irq_ack) (void *irq_manager, int intno);
+    void (*qemu_irq_ack)(CPUState *env, void *irq_manager, int intno);
 
     /* Leon3 cache control */
     uint32_t cache_control;
 } CPUSPARCState;
 
 #ifndef NO_CPU_IO_DEFS
-/* helper.c */
+/* cpu_init.c */
 CPUSPARCState *cpu_sparc_init(const char *cpu_model);
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+/* mmu_helper.c */
 int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu);
+                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
 
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write);
+#define TARGET_CPU_MEMORY_RW_DEBUG
+#endif
+
+
 /* translate.c */
 void gen_intermediate_code_init(CPUSPARCState *env);
 
 /* cpu-exec.c */
 int cpu_sparc_exec(CPUSPARCState *s);
 
-/* op_helper.c */
+/* win_helper.c */
 target_ulong cpu_get_psr(CPUState *env1);
 void cpu_put_psr(CPUState *env1, target_ulong val);
 #ifdef TARGET_SPARC64
@@ -474,11 +538,15 @@ target_ulong cpu_get_ccr(CPUState *env1);
 void cpu_put_ccr(CPUState *env1, target_ulong val);
 target_ulong cpu_get_cwp64(CPUState *env1);
 void cpu_put_cwp64(CPUState *env1, int cwp);
+void cpu_change_pstate(CPUState *env1, uint32_t new_pstate);
 #endif
 int cpu_cwp_inc(CPUState *env1, int cwp);
 int cpu_cwp_dec(CPUState *env1, int cwp);
 void cpu_set_cwp(CPUState *env1, int new_cwp);
-void leon3_irq_manager(void *irq_manager, int intno);
+
+/* int_helper.c */
+void do_interrupt(CPUState *env);
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno);
 
 /* sun4m.c, sun4u.c */
 void cpu_check_irqs(CPUSPARCState *env);
@@ -507,11 +575,13 @@ static inline int tlb_compare_context(const SparcTLBEntry *tlb,
 
 /* cpu-exec.c */
 #if !defined(CONFIG_USER_ONLY)
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size);
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size);
+#if defined(TARGET_SPARC64)
 target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
                                            int mmu_idx);
 
+#endif
 #endif
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
@@ -521,7 +591,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 #define cpu_signal_handler cpu_sparc_signal_handler
 #define cpu_list sparc_cpu_list
 
-#define CPU_SAVE_VERSION 6
+#define CPU_SAVE_VERSION 7
 
 /* MMU modes definitions */
 #if defined (TARGET_SPARC64)
@@ -603,17 +673,6 @@ static inline int cpu_pil_allowed(CPUState *env1, int pil)
 #endif
 }
 
-static inline int cpu_fpu_enabled(CPUState *env1)
-{
-#if defined(CONFIG_USER_ONLY)
-    return 1;
-#elif !defined(TARGET_SPARC64)
-    return env1->psref;
-#else
-    return ((env1->pstate & PS_PEF) != 0) && ((env1->fprs & FPRS_FEF) != 0);
-#endif
-}
-
 #if defined(CONFIG_USER_ONLY)
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
@@ -636,6 +695,9 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
 trap_state* cpu_tsptr(CPUState* env);
 #endif
 
+#define TB_FLAG_FPU_ENABLED (1 << 4)
+#define TB_FLAG_AM_ENABLED (1 << 5)
+
 static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
                                         target_ulong *cs_base, int *flags)
 {
@@ -643,17 +705,56 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
     *cs_base = env->npc;
 #ifdef TARGET_SPARC64
     // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
-    *flags = ((env->pstate & PS_AM) << 2)          /* 5 */
-        | (((env->pstate & PS_PEF) >> 1)           /* 3 */
-        | ((env->fprs & FPRS_FEF) << 2))           /* 4 */
-        | (env->pstate & PS_PRIV)                  /* 2 */
+    *flags = (env->pstate & PS_PRIV)               /* 2 */
         | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
         | ((env->tl & 0xff) << 8)
         | (env->dmmu.mmu_primary_context << 16);   /* 16... */
+    if (env->pstate & PS_AM) {
+        *flags |= TB_FLAG_AM_ENABLED;
+    }
+    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
+        && (env->fprs & FPRS_FEF)) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
 #else
     // FPU enable . Supervisor
-    *flags = (env->psref << 4) | env->psrs;
+    *flags = env->psrs;
+    if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
 #endif
 }
 
+static inline bool tb_fpu_enabled(int tb_flags)
+{
+#if defined(CONFIG_USER_ONLY)
+    return true;
+#else
+    return tb_flags & TB_FLAG_FPU_ENABLED;
+#endif
+}
+
+static inline bool tb_am_enabled(int tb_flags)
+{
+#ifndef TARGET_SPARC64
+    return false;
+#else
+    return tb_flags & TB_FLAG_AM_ENABLED;
+#endif
+}
+
+static inline bool cpu_has_work(CPUState *env1)
+{
+    return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+           cpu_interrupts_enabled(env1);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+    env->npc = tb->cs_base;
+}
+
 #endif
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
new file mode 100644 (file)
index 0000000..c7269b5
--- /dev/null
@@ -0,0 +1,848 @@
+/*
+ * Sparc CPU init helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_FEATURES
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+void cpu_reset(CPUSPARCState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    tlb_flush(env, 1);
+    env->cwp = 0;
+#ifndef TARGET_SPARC64
+    env->wim = 1;
+#endif
+    env->regwptr = env->regbase + (env->cwp * 16);
+    CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+    env->cleanwin = env->nwindows - 2;
+    env->cansave = env->nwindows - 2;
+    env->pstate = PS_RMO | PS_PEF | PS_IE;
+    env->asi = 0x82; /* Primary no-fault */
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+    env->psret = 0;
+    env->psrs = 1;
+    env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+    env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+    env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+    env->tl = env->maxtl;
+    cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+    env->lsu = 0;
+#else
+    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+    env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+    env->pc = 0;
+    env->npc = env->pc + 4;
+#endif
+    env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+    sparc_def_t def1, *def = &def1;
+
+    if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+        return -1;
+    }
+
+    env->def = g_new0(sparc_def_t, 1);
+    memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+    if ((env->def->features & CPU_FEATURE_FLOAT)) {
+        env->def->features |= CPU_FEATURE_FLOAT128;
+    }
+#endif
+    env->cpu_model_str = cpu_model;
+    env->version = def->iu_version;
+    env->fsr = def->fpu_version;
+    env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+    env->mmuregs[0] |= def->mmu_version;
+    cpu_sparc_set_id(env, 0);
+    env->mxccregs[7] |= def->mxcc_version;
+#else
+    env->mmu_version = def->mmu_version;
+    env->maxtl = def->maxtl;
+    env->version |= def->maxtl << 8;
+    env->version |= def->nwindows - 1;
+#endif
+    return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+    g_free(env->def);
+    g_free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+    CPUSPARCState *env;
+
+    env = g_new0(CPUSPARCState, 1);
+    cpu_exec_init(env);
+
+    gen_intermediate_code_init(env);
+
+    if (cpu_sparc_register(env, cpu_model) < 0) {
+        cpu_sparc_close(env);
+        return NULL;
+    }
+    qemu_init_vcpu(env);
+
+    return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+    {
+        .name = "Fujitsu Sparc64",
+        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 4,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 III",
+        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 5,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 IV",
+        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 V",
+        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc I",
+        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc II",
+        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIi",
+        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIe",
+        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III",
+        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III Cu",
+        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IIIi",
+        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV",
+        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_4,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV+",
+        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+    },
+    {
+        .name = "Sun UltraSparc IIIi+",
+        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc T1",
+        /* defined in sparc_ifu_fdp.v and ctu.h */
+        .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "Sun UltraSparc T2",
+        /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
+        .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "NEC UltraSparc I",
+        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+#else
+    {
+        .name = "Fujitsu MB86900",
+        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Fujitsu MB86904",
+        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu MB86907",
+        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LSI L64811",
+        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C601",
+        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C611",
+        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "TI MicroSparc I",
+        .iu_version = 0x41000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x41000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x0000003f,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+        CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FMUL,
+    },
+    {
+        .name = "TI MicroSparc II",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x02000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI MicroSparc IIep",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016bff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 40", /* STP1020NPGA */
+        .iu_version = 0x41000000, /* SuperSPARC 2.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 50", /* STP1020PGA */
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 51",
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 60", /* STP1020APGA */
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 61",
+        .iu_version = 0x44000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc II",
+        .iu_version = 0x40000000, /* SuperSPARC II 1.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT625",
+        .iu_version = 0x1e000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1e000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT620",
+        .iu_version = 0x1f000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1f000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "BIT B5010",
+        .iu_version = 0x20000000,
+        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+        .mmu_version = 0x20000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Matsushita MN10501",
+        .iu_version = 0x50000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x50000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Weitek W8601",
+        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LEON2",
+        .iu_version = 0xf2000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf2000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+    },
+    {
+        .name = "LEON3",
+        .iu_version = 0xf3000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf3000000,
+        .mmu_bm = 0x00000000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+    },
+#endif
+};
+
+static const char * const feature_name[] = {
+    "float",
+    "float128",
+    "swap",
+    "mul",
+    "div",
+    "flush",
+    "fsqrt",
+    "fmul",
+    "vis1",
+    "vis2",
+    "fsmuld",
+    "hypv",
+    "cmt",
+    "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+                           uint32_t features, const char *prefix)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+        if (feature_name[i] && (features & (1 << i))) {
+            if (prefix) {
+                (*cpu_fprintf)(f, "%s", prefix);
+            }
+            (*cpu_fprintf)(f, "%s ", feature_name[i]);
+        }
+    }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+        if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+            *features |= 1 << i;
+            return;
+        }
+    }
+    fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+    unsigned int i;
+    const sparc_def_t *def = NULL;
+    char *s = strdup(cpu_model);
+    char *featurestr, *name = strtok(s, ",");
+    uint32_t plus_features = 0;
+    uint32_t minus_features = 0;
+    uint64_t iu_version;
+    uint32_t fpu_version, mmu_version, nwindows;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        if (strcasecmp(name, sparc_defs[i].name) == 0) {
+            def = &sparc_defs[i];
+        }
+    }
+    if (!def) {
+        goto error;
+    }
+    memcpy(cpu_def, def, sizeof(*def));
+
+    featurestr = strtok(NULL, ",");
+    while (featurestr) {
+        char *val;
+
+        if (featurestr[0] == '+') {
+            add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+        } else if (featurestr[0] == '-') {
+            add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+        } else if ((val = strchr(featurestr, '='))) {
+            *val = 0; val++;
+            if (!strcmp(featurestr, "iu_version")) {
+                char *err;
+
+                iu_version = strtoll(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+            } else if (!strcmp(featurestr, "fpu_version")) {
+                char *err;
+
+                fpu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+            } else if (!strcmp(featurestr, "mmu_version")) {
+                char *err;
+
+                mmu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+            } else if (!strcmp(featurestr, "nwindows")) {
+                char *err;
+
+                nwindows = strtol(val, &err, 0);
+                if (!*val || *err || nwindows > MAX_NWINDOWS ||
+                    nwindows < MIN_NWINDOWS) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+            } else {
+                fprintf(stderr, "unrecognized feature %s\n", featurestr);
+                goto error;
+            }
+        } else {
+            fprintf(stderr, "feature string `%s' not in format "
+                    "(+feature|-feature|feature=xyz)\n", featurestr);
+            goto error;
+        }
+        featurestr = strtok(NULL, ",");
+    }
+    cpu_def->features |= plus_features;
+    cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+    print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+    free(s);
+    return 0;
+
+ error:
+    free(s);
+    return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
+                       " FPU %08x MMU %08x NWINS %d ",
+                       sparc_defs[i].name,
+                       sparc_defs[i].iu_version,
+                       sparc_defs[i].fpu_version,
+                       sparc_defs[i].mmu_version,
+                       sparc_defs[i].nwindows);
+        print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+                       ~sparc_defs[i].features, "-");
+        print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+                       sparc_defs[i].features, "+");
+        (*cpu_fprintf)(f, "\n");
+    }
+    (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+    print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+    print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+                   "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+                         uint32_t cc)
+{
+    cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
+                cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
+                cc & PSR_CARRY ? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i, x;
+
+    cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
+                env->npc);
+    cpu_fprintf(f, "General Registers:\n");
+
+    for (i = 0; i < 8; i++) {
+        if (i % REGS_PER_LINE == 0) {
+            cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+        }
+        cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+        if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+    cpu_fprintf(f, "\nCurrent Register Window:\n");
+    for (x = 0; x < 3; x++) {
+        for (i = 0; i < 8; i++) {
+            if (i % REGS_PER_LINE == 0) {
+                cpu_fprintf(f, "%%%c%d-%d: ",
+                            x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+                            i, i + REGS_PER_LINE - 1);
+            }
+            cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+            if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+                cpu_fprintf(f, "\n");
+            }
+        }
+    }
+    cpu_fprintf(f, "\nFloating Point Registers:\n");
+    for (i = 0; i < TARGET_DPREGS; i++) {
+        if ((i & 3) == 0) {
+            cpu_fprintf(f, "%%f%02d:", i * 2);
+        }
+        cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
+        if ((i & 3) == 3) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+#ifdef TARGET_SPARC64
+    cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+                (unsigned)cpu_get_ccr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+    cpu_fprintf(f, " xcc: ");
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+    cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+                env->psrpil);
+    cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+                "cleanwin: %d cwp: %d\n",
+                env->cansave, env->canrestore, env->otherwin, env->wstate,
+                env->cleanwin, env->nwindows - 1 - env->cwp);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+                TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+    cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+    cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
+                env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
+                env->wim);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+                env->fsr, env->y);
+#endif
+}
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
new file mode 100644 (file)
index 0000000..c7a2512
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * FPU op helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+static void check_ieee_exceptions(CPUState *env)
+{
+    target_ulong status;
+
+    status = get_float_exception_flags(&env->fp_status);
+    if (status) {
+        /* Copy IEEE 754 flags into FSR */
+        if (status & float_flag_invalid) {
+            env->fsr |= FSR_NVC;
+        }
+        if (status & float_flag_overflow) {
+            env->fsr |= FSR_OFC;
+        }
+        if (status & float_flag_underflow) {
+            env->fsr |= FSR_UFC;
+        }
+        if (status & float_flag_divbyzero) {
+            env->fsr |= FSR_DZC;
+        }
+        if (status & float_flag_inexact) {
+            env->fsr |= FSR_NXC;
+        }
+
+        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+            /* Unmasked exception, generate a trap */
+            env->fsr |= FSR_FTT_IEEE_EXCP;
+            helper_raise_exception(env, TT_FP_EXCP);
+        } else {
+            /* Accumulate exceptions */
+            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+        }
+    }
+}
+
+static inline void clear_float_exceptions(CPUState *env)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
+#define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
+
+#define F_BINOP(name)                                           \
+    float32 helper_f ## name ## s (CPUState *env, float32 src1, \
+                                   float32 src2)                \
+    {                                                           \
+        float32 ret;                                            \
+        clear_float_exceptions(env);                            \
+        ret = float32_ ## name (src1, src2, &env->fp_status);   \
+        check_ieee_exceptions(env);                             \
+        return ret;                                             \
+    }                                                           \
+    float64 helper_f ## name ## d (CPUState * env, float64 src1,\
+                                   float64 src2)                \
+    {                                                           \
+        float64 ret;                                            \
+        clear_float_exceptions(env);                            \
+        ret = float64_ ## name (src1, src2, &env->fp_status);   \
+        check_ieee_exceptions(env);                             \
+        return ret;                                             \
+    }                                                           \
+    F_HELPER(name, q)                                           \
+    {                                                           \
+        clear_float_exceptions(env);                            \
+        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
+        check_ieee_exceptions(env);                             \
+    }
+
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
+
+float64 helper_fsmuld(CPUState *env, float32 src1, float32 src2)
+{
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float64_mul(float32_to_float64(src1, &env->fp_status),
+                      float32_to_float64(src2, &env->fp_status),
+                      &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+void helper_fdmulq(CPUState *env, float64 src1, float64 src2)
+{
+    clear_float_exceptions(env);
+    QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
+                       float64_to_float128(src2, &env->fp_status),
+                       &env->fp_status);
+    check_ieee_exceptions(env);
+}
+
+float32 helper_fnegs(float32 src)
+{
+    return float32_chs(src);
+}
+
+#ifdef TARGET_SPARC64
+float64 helper_fnegd(float64 src)
+{
+    return float64_chs(src);
+}
+
+F_HELPER(neg, q)
+{
+    QT0 = float128_chs(QT1);
+}
+#endif
+
+/* Integer to float conversion.  */
+float32 helper_fitos(CPUState *env, int32_t src)
+{
+    /* Inexact error possible converting int to float.  */
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = int32_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+float64 helper_fitod(CPUState *env, int32_t src)
+{
+    /* No possible exceptions converting int to double.  */
+    return int32_to_float64(src, &env->fp_status);
+}
+
+void helper_fitoq(CPUState *env, int32_t src)
+{
+    /* No possible exceptions converting int to long double.  */
+    QT0 = int32_to_float128(src, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+float32 helper_fxtos(CPUState *env, int64_t src)
+{
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = int64_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+float64 helper_fxtod(CPUState *env, int64_t src)
+{
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = int64_to_float64(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+void helper_fxtoq(CPUState *env, int64_t src)
+{
+    /* No possible exceptions converting long long to long double.  */
+    QT0 = int64_to_float128(src, &env->fp_status);
+}
+#endif
+#undef F_HELPER
+
+/* floating point conversion */
+float32 helper_fdtos(CPUState *env, float64 src)
+{
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float64_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+float64 helper_fstod(CPUState *env, float32 src)
+{
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float32_to_float64(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+float32 helper_fqtos(CPUState *env)
+{
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float128_to_float32(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+void helper_fstoq(CPUState *env, float32 src)
+{
+    clear_float_exceptions(env);
+    QT0 = float32_to_float128(src, &env->fp_status);
+    check_ieee_exceptions(env);
+}
+
+float64 helper_fqtod(CPUState *env)
+{
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float128_to_float64(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+void helper_fdtoq(CPUState *env, float64 src)
+{
+    clear_float_exceptions(env);
+    QT0 = float64_to_float128(src, &env->fp_status);
+    check_ieee_exceptions(env);
+}
+
+/* Float to integer conversion.  */
+int32_t helper_fstoi(CPUState *env, float32 src)
+{
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float32_to_int32_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+int32_t helper_fdtoi(CPUState *env, float64 src)
+{
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float64_to_int32_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+int32_t helper_fqtoi(CPUState *env)
+{
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+int64_t helper_fstox(CPUState *env, float32 src)
+{
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float32_to_int64_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+int64_t helper_fdtox(CPUState *env, float64 src)
+{
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float64_to_int64_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+int64_t helper_fqtox(CPUState *env)
+{
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+#endif
+
+float32 helper_fabss(float32 src)
+{
+    return float32_abs(src);
+}
+
+#ifdef TARGET_SPARC64
+float64 helper_fabsd(float64 src)
+{
+    return float64_abs(src);
+}
+
+void helper_fabsq(CPUState *env)
+{
+    QT0 = float128_abs(QT1);
+}
+#endif
+
+float32 helper_fsqrts(CPUState *env, float32 src)
+{
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float32_sqrt(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+float64 helper_fsqrtd(CPUState *env, float64 src)
+{
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float64_sqrt(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
+}
+
+void helper_fsqrtq(CPUState *env)
+{
+    clear_float_exceptions(env);
+    QT0 = float128_sqrt(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+}
+
+#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
+    void glue(helper_, name) (CPUState *env)                            \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
+                  glue(size, _is_any_nan)(reg2)) &&                     \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            helper_raise_exception(env, TT_FP_EXCP);                    \
+        }                                                               \
+        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                helper_raise_exception(env, TT_FP_EXCP);                \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+#define GEN_FCMP_T(name, size, FS, E)                                   \
+    void glue(helper_, name)(CPUState *env, size src1, size src2)       \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(src1) ||                      \
+                  glue(size, _is_any_nan)(src2)) &&                     \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            helper_raise_exception(env, TT_FP_EXCP);                    \
+        }                                                               \
+        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                helper_raise_exception(env, TT_FP_EXCP);                \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+
+GEN_FCMP_T(fcmps, float32, 0, 0);
+GEN_FCMP_T(fcmpd, float64, 0, 0);
+
+GEN_FCMP_T(fcmpes, float32, 0, 1);
+GEN_FCMP_T(fcmped, float64, 0, 1);
+
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+
+#ifdef TARGET_SPARC64
+GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+
+GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+
+GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+
+GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+
+GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+
+GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
+#undef GEN_FCMP_T
+#undef GEN_FCMP
+
+static inline void set_fsr(CPUState *env)
+{
+    int rnd_mode;
+
+    switch (env->fsr & FSR_RD_MASK) {
+    case FSR_RD_NEAREST:
+        rnd_mode = float_round_nearest_even;
+        break;
+    default:
+    case FSR_RD_ZERO:
+        rnd_mode = float_round_to_zero;
+        break;
+    case FSR_RD_POS:
+        rnd_mode = float_round_up;
+        break;
+    case FSR_RD_NEG:
+        rnd_mode = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_mode, &env->fp_status);
+}
+
+void helper_ldfsr(CPUState *env, uint32_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
+    set_fsr(env);
+}
+
+#ifdef TARGET_SPARC64
+void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
+    set_fsr(env);
+}
+#endif
index b2d4d70a11fe887ba993ab23d56d7844c8b30616..037a72ce4ef86ab25d480391c1691d9c9d264a40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  sparc helpers
+ *  Misc Sparc helpers
  *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
  * 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
 
 #include "cpu.h"
-#include "exec-all.h"
-#include "qemu-common.h"
+#include "host-utils.h"
+#include "helper.h"
+#include "sysemu.h"
 
-//#define DEBUG_MMU
-//#define DEBUG_FEATURES
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...) \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
-
-/* Sparc MMU emulation */
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+void helper_raise_exception(CPUState *env, int tt)
 {
-    if (rw & 2)
-        env1->exception_index = TT_TFAULT;
-    else
-        env1->exception_index = TT_DFAULT;
-    return 1;
+    env->exception_index = tt;
+    cpu_loop_exit(env);
 }
 
-#else
-
-#ifndef TARGET_SPARC64
-/*
- * Sparc V8 Reference MMU (SRMMU)
- */
-static const int access_table[8][8] = {
-    { 0, 0, 0, 0, 8, 0, 12, 12 },
-    { 0, 0, 0, 0, 8, 0, 0, 0 },
-    { 8, 8, 0, 0, 0, 8, 12, 12 },
-    { 8, 8, 0, 0, 0, 8, 0, 0 },
-    { 8, 0, 8, 0, 8, 8, 12, 12 },
-    { 8, 0, 8, 0, 8, 0, 8, 0 },
-    { 8, 8, 8, 0, 8, 8, 12, 12 },
-    { 8, 8, 8, 0, 8, 8, 8, 0 }
-};
-
-static const int perm_table[2][8] = {
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC
-    },
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ,
-        0,
-        0,
-    }
-};
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
+void helper_debug(CPUState *env)
 {
-    int access_perms = 0;
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-    int error_code = 0, is_dirty, is_user;
-    unsigned long page_offset;
-
-    is_user = mmu_idx == MMU_USER_IDX;
-
-    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
-        *page_size = TARGET_PAGE_SIZE;
-        // Boot mode: instruction fetches are taken from PROM
-        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
-            *physical = env->prom_addr | (address & 0x7ffffULL);
-            *prot = PAGE_READ | PAGE_EXEC;
-            return 0;
-        }
-        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return 0;
-    }
-
-    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
-    *physical = 0xffffffffffff0000ULL;
-
-    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
-    /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    /* Ctx pde */
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-        return 1 << 2;
-    case 2: /* L0 PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 4 << 2;
-    case 1: /* L0 PDE */
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-            return (1 << 8) | (1 << 2);
-        case 3: /* Reserved */
-            return (1 << 8) | (4 << 2);
-        case 1: /* L1 PDE */
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-                return (2 << 8) | (1 << 2);
-            case 3: /* Reserved */
-                return (2 << 8) | (4 << 2);
-            case 1: /* L2 PDE */
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                    return (3 << 8) | (1 << 2);
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return (3 << 8) | (4 << 2);
-                case 2: /* L3 PTE */
-                    page_offset = (address & TARGET_PAGE_MASK) &
-                        (TARGET_PAGE_SIZE - 1);
-                }
-                *page_size = TARGET_PAGE_SIZE;
-                break;
-            case 2: /* L2 PTE */
-                page_offset = address & 0x3ffff;
-                *page_size = 0x40000;
-            }
-            break;
-        case 2: /* L1 PTE */
-            page_offset = address & 0xffffff;
-            *page_size = 0x1000000;
-        }
-    }
-
-    /* check access */
-    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
-    error_code = access_table[*access_index][access_perms];
-    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
-        return error_code;
-
-    /* update page modified and dirty bits */
-    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
-    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
-        pde |= PG_ACCESSED_MASK;
-        if (is_dirty)
-            pde |= PG_MODIFIED_MASK;
-        stl_phys_notdirty(pde_ptr, pde);
-    }
-
-    /* the page can be put in the TLB */
-    *prot = perm_table[is_user][access_perms];
-    if (!(pde & PG_MODIFIED_MASK)) {
-        /* only set write access if already dirty... otherwise wait
-           for dirty access */
-        *prot &= ~PAGE_WRITE;
-    }
-
-    /* Even if large ptes, we map only one 4KB page in the cache to
-       avoid filling it too fast */
-    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
-    return error_code;
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
-{
-    target_phys_addr_t paddr;
-    target_ulong vaddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        vaddr = address & TARGET_PAGE_MASK;
-        paddr &= TARGET_PAGE_MASK;
-#ifdef DEBUG_MMU
-        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
-               TARGET_FMT_lx "\n", address, paddr, vaddr);
-#endif
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-
-    if (env->mmuregs[3]) /* Fault status register */
-        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
-    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
-    env->mmuregs[4] = address; /* Fault address register */
-
-    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
-        // No fault mode: if a mapping is available, just override
-        // permissions. If no mapping is available, redirect accesses to
-        // neverland. Fake/overridden mappings will be flushed when
-        // switching to normal mode.
-        vaddr = address & TARGET_PAGE_MASK;
-        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
-        return 0;
-    } else {
-        if (rw & 2)
-            env->exception_index = TT_TFAULT;
-        else
-            env->exception_index = TT_DFAULT;
-        return 1;
-    }
-}
-
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
-{
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-
-    /* Context base + context number */
-    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
-        (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-    case 2: /* PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 0;
-    case 1: /* L1 PDE */
-        if (mmulev == 3)
-            return pde;
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-        case 3: /* Reserved */
-            return 0;
-        case 2: /* L1 PTE */
-            return pde;
-        case 1: /* L2 PDE */
-            if (mmulev == 2)
-                return pde;
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-            case 3: /* Reserved */
-                return 0;
-            case 2: /* L2 PTE */
-                return pde;
-            case 1: /* L3 PDE */
-                if (mmulev == 1)
-                    return pde;
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return 0;
-                case 2: /* L3 PTE */
-                    return pde;
-                }
-            }
-        }
-    }
-    return 0;
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
 }
 
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
-{
-    target_ulong va, va1, va2;
-    unsigned int n, m, o;
-    target_phys_addr_t pde_ptr, pa;
-    uint32_t pde;
-
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
-                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
-    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
-        pde = mmu_probe(env, va, 2);
-        if (pde) {
-            pa = cpu_get_phys_page_debug(env, va);
-            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
-                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
-            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
-                pde = mmu_probe(env, va1, 1);
-                if (pde) {
-                    pa = cpu_get_phys_page_debug(env, va1);
-                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
-                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
-                                   va1, pa, pde);
-                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
-                        pde = mmu_probe(env, va2, 0);
-                        if (pde) {
-                            pa = cpu_get_phys_page_debug(env, va2);
-                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
-                                           TARGET_FMT_plx " PTE: "
-                                           TARGET_FMT_lx "\n",
-                                           va2, pa, pde);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-#else /* !TARGET_SPARC64 */
-
-// 41 bit physical address space
-static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
-{
-    return x & 0x1ffffffffffULL;
-}
-
-/*
- * UltraSparc IIi I/DMMUs
- */
-
-// Returns true if TTE tag is valid and matches virtual address value in context
-// requires virtual address mask value calculated from TTE entry size
-static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
-                                       uint64_t address, uint64_t context,
-                                       target_phys_addr_t *physical)
-{
-    uint64_t mask;
-
-    switch ((tlb->tte >> 61) & 3) {
-    default:
-    case 0x0: // 8k
-        mask = 0xffffffffffffe000ULL;
-        break;
-    case 0x1: // 64k
-        mask = 0xffffffffffff0000ULL;
-        break;
-    case 0x2: // 512k
-        mask = 0xfffffffffff80000ULL;
-        break;
-    case 0x3: // 4M
-        mask = 0xffffffffffc00000ULL;
-        break;
-    }
-
-    // valid, context match, virtual address match?
-    if (TTE_IS_VALID(tlb->tte) &&
-        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
-        && compare_masked(address, tlb->tag, mask))
-    {
-        // decode physical address
-        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
-        return 1;
-    }
-
-    return 0;
-}
-
-static int get_physical_address_data(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int rw, int mmu_idx)
+#ifdef TARGET_SPARC64
+target_ulong helper_popc(target_ulong val)
 {
-    unsigned int i;
-    uint64_t context;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_READ | PAGE_WRITE;
-        return 0;
-    }
-
-    switch(mmu_idx) {
-    case MMU_USER_IDX:
-    case MMU_KERNEL_IDX:
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-        break;
-    case MMU_USER_SECONDARY_IDX:
-    case MMU_KERNEL_SECONDARY_IDX:
-        context = env->dmmu.mmu_secondary_context & 0x1fff;
-        break;
-    case MMU_NUCLEUS_IDX:
-    default:
-        context = 0;
-        break;
-    }
-
-    for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
-        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
-
-            uint8_t fault_type = 0;
-
-            // access ok?
-            if ((env->dtlb[i].tte & 0x4) && is_user) {
-                fault_type |= 1; /* privilege violation */
-                env->exception_index = TT_DFAULT;
-
-                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) {
-                env->exception_index = TT_DPROT;
-
-                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            } else {
-                *prot = PAGE_READ;
-                if (env->dtlb[i].tte & 0x2)
-                    *prot |= PAGE_WRITE;
-
-                TTE_SET_USED(env->dtlb[i].tte);
-
-                return 0;
-            }
-
-            if (env->dmmu.sfsr & 1) /* Fault status register */
-                env->dmmu.sfsr = 2; /* overflow (not read before
-                                             another fault) */
-
-            env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
-
-            env->dmmu.sfsr |= (fault_type << 7);
-
-            env->dmmu.sfar = address; /* Fault address register */
-
-            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-
-            return 1;
-        }
-    }
-
-    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_DMISS;
-    return 1;
+    return ctpop64(val);
 }
 
-static int get_physical_address_code(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int mmu_idx)
+void helper_tick_set_count(void *opaque, uint64_t count)
 {
-    unsigned int i;
-    uint64_t context;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
-        /* IMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_EXEC;
-        return 0;
-    }
-
-    if (env->tl == 0) {
-        /* PRIMARY context */
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-    } else {
-        /* NUCLEUS context */
-        context = 0;
-    }
-
-    for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
-        if (ultrasparc_tag_match(&env->itlb[i],
-                                 address, context, physical)) {
-            // access ok?
-            if ((env->itlb[i].tte & 0x4) && is_user) {
-                if (env->immu.sfsr) /* Fault status register */
-                    env->immu.sfsr = 2; /* overflow (not read before
-                                             another fault) */
-                env->immu.sfsr |= (is_user << 3) | 1;
-                env->exception_index = TT_TFAULT;
-
-                env->immu.tag_access = (address & ~0x1fffULL) | context;
-
-                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
-                            address, context);
-
-                return 1;
-            }
-            *prot = PAGE_EXEC;
-            TTE_SET_USED(env->itlb[i].tte);
-            return 0;
-        }
-    }
-
-    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
-    env->immu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_TMISS;
-    return 1;
-}
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
-{
-    /* ??? We treat everything as a small page, then explicitly flush
-       everything when an entry is evicted.  */
-    *page_size = TARGET_PAGE_SIZE;
-
-#if defined (DEBUG_MMU)
-    /* safety net to catch wrong softmmu index use from dynamic code */
-    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
-        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                " address=%" PRIx64
-                "\n",
-                (rw == 2 ? "CODE" : "DATA"),
-                env->tl, mmu_idx,
-                env->dmmu.mmu_primary_context,
-                env->dmmu.mmu_secondary_context,
-                address);
-    }
+#if !defined(CONFIG_USER_ONLY)
+    cpu_tick_set_count(opaque, count);
 #endif
-
-    if (rw == 2)
-        return get_physical_address_code(env, physical, prot, address,
-                                         mmu_idx);
-    else
-        return get_physical_address_data(env, physical, prot, address, rw,
-                                         mmu_idx);
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
-{
-    target_ulong virt_addr, vaddr;
-    target_phys_addr_t paddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        virt_addr = address & TARGET_PAGE_MASK;
-        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
-                             (TARGET_PAGE_SIZE - 1));
-
-        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
-                    " vaddr %" PRIx64
-                    " mmu_idx=%d"
-                    " tl=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                    "\n",
-                    address, paddr, vaddr, mmu_idx, env->tl,
-                    env->dmmu.mmu_primary_context,
-                    env->dmmu.mmu_secondary_context);
-
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-    // XXX
-    return 1;
 }
 
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+uint64_t helper_tick_get_count(void *opaque)
 {
-    unsigned int i;
-    const char *mask;
-
-    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
-                   PRId64 "\n",
-                   env->dmmu.mmu_primary_context,
-                   env->dmmu.mmu_secondary_context);
-    if ((env->lsu & DMMU_E) == 0) {
-        (*cpu_fprintf)(f, "DMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "DMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch ((env->dtlb[i].tte >> 61) & 3) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
-                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
-                               env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
-                               mask,
-                               env->dtlb[i].tte & 0x4? "priv": "user",
-                               env->dtlb[i].tte & 0x2? "RW": "RO",
-                               env->dtlb[i].tte & 0x40? "locked": "unlocked",
-                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->dtlb[i].tte)?
-                               "global" : "local");
-            }
-        }
-    }
-    if ((env->lsu & IMMU_E) == 0) {
-        (*cpu_fprintf)(f, "IMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "IMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch ((env->itlb[i].tte >> 61) & 3) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
-                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
-                               env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
-                               mask,
-                               env->itlb[i].tte & 0x4? "priv": "user",
-                               env->itlb[i].tte & 0x40? "locked": "unlocked",
-                               env->itlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->itlb[i].tte)?
-                               "global" : "local");
-            }
-        }
-    }
-}
-
-#endif /* TARGET_SPARC64 */
-#endif /* !CONFIG_USER_ONLY */
-
-
 #if !defined(CONFIG_USER_ONLY)
-target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
-                                           int mmu_idx)
-{
-    target_phys_addr_t phys_addr;
-    target_ulong page_size;
-    int prot, access_index;
-
-    if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
-                             mmu_idx, &page_size) != 0)
-        if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
-                                 0, mmu_idx, &page_size) != 0)
-            return -1;
-    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
-        return -1;
-    return phys_addr;
-}
-
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
-    return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env));
-}
-#endif
-
-void cpu_reset(CPUSPARCState *env)
-{
-    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-        log_cpu_state(env, 0);
-    }
-
-    tlb_flush(env, 1);
-    env->cwp = 0;
-#ifndef TARGET_SPARC64
-    env->wim = 1;
-#endif
-    env->regwptr = env->regbase + (env->cwp * 16);
-    CC_OP = CC_OP_FLAGS;
-#if defined(CONFIG_USER_ONLY)
-#ifdef TARGET_SPARC64
-    env->cleanwin = env->nwindows - 2;
-    env->cansave = env->nwindows - 2;
-    env->pstate = PS_RMO | PS_PEF | PS_IE;
-    env->asi = 0x82; // Primary no-fault
-#endif
+    return cpu_tick_get_count(opaque);
 #else
-#if !defined(TARGET_SPARC64)
-    env->psret = 0;
-    env->psrs = 1;
-    env->psrps = 1;
-#endif
-#ifdef TARGET_SPARC64
-    env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
-    env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
-    env->tl = env->maxtl;
-    cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
-    env->lsu = 0;
-#else
-    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
-    env->mmuregs[0] |= env->def->mmu_bm;
-#endif
-    env->pc = 0;
-    env->npc = env->pc + 4;
+    return 0;
 #endif
-    env->cache_control = 0;
 }
 
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+void helper_tick_set_limit(void *opaque, uint64_t limit)
 {
-    sparc_def_t def1, *def = &def1;
-
-    if (cpu_sparc_find_by_name(def, cpu_model) < 0)
-        return -1;
-
-    env->def = qemu_mallocz(sizeof(*def));
-    memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
-    if ((env->def->features & CPU_FEATURE_FLOAT))
-        env->def->features |= CPU_FEATURE_FLOAT128;
-#endif
-    env->cpu_model_str = cpu_model;
-    env->version = def->iu_version;
-    env->fsr = def->fpu_version;
-    env->nwindows = def->nwindows;
-#if !defined(TARGET_SPARC64)
-    env->mmuregs[0] |= def->mmu_version;
-    cpu_sparc_set_id(env, 0);
-    env->mxccregs[7] |= def->mxcc_version;
-#else
-    env->mmu_version = def->mmu_version;
-    env->maxtl = def->maxtl;
-    env->version |= def->maxtl << 8;
-    env->version |= def->nwindows - 1;
+#if !defined(CONFIG_USER_ONLY)
+    cpu_tick_set_limit(opaque, limit);
 #endif
-    return 0;
-}
-
-static void cpu_sparc_close(CPUSPARCState *env)
-{
-    free(env->def);
-    free(env);
 }
+#endif
 
-CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+static target_ulong helper_udiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
 {
-    CPUSPARCState *env;
+    int overflow = 0;
+    uint64_t x0;
+    uint32_t x1;
 
-    env = qemu_mallocz(sizeof(CPUSPARCState));
-    cpu_exec_init(env);
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
 
-    gen_intermediate_code_init(env);
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
+    }
 
-    if (cpu_sparc_register(env, cpu_model) < 0) {
-        cpu_sparc_close(env);
-        return NULL;
+    x0 = x0 / x1;
+    if (x0 > 0xffffffff) {
+        x0 = 0xffffffff;
+        overflow = 1;
     }
-    qemu_init_vcpu(env);
 
-    return env;
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
 }
 
-void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+target_ulong helper_udiv(CPUState *env, target_ulong a, target_ulong b)
 {
-#if !defined(TARGET_SPARC64)
-    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
-#endif
+    return helper_udiv_common(env, a, b, 0);
 }
 
-static const sparc_def_t sparc_defs[] = {
-#ifdef TARGET_SPARC64
-    {
-        .name = "Fujitsu Sparc64",
-        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 4,
-        .maxtl = 4,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 III",
-        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 5,
-        .maxtl = 4,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 IV",
-        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 V",
-        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc I",
-        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc II",
-        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc IIi",
-        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc IIe",
-        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc III",
-        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc III Cu",
-        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_3,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IIIi",
-        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IV",
-        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_4,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IV+",
-        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
-    },
-    {
-        .name = "Sun UltraSparc IIIi+",
-        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_3,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc T1",
-        // defined in sparc_ifu_fdp.v and ctu.h
-        .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_sun4v,
-        .nwindows = 8,
-        .maxtl = 6,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
-        | CPU_FEATURE_GL,
-    },
-    {
-        .name = "Sun UltraSparc T2",
-        // defined in tlu_asi_ctl.v and n2_revid_cust.v
-        .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_sun4v,
-        .nwindows = 8,
-        .maxtl = 6,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
-        | CPU_FEATURE_GL,
-    },
-    {
-        .name = "NEC UltraSparc I",
-        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-#else
-    {
-        .name = "Fujitsu MB86900",
-        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 7,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Fujitsu MB86904",
-        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu MB86907",
-        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "LSI L64811",
-        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
-        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Cypress CY7C601",
-        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Cypress CY7C611",
-        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "TI MicroSparc I",
-        .iu_version = 0x41000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x41000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x0000003f,
-        .nwindows = 7,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
-        CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FMUL,
-    },
-    {
-        .name = "TI MicroSparc II",
-        .iu_version = 0x42000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x02000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI MicroSparc IIep",
-        .iu_version = 0x42000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x04000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016bff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 40", // STP1020NPGA
-        .iu_version = 0x41000000, // SuperSPARC 2.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 50", // STP1020PGA
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 51",
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 60", // STP1020APGA
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 61",
-        .iu_version = 0x44000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc II",
-        .iu_version = 0x40000000, // SuperSPARC II 1.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Ross RT625",
-        .iu_version = 0x1e000000,
-        .fpu_version = 1 << 17,
-        .mmu_version = 0x1e000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Ross RT620",
-        .iu_version = 0x1f000000,
-        .fpu_version = 1 << 17,
-        .mmu_version = 0x1f000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "BIT B5010",
-        .iu_version = 0x20000000,
-        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
-        .mmu_version = 0x20000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Matsushita MN10501",
-        .iu_version = 0x50000000,
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x50000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Weitek W8601",
-        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "LEON2",
-        .iu_version = 0xf2000000,
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0xf2000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
-    },
-    {
-        .name = "LEON3",
-        .iu_version = 0xf3000000,
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0xf3000000,
-        .mmu_bm = 0x00000000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
-        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
-    },
-#endif
-};
-
-static const char * const feature_name[] = {
-    "float",
-    "float128",
-    "swap",
-    "mul",
-    "div",
-    "flush",
-    "fsqrt",
-    "fmul",
-    "vis1",
-    "vis2",
-    "fsmuld",
-    "hypv",
-    "cmt",
-    "gl",
-};
-
-static void print_features(FILE *f, fprintf_function cpu_fprintf,
-                           uint32_t features, const char *prefix)
+target_ulong helper_udiv_cc(CPUState *env, target_ulong a, target_ulong b)
 {
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
-        if (feature_name[i] && (features & (1 << i))) {
-            if (prefix)
-                (*cpu_fprintf)(f, "%s", prefix);
-            (*cpu_fprintf)(f, "%s ", feature_name[i]);
-        }
+    return helper_udiv_common(env, a, b, 1);
 }
 
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+static target_ulong helper_sdiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
 {
-    unsigned int i;
+    int overflow = 0;
+    int64_t x0;
+    int32_t x1;
 
-    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
-        if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
-            *features |= 1 << i;
-            return;
-        }
-    fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
-{
-    unsigned int i;
-    const sparc_def_t *def = NULL;
-    char *s = strdup(cpu_model);
-    char *featurestr, *name = strtok(s, ",");
-    uint32_t plus_features = 0;
-    uint32_t minus_features = 0;
-    uint64_t iu_version;
-    uint32_t fpu_version, mmu_version, nwindows;
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
 
-    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
-        if (strcasecmp(name, sparc_defs[i].name) == 0) {
-            def = &sparc_defs[i];
-        }
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
     }
-    if (!def)
-        goto error;
-    memcpy(cpu_def, def, sizeof(*def));
-
-    featurestr = strtok(NULL, ",");
-    while (featurestr) {
-        char *val;
-
-        if (featurestr[0] == '+') {
-            add_flagname_to_bitmaps(featurestr + 1, &plus_features);
-        } else if (featurestr[0] == '-') {
-            add_flagname_to_bitmaps(featurestr + 1, &minus_features);
-        } else if ((val = strchr(featurestr, '='))) {
-            *val = 0; val++;
-            if (!strcmp(featurestr, "iu_version")) {
-                char *err;
-
-                iu_version = strtoll(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->iu_version = iu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
-#endif
-            } else if (!strcmp(featurestr, "fpu_version")) {
-                char *err;
-
-                fpu_version = strtol(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->fpu_version = fpu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "fpu_version %x\n", fpu_version);
-#endif
-            } else if (!strcmp(featurestr, "mmu_version")) {
-                char *err;
 
-                mmu_version = strtol(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->mmu_version = mmu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "mmu_version %x\n", mmu_version);
-#endif
-            } else if (!strcmp(featurestr, "nwindows")) {
-                char *err;
-
-                nwindows = strtol(val, &err, 0);
-                if (!*val || *err || nwindows > MAX_NWINDOWS ||
-                    nwindows < MIN_NWINDOWS) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->nwindows = nwindows;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "nwindows %d\n", nwindows);
-#endif
-            } else {
-                fprintf(stderr, "unrecognized feature %s\n", featurestr);
-                goto error;
-            }
-        } else {
-            fprintf(stderr, "feature string `%s' not in format "
-                    "(+feature|-feature|feature=xyz)\n", featurestr);
-            goto error;
-        }
-        featurestr = strtok(NULL, ",");
+    x0 = x0 / x1;
+    if ((int32_t) x0 != x0) {
+        x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
+        overflow = 1;
     }
-    cpu_def->features |= plus_features;
-    cpu_def->features &= ~minus_features;
-#ifdef DEBUG_FEATURES
-    print_features(stderr, fprintf, cpu_def->features, NULL);
-#endif
-    free(s);
-    return 0;
-
- error:
-    free(s);
-    return -1;
-}
-
-void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
-{
-    unsigned int i;
 
-    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
-        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
-                       sparc_defs[i].name,
-                       sparc_defs[i].iu_version,
-                       sparc_defs[i].fpu_version,
-                       sparc_defs[i].mmu_version,
-                       sparc_defs[i].nwindows);
-        print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
-                       ~sparc_defs[i].features, "-");
-        print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
-                       sparc_defs[i].features, "+");
-        (*cpu_fprintf)(f, "\n");
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
     }
-    (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
-    print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
-    (*cpu_fprintf)(f, "\n");
-    (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
-    print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
-    (*cpu_fprintf)(f, "\n");
-    (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
-                   "fpu_version mmu_version nwindows\n");
+    return x0;
 }
 
-static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
-                         uint32_t cc)
+target_ulong helper_sdiv(CPUState *env, target_ulong a, target_ulong b)
 {
-    cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
-                cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
-                cc & PSR_CARRY? 'C' : '-');
+    return helper_sdiv_common(env, a, b, 0);
 }
 
-#ifdef TARGET_SPARC64
-#define REGS_PER_LINE 4
-#else
-#define REGS_PER_LINE 8
-#endif
-
-void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
-                    int flags)
+target_ulong helper_sdiv_cc(CPUState *env, target_ulong a, target_ulong b)
 {
-    int i, x;
-
-    cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
-                env->npc);
-    cpu_fprintf(f, "General Registers:\n");
-
-    for (i = 0; i < 8; i++) {
-        if (i % REGS_PER_LINE == 0) {
-            cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
-        }
-        cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
-        if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
-            cpu_fprintf(f, "\n");
-        }
-    }
-    cpu_fprintf(f, "\nCurrent Register Window:\n");
-    for (x = 0; x < 3; x++) {
-        for (i = 0; i < 8; i++) {
-            if (i % REGS_PER_LINE == 0) {
-                cpu_fprintf(f, "%%%c%d-%d: ",
-                            x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
-                            i, i + REGS_PER_LINE - 1);
-            }
-            cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
-            if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
-                cpu_fprintf(f, "\n");
-            }
-        }
-    }
-    cpu_fprintf(f, "\nFloating Point Registers:\n");
-    for (i = 0; i < TARGET_FPREGS; i++) {
-        if ((i & 3) == 0)
-            cpu_fprintf(f, "%%f%02d:", i);
-        cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
-        if ((i & 3) == 3)
-            cpu_fprintf(f, "\n");
-    }
-#ifdef TARGET_SPARC64
-    cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
-                (unsigned)cpu_get_ccr(env));
-    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
-    cpu_fprintf(f, " xcc: ");
-    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
-    cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
-                env->psrpil);
-    cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
-                "cleanwin: %d cwp: %d\n",
-                env->cansave, env->canrestore, env->otherwin, env->wstate,
-                env->cleanwin, env->nwindows - 1 - env->cwp);
-    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
-                TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
-#else
-    cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
-    cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
-    cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
-                env->psrps? 'P' : '-', env->psret? 'E' : '-',
-                env->wim);
-    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
-                env->fsr, env->y);
-#endif
+    return helper_sdiv_common(env, a, b, 1);
 }
index 12e8557133d527ea087a25efc7d9c52998368807..1f67b08065c022ef80c9ac491530ba652035850e 100644 (file)
 #include "def-helper.h"
 
 #ifndef TARGET_SPARC64
-DEF_HELPER_0(rett, void)
-DEF_HELPER_1(wrpsr, void, tl)
-DEF_HELPER_0(rdpsr, tl)
+DEF_HELPER_1(rett, void, env)
+DEF_HELPER_2(wrpsr, void, env, tl)
+DEF_HELPER_1(rdpsr, tl, env)
 #else
-DEF_HELPER_1(wrpil, void, tl)
-DEF_HELPER_1(wrpstate, void, tl)
-DEF_HELPER_0(done, void)
-DEF_HELPER_0(retry, void)
-DEF_HELPER_0(flushw, void)
-DEF_HELPER_0(saved, void)
-DEF_HELPER_0(restored, void)
-DEF_HELPER_0(rdccr, tl)
-DEF_HELPER_1(wrccr, void, tl)
-DEF_HELPER_0(rdcwp, tl)
-DEF_HELPER_1(wrcwp, void, tl)
-DEF_HELPER_2(array8, tl, tl, tl)
-DEF_HELPER_2(alignaddr, tl, tl, tl)
+DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_2(wrpstate, void, env, tl)
+DEF_HELPER_1(done, void, env)
+DEF_HELPER_1(retry, void, env)
+DEF_HELPER_1(flushw, void, env)
+DEF_HELPER_1(saved, void, env)
+DEF_HELPER_1(restored, void, env)
+DEF_HELPER_1(rdccr, tl, env)
+DEF_HELPER_2(wrccr, void, env, tl)
+DEF_HELPER_1(rdcwp, tl, env)
+DEF_HELPER_2(wrcwp, void, env, tl)
+DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
 DEF_HELPER_3(ldda_asi, void, tl, int, int)
 DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
 DEF_HELPER_4(stf_asi, void, tl, int, int, int)
 DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
 DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
-DEF_HELPER_1(set_softint, void, i64)
-DEF_HELPER_1(clear_softint, void, i64)
-DEF_HELPER_1(write_softint, void, i64)
+DEF_HELPER_2(set_softint, void, env, i64)
+DEF_HELPER_2(clear_softint, void, env, i64)
+DEF_HELPER_2(write_softint, void, env, i64)
 DEF_HELPER_2(tick_set_count, void, ptr, i64)
 DEF_HELPER_1(tick_get_count, i64, ptr)
 DEF_HELPER_2(tick_set_limit, void, ptr, i64)
 #endif
 DEF_HELPER_2(check_align, void, tl, i32)
-DEF_HELPER_0(debug, void)
-DEF_HELPER_0(save, void)
-DEF_HELPER_0(restore, void)
-DEF_HELPER_1(flush, void, tl)
-DEF_HELPER_2(udiv, tl, tl, tl)
-DEF_HELPER_2(udiv_cc, tl, tl, tl)
-DEF_HELPER_2(sdiv, tl, tl, tl)
-DEF_HELPER_2(sdiv_cc, tl, tl, tl)
-DEF_HELPER_2(stdf, void, tl, int)
-DEF_HELPER_2(lddf, void, tl, int)
+DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(save, void, env)
+DEF_HELPER_1(restore, void, env)
+DEF_HELPER_3(udiv, tl, env, tl, tl)
+DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
+DEF_HELPER_3(sdiv, tl, env, tl, tl)
+DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
 DEF_HELPER_2(ldqf, void, tl, int)
 DEF_HELPER_2(stqf, void, tl, int)
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
 DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
 DEF_HELPER_4(st_asi, void, tl, i64, int, int)
 #endif
-DEF_HELPER_1(ldfsr, void, i32)
-DEF_HELPER_0(check_ieee_exceptions, void)
-DEF_HELPER_0(clear_float_exceptions, void)
-DEF_HELPER_1(fabss, f32, f32)
-DEF_HELPER_1(fsqrts, f32, f32)
-DEF_HELPER_0(fsqrtd, void)
-DEF_HELPER_2(fcmps, void, f32, f32)
-DEF_HELPER_0(fcmpd, void)
-DEF_HELPER_2(fcmpes, void, f32, f32)
-DEF_HELPER_0(fcmped, void)
-DEF_HELPER_0(fsqrtq, void)
-DEF_HELPER_0(fcmpq, void)
-DEF_HELPER_0(fcmpeq, void)
+DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
+DEF_HELPER_2(fsqrts, f32, env, f32)
+DEF_HELPER_2(fsqrtd, f64, env, f64)
+DEF_HELPER_3(fcmps, void, env, f32, f32)
+DEF_HELPER_3(fcmpd, void, env, f64, f64)
+DEF_HELPER_3(fcmpes, void, env, f32, f32)
+DEF_HELPER_3(fcmped, void, env, f64, f64)
+DEF_HELPER_1(fsqrtq, void, env)
+DEF_HELPER_1(fcmpq, void, env)
+DEF_HELPER_1(fcmpeq, void, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(ldxfsr, void, i64)
-DEF_HELPER_0(fabsd, void)
-DEF_HELPER_2(fcmps_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmpd_fcc1, void)
-DEF_HELPER_0(fcmpd_fcc2, void)
-DEF_HELPER_0(fcmpd_fcc3, void)
-DEF_HELPER_2(fcmpes_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmped_fcc1, void)
-DEF_HELPER_0(fcmped_fcc2, void)
-DEF_HELPER_0(fcmped_fcc3, void)
-DEF_HELPER_0(fabsq, void)
-DEF_HELPER_0(fcmpq_fcc1, void)
-DEF_HELPER_0(fcmpq_fcc2, void)
-DEF_HELPER_0(fcmpq_fcc3, void)
-DEF_HELPER_0(fcmpeq_fcc1, void)
-DEF_HELPER_0(fcmpeq_fcc2, void)
-DEF_HELPER_0(fcmpeq_fcc3, void)
+DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64)
+DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
+DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64)
+DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64)
+DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64)
+DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
+DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
+DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
+DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
+DEF_HELPER_1(fabsq, void, env)
+DEF_HELPER_1(fcmpq_fcc1, void, env)
+DEF_HELPER_1(fcmpq_fcc2, void, env)
+DEF_HELPER_1(fcmpq_fcc3, void, env)
+DEF_HELPER_1(fcmpeq_fcc1, void, env)
+DEF_HELPER_1(fcmpeq_fcc2, void, env)
+DEF_HELPER_1(fcmpeq_fcc3, void, env)
 #endif
-DEF_HELPER_1(raise_exception, void, int)
-DEF_HELPER_0(shutdown, void)
-#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
-#define F_HELPER_DQ_0_0(name)                   \
-    F_HELPER_0_0(name ## d);                    \
-    F_HELPER_0_0(name ## q)
+DEF_HELPER_2(raise_exception, void, env, int)
+#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
 
-F_HELPER_DQ_0_0(add);
-F_HELPER_DQ_0_0(sub);
-F_HELPER_DQ_0_0(mul);
-F_HELPER_DQ_0_0(div);
+DEF_HELPER_3(faddd, f64, env, f64, f64)
+DEF_HELPER_3(fsubd, f64, env, f64, f64)
+DEF_HELPER_3(fmuld, f64, env, f64, f64)
+DEF_HELPER_3(fdivd, f64, env, f64, f64)
+F_HELPER_0_1(addq)
+F_HELPER_0_1(subq)
+F_HELPER_0_1(mulq)
+F_HELPER_0_1(divq)
 
-DEF_HELPER_2(fadds, f32, f32, f32)
-DEF_HELPER_2(fsubs, f32, f32, f32)
-DEF_HELPER_2(fmuls, f32, f32, f32)
-DEF_HELPER_2(fdivs, f32, f32, f32)
+DEF_HELPER_3(fadds, f32, env, f32, f32)
+DEF_HELPER_3(fsubs, f32, env, f32, f32)
+DEF_HELPER_3(fmuls, f32, env, f32, f32)
+DEF_HELPER_3(fdivs, f32, env, f32, f32)
 
-DEF_HELPER_2(fsmuld, void, f32, f32)
-F_HELPER_0_0(dmulq);
+DEF_HELPER_3(fsmuld, f64, env, f32, f32)
+DEF_HELPER_3(fdmulq, void, env, f64, f64);
 
-DEF_HELPER_1(fnegs, f32, f32)
-DEF_HELPER_1(fitod, void, s32)
-DEF_HELPER_1(fitoq, void, s32)
+DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
+DEF_HELPER_2(fitod, f64, env, s32)
+DEF_HELPER_2(fitoq, void, env, s32)
 
-DEF_HELPER_1(fitos, f32, s32)
+DEF_HELPER_2(fitos, f32, env, s32)
 
 #ifdef TARGET_SPARC64
-DEF_HELPER_0(fnegd, void)
-DEF_HELPER_0(fnegq, void)
-DEF_HELPER_0(fxtos, i32)
-F_HELPER_DQ_0_0(xto);
+DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64)
+DEF_HELPER_1(fnegq, void, env)
+DEF_HELPER_2(fxtos, f32, env, s64)
+DEF_HELPER_2(fxtod, f64, env, s64)
+DEF_HELPER_2(fxtoq, void, env, s64)
 #endif
-DEF_HELPER_0(fdtos, f32)
-DEF_HELPER_1(fstod, void, f32)
-DEF_HELPER_0(fqtos, f32)
-DEF_HELPER_1(fstoq, void, f32)
-F_HELPER_0_0(qtod);
-F_HELPER_0_0(dtoq);
-DEF_HELPER_1(fstoi, s32, f32)
-DEF_HELPER_0(fdtoi, s32)
-DEF_HELPER_0(fqtoi, s32)
+DEF_HELPER_2(fdtos, f32, env, f64)
+DEF_HELPER_2(fstod, f64, env, f32)
+DEF_HELPER_1(fqtos, f32, env)
+DEF_HELPER_2(fstoq, void, env, f32)
+DEF_HELPER_1(fqtod, f64, env)
+DEF_HELPER_2(fdtoq, void, env, f64)
+DEF_HELPER_2(fstoi, s32, env, f32)
+DEF_HELPER_2(fdtoi, s32, env, f64)
+DEF_HELPER_1(fqtoi, s32, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(fstox, void, i32)
-F_HELPER_0_0(dtox);
-F_HELPER_0_0(qtox);
-F_HELPER_0_0(aligndata);
+DEF_HELPER_2(fstox, s64, env, f32)
+DEF_HELPER_2(fdtox, s64, env, f64)
+DEF_HELPER_1(fqtox, s64, env)
 
-F_HELPER_0_0(pmerge);
-F_HELPER_0_0(mul8x16);
-F_HELPER_0_0(mul8x16al);
-F_HELPER_0_0(mul8x16au);
-F_HELPER_0_0(mul8sux16);
-F_HELPER_0_0(mul8ulx16);
-F_HELPER_0_0(muld8sux16);
-F_HELPER_0_0(muld8ulx16);
-F_HELPER_0_0(expand);
-#define VIS_HELPER(name)                                 \
-    F_HELPER_0_0(name##16);                              \
-    DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \
-    F_HELPER_0_0(name##32);                              \
-    DEF_HELPER_2(f ## name ## 32s, i32, i32, i32)
+DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_3(pdist, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
+DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
+DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
+#define VIS_HELPER(name)                                                 \
+    DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE,  \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_CONST | TCG_CALL_PURE, \
+                       i32, i32, i32)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_CONST | TCG_CALL_PURE,  \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_CONST | TCG_CALL_PURE, \
+                       i32, i32, i32)
 
 VIS_HELPER(padd);
 VIS_HELPER(psub);
-#define VIS_CMPHELPER(name)                              \
-    F_HELPER_0_0(name##16);                              \
-    F_HELPER_0_0(name##32)
+#define VIS_CMPHELPER(name)                                              \
+    DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_CONST | TCG_CALL_PURE,      \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_CONST | TCG_CALL_PURE,      \
+                       i64, i64, i64)
 VIS_CMPHELPER(cmpgt);
 VIS_CMPHELPER(cmpeq);
 VIS_CMPHELPER(cmple);
 VIS_CMPHELPER(cmpne);
 #endif
-#undef F_HELPER_0_0
-#undef F_HELPER_DQ_0_0
+#undef F_HELPER_0_1
 #undef VIS_HELPER
 #undef VIS_CMPHELPER
-DEF_HELPER_0(compute_psr, void);
-DEF_HELPER_0(compute_C_icc, i32);
+DEF_HELPER_1(compute_psr, void, env);
+DEF_HELPER_1(compute_C_icc, i32, env);
 
 #include "def-helper.h"
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
new file mode 100644 (file)
index 0000000..ac9d01e
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Sparc32 interrupt helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+#include "sysemu.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_WIN_OVF] = "Window Overflow",
+    [TT_WIN_UNF] = "Window Underflow",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int cwp, intno = env->exception_index;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x100) {
+            name = "Unknown";
+        } else if (intno >= 0x80) {
+            name = "Trap Instruction";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->psret == 0) {
+        if (env->exception_index == 0x80 &&
+            env->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
+            qemu_system_shutdown_request();
+        } else {
+            cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
+                      env->exception_index);
+        }
+        return;
+    }
+#endif
+    env->psret = 0;
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    cpu_set_cwp(env, cwp);
+    env->regwptr[9] = env->pc;
+    env->regwptr[10] = env->npc;
+    env->psrps = env->psrs;
+    env->psrs = 1;
+    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env, env->irq_manager, intno);
+    }
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void leon3_cache_control_int(CPUState *env)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            trace_int_helper_icache_freeze();
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            trace_int_helper_dcache_freeze();
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno)
+{
+    leon3_irq_ack(irq_manager, intno);
+    leon3_cache_control_int(env);
+}
+#endif
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
new file mode 100644 (file)
index 0000000..1d471db
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Sparc64 interrupt helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_TMISS] = "Instruction Access MMU Miss",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CLRWIN] = "Clean Windows",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_DMISS] = "Data Access MMU Miss",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DPROT] = "Data Protection Error",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_PRIV_ACT] = "Privileged Action",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int intno = env->exception_index;
+    trap_state *tsptr;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x180) {
+            name = "Unknown";
+        } else if (intno >= 0x100) {
+            name = "Trap Instruction";
+        } else if (intno >= 0xc0) {
+            name = "Window Fill";
+        } else if (intno >= 0x80) {
+            name = "Window Spill";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+                " SP=%016" PRIx64 "\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->tl >= env->maxtl) {
+        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+                  " Error state", env->exception_index, env->tl, env->maxtl);
+        return;
+    }
+#endif
+    if (env->tl < env->maxtl - 1) {
+        env->tl++;
+    } else {
+        env->pstate |= PS_RED;
+        if (env->tl < env->maxtl) {
+            env->tl++;
+        }
+    }
+    tsptr = cpu_tsptr(env);
+
+    tsptr->tstate = (cpu_get_ccr(env) << 32) |
+        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+        cpu_get_cwp64(env);
+    tsptr->tpc = env->pc;
+    tsptr->tnpc = env->npc;
+    tsptr->tt = intno;
+
+    switch (intno) {
+    case TT_IVEC:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
+        break;
+    case TT_TFAULT:
+    case TT_DFAULT:
+    case TT_TMISS ... TT_TMISS + 3:
+    case TT_DMISS ... TT_DMISS + 3:
+    case TT_DPROT ... TT_DPROT + 3:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
+        break;
+    default:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
+        break;
+    }
+
+    if (intno == TT_CLRWIN) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
+    } else if ((intno & 0x1c0) == TT_SPILL) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
+    } else if ((intno & 0x1c0) == TT_FILL) {
+        cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+    }
+    env->tbr &= ~0x7fffULL;
+    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+}
+
+trap_state *cpu_tsptr(CPUState* env)
+{
+    return &env->ts[env->tl & MAXTL_MASK];
+}
+
+static bool do_modify_softint(CPUState *env, uint32_t value)
+{
+    if (env->softint != value) {
+        env->softint = value;
+#if !defined(CONFIG_USER_ONLY)
+        if (cpu_interrupts_enabled(env)) {
+            cpu_check_irqs(env);
+        }
+#endif
+        return true;
+    }
+    return false;
+}
+
+void helper_set_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, env->softint | (uint32_t)value)) {
+        trace_int_helper_set_softint(env->softint);
+    }
+}
+
+void helper_clear_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
+        trace_int_helper_clear_softint(env->softint);
+    }
+}
+
+void helper_write_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, (uint32_t)value)) {
+        trace_int_helper_write_softint(env->softint);
+    }
+}
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
new file mode 100644 (file)
index 0000000..b59707e
--- /dev/null
@@ -0,0 +1,2371 @@
+/*
+ * Helpers for loads and stores
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+//#define DEBUG_MMU
+//#define DEBUG_MXCC
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...)                                   \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, ...)                                  \
+    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, ...)                                   \
+    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
+#else
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size);
+#endif
+#endif
+
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+/* Calculates TSB pointer value for fault page size 8k or 64k */
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+                                       uint64_t tag_access_register,
+                                       int page_size)
+{
+    uint64_t tsb_base = tsb_register & ~0x1fffULL;
+    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+    int tsb_size  = tsb_register & 0xf;
+
+    /* discard lower 13 bits which hold tag access context */
+    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+    /* now reorder bits */
+    uint64_t tsb_base_mask = ~0x1fffULL;
+    uint64_t va = tag_access_va;
+
+    /* move va bits to correct position */
+    if (page_size == 8*1024) {
+        va >>= 9;
+    } else if (page_size == 64*1024) {
+        va >>= 12;
+    }
+
+    if (tsb_size) {
+        tsb_base_mask <<= tsb_size;
+    }
+
+    /* calculate tsb_base mask and adjust va if split is in use */
+    if (tsb_split) {
+        if (page_size == 8*1024) {
+            va &= ~(1ULL << (13 + tsb_size));
+        } else if (page_size == 64*1024) {
+            va |= (1ULL << (13 + tsb_size));
+        }
+        tsb_base_mask <<= 1;
+    }
+
+    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+/* Calculates tag target register value by reordering bits
+   in tag access register */
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+static void replace_tlb_entry(SparcTLBEntry *tlb,
+                              uint64_t tlb_tag, uint64_t tlb_tte,
+                              CPUState *env1)
+{
+    target_ulong mask, size, va, offset;
+
+    /* flush page range if translation is valid */
+    if (TTE_IS_VALID(tlb->tte)) {
+
+        mask = 0xffffffffffffe000ULL;
+        mask <<= 3 * ((tlb->tte >> 61) & 3);
+        size = ~mask + 1;
+
+        va = tlb->tag & mask;
+
+        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env1, va + offset);
+        }
+    }
+
+    tlb->tag = tlb_tag;
+    tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+                      const char *strmmu, CPUState *env1)
+{
+    unsigned int i;
+    target_ulong mask;
+    uint64_t context;
+
+    int is_demap_context = (demap_addr >> 6) & 1;
+
+    /* demap context */
+    switch ((demap_addr >> 4) & 3) {
+    case 0: /* primary */
+        context = env1->dmmu.mmu_primary_context;
+        break;
+    case 1: /* secondary */
+        context = env1->dmmu.mmu_secondary_context;
+        break;
+    case 2: /* nucleus */
+        context = 0;
+        break;
+    case 3: /* reserved */
+    default:
+        return;
+    }
+
+    for (i = 0; i < 64; i++) {
+        if (TTE_IS_VALID(tlb[i].tte)) {
+
+            if (is_demap_context) {
+                /* will remove non-global entries matching context value */
+                if (TTE_IS_GLOBAL(tlb[i].tte) ||
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            } else {
+                /* demap page
+                   will remove any entry matching VA */
+                mask = 0xffffffffffffe000ULL;
+                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+                    continue;
+                }
+
+                /* entry should be global or matching context value */
+                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            }
+
+            replace_tlb_entry(&tlb[i], 0, 0, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+        }
+    }
+}
+
+static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
+                                 uint64_t tlb_tag, uint64_t tlb_tte,
+                                 const char *strmmu, CPUState *env1)
+{
+    unsigned int i, replace_used;
+
+    /* Try replacing invalid entry */
+    for (i = 0; i < 64; i++) {
+        if (!TTE_IS_VALID(tlb[i].tte)) {
+            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+            return;
+        }
+    }
+
+    /* All entries are valid, try replacing unlocked entry */
+
+    for (replace_used = 0; replace_used < 2; ++replace_used) {
+
+        /* Used entries are not replaced on first pass */
+
+        for (i = 0; i < 64; i++) {
+            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
+
+                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
+                            strmmu, (replace_used ? "used" : "unused"), i);
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                return;
+            }
+        }
+
+        /* Now reset used bit and search for unused entries again */
+
+        for (i = 0; i < 64; i++) {
+            TTE_SET_UNUSED(tlb[i].tte);
+        }
+    }
+
+#ifdef DEBUG_MMU
+    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
+#endif
+    /* error state? */
+}
+
+#endif
+
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(env1)) {
+        addr &= 0xffffffffULL;
+    }
+#endif
+    return addr;
+}
+
+/* returns true if access using this ASI is to have address translated by MMU
+   otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+    /* Ultrasparc IIi translating asi
+       - note this list is defined by cpu implementation
+    */
+    switch (asi) {
+    case 0x04 ... 0x11:
+    case 0x16 ... 0x19:
+    case 0x1E ... 0x1F:
+    case 0x24 ... 0x2C:
+    case 0x70 ... 0x73:
+    case 0x78 ... 0x79:
+    case 0x80 ... 0xFF:
+        return 1;
+
+    default:
+        return 0;
+    }
+#else
+    /* TODO: check sparc32 bits */
+    return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+                                            int asi, target_ulong addr)
+{
+    if (is_translating_asi(asi)) {
+        return address_mask(env, addr);
+    } else {
+        return addr;
+    }
+}
+
+void helper_check_align(target_ulong addr, uint32_t align)
+{
+    if (addr & align) {
+#ifdef DEBUG_UNALIGNED
+        printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+               "\n", addr, env->pc);
+#endif
+        helper_raise_exception(env, TT_UNALIGNED);
+    }
+}
+
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) &&   \
+    defined(DEBUG_MXCC)
+static void dump_mxcc(CPUState *env)
+{
+    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccdata[0], env->mxccdata[1],
+           env->mxccdata[2], env->mxccdata[3]);
+    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n"
+           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccregs[0], env->mxccregs[1],
+           env->mxccregs[2], env->mxccregs[3],
+           env->mxccregs[4], env->mxccregs[5],
+           env->mxccregs[6], env->mxccregs[7]);
+}
+#endif
+
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY))     \
+    && defined(DEBUG_ASI)
+static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
+                     uint64_t r1)
+{
+    switch (size) {
+    case 1:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xff);
+        break;
+    case 2:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffff);
+        break;
+    case 4:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffffffff);
+        break;
+    case 8:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
+                    addr, asi, r1);
+        break;
+    }
+}
+#endif
+
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+
+        /* These values must always be read as zeros */
+        val &= ~CACHE_CTRL_FD;
+        val &= ~CACHE_CTRL_FI;
+        val &= ~CACHE_CTRL_IB;
+        val &= ~CACHE_CTRL_IP;
+        val &= ~CACHE_CTRL_DP;
+
+        env->cache_control = val;
+        break;
+    case 0x04:              /* Instruction cache configuration */
+    case 0x08:              /* Data cache configuration */
+        /* Read Only */
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+        break;
+    };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+        ret = env->cache_control;
+        break;
+
+        /* Configuration registers are read and only always keep those
+           predefined values */
+
+    case 0x04:              /* Instruction cache configuration */
+        ret = 0x10220000;
+        break;
+    case 0x08:              /* Data cache configuration */
+        ret = 0x18220000;
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+        break;
+    };
+    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
+    uint32_t last_addr = addr;
+#endif
+
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                ret = leon3_cache_control_ld(addr, size);
+            }
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00c00: /* Module reset register */
+            if (size == 8) {
+                ret = env->mxccregs[5];
+                /* should we do something here? */
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                ret = env->mxccregs[7];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
+                     "addr = %08x -> ret = %" PRIx64 ","
+                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU probe */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            if (mmulev > 4) {
+                ret = 0;
+            } else {
+                ret = mmu_probe(env, addr, mmulev);
+            }
+            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
+                        addr, mmulev, ret);
+        }
+        break;
+    case 4: /* read MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+
+            ret = env->mmuregs[reg];
+            if (reg == 3) { /* Fault status cleared on read */
+                env->mmuregs[3] = 0;
+            } else if (reg == 0x13) { /* Fault status read */
+                ret = env->mmuregs[3];
+            } else if (reg == 0x14) { /* Fault address read */
+                ret = env->mmuregs[4];
+            }
+            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 9: /* Supervisor code access */
+        switch (size) {
+        case 1:
+            ret = ldub_code(addr);
+            break;
+        case 2:
+            ret = lduw_code(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_code(addr);
+            break;
+        case 8:
+            ret = ldq_code(addr);
+            break;
+        }
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            ret = ldub_user(addr);
+            break;
+        case 2:
+            ret = lduw_user(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(addr);
+            break;
+        case 8:
+            ret = ldq_user(addr);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            ret = ldub_kernel(addr);
+            break;
+        case 2:
+            ret = lduw_kernel(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(addr);
+            break;
+        case 8:
+            ret = ldq_kernel(addr);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+        break;
+    case 0x20: /* MMU passthrough */
+        switch (size) {
+        case 1:
+            ret = ldub_phys(addr);
+            break;
+        case 2:
+            ret = lduw_phys(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_phys(addr);
+            break;
+        case 8:
+            ret = ldq_phys(addr);
+            break;
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        switch (size) {
+        case 1:
+            ret = ldub_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 2:
+            ret = lduw_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        default:
+        case 4:
+            ret = ldl_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 8:
+            ret = ldq_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        }
+        break;
+    case 0x30: /* Turbosparc secondary cache diagnostic */
+    case 0x31: /* Turbosparc RAM snoop */
+    case 0x32: /* Turbosparc page table descriptor diagnostic */
+    case 0x39: /* data cache diagnostic register */
+        ret = 0;
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                ret = env->mmubpregs[reg];
+                break;
+            case 1: /* Breakpoint Mask */
+                ret = env->mmubpregs[reg];
+                break;
+            case 2: /* Breakpoint Control */
+                ret = env->mmubpregs[reg];
+                break;
+            case 3: /* Breakpoint Status */
+                ret = env->mmubpregs[reg];
+                env->mmubpregs[reg] = 0ULL;
+                break;
+            }
+            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
+                        ret);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        ret = env->mmubpctrv;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        ret = env->mmubpctrc;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        ret = env->mmubpctrs;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        ret = env->mmubpaction;
+        break;
+    case 8: /* User code access, XXX */
+    default:
+        do_unassigned_access(addr, 0, 0, asi, size);
+        ret = 0;
+        break;
+    }
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+{
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                leon3_cache_control_st(addr, val, size);
+            }
+            break;
+
+        case 0x01c00000: /* MXCC stream data register 0 */
+            if (size == 8) {
+                env->mxccdata[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00008: /* MXCC stream data register 1 */
+            if (size == 8) {
+                env->mxccdata[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00010: /* MXCC stream data register 2 */
+            if (size == 8) {
+                env->mxccdata[2] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00018: /* MXCC stream data register 3 */
+            if (size == 8) {
+                env->mxccdata[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00100: /* MXCC stream source */
+            if (size == 8) {
+                env->mxccregs[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        0);
+            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        8);
+            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        16);
+            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        24);
+            break;
+        case 0x01c00200: /* MXCC stream destination */
+            if (size == 8) {
+                env->mxccregs[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
+                     env->mxccdata[0]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
+                     env->mxccdata[1]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
+                     env->mxccdata[2]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
+                     env->mxccdata[3]);
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                env->mxccregs[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
+                    | val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00e00: /* MXCC error register  */
+            /* writing a 1 bit clears the error */
+            if (size == 8) {
+                env->mxccregs[6] &= ~val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                env->mxccregs[7] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
+                     asi, size, addr, val);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU flush */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            DPRINTF_MMU("mmu flush level %d\n", mmulev);
+            switch (mmulev) {
+            case 0: /* flush page */
+                tlb_flush_page(env, addr & 0xfffff000);
+                break;
+            case 1: /* flush segment (256k) */
+            case 2: /* flush region (16M) */
+            case 3: /* flush context (4G) */
+            case 4: /* flush entire */
+                tlb_flush(env, 1);
+                break;
+            default:
+                break;
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 4: /* write MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+            uint32_t oldreg;
+
+            oldreg = env->mmuregs[reg];
+            switch (reg) {
+            case 0: /* Control Register */
+                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+                    (val & 0x00ffffff);
+                /* Mappings generated during no-fault mode or MMU
+                   disabled mode are invalid in normal mode */
+                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 1: /* Context Table Pointer Register */
+                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
+                break;
+            case 2: /* Context Register */
+                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
+                if (oldreg != env->mmuregs[reg]) {
+                    /* we flush when the MMU context changes because
+                       QEMU has no MMU context support */
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 3: /* Synchronous Fault Status Register with Clear */
+            case 4: /* Synchronous Fault Address Register */
+                break;
+            case 0x10: /* TLB Replacement Control Register */
+                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
+                break;
+            case 0x13: /* Synchronous Fault Status Register with Read
+                          and Clear */
+                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
+                break;
+            case 0x14: /* Synchronous Fault Address Register */
+                env->mmuregs[4] = val;
+                break;
+            default:
+                env->mmuregs[reg] = val;
+                break;
+            }
+            if (oldreg != env->mmuregs[reg]) {
+                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
+                            reg, oldreg, env->mmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            stb_user(addr, val);
+            break;
+        case 2:
+            stw_user(addr, val);
+            break;
+        default:
+        case 4:
+            stl_user(addr, val);
+            break;
+        case 8:
+            stq_user(addr, val);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            stb_kernel(addr, val);
+            break;
+        case 2:
+            stw_kernel(addr, val);
+            break;
+        default:
+        case 4:
+            stl_kernel(addr, val);
+            break;
+        case 8:
+            stq_kernel(addr, val);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+    case 0x10: /* I/D-cache flush page */
+    case 0x11: /* I/D-cache flush segment */
+    case 0x12: /* I/D-cache flush region */
+    case 0x13: /* I/D-cache flush context */
+    case 0x14: /* I/D-cache flush user */
+        break;
+    case 0x17: /* Block copy, sta access */
+        {
+            /* val = src
+               addr = dst
+               copy 32 bytes */
+            unsigned int i;
+            uint32_t src = val & ~3, dst = addr & ~3, temp;
+
+            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+                temp = ldl_kernel(src);
+                stl_kernel(dst, temp);
+            }
+        }
+        break;
+    case 0x1f: /* Block fill, stda access */
+        {
+            /* addr = dst
+               fill 32 bytes with val */
+            unsigned int i;
+            uint32_t dst = addr & 7;
+
+            for (i = 0; i < 32; i += 8, dst += 8) {
+                stq_kernel(dst, val);
+            }
+        }
+        break;
+    case 0x20: /* MMU passthrough */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+            default:
+                stl_phys(addr, val);
+                break;
+            case 8:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        {
+            switch (size) {
+            case 1:
+                stb_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 2:
+                stw_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 4:
+            default:
+                stl_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 8:
+                stq_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            }
+        }
+        break;
+    case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
+    case 0x31: /* store buffer data, Ross RT620 I-cache flush or
+                  Turbosparc snoop RAM */
+    case 0x32: /* store buffer control or Turbosparc page table
+                  descriptor diagnostic */
+    case 0x36: /* I-cache flash clear */
+    case 0x37: /* D-cache flash clear */
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 1: /* Breakpoint Mask */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 2: /* Breakpoint Control */
+                env->mmubpregs[reg] = (val & 0x7fULL);
+                break;
+            case 3: /* Breakpoint Status */
+                env->mmubpregs[reg] = (val & 0xfULL);
+                break;
+            }
+            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
+                        env->mmuregs[reg]);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        env->mmubpctrv = val & 0xffffffff;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        env->mmubpctrc = val & 0x3;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        env->mmubpctrs = val & 0x3;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        env->mmubpaction = val & 0x1fff;
+        break;
+    case 8: /* User code access, XXX */
+    case 9: /* Supervisor code access, XXX */
+    default:
+        do_unassigned_access(addr, 1, 0, asi, size);
+        break;
+    }
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+}
+
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0x82: /* Primary no-fault */
+    case 0x8a: /* Primary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_raw(addr);
+                break;
+            case 2:
+                ret = lduw_raw(addr);
+                break;
+            case 4:
+                ret = ldl_raw(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(addr);
+                break;
+            }
+        }
+        break;
+    case 0x83: /* Secondary no-fault */
+    case 0x8b: /* Secondary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        break;
+    default:
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0x8a: /* Primary no-fault LE */
+    case 0x8b: /* Secondary no-fault LE */
+        switch (size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                stb_raw(addr, val);
+                break;
+            case 2:
+                stw_raw(addr, val);
+                break;
+            case 4:
+                stl_raw(addr, val);
+                break;
+            case 8:
+            default:
+                stq_raw(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        return;
+
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* process nonfaulting loads first */
+    if ((asi & 0xf6) == 0x82) {
+        int mmu_idx;
+
+        /* secondary space access has lowest asi bit equal to 1 */
+        if (env->pstate & PS_PRIV) {
+            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+        } else {
+            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+        }
+
+        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            /* env->exception_index is set in get_physical_address_data(). */
+            helper_raise_exception(env, env->exception_index);
+        }
+
+        /* convert nonfaulting load ASIs to normal load ASIs */
+        asi &= ~0x02;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    ret = ldub_hypv(addr);
+                    break;
+                case 2:
+                    ret = lduw_hypv(addr);
+                    break;
+                case 4:
+                    ret = ldl_hypv(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_hypv(addr);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel_secondary(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel_secondary(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel_secondary(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel_secondary(addr);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel(addr);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    ret = ldub_user_secondary(addr);
+                    break;
+                case 2:
+                    ret = lduw_user_secondary(addr);
+                    break;
+                case 4:
+                    ret = ldl_user_secondary(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user_secondary(addr);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    ret = ldub_user(addr);
+                    break;
+                case 2:
+                    ret = lduw_user(addr);
+                    break;
+                case 4:
+                    ret = ldl_user(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user(addr);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_phys(addr);
+                break;
+            case 2:
+                ret = lduw_phys(addr);
+                break;
+            case 4:
+                ret = ldl_phys(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_phys(addr);
+                break;
+            }
+            break;
+        }
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return 0;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_nucleus(addr);
+                break;
+            case 2:
+                ret = lduw_nucleus(addr);
+                break;
+            case 4:
+                ret = ldl_nucleus(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_nucleus(addr);
+                break;
+            }
+            break;
+        }
+    case 0x4a: /* UPA config */
+        /* XXX */
+        break;
+    case 0x45: /* LSU */
+        ret = env->lsu;
+        break;
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* I-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->immu.tag_access);
+            } else {
+                ret = env->immuregs[reg];
+            }
+
+            break;
+        }
+    case 0x51: /* I-MMU 8k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x52: /* I-MMU 64k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x55: /* I-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tte;
+            break;
+        }
+    case 0x56: /* I-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tag;
+            break;
+        }
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* D-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->dmmu.tag_access);
+            } else {
+                ret = env->dmmuregs[reg];
+            }
+            break;
+        }
+    case 0x59: /* D-MMU 8k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x5a: /* D-MMU 64k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x5d: /* D-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tte;
+            break;
+        }
+    case 0x5e: /* D-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tag;
+            break;
+        }
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        break;
+    case 0x5b: /* D-MMU data pointer */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x49: /* Interrupt data receive */
+    case 0x7f: /* Incoming interrupt vector, RO */
+        /* XXX */
+        break;
+    case 0x54: /* I-MMU data in, WO */
+    case 0x57: /* I-MMU demap, WO */
+    case 0x5c: /* D-MMU data in, WO */
+    case 0x5f: /* D-MMU demap, WO */
+    case 0x77: /* Interrupt vector, WO */
+    default:
+        do_unassigned_access(addr, 0, 0, 1, size);
+        ret = 0;
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    stb_hypv(addr, val);
+                    break;
+                case 2:
+                    stw_hypv(addr, val);
+                    break;
+                case 4:
+                    stl_hypv(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_hypv(addr, val);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        stb_kernel_secondary(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel_secondary(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel_secondary(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel_secondary(addr, val);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        stb_kernel(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel(addr, val);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    stb_user_secondary(addr, val);
+                    break;
+                case 2:
+                    stw_user_secondary(addr, val);
+                    break;
+                case 4:
+                    stl_user_secondary(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user_secondary(addr, val);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    stb_user(addr, val);
+                    break;
+                case 2:
+                    stw_user(addr, val);
+                    break;
+                case 4:
+                    stl_user(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user(addr, val);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+                stl_phys(addr, val);
+                break;
+            case 8:
+            default:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        return;
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                stb_nucleus(addr, val);
+                break;
+            case 2:
+                stw_nucleus(addr, val);
+                break;
+            case 4:
+                stl_nucleus(addr, val);
+                break;
+            default:
+            case 8:
+                stq_nucleus(addr, val);
+                break;
+            }
+            break;
+        }
+
+    case 0x4a: /* UPA config */
+        /* XXX */
+        return;
+    case 0x45: /* LSU */
+        {
+            uint64_t oldreg;
+
+            oldreg = env->lsu;
+            env->lsu = val & (DMMU_E | IMMU_E);
+            /* Mappings generated during D/I MMU disabled mode are
+               invalid in normal mode */
+            if (oldreg != env->lsu) {
+                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+                            oldreg, env->lsu);
+#ifdef DEBUG_MMU
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                tlb_flush(env, 1);
+            }
+            return;
+        }
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->immuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+                return;
+            case 1: /* Not in I-MMU */
+            case 2:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR */
+                }
+                env->immu.sfsr = val;
+                break;
+            case 4: /* RO */
+                return;
+            case 5: /* TSB access */
+                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->immu.tsb, val);
+                env->immu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->immu.tag_access = val;
+                break;
+            case 7:
+            case 8:
+                return;
+            default:
+                break;
+            }
+
+            if (oldreg != env->immuregs[reg]) {
+                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x54: /* I-MMU data in */
+        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
+        return;
+    case 0x55: /* I-MMU data access */
+        {
+            /* TODO: auto demap */
+
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x57: /* I-MMU demap */
+        demap_tlb(env->itlb, addr, "immu", env);
+        return;
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->dmmuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+            case 4:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR, Fault address */
+                    env->dmmu.sfar = 0;
+                }
+                env->dmmu.sfsr = val;
+                break;
+            case 1: /* Primary context */
+                env->dmmu.mmu_primary_context = val;
+                /* can be optimized to only flush MMU_USER_IDX
+                   and MMU_KERNEL_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 2: /* Secondary context */
+                env->dmmu.mmu_secondary_context = val;
+                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+                   and MMU_KERNEL_SECONDARY_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 5: /* TSB access */
+                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->dmmu.tsb, val);
+                env->dmmu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->dmmu.tag_access = val;
+                break;
+            case 7: /* Virtual Watchpoint */
+            case 8: /* Physical Watchpoint */
+            default:
+                env->dmmuregs[reg] = val;
+                break;
+            }
+
+            if (oldreg != env->dmmuregs[reg]) {
+                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5c: /* D-MMU data in */
+        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
+        return;
+    case 0x5d: /* D-MMU data access */
+        {
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5f: /* D-MMU demap */
+        demap_tlb(env->dtlb, addr, "dmmu", env);
+        return;
+    case 0x49: /* Interrupt data receive */
+        /* XXX */
+        return;
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        return;
+    case 0x51: /* I-MMU 8k TSB pointer, RO */
+    case 0x52: /* I-MMU 64k TSB pointer, RO */
+    case 0x56: /* I-MMU tag read, RO */
+    case 0x59: /* D-MMU 8k TSB pointer, RO */
+    case 0x5a: /* D-MMU 64k TSB pointer, RO */
+    case 0x5b: /* D-MMU data pointer, RO */
+    case 0x5e: /* D-MMU tag read, RO */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x7f: /* Incoming interrupt vector, RO */
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
+        helper_check_align(addr, 0xf);
+        if (rd == 0) {
+            env->gregs[1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[1]);
+            }
+        } else if (rd < 8) {
+            env->gregs[rd] = ldq_nucleus(addr);
+            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[rd]);
+                bswap64s(&env->gregs[rd + 1]);
+            }
+        } else {
+            env->regwptr[rd] = ldq_nucleus(addr);
+            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->regwptr[rd]);
+                bswap64s(&env->regwptr[rd + 1]);
+            }
+        }
+        break;
+#endif
+    default:
+        helper_check_align(addr, 0x3);
+        if (rd == 0) {
+            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else if (rd < 8) {
+            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else {
+            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        }
+        break;
+    }
+}
+
+void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    target_ulong val;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xf0: /* UA2007/JPS1 Block load primary */
+    case 0xf1: /* UA2007/JPS1 Block load secondary */
+    case 0xf8: /* UA2007/JPS1 Block load primary LE */
+    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x8f, 8, 0);
+        }
+        return;
+
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block load primary, user privilege */
+    case 0x71: /* JPS1 Block load secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 8; i++, rd += 2, addr += 4) {
+            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x19, 8, 0);
+        }
+        return;
+
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        val = helper_ld_asi(addr, asi, size, 0);
+        if (rd & 1) {
+            env->fpr[rd/2].l.lower = val;
+        } else {
+            env->fpr[rd/2].l.upper = val;
+        }
+        break;
+    case 8:
+        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, size, 0);
+        break;
+    case 16:
+        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, 8, 0);
+        env->fpr[rd/2 + 1].ll = helper_ld_asi(addr + 8, asi, 8, 0);
+        break;
+    }
+}
+
+void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    target_ulong val;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
+    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
+    case 0xf0: /* UA2007/JPS1 Block store primary */
+    case 0xf1: /* UA2007/JPS1 Block store secondary */
+    case 0xf8: /* UA2007/JPS1 Block store primary LE */
+    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x8f, 8);
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block store primary, user privilege */
+    case 0x71: /* JPS1 Block store secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x19, 8);
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        if (rd & 1) {
+            val = env->fpr[rd/2].l.lower;
+        } else {
+            val = env->fpr[rd/2].l.upper;
+        }
+        helper_st_asi(addr, val, asi, size);
+        break;
+    case 8:
+        helper_st_asi(addr, env->fpr[rd/2].ll, asi, size);
+        break;
+    case 16:
+        helper_st_asi(addr, env->fpr[rd/2].ll, asi, 8);
+        helper_st_asi(addr + 8, env->fpr[rd/2 + 1].ll, asi, 8);
+        break;
+    }
+}
+
+target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
+                            target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    val2 &= 0xffffffffUL;
+    ret = helper_ld_asi(addr, asi, 4, 0);
+    ret &= 0xffffffffUL;
+    if (val2 == ret) {
+        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+    }
+    return ret;
+}
+
+target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
+                             target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    ret = helper_ld_asi(addr, asi, 8, 0);
+    if (val2 == ret) {
+        helper_st_asi(addr, val1, asi, 8);
+    }
+    return ret;
+}
+#endif /* TARGET_SPARC64 */
+
+void helper_ldqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit load */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.ll.upper = ldq_user(addr);
+        u.ll.lower = ldq_user(addr + 8);
+        QT0 = u.q;
+        break;
+    case MMU_KERNEL_IDX:
+        u.ll.upper = ldq_kernel(addr);
+        u.ll.lower = ldq_kernel(addr + 8);
+        QT0 = u.q;
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.ll.upper = ldq_hypv(addr);
+        u.ll.lower = ldq_hypv(addr + 8);
+        QT0 = u.q;
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.ll.upper = ldq_raw(address_mask(env, addr));
+    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
+    QT0 = u.q;
+#endif
+}
+
+void helper_stqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit store */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.q = QT0;
+        stq_user(addr, u.ll.upper);
+        stq_user(addr + 8, u.ll.lower);
+        break;
+    case MMU_KERNEL_IDX:
+        u.q = QT0;
+        stq_kernel(addr, u.ll.upper);
+        stq_kernel(addr + 8, u.ll.lower);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.q = QT0;
+        stq_hypv(addr, u.ll.upper);
+        stq_hypv(addr + 8, u.ll.lower);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.q = QT0;
+    stq_raw(address_mask(env, addr), u.ll.upper);
+    stq_raw(address_mask(env, addr + 8), u.ll.lower);
+#endif
+}
+
+#ifndef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+{
+    int fault_type;
+
+#ifdef DEBUG_UNASSIGNED
+    if (is_asi) {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " asi 0x%02x from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, is_asi, env->pc);
+    } else {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, env->pc);
+    }
+#endif
+    /* Don't overwrite translation and access faults */
+    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+    if ((fault_type > 4) || (fault_type == 0)) {
+        env->mmuregs[3] = 0; /* Fault status register */
+        if (is_asi) {
+            env->mmuregs[3] |= 1 << 16;
+        }
+        if (env->psrs) {
+            env->mmuregs[3] |= 1 << 5;
+        }
+        if (is_exec) {
+            env->mmuregs[3] |= 1 << 6;
+        }
+        if (is_write) {
+            env->mmuregs[3] |= 1 << 7;
+        }
+        env->mmuregs[3] |= (5 << 2) | 2;
+        /* SuperSPARC will never place instruction fault addresses in the FAR */
+        if (!is_exec) {
+            env->mmuregs[4] = addr; /* Fault address register */
+        }
+    }
+    /* overflow (same type fault was not read before another fault) */
+    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+        env->mmuregs[3] |= 1;
+    }
+
+    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+        if (is_exec) {
+            helper_raise_exception(env, TT_CODE_ACCESS);
+        } else {
+            helper_raise_exception(env, TT_DATA_ACCESS);
+        }
+    }
+
+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
+}
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size)
+#else
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+#endif
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+
+    if (is_exec) {
+        helper_raise_exception(env, TT_CODE_ACCESS);
+    } else {
+        helper_raise_exception(env, TT_DATA_ACCESS);
+    }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    env = saved_env;
+}
+#endif
index 752e431778b27ad2d835dc6f8fd6a27720c663d3..235b088a45a6ae7b70b5c04ae0267c8b0caaacbe 100644 (file)
@@ -2,7 +2,7 @@
 #include "hw/boards.h"
 #include "qemu-timer.h"
 
-#include "exec-all.h"
+#include "cpu.h"
 
 void cpu_save(QEMUFile *f, void *opaque)
 {
@@ -21,13 +21,9 @@ void cpu_save(QEMUFile *f, void *opaque)
         qemu_put_betls(f, &env->regbase[i]);
 
     /* FPU */
-    for(i = 0; i < TARGET_FPREGS; i++) {
-        union {
-            float32 f;
-            uint32_t i;
-        } u;
-        u.f = env->fpr[i];
-        qemu_put_be32(f, u.i);
+    for (i = 0; i < TARGET_DPREGS; i++) {
+        qemu_put_be32(f, env->fpr[i].l.upper);
+        qemu_put_be32(f, env->fpr[i].l.lower);
     }
 
     qemu_put_betls(f, &env->pc);
@@ -45,6 +41,19 @@ void cpu_save(QEMUFile *f, void *opaque)
     /* MMU */
     for (i = 0; i < 32; i++)
         qemu_put_be32s(f, &env->mmuregs[i]);
+    for (i = 0; i < 4; i++) {
+        qemu_put_be64s(f, &env->mxccdata[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        qemu_put_be64s(f, &env->mxccregs[i]);
+    }
+    qemu_put_be32s(f, &env->mmubpctrv);
+    qemu_put_be32s(f, &env->mmubpctrc);
+    qemu_put_be32s(f, &env->mmubpctrs);
+    qemu_put_be64s(f, &env->mmubpaction);
+    for (i = 0; i < 4; i++) {
+        qemu_put_be64s(f, &env->mmubpregs[i]);
+    }
 #else
     qemu_put_be64s(f, &env->lsu);
     for (i = 0; i < 16; i++) {
@@ -115,13 +124,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         qemu_get_betls(f, &env->regbase[i]);
 
     /* FPU */
-    for(i = 0; i < TARGET_FPREGS; i++) {
-        union {
-            float32 f;
-            uint32_t i;
-        } u;
-        u.i = qemu_get_be32(f);
-        env->fpr[i] = u.f;
+    for (i = 0; i < TARGET_DPREGS; i++) {
+        env->fpr[i].l.upper = qemu_get_be32(f);
+        env->fpr[i].l.lower = qemu_get_be32(f);
     }
 
     qemu_get_betls(f, &env->pc);
@@ -141,6 +146,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     /* MMU */
     for (i = 0; i < 32; i++)
         qemu_get_be32s(f, &env->mmuregs[i]);
+    for (i = 0; i < 4; i++) {
+        qemu_get_be64s(f, &env->mxccdata[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        qemu_get_be64s(f, &env->mxccregs[i]);
+    }
+    qemu_get_be32s(f, &env->mmubpctrv);
+    qemu_get_be32s(f, &env->mmubpctrc);
+    qemu_get_be32s(f, &env->mmubpctrs);
+    qemu_get_be64s(f, &env->mmubpaction);
+    for (i = 0; i < 4; i++) {
+        qemu_get_be64s(f, &env->mmubpregs[i]);
+    }
 #else
     qemu_get_be64s(f, &env->lsu);
     for (i = 0; i < 16; i++) {
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
new file mode 100644 (file)
index 0000000..8cdc224
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ *  Sparc MMU helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+
+/* Sparc MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    if (rw & 2) {
+        env1->exception_index = TT_TFAULT;
+    } else {
+        env1->exception_index = TT_DFAULT;
+    }
+    return 1;
+}
+
+#else
+
+#ifndef TARGET_SPARC64
+/*
+ * Sparc V8 Reference MMU (SRMMU)
+ */
+static const int access_table[8][8] = {
+    { 0, 0, 0, 0, 8, 0, 12, 12 },
+    { 0, 0, 0, 0, 8, 0, 0, 0 },
+    { 8, 8, 0, 0, 0, 8, 12, 12 },
+    { 8, 8, 0, 0, 0, 8, 0, 0 },
+    { 8, 0, 8, 0, 8, 8, 12, 12 },
+    { 8, 0, 8, 0, 8, 0, 8, 0 },
+    { 8, 8, 8, 0, 8, 8, 12, 12 },
+    { 8, 8, 8, 0, 8, 8, 8, 0 }
+};
+
+static const int perm_table[2][8] = {
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC
+    },
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ,
+        0,
+        0,
+    }
+};
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    int access_perms = 0;
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+    int error_code = 0, is_dirty, is_user;
+    unsigned long page_offset;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+
+    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+        *page_size = TARGET_PAGE_SIZE;
+        /* Boot mode: instruction fetches are taken from PROM */
+        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
+            *physical = env->prom_addr | (address & 0x7ffffULL);
+            *prot = PAGE_READ | PAGE_EXEC;
+            return 0;
+        }
+        *physical = address;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
+    *physical = 0xffffffffffff0000ULL;
+
+    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    /* Ctx pde */
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+        return 1 << 2;
+    case 2: /* L0 PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 4 << 2;
+    case 1: /* L0 PDE */
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+            return (1 << 8) | (1 << 2);
+        case 3: /* Reserved */
+            return (1 << 8) | (4 << 2);
+        case 1: /* L1 PDE */
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+                return (2 << 8) | (1 << 2);
+            case 3: /* Reserved */
+                return (2 << 8) | (4 << 2);
+            case 1: /* L2 PDE */
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                    return (3 << 8) | (1 << 2);
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return (3 << 8) | (4 << 2);
+                case 2: /* L3 PTE */
+                    page_offset = (address & TARGET_PAGE_MASK) &
+                        (TARGET_PAGE_SIZE - 1);
+                }
+                *page_size = TARGET_PAGE_SIZE;
+                break;
+            case 2: /* L2 PTE */
+                page_offset = address & 0x3ffff;
+                *page_size = 0x40000;
+            }
+            break;
+        case 2: /* L1 PTE */
+            page_offset = address & 0xffffff;
+            *page_size = 0x1000000;
+        }
+    }
+
+    /* check access */
+    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+    error_code = access_table[*access_index][access_perms];
+    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
+        return error_code;
+    }
+
+    /* update page modified and dirty bits */
+    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
+    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+        pde |= PG_ACCESSED_MASK;
+        if (is_dirty) {
+            pde |= PG_MODIFIED_MASK;
+        }
+        stl_phys_notdirty(pde_ptr, pde);
+    }
+
+    /* the page can be put in the TLB */
+    *prot = perm_table[is_user][access_perms];
+    if (!(pde & PG_MODIFIED_MASK)) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        *prot &= ~PAGE_WRITE;
+    }
+
+    /* Even if large ptes, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+    return error_code;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_phys_addr_t paddr;
+    target_ulong vaddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        vaddr = address & TARGET_PAGE_MASK;
+        paddr &= TARGET_PAGE_MASK;
+#ifdef DEBUG_MMU
+        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+               TARGET_FMT_lx "\n", address, paddr, vaddr);
+#endif
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    if (env->mmuregs[3]) { /* Fault status register */
+        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    }
+    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
+    env->mmuregs[4] = address; /* Fault address register */
+
+    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
+        /* No fault mode: if a mapping is available, just override
+           permissions. If no mapping is available, redirect accesses to
+           neverland. Fake/overridden mappings will be flushed when
+           switching to normal mode. */
+        vaddr = address & TARGET_PAGE_MASK;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+        return 0;
+    } else {
+        if (rw & 2) {
+            env->exception_index = TT_TFAULT;
+        } else {
+            env->exception_index = TT_DFAULT;
+        }
+        return 1;
+    }
+}
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+        (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 0;
+    case 1: /* L1 PDE */
+        if (mmulev == 3) {
+            return pde;
+        }
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+        case 3: /* Reserved */
+            return 0;
+        case 2: /* L1 PTE */
+            return pde;
+        case 1: /* L2 PDE */
+            if (mmulev == 2) {
+                return pde;
+            }
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+            case 3: /* Reserved */
+                return 0;
+            case 2: /* L2 PTE */
+                return pde;
+            case 1: /* L3 PDE */
+                if (mmulev == 1) {
+                    return pde;
+                }
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return 0;
+                case 2: /* L3 PTE */
+                    return pde;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    target_ulong va, va1, va2;
+    unsigned int n, m, o;
+    target_phys_addr_t pde_ptr, pa;
+    uint32_t pde;
+
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+        pde = mmu_probe(env, va, 2);
+        if (pde) {
+            pa = cpu_get_phys_page_debug(env, va);
+            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+                pde = mmu_probe(env, va1, 1);
+                if (pde) {
+                    pa = cpu_get_phys_page_debug(env, va1);
+                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+                                   va1, pa, pde);
+                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+                        pde = mmu_probe(env, va2, 0);
+                        if (pde) {
+                            pa = cpu_get_phys_page_debug(env, va2);
+                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
+                                           TARGET_FMT_plx " PTE: "
+                                           TARGET_FMT_lx "\n",
+                                           va2, pa, pde);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int i;
+    int len1;
+    int cwp = env->cwp;
+
+    if (!is_write) {
+        for (i = 0; i < env->nwindows; i++) {
+            int off;
+            target_ulong fp = env->regbase[cwp * 16 + 22];
+
+            /* Assume fp == 0 means end of frame.  */
+            if (fp == 0) {
+                break;
+            }
+
+            cwp = cpu_cwp_inc(env, cwp + 1);
+
+            /* Invalid window ? */
+            if (env->wim & (1 << cwp)) {
+                break;
+            }
+
+            /* According to the ABI, the stack is growing downward.  */
+            if (addr + len < fp) {
+                break;
+            }
+
+            /* Not in this frame.  */
+            if (addr > fp + 64) {
+                continue;
+            }
+
+            /* Handle access before this window.  */
+            if (addr < fp) {
+                len1 = fp - addr;
+                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+                    return -1;
+                }
+                addr += len1;
+                len -= len1;
+                buf += len1;
+            }
+
+            /* Access byte per byte to registers. Not very efficient but speed
+             * is not critical.
+             */
+            off = addr - fp;
+            len1 = 64 - off;
+
+            if (len1 > len) {
+                len1 = len;
+            }
+
+            for (; len1; len1--) {
+                int reg = cwp * 16 + 8 + (off >> 2);
+                union {
+                    uint32_t v;
+                    uint8_t c[4];
+                } u;
+                u.v = cpu_to_be32(env->regbase[reg]);
+                *buf++ = u.c[off & 3];
+                addr++;
+                len--;
+                off++;
+            }
+
+            if (len == 0) {
+                return 0;
+            }
+        }
+    }
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#else /* !TARGET_SPARC64 */
+
+/* 41 bit physical address space */
+static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
+{
+    return x & 0x1ffffffffffULL;
+}
+
+/*
+ * UltraSparc IIi I/DMMUs
+ */
+
+/* Returns true if TTE tag is valid and matches virtual address value
+   in context requires virtual address mask value calculated from TTE
+   entry size */
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+                                       uint64_t address, uint64_t context,
+                                       target_phys_addr_t *physical)
+{
+    uint64_t mask;
+
+    switch (TTE_PGSIZE(tlb->tte)) {
+    default:
+    case 0x0: /* 8k */
+        mask = 0xffffffffffffe000ULL;
+        break;
+    case 0x1: /* 64k */
+        mask = 0xffffffffffff0000ULL;
+        break;
+    case 0x2: /* 512k */
+        mask = 0xfffffffffff80000ULL;
+        break;
+    case 0x3: /* 4M */
+        mask = 0xffffffffffc00000ULL;
+        break;
+    }
+
+    /* valid, context match, virtual address match? */
+    if (TTE_IS_VALID(tlb->tte) &&
+        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
+        && compare_masked(address, tlb->tag, mask)) {
+        /* decode physical address */
+        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int get_physical_address_data(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int rw, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+    uint64_t sfsr = 0;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_READ | PAGE_WRITE;
+        return 0;
+    }
+
+    switch (mmu_idx) {
+    case MMU_USER_IDX:
+    case MMU_KERNEL_IDX:
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+        sfsr |= SFSR_CT_PRIMARY;
+        break;
+    case MMU_USER_SECONDARY_IDX:
+    case MMU_KERNEL_SECONDARY_IDX:
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
+        break;
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* FALLTHRU */
+    default:
+        context = 0;
+        break;
+    }
+
+    if (rw == 1) {
+        sfsr |= SFSR_WRITE_BIT;
+    } else if (rw == 4) {
+        sfsr |= SFSR_NF_BIT;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
+            int do_fault = 0;
+
+            /* access ok? */
+            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+                do_fault = 1;
+                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
+                trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
+            }
+            if (rw == 4) {
+                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NF_E_BIT;
+                }
+            } else {
+                if (TTE_IS_NFO(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NFO_BIT;
+                }
+            }
+
+            if (do_fault) {
+                /* faults above are reported with TT_DFAULT. */
+                env->exception_index = TT_DFAULT;
+            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+                do_fault = 1;
+                env->exception_index = TT_DPROT;
+
+                trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
+            }
+
+            if (!do_fault) {
+                *prot = PAGE_READ;
+                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
+                    *prot |= PAGE_WRITE;
+                }
+
+                TTE_SET_USED(env->dtlb[i].tte);
+
+                return 0;
+            }
+
+            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+                sfsr |= SFSR_OW_BIT; /* overflow (not read before
+                                        another fault) */
+            }
+
+            if (env->pstate & PS_PRIV) {
+                sfsr |= SFSR_PR_BIT;
+            }
+
+            /* FIXME: ASI field in SFSR must be set */
+            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
+
+            env->dmmu.sfar = address; /* Fault address register */
+
+            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+
+            return 1;
+        }
+    }
+
+    trace_mmu_helper_dmiss(address, context);
+
+    /*
+     * On MMU misses:
+     * - UltraSPARC IIi: SFSR and SFAR unmodified
+     * - JPS1: SFAR updated and some fields of SFSR updated
+     */
+    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_DMISS;
+    return 1;
+}
+
+static int get_physical_address_code(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+        /* IMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_EXEC;
+        return 0;
+    }
+
+    if (env->tl == 0) {
+        /* PRIMARY context */
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+    } else {
+        /* NUCLEUS context */
+        context = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->itlb[i],
+                                 address, context, physical)) {
+            /* access ok? */
+            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+                /* Fault status register */
+                if (env->immu.sfsr & SFSR_VALID_BIT) {
+                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+                                                     another fault) */
+                } else {
+                    env->immu.sfsr = 0;
+                }
+                if (env->pstate & PS_PRIV) {
+                    env->immu.sfsr |= SFSR_PR_BIT;
+                }
+                if (env->tl > 0) {
+                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                }
+
+                /* FIXME: ASI field in SFSR must be set */
+                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+                env->exception_index = TT_TFAULT;
+
+                env->immu.tag_access = (address & ~0x1fffULL) | context;
+
+                trace_mmu_helper_tfault(address, context);
+
+                return 1;
+            }
+            *prot = PAGE_EXEC;
+            TTE_SET_USED(env->itlb[i].tte);
+            return 0;
+        }
+    }
+
+    trace_mmu_helper_tmiss(address, context);
+
+    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+    env->immu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_TMISS;
+    return 1;
+}
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    /* ??? We treat everything as a small page, then explicitly flush
+       everything when an entry is evicted.  */
+    *page_size = TARGET_PAGE_SIZE;
+
+    /* safety net to catch wrong softmmu index use from dynamic code */
+    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
+        if (rw == 2) {
+            trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        } else {
+            trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        }
+    }
+
+    if (rw == 2) {
+        return get_physical_address_code(env, physical, prot, address,
+                                         mmu_idx);
+    } else {
+        return get_physical_address_data(env, physical, prot, address, rw,
+                                         mmu_idx);
+    }
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_ulong virt_addr, vaddr;
+    target_phys_addr_t paddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        virt_addr = address & TARGET_PAGE_MASK;
+        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
+                             (TARGET_PAGE_SIZE - 1));
+
+        trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
+                                   env->dmmu.mmu_primary_context,
+                                   env->dmmu.mmu_secondary_context);
+
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+    /* XXX */
+    return 1;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    unsigned int i;
+    const char *mask;
+
+    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+                   PRId64 "\n",
+                   env->dmmu.mmu_primary_context,
+                   env->dmmu.mmu_secondary_context);
+    if ((env->lsu & DMMU_E) == 0) {
+        (*cpu_fprintf)(f, "DMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "DMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->dtlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->dtlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->dtlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+    if ((env->lsu & IMMU_E) == 0) {
+        (*cpu_fprintf)(f, "IMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "IMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->itlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->itlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->itlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+                               TTE_IS_LOCKED(env->itlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->itlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->itlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+}
+
+#endif /* TARGET_SPARC64 */
+
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+                                   target_ulong addr, int rw, int mmu_idx)
+{
+    target_ulong page_size;
+    int prot, access_index;
+
+    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+                                mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx)
+{
+    target_phys_addr_t phys_addr;
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_phys_addr_t phys_addr;
+    int mmu_idx = cpu_mmu_index(env);
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+            return -1;
+        }
+    }
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
index 854f168c60c7a0381960f90f30166f954825c0d1..02b660ddf9aa54b57a24c92adeed48e214b6324a 100644 (file)
-#include "exec.h"
-#include "host-utils.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
 #include "helper.h"
-#include "sysemu.h"
-
-//#define DEBUG_MMU
-//#define DEBUG_MXCC
-//#define DEBUG_UNALIGNED
-//#define DEBUG_UNASSIGNED
-//#define DEBUG_ASI
-//#define DEBUG_PCALL
-//#define DEBUG_PSTATE
-//#define DEBUG_CACHE_CONTROL
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...)                                   \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_MXCC
-#define DPRINTF_MXCC(fmt, ...)                                  \
-    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MXCC(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_ASI
-#define DPRINTF_ASI(fmt, ...)                                   \
-    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
-#endif
-
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...)                                   \
-    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
-    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
-#endif
-
-#ifdef TARGET_SPARC64
-#ifndef TARGET_ABI32
-#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
-#else
-#define AM_CHECK(env1) (1)
-#endif
-#endif
-
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
-/* Leon3 cache control */
-
-/* Cache control: emulate the behavior of cache control registers but without
-   any effect on the emulated */
-
-#define CACHE_STATE_MASK 0x3
-#define CACHE_DISABLED   0x0
-#define CACHE_FROZEN     0x1
-#define CACHE_ENABLED    0x3
-
-/* Cache Control register fields */
-
-#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
-#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
-#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
-#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
-#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
-#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
-#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
-#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
-
-#if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                          int is_asi, int size);
-#endif
-
-#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-// Calculates TSB pointer value for fault page size 8k or 64k
-static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
-                                       uint64_t tag_access_register,
-                                       int page_size)
-{
-    uint64_t tsb_base = tsb_register & ~0x1fffULL;
-    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
-    int tsb_size  = tsb_register & 0xf;
-
-    // discard lower 13 bits which hold tag access context
-    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
-
-    // now reorder bits
-    uint64_t tsb_base_mask = ~0x1fffULL;
-    uint64_t va = tag_access_va;
-
-    // move va bits to correct position
-    if (page_size == 8*1024) {
-        va >>= 9;
-    } else if (page_size == 64*1024) {
-        va >>= 12;
-    }
-
-    if (tsb_size) {
-        tsb_base_mask <<= tsb_size;
-    }
-
-    // calculate tsb_base mask and adjust va if split is in use
-    if (tsb_split) {
-        if (page_size == 8*1024) {
-            va &= ~(1ULL << (13 + tsb_size));
-        } else if (page_size == 64*1024) {
-            va |= (1ULL << (13 + tsb_size));
-        }
-        tsb_base_mask <<= 1;
-    }
-
-    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
-}
-
-// Calculates tag target register value by reordering bits
-// in tag access register
-static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
-{
-    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
-}
-
-static void replace_tlb_entry(SparcTLBEntry *tlb,
-                              uint64_t tlb_tag, uint64_t tlb_tte,
-                              CPUState *env1)
-{
-    target_ulong mask, size, va, offset;
-
-    // flush page range if translation is valid
-    if (TTE_IS_VALID(tlb->tte)) {
-
-        mask = 0xffffffffffffe000ULL;
-        mask <<= 3 * ((tlb->tte >> 61) & 3);
-        size = ~mask + 1;
-
-        va = tlb->tag & mask;
-
-        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env1, va + offset);
-        }
-    }
-
-    tlb->tag = tlb_tag;
-    tlb->tte = tlb_tte;
-}
-
-static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
-                      const char* strmmu, CPUState *env1)
-{
-    unsigned int i;
-    target_ulong mask;
-    uint64_t context;
-
-    int is_demap_context = (demap_addr >> 6) & 1;
-
-    // demap context
-    switch ((demap_addr >> 4) & 3) {
-    case 0: // primary
-        context = env1->dmmu.mmu_primary_context;
-        break;
-    case 1: // secondary
-        context = env1->dmmu.mmu_secondary_context;
-        break;
-    case 2: // nucleus
-        context = 0;
-        break;
-    case 3: // reserved
-    default:
-        return;
-    }
-
-    for (i = 0; i < 64; i++) {
-        if (TTE_IS_VALID(tlb[i].tte)) {
-
-            if (is_demap_context) {
-                // will remove non-global entries matching context value
-                if (TTE_IS_GLOBAL(tlb[i].tte) ||
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            } else {
-                // demap page
-                // will remove any entry matching VA
-                mask = 0xffffffffffffe000ULL;
-                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
-
-                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
-                    continue;
-                }
-
-                // entry should be global or matching context value
-                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            }
-
-            replace_tlb_entry(&tlb[i], 0, 0, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-        }
-    }
-}
-
-static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
-                                 uint64_t tlb_tag, uint64_t tlb_tte,
-                                 const char* strmmu, CPUState *env1)
-{
-    unsigned int i, replace_used;
-
-    // Try replacing invalid entry
-    for (i = 0; i < 64; i++) {
-        if (!TTE_IS_VALID(tlb[i].tte)) {
-            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-            return;
-        }
-    }
-
-    // All entries are valid, try replacing unlocked entry
-
-    for (replace_used = 0; replace_used < 2; ++replace_used) {
-
-        // Used entries are not replaced on first pass
-
-        for (i = 0; i < 64; i++) {
-            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
-
-                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
-                            strmmu, (replace_used?"used":"unused"), i);
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                return;
-            }
-        }
-
-        // Now reset used bit and search for unused entries again
-
-        for (i = 0; i < 64; i++) {
-            TTE_SET_UNUSED(tlb[i].tte);
-        }
-    }
-
-#ifdef DEBUG_MMU
-    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
-#endif
-    // error state?
-}
-
-#endif
-
-static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
-{
-#ifdef TARGET_SPARC64
-    if (AM_CHECK(env1))
-        addr &= 0xffffffffULL;
-#endif
-    return addr;
-}
-
-/* returns true if access using this ASI is to have address translated by MMU
-   otherwise access is to raw physical address */
-static inline int is_translating_asi(int asi)
-{
-#ifdef TARGET_SPARC64
-    /* Ultrasparc IIi translating asi
-       - note this list is defined by cpu implementation
-     */
-    switch (asi) {
-    case 0x04 ... 0x11:
-    case 0x18 ... 0x19:
-    case 0x24 ... 0x2C:
-    case 0x70 ... 0x73:
-    case 0x78 ... 0x79:
-    case 0x80 ... 0xFF:
-        return 1;
-
-    default:
-        return 0;
-    }
-#else
-    /* TODO: check sparc32 bits */
-    return 0;
-#endif
-}
-
-static inline target_ulong asi_address_mask(CPUState *env1,
-                                            int asi, target_ulong addr)
-{
-    if (is_translating_asi(asi)) {
-        return address_mask(env, addr);
-    } else {
-        return addr;
-    }
-}
-
-static void raise_exception(int tt)
-{
-    env->exception_index = tt;
-    cpu_loop_exit();
-}
-
-void HELPER(raise_exception)(int tt)
-{
-    raise_exception(tt);
-}
-
-void helper_shutdown(void)
-{
-#if !defined(CONFIG_USER_ONLY)
-    qemu_system_shutdown_request();
-#endif
-}
-
-void helper_check_align(target_ulong addr, uint32_t align)
-{
-    if (addr & align) {
-#ifdef DEBUG_UNALIGNED
-    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-        raise_exception(TT_UNALIGNED);
-    }
-}
-
-#define F_HELPER(name, p) void helper_f##name##p(void)
-
-#define F_BINOP(name)                                           \
-    float32 helper_f ## name ## s (float32 src1, float32 src2)  \
-    {                                                           \
-        return float32_ ## name (src1, src2, &env->fp_status);  \
-    }                                                           \
-    F_HELPER(name, d)                                           \
-    {                                                           \
-        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
-    }                                                           \
-    F_HELPER(name, q)                                           \
-    {                                                           \
-        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
-    }
-
-F_BINOP(add);
-F_BINOP(sub);
-F_BINOP(mul);
-F_BINOP(div);
-#undef F_BINOP
-
-void helper_fsmuld(float32 src1, float32 src2)
-{
-    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
-                      float32_to_float64(src2, &env->fp_status),
-                      &env->fp_status);
-}
-
-void helper_fdmulq(void)
-{
-    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
-                       float64_to_float128(DT1, &env->fp_status),
-                       &env->fp_status);
-}
-
-float32 helper_fnegs(float32 src)
-{
-    return float32_chs(src);
-}
-
-#ifdef TARGET_SPARC64
-F_HELPER(neg, d)
-{
-    DT0 = float64_chs(DT1);
-}
-
-F_HELPER(neg, q)
-{
-    QT0 = float128_chs(QT1);
-}
-#endif
-
-/* Integer to float conversion.  */
-float32 helper_fitos(int32_t src)
-{
-    return int32_to_float32(src, &env->fp_status);
-}
-
-void helper_fitod(int32_t src)
-{
-    DT0 = int32_to_float64(src, &env->fp_status);
-}
-
-void helper_fitoq(int32_t src)
-{
-    QT0 = int32_to_float128(src, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-float32 helper_fxtos(void)
-{
-    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, d)
-{
-    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, q)
-{
-    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
-}
-#endif
-#undef F_HELPER
-
-/* floating point conversion */
-float32 helper_fdtos(void)
-{
-    return float64_to_float32(DT1, &env->fp_status);
-}
-
-void helper_fstod(float32 src)
-{
-    DT0 = float32_to_float64(src, &env->fp_status);
-}
-
-float32 helper_fqtos(void)
-{
-    return float128_to_float32(QT1, &env->fp_status);
-}
-
-void helper_fstoq(float32 src)
-{
-    QT0 = float32_to_float128(src, &env->fp_status);
-}
-
-void helper_fqtod(void)
-{
-    DT0 = float128_to_float64(QT1, &env->fp_status);
-}
-
-void helper_fdtoq(void)
-{
-    QT0 = float64_to_float128(DT1, &env->fp_status);
-}
-
-/* Float to integer conversion.  */
-int32_t helper_fstoi(float32 src)
-{
-    return float32_to_int32_round_to_zero(src, &env->fp_status);
-}
-
-int32_t helper_fdtoi(void)
-{
-    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
-}
-
-int32_t helper_fqtoi(void)
-{
-    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fstox(float32 src)
-{
-    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
-}
-
-void helper_fdtox(void)
-{
-    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
-}
-
-void helper_fqtox(void)
-{
-    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-}
-
-void helper_faligndata(void)
-{
-    uint64_t tmp;
-
-    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
-    /* on many architectures a shift of 64 does nothing */
-    if ((env->gsr & 7) != 0) {
-        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
-    }
-    *((uint64_t *)&DT0) = tmp;
-}
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define VIS_B64(n) b[7 - (n)]
-#define VIS_W64(n) w[3 - (n)]
-#define VIS_SW64(n) sw[3 - (n)]
-#define VIS_L64(n) l[1 - (n)]
-#define VIS_B32(n) b[3 - (n)]
-#define VIS_W32(n) w[1 - (n)]
-#else
-#define VIS_B64(n) b[n]
-#define VIS_W64(n) w[n]
-#define VIS_SW64(n) sw[n]
-#define VIS_L64(n) l[n]
-#define VIS_B32(n) b[n]
-#define VIS_W32(n) w[n]
-#endif
-
-typedef union {
-    uint8_t b[8];
-    uint16_t w[4];
-    int16_t sw[4];
-    uint32_t l[2];
-    float64 d;
-} vis64;
-
-typedef union {
-    uint8_t b[4];
-    uint16_t w[2];
-    uint32_t l;
-    float32 f;
-} vis32;
-
-void helper_fpmerge(void)
-{
-    vis64 s, d;
-
-    s.d = DT0;
-    d.d = DT1;
-
-    // Reverse calculation order to handle overlap
-    d.VIS_B64(7) = s.VIS_B64(3);
-    d.VIS_B64(6) = d.VIS_B64(3);
-    d.VIS_B64(5) = s.VIS_B64(2);
-    d.VIS_B64(4) = d.VIS_B64(2);
-    d.VIS_B64(3) = s.VIS_B64(1);
-    d.VIS_B64(2) = d.VIS_B64(1);
-    d.VIS_B64(1) = s.VIS_B64(0);
-    //d.VIS_B64(0) = d.VIS_B64(0);
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16al(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16au(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8sux16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8ulx16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmuld8sux16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_L64(r) = tmp;
-
-    // Reverse calculation order to handle overlap
-    PMUL(1);
-    PMUL(0);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmuld8ulx16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_L64(r) = tmp;
-
-    // Reverse calculation order to handle overlap
-    PMUL(1);
-    PMUL(0);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fexpand(void)
-{
-    vis32 s;
-    vis64 d;
-
-    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
-    d.d = DT1;
-    d.VIS_W64(0) = s.VIS_B32(0) << 4;
-    d.VIS_W64(1) = s.VIS_B32(1) << 4;
-    d.VIS_W64(2) = s.VIS_B32(2) << 4;
-    d.VIS_W64(3) = s.VIS_B32(3) << 4;
-
-    DT0 = d.d;
-}
-
-#define VIS_HELPER(name, F)                             \
-    void name##16(void)                                 \
-    {                                                   \
-        vis64 s, d;                                     \
-                                                        \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
-                                                        \
-        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
-        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
-        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
-        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
-                                                        \
-        DT0 = d.d;                                      \
-    }                                                   \
-                                                        \
-    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
-    {                                                   \
-        vis32 s, d;                                     \
-                                                        \
-        s.l = src1;                                     \
-        d.l = src2;                                     \
-                                                        \
-        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
-        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
-                                                        \
-        return d.l;                                     \
-    }                                                   \
-                                                        \
-    void name##32(void)                                 \
-    {                                                   \
-        vis64 s, d;                                     \
-                                                        \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
-                                                        \
-        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
-        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
-                                                        \
-        DT0 = d.d;                                      \
-    }                                                   \
-                                                        \
-    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
-    {                                                   \
-        vis32 s, d;                                     \
-                                                        \
-        s.l = src1;                                     \
-        d.l = src2;                                     \
-                                                        \
-        d.l = F(d.l, s.l);                              \
-                                                        \
-        return d.l;                                     \
-    }
-
-#define FADD(a, b) ((a) + (b))
-#define FSUB(a, b) ((a) - (b))
-VIS_HELPER(helper_fpadd, FADD)
-VIS_HELPER(helper_fpsub, FSUB)
-
-#define VIS_CMPHELPER(name, F)                                        \
-    void name##16(void)                                           \
-    {                                                             \
-        vis64 s, d;                                               \
-                                                                  \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
-                                                                  \
-        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0;       \
-        d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0;      \
-        d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0;      \
-        d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0;      \
-                                                                  \
-        DT0 = d.d;                                                \
-    }                                                             \
-                                                                  \
-    void name##32(void)                                           \
-    {                                                             \
-        vis64 s, d;                                               \
-                                                                  \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
-                                                                  \
-        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0;       \
-        d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0;      \
-                                                                  \
-        DT0 = d.d;                                                \
-    }
-
-#define FCMPGT(a, b) ((a) > (b))
-#define FCMPEQ(a, b) ((a) == (b))
-#define FCMPLE(a, b) ((a) <= (b))
-#define FCMPNE(a, b) ((a) != (b))
-
-VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
-VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
-VIS_CMPHELPER(helper_fcmple, FCMPLE)
-VIS_CMPHELPER(helper_fcmpne, FCMPNE)
-#endif
-
-void helper_check_ieee_exceptions(void)
-{
-    target_ulong status;
-
-    status = get_float_exception_flags(&env->fp_status);
-    if (status) {
-        /* Copy IEEE 754 flags into FSR */
-        if (status & float_flag_invalid)
-            env->fsr |= FSR_NVC;
-        if (status & float_flag_overflow)
-            env->fsr |= FSR_OFC;
-        if (status & float_flag_underflow)
-            env->fsr |= FSR_UFC;
-        if (status & float_flag_divbyzero)
-            env->fsr |= FSR_DZC;
-        if (status & float_flag_inexact)
-            env->fsr |= FSR_NXC;
-
-        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
-            /* Unmasked exception, generate a trap */
-            env->fsr |= FSR_FTT_IEEE_EXCP;
-            raise_exception(TT_FP_EXCP);
-        } else {
-            /* Accumulate exceptions */
-            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
-        }
-    }
-}
-
-void helper_clear_float_exceptions(void)
-{
-    set_float_exception_flags(0, &env->fp_status);
-}
-
-float32 helper_fabss(float32 src)
-{
-    return float32_abs(src);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fabsd(void)
-{
-    DT0 = float64_abs(DT1);
-}
-
-void helper_fabsq(void)
-{
-    QT0 = float128_abs(QT1);
-}
-#endif
-
-float32 helper_fsqrts(float32 src)
-{
-    return float32_sqrt(src, &env->fp_status);
-}
-
-void helper_fsqrtd(void)
-{
-    DT0 = float64_sqrt(DT1, &env->fp_status);
-}
-
-void helper_fsqrtq(void)
-{
-    QT0 = float128_sqrt(QT1, &env->fp_status);
-}
-
-#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
-    void glue(helper_, name) (void)                                     \
-    {                                                                   \
-        env->fsr &= FSR_FTT_NMASK;                                      \
-        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
-                     glue(size, _is_any_nan)(reg2)) &&                  \
-            (env->fsr & FSR_NVM)) {                                     \
-            env->fsr |= FSR_NVC;                                        \
-            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
-            raise_exception(TT_FP_EXCP);                                \
-        }                                                               \
-        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
-        case float_relation_unordered:                                  \
-            if ((env->fsr & FSR_NVM)) {                                 \
-                env->fsr |= FSR_NVC;                                    \
-                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
-                raise_exception(TT_FP_EXCP);                            \
-            } else {                                                    \
-                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
-                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
-                env->fsr |= FSR_NVA;                                    \
-            }                                                           \
-            break;                                                      \
-        case float_relation_less:                                       \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC0 << FS;                                 \
-            break;                                                      \
-        case float_relation_greater:                                    \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC1 << FS;                                 \
-            break;                                                      \
-        default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            break;                                                      \
-        }                                                               \
-    }
-#define GEN_FCMPS(name, size, FS, E)                                    \
-    void glue(helper_, name)(float32 src1, float32 src2)                \
-    {                                                                   \
-        env->fsr &= FSR_FTT_NMASK;                                      \
-        if (E && (glue(size, _is_any_nan)(src1) ||                      \
-                     glue(size, _is_any_nan)(src2)) &&                  \
-            (env->fsr & FSR_NVM)) {                                     \
-            env->fsr |= FSR_NVC;                                        \
-            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
-            raise_exception(TT_FP_EXCP);                                \
-        }                                                               \
-        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
-        case float_relation_unordered:                                  \
-            if ((env->fsr & FSR_NVM)) {                                 \
-                env->fsr |= FSR_NVC;                                    \
-                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
-                raise_exception(TT_FP_EXCP);                            \
-            } else {                                                    \
-                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
-                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
-                env->fsr |= FSR_NVA;                                    \
-            }                                                           \
-            break;                                                      \
-        case float_relation_less:                                       \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC0 << FS;                                 \
-            break;                                                      \
-        case float_relation_greater:                                    \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC1 << FS;                                 \
-            break;                                                      \
-        default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            break;                                                      \
-        }                                                               \
-    }
-
-GEN_FCMPS(fcmps, float32, 0, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
-
-GEN_FCMPS(fcmpes, float32, 0, 1);
-GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
-
-GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
-GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
-
-static uint32_t compute_all_flags(void)
-{
-    return env->psr & PSR_ICC;
-}
-
-static uint32_t compute_C_flags(void)
-{
-    return env->psr & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_icc(int32_t dst)
-{
-    uint32_t ret = 0;
-
-    if (dst == 0) {
-        ret = PSR_ZERO;
-    } else if (dst < 0) {
-        ret = PSR_NEG;
-    }
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_flags_xcc(void)
-{
-    return env->xcc & PSR_ICC;
-}
-
-static uint32_t compute_C_flags_xcc(void)
-{
-    return env->xcc & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_xcc(target_long dst)
-{
-    uint32_t ret = 0;
-
-    if (!dst) {
-        ret = PSR_ZERO;
-    } else if (dst < 0) {
-        ret = PSR_NEG;
-    }
-    return ret;
-}
-#endif
-
-static inline uint32_t get_V_div_icc(target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (src2 != 0) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_div(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_V_div_icc(CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_div(void)
-{
-    return 0;
-}
-
-static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
-{
-    uint32_t ret = 0;
-
-    if (dst < src1) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
-                                      uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
-                                     uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
-{
-    uint32_t ret = 0;
-
-    if (dst < src1) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
-                                      target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
-                                         target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_add_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_add_xcc(CC_DST, CC_SRC);
-    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_add_xcc(void)
-{
-    return get_C_add_xcc(CC_DST, CC_SRC);
-}
-#endif
-
-static uint32_t compute_all_add(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_add(void)
-{
-    return get_C_add_icc(CC_DST, CC_SRC);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_addx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_addx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-#endif
-
-static uint32_t compute_all_addx(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_addx(void)
-{
-    uint32_t ret;
-
-    ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if ((src1 | src2) & 0x3) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_tadd(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_taddtv(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    return ret;
-}
-
-static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (src1 < src2) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
-                                      uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
-                                     uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (src1 < src2) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
-                                      target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
-                                     target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_sub_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_sub_xcc(void)
-{
-    return get_C_sub_xcc(CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_sub(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_sub(void)
-{
-    return get_C_sub_icc(CC_SRC, CC_SRC2);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_subx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_subx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-#endif
-
-static uint32_t compute_all_subx(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_subx(void)
-{
-    uint32_t ret;
-
-    ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_tsub(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_tsubtv(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_logic(void)
-{
-    return get_NZ_icc(CC_DST);
-}
-
-static uint32_t compute_C_logic(void)
-{
-    return 0;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_logic_xcc(void)
-{
-    return get_NZ_xcc(CC_DST);
-}
-#endif
-
-typedef struct CCTable {
-    uint32_t (*compute_all)(void); /* return all the flags */
-    uint32_t (*compute_c)(void);  /* return the C flag */
-} CCTable;
-
-static const CCTable icc_table[CC_OP_NB] = {
-    /* CC_OP_DYNAMIC should never happen */
-    [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
-    [CC_OP_DIV] = { compute_all_div, compute_C_div },
-    [CC_OP_ADD] = { compute_all_add, compute_C_add },
-    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
-    [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
-    [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
-    [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
-    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
-    [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
-    [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
-    [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
-};
-
-#ifdef TARGET_SPARC64
-static const CCTable xcc_table[CC_OP_NB] = {
-    /* CC_OP_DYNAMIC should never happen */
-    [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
-    [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
-    [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
-    [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
-    [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
-};
-#endif
-
-void helper_compute_psr(void)
-{
-    uint32_t new_psr;
-
-    new_psr = icc_table[CC_OP].compute_all();
-    env->psr = new_psr;
-#ifdef TARGET_SPARC64
-    new_psr = xcc_table[CC_OP].compute_all();
-    env->xcc = new_psr;
-#endif
-    CC_OP = CC_OP_FLAGS;
-}
-
-uint32_t helper_compute_C_icc(void)
-{
-    uint32_t ret;
-
-    ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
-    return ret;
-}
-
-static inline void memcpy32(target_ulong *dst, const target_ulong *src)
-{
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    dst[4] = src[4];
-    dst[5] = src[5];
-    dst[6] = src[6];
-    dst[7] = src[7];
-}
-
-static void set_cwp(int new_cwp)
-{
-    /* put the modified wrap registers at their proper location */
-    if (env->cwp == env->nwindows - 1) {
-        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
-    }
-    env->cwp = new_cwp;
-
-    /* put the wrap registers at their temporary location */
-    if (new_cwp == env->nwindows - 1) {
-        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
-    }
-    env->regwptr = env->regbase + (new_cwp * 16);
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    set_cwp(new_cwp);
-    env = saved_env;
-}
-
-static target_ulong get_psr(void)
-{
-    helper_compute_psr();
-
-#if !defined (TARGET_SPARC64)
-    return env->version | (env->psr & PSR_ICC) |
-        (env->psref? PSR_EF : 0) |
-        (env->psrpil << 8) |
-        (env->psrs? PSR_S : 0) |
-        (env->psrps? PSR_PS : 0) |
-        (env->psret? PSR_ET : 0) | env->cwp;
-#else
-    return env->psr & PSR_ICC;
-#endif
-}
-
-target_ulong cpu_get_psr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_psr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_psr(target_ulong val)
-{
-    env->psr = val & PSR_ICC;
-#if !defined (TARGET_SPARC64)
-    env->psref = (val & PSR_EF)? 1 : 0;
-    env->psrpil = (val & PSR_PIL) >> 8;
-#endif
-#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
-    cpu_check_irqs(env);
-#endif
-#if !defined (TARGET_SPARC64)
-    env->psrs = (val & PSR_S)? 1 : 0;
-    env->psrps = (val & PSR_PS)? 1 : 0;
-    env->psret = (val & PSR_ET)? 1 : 0;
-    set_cwp(val & PSR_CWP);
-#endif
-    env->cc_op = CC_OP_FLAGS;
-}
-
-void cpu_put_psr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_psr(val);
-    env = saved_env;
-}
-
-static int cwp_inc(int cwp)
-{
-    if (unlikely(cwp >= env->nwindows)) {
-        cwp -= env->nwindows;
-    }
-    return cwp;
-}
-
-int cpu_cwp_inc(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_inc(cwp);
-    env = saved_env;
-    return ret;
-}
-
-static int cwp_dec(int cwp)
-{
-    if (unlikely(cwp < 0)) {
-        cwp += env->nwindows;
-    }
-    return cwp;
-}
-
-int cpu_cwp_dec(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_dec(cwp);
-    env = saved_env;
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
-
-GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
-
-GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
-GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
-
-GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
-GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
-GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
-
-GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
-GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
-GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
-
-GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
-GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
-GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
-#endif
-#undef GEN_FCMPS
-
-#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
-    defined(DEBUG_MXCC)
-static void dump_mxcc(CPUState *env)
-{
-    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccdata[0], env->mxccdata[1],
-           env->mxccdata[2], env->mxccdata[3]);
-    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n"
-           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccregs[0], env->mxccregs[1],
-           env->mxccregs[2], env->mxccregs[3],
-           env->mxccregs[4], env->mxccregs[5],
-           env->mxccregs[6], env->mxccregs[7]);
-}
-#endif
-
-#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
-    && defined(DEBUG_ASI)
-static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
-                     uint64_t r1)
-{
-    switch (size)
-    {
-    case 1:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xff);
-        break;
-    case 2:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffff);
-        break;
-    case 4:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffffffff);
-        break;
-    case 8:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
-                    addr, asi, r1);
-        break;
-    }
-}
-#endif
-
-#ifndef TARGET_SPARC64
-#ifndef CONFIG_USER_ONLY
-
-
-/* Leon3 cache control */
-
-static void leon3_cache_control_int(void)
-{
-    uint32_t state = 0;
-
-    if (env->cache_control & CACHE_CTRL_IF) {
-        /* Instruction cache state */
-        state = env->cache_control & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
-        }
-
-        env->cache_control &= ~CACHE_STATE_MASK;
-        env->cache_control |= state;
-    }
-
-    if (env->cache_control & CACHE_CTRL_DF) {
-        /* Data cache state */
-        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
-        }
-
-        env->cache_control &= ~(CACHE_STATE_MASK << 2);
-        env->cache_control |= (state << 2);
-    }
-}
-
-static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
-{
-    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
-                          addr, val, size);
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-
-        /* These values must always be read as zeros */
-        val &= ~CACHE_CTRL_FD;
-        val &= ~CACHE_CTRL_FI;
-        val &= ~CACHE_CTRL_IB;
-        val &= ~CACHE_CTRL_IP;
-        val &= ~CACHE_CTRL_DP;
-
-        env->cache_control = val;
-        break;
-    case 0x04:              /* Instruction cache configuration */
-    case 0x08:              /* Data cache configuration */
-        /* Read Only */
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
-        break;
-    };
-}
-
-static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
-{
-    uint64_t ret = 0;
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return 0;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-        ret = env->cache_control;
-        break;
-
-        /* Configuration registers are read and only always keep those
-           predefined values */
-
-    case 0x04:              /* Instruction cache configuration */
-        ret = 0x10220000;
-        break;
-    case 0x08:              /* Data cache configuration */
-        ret = 0x18220000;
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
-        break;
-    };
-    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
-                          addr, ret, size);
-    return ret;
-}
-
-void leon3_irq_manager(void *irq_manager, int intno)
-{
-    leon3_irq_ack(irq_manager, intno);
-    leon3_cache_control_int();
-}
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
-    uint32_t last_addr = addr;
-#endif
-
-    helper_check_align(addr, size - 1);
-    switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                ret = leon3_cache_control_ld(addr, size);
-            }
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8)
-                ret = env->mxccregs[3];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4)
-                ret = env->mxccregs[3];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00c00: /* Module reset register */
-            if (size == 8) {
-                ret = env->mxccregs[5];
-                // should we do something here?
-            } else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8)
-                ret = env->mxccregs[7];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
-                     "addr = %08x -> ret = %" PRIx64 ","
-                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU probe */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            if (mmulev > 4)
-                ret = 0;
-            else
-                ret = mmu_probe(env, addr, mmulev);
-            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
-                        addr, mmulev, ret);
-        }
-        break;
-    case 4: /* read MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-
-            ret = env->mmuregs[reg];
-            if (reg == 3) /* Fault status cleared on read */
-                env->mmuregs[3] = 0;
-            else if (reg == 0x13) /* Fault status read */
-                ret = env->mmuregs[3];
-            else if (reg == 0x14) /* Fault address read */
-                ret = env->mmuregs[4];
-            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
-        }
-        break;
-    case 5: // Turbosparc ITLB Diagnostic
-    case 6: // Turbosparc DTLB Diagnostic
-    case 7: // Turbosparc IOTLB Diagnostic
-        break;
-    case 9: /* Supervisor code access */
-        switch(size) {
-        case 1:
-            ret = ldub_code(addr);
-            break;
-        case 2:
-            ret = lduw_code(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_code(addr);
-            break;
-        case 8:
-            ret = ldq_code(addr);
-            break;
-        }
-        break;
-    case 0xa: /* User data access */
-        switch(size) {
-        case 1:
-            ret = ldub_user(addr);
-            break;
-        case 2:
-            ret = lduw_user(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_user(addr);
-            break;
-        case 8:
-            ret = ldq_user(addr);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch(size) {
-        case 1:
-            ret = ldub_kernel(addr);
-            break;
-        case 2:
-            ret = lduw_kernel(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_kernel(addr);
-            break;
-        case 8:
-            ret = ldq_kernel(addr);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-        break;
-    case 0x20: /* MMU passthrough */
-        switch(size) {
-        case 1:
-            ret = ldub_phys(addr);
-            break;
-        case 2:
-            ret = lduw_phys(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_phys(addr);
-            break;
-        case 8:
-            ret = ldq_phys(addr);
-            break;
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        switch(size) {
-        case 1:
-            ret = ldub_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 2:
-            ret = lduw_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        default:
-        case 4:
-            ret = ldl_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 8:
-            ret = ldq_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        }
-        break;
-    case 0x30: // Turbosparc secondary cache diagnostic
-    case 0x31: // Turbosparc RAM snoop
-    case 0x32: // Turbosparc page table descriptor diagnostic
-    case 0x39: /* data cache diagnostic register */
-    case 0x4c: /* SuperSPARC MMU Breakpoint Action register */
-        ret = 0;
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch(reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                ret = env->mmubpregs[reg];
-                break;
-            case 1: /* Breakpoint Mask */
-                ret = env->mmubpregs[reg];
-                break;
-            case 2: /* Breakpoint Control */
-                ret = env->mmubpregs[reg];
-                break;
-            case 3: /* Breakpoint Status */
-                ret = env->mmubpregs[reg];
-                env->mmubpregs[reg] = 0ULL;
-                break;
-            }
-            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
-                        ret);
-        }
-        break;
-    case 8: /* User code access, XXX */
-    default:
-        do_unassigned_access(addr, 0, 0, asi, size);
-        ret = 0;
-        break;
-    }
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
-{
-    helper_check_align(addr, size - 1);
-    switch(asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                leon3_cache_control_st(addr, val, size);
-            }
-            break;
-
-        case 0x01c00000: /* MXCC stream data register 0 */
-            if (size == 8)
-                env->mxccdata[0] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00008: /* MXCC stream data register 1 */
-            if (size == 8)
-                env->mxccdata[1] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00010: /* MXCC stream data register 2 */
-            if (size == 8)
-                env->mxccdata[2] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00018: /* MXCC stream data register 3 */
-            if (size == 8)
-                env->mxccdata[3] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00100: /* MXCC stream source */
-            if (size == 8)
-                env->mxccregs[0] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        0);
-            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        8);
-            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        16);
-            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        24);
-            break;
-        case 0x01c00200: /* MXCC stream destination */
-            if (size == 8)
-                env->mxccregs[1] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
-                     env->mxccdata[0]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
-                     env->mxccdata[1]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
-                     env->mxccdata[2]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
-                     env->mxccdata[3]);
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8)
-                env->mxccregs[3] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4)
-                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
-                    | val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00e00: /* MXCC error register  */
-            // writing a 1 bit clears the error
-            if (size == 8)
-                env->mxccregs[6] &= ~val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8)
-                env->mxccregs[7] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
-                     asi, size, addr, val);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU flush */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            DPRINTF_MMU("mmu flush level %d\n", mmulev);
-            switch (mmulev) {
-            case 0: // flush page
-                tlb_flush_page(env, addr & 0xfffff000);
-                break;
-            case 1: // flush segment (256k)
-            case 2: // flush region (16M)
-            case 3: // flush context (4G)
-            case 4: // flush entire
-                tlb_flush(env, 1);
-                break;
-            default:
-                break;
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 4: /* write MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-            uint32_t oldreg;
-
-            oldreg = env->mmuregs[reg];
-            switch(reg) {
-            case 0: // Control Register
-                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
-                                    (val & 0x00ffffff);
-                // Mappings generated during no-fault mode or MMU
-                // disabled mode are invalid in normal mode
-                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
-                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
-                    tlb_flush(env, 1);
-                break;
-            case 1: // Context Table Pointer Register
-                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
-                break;
-            case 2: // Context Register
-                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
-                if (oldreg != env->mmuregs[reg]) {
-                    /* we flush when the MMU context changes because
-                       QEMU has no MMU context support */
-                    tlb_flush(env, 1);
-                }
-                break;
-            case 3: // Synchronous Fault Status Register with Clear
-            case 4: // Synchronous Fault Address Register
-                break;
-            case 0x10: // TLB Replacement Control Register
-                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
-                break;
-            case 0x13: // Synchronous Fault Status Register with Read and Clear
-                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
-                break;
-            case 0x14: // Synchronous Fault Address Register
-                env->mmuregs[4] = val;
-                break;
-            default:
-                env->mmuregs[reg] = val;
-                break;
-            }
-            if (oldreg != env->mmuregs[reg]) {
-                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
-                            reg, oldreg, env->mmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 5: // Turbosparc ITLB Diagnostic
-    case 6: // Turbosparc DTLB Diagnostic
-    case 7: // Turbosparc IOTLB Diagnostic
-        break;
-    case 0xa: /* User data access */
-        switch(size) {
-        case 1:
-            stb_user(addr, val);
-            break;
-        case 2:
-            stw_user(addr, val);
-            break;
-        default:
-        case 4:
-            stl_user(addr, val);
-            break;
-        case 8:
-            stq_user(addr, val);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch(size) {
-        case 1:
-            stb_kernel(addr, val);
-            break;
-        case 2:
-            stw_kernel(addr, val);
-            break;
-        default:
-        case 4:
-            stl_kernel(addr, val);
-            break;
-        case 8:
-            stq_kernel(addr, val);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-    case 0x10: /* I/D-cache flush page */
-    case 0x11: /* I/D-cache flush segment */
-    case 0x12: /* I/D-cache flush region */
-    case 0x13: /* I/D-cache flush context */
-    case 0x14: /* I/D-cache flush user */
-        break;
-    case 0x17: /* Block copy, sta access */
-        {
-            // val = src
-            // addr = dst
-            // copy 32 bytes
-            unsigned int i;
-            uint32_t src = val & ~3, dst = addr & ~3, temp;
-
-            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
-                temp = ldl_kernel(src);
-                stl_kernel(dst, temp);
-            }
-        }
-        break;
-    case 0x1f: /* Block fill, stda access */
-        {
-            // addr = dst
-            // fill 32 bytes with val
-            unsigned int i;
-            uint32_t dst = addr & 7;
-
-            for (i = 0; i < 32; i += 8, dst += 8)
-                stq_kernel(dst, val);
-        }
-        break;
-    case 0x20: /* MMU passthrough */
-        {
-            switch(size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-            default:
-                stl_phys(addr, val);
-                break;
-            case 8:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        {
-            switch(size) {
-            case 1:
-                stb_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 2:
-                stw_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 4:
-            default:
-                stl_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 8:
-                stq_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            }
-        }
-        break;
-    case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
-    case 0x31: // store buffer data, Ross RT620 I-cache flush or
-               // Turbosparc snoop RAM
-    case 0x32: // store buffer control or Turbosparc page table
-               // descriptor diagnostic
-    case 0x36: /* I-cache flash clear */
-    case 0x37: /* D-cache flash clear */
-    case 0x4c: /* breakpoint action */
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch(reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 1: /* Breakpoint Mask */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 2: /* Breakpoint Control */
-                env->mmubpregs[reg] = (val & 0x7fULL);
-                break;
-            case 3: /* Breakpoint Status */
-                env->mmubpregs[reg] = (val & 0xfULL);
-                break;
-            }
-            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
-                        env->mmuregs[reg]);
-        }
-        break;
-    case 8: /* User code access, XXX */
-    case 9: /* Supervisor code access, XXX */
-    default:
-        do_unassigned_access(addr, 1, 0, asi, size);
-        break;
-    }
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-}
-
-#endif /* CONFIG_USER_ONLY */
-#else /* TARGET_SPARC64 */
-
-#ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    if (asi < 0x80)
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0x82: // Primary no-fault
-    case 0x8a: // Primary no-fault LE
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        // Fall through
-    case 0x80: // Primary
-    case 0x88: // Primary LE
-        {
-            switch(size) {
-            case 1:
-                ret = ldub_raw(addr);
-                break;
-            case 2:
-                ret = lduw_raw(addr);
-                break;
-            case 4:
-                ret = ldl_raw(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_raw(addr);
-                break;
-            }
-        }
-        break;
-    case 0x83: // Secondary no-fault
-    case 0x8b: // Secondary no-fault LE
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        // Fall through
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
-        // XXX
-        break;
-    default:
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0x8a: // Primary no-fault LE
-    case 0x8b: // Secondary no-fault LE
-        switch(size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-    if (asi < 0x80)
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-        switch(size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch(asi) {
-    case 0x80: // Primary
-    case 0x88: // Primary LE
-        {
-            switch(size) {
-            case 1:
-                stb_raw(addr, val);
-                break;
-            case 2:
-                stw_raw(addr, val);
-                break;
-            case 4:
-                stl_raw(addr, val);
-                break;
-            case 8:
-            default:
-                stq_raw(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
-        // XXX
-        return;
-
-    case 0x82: // Primary no-fault, RO
-    case 0x83: // Secondary no-fault, RO
-    case 0x8a: // Primary no-fault LE, RO
-    case 0x8b: // Secondary no-fault LE, RO
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-
-#else /* CONFIG_USER_ONLY */
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0x82: // Primary no-fault
-    case 0x8a: // Primary no-fault LE
-    case 0x83: // Secondary no-fault
-    case 0x8b: // Secondary no-fault LE
-        {
-            /* secondary space access has lowest asi bit equal to 1 */
-            int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX
-                                             : MMU_KERNEL_SECONDARY_IDX;
-
-            if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) {
-#ifdef DEBUG_ASI
-                dump_asi("read ", last_addr, asi, size, ret);
-#endif
-                return 0;
-            }
-        }
-        // Fall through
-    case 0x10: // As if user primary
-    case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x80: // Primary
-    case 0x81: // Secondary
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0xe2: // UA2007 Primary block init
-    case 0xe3: // UA2007 Secondary block init
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch(size) {
-                case 1:
-                    ret = ldub_hypv(addr);
-                    break;
-                case 2:
-                    ret = lduw_hypv(addr);
-                    break;
-                case 4:
-                    ret = ldl_hypv(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_hypv(addr);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch(size) {
-                    case 1:
-                        ret = ldub_kernel_secondary(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel_secondary(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel_secondary(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel_secondary(addr);
-                        break;
-                    }
-                } else {
-                    switch(size) {
-                    case 1:
-                        ret = ldub_kernel(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel(addr);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch(size) {
-                case 1:
-                    ret = ldub_user_secondary(addr);
-                    break;
-                case 2:
-                    ret = lduw_user_secondary(addr);
-                    break;
-                case 4:
-                    ret = ldl_user_secondary(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user_secondary(addr);
-                    break;
-                }
-            } else {
-                switch(size) {
-                case 1:
-                    ret = ldub_user(addr);
-                    break;
-                case 2:
-                    ret = lduw_user(addr);
-                    break;
-                case 4:
-                    ret = ldl_user(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user(addr);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: // Bypass
-    case 0x15: // Bypass, non-cacheable
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-        {
-            switch(size) {
-            case 1:
-                ret = ldub_phys(addr);
-                break;
-            case 2:
-                ret = lduw_phys(addr);
-                break;
-            case 4:
-                ret = ldl_phys(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_phys(addr);
-                break;
-            }
-            break;
-        }
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        //  Only ldda allowed
-        raise_exception(TT_ILL_INSN);
-        return 0;
-    case 0x04: // Nucleus
-    case 0x0c: // Nucleus Little Endian (LE)
-    {
-        switch(size) {
-        case 1:
-            ret = ldub_nucleus(addr);
-            break;
-        case 2:
-            ret = lduw_nucleus(addr);
-            break;
-        case 4:
-            ret = ldl_nucleus(addr);
-            break;
-        default:
-        case 8:
-            ret = ldq_nucleus(addr);
-            break;
-        }
-        break;
-    }
-    case 0x4a: // UPA config
-        // XXX
-        break;
-    case 0x45: // LSU
-        ret = env->lsu;
-        break;
-    case 0x50: // I-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                // I-TSB Tag Target register
-                ret = ultrasparc_tag_target(env->immu.tag_access);
-            } else {
-                ret = env->immuregs[reg];
-            }
-
-            break;
-        }
-    case 0x51: // I-MMU 8k TSB pointer
-        {
-            // env->immuregs[5] holds I-MMU TSB register value
-            // env->immuregs[6] holds I-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x52: // I-MMU 64k TSB pointer
-        {
-            // env->immuregs[5] holds I-MMU TSB register value
-            // env->immuregs[6] holds I-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x55: // I-MMU data access
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tte;
-            break;
-        }
-    case 0x56: // I-MMU tag read
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tag;
-            break;
-        }
-    case 0x58: // D-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                // D-TSB Tag Target register
-                ret = ultrasparc_tag_target(env->dmmu.tag_access);
-            } else {
-                ret = env->dmmuregs[reg];
-            }
-            break;
-        }
-    case 0x59: // D-MMU 8k TSB pointer
-        {
-            // env->dmmuregs[5] holds D-MMU TSB register value
-            // env->dmmuregs[6] holds D-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x5a: // D-MMU 64k TSB pointer
-        {
-            // env->dmmuregs[5] holds D-MMU TSB register value
-            // env->dmmuregs[6] holds D-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x5d: // D-MMU data access
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tte;
-            break;
-        }
-    case 0x5e: // D-MMU tag read
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tag;
-            break;
-        }
-    case 0x46: // D-cache data
-    case 0x47: // D-cache tag access
-    case 0x4b: // E-cache error enable
-    case 0x4c: // E-cache asynchronous fault status
-    case 0x4d: // E-cache asynchronous fault address
-    case 0x4e: // E-cache tag data
-    case 0x66: // I-cache instruction access
-    case 0x67: // I-cache tag access
-    case 0x6e: // I-cache predecode
-    case 0x6f: // I-cache LRU etc.
-    case 0x76: // E-cache tag
-    case 0x7e: // E-cache tag
-        break;
-    case 0x5b: // D-MMU data pointer
-    case 0x48: // Interrupt dispatch, RO
-    case 0x49: // Interrupt data receive
-    case 0x7f: // Incoming interrupt vector, RO
-        // XXX
-        break;
-    case 0x54: // I-MMU data in, WO
-    case 0x57: // I-MMU demap, WO
-    case 0x5c: // D-MMU data in, WO
-    case 0x5f: // D-MMU demap, WO
-    case 0x77: // Interrupt vector, WO
-    default:
-        do_unassigned_access(addr, 0, 0, 1, size);
-        ret = 0;
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x0c: // Nucleus Little Endian (LE)
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0x8a: // Primary no-fault LE
-    case 0x8b: // Secondary no-fault LE
-        switch(size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x0c: // Nucleus Little Endian (LE)
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-        switch(size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch(asi) {
-    case 0x10: // As if user primary
-    case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x80: // Primary
-    case 0x81: // Secondary
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0xe2: // UA2007 Primary block init
-    case 0xe3: // UA2007 Secondary block init
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch(size) {
-                case 1:
-                    stb_hypv(addr, val);
-                    break;
-                case 2:
-                    stw_hypv(addr, val);
-                    break;
-                case 4:
-                    stl_hypv(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_hypv(addr, val);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch(size) {
-                    case 1:
-                        stb_kernel_secondary(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel_secondary(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel_secondary(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel_secondary(addr, val);
-                        break;
-                    }
-                } else {
-                    switch(size) {
-                    case 1:
-                        stb_kernel(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel(addr, val);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch(size) {
-                case 1:
-                    stb_user_secondary(addr, val);
-                    break;
-                case 2:
-                    stw_user_secondary(addr, val);
-                    break;
-                case 4:
-                    stl_user_secondary(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user_secondary(addr, val);
-                    break;
-                }
-            } else {
-                switch(size) {
-                case 1:
-                    stb_user(addr, val);
-                    break;
-                case 2:
-                    stw_user(addr, val);
-                    break;
-                case 4:
-                    stl_user(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user(addr, val);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: // Bypass
-    case 0x15: // Bypass, non-cacheable
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-        {
-            switch(size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-                stl_phys(addr, val);
-                break;
-            case 8:
-            default:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        return;
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        //  Only ldda allowed
-        raise_exception(TT_ILL_INSN);
-        return;
-    case 0x04: // Nucleus
-    case 0x0c: // Nucleus Little Endian (LE)
-    {
-        switch(size) {
-        case 1:
-            stb_nucleus(addr, val);
-            break;
-        case 2:
-            stw_nucleus(addr, val);
-            break;
-        case 4:
-            stl_nucleus(addr, val);
-            break;
-        default:
-        case 8:
-            stq_nucleus(addr, val);
-            break;
-        }
-        break;
-    }
-
-    case 0x4a: // UPA config
-        // XXX
-        return;
-    case 0x45: // LSU
-        {
-            uint64_t oldreg;
-
-            oldreg = env->lsu;
-            env->lsu = val & (DMMU_E | IMMU_E);
-            // Mappings generated during D/I MMU disabled mode are
-            // invalid in normal mode
-            if (oldreg != env->lsu) {
-                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
-                            oldreg, env->lsu);
-#ifdef DEBUG_MMU
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                tlb_flush(env, 1);
-            }
-            return;
-        }
-    case 0x50: // I-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->immuregs[reg];
-            switch(reg) {
-            case 0: // RO
-                return;
-            case 1: // Not in I-MMU
-            case 2:
-                return;
-            case 3: // SFSR
-                if ((val & 1) == 0)
-                    val = 0; // Clear SFSR
-                env->immu.sfsr = val;
-                break;
-            case 4: // RO
-                return;
-            case 5: // TSB access
-                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->immu.tsb, val);
-                env->immu.tsb = val;
-                break;
-            case 6: // Tag access
-                env->immu.tag_access = val;
-                break;
-            case 7:
-            case 8:
-                return;
-            default:
-                break;
-            }
-
-            if (oldreg != env->immuregs[reg]) {
-                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x54: // I-MMU data in
-        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
-        return;
-    case 0x55: // I-MMU data access
-        {
-            // TODO: auto demap
-
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x57: // I-MMU demap
-        demap_tlb(env->itlb, addr, "immu", env);
-        return;
-    case 0x58: // D-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->dmmuregs[reg];
-            switch(reg) {
-            case 0: // RO
-            case 4:
-                return;
-            case 3: // SFSR
-                if ((val & 1) == 0) {
-                    val = 0; // Clear SFSR, Fault address
-                    env->dmmu.sfar = 0;
-                }
-                env->dmmu.sfsr = val;
-                break;
-            case 1: // Primary context
-                env->dmmu.mmu_primary_context = val;
-                /* can be optimized to only flush MMU_USER_IDX
-                   and MMU_KERNEL_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 2: // Secondary context
-                env->dmmu.mmu_secondary_context = val;
-                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
-                   and MMU_KERNEL_SECONDARY_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 5: // TSB access
-                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->dmmu.tsb, val);
-                env->dmmu.tsb = val;
-                break;
-            case 6: // Tag access
-                env->dmmu.tag_access = val;
-                break;
-            case 7: // Virtual Watchpoint
-            case 8: // Physical Watchpoint
-            default:
-                env->dmmuregs[reg] = val;
-                break;
-            }
-
-            if (oldreg != env->dmmuregs[reg]) {
-                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5c: // D-MMU data in
-        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
-        return;
-    case 0x5d: // D-MMU data access
-        {
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5f: // D-MMU demap
-        demap_tlb(env->dtlb, addr, "dmmu", env);
-        return;
-    case 0x49: // Interrupt data receive
-        // XXX
-        return;
-    case 0x46: // D-cache data
-    case 0x47: // D-cache tag access
-    case 0x4b: // E-cache error enable
-    case 0x4c: // E-cache asynchronous fault status
-    case 0x4d: // E-cache asynchronous fault address
-    case 0x4e: // E-cache tag data
-    case 0x66: // I-cache instruction access
-    case 0x67: // I-cache tag access
-    case 0x6e: // I-cache predecode
-    case 0x6f: // I-cache LRU etc.
-    case 0x76: // E-cache tag
-    case 0x7e: // E-cache tag
-        return;
-    case 0x51: // I-MMU 8k TSB pointer, RO
-    case 0x52: // I-MMU 64k TSB pointer, RO
-    case 0x56: // I-MMU tag read, RO
-    case 0x59: // D-MMU 8k TSB pointer, RO
-    case 0x5a: // D-MMU 64k TSB pointer, RO
-    case 0x5b: // D-MMU data pointer, RO
-    case 0x5e: // D-MMU tag read, RO
-    case 0x48: // Interrupt dispatch, RO
-    case 0x7f: // Incoming interrupt vector, RO
-    case 0x82: // Primary no-fault, RO
-    case 0x83: // Secondary no-fault, RO
-    case 0x8a: // Primary no-fault LE, RO
-    case 0x8b: // Secondary no-fault LE, RO
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-#endif /* CONFIG_USER_ONLY */
-
-void helper_ldda_asi(target_ulong addr, int asi, int rd)
-{
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-#if !defined(CONFIG_USER_ONLY)
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        helper_check_align(addr, 0xf);
-        if (rd == 0) {
-            env->gregs[1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c)
-                bswap64s(&env->gregs[1]);
-        } else if (rd < 8) {
-            env->gregs[rd] = ldq_nucleus(addr);
-            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[rd]);
-                bswap64s(&env->gregs[rd + 1]);
-            }
-        } else {
-            env->regwptr[rd] = ldq_nucleus(addr);
-            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->regwptr[rd]);
-                bswap64s(&env->regwptr[rd + 1]);
-            }
-        }
-        break;
-#endif
-    default:
-        helper_check_align(addr, 0x3);
-        if (rd == 0)
-            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        } else {
-            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        }
-        break;
-    }
-}
-
-void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    target_ulong val;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xf0: // Block load primary
-    case 0xf1: // Block load secondary
-    case 0xf8: // Block load primary LE
-    case 0xf9: // Block load secondary LE
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    case 0x70: // Block load primary, user privilege
-    case 0x71: // Block load secondary, user privilege
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x1f, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    val = helper_ld_asi(addr, asi, size, 0);
-    switch(size) {
-    default:
-    case 4:
-        *((uint32_t *)&env->fpr[rd]) = val;
-        break;
-    case 8:
-        *((int64_t *)&DT0) = val;
-        break;
-    case 16:
-        // XXX
-        break;
-    }
-}
-
-void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    target_ulong val = 0;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xe0: // UA2007 Block commit store primary (cache flush)
-    case 0xe1: // UA2007 Block commit store secondary (cache flush)
-    case 0xf0: // Block store primary
-    case 0xf1: // Block store secondary
-    case 0xf8: // Block store primary LE
-    case 0xf9: // Block store secondary LE
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x8f, 4);
-            addr += 4;
-        }
-
-        return;
-    case 0x70: // Block store primary, user privilege
-    case 0x71: // Block store secondary, user privilege
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x1f, 4);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    switch(size) {
-    default:
-    case 4:
-        val = *((uint32_t *)&env->fpr[rd]);
-        break;
-    case 8:
-        val = *((int64_t *)&DT0);
-        break;
-    case 16:
-        // XXX
-        break;
-    }
-    helper_st_asi(addr, val, asi, size);
-}
-
-target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
-                            target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(addr, asi, 4, 0);
-    ret &= 0xffffffffUL;
-    if (val2 == ret)
-        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
-    return ret;
-}
-
-target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
-                             target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    ret = helper_ld_asi(addr, asi, 8, 0);
-    if (val2 == ret)
-        helper_st_asi(addr, val1, asi, 8);
-    return ret;
-}
-#endif /* TARGET_SPARC64 */
-
-#ifndef TARGET_SPARC64
-void helper_rett(void)
-{
-    unsigned int cwp;
-
-    if (env->psret == 1)
-        raise_exception(TT_ILL_INSN);
-
-    env->psret = 1;
-    cwp = cwp_inc(env->cwp + 1) ;
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_UNF);
-    }
-    set_cwp(cwp);
-    env->psrs = env->psrps;
-}
-#endif
-
-static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    uint64_t x0;
-    uint32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        raise_exception(TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if (x0 > 0xffffffff) {
-        x0 = 0xffffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_udiv(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 0);
-}
-
-target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 1);
-}
-
-static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    int64_t x0;
-    int32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        raise_exception(TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if ((int32_t) x0 != x0) {
-        x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 0);
-}
-
-target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 1);
-}
-
-void helper_stdf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        stfq_user(addr, DT0);
-        break;
-    case MMU_KERNEL_IDX:
-        stfq_kernel(addr, DT0);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        stfq_hypv(addr, DT0);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    stfq_raw(address_mask(env, addr), DT0);
-#endif
-}
-
-void helper_lddf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        DT0 = ldfq_user(addr);
-        break;
-    case MMU_KERNEL_IDX:
-        DT0 = ldfq_kernel(addr);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        DT0 = ldfq_hypv(addr);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    DT0 = ldfq_raw(address_mask(env, addr));
-#endif
-}
-
-void helper_ldqf(target_ulong addr, int mem_idx)
-{
-    // XXX add 128 bit load
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.ll.upper = ldq_user(addr);
-        u.ll.lower = ldq_user(addr + 8);
-        QT0 = u.q;
-        break;
-    case MMU_KERNEL_IDX:
-        u.ll.upper = ldq_kernel(addr);
-        u.ll.lower = ldq_kernel(addr + 8);
-        QT0 = u.q;
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.ll.upper = ldq_hypv(addr);
-        u.ll.lower = ldq_hypv(addr + 8);
-        QT0 = u.q;
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.ll.upper = ldq_raw(address_mask(env, addr));
-    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
-    QT0 = u.q;
-#endif
-}
-
-void helper_stqf(target_ulong addr, int mem_idx)
-{
-    // XXX add 128 bit store
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.q = QT0;
-        stq_user(addr, u.ll.upper);
-        stq_user(addr + 8, u.ll.lower);
-        break;
-    case MMU_KERNEL_IDX:
-        u.q = QT0;
-        stq_kernel(addr, u.ll.upper);
-        stq_kernel(addr + 8, u.ll.lower);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.q = QT0;
-        stq_hypv(addr, u.ll.upper);
-        stq_hypv(addr + 8, u.ll.lower);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.q = QT0;
-    stq_raw(address_mask(env, addr), u.ll.upper);
-    stq_raw(address_mask(env, addr + 8), u.ll.lower);
-#endif
-}
-
-static inline void set_fsr(void)
-{
-    int rnd_mode;
-
-    switch (env->fsr & FSR_RD_MASK) {
-    case FSR_RD_NEAREST:
-        rnd_mode = float_round_nearest_even;
-        break;
-    default:
-    case FSR_RD_ZERO:
-        rnd_mode = float_round_to_zero;
-        break;
-    case FSR_RD_POS:
-        rnd_mode = float_round_up;
-        break;
-    case FSR_RD_NEG:
-        rnd_mode = float_round_down;
-        break;
-    }
-    set_float_rounding_mode(rnd_mode, &env->fp_status);
-}
-
-void helper_ldfsr(uint32_t new_fsr)
-{
-    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
-    set_fsr();
-}
-
-#ifdef TARGET_SPARC64
-void helper_ldxfsr(uint64_t new_fsr)
-{
-    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
-    set_fsr();
-}
-#endif
-
-void helper_debug(void)
-{
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit();
-}
-
-#ifndef TARGET_SPARC64
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
-   handling ? */
-void helper_save(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_dec(env->cwp - 1);
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_OVF);
-    }
-    set_cwp(cwp);
-}
-
-void helper_restore(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_inc(env->cwp + 1);
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_UNF);
-    }
-    set_cwp(cwp);
-}
-
-void helper_wrpsr(target_ulong new_psr)
-{
-    if ((new_psr & PSR_CWP) >= env->nwindows) {
-        raise_exception(TT_ILL_INSN);
-    } else {
-        cpu_put_psr(env, new_psr);
-    }
-}
-
-target_ulong helper_rdpsr(void)
-{
-    return get_psr();
-}
-
-#else
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
-   handling ? */
-void helper_save(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_dec(env->cwp - 1);
-    if (env->cansave == 0) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ?
-                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                    ((env->wstate & 0x7) << 2)));
-    } else {
-        if (env->cleanwin - env->canrestore == 0) {
-            // XXX Clean windows without trap
-            raise_exception(TT_CLRWIN);
-        } else {
-            env->cansave--;
-            env->canrestore++;
-            set_cwp(cwp);
-        }
-    }
-}
-
-void helper_restore(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_inc(env->cwp + 1);
-    if (env->canrestore == 0) {
-        raise_exception(TT_FILL | (env->otherwin != 0 ?
-                                   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                   ((env->wstate & 0x7) << 2)));
-    } else {
-        env->cansave++;
-        env->canrestore--;
-        set_cwp(cwp);
-    }
-}
-
-void helper_flushw(void)
-{
-    if (env->cansave != env->nwindows - 2) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ?
-                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                    ((env->wstate & 0x7) << 2)));
-    }
-}
-
-void helper_saved(void)
-{
-    env->cansave++;
-    if (env->otherwin == 0)
-        env->canrestore--;
-    else
-        env->otherwin--;
-}
-
-void helper_restored(void)
-{
-    env->canrestore++;
-    if (env->cleanwin < env->nwindows - 1)
-        env->cleanwin++;
-    if (env->otherwin == 0)
-        env->cansave--;
-    else
-        env->otherwin--;
-}
-
-static target_ulong get_ccr(void)
-{
-    target_ulong psr;
-
-    psr = get_psr();
-
-    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
-}
-
-target_ulong cpu_get_ccr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_ccr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_ccr(target_ulong val)
-{
-    target_ulong tmp = val;
-
-    env->xcc = (tmp >> 4) << 20;
-    env->psr = (tmp & 0xf) << 20;
-    CC_OP = CC_OP_FLAGS;
-}
-
-void cpu_put_ccr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_ccr(val);
-    env = saved_env;
-}
-
-static target_ulong get_cwp64(void)
-{
-    return env->nwindows - 1 - env->cwp;
-}
-
-target_ulong cpu_get_cwp64(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_cwp64();
-    env = saved_env;
-    return ret;
-}
-
-static void put_cwp64(int cwp)
-{
-    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
-        cwp %= env->nwindows;
-    }
-    set_cwp(env->nwindows - 1 - cwp);
-}
-
-void cpu_put_cwp64(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_cwp64(cwp);
-    env = saved_env;
-}
-
-target_ulong helper_rdccr(void)
-{
-    return get_ccr();
-}
-
-void helper_wrccr(target_ulong new_ccr)
-{
-    put_ccr(new_ccr);
-}
-
-// CWP handling is reversed in V9, but we still use the V8 register
-// order.
-target_ulong helper_rdcwp(void)
-{
-    return get_cwp64();
-}
-
-void helper_wrcwp(target_ulong new_cwp)
-{
-    put_cwp64(new_cwp);
-}
-
-// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO)                                  \
-    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
-
-// This function uses the order in the manuals, i.e. bit 0 is 2^0
-#define GET_FIELD_SP(X, FROM, TO)               \
-    GET_FIELD(X, 63 - (TO), 63 - (FROM))
-
-target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
-{
-    return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
-        (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
-        (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
-        (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
-        (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
-        (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
-        (((pixel_addr >> 55) & 1) << 4) |
-        (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
-        GET_FIELD_SP(pixel_addr, 11, 12);
-}
-
-target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
-{
-    uint64_t tmp;
-
-    tmp = addr + offset;
-    env->gsr &= ~7ULL;
-    env->gsr |= tmp & 7ULL;
-    return tmp & ~7ULL;
-}
-
-target_ulong helper_popc(target_ulong val)
-{
-    return ctpop64(val);
-}
-
-static inline uint64_t *get_gregset(uint32_t pstate)
-{
-    switch (pstate) {
-    default:
-        DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
-                pstate,
-                (pstate & PS_IG) ? " IG" : "",
-                (pstate & PS_MG) ? " MG" : "",
-                (pstate & PS_AG) ? " AG" : "");
-        /* pass through to normal set of global registers */
-    case 0:
-        return env->bgregs;
-    case PS_AG:
-        return env->agregs;
-    case PS_MG:
-        return env->mgregs;
-    case PS_IG:
-        return env->igregs;
-    }
-}
-
-static inline void change_pstate(uint32_t new_pstate)
-{
-    uint32_t pstate_regs, new_pstate_regs;
-    uint64_t *src, *dst;
-
-    if (env->def->features & CPU_FEATURE_GL) {
-        // PS_AG is not implemented in this case
-        new_pstate &= ~PS_AG;
-    }
-
-    pstate_regs = env->pstate & 0xc01;
-    new_pstate_regs = new_pstate & 0xc01;
-
-    if (new_pstate_regs != pstate_regs) {
-        DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
-                       pstate_regs, new_pstate_regs);
-        // Switch global register bank
-        src = get_gregset(new_pstate_regs);
-        dst = get_gregset(pstate_regs);
-        memcpy32(dst, env->gregs);
-        memcpy32(env->gregs, src);
-    }
-    else {
-        DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
-                       new_pstate_regs);
-    }
-    env->pstate = new_pstate;
-}
-
-void helper_wrpstate(target_ulong new_state)
-{
-    change_pstate(new_state & 0xf3f);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void helper_wrpil(target_ulong new_pil)
-{
-#if !defined(CONFIG_USER_ONLY)
-    DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
-                   env->psrpil, (uint32_t)new_pil);
-
-    env->psrpil = new_pil;
-
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void helper_done(void)
-{
-    trap_state* tsptr = cpu_tsptr(env);
-
-    env->pc = tsptr->tnpc;
-    env->npc = tsptr->tnpc + 4;
-    put_ccr(tsptr->tstate >> 32);
-    env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
-    env->tl--;
-
-    DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void helper_retry(void)
-{
-    trap_state* tsptr = cpu_tsptr(env);
-
-    env->pc = tsptr->tpc;
-    env->npc = tsptr->tnpc;
-    put_ccr(tsptr->tstate >> 32);
-    env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
-    env->tl--;
-
-    DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-static void do_modify_softint(const char* operation, uint32_t value)
-{
-    if (env->softint != value) {
-        env->softint = value;
-        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
-#if !defined(CONFIG_USER_ONLY)
-        if (cpu_interrupts_enabled(env)) {
-            cpu_check_irqs(env);
-        }
-#endif
-    }
-}
-
-void helper_set_softint(uint64_t value)
-{
-    do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
-}
-
-void helper_clear_softint(uint64_t value)
-{
-    do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
-}
-
-void helper_write_softint(uint64_t value)
-{
-    do_modify_softint("helper_write_softint", (uint32_t)value);
-}
-#endif
-
-void helper_flush(target_ulong addr)
-{
-    addr &= ~7;
-    tb_invalidate_page_range(addr, addr + 8);
-}
-
-#ifdef TARGET_SPARC64
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
-    [TT_TFAULT] = "Instruction Access Fault",
-    [TT_TMISS] = "Instruction Access MMU Miss",
-    [TT_CODE_ACCESS] = "Instruction Access Error",
-    [TT_ILL_INSN] = "Illegal Instruction",
-    [TT_PRIV_INSN] = "Privileged Instruction",
-    [TT_NFPU_INSN] = "FPU Disabled",
-    [TT_FP_EXCP] = "FPU Exception",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_CLRWIN] = "Clean Windows",
-    [TT_DIV_ZERO] = "Division By Zero",
-    [TT_DFAULT] = "Data Access Fault",
-    [TT_DMISS] = "Data Access MMU Miss",
-    [TT_DATA_ACCESS] = "Data Access Error",
-    [TT_DPROT] = "Data Protection Error",
-    [TT_UNALIGNED] = "Unaligned Memory Access",
-    [TT_PRIV_ACT] = "Privileged Action",
-    [TT_EXTINT | 0x1] = "External Interrupt 1",
-    [TT_EXTINT | 0x2] = "External Interrupt 2",
-    [TT_EXTINT | 0x3] = "External Interrupt 3",
-    [TT_EXTINT | 0x4] = "External Interrupt 4",
-    [TT_EXTINT | 0x5] = "External Interrupt 5",
-    [TT_EXTINT | 0x6] = "External Interrupt 6",
-    [TT_EXTINT | 0x7] = "External Interrupt 7",
-    [TT_EXTINT | 0x8] = "External Interrupt 8",
-    [TT_EXTINT | 0x9] = "External Interrupt 9",
-    [TT_EXTINT | 0xa] = "External Interrupt 10",
-    [TT_EXTINT | 0xb] = "External Interrupt 11",
-    [TT_EXTINT | 0xc] = "External Interrupt 12",
-    [TT_EXTINT | 0xd] = "External Interrupt 13",
-    [TT_EXTINT | 0xe] = "External Interrupt 14",
-    [TT_EXTINT | 0xf] = "External Interrupt 15",
-};
-#endif
-
-trap_state* cpu_tsptr(CPUState* env)
-{
-    return &env->ts[env->tl & MAXTL_MASK];
-}
-
-void do_interrupt(CPUState *env)
-{
-    int intno = env->exception_index;
-    trap_state* tsptr;
-
-#ifdef DEBUG_PCALL
-    if (qemu_loglevel_mask(CPU_LOG_INT)) {
-        static int count;
-        const char *name;
-
-        if (intno < 0 || intno >= 0x180)
-            name = "Unknown";
-        else if (intno >= 0x100)
-            name = "Trap Instruction";
-        else if (intno >= 0xc0)
-            name = "Window Fill";
-        else if (intno >= 0x80)
-            name = "Window Spill";
-        else {
-            name = excp_names[intno];
-            if (!name)
-                name = "Unknown";
-        }
-
-        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
-                " SP=%016" PRIx64 "\n",
-                count, name, intno,
-                env->pc,
-                env->npc, env->regwptr[6]);
-        log_cpu_state(env, 0);
-#if 0
-        {
-            int i;
-            uint8_t *ptr;
-
-            qemu_log("       code=");
-            ptr = (uint8_t *)env->pc;
-            for(i = 0; i < 16; i++) {
-                qemu_log(" %02x", ldub(ptr + i));
-            }
-            qemu_log("\n");
-        }
-#endif
-        count++;
-    }
-#endif
-#if !defined(CONFIG_USER_ONLY)
-    if (env->tl >= env->maxtl) {
-        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
-                  " Error state", env->exception_index, env->tl, env->maxtl);
-        return;
-    }
-#endif
-    if (env->tl < env->maxtl - 1) {
-        env->tl++;
-    } else {
-        env->pstate |= PS_RED;
-        if (env->tl < env->maxtl)
-            env->tl++;
-    }
-    tsptr = cpu_tsptr(env);
-
-    tsptr->tstate = (get_ccr() << 32) |
-        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
-        get_cwp64();
-    tsptr->tpc = env->pc;
-    tsptr->tnpc = env->npc;
-    tsptr->tt = intno;
-
-    switch (intno) {
-    case TT_IVEC:
-        change_pstate(PS_PEF | PS_PRIV | PS_IG);
-        break;
-    case TT_TFAULT:
-    case TT_DFAULT:
-    case TT_TMISS ... TT_TMISS + 3:
-    case TT_DMISS ... TT_DMISS + 3:
-    case TT_DPROT ... TT_DPROT + 3:
-        change_pstate(PS_PEF | PS_PRIV | PS_MG);
-        break;
-    default:
-        change_pstate(PS_PEF | PS_PRIV | PS_AG);
-        break;
-    }
-
-    if (intno == TT_CLRWIN) {
-        set_cwp(cwp_dec(env->cwp - 1));
-    } else if ((intno & 0x1c0) == TT_SPILL) {
-        set_cwp(cwp_dec(env->cwp - env->cansave - 2));
-    } else if ((intno & 0x1c0) == TT_FILL) {
-        set_cwp(cwp_inc(env->cwp + 1));
-    }
-    env->tbr &= ~0x7fffULL;
-    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
-    env->pc = env->tbr;
-    env->npc = env->pc + 4;
-    env->exception_index = -1;
-}
-#else
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
-    [TT_TFAULT] = "Instruction Access Fault",
-    [TT_ILL_INSN] = "Illegal Instruction",
-    [TT_PRIV_INSN] = "Privileged Instruction",
-    [TT_NFPU_INSN] = "FPU Disabled",
-    [TT_WIN_OVF] = "Window Overflow",
-    [TT_WIN_UNF] = "Window Underflow",
-    [TT_UNALIGNED] = "Unaligned Memory Access",
-    [TT_FP_EXCP] = "FPU Exception",
-    [TT_DFAULT] = "Data Access Fault",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_EXTINT | 0x1] = "External Interrupt 1",
-    [TT_EXTINT | 0x2] = "External Interrupt 2",
-    [TT_EXTINT | 0x3] = "External Interrupt 3",
-    [TT_EXTINT | 0x4] = "External Interrupt 4",
-    [TT_EXTINT | 0x5] = "External Interrupt 5",
-    [TT_EXTINT | 0x6] = "External Interrupt 6",
-    [TT_EXTINT | 0x7] = "External Interrupt 7",
-    [TT_EXTINT | 0x8] = "External Interrupt 8",
-    [TT_EXTINT | 0x9] = "External Interrupt 9",
-    [TT_EXTINT | 0xa] = "External Interrupt 10",
-    [TT_EXTINT | 0xb] = "External Interrupt 11",
-    [TT_EXTINT | 0xc] = "External Interrupt 12",
-    [TT_EXTINT | 0xd] = "External Interrupt 13",
-    [TT_EXTINT | 0xe] = "External Interrupt 14",
-    [TT_EXTINT | 0xf] = "External Interrupt 15",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_CODE_ACCESS] = "Instruction Access Error",
-    [TT_DATA_ACCESS] = "Data Access Error",
-    [TT_DIV_ZERO] = "Division By Zero",
-    [TT_NCP_INSN] = "Coprocessor Disabled",
-};
-#endif
-
-void do_interrupt(CPUState *env)
-{
-    int cwp, intno = env->exception_index;
-
-#ifdef DEBUG_PCALL
-    if (qemu_loglevel_mask(CPU_LOG_INT)) {
-        static int count;
-        const char *name;
-
-        if (intno < 0 || intno >= 0x100)
-            name = "Unknown";
-        else if (intno >= 0x80)
-            name = "Trap Instruction";
-        else {
-            name = excp_names[intno];
-            if (!name)
-                name = "Unknown";
-        }
-
-        qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
-                count, name, intno,
-                env->pc,
-                env->npc, env->regwptr[6]);
-        log_cpu_state(env, 0);
-#if 0
-        {
-            int i;
-            uint8_t *ptr;
-
-            qemu_log("       code=");
-            ptr = (uint8_t *)env->pc;
-            for(i = 0; i < 16; i++) {
-                qemu_log(" %02x", ldub(ptr + i));
-            }
-            qemu_log("\n");
-        }
-#endif
-        count++;
-    }
-#endif
-#if !defined(CONFIG_USER_ONLY)
-    if (env->psret == 0) {
-        cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
-                  env->exception_index);
-        return;
-    }
-#endif
-    env->psret = 0;
-    cwp = cwp_dec(env->cwp - 1);
-    set_cwp(cwp);
-    env->regwptr[9] = env->pc;
-    env->regwptr[10] = env->npc;
-    env->psrps = env->psrs;
-    env->psrs = 1;
-    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
-    env->pc = env->tbr;
-    env->npc = env->pc + 4;
-    env->exception_index = -1;
 
 #if !defined(CONFIG_USER_ONLY)
-    /* IRQ acknowledgment */
-    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
-        env->qemu_irq_ack(env->irq_manager, intno);
-    }
-#endif
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-
 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
                                 void *retaddr);
 
@@ -4375,7 +34,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);
         }
     }
 }
@@ -4388,148 +47,28 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
            "\n", addr, env->pc);
 #endif
     cpu_restore_state2(retaddr);
-    raise_exception(TT_UNALIGNED);
+    helper_raise_exception(env, TT_UNALIGNED);
 }
 
 /* try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     int ret;
     CPUState *saved_env;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
-    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         cpu_restore_state2(retaddr);
-        cpu_loop_exit();
+        cpu_loop_exit(env);
     }
     env = saved_env;
 }
 
 #endif /* !CONFIG_USER_ONLY */
-
-#ifndef TARGET_SPARC64
-#if !defined(CONFIG_USER_ONLY)
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size)
-{
-    CPUState *saved_env;
-    int fault_type;
-
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
-#ifdef DEBUG_UNASSIGNED
-    if (is_asi)
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " asi 0x%02x from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, is_asi, env->pc);
-    else
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, env->pc);
-#endif
-    /* Don't overwrite translation and access faults */
-    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
-    if ((fault_type > 4) || (fault_type == 0)) {
-        env->mmuregs[3] = 0; /* Fault status register */
-        if (is_asi)
-            env->mmuregs[3] |= 1 << 16;
-        if (env->psrs)
-            env->mmuregs[3] |= 1 << 5;
-        if (is_exec)
-            env->mmuregs[3] |= 1 << 6;
-        if (is_write)
-            env->mmuregs[3] |= 1 << 7;
-        env->mmuregs[3] |= (5 << 2) | 2;
-        /* SuperSPARC will never place instruction fault addresses in the FAR */
-        if (!is_exec) {
-            env->mmuregs[4] = addr; /* Fault address register */
-        }
-    }
-    /* overflow (same type fault was not read before another fault) */
-    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
-        env->mmuregs[3] |= 1;
-    }
-
-    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
-        if (is_exec)
-            raise_exception(TT_CODE_ACCESS);
-        else
-            raise_exception(TT_DATA_ACCESS);
-    }
-
-    /* flush neverland mappings created during no-fault mode,
-       so the sequential MMU faults report proper fault types */
-    if (env->mmuregs[0] & MMU_NF) {
-        tlb_flush(env, 1);
-    }
-
-    env = saved_env;
-}
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                          int is_asi, int size)
-#else
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int is_asi, int size)
-#endif
-{
-    CPUState *saved_env;
-
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
-
-#ifdef DEBUG_UNASSIGNED
-    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-
-    if (is_exec)
-        raise_exception(TT_CODE_ACCESS);
-    else
-        raise_exception(TT_DATA_ACCESS);
-
-    env = saved_env;
-}
-#endif
-
-
-#ifdef TARGET_SPARC64
-void helper_tick_set_count(void *opaque, uint64_t count)
-{
-#if !defined(CONFIG_USER_ONLY)
-    cpu_tick_set_count(opaque, count);
-#endif
-}
-
-uint64_t helper_tick_get_count(void *opaque)
-{
-#if !defined(CONFIG_USER_ONLY)
-    return cpu_tick_get_count(opaque);
-#else
-    return 0;
-#endif
-}
-
-void helper_tick_set_limit(void *opaque, uint64_t limit)
-{
-#if !defined(CONFIG_USER_ONLY)
-    cpu_tick_set_limit(opaque, limit);
-#endif
-}
-#endif
index e26462eef5895306b08f7e5d9b300d1817896fd1..d26111209e388dee20f21e174db7b298a85d1171 100644 (file)
@@ -25,7 +25,6 @@
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "helper.h"
 #include "tcg-op.h"
@@ -64,7 +63,7 @@ static TCGv cpu_tmp0;
 static TCGv_i32 cpu_tmp32;
 static TCGv_i64 cpu_tmp64;
 /* Floating point registers */
-static TCGv_i32 cpu_fpr[TARGET_FPREGS];
+static TCGv_i64 cpu_fpr[TARGET_DPREGS];
 
 static target_ulong gen_opc_npc[OPC_BUF_SIZE];
 static target_ulong gen_opc_jump_pc[2];
@@ -83,6 +82,8 @@ typedef struct DisasContext {
     uint32_t cc_op;  /* current CC operation */
     struct TranslationBlock *tb;
     sparc_def_t *def;
+    TCGv_i32 t32[3];
+    int n_t32;
 } DisasContext;
 
 // This function uses non-native bit order
@@ -115,67 +116,116 @@ static int sign_extend(int x, int len)
 
 #define IS_IMM (insn & (1<<13))
 
+static inline void gen_update_fprs_dirty(int rd)
+{
+#if defined(TARGET_SPARC64)
+    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
+#endif
+}
+
 /* floating point registers moves */
-static void gen_op_load_fpr_DT0(unsigned int src)
+static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
+{
+#if TCG_TARGET_REG_BITS == 32
+    if (src & 1) {
+        return TCGV_LOW(cpu_fpr[src / 2]);
+    } else {
+        return TCGV_HIGH(cpu_fpr[src / 2]);
+    }
+#else
+    if (src & 1) {
+        return MAKE_TCGV_I32(GET_TCGV_I64(cpu_fpr[src / 2]));
+    } else {
+        TCGv_i32 ret = tcg_temp_local_new_i32();
+        TCGv_i64 t = tcg_temp_new_i64();
+
+        tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32);
+        tcg_gen_trunc_i64_i32(ret, t);
+        tcg_temp_free_i64(t);
+
+        dc->t32[dc->n_t32++] = ret;
+        assert(dc->n_t32 <= ARRAY_SIZE(dc->t32));
+
+        return ret;
+    }
+#endif
+}
+
+static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
+{
+#if TCG_TARGET_REG_BITS == 32
+    if (dst & 1) {
+        tcg_gen_mov_i32(TCGV_LOW(cpu_fpr[dst / 2]), v);
+    } else {
+        tcg_gen_mov_i32(TCGV_HIGH(cpu_fpr[dst / 2]), v);
+    }
+#else
+    TCGv_i64 t = MAKE_TCGV_I64(GET_TCGV_I32(v));
+    tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t,
+                        (dst & 1 ? 0 : 32), 32);
+#endif
+    gen_update_fprs_dirty(dst);
+}
+
+static TCGv_i32 gen_dest_fpr_F(void)
+{
+    return cpu_tmp32;
+}
+
+static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.lower));
+    src = DFPREG(src);
+    return cpu_fpr[src / 2];
 }
 
-static void gen_op_load_fpr_DT1(unsigned int src)
+static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) +
-                   offsetof(CPU_DoubleU, l.lower));
+    dst = DFPREG(dst);
+    tcg_gen_mov_i64(cpu_fpr[dst / 2], v);
+    gen_update_fprs_dirty(dst);
 }
 
-static void gen_op_store_DT0_fpr(unsigned int dst)
+static TCGv_i64 gen_dest_fpr_D(void)
 {
-    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.lower));
+    return cpu_tmp64;
 }
 
 static void gen_op_load_fpr_QT0(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
 static void gen_op_load_fpr_QT1(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
 static void gen_op_store_QT0_fpr(unsigned int dst)
 {
-    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_ld_i64(cpu_fpr[dst / 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
+#ifdef TARGET_SPARC64
+static void gen_move_Q(unsigned int rd, unsigned int rs)
+{
+    rd = QFPREG(rd);
+    rs = QFPREG(rs);
+
+    tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
+    tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
+    gen_update_fprs_dirty(rd);
+}
+#endif
+
 /* moves */
 #ifdef CONFIG_USER_ONLY
 #define supervisor(dc) 0
@@ -241,7 +291,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);
@@ -295,7 +345,7 @@ static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
     tcg_temp_free(r_temp);
@@ -311,7 +361,7 @@ static inline void gen_tag_tv(TCGv src1, TCGv src2)
     tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3);
     tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
 }
@@ -429,7 +479,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
     default:
         /* We need external help to produce the carry.  */
         carry_32 = tcg_temp_new_i32();
-        gen_helper_compute_C_icc(carry_32);
+        gen_helper_compute_C_icc(carry_32, cpu_env);
         break;
     }
 
@@ -493,7 +543,7 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
     tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
     tcg_temp_free(r_temp);
@@ -568,7 +618,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
     default:
         /* We need external help to produce the carry.  */
         carry_32 = tcg_temp_new_i32();
-        gen_helper_compute_C_icc(carry_32);
+        gen_helper_compute_C_icc(carry_32, cpu_env);
         break;
     }
 
@@ -720,7 +770,7 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor)
     l1 = gen_new_label();
     tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1);
     r_const = tcg_const_i32(TT_DIV_ZERO);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
 }
@@ -728,19 +778,24 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor)
 static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
 {
     int l1, l2;
+    TCGv r_temp1, r_temp2;
 
     l1 = gen_new_label();
     l2 = gen_new_label();
-    tcg_gen_mov_tl(cpu_cc_src, src1);
-    tcg_gen_mov_tl(cpu_cc_src2, src2);
-    gen_trap_ifdivzero_tl(cpu_cc_src2);
-    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src, INT64_MIN, l1);
-    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src2, -1, l1);
+    r_temp1 = tcg_temp_local_new();
+    r_temp2 = tcg_temp_local_new();
+    tcg_gen_mov_tl(r_temp1, src1);
+    tcg_gen_mov_tl(r_temp2, src2);
+    gen_trap_ifdivzero_tl(r_temp2);
+    tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1);
+    tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1);
     tcg_gen_movi_i64(dst, INT64_MIN);
     tcg_gen_br(l2);
     gen_set_label(l1);
-    tcg_gen_div_i64(dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_div_i64(dst, r_temp1, r_temp2);
     gen_set_label(l2);
+    tcg_temp_free(r_temp1);
+    tcg_temp_free(r_temp2);
 }
 #endif
 
@@ -1087,7 +1142,7 @@ static inline void save_state(DisasContext *dc, TCGv cond)
     /* flush pending conditional evaluations before exposing cpu state */
     if (dc->cc_op != CC_OP_FLAGS) {
         dc->cc_op = CC_OP_FLAGS;
-        gen_helper_compute_psr();
+        gen_helper_compute_psr(cpu_env);
     }
     save_npc(dc, cond);
 }
@@ -1129,7 +1184,7 @@ static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond,
     case CC_OP_FLAGS:
         break;
     default:
-        gen_helper_compute_psr();
+        gen_helper_compute_psr(cpu_env);
         dc->cc_op = CC_OP_FLAGS;
         break;
     }
@@ -1282,7 +1337,6 @@ static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src)
 }
 #endif
 
-/* XXX: potentially incorrect if dynamic npc */
 static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
                       TCGv r_cond)
 {
@@ -1317,13 +1371,17 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
         } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
-            dc->jump_pc[1] = dc->npc + 4;
-            dc->npc = JUMP_PC;
+            if (unlikely(dc->npc == DYNAMIC_PC)) {
+                dc->jump_pc[1] = DYNAMIC_PC;
+                tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+            } else {
+                dc->jump_pc[1] = dc->npc + 4;
+                dc->npc = JUMP_PC;
+            }
         }
     }
 }
 
-/* XXX: potentially incorrect if dynamic npc */
 static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
                       TCGv r_cond)
 {
@@ -1358,14 +1416,18 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
         } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
-            dc->jump_pc[1] = dc->npc + 4;
-            dc->npc = JUMP_PC;
+            if (unlikely(dc->npc == DYNAMIC_PC)) {
+                dc->jump_pc[1] = DYNAMIC_PC;
+                tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+            } else {
+                dc->jump_pc[1] = dc->npc + 4;
+                dc->npc = JUMP_PC;
+            }
         }
     }
 }
 
 #ifdef TARGET_SPARC64
-/* XXX: potentially incorrect if dynamic npc */
 static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
                           TCGv r_cond, TCGv r_reg)
 {
@@ -1380,8 +1442,13 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
     } else {
         dc->pc = dc->npc;
         dc->jump_pc[0] = target;
-        dc->jump_pc[1] = dc->npc + 4;
-        dc->npc = JUMP_PC;
+        if (unlikely(dc->npc == DYNAMIC_PC)) {
+            dc->jump_pc[1] = DYNAMIC_PC;
+            tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+        } else {
+            dc->jump_pc[1] = dc->npc + 4;
+            dc->npc = JUMP_PC;
+        }
     }
 }
 
@@ -1389,34 +1456,34 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmps(r_rs1, r_rs2);
+        gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmps_fcc1(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmps_fcc2(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmps_fcc3(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
 
-static inline void gen_op_fcmpd(int fccno)
+static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpd();
+        gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpd_fcc1();
+        gen_helper_fcmpd_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpd_fcc2();
+        gen_helper_fcmpd_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpd_fcc3();
+        gen_helper_fcmpd_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1425,16 +1492,16 @@ static inline void gen_op_fcmpq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpq();
+        gen_helper_fcmpq(cpu_env);
         break;
     case 1:
-        gen_helper_fcmpq_fcc1();
+        gen_helper_fcmpq_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmpq_fcc2();
+        gen_helper_fcmpq_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmpq_fcc3();
+        gen_helper_fcmpq_fcc3(cpu_env);
         break;
     }
 }
@@ -1443,34 +1510,34 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpes(r_rs1, r_rs2);
+        gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpes_fcc1(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpes_fcc2(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpes_fcc3(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
 
-static inline void gen_op_fcmped(int fccno)
+static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmped();
+        gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmped_fcc1();
+        gen_helper_fcmped_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmped_fcc2();
+        gen_helper_fcmped_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmped_fcc3();
+        gen_helper_fcmped_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1479,16 +1546,16 @@ static inline void gen_op_fcmpeq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpeq();
+        gen_helper_fcmpeq(cpu_env);
         break;
     case 1:
-        gen_helper_fcmpeq_fcc1();
+        gen_helper_fcmpeq_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmpeq_fcc2();
+        gen_helper_fcmpeq_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmpeq_fcc3();
+        gen_helper_fcmpeq_fcc3(cpu_env);
         break;
     }
 }
@@ -1497,32 +1564,32 @@ static inline void gen_op_fcmpeq(int fccno)
 
 static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmps(r_rs1, r_rs2);
+    gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
 }
 
-static inline void gen_op_fcmpd(int fccno)
+static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmpd();
+    gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpq(int fccno)
 {
-    gen_helper_fcmpq();
+    gen_helper_fcmpq(cpu_env);
 }
 
 static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmpes(r_rs1, r_rs2);
+    gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
 }
 
-static inline void gen_op_fcmped(int fccno)
+static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmped();
+    gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpeq(int fccno)
 {
-    gen_helper_fcmpeq();
+    gen_helper_fcmpeq(cpu_env);
 }
 #endif
 
@@ -1533,7 +1600,7 @@ static inline void gen_op_fpexception_im(int fsr_flags)
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
     tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
     r_const = tcg_const_i32(TT_FP_EXCP);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
 }
 
@@ -1545,7 +1612,7 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
 
         save_state(dc, r_cond);
         r_const = tcg_const_i32(TT_NFPU_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
         return 1;
@@ -1559,9 +1626,308 @@ static inline void gen_op_clear_ieee_excp_and_FTT(void)
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
 }
 
-static inline void gen_clear_float_exceptions(void)
+static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i32 dst, src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, src);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src1, src2;
+
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+                                  void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src1, src2;
+
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, src1, src2);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64))
+{
+    TCGv_i64 dst, src;
+
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src;
+
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                                  void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                           void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_gsr, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
+                           void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src0, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    src0 = gen_load_fpr_D(dc, rd);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src0, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_ptr))
+{
+    gen_op_load_fpr_QT1(QFPREG(rs));
+
+    gen(cpu_env);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr))
+{
+    gen_op_load_fpr_QT1(QFPREG(rs));
+
+    gen(cpu_env);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+#endif
+
+static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
+                               void (*gen)(TCGv_ptr))
+{
+    gen_op_load_fpr_QT0(QFPREG(rs1));
+    gen_op_load_fpr_QT1(QFPREG(rs2));
+
+    gen(cpu_env);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src1, src2;
+
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
+                               void (*gen)(TCGv_ptr, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+
+    gen(cpu_env, src1, src2);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i64))
+{
+    TCGv_i32 dst;
+    TCGv_i64 src;
+
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr))
+{
+    TCGv_i32 dst;
+
+    gen_op_load_fpr_QT1(QFPREG(rs));
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr))
+{
+    TCGv_i64 dst;
+
+    gen_op_load_fpr_QT1(QFPREG(rs));
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr, TCGv_i32))
+{
+    TCGv_i32 src;
+
+    src = gen_load_fpr_F(dc, rs);
+
+    gen(cpu_env, src);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr, TCGv_i64))
 {
-    gen_helper_clear_float_exceptions();
+    TCGv_i64 src;
+
+    src = gen_load_fpr_D(dc, rs);
+
+    gen(cpu_env, src);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
 }
 
 /* asi moves */
@@ -1855,6 +2221,148 @@ static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
 
     tcg_temp_free_i32(r_tl);
 }
+
+static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2,
+                     int width, bool cc, bool left)
+{
+    TCGv lo1, lo2, t1, t2;
+    uint64_t amask, tabl, tabr;
+    int shift, imask, omask;
+
+    if (cc) {
+        tcg_gen_mov_tl(cpu_cc_src, s1);
+        tcg_gen_mov_tl(cpu_cc_src2, s2);
+        tcg_gen_sub_tl(cpu_cc_dst, s1, s2);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
+        dc->cc_op = CC_OP_SUB;
+    }
+
+    /* Theory of operation: there are two tables, left and right (not to
+       be confused with the left and right versions of the opcode).  These
+       are indexed by the low 3 bits of the inputs.  To make things "easy",
+       these tables are loaded into two constants, TABL and TABR below.
+       The operation index = (input & imask) << shift calculates the index
+       into the constant, while val = (table >> index) & omask calculates
+       the value we're looking for.  */
+    switch (width) {
+    case 8:
+        imask = 0x7;
+        shift = 3;
+        omask = 0xff;
+        if (left) {
+            tabl = 0x80c0e0f0f8fcfeffULL;
+            tabr = 0xff7f3f1f0f070301ULL;
+        } else {
+            tabl = 0x0103070f1f3f7fffULL;
+            tabr = 0xfffefcf8f0e0c080ULL;
+        }
+        break;
+    case 16:
+        imask = 0x6;
+        shift = 1;
+        omask = 0xf;
+        if (left) {
+            tabl = 0x8cef;
+            tabr = 0xf731;
+        } else {
+            tabl = 0x137f;
+            tabr = 0xfec8;
+        }
+        break;
+    case 32:
+        imask = 0x4;
+        shift = 0;
+        omask = 0x3;
+        if (left) {
+            tabl = (2 << 2) | 3;
+            tabr = (3 << 2) | 1;
+        } else {
+            tabl = (1 << 2) | 3;
+            tabr = (3 << 2) | 2;
+        }
+        break;
+    default:
+        abort();
+    }
+
+    lo1 = tcg_temp_new();
+    lo2 = tcg_temp_new();
+    tcg_gen_andi_tl(lo1, s1, imask);
+    tcg_gen_andi_tl(lo2, s2, imask);
+    tcg_gen_shli_tl(lo1, lo1, shift);
+    tcg_gen_shli_tl(lo2, lo2, shift);
+
+    t1 = tcg_const_tl(tabl);
+    t2 = tcg_const_tl(tabr);
+    tcg_gen_shr_tl(lo1, t1, lo1);
+    tcg_gen_shr_tl(lo2, t2, lo2);
+    tcg_gen_andi_tl(dst, lo1, omask);
+    tcg_gen_andi_tl(lo2, lo2, omask);
+
+    amask = -8;
+    if (AM_CHECK(dc)) {
+        amask &= 0xffffffffULL;
+    }
+    tcg_gen_andi_tl(s1, s1, amask);
+    tcg_gen_andi_tl(s2, s2, amask);
+
+    /* We want to compute
+        dst = (s1 == s2 ? lo1 : lo1 & lo2).
+       We've already done dst = lo1, so this reduces to
+        dst &= (s1 == s2 ? -1 : lo2)
+       Which we perform by
+        lo2 |= -(s1 == s2)
+        dst &= lo2
+    */
+    tcg_gen_setcond_tl(TCG_COND_EQ, t1, s1, s2);
+    tcg_gen_neg_tl(t1, t1);
+    tcg_gen_or_tl(lo2, lo2, t1);
+    tcg_gen_and_tl(dst, dst, lo2);
+
+    tcg_temp_free(lo1);
+    tcg_temp_free(lo2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+}
+
+static void gen_alignaddr(TCGv dst, TCGv s1, TCGv s2, bool left)
+{
+    TCGv tmp = tcg_temp_new();
+
+    tcg_gen_add_tl(tmp, s1, s2);
+    tcg_gen_andi_tl(dst, tmp, -8);
+    if (left) {
+        tcg_gen_neg_tl(tmp, tmp);
+    }
+    tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
+
+    tcg_temp_free(tmp);
+}
+
+static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
+{
+    TCGv t1, t2, shift;
+
+    t1 = tcg_temp_new();
+    t2 = tcg_temp_new();
+    shift = tcg_temp_new();
+
+    tcg_gen_andi_tl(shift, gsr, 7);
+    tcg_gen_shli_tl(shift, shift, 3);
+    tcg_gen_shl_tl(t1, s1, shift);
+
+    /* A shift of 64 does not produce 0 in TCG.  Divide this into a
+       shift of (up to 63) followed by a constant shift of 1.  */
+    tcg_gen_xori_tl(shift, shift, 63);
+    tcg_gen_shr_tl(t2, s2, shift);
+    tcg_gen_shri_tl(t2, t2, 1);
+
+    tcg_gen_or_tl(dst, t1, t2);
+
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(shift);
+}
 #endif
 
 #define CHECK_IU_FEATURE(dc, FEATURE)                      \
@@ -1869,6 +2377,8 @@ static void disas_sparc_insn(DisasContext * dc)
 {
     unsigned int insn, opc, rs1, rs2, rd;
     TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2;
+    TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32;
+    TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64;
     target_long simm;
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
@@ -1893,7 +2403,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     int cc;
 
                     target = GET_FIELD_SP(insn, 0, 18);
-                    target = sign_extend(target, 18);
+                    target = sign_extend(target, 19);
                     target <<= 2;
                     cc = GET_FIELD_SP(insn, 20, 21);
                     if (cc == 0)
@@ -2008,15 +2518,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
+                    gen_helper_raise_exception(cpu_env, cpu_tmp32);
 
-                    if (rs2 == 0 &&
-                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
-
-                        gen_helper_shutdown();
-
-                    } else {
-                        gen_helper_raise_exception(cpu_tmp32);
-                    }
                 } else if (cond != 0) {
                     TCGv r_cond = tcg_temp_new();
                     int l1;
@@ -2045,7 +2548,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
-                    gen_helper_raise_exception(cpu_tmp32);
+                    gen_helper_raise_exception(cpu_env, cpu_tmp32);
 
                     gen_set_label(l1);
                     tcg_temp_free(r_cond);
@@ -2083,8 +2586,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 rdccr */
-                    gen_helper_compute_psr();
-                    gen_helper_rdccr(cpu_dst);
+                    gen_helper_compute_psr(cpu_env);
+                    gen_helper_rdccr(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3: /* V9 rdasi */
@@ -2159,9 +2662,9 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifndef TARGET_SPARC64
                 if (!supervisor(dc))
                     goto priv_insn;
-                gen_helper_compute_psr();
+                gen_helper_compute_psr(cpu_env);
                 dc->cc_op = CC_OP_FLAGS;
-                gen_helper_rdpsr(cpu_dst);
+                gen_helper_rdpsr(cpu_dst, cpu_env);
 #else
                 CHECK_IU_FEATURE(dc, HYPV);
                 if (!hypervisor(dc))
@@ -2274,7 +2777,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
                     break;
                 case 9: // cwp
-                    gen_helper_rdcwp(cpu_tmp0);
+                    gen_helper_rdcwp(cpu_tmp0, cpu_env);
                     break;
                 case 10: // cansave
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
@@ -2328,7 +2831,7 @@ static void disas_sparc_insn(DisasContext * dc)
             } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
 #ifdef TARGET_SPARC64
                 save_state(dc, cpu_cond);
-                gen_helper_flushw();
+                gen_helper_flushw(cpu_env);
 #else
                 if (!supervisor(dc))
                     goto priv_insn;
@@ -2346,302 +2849,162 @@ static void disas_sparc_insn(DisasContext * dc)
                 save_state(dc, cpu_cond);
                 switch (xop) {
                 case 0x1: /* fmovs */
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     break;
                 case 0x5: /* fnegs */
-                    gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_ne_fop_FF(dc, rd, rs2, gen_helper_fnegs);
                     break;
                 case 0x9: /* fabss */
-                    gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_ne_fop_FF(dc, rd, rs2, gen_helper_fabss);
                     break;
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
-                    gen_clear_float_exceptions();
-                    gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fsqrts);
                     break;
                 case 0x2a: /* fsqrtd */
                     CHECK_FPU_FEATURE(dc, FSQRT);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsqrtd();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fsqrtd);
                     break;
                 case 0x2b: /* fsqrtq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsqrtq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QQ(dc, rd, rs2, gen_helper_fsqrtq);
                     break;
                 case 0x41: /* fadds */
-                    gen_clear_float_exceptions();
-                    gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fadds);
                     break;
                 case 0x42: /* faddd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_faddd();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_faddd);
                     break;
                 case 0x43: /* faddq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_faddq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_faddq);
                     break;
                 case 0x45: /* fsubs */
-                    gen_clear_float_exceptions();
-                    gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fsubs);
                     break;
                 case 0x46: /* fsubd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsubd();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fsubd);
                     break;
                 case 0x47: /* fsubq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsubq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fsubq);
                     break;
                 case 0x49: /* fmuls */
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_clear_float_exceptions();
-                    gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fmuls);
                     break;
                 case 0x4a: /* fmuld */
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fmuld();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld);
                     break;
                 case 0x4b: /* fmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fmulq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fmulq);
                     break;
                 case 0x4d: /* fdivs */
-                    gen_clear_float_exceptions();
-                    gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fdivs);
                     break;
                 case 0x4e: /* fdivd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdivd();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fdivd);
                     break;
                 case 0x4f: /* fdivq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdivq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fdivq);
                     break;
                 case 0x69: /* fsmuld */
                     CHECK_FPU_FEATURE(dc, FSMULD);
-                    gen_clear_float_exceptions();
-                    gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DFF(dc, rd, rs1, rs2, gen_helper_fsmuld);
                     break;
                 case 0x6e: /* fdmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdmulq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_fop_QDD(dc, rd, rs1, rs2, gen_helper_fdmulq);
                     break;
                 case 0xc4: /* fitos */
-                    gen_clear_float_exceptions();
-                    gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fitos);
                     break;
                 case 0xc6: /* fdtos */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fdtos);
                     break;
                 case 0xc7: /* fqtos */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fqtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FQ(dc, rd, rs2, gen_helper_fqtos);
                     break;
                 case 0xc8: /* fitod */
-                    gen_helper_fitod(cpu_fpr[rs2]);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DF(dc, rd, rs2, gen_helper_fitod);
                     break;
                 case 0xc9: /* fstod */
-                    gen_helper_fstod(cpu_fpr[rs2]);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DF(dc, rd, rs2, gen_helper_fstod);
                     break;
                 case 0xcb: /* fqtod */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fqtod();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DQ(dc, rd, rs2, gen_helper_fqtod);
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fitoq(cpu_fpr[rs2]);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QF(dc, rd, rs2, gen_helper_fitoq);
                     break;
                 case 0xcd: /* fstoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fstoq(cpu_fpr[rs2]);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QF(dc, rd, rs2, gen_helper_fstoq);
                     break;
                 case 0xce: /* fdtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fdtoq();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QD(dc, rd, rs2, gen_helper_fdtoq);
                     break;
                 case 0xd1: /* fstoi */
-                    gen_clear_float_exceptions();
-                    gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fstoi);
                     break;
                 case 0xd2: /* fdtoi */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdtoi(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fdtoi);
                     break;
                 case 0xd3: /* fqtoi */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fqtoi(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FQ(dc, rd, rs2, gen_helper_fqtoi);
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],
-                                    cpu_fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],
-                                    cpu_fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
-                                    cpu_fpr[QFPREG(rs2) + 3]);
+                    gen_move_Q(rd, rs2);
                     break;
                 case 0x6: /* V9 fnegd */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fnegd();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd);
                     break;
                 case 0x7: /* V9 fnegq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fnegq();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fnegq);
                     break;
                 case 0xa: /* V9 fabsd */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fabsd();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DD(dc, rd, rs2, gen_helper_fabsd);
                     break;
                 case 0xb: /* V9 fabsq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fabsq();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fabsq);
                     break;
                 case 0x81: /* V9 fstox */
-                    gen_clear_float_exceptions();
-                    gen_helper_fstox(cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DF(dc, rd, rs2, gen_helper_fstox);
                     break;
                 case 0x82: /* V9 fdtox */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdtox();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fdtox);
                     break;
                 case 0x83: /* V9 fqtox */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fqtox();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DQ(dc, rd, rs2, gen_helper_fqtox);
                     break;
                 case 0x84: /* V9 fxtos */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fxtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fxtos);
                     break;
                 case 0x88: /* V9 fxtod */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fxtod();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fxtod);
                     break;
                 case 0x8c: /* V9 fxtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fxtoq();
-                    gen_helper_check_ieee_exceptions();
-                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    gen_ne_fop_QD(dc, rd, rs2, gen_helper_fxtoq);
                     break;
 #endif
                 default:
@@ -2667,7 +3030,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
@@ -2678,8 +3042,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], cpu_fpr[DFPREG(rs2) + 1]);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
@@ -2691,10 +3055,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], cpu_fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], cpu_fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], cpu_fpr[QFPREG(rs2) + 3]);
+                    gen_move_Q(rd, rs2);
                     gen_set_label(l1);
                     break;
                 }
@@ -2712,7 +3073,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
+                        gen_store_fpr_F(dc, rd, cpu_src1_32);           \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2727,10 +3089,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
-                                        cpu_fpr[DFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
-                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs2);          \
+                        gen_store_fpr_D(dc, rd, cpu_src1_64);           \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2745,14 +3105,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
-                                        cpu_fpr[QFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
-                                        cpu_fpr[QFPREG(rs2) + 1]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
-                                        cpu_fpr[QFPREG(rs2) + 2]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
-                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_move_Q(rd, rs2);                            \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2810,7 +3163,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
+                        gen_store_fpr_F(dc, rd, cpu_src1_32);           \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2825,10 +3179,9 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
-                                        cpu_fpr[DFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
-                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs2);          \
+                        gen_store_fpr_D(dc, rd, cpu_src1_64);           \
+                        gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2843,14 +3196,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
-                                        cpu_fpr[QFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
-                                        cpu_fpr[QFPREG(rs2) + 1]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
-                                        cpu_fpr[QFPREG(rs2) + 2]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
-                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_move_Q(rd, rs2);                            \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2860,6 +3206,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x102: /* V9 fmovdcc %icc */
                         FMOVDCC(0);
+                        break;
                     case 0x103: /* V9 fmovqcc %icc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
                         FMOVQCC(0);
@@ -2879,12 +3226,14 @@ static void disas_sparc_insn(DisasContext * dc)
 #undef FMOVQCC
 #endif
                     case 0x51: /* fcmps, V9 %fcc */
-                        gen_op_fcmps(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                        cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                        gen_op_fcmps(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x52: /* fcmpd, V9 %fcc */
-                        gen_op_load_fpr_DT0(DFPREG(rs1));
-                        gen_op_load_fpr_DT1(DFPREG(rs2));
-                        gen_op_fcmpd(rd & 3);
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                        cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                        gen_op_fcmpd(rd & 3, cpu_src1_64, cpu_src2_64);
                         break;
                     case 0x53: /* fcmpq, V9 %fcc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2893,12 +3242,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmpq(rd & 3);
                         break;
                     case 0x55: /* fcmpes, V9 %fcc */
-                        gen_op_fcmpes(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                        cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                        gen_op_fcmpes(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x56: /* fcmped, V9 %fcc */
-                        gen_op_load_fpr_DT0(DFPREG(rs1));
-                        gen_op_load_fpr_DT1(DFPREG(rs2));
-                        gen_op_fcmped(rd & 3);
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                        cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                        gen_op_fcmped(rd & 3, cpu_src1_64, cpu_src2_64);
                         break;
                     case 0x57: /* fcmpeq, V9 %fcc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -3174,28 +3525,39 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
 #ifdef TARGET_SPARC64
                     case 0xd: /* V9 udivx */
-                        tcg_gen_mov_tl(cpu_cc_src, cpu_src1);
-                        tcg_gen_mov_tl(cpu_cc_src2, cpu_src2);
-                        gen_trap_ifdivzero_tl(cpu_cc_src2);
-                        tcg_gen_divu_i64(cpu_dst, cpu_cc_src, cpu_cc_src2);
+                        {
+                            TCGv r_temp1, r_temp2;
+                            r_temp1 = tcg_temp_local_new();
+                            r_temp2 = tcg_temp_local_new();
+                            tcg_gen_mov_tl(r_temp1, cpu_src1);
+                            tcg_gen_mov_tl(r_temp2, cpu_src2);
+                            gen_trap_ifdivzero_tl(r_temp2);
+                            tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2);
+                            tcg_temp_free(r_temp1);
+                            tcg_temp_free(r_temp2);
+                        }
                         break;
 #endif
                     case 0xe: /* udiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     case 0xf: /* sdiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     default:
@@ -3233,7 +3595,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         dc->cc_op = CC_OP_TSUBTV;
                         break;
                     case 0x24: /* mulscc */
-                        gen_helper_compute_psr();
+                        gen_helper_compute_psr(cpu_env);
                         gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2);
                         gen_movl_TN_reg(rd, cpu_dst);
                         tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
@@ -3291,7 +3653,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #else
                             case 0x2: /* V9 wrccr */
                                 tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                                gen_helper_wrccr(cpu_dst);
+                                gen_helper_wrccr(cpu_env, cpu_dst);
                                 tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                                 dc->cc_op = CC_OP_FLAGS;
                                 break;
@@ -3324,19 +3686,19 @@ static void disas_sparc_insn(DisasContext * dc)
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_set_softint(cpu_tmp64);
+                                gen_helper_set_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x15: /* Softint clear */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_clear_softint(cpu_tmp64);
+                                gen_helper_clear_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x16: /* Softint write */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_write_softint(cpu_tmp64);
+                                gen_helper_write_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x17: /* Tick compare */
 #if !defined(CONFIG_USER_ONLY)
@@ -3411,10 +3773,10 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef TARGET_SPARC64
                             switch (rd) {
                             case 0:
-                                gen_helper_saved();
+                                gen_helper_saved(cpu_env);
                                 break;
                             case 1:
-                                gen_helper_restored();
+                                gen_helper_restored(cpu_env);
                                 break;
                             case 2: /* UA2005 allclean */
                             case 3: /* UA2005 otherw */
@@ -3426,7 +3788,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             }
 #else
                             tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                            gen_helper_wrpsr(cpu_dst);
+                            gen_helper_wrpsr(cpu_env, cpu_dst);
                             tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                             dc->cc_op = CC_OP_FLAGS;
                             save_state(dc, cpu_cond);
@@ -3505,22 +3867,34 @@ static void disas_sparc_insn(DisasContext * dc)
                                 tcg_gen_mov_tl(cpu_tbr, cpu_tmp0);
                                 break;
                             case 6: // pstate
-                                save_state(dc, cpu_cond);
-                                gen_helper_wrpstate(cpu_tmp0);
-                                dc->npc = DYNAMIC_PC;
+                                {
+                                    TCGv r_tmp = tcg_temp_local_new();
+
+                                    tcg_gen_mov_tl(r_tmp, cpu_tmp0);
+                                    save_state(dc, cpu_cond);
+                                    gen_helper_wrpstate(cpu_env, r_tmp);
+                                    tcg_temp_free(r_tmp);
+                                    dc->npc = DYNAMIC_PC;
+                                }
                                 break;
                             case 7: // tl
-                                save_state(dc, cpu_cond);
-                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
-                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
-                                               offsetof(CPUSPARCState, tl));
-                                dc->npc = DYNAMIC_PC;
+                                {
+                                    TCGv r_tmp = tcg_temp_local_new();
+
+                                    tcg_gen_mov_tl(r_tmp, cpu_tmp0);
+                                    save_state(dc, cpu_cond);
+                                    tcg_gen_trunc_tl_i32(cpu_tmp32, r_tmp);
+                                    tcg_temp_free(r_tmp);
+                                    tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                                   offsetof(CPUSPARCState, tl));
+                                    dc->npc = DYNAMIC_PC;
+                                }
                                 break;
                             case 8: // pil
-                                gen_helper_wrpil(cpu_tmp0);
+                                gen_helper_wrpil(cpu_env, cpu_tmp0);
                                 break;
                             case 9: // cwp
-                                gen_helper_wrcwp(cpu_tmp0);
+                                gen_helper_wrcwp(cpu_env, cpu_tmp0);
                                 break;
                             case 10: // cansave
                                 tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
@@ -3715,19 +4089,89 @@ static void disas_sparc_insn(DisasContext * dc)
 
                 switch (opf) {
                 case 0x000: /* VIS I edge8cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x001: /* VIS II edge8n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x002: /* VIS I edge8lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x003: /* VIS II edge8ln */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x004: /* VIS I edge16cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x005: /* VIS II edge16n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x006: /* VIS I edge16lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x007: /* VIS II edge16ln */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x008: /* VIS I edge32cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x009: /* VIS II edge32n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x00a: /* VIS I edge32lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x00b: /* VIS II edge32ln */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x010: /* VIS I array8 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
@@ -3755,372 +4199,317 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2);
+                    gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 0);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
-                case 0x019: /* VIS II bmask */
                 case 0x01a: /* VIS I alignaddrl */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x019: /* VIS II bmask */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    cpu_src2 = get_src1(insn, cpu_src2);
+                    tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                    tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, cpu_dst, 32, 32);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x020: /* VIS I fcmple16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmple16(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x022: /* VIS I fcmpne16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpne16(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x024: /* VIS I fcmple32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmple32(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x026: /* VIS I fcmpne32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpne32(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpgt16(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpeq16(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpgt32(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpeq32(cpu_dst, cpu_src1_64, cpu_src2_64);
+                    gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x031: /* VIS I fmul8x16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16);
                     break;
                 case 0x033: /* VIS I fmul8x16au */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16au();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16au);
                     break;
                 case 0x035: /* VIS I fmul8x16al */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16al();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16al);
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8sux16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8sux16);
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8ulx16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8ulx16);
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8sux16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8sux16);
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8ulx16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8ulx16);
                     break;
                 case 0x03a: /* VIS I fpack32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpack32);
+                    break;
                 case 0x03b: /* VIS I fpack16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpack16(cpu_dst_32, cpu_gsr, cpu_src1_64);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    break;
                 case 0x03d: /* VIS I fpackfix */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpackfix(cpu_dst_32, cpu_gsr, cpu_src1_64);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    break;
                 case 0x03e: /* VIS I pdist */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_ne_fop_DDDD(dc, rd, rs1, rs2, gen_helper_pdist);
+                    break;
                 case 0x048: /* VIS I faligndata */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_faligndata();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_faligndata);
                     break;
                 case 0x04b: /* VIS I fpmerge */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpmerge();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpmerge);
                     break;
                 case 0x04c: /* VIS II bshuffle */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_bshuffle);
+                    break;
                 case 0x04d: /* VIS I fexpand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fexpand();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fexpand);
                     break;
                 case 0x050: /* VIS I fpadd16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd16);
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd16s(cpu_fpr[rd],
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpadd16s);
                     break;
                 case 0x052: /* VIS I fpadd32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd32);
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd32s(cpu_fpr[rd],
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_add_i32);
                     break;
                 case 0x054: /* VIS I fpsub16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub16();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub16);
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub16s(cpu_fpr[rd],
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpsub16s);
                     break;
                 case 0x056: /* VIS I fpsub32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub32();
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub32);
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub32s(cpu_fpr[rd],
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_sub_i32);
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], 0);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], 0);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_movi_i64(cpu_dst_64, 0);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x061: /* VIS I fzeros */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[rd], 0);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_movi_i32(cpu_dst_32, 0);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nor_i64);
                     break;
                 case 0x063: /* VIS I fnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nor_i32);
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                     cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                     cpu_fpr[DFPREG(rs1) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_andc_i64);
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_andc_i32);
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DD(dc, rd, rs2, tcg_gen_not_i64);
                     break;
                 case 0x067: /* VIS I fnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_ne_fop_FF(dc, rd, rs2, tcg_gen_not_i32);
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
-                                     cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1],
-                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_andc_i64);
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_andc_i32);
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_ne_fop_DD(dc, rd, rs1, tcg_gen_not_i64);
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    gen_ne_fop_FF(dc, rd, rs1, tcg_gen_not_i32);
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_xor_i64);
                     break;
                 case 0x06d: /* VIS I fxors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_xor_i32);
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
-                                     cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nand_i64);
                     break;
                 case 0x06f: /* VIS I fnands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nand_i32);
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_and_i64);
                     break;
                 case 0x071: /* VIS I fands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_and_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_and_i32);
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2)], -1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_tmp32,
-                                    cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2) + 1], -1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], cpu_tmp32,
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_eqv_i64);
                     break;
                 case 0x073: /* VIS I fxnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[rs2], -1);
-                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_tmp32, cpu_fpr[rs1]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_eqv_i32);
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x075: /* VIS I fsrc1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_orc_i64);
                     break;
                 case 0x077: /* VIS I fornot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_orc_i32);
                     break;
                 case 0x078: /* VIS I fsrc2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs2));
-                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x079: /* VIS I fsrc2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
-                                    cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_orc_i64);
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_orc_i32);
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                   cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd) + 1],
-                                   cpu_fpr[DFPREG(rs1) + 1],
-                                   cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_or_i64);
                     break;
                 case 0x07d: /* VIS I fors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_or_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_or_i32);
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], -1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], -1);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_movi_i64(cpu_dst_64, -1);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x07f: /* VIS I fones */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[rd], -1);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_movi_i32(cpu_dst_32, -1);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x080: /* VIS I shutdown */
                 case 0x081: /* VIS II siam */
@@ -4155,7 +4544,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     } else
                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
                 }
-                gen_helper_restore();
+                gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc, cpu_cond);
                 r_const = tcg_const_i32(3);
                 gen_helper_check_align(cpu_dst, r_const);
@@ -4207,23 +4596,23 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_temp_free_i32(r_const);
                         tcg_gen_mov_tl(cpu_npc, cpu_dst);
                         dc->npc = DYNAMIC_PC;
-                        gen_helper_rett();
+                        gen_helper_rett(cpu_env);
                     }
                     goto jmp_insn;
 #endif
                 case 0x3b: /* flush */
                     if (!((dc)->def->features & CPU_FEATURE_FLUSH))
                         goto unimp_flush;
-                    gen_helper_flush(cpu_dst);
+                    /* nop */
                     break;
                 case 0x3c:      /* save */
                     save_state(dc, cpu_cond);
-                    gen_helper_save();
+                    gen_helper_save(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3d:      /* restore */
                     save_state(dc, cpu_cond);
-                    gen_helper_restore();
+                    gen_helper_restore(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
@@ -4235,14 +4624,14 @@ static void disas_sparc_insn(DisasContext * dc)
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_done();
+                            gen_helper_done(cpu_env);
                             goto jmp_insn;
                         case 1:
                             if (!supervisor(dc))
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_retry();
+                            gen_helper_retry(cpu_env);
                             goto jmp_insn;
                         default:
                             goto illegal_insn;
@@ -4265,7 +4654,7 @@ static void disas_sparc_insn(DisasContext * dc)
                cpu state */
             if (dc->cc_op != CC_OP_FLAGS) {
                 dc->cc_op = CC_OP_FLAGS;
-                gen_helper_compute_psr();
+                gen_helper_compute_psr(cpu_env);
             }
             cpu_src1 = get_src1(insn, cpu_src1);
             if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa
@@ -4461,19 +4850,31 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x2d: /* V9 prefetch, no effect */
                     goto skip_move;
                 case 0x30: /* V9 ldfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 4, rd);
+                    gen_update_fprs_dirty(rd);
                     goto skip_move;
                 case 0x33: /* V9 lddfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd));
+                    gen_update_fprs_dirty(DFPREG(rd));
                     goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
                 case 0x32: /* V9 ldqfa */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
                     save_state(dc, cpu_cond);
                     gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd));
+                    gen_update_fprs_dirty(QFPREG(rd));
                     goto skip_move;
 #endif
                 default:
@@ -4491,23 +4892,25 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x20:      /* ldf, load fpreg */
                     gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
-                    tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_trunc_tl_i32(cpu_dst_32, cpu_tmp0);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x21:      /* ldfsr, V9 ldxfsr */
 #ifdef TARGET_SPARC64
                     gen_address_mask(dc, cpu_addr);
                     if (rd == 1) {
                         tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
-                        gen_helper_ldxfsr(cpu_tmp64);
+                        gen_helper_ldxfsr(cpu_env, cpu_tmp64);
                     } else {
                         tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
                         tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
-                        gen_helper_ldfsr(cpu_tmp32);
+                        gen_helper_ldfsr(cpu_env, cpu_tmp32);
                     }
 #else
                     {
                         tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
-                        gen_helper_ldfsr(cpu_tmp32);
+                        gen_helper_ldfsr(cpu_env, cpu_tmp32);
                     }
 #endif
                     break;
@@ -4521,18 +4924,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_helper_ldqf(cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_QT0_fpr(QFPREG(rd));
+                        gen_update_fprs_dirty(QFPREG(rd));
                     }
                     break;
                 case 0x23:      /* lddf, load double fpreg */
-                    {
-                        TCGv_i32 r_const;
-
-                        r_const = tcg_const_i32(dc->mem_idx);
-                        gen_address_mask(dc, cpu_addr);
-                        gen_helper_lddf(cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
-                        gen_op_store_DT0_fpr(DFPREG(rd));
-                    }
+                    gen_address_mask(dc, cpu_addr);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_qemu_ld64(cpu_dst_64, cpu_addr, dc->mem_idx);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 default:
                     goto illegal_insn;
@@ -4639,7 +5038,8 @@ static void disas_sparc_insn(DisasContext * dc)
                 switch (xop) {
                 case 0x24: /* stf, store fpreg */
                     gen_address_mask(dc, cpu_addr);
-                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_fpr[rd]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rd);
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_src1_32);
                     tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx);
                     break;
                 case 0x25: /* stfsr, V9 stxfsr */
@@ -4682,15 +5082,9 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
 #endif
                 case 0x27: /* stdf, store double fpreg */
-                    {
-                        TCGv_i32 r_const;
-
-                        gen_op_load_fpr_DT0(DFPREG(rd));
-                        r_const = tcg_const_i32(dc->mem_idx);
-                        gen_address_mask(dc, cpu_addr);
-                        gen_helper_stdf(cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
-                    }
+                    gen_address_mask(dc, cpu_addr);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rd);
+                    tcg_gen_qemu_st64(cpu_src1_64, cpu_addr, dc->mem_idx);
                     break;
                 default:
                     goto illegal_insn;
@@ -4700,6 +5094,9 @@ static void disas_sparc_insn(DisasContext * dc)
                 switch (xop) {
 #ifdef TARGET_SPARC64
                 case 0x34: /* V9 stfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
                     gen_stf_asi(cpu_addr, insn, 4, rd);
                     break;
                 case 0x36: /* V9 stqfa */
@@ -4707,15 +5104,19 @@ static void disas_sparc_insn(DisasContext * dc)
                         TCGv_i32 r_const;
 
                         CHECK_FPU_FEATURE(dc, FLOAT128);
+                        if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                            goto jmp_insn;
+                        }
                         r_const = tcg_const_i32(7);
                         gen_helper_check_align(cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
-                        gen_op_load_fpr_QT0(QFPREG(rd));
                         gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd));
                     }
                     break;
                 case 0x37: /* V9 stdfa */
-                    gen_op_load_fpr_DT0(DFPREG(rd));
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
                     gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd));
                     break;
                 case 0x3c: /* V9 casa */
@@ -4761,7 +5162,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_ILL_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4772,7 +5173,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_UNIMP_FLUSH);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4784,7 +5185,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_PRIV_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4809,7 +5210,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_NCP_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free(r_const);
         dc->is_br = 1;
     }
@@ -4818,6 +5219,13 @@ static void disas_sparc_insn(DisasContext * dc)
  egress:
     tcg_temp_free(cpu_tmp1);
     tcg_temp_free(cpu_tmp2);
+    if (dc->n_t32 != 0) {
+        int i;
+        for (i = dc->n_t32 - 1; i >= 0; --i) {
+            tcg_temp_free_i32(dc->t32[i]);
+        }
+        dc->n_t32 = 0;
+    }
 }
 
 static inline void gen_intermediate_code_internal(TranslationBlock * tb,
@@ -4840,13 +5248,8 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     dc->cc_op = CC_OP_DYNAMIC;
     dc->mem_idx = cpu_mmu_index(env);
     dc->def = env->def;
-    if ((dc->def->features & CPU_FEATURE_FLOAT))
-        dc->fpu_enabled = cpu_fpu_enabled(env);
-    else
-        dc->fpu_enabled = 0;
-#ifdef TARGET_SPARC64
-    dc->address_mask_32bit = env->pstate & PS_AM;
-#endif
+    dc->fpu_enabled = tb_fpu_enabled(tb->flags);
+    dc->address_mask_32bit = tb_am_enabled(tb->flags);
     dc->singlestep = (env->singlestep_enabled || singlestep);
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
 
@@ -4871,7 +5274,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
                 if (bp->pc == dc->pc) {
                     if (dc->pc != pc_start)
                         save_state(dc, cpu_cond);
-                    gen_helper_debug();
+                    gen_helper_debug(cpu_env);
                     tcg_gen_exit_tb(0);
                     dc->is_br = 1;
                     goto exit_gen_loop;
@@ -4922,6 +5325,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     tcg_temp_free_i64(cpu_tmp64);
     tcg_temp_free_i32(cpu_tmp32);
     tcg_temp_free(cpu_tmp0);
+
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
     if (!dc->is_br) {
@@ -4986,15 +5390,11 @@ void gen_intermediate_code_init(CPUSPARCState *env)
         "g6",
         "g7",
     };
-    static const char * const fregnames[64] = {
-        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
-        "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
-        "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
-        "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-        "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
-        "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
-        "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
-        "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
+    static const char * const fregnames[32] = {
+        "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
+        "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
+        "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
+        "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
     };
 
     /* init various static tables */
@@ -5064,14 +5464,16 @@ void gen_intermediate_code_init(CPUSPARCState *env)
         cpu_tbr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, tbr),
                                      "tbr");
 #endif
-        for (i = 1; i < 8; i++)
+        for (i = 1; i < 8; i++) {
             cpu_gregs[i] = tcg_global_mem_new(TCG_AREG0,
                                               offsetof(CPUState, gregs[i]),
                                               gregnames[i]);
-        for (i = 0; i < TARGET_FPREGS; i++)
-            cpu_fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
+        }
+        for (i = 0; i < TARGET_DPREGS; i++) {
+            cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                                 offsetof(CPUState, fpr[i]),
                                                 fregnames[i]);
+        }
 
         /* register helpers */
 
@@ -5080,8 +5482,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];
@@ -5101,6 +5502,6 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb,
 
     /* flush pending conditional evaluations before exposing cpu state */
     if (CC_OP != CC_OP_FLAGS) {
-        helper_compute_psr();
+        helper_compute_psr(env);
     }
 }
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
new file mode 100644 (file)
index 0000000..a992c29
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * VIS op helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+/* This function uses non-native bit order */
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
+{
+    return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
+        (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
+        (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
+        (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
+        (((pixel_addr >> 55) & 1) << 4) |
+        (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
+        GET_FIELD_SP(pixel_addr, 11, 12);
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+    uint8_t b[8];
+    uint16_t w[4];
+    int16_t sw[4];
+    uint32_t l[2];
+    uint64_t ll;
+    float64 d;
+} VIS64;
+
+typedef union {
+    uint8_t b[4];
+    uint16_t w[2];
+    uint32_t l;
+    float32 f;
+} VIS32;
+
+uint64_t helper_fpmerge(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+
+    s.ll = src1;
+    d.ll = src2;
+
+    /* Reverse calculation order to handle overlap */
+    d.VIS_B64(7) = s.VIS_B64(3);
+    d.VIS_B64(6) = d.VIS_B64(3);
+    d.VIS_B64(5) = s.VIS_B64(2);
+    d.VIS_B64(4) = d.VIS_B64(2);
+    d.VIS_B64(3) = s.VIS_B64(1);
+    d.VIS_B64(2) = d.VIS_B64(1);
+    d.VIS_B64(1) = s.VIS_B64(0);
+    /* d.VIS_B64(0) = d.VIS_B64(0); */
+
+    return d.ll;
+}
+
+uint64_t helper_fmul8x16(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmul8x16al(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmul8x16au(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmul8sux16(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmul8ulx16(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmuld8sux16(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_L64(r) = tmp;
+
+    /* Reverse calculation order to handle overlap */
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fmuld8ulx16(uint64_t src1, uint64_t src2)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.ll = src1;
+    d.ll = src2;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_L64(r) = tmp;
+
+    /* Reverse calculation order to handle overlap */
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    return d.ll;
+}
+
+uint64_t helper_fexpand(uint64_t src1, uint64_t src2)
+{
+    VIS32 s;
+    VIS64 d;
+
+    s.l = (uint32_t)src1;
+    d.ll = src2;
+    d.VIS_W64(0) = s.VIS_B32(0) << 4;
+    d.VIS_W64(1) = s.VIS_B32(1) << 4;
+    d.VIS_W64(2) = s.VIS_B32(2) << 4;
+    d.VIS_W64(3) = s.VIS_B32(3) << 4;
+
+    return d.ll;
+}
+
+#define VIS_HELPER(name, F)                             \
+    uint64_t name##16(uint64_t src1, uint64_t src2)     \
+    {                                                   \
+        VIS64 s, d;                                     \
+                                                        \
+        s.ll = src1;                                    \
+        d.ll = src2;                                    \
+                                                        \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
+        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
+        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
+        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
+                                                        \
+        return d.ll;                                    \
+    }                                                   \
+                                                        \
+    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
+    {                                                   \
+        VIS32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
+        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
+                                                        \
+        return d.l;                                     \
+    }                                                   \
+                                                        \
+    uint64_t name##32(uint64_t src1, uint64_t src2)     \
+    {                                                   \
+        VIS64 s, d;                                     \
+                                                        \
+        s.ll = src1;                                    \
+        d.ll = src2;                                    \
+                                                        \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
+        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
+                                                        \
+        return d.ll;                                    \
+    }                                                   \
+                                                        \
+    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
+    {                                                   \
+        VIS32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.l = F(d.l, s.l);                              \
+                                                        \
+        return d.l;                                     \
+    }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_HELPER(helper_fpadd, FADD)
+VIS_HELPER(helper_fpsub, FSUB)
+
+#define VIS_CMPHELPER(name, F)                                    \
+    uint64_t name##16(uint64_t src1, uint64_t src2)               \
+    {                                                             \
+        VIS64 s, d;                                               \
+                                                                  \
+        s.ll = src1;                                              \
+        d.ll = src2;                                              \
+                                                                  \
+        d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
+        d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0;    \
+        d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0;           \
+                                                                  \
+        return d.ll;                                              \
+    }                                                             \
+                                                                  \
+    uint64_t name##32(uint64_t src1, uint64_t src2)               \
+    {                                                             \
+        VIS64 s, d;                                               \
+                                                                  \
+        s.ll = src1;                                              \
+        d.ll = src2;                                              \
+                                                                  \
+        d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
+        d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
+        d.VIS_L64(1) = 0;                                         \
+                                                                  \
+        return d.ll;                                              \
+    }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
+VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
+VIS_CMPHELPER(helper_fcmple, FCMPLE)
+VIS_CMPHELPER(helper_fcmpne, FCMPNE)
+
+uint64_t helper_pdist(uint64_t sum, uint64_t src1, uint64_t src2)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+        int s1, s2;
+
+        s1 = (src1 >> (56 - (i * 8))) & 0xff;
+        s2 = (src2 >> (56 - (i * 8))) & 0xff;
+
+        /* Absolute value of difference. */
+        s1 -= s2;
+        if (s1 < 0) {
+            s1 = -s1;
+        }
+
+        sum += s1;
+    }
+
+    return sum;
+}
+
+uint32_t helper_fpack16(uint64_t gsr, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0xf;
+    uint32_t ret = 0;
+    int byte;
+
+    for (byte = 0; byte < 4; byte++) {
+        uint32_t val;
+        int16_t src = rs2 >> (byte * 16);
+        int32_t scaled = src << scale;
+        int32_t from_fixed = scaled >> 7;
+
+        val = (from_fixed < 0 ?  0 :
+               from_fixed > 255 ?  255 : from_fixed);
+
+        ret |= val << (8 * byte);
+    }
+
+    return ret;
+}
+
+uint64_t helper_fpack32(uint64_t gsr, uint64_t rs1, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0x1f;
+    uint64_t ret = 0;
+    int word;
+
+    ret = (rs1 << 8) & ~(0x000000ff000000ffULL);
+    for (word = 0; word < 2; word++) {
+        uint64_t val;
+        int32_t src = rs2 >> (word * 32);
+        int64_t scaled = (int64_t)src << scale;
+        int64_t from_fixed = scaled >> 23;
+
+        val = (from_fixed < 0 ? 0 :
+               (from_fixed > 255) ? 255 : from_fixed);
+
+        ret |= val << (32 * word);
+    }
+
+    return ret;
+}
+
+uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0x1f;
+    uint32_t ret = 0;
+    int word;
+
+    for (word = 0; word < 2; word++) {
+        uint32_t val;
+        int32_t src = rs2 >> (word * 32);
+        int64_t scaled = src << scale;
+        int64_t from_fixed = scaled >> 16;
+
+        val = (from_fixed < -32768 ? -32768 :
+               from_fixed > 32767 ?  32767 : from_fixed);
+
+        ret |= (val & 0xffff) << (word * 16);
+    }
+
+    return ret;
+}
+
+uint64 helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } s;
+    VIS64 r;
+    uint32_t i, mask, host;
+
+    /* Set up S such that we can index across all of the bytes.  */
+#ifdef HOST_WORDS_BIGENDIAN
+    s.ll[0] = src1;
+    s.ll[1] = src2;
+    host = 0;
+#else
+    s.ll[1] = src1;
+    s.ll[0] = src2;
+    host = 15;
+#endif
+    mask = gsr >> 32;
+
+    for (i = 0; i < 8; ++i) {
+        unsigned e = (mask >> (28 - i*4)) & 0xf;
+        r.VIS_B64(i) = s.b[e ^ host];
+    }
+
+    return r.ll;
+}
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
new file mode 100644 (file)
index 0000000..a68c649
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Helpers for CWP and PSTATE handling
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst[4] = src[4];
+    dst[5] = src[5];
+    dst[6] = src[6];
+    dst[7] = src[7];
+}
+
+void cpu_set_cwp(CPUState *env, int new_cwp)
+{
+    /* put the modified wrap registers at their proper location */
+    if (env->cwp == env->nwindows - 1) {
+        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+    }
+    env->cwp = new_cwp;
+
+    /* put the wrap registers at their temporary location */
+    if (new_cwp == env->nwindows - 1) {
+        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+    }
+    env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+target_ulong cpu_get_psr(CPUState *env)
+{
+    helper_compute_psr(env);
+
+#if !defined(TARGET_SPARC64)
+    return env->version | (env->psr & PSR_ICC) |
+        (env->psref ? PSR_EF : 0) |
+        (env->psrpil << 8) |
+        (env->psrs ? PSR_S : 0) |
+        (env->psrps ? PSR_PS : 0) |
+        (env->psret ? PSR_ET : 0) | env->cwp;
+#else
+    return env->psr & PSR_ICC;
+#endif
+}
+
+void cpu_put_psr(CPUState *env, target_ulong val)
+{
+    env->psr = val & PSR_ICC;
+#if !defined(TARGET_SPARC64)
+    env->psref = (val & PSR_EF) ? 1 : 0;
+    env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+    cpu_check_irqs(env);
+#endif
+#if !defined(TARGET_SPARC64)
+    env->psrs = (val & PSR_S) ? 1 : 0;
+    env->psrps = (val & PSR_PS) ? 1 : 0;
+    env->psret = (val & PSR_ET) ? 1 : 0;
+    cpu_set_cwp(env, val & PSR_CWP);
+#endif
+    env->cc_op = CC_OP_FLAGS;
+}
+
+int cpu_cwp_inc(CPUState *env, int cwp)
+{
+    if (unlikely(cwp >= env->nwindows)) {
+        cwp -= env->nwindows;
+    }
+    return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env, int cwp)
+{
+    if (unlikely(cwp < 0)) {
+        cwp += env->nwindows;
+    }
+    return cwp;
+}
+
+#ifndef TARGET_SPARC64
+void helper_rett(CPUState *env)
+{
+    unsigned int cwp;
+
+    if (env->psret == 1) {
+        helper_raise_exception(env, TT_ILL_INSN);
+    }
+
+    env->psret = 1;
+    cwp = cpu_cwp_inc(env, env->cwp + 1) ;
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_UNF);
+    }
+    cpu_set_cwp(env, cwp);
+    env->psrs = env->psrps;
+}
+
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_OVF);
+    }
+    cpu_set_cwp(env, cwp);
+}
+
+void helper_restore(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_UNF);
+    }
+    cpu_set_cwp(env, cwp);
+}
+
+void helper_wrpsr(CPUState *env, target_ulong new_psr)
+{
+    if ((new_psr & PSR_CWP) >= env->nwindows) {
+        helper_raise_exception(env, TT_ILL_INSN);
+    } else {
+        cpu_put_psr(env, new_psr);
+    }
+}
+
+target_ulong helper_rdpsr(CPUState *env)
+{
+    return cpu_get_psr(env);
+}
+
+#else
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    if (env->cansave == 0) {
+        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+                                                (TT_WOTHER |
+                                                 ((env->wstate & 0x38) >> 1)) :
+                                                ((env->wstate & 0x7) << 2)));
+    } else {
+        if (env->cleanwin - env->canrestore == 0) {
+            /* XXX Clean windows without trap */
+            helper_raise_exception(env, TT_CLRWIN);
+        } else {
+            env->cansave--;
+            env->canrestore++;
+            cpu_set_cwp(env, cwp);
+        }
+    }
+}
+
+void helper_restore(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
+    if (env->canrestore == 0) {
+        helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
+                                               (TT_WOTHER |
+                                                ((env->wstate & 0x38) >> 1)) :
+                                               ((env->wstate & 0x7) << 2)));
+    } else {
+        env->cansave++;
+        env->canrestore--;
+        cpu_set_cwp(env, cwp);
+    }
+}
+
+void helper_flushw(CPUState *env)
+{
+    if (env->cansave != env->nwindows - 2) {
+        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+                                                (TT_WOTHER |
+                                                 ((env->wstate & 0x38) >> 1)) :
+                                                ((env->wstate & 0x7) << 2)));
+    }
+}
+
+void helper_saved(CPUState *env)
+{
+    env->cansave++;
+    if (env->otherwin == 0) {
+        env->canrestore--;
+    } else {
+        env->otherwin--;
+    }
+}
+
+void helper_restored(CPUState *env)
+{
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1) {
+        env->cleanwin++;
+    }
+    if (env->otherwin == 0) {
+        env->cansave--;
+    } else {
+        env->otherwin--;
+    }
+}
+
+target_ulong cpu_get_ccr(CPUState *env)
+{
+    target_ulong psr;
+
+    psr = cpu_get_psr(env);
+
+    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+void cpu_put_ccr(CPUState *env, target_ulong val)
+{
+    env->xcc = (val >> 4) << 20;
+    env->psr = (val & 0xf) << 20;
+    CC_OP = CC_OP_FLAGS;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env)
+{
+    return env->nwindows - 1 - env->cwp;
+}
+
+void cpu_put_cwp64(CPUState *env, int cwp)
+{
+    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+        cwp %= env->nwindows;
+    }
+    cpu_set_cwp(env, env->nwindows - 1 - cwp);
+}
+
+target_ulong helper_rdccr(CPUState *env)
+{
+    return cpu_get_ccr(env);
+}
+
+void helper_wrccr(CPUState *env, target_ulong new_ccr)
+{
+    cpu_put_ccr(env, new_ccr);
+}
+
+/* CWP handling is reversed in V9, but we still use the V8 register
+   order. */
+target_ulong helper_rdcwp(CPUState *env)
+{
+    return cpu_get_cwp64(env);
+}
+
+void helper_wrcwp(CPUState *env, target_ulong new_cwp)
+{
+    cpu_put_cwp64(env, new_cwp);
+}
+
+static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
+{
+    switch (pstate) {
+    default:
+        trace_win_helper_gregset_error(pstate);
+        /* pass through to normal set of global registers */
+    case 0:
+        return env->bgregs;
+    case PS_AG:
+        return env->agregs;
+    case PS_MG:
+        return env->mgregs;
+    case PS_IG:
+        return env->igregs;
+    }
+}
+
+void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
+{
+    uint32_t pstate_regs, new_pstate_regs;
+    uint64_t *src, *dst;
+
+    if (env->def->features & CPU_FEATURE_GL) {
+        /* PS_AG is not implemented in this case */
+        new_pstate &= ~PS_AG;
+    }
+
+    pstate_regs = env->pstate & 0xc01;
+    new_pstate_regs = new_pstate & 0xc01;
+
+    if (new_pstate_regs != pstate_regs) {
+        trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
+
+        /* Switch global register bank */
+        src = get_gregset(env, new_pstate_regs);
+        dst = get_gregset(env, pstate_regs);
+        memcpy32(dst, env->gregs);
+        memcpy32(env->gregs, src);
+    } else {
+        trace_win_helper_no_switch_pstate(new_pstate_regs);
+    }
+    env->pstate = new_pstate;
+}
+
+void helper_wrpstate(CPUState *env, target_ulong new_state)
+{
+    cpu_change_pstate(env, new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_wrpil(CPUState *env, target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+    trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
+
+    env->psrpil = new_pil;
+
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_done(CPUState *env)
+{
+    trap_state *tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tnpc;
+    env->npc = tsptr->tnpc + 4;
+    cpu_put_ccr(env, tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
+    env->tl--;
+
+    trace_win_helper_done(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_retry(CPUState *env)
+{
+    trap_state *tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tpc;
+    env->npc = tsptr->tnpc;
+    cpu_put_ccr(env, tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
+    env->tl--;
+
+    trace_win_helper_retry(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+#endif
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
new file mode 100644 (file)
index 0000000..b4e72cf
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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);
+
+#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);
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
+#endif /* __CPU_UC32_H__ */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
new file mode 100644 (file)
index 0000000..b5b1cb7
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * 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 "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 = g_malloc0(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)
+{
+    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..6cf5255
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  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 "cpu.h"
+#include "dyngen-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(env);
+}
+
+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..4d0aa43
--- /dev/null
@@ -0,0 +1,2103 @@
+/*
+ *  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 "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((tcg_target_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 0x0:
+        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 0x1:
+        if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
+            do_misc(env, s, insn);
+            break;
+        }
+        do_datap(env, s, insn);
+        break;
+
+    case 0x2:
+        if (UCOP_SET(8) && UCOP_SET(5)) {
+            do_ldst_hwsb(env, s, insn);
+            break;
+        }
+        if (UCOP_SET(8) || UCOP_SET(5)) {
+            ILLEGAL;
+        }
+    case 0x3:
+        do_ldst_ir(env, s, insn);
+        break;
+
+    case 0x4:
+        if (UCOP_SET(8)) {
+            ILLEGAL; /* extended instructions */
+        }
+        do_ldst_m(env, s, insn);
+        break;
+    case 0x5:
+        do_branch(env, s, insn);
+        break;
+    case 0x6:
+        /* Coprocessor.  */
+        disas_coproc_insn(env, s, insn);
+        break;
+    case 0x7:
+        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];
+}
diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c
new file mode 100644 (file)
index 0000000..4d9bd55
--- /dev/null
@@ -0,0 +1,28 @@
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+#include "core-dc232b/core-isa.h"
+#include "overlay_tool.h"
+
+static const XtensaConfig dc232b = {
+    .name = "dc232b",
+    .options = XTENSA_OPTIONS,
+    .gdb_regmap = {
+        .num_regs = 120,
+        .num_core_regs = 52,
+        .reg = {
+#include "core-dc232b/gdb-config.c"
+        }
+    },
+    .nareg = XCHAL_NUM_AREGS,
+    .ndepc = 1,
+    EXCEPTIONS_SECTION,
+    INTERRUPTS_SECTION,
+    TLB_SECTION,
+    .clock_freq_khz = 10000,
+};
+
+REGISTER_CORE(dc232b)
diff --git a/target-xtensa/core-dc232b/core-isa.h b/target-xtensa/core-dc232b/core-isa.h
new file mode 100644 (file)
index 0000000..69f1065
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Xtensa processor core configuration information.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1999-2007 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_CONFIGURATION_H
+#define _XTENSA_CORE_CONFIGURATION_H
+
+
+/****************************************************************************
+            Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ *  configured, and a value of 0 otherwise.  These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+                                ISA
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE                   0       /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED             1       /* windowed registers option */
+#define XCHAL_NUM_AREGS                 32      /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2            5       /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE      3       /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG                1       /* debug option */
+#define XCHAL_HAVE_DENSITY              1       /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS                1       /* zero-overhead loops */
+#define XCHAL_HAVE_NSA                  1       /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX               1       /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT                 1       /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS               1       /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16                1       /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32                1       /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH           0       /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_DIV32                1       /* QUOS/QUOU/REMS/REMU insns */
+#define XCHAL_HAVE_L32R                 1       /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS    1       /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16              0       /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX                 1       /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES        0       /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES   0       /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12           1       /* (obsolete option) */
+#define XCHAL_HAVE_ABS                  1       /* ABS instruction */
+/*#define XCHAL_HAVE_POPC               0*/     /* POPC instruction */
+/*#define XCHAL_HAVE_CRC                0*/     /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC         1       /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I               1       /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION          0       /* speculation */
+#define XCHAL_HAVE_FULL_RESET           1       /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS              1       /* */
+#define XCHAL_NUM_MISC_REGS             2       /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER           0       /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID                 1       /* processor ID register */
+#define XCHAL_HAVE_THREADPTR            1       /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS             0       /* boolean registers */
+#define XCHAL_HAVE_CP                   1       /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG                 8       /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16                1       /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005        0       /* vector floating-point pkg */
+#define XCHAL_HAVE_FP                   0       /* floating point pkg */
+#define XCHAL_HAVE_VECTRA1              0       /* Vectra I  pkg */
+#define XCHAL_HAVE_VECTRALX             0       /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFI2                0       /* HiFi2 Audio Engine pkg */
+
+
+/*----------------------------------------------------------------------
+                                MISC
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES   8       /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH          4       /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH                4       /* data width in bytes */
+/*  In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION  1       /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1       /* unaligned stores cause exc.*/
+
+#define XCHAL_SW_VERSION                701001  /* sw version of this header */
+
+#define XCHAL_CORE_ID                   "dc232b"        /* alphanum core name
+                                                   (CoreID) set in the Xtensa
+                                                   Processor Generator */
+
+#define XCHAL_CORE_DESCRIPTION          "Diamond 232L Standard Core Rev.B (LE)"
+#define XCHAL_BUILD_UNIQUE_ID           0x0000BEEF      /* 22-bit sw build ID */
+
+/*
+ *  These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0              0xC56307FE      /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1              0x0D40BEEF      /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME           "LX2.1.1"       /* full version name */
+#define XCHAL_HW_VERSION_MAJOR          2210    /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR          1       /* minor ver# of targeted hw */
+#define XCHAL_HW_VERSION                221001  /* major*100+minor */
+#define XCHAL_HW_REL_LX2                1
+#define XCHAL_HW_REL_LX2_1              1
+#define XCHAL_HW_REL_LX2_1_1            1
+#define XCHAL_HW_CONFIGID_RELIABLE      1
+/*  If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR      2210    /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR      1       /* minor v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION            221001  /* earliest targeted hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR      2210    /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR      1       /* minor v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION            221001  /* latest targeted hw */
+
+
+/*----------------------------------------------------------------------
+                                CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE           32      /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE           32      /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH          5       /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH          5       /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE               16384   /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE               16384   /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK       1       /* writeback feature */
+
+
+
+
+/****************************************************************************
+    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+                                CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF                  1       /* any outbound PIF present */
+
+/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */
+
+/*  Number of cache sets in log2(lines per way):  */
+#define XCHAL_ICACHE_SETWIDTH           7
+#define XCHAL_DCACHE_SETWIDTH           7
+
+/*  Cache set associativity (number of ways):  */
+#define XCHAL_ICACHE_WAYS               4
+#define XCHAL_DCACHE_WAYS               4
+
+/*  Cache features:  */
+#define XCHAL_ICACHE_LINE_LOCKABLE      1
+#define XCHAL_DCACHE_LINE_LOCKABLE      1
+#define XCHAL_ICACHE_ECC_PARITY         0
+#define XCHAL_DCACHE_ECC_PARITY         0
+
+/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */
+#define XCHAL_CA_BITS                   4
+
+
+/*----------------------------------------------------------------------
+                        INTERNAL I/D RAM/ROMs and XLMI
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM               0       /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM               0       /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM               0       /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM               0       /* number of core data RAMs */
+#define XCHAL_NUM_URAM                  0       /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI                  0       /* number of core XLMI ports */
+
+
+/*----------------------------------------------------------------------
+                        INTERRUPTS and TIMERS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS           1       /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS   1       /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI                  1       /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT               1       /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS                3       /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS            22      /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2       5       /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS         17      /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS             6       /* number of interrupt levels
+                                                   (not including level zero) */
+#define XCHAL_EXCM_LEVEL                3       /* level masked by PS.EXCM */
+        /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/*  Masks of interrupts at each interrupt level:  */
+#define XCHAL_INTLEVEL1_MASK            0x001F80FF
+#define XCHAL_INTLEVEL2_MASK            0x00000100
+#define XCHAL_INTLEVEL3_MASK            0x00200E00
+#define XCHAL_INTLEVEL4_MASK            0x00001000
+#define XCHAL_INTLEVEL5_MASK            0x00002000
+#define XCHAL_INTLEVEL6_MASK            0x00000000
+#define XCHAL_INTLEVEL7_MASK            0x00004000
+
+/*  Masks of interrupts at each range 1..n of interrupt levels:  */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK   0x001F80FF
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK   0x001F81FF
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK   0x003F8FFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK   0x003F9FFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK   0x003FBFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK   0x003FBFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK   0x003FFFFF
+
+/*  Level of each interrupt:  */
+#define XCHAL_INT0_LEVEL                1
+#define XCHAL_INT1_LEVEL                1
+#define XCHAL_INT2_LEVEL                1
+#define XCHAL_INT3_LEVEL                1
+#define XCHAL_INT4_LEVEL                1
+#define XCHAL_INT5_LEVEL                1
+#define XCHAL_INT6_LEVEL                1
+#define XCHAL_INT7_LEVEL                1
+#define XCHAL_INT8_LEVEL                2
+#define XCHAL_INT9_LEVEL                3
+#define XCHAL_INT10_LEVEL               3
+#define XCHAL_INT11_LEVEL               3
+#define XCHAL_INT12_LEVEL               4
+#define XCHAL_INT13_LEVEL               5
+#define XCHAL_INT14_LEVEL               7
+#define XCHAL_INT15_LEVEL               1
+#define XCHAL_INT16_LEVEL               1
+#define XCHAL_INT17_LEVEL               1
+#define XCHAL_INT18_LEVEL               1
+#define XCHAL_INT19_LEVEL               1
+#define XCHAL_INT20_LEVEL               1
+#define XCHAL_INT21_LEVEL               3
+#define XCHAL_DEBUGLEVEL                6       /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT     1       /* OCD external db interrupt */
+#define XCHAL_NMILEVEL                  7       /* NMI "level" (for use with
+                                                   EXCSAVE/EPS/EPC_n, RFI n) */
+
+/*  Type of each interrupt:  */
+#define XCHAL_INT0_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE         XTHAL_INTTYPE_TIMER
+#define XCHAL_INT7_TYPE         XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT8_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT9_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT10_TYPE        XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE        XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT12_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT13_TYPE        XTHAL_INTTYPE_TIMER
+#define XCHAL_INT14_TYPE        XTHAL_INTTYPE_NMI
+#define XCHAL_INT15_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT16_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT17_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT18_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT19_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT20_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT21_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+
+/*  Masks of interrupts for each type of interrupt:  */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000
+#define XCHAL_INTTYPE_MASK_SOFTWARE     0x00000880
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE  0x003F8000
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F
+#define XCHAL_INTTYPE_MASK_TIMER        0x00002440
+#define XCHAL_INTTYPE_MASK_NMI          0x00004000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR  0x00000000
+
+/*  Interrupt numbers assigned to specific interrupt sources:  */
+#define XCHAL_TIMER0_INTERRUPT          6       /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT          10      /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT          13      /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT          XTHAL_TIMER_UNCONFIGURED
+#define XCHAL_NMI_INTERRUPT             14      /* non-maskable interrupt */
+
+/*  Interrupt numbers for levels at which only one interrupt is configured:  */
+#define XCHAL_INTLEVEL2_NUM             8
+#define XCHAL_INTLEVEL4_NUM             12
+#define XCHAL_INTLEVEL5_NUM             13
+#define XCHAL_INTLEVEL7_NUM             14
+/*  (There are many interrupts each at level(s) 1, 3.)  */
+
+
+/*
+ *  External interrupt vectors/levels.
+ *  These macros describe how Xtensa processor interrupt numbers
+ *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ *  map to external BInterrupt<n> pins, for those interrupts
+ *  configured as external (level-triggered, edge-triggered, or NMI).
+ *  See the Xtensa processor databook for more details.
+ */
+
+/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
+#define XCHAL_EXTINT0_NUM               0       /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM               1       /* (intlevel 1) */
+#define XCHAL_EXTINT2_NUM               2       /* (intlevel 1) */
+#define XCHAL_EXTINT3_NUM               3       /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM               4       /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM               5       /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM               8       /* (intlevel 2) */
+#define XCHAL_EXTINT7_NUM               9       /* (intlevel 3) */
+#define XCHAL_EXTINT8_NUM               12      /* (intlevel 4) */
+#define XCHAL_EXTINT9_NUM               14      /* (intlevel 7) */
+#define XCHAL_EXTINT10_NUM              15      /* (intlevel 1) */
+#define XCHAL_EXTINT11_NUM              16      /* (intlevel 1) */
+#define XCHAL_EXTINT12_NUM              17      /* (intlevel 1) */
+#define XCHAL_EXTINT13_NUM              18      /* (intlevel 1) */
+#define XCHAL_EXTINT14_NUM              19      /* (intlevel 1) */
+#define XCHAL_EXTINT15_NUM              20      /* (intlevel 1) */
+#define XCHAL_EXTINT16_NUM              21      /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+                        EXCEPTIONS and VECTORS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION               2       /* Xtensa Exception Architecture
+                                                   number: 1 == XEA1 (old)
+                                                           2 == XEA2 (new)
+                                                           0 == XEAX (extern) */
+#define XCHAL_HAVE_XEA1                 0       /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2                 1       /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX                 0       /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS           1       /* exception option */
+#define XCHAL_HAVE_MEM_ECC_PARITY       0       /* local memory ECC/parity */
+#define XCHAL_HAVE_VECTOR_SELECT        1       /* relocatable vectors */
+#define XCHAL_HAVE_VECBASE              1       /* relocatable vectors */
+#define XCHAL_VECBASE_RESET_VADDR       0xD0000000  /* VECBASE reset value */
+#define XCHAL_VECBASE_RESET_PADDR       0x00000000
+#define XCHAL_RESET_VECBASE_OVERLAP     0
+
+#define XCHAL_RESET_VECTOR0_VADDR       0xFE000000
+#define XCHAL_RESET_VECTOR0_PADDR       0xFE000000
+#define XCHAL_RESET_VECTOR1_VADDR       0xD8000500
+#define XCHAL_RESET_VECTOR1_PADDR       0x00000500
+#define XCHAL_RESET_VECTOR_VADDR        0xFE000000
+#define XCHAL_RESET_VECTOR_PADDR        0xFE000000
+#define XCHAL_USER_VECOFS               0x00000340
+#define XCHAL_USER_VECTOR_VADDR         0xD0000340
+#define XCHAL_USER_VECTOR_PADDR         0x00000340
+#define XCHAL_KERNEL_VECOFS             0x00000300
+#define XCHAL_KERNEL_VECTOR_VADDR       0xD0000300
+#define XCHAL_KERNEL_VECTOR_PADDR       0x00000300
+#define XCHAL_DOUBLEEXC_VECOFS          0x000003C0
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR    0xD00003C0
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR    0x000003C0
+#define XCHAL_WINDOW_OF4_VECOFS         0x00000000
+#define XCHAL_WINDOW_UF4_VECOFS         0x00000040
+#define XCHAL_WINDOW_OF8_VECOFS         0x00000080
+#define XCHAL_WINDOW_UF8_VECOFS         0x000000C0
+#define XCHAL_WINDOW_OF12_VECOFS        0x00000100
+#define XCHAL_WINDOW_UF12_VECOFS        0x00000140
+#define XCHAL_WINDOW_VECTORS_VADDR      0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR      0x00000000
+#define XCHAL_INTLEVEL2_VECOFS          0x00000180
+#define XCHAL_INTLEVEL2_VECTOR_VADDR    0xD0000180
+#define XCHAL_INTLEVEL2_VECTOR_PADDR    0x00000180
+#define XCHAL_INTLEVEL3_VECOFS          0x000001C0
+#define XCHAL_INTLEVEL3_VECTOR_VADDR    0xD00001C0
+#define XCHAL_INTLEVEL3_VECTOR_PADDR    0x000001C0
+#define XCHAL_INTLEVEL4_VECOFS          0x00000200
+#define XCHAL_INTLEVEL4_VECTOR_VADDR    0xD0000200
+#define XCHAL_INTLEVEL4_VECTOR_PADDR    0x00000200
+#define XCHAL_INTLEVEL5_VECOFS          0x00000240
+#define XCHAL_INTLEVEL5_VECTOR_VADDR    0xD0000240
+#define XCHAL_INTLEVEL5_VECTOR_PADDR    0x00000240
+#define XCHAL_INTLEVEL6_VECOFS          0x00000280
+#define XCHAL_INTLEVEL6_VECTOR_VADDR    0xD0000280
+#define XCHAL_INTLEVEL6_VECTOR_PADDR    0x00000280
+#define XCHAL_DEBUG_VECOFS              XCHAL_INTLEVEL6_VECOFS
+#define XCHAL_DEBUG_VECTOR_VADDR        XCHAL_INTLEVEL6_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR        XCHAL_INTLEVEL6_VECTOR_PADDR
+#define XCHAL_NMI_VECOFS                0x000002C0
+#define XCHAL_NMI_VECTOR_VADDR          0xD00002C0
+#define XCHAL_NMI_VECTOR_PADDR          0x000002C0
+#define XCHAL_INTLEVEL7_VECOFS          XCHAL_NMI_VECOFS
+#define XCHAL_INTLEVEL7_VECTOR_VADDR    XCHAL_NMI_VECTOR_VADDR
+#define XCHAL_INTLEVEL7_VECTOR_PADDR    XCHAL_NMI_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+                                DEBUG
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD                  1       /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK                2       /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK                2       /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY        1       /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+                                MMU
+  ----------------------------------------------------------------------*/
+
+/*  See core-matmap.h header file for more details.  */
+
+#define XCHAL_HAVE_TLBS                 1       /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY         0       /* one way maps I+D 4GB vaddr */
+#define XCHAL_HAVE_IDENTITY_MAP         0       /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR            0       /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR      0       /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR        0       /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU              1       /* full MMU (with page table
+                                                   [autorefill] and protection)
+                                                   usable for an MMU-based OS */
+/*  If none of the above last 4 are set, it's a custom TLB configuration.  */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS             8       /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS                 4       /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS             2       /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
diff --git a/target-xtensa/core-dc232b/gdb-config.c b/target-xtensa/core-dc232b/gdb-config.c
new file mode 100644 (file)
index 0000000..13aba5e
--- /dev/null
@@ -0,0 +1,261 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,
+          0, 0, 0, 0, 0, 0)
+  XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(36, 144,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,
+          0, 0, 0, 0, 0, 0)
+  XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(38, 152,  3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(39, 156,  8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart,
+          0, 0, 0, 0, 0, 0)
+  XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,
+          0, 0, 0, 0, 0, 0)
+  XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,
+          0, 0, 0, 0, 0, 0)
+  XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,
+          0, 0, 0, 0, 0, 0)
+  XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo,
+          0, 0, 0, 0, 0, 0)
+  XTREG(46, 184,  8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi,
+          0, 0, 0, 0, 0, 0)
+  XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate,
+          0, 0, 0, 0, 0, 0)
+  XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(55, 220, 18, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(56, 224, 18, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(57, 228,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(58, 232, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(59, 236, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(60, 240, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(61, 244, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(62, 248, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(63, 252, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(64, 256, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(65, 260, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(66, 264, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(67, 268, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(68, 272, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(69, 276, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(70, 280, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(71, 284, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(72, 288, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(73, 292, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(74, 296, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(75, 300, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(76, 304, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(77, 308, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(78, 312, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(79, 316, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(80, 320, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(81, 324, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(82, 328, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(83, 332, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(84, 336, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(85, 340, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(86, 344,  8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(87, 348, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,
+          0, 0, 0, 0, 0, 0)
+  XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,
+          0, 0, 0, 0, 0, 0)
+  XTREG(89, 356, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,
+          0, 0, 0, 0, 0, 0)
+  XTREG(90, 360, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(91, 364, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(92, 368,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(93, 372, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(94, 376, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(95, 380, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(96, 384, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(97, 388,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel,
+          0, 0, 0, 0, 0, 0)
+  XTREG(98, 392, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(99, 396, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(100, 400, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(101, 404, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(102, 408, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(103, 412, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(104, 416, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(105, 420, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(106, 424, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(107, 428, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(108, 432, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(109, 436, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(110, 440, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(111, 444, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(112, 448, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(113, 452, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(114, 456, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(115, 460, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(116, 464, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(117, 468, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(118, 472, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(119, 476, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,
+          0, 0, 0, 0, 0, 0)
diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c
new file mode 100644 (file)
index 0000000..7650462
--- /dev/null
@@ -0,0 +1,22 @@
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+#include "core-fsf/core-isa.h"
+#include "overlay_tool.h"
+
+static const XtensaConfig fsf = {
+    .name = "fsf",
+    .options = XTENSA_OPTIONS,
+    /* GDB for this core is not supported currently */
+    .nareg = XCHAL_NUM_AREGS,
+    .ndepc = 1,
+    EXCEPTIONS_SECTION,
+    INTERRUPTS_SECTION,
+    TLB_SECTION,
+    .clock_freq_khz = 10000,
+};
+
+REGISTER_CORE(fsf)
diff --git a/target-xtensa/core-fsf/core-isa.h b/target-xtensa/core-fsf/core-isa.h
new file mode 100644 (file)
index 0000000..b519d6c
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Xtensa processor core configuration information.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2006 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_H
+#define _XTENSA_CORE_H
+
+
+/****************************************************************************
+            Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ *  configured, and a value of 0 otherwise.  These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+                                ISA
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE                   1       /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED             1       /* windowed registers option */
+#define XCHAL_NUM_AREGS                 64      /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2            6       /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE      3       /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG                1       /* debug option */
+#define XCHAL_HAVE_DENSITY              1       /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS                1       /* zero-overhead loops */
+#define XCHAL_HAVE_NSA                  1       /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX               0       /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT                 0       /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS               0       /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16                0       /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32                0       /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH           0       /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_L32R                 1       /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS    1       /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16              0       /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX                 1       /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES        0       /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES   0       /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12           1       /* (obsolete option) */
+#define XCHAL_HAVE_ABS                  1       /* ABS instruction */
+/*#define XCHAL_HAVE_POPC               0*/     /* POPC instruction */
+/*#define XCHAL_HAVE_CRC                0*/     /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC         0       /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I               0       /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION          0       /* speculation */
+#define XCHAL_HAVE_FULL_RESET           1       /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS              1       /* */
+#define XCHAL_NUM_MISC_REGS             2       /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER           0       /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID                 1       /* processor ID register */
+#define XCHAL_HAVE_THREADPTR            1       /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS             0       /* boolean registers */
+#define XCHAL_HAVE_CP                   0       /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG                 0       /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16                0       /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005        0       /* vector floating-point pkg */
+#define XCHAL_HAVE_FP                   0       /* floating point pkg */
+#define XCHAL_HAVE_VECTRA1              0       /* Vectra I  pkg */
+#define XCHAL_HAVE_VECTRALX             0       /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFI2                0       /* HiFi2 Audio Engine pkg */
+
+
+/*----------------------------------------------------------------------
+                                MISC
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES   4       /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH          4       /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH                4       /* data width in bytes */
+/*  In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION  1       /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1       /* unaligned stores cause exc.*/
+
+#define XCHAL_SW_VERSION                800002  /* sw version of this header */
+
+#define XCHAL_CORE_ID                   "fsf"   /* alphanum core name
+                                                   (CoreID) set in the Xtensa
+                                                   Processor Generator */
+
+#define XCHAL_CORE_DESCRIPTION          "fsf standard core"
+#define XCHAL_BUILD_UNIQUE_ID           0x00006700      /* 22-bit sw build ID */
+
+/*
+ *  These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0              0xC103C3FF      /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1              0x0C006700      /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME           "LX2.0.0"       /* full version name */
+#define XCHAL_HW_VERSION_MAJOR          2200    /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR          0       /* minor ver# of targeted hw */
+#define XTHAL_HW_REL_LX2                1
+#define XTHAL_HW_REL_LX2_0              1
+#define XTHAL_HW_REL_LX2_0_0            1
+#define XCHAL_HW_CONFIGID_RELIABLE      1
+/*  If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR      2200    /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR      0       /* minor v of earliest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR      2200    /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR      0       /* minor v of latest tgt hw */
+
+
+/*----------------------------------------------------------------------
+                                CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE           16      /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE           16      /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH          4       /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH          4       /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE               8192    /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE               8192    /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK       0       /* writeback feature */
+
+
+
+
+/****************************************************************************
+    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+                                CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF                  1       /* any outbound PIF present */
+
+/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */
+
+/*  Number of cache sets in log2(lines per way):  */
+#define XCHAL_ICACHE_SETWIDTH           8
+#define XCHAL_DCACHE_SETWIDTH           8
+
+/*  Cache set associativity (number of ways):  */
+#define XCHAL_ICACHE_WAYS               2
+#define XCHAL_DCACHE_WAYS               2
+
+/*  Cache features:  */
+#define XCHAL_ICACHE_LINE_LOCKABLE      0
+#define XCHAL_DCACHE_LINE_LOCKABLE      0
+#define XCHAL_ICACHE_ECC_PARITY         0
+#define XCHAL_DCACHE_ECC_PARITY         0
+
+/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */
+#define XCHAL_CA_BITS                   4
+
+
+/*----------------------------------------------------------------------
+                        INTERNAL I/D RAM/ROMs and XLMI
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM               0       /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM               0       /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM               0       /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM               0       /* number of core data RAMs */
+#define XCHAL_NUM_URAM                  0       /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI                  0       /* number of core XLMI ports */
+
+
+/*----------------------------------------------------------------------
+                        INTERRUPTS and TIMERS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS           1       /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS   1       /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI                  0       /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT               1       /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS                3       /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS            17      /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2       5       /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS         10      /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS             4       /* number of interrupt levels
+                                                   (not including level zero) */
+#define XCHAL_EXCM_LEVEL                1       /* level masked by PS.EXCM */
+        /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/*  Masks of interrupts at each interrupt level:  */
+#define XCHAL_INTLEVEL1_MASK            0x000064F9
+#define XCHAL_INTLEVEL2_MASK            0x00008902
+#define XCHAL_INTLEVEL3_MASK            0x00011204
+#define XCHAL_INTLEVEL4_MASK            0x00000000
+#define XCHAL_INTLEVEL5_MASK            0x00000000
+#define XCHAL_INTLEVEL6_MASK            0x00000000
+#define XCHAL_INTLEVEL7_MASK            0x00000000
+
+/*  Masks of interrupts at each range 1..n of interrupt levels:  */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK   0x000064F9
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK   0x0000EDFB
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK   0x0001FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK   0x0001FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK   0x0001FFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK   0x0001FFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK   0x0001FFFF
+
+/*  Level of each interrupt:  */
+#define XCHAL_INT0_LEVEL                1
+#define XCHAL_INT1_LEVEL                2
+#define XCHAL_INT2_LEVEL                3
+#define XCHAL_INT3_LEVEL                1
+#define XCHAL_INT4_LEVEL                1
+#define XCHAL_INT5_LEVEL                1
+#define XCHAL_INT6_LEVEL                1
+#define XCHAL_INT7_LEVEL                1
+#define XCHAL_INT8_LEVEL                2
+#define XCHAL_INT9_LEVEL                3
+#define XCHAL_INT10_LEVEL               1
+#define XCHAL_INT11_LEVEL               2
+#define XCHAL_INT12_LEVEL               3
+#define XCHAL_INT13_LEVEL               1
+#define XCHAL_INT14_LEVEL               1
+#define XCHAL_INT15_LEVEL               2
+#define XCHAL_INT16_LEVEL               3
+#define XCHAL_DEBUGLEVEL                4       /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT     0       /* OCD external db interrupt */
+
+/*  Type of each interrupt:  */
+#define XCHAL_INT0_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE         XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT8_TYPE         XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT9_TYPE         XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT10_TYPE        XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE        XTHAL_INTTYPE_TIMER
+#define XCHAL_INT12_TYPE        XTHAL_INTTYPE_TIMER
+#define XCHAL_INT13_TYPE        XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT14_TYPE        XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT15_TYPE        XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT16_TYPE        XTHAL_INTTYPE_SOFTWARE
+
+/*  Masks of interrupts for each type of interrupt:  */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000
+#define XCHAL_INTTYPE_MASK_SOFTWARE     0x0001E000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE  0x00000380
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F
+#define XCHAL_INTTYPE_MASK_TIMER        0x00001C00
+#define XCHAL_INTTYPE_MASK_NMI          0x00000000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR  0x00000000
+
+/*  Interrupt numbers assigned to specific interrupt sources:  */
+#define XCHAL_TIMER0_INTERRUPT          10      /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT          11      /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT          12      /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT          XTHAL_TIMER_UNCONFIGURED
+
+/*  Interrupt numbers for levels at which only one interrupt is configured:  */
+/*  (There are many interrupts each at level(s) 1, 2, 3.)  */
+
+
+/*
+ *  External interrupt vectors/levels.
+ *  These macros describe how Xtensa processor interrupt numbers
+ *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ *  map to external BInterrupt<n> pins, for those interrupts
+ *  configured as external (level-triggered, edge-triggered, or NMI).
+ *  See the Xtensa processor databook for more details.
+ */
+
+/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
+#define XCHAL_EXTINT0_NUM               0       /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM               1       /* (intlevel 2) */
+#define XCHAL_EXTINT2_NUM               2       /* (intlevel 3) */
+#define XCHAL_EXTINT3_NUM               3       /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM               4       /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM               5       /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM               6       /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM               7       /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM               8       /* (intlevel 2) */
+#define XCHAL_EXTINT9_NUM               9       /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+                        EXCEPTIONS and VECTORS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION               2       /* Xtensa Exception Architecture
+                                                   number: 1 == XEA1 (old)
+                                                           2 == XEA2 (new)
+                                                           0 == XEAX (extern) */
+#define XCHAL_HAVE_XEA1                 0       /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2                 1       /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX                 0       /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS           1       /* exception option */
+#define XCHAL_HAVE_MEM_ECC_PARITY       0       /* local memory ECC/parity */
+
+#define XCHAL_RESET_VECTOR_VADDR        0xFE000020
+#define XCHAL_RESET_VECTOR_PADDR        0xFE000020
+#define XCHAL_USER_VECTOR_VADDR         0xD0000220
+#define XCHAL_USER_VECTOR_PADDR         0x00000220
+#define XCHAL_KERNEL_VECTOR_VADDR       0xD0000200
+#define XCHAL_KERNEL_VECTOR_PADDR       0x00000200
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR    0xD0000290
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR    0x00000290
+#define XCHAL_WINDOW_VECTORS_VADDR      0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR      0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR    0xD0000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR    0x00000240
+#define XCHAL_INTLEVEL3_VECTOR_VADDR    0xD0000250
+#define XCHAL_INTLEVEL3_VECTOR_PADDR    0x00000250
+#define XCHAL_INTLEVEL4_VECTOR_VADDR    0xFE000520
+#define XCHAL_INTLEVEL4_VECTOR_PADDR    0xFE000520
+#define XCHAL_DEBUG_VECTOR_VADDR        XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR        XCHAL_INTLEVEL4_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+                                DEBUG
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD                  1       /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK                2       /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK                2       /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY        1       /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+                                MMU
+  ----------------------------------------------------------------------*/
+
+/*  See <xtensa/config/core-matmap.h> header file for more details.  */
+
+#define XCHAL_HAVE_TLBS                 1       /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY         0       /* one way maps I+D 4GB vaddr */
+#define XCHAL_HAVE_IDENTITY_MAP         0       /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR            0       /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR      0       /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR        0       /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU              1       /* full MMU (with page table
+                                                   [autorefill] and protection)
+                                                   usable for an MMU-based OS */
+/*  If none of the above last 4 are set, it's a custom TLB configuration.  */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS             8       /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS                 4       /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS             2       /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
new file mode 100644 (file)
index 0000000..0db83a6
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CPU_XTENSA_H
+#define CPU_XTENSA_H
+
+#define TARGET_LONG_BITS 32
+#define ELF_MACHINE EM_XTENSA
+
+#define CPUState struct CPUXtensaState
+
+#include "config.h"
+#include "qemu-common.h"
+#include "cpu-defs.h"
+
+#define TARGET_HAS_ICE 1
+
+#define NB_MMU_MODES 4
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define TARGET_PAGE_BITS 12
+
+enum {
+    /* Additional instructions */
+    XTENSA_OPTION_CODE_DENSITY,
+    XTENSA_OPTION_LOOP,
+    XTENSA_OPTION_EXTENDED_L32R,
+    XTENSA_OPTION_16_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IMUL_HIGH,
+    XTENSA_OPTION_32_BIT_IDIV,
+    XTENSA_OPTION_MAC16,
+    XTENSA_OPTION_MISC_OP_NSA,
+    XTENSA_OPTION_MISC_OP_MINMAX,
+    XTENSA_OPTION_MISC_OP_SEXT,
+    XTENSA_OPTION_MISC_OP_CLAMPS,
+    XTENSA_OPTION_COPROCESSOR,
+    XTENSA_OPTION_BOOLEAN,
+    XTENSA_OPTION_FP_COPROCESSOR,
+    XTENSA_OPTION_MP_SYNCHRO,
+    XTENSA_OPTION_CONDITIONAL_STORE,
+
+    /* Interrupts and exceptions */
+    XTENSA_OPTION_EXCEPTION,
+    XTENSA_OPTION_RELOCATABLE_VECTOR,
+    XTENSA_OPTION_UNALIGNED_EXCEPTION,
+    XTENSA_OPTION_INTERRUPT,
+    XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+    XTENSA_OPTION_TIMER_INTERRUPT,
+
+    /* Local memory */
+    XTENSA_OPTION_ICACHE,
+    XTENSA_OPTION_ICACHE_TEST,
+    XTENSA_OPTION_ICACHE_INDEX_LOCK,
+    XTENSA_OPTION_DCACHE,
+    XTENSA_OPTION_DCACHE_TEST,
+    XTENSA_OPTION_DCACHE_INDEX_LOCK,
+    XTENSA_OPTION_IRAM,
+    XTENSA_OPTION_IROM,
+    XTENSA_OPTION_DRAM,
+    XTENSA_OPTION_DROM,
+    XTENSA_OPTION_XLMI,
+    XTENSA_OPTION_HW_ALIGNMENT,
+    XTENSA_OPTION_MEMORY_ECC_PARITY,
+
+    /* Memory protection and translation */
+    XTENSA_OPTION_REGION_PROTECTION,
+    XTENSA_OPTION_REGION_TRANSLATION,
+    XTENSA_OPTION_MMU,
+
+    /* Other */
+    XTENSA_OPTION_WINDOWED_REGISTER,
+    XTENSA_OPTION_PROCESSOR_INTERFACE,
+    XTENSA_OPTION_MISC_SR,
+    XTENSA_OPTION_THREAD_POINTER,
+    XTENSA_OPTION_PROCESSOR_ID,
+    XTENSA_OPTION_DEBUG,
+    XTENSA_OPTION_TRACE_PORT,
+};
+
+enum {
+    THREADPTR = 231,
+    FCR = 232,
+    FSR = 233,
+};
+
+enum {
+    LBEG = 0,
+    LEND = 1,
+    LCOUNT = 2,
+    SAR = 3,
+    BR = 4,
+    LITBASE = 5,
+    SCOMPARE1 = 12,
+    ACCLO = 16,
+    ACCHI = 17,
+    MR = 32,
+    WINDOW_BASE = 72,
+    WINDOW_START = 73,
+    PTEVADDR = 83,
+    RASID = 90,
+    ITLBCFG = 91,
+    DTLBCFG = 92,
+    EPC1 = 177,
+    DEPC = 192,
+    EPS2 = 194,
+    EXCSAVE1 = 209,
+    CPENABLE = 224,
+    INTSET = 226,
+    INTCLEAR = 227,
+    INTENABLE = 228,
+    PS = 230,
+    VECBASE = 231,
+    EXCCAUSE = 232,
+    CCOUNT = 234,
+    PRID = 235,
+    EXCVADDR = 238,
+    CCOMPARE = 240,
+};
+
+#define PS_INTLEVEL 0xf
+#define PS_INTLEVEL_SHIFT 0
+
+#define PS_EXCM 0x10
+#define PS_UM 0x20
+
+#define PS_RING 0xc0
+#define PS_RING_SHIFT 6
+
+#define PS_OWB 0xf00
+#define PS_OWB_SHIFT 8
+
+#define PS_CALLINC 0x30000
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_LEN 2
+
+#define PS_WOE 0x40000
+
+#define MAX_NAREG 64
+#define MAX_NINTERRUPT 32
+#define MAX_NLEVEL 6
+#define MAX_NNMI 1
+#define MAX_NCCOMPARE 3
+#define MAX_TLB_WAY_SIZE 8
+
+#define REGION_PAGE_MASK 0xe0000000
+
+enum {
+    /* Static vectors */
+    EXC_RESET,
+    EXC_MEMORY_ERROR,
+
+    /* Dynamic vectors */
+    EXC_WINDOW_OVERFLOW4,
+    EXC_WINDOW_UNDERFLOW4,
+    EXC_WINDOW_OVERFLOW8,
+    EXC_WINDOW_UNDERFLOW8,
+    EXC_WINDOW_OVERFLOW12,
+    EXC_WINDOW_UNDERFLOW12,
+    EXC_IRQ,
+    EXC_KERNEL,
+    EXC_USER,
+    EXC_DOUBLE,
+    EXC_MAX
+};
+
+enum {
+    ILLEGAL_INSTRUCTION_CAUSE = 0,
+    SYSCALL_CAUSE,
+    INSTRUCTION_FETCH_ERROR_CAUSE,
+    LOAD_STORE_ERROR_CAUSE,
+    LEVEL1_INTERRUPT_CAUSE,
+    ALLOCA_CAUSE,
+    INTEGER_DIVIDE_BY_ZERO_CAUSE,
+    PRIVILEGED_CAUSE = 8,
+    LOAD_STORE_ALIGNMENT_CAUSE,
+
+    INSTR_PIF_DATA_ERROR_CAUSE = 12,
+    LOAD_STORE_PIF_DATA_ERROR_CAUSE,
+    INSTR_PIF_ADDR_ERROR_CAUSE,
+    LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
+
+    INST_TLB_MISS_CAUSE,
+    INST_TLB_MULTI_HIT_CAUSE,
+    INST_FETCH_PRIVILEGE_CAUSE,
+    INST_FETCH_PROHIBITED_CAUSE = 20,
+    LOAD_STORE_TLB_MISS_CAUSE = 24,
+    LOAD_STORE_TLB_MULTI_HIT_CAUSE,
+    LOAD_STORE_PRIVILEGE_CAUSE,
+    LOAD_PROHIBITED_CAUSE = 28,
+    STORE_PROHIBITED_CAUSE,
+
+    COPROCESSOR0_DISABLED = 32,
+};
+
+typedef enum {
+    INTTYPE_LEVEL,
+    INTTYPE_EDGE,
+    INTTYPE_NMI,
+    INTTYPE_SOFTWARE,
+    INTTYPE_TIMER,
+    INTTYPE_DEBUG,
+    INTTYPE_WRITE_ERR,
+    INTTYPE_MAX
+} interrupt_type;
+
+typedef struct xtensa_tlb_entry {
+    uint32_t vaddr;
+    uint32_t paddr;
+    uint8_t asid;
+    uint8_t attr;
+    bool variable;
+} xtensa_tlb_entry;
+
+typedef struct xtensa_tlb {
+    unsigned nways;
+    const unsigned way_size[10];
+    bool varway56;
+    unsigned nrefillentries;
+} xtensa_tlb;
+
+typedef struct XtensaGdbReg {
+    int targno;
+    int type;
+    int group;
+} XtensaGdbReg;
+
+typedef struct XtensaGdbRegmap {
+    int num_regs;
+    int num_core_regs;
+    /* PC + a + ar + sr + ur */
+    XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
+} XtensaGdbRegmap;
+
+typedef struct XtensaConfig {
+    const char *name;
+    uint64_t options;
+    XtensaGdbRegmap gdb_regmap;
+    unsigned nareg;
+    int excm_level;
+    int ndepc;
+    uint32_t vecbase;
+    uint32_t exception_vector[EXC_MAX];
+    unsigned ninterrupt;
+    unsigned nlevel;
+    uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t inttype_mask[INTTYPE_MAX];
+    struct {
+        uint32_t level;
+        interrupt_type inttype;
+    } interrupt[MAX_NINTERRUPT];
+    unsigned nccompare;
+    uint32_t timerint[MAX_NCCOMPARE];
+    unsigned nextint;
+    unsigned extint[MAX_NINTERRUPT];
+    uint32_t clock_freq_khz;
+
+    xtensa_tlb itlb;
+    xtensa_tlb dtlb;
+} XtensaConfig;
+
+typedef struct XtensaConfigList {
+    const XtensaConfig *config;
+    struct XtensaConfigList *next;
+} XtensaConfigList;
+
+typedef struct CPUXtensaState {
+    const XtensaConfig *config;
+    uint32_t regs[16];
+    uint32_t pc;
+    uint32_t sregs[256];
+    uint32_t uregs[256];
+    uint32_t phys_regs[MAX_NAREG];
+
+    xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
+    xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
+    unsigned autorefill_idx;
+
+    int pending_irq_level; /* level of last raised IRQ */
+    void **irq_inputs;
+    QEMUTimer *ccompare_timer;
+    uint32_t wake_ccount;
+    int64_t halt_clock;
+
+    int exception_taken;
+
+    CPU_COMMON
+} CPUXtensaState;
+
+#define cpu_init cpu_xtensa_init
+#define cpu_exec cpu_xtensa_exec
+#define cpu_gen_code cpu_xtensa_gen_code
+#define cpu_signal_handler cpu_xtensa_signal_handler
+#define cpu_list xtensa_cpu_list
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model);
+void xtensa_translate_init(void);
+int cpu_xtensa_exec(CPUXtensaState *s);
+void xtensa_register_core(XtensaConfigList *node);
+void do_interrupt(CPUXtensaState *s);
+void check_interrupts(CPUXtensaState *s);
+void xtensa_irq_init(CPUState *env);
+void *xtensa_get_extint(CPUState *env, unsigned extint);
+void xtensa_advance_ccount(CPUState *env, uint32_t d);
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active);
+void xtensa_rearm_ccompare_timer(CPUState *env);
+int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+void xtensa_sync_window_from_phys(CPUState *env);
+void xtensa_sync_phys_from_window(CPUState *env);
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way);
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei);
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access);
+
+
+#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
+
+static inline bool xtensa_option_bits_enabled(const XtensaConfig *config,
+        uint64_t opt)
+{
+    return (config->options & opt) != 0;
+}
+
+static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
+{
+    return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt));
+}
+
+static inline int xtensa_get_cintlevel(const CPUState *env)
+{
+    int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
+    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
+        level = env->config->excm_level;
+    }
+    return level;
+}
+
+static inline int xtensa_get_ring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+static inline int xtensa_get_cring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
+            (env->sregs[PS] & PS_EXCM) == 0) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUState *env,
+        bool dtlb, unsigned wi, unsigned ei)
+{
+    return dtlb ?
+        env->dtlb[wi] + ei :
+        env->itlb[wi] + ei;
+}
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _ring0
+#define MMU_MODE1_SUFFIX _ring1
+#define MMU_MODE2_SUFFIX _ring2
+#define MMU_MODE3_SUFFIX _ring3
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return xtensa_get_cring(env);
+}
+
+#define XTENSA_TBFLAG_RING_MASK 0x3
+#define XTENSA_TBFLAG_EXCM 0x4
+#define XTENSA_TBFLAG_LITBASE 0x8
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+    *flags |= xtensa_get_ring(env);
+    if (env->sregs[PS] & PS_EXCM) {
+        *flags |= XTENSA_TBFLAG_EXCM;
+    }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+            (env->sregs[LITBASE] & 1)) {
+        *flags |= XTENSA_TBFLAG_LITBASE;
+    }
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return env->pending_irq_level;
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
new file mode 100644 (file)
index 0000000..2a0cb1a
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
+
+static void reset_mmu(CPUState *env);
+
+void cpu_reset(CPUXtensaState *env)
+{
+    env->exception_taken = 0;
+    env->pc = env->config->exception_vector[EXC_RESET];
+    env->sregs[LITBASE] &= ~1;
+    env->sregs[PS] = xtensa_option_enabled(env->config,
+            XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+    env->sregs[VECBASE] = env->config->vecbase;
+
+    env->pending_irq_level = 0;
+    reset_mmu(env);
+}
+
+static struct XtensaConfigList *xtensa_cores;
+
+void xtensa_register_core(XtensaConfigList *node)
+{
+    node->next = xtensa_cores;
+    xtensa_cores = node;
+}
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
+{
+    static int tcg_inited;
+    CPUXtensaState *env;
+    const XtensaConfig *config = NULL;
+    XtensaConfigList *core = xtensa_cores;
+
+    for (; core; core = core->next)
+        if (strcmp(core->config->name, cpu_model) == 0) {
+            config = core->config;
+            break;
+        }
+
+    if (config == NULL) {
+        return NULL;
+    }
+
+    env = g_malloc0(sizeof(*env));
+    env->config = config;
+    cpu_exec_init(env);
+
+    if (!tcg_inited) {
+        tcg_inited = 1;
+        xtensa_translate_init();
+    }
+
+    xtensa_irq_init(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    XtensaConfigList *core = xtensa_cores;
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (; core; core = core->next) {
+        cpu_fprintf(f, "  %s\n", core->config->name);
+    }
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+
+    if (xtensa_get_physical_addr(env, addr, 0, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    if (xtensa_get_physical_addr(env, addr, 2, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    return ~0;
+}
+
+static uint32_t relocated_vector(CPUState *env, uint32_t vector)
+{
+    if (xtensa_option_enabled(env->config,
+                XTENSA_OPTION_RELOCATABLE_VECTOR)) {
+        return vector - env->config->vecbase + env->sregs[VECBASE];
+    } else {
+        return vector;
+    }
+}
+
+/*!
+ * Handle penging IRQ.
+ * For the high priority interrupt jump to the corresponding interrupt vector.
+ * For the level-1 interrupt convert it to either user, kernel or double
+ * exception with the 'level-1 interrupt' exception cause.
+ */
+static void handle_interrupt(CPUState *env)
+{
+    int level = env->pending_irq_level;
+
+    if (level > xtensa_get_cintlevel(env) &&
+            level <= env->config->nlevel &&
+            (env->config->level_mask[level] &
+             env->sregs[INTSET] &
+             env->sregs[INTENABLE])) {
+        if (level > 1) {
+            env->sregs[EPC1 + level - 1] = env->pc;
+            env->sregs[EPS2 + level - 2] = env->sregs[PS];
+            env->sregs[PS] =
+                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
+            env->pc = relocated_vector(env,
+                    env->config->interrupt_vector[level]);
+        } else {
+            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
+
+            if (env->sregs[PS] & PS_EXCM) {
+                if (env->config->ndepc) {
+                    env->sregs[DEPC] = env->pc;
+                } else {
+                    env->sregs[EPC1] = env->pc;
+                }
+                env->exception_index = EXC_DOUBLE;
+            } else {
+                env->sregs[EPC1] = env->pc;
+                env->exception_index =
+                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+            }
+            env->sregs[PS] |= PS_EXCM;
+        }
+        env->exception_taken = 1;
+    }
+}
+
+void do_interrupt(CPUState *env)
+{
+    if (env->exception_index == EXC_IRQ) {
+        qemu_log_mask(CPU_LOG_INT,
+                "%s(EXC_IRQ) level = %d, cintlevel = %d, "
+                "pc = %08x, a0 = %08x, ps = %08x, "
+                "intset = %08x, intenable = %08x, "
+                "ccount = %08x\n",
+                __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
+                env->pc, env->regs[0], env->sregs[PS],
+                env->sregs[INTSET], env->sregs[INTENABLE],
+                env->sregs[CCOUNT]);
+        handle_interrupt(env);
+    }
+
+    switch (env->exception_index) {
+    case EXC_WINDOW_OVERFLOW4:
+    case EXC_WINDOW_UNDERFLOW4:
+    case EXC_WINDOW_OVERFLOW8:
+    case EXC_WINDOW_UNDERFLOW8:
+    case EXC_WINDOW_OVERFLOW12:
+    case EXC_WINDOW_UNDERFLOW12:
+    case EXC_KERNEL:
+    case EXC_USER:
+    case EXC_DOUBLE:
+        qemu_log_mask(CPU_LOG_INT, "%s(%d) "
+                "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
+                __func__, env->exception_index,
+                env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
+        if (env->config->exception_vector[env->exception_index]) {
+            env->pc = relocated_vector(env,
+                    env->config->exception_vector[env->exception_index]);
+            env->exception_taken = 1;
+        } else {
+            qemu_log("%s(pc = %08x) bad exception_index: %d\n",
+                    __func__, env->pc, env->exception_index);
+        }
+        break;
+
+    case EXC_IRQ:
+        break;
+
+    default:
+        qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
+                __func__, env->pc, env->exception_index);
+        break;
+    }
+    check_interrupts(env);
+}
+
+static void reset_tlb_mmu_all_ways(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned wi, ei;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
+            entry[wi][ei].asid = 0;
+            entry[wi][ei].variable = true;
+        }
+    }
+}
+
+static void reset_tlb_mmu_ways56(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    if (!tlb->varway56) {
+        static const xtensa_tlb_entry way5[] = {
+            {
+                .vaddr = 0xd0000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xd8000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        static const xtensa_tlb_entry way6[] = {
+            {
+                .vaddr = 0xe0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xf0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        memcpy(entry[5], way5, sizeof(way5));
+        memcpy(entry[6], way6, sizeof(way6));
+    } else {
+        uint32_t ei;
+        for (ei = 0; ei < 8; ++ei) {
+            entry[6][ei].vaddr = ei << 29;
+            entry[6][ei].paddr = ei << 29;
+            entry[6][ei].asid = 1;
+            entry[6][ei].attr = 3;
+        }
+    }
+}
+
+static void reset_tlb_region_way0(CPUState *env,
+        xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned ei;
+
+    for (ei = 0; ei < 8; ++ei) {
+        entry[0][ei].vaddr = ei << 29;
+        entry[0][ei].paddr = ei << 29;
+        entry[0][ei].asid = 1;
+        entry[0][ei].attr = 2;
+        entry[0][ei].variable = true;
+    }
+}
+
+static void reset_mmu(CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        env->sregs[RASID] = 0x04030201;
+        env->sregs[ITLBCFG] = 0;
+        env->sregs[DTLBCFG] = 0;
+        env->autorefill_idx = 0;
+        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
+        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
+    } else {
+        reset_tlb_region_way0(env, env->itlb);
+        reset_tlb_region_way0(env, env->dtlb);
+    }
+}
+
+static unsigned get_ring(const CPUState *env, uint8_t asid)
+{
+    unsigned i;
+    for (i = 0; i < 4; ++i) {
+        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
+            return i;
+        }
+    }
+    return 0xff;
+}
+
+/*!
+ * Lookup xtensa TLB for the given virtual address.
+ * See ISA, 4.6.2.2
+ *
+ * \param pwi: [out] way index
+ * \param pei: [out] entry index
+ * \param pring: [out] access ring
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring)
+{
+    const xtensa_tlb *tlb = dtlb ?
+        &env->config->dtlb : &env->config->itlb;
+    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
+        env->dtlb : env->itlb;
+
+    int nhits = 0;
+    unsigned wi;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        uint32_t vpn;
+        uint32_t ei;
+        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
+        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
+            unsigned ring = get_ring(env, entry[wi][ei].asid);
+            if (ring < 4) {
+                if (++nhits > 1) {
+                    return dtlb ?
+                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
+                        INST_TLB_MULTI_HIT_CAUSE;
+                }
+                *pwi = wi;
+                *pei = ei;
+                *pring = ring;
+            }
+        }
+    }
+    return nhits ? 0 :
+        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
+}
+
+/*!
+ * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.5.10
+ */
+static unsigned mmu_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if (attr < 12) {
+        access |= PAGE_READ;
+        if (attr & 0x1) {
+            access |= PAGE_EXEC;
+        }
+        if (attr & 0x2) {
+            access |= PAGE_WRITE;
+        }
+    } else if (attr == 13) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    return access;
+}
+
+/*!
+ * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.3.3
+ */
+static unsigned region_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if ((attr < 6 && attr != 3) || attr == 14) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    if (attr > 0 && attr < 6) {
+        access |= PAGE_EXEC;
+    }
+    return access;
+}
+
+static bool is_access_granted(unsigned access, int is_write)
+{
+    switch (is_write) {
+    case 0:
+        return access & PAGE_READ;
+
+    case 1:
+        return access & PAGE_WRITE;
+
+    case 2:
+        return access & PAGE_EXEC;
+
+    default:
+        return 0;
+    }
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring);
+
+static int get_physical_addr_mmu(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi;
+    uint32_t ei;
+    uint8_t ring;
+    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
+
+    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
+            (mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
+            autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) {
+        ret = 0;
+    }
+    if (ret != 0) {
+        return ret;
+    }
+
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (ring < mmu_idx) {
+        return dtlb ?
+            LOAD_STORE_PRIVILEGE_CAUSE :
+            INST_FETCH_PRIVILEGE_CAUSE;
+    }
+
+    *access = mmu_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
+    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
+
+    return 0;
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring)
+{
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+    uint32_t pt_vaddr =
+        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
+    int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0,
+            &paddr, &page_size, &access);
+
+    qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
+            vaddr, ret ? ~0 : paddr);
+
+    if (ret == 0) {
+        uint32_t vpn;
+        uint32_t pte = ldl_phys(paddr);
+
+        *ring = (pte >> 4) & 0x3;
+        *wi = (++env->autorefill_idx) & 0x3;
+        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei);
+        xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte);
+        qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
+                __func__, vaddr, vpn, pte);
+    }
+    return ret;
+}
+
+static int get_physical_addr_region(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi = 0;
+    uint32_t ei = (vaddr >> 29) & 0x7;
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    *access = region_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
+    *page_size = ~REGION_PAGE_MASK + 1;
+
+    return 0;
+}
+
+/*!
+ * Convert virtual address to physical addr.
+ * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
+ *
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else if (xtensa_option_bits_enabled(env->config,
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
+        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else {
+        *paddr = vaddr;
+        *page_size = TARGET_PAGE_SIZE;
+        *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+}
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
new file mode 100644 (file)
index 0000000..09ab332
--- /dev/null
@@ -0,0 +1,32 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
+DEF_HELPER_1(nsa, i32, i32)
+DEF_HELPER_1(nsau, i32, i32)
+DEF_HELPER_1(wsr_windowbase, void, i32)
+DEF_HELPER_3(entry, void, i32, i32, i32)
+DEF_HELPER_1(retw, i32, i32)
+DEF_HELPER_1(rotw, void, i32)
+DEF_HELPER_2(window_check, void, i32, i32)
+DEF_HELPER_0(restore_owb, void)
+DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
+DEF_HELPER_1(simcall, void, env)
+DEF_HELPER_0(dump_state, void)
+
+DEF_HELPER_2(waiti, void, i32, i32)
+DEF_HELPER_2(timer_irq, void, i32, i32)
+DEF_HELPER_1(advance_ccount, void, i32)
+DEF_HELPER_1(check_interrupts, void, env)
+
+DEF_HELPER_1(wsr_rasid, void, i32)
+DEF_HELPER_2(rtlb0, i32, i32, i32)
+DEF_HELPER_2(rtlb1, i32, i32, i32)
+DEF_HELPER_2(itlb, void, i32, i32)
+DEF_HELPER_2(ptlb, i32, i32, i32)
+DEF_HELPER_3(wtlb, void, i32, i32, i32)
+
+#include "def-helper.h"
diff --git a/target-xtensa/machine.c b/target-xtensa/machine.c
new file mode 100644 (file)
index 0000000..ddeffb2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
new file mode 100644 (file)
index 0000000..0605611
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helpers.h"
+#include "host-utils.h"
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr);
+
+#define ALIGNED_ONLY
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+static void do_restore_state(void *pc_ptr)
+{
+    TranslationBlock *tb;
+    uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
+
+    tb = tb_find_pc(pc);
+    if (tb) {
+        cpu_restore_state(tb, env, pc);
+    }
+}
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
+            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
+        do_restore_state(retaddr);
+        HELPER(exception_cause_vaddr)(
+                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+    }
+}
+
+void tlb_fill(CPUState *env1, target_ulong vaddr, int is_write, int mmu_idx,
+              void *retaddr)
+{
+    CPUState *saved_env = env;
+
+    env = env1;
+    {
+        uint32_t paddr;
+        uint32_t page_size;
+        unsigned access;
+        int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
+                &paddr, &page_size, &access);
+
+        qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
+                vaddr, is_write, mmu_idx, paddr, ret);
+
+        if (ret == 0) {
+            tlb_set_page(env,
+                    vaddr & TARGET_PAGE_MASK,
+                    paddr & TARGET_PAGE_MASK,
+                    access, mmu_idx, page_size);
+        } else {
+            do_restore_state(retaddr);
+            HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
+        }
+    }
+    env = saved_env;
+}
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
+{
+    uint32_t vector;
+
+    env->pc = pc;
+    if (env->sregs[PS] & PS_EXCM) {
+        if (env->config->ndepc) {
+            env->sregs[DEPC] = pc;
+        } else {
+            env->sregs[EPC1] = pc;
+        }
+        vector = EXC_DOUBLE;
+    } else {
+        env->sregs[EPC1] = pc;
+        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+    }
+
+    env->sregs[EXCCAUSE] = cause;
+    env->sregs[PS] |= PS_EXCM;
+
+    HELPER(exception)(vector);
+}
+
+void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
+{
+    env->sregs[EXCVADDR] = vaddr;
+    HELPER(exception_cause)(pc, cause);
+}
+
+uint32_t HELPER(nsa)(uint32_t v)
+{
+    if (v & 0x80000000) {
+        v = ~v;
+    }
+    return v ? clz32(v) - 1 : 31;
+}
+
+uint32_t HELPER(nsau)(uint32_t v)
+{
+    return v ? clz32(v) : 32;
+}
+
+static void copy_window_from_phys(CPUState *env,
+        uint32_t window, uint32_t phys, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n1 * sizeof(uint32_t));
+        memcpy(env->regs + window + n1, env->phys_regs,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+static void copy_phys_from_window(CPUState *env,
+        uint32_t phys, uint32_t window, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n1 * sizeof(uint32_t));
+        memcpy(env->phys_regs, env->regs + window + n1,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+
+static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
+{
+    return a & (env->config->nareg / 4 - 1);
+}
+
+static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
+{
+    return 1 << windowbase_bound(a, env);
+}
+
+void xtensa_sync_window_from_phys(CPUState *env)
+{
+    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
+}
+
+void xtensa_sync_phys_from_window(CPUState *env)
+{
+    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
+}
+
+static void rotate_window_abs(uint32_t position)
+{
+    xtensa_sync_phys_from_window(env);
+    env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
+    xtensa_sync_window_from_phys(env);
+}
+
+static void rotate_window(uint32_t delta)
+{
+    rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
+}
+
+void HELPER(wsr_windowbase)(uint32_t v)
+{
+    rotate_window_abs(v);
+}
+
+void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
+{
+    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
+    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
+                pc, env->sregs[PS]);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
+        rotate_window(callinc);
+        env->sregs[WINDOW_START] |=
+            windowstart_bit(env->sregs[WINDOW_BASE], env);
+    }
+}
+
+void HELPER(window_check)(uint32_t pc, uint32_t w)
+{
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t m, n;
+
+    if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
+        return;
+    }
+
+    for (n = 1; ; ++n) {
+        if (n > w) {
+            return;
+        }
+        if (windowstart & windowstart_bit(windowbase + n, env)) {
+            break;
+        }
+    }
+
+    m = windowbase_bound(windowbase + n, env);
+    rotate_window(n);
+    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+    env->sregs[EPC1] = env->pc = pc;
+
+    if (windowstart & windowstart_bit(m + 1, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW4);
+    } else if (windowstart & windowstart_bit(m + 2, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW8);
+    } else {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW12);
+    }
+}
+
+uint32_t HELPER(retw)(uint32_t pc)
+{
+    int n = (env->regs[0] >> 30) & 0x3;
+    int m = 0;
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t ret_pc = 0;
+
+    if (windowstart & windowstart_bit(windowbase - 1, env)) {
+        m = 1;
+    } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
+        m = 2;
+    } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
+        m = 3;
+    }
+
+    if (n == 0 || (m != 0 && m != n) ||
+            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal retw instruction(pc = %08x), "
+                "PS = %08x, m = %d, n = %d\n",
+                pc, env->sregs[PS], m, n);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        int owb = windowbase;
+
+        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
+
+        rotate_window(-n);
+        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
+            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
+        } else {
+            /* window underflow */
+            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+                (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+            env->sregs[EPC1] = env->pc = pc;
+
+            if (n == 1) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
+            } else if (n == 2) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
+            } else if (n == 3) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
+            }
+        }
+    }
+    return ret_pc;
+}
+
+void HELPER(rotw)(uint32_t imm4)
+{
+    rotate_window(imm4);
+}
+
+void HELPER(restore_owb)(void)
+{
+    rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
+}
+
+void HELPER(movsp)(uint32_t pc)
+{
+    if ((env->sregs[WINDOW_START] &
+            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
+        HELPER(exception_cause)(pc, ALLOCA_CAUSE);
+    }
+}
+
+void HELPER(wsr_lbeg)(uint32_t v)
+{
+    if (env->sregs[LBEG] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LBEG] = v;
+    }
+}
+
+void HELPER(wsr_lend)(uint32_t v)
+{
+    if (env->sregs[LEND] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LEND] = v;
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+    }
+}
+
+void HELPER(dump_state)(void)
+{
+    cpu_dump_state(env, stderr, fprintf, 0);
+}
+
+void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
+{
+    env->pc = pc;
+    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
+        (intlevel << PS_INTLEVEL_SHIFT);
+    check_interrupts(env);
+    if (env->pending_irq_level) {
+        cpu_loop_exit(env);
+        return;
+    }
+
+    env->halt_clock = qemu_get_clock_ns(vm_clock);
+    env->halted = 1;
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        xtensa_rearm_ccompare_timer(env);
+    }
+    HELPER(exception)(EXCP_HLT);
+}
+
+void HELPER(timer_irq)(uint32_t id, uint32_t active)
+{
+    xtensa_timer_irq(env, id, active);
+}
+
+void HELPER(advance_ccount)(uint32_t d)
+{
+    xtensa_advance_ccount(env, d);
+}
+
+void HELPER(check_interrupts)(CPUState *env)
+{
+    check_interrupts(env);
+}
+
+void HELPER(wsr_rasid)(uint32_t v)
+{
+    v = (v & 0xffffff00) | 0x1;
+    if (v != env->sregs[RASID]) {
+        env->sregs[RASID] = v;
+        tlb_flush(env, 1);
+    }
+}
+
+static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
+{
+    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
+
+    switch (way) {
+    case 4:
+        return (tlbcfg >> 16) & 0x3;
+
+    case 5:
+        return (tlbcfg >> 20) & 0x1;
+
+    case 6:
+        return (tlbcfg >> 24) & 0x1;
+
+    default:
+        return 0;
+    }
+}
+
+/*!
+ * Get bit mask for the virtual address bits translated by the TLB way
+ */
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        switch (way) {
+        case 4:
+            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
+
+        case 5:
+            if (varway56) {
+                return 0xf8000000 << get_page_size(env, dtlb, way);
+            } else {
+                return 0xf8000000;
+            }
+
+        case 6:
+            if (varway56) {
+                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
+            } else {
+                return 0xf0000000;
+            }
+
+        default:
+            return 0xfffff000;
+        }
+    } else {
+        return REGION_PAGE_MASK;
+    }
+}
+
+/*!
+ * Get bit mask for the 'VPN without index' field.
+ * See ISA, 4.6.5.6, data format for RxTLB0
+ */
+static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (way < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        return is32 ? 0xffff8000 : 0xffffc000;
+    } else if (way == 4) {
+        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
+    } else if (way <= 6) {
+        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        if (varway56) {
+            return mask << (way == 5 ? 2 : 3);
+        } else {
+            return mask << 1;
+        }
+    } else {
+        return 0xfffff000;
+    }
+}
+
+/*!
+ * Split virtual address into VPN (with index) and entry index
+ * for the given TLB way
+ */
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei)
+{
+    bool varway56 = dtlb ?
+        env->config->dtlb.varway56 :
+        env->config->itlb.varway56;
+
+    if (!dtlb) {
+        wi &= 7;
+    }
+
+    if (wi < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
+    } else {
+        switch (wi) {
+        case 4:
+            {
+                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
+                *ei = (v >> eibase) & 0x3;
+            }
+            break;
+
+        case 5:
+            if (varway56) {
+                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x3;
+            } else {
+                *ei = (v >> 27) & 0x1;
+            }
+            break;
+
+        case 6:
+            if (varway56) {
+                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x7;
+            } else {
+                *ei = (v >> 28) & 0x1;
+            }
+            break;
+
+        default:
+            *ei = 0;
+            break;
+        }
+    }
+    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+}
+
+/*!
+ * Split TLB address into TLB way, entry index and VPN (with index).
+ * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
+ */
+static void split_tlb_entry_spec(uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        *wi = v & (dtlb ? 0xf : 0x7);
+        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
+    } else {
+        *vpn = v & REGION_PAGE_MASK;
+        *wi = 0;
+        *ei = (v >> 29) & 0x7;
+    }
+}
+
+static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    if (pwi) {
+        *pwi = wi;
+    }
+    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
+}
+
+uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
+    } else {
+        return v & REGION_PAGE_MASK;
+    }
+}
+
+uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
+{
+    const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
+    return entry->paddr | entry->attr;
+}
+
+void HELPER(itlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        if (entry->variable && entry->asid) {
+            tlb_flush_page(env, entry->vaddr);
+            entry->asid = 0;
+        }
+    }
+}
+
+uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        uint32_t ei;
+        uint8_t ring;
+        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
+
+        switch (res) {
+        case 0:
+            if (ring >= xtensa_get_ring(env)) {
+                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
+            }
+            break;
+
+        case INST_TLB_MULTI_HIT_CAUSE:
+        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
+            HELPER(exception_cause_vaddr)(env->pc, res, v);
+            break;
+        }
+        return 0;
+    } else {
+        return (v & REGION_PAGE_MASK) | 0x1;
+    }
+}
+
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
+{
+    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        if (entry->variable) {
+            if (entry->asid) {
+                tlb_flush_page(env, entry->vaddr);
+            }
+            entry->vaddr = vpn;
+            entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+            entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
+            entry->attr = pte & 0xf;
+        } else {
+            qemu_log("%s %d, %d, %d trying to set immutable entry\n",
+                    __func__, dtlb, wi, ei);
+        }
+    } else {
+        tlb_flush_page(env, entry->vaddr);
+        if (xtensa_option_enabled(env->config,
+                    XTENSA_OPTION_REGION_TRANSLATION)) {
+            entry->paddr = pte & REGION_PAGE_MASK;
+        }
+        entry->attr = pte & 0xf;
+    }
+}
+
+void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
+}
diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h
new file mode 100644 (file)
index 0000000..df19cc9
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \
+        a1, a2, a3, a4, a5, a6) \
+    { .targno = (no), .type = (typ), .group = (grp) },
+
+#ifndef XCHAL_HAVE_DIV32
+#define XCHAL_HAVE_DIV32 0
+#endif
+
+#ifndef XCHAL_UNALIGNED_LOAD_HW
+#define XCHAL_UNALIGNED_LOAD_HW 0
+#endif
+
+#ifndef XCHAL_HAVE_VECBASE
+#define XCHAL_HAVE_VECBASE 0
+#define XCHAL_VECBASE_RESET_VADDR 0
+#endif
+
+#define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0)
+
+#define XTENSA_OPTIONS ( \
+    XCHAL_OPTION(XCHAL_HAVE_DENSITY, XTENSA_OPTION_CODE_DENSITY) | \
+    XCHAL_OPTION(XCHAL_HAVE_LOOPS, XTENSA_OPTION_LOOP) | \
+    XCHAL_OPTION(XCHAL_HAVE_ABSOLUTE_LITERALS, XTENSA_OPTION_EXTENDED_L32R) | \
+    XCHAL_OPTION(XCHAL_HAVE_MUL16, XTENSA_OPTION_16_BIT_IMUL) | \
+    XCHAL_OPTION(XCHAL_HAVE_MUL32, XTENSA_OPTION_32_BIT_IMUL) | \
+    XCHAL_OPTION(XCHAL_HAVE_MUL32_HIGH, XTENSA_OPTION_32_BIT_IMUL_HIGH) | \
+    XCHAL_OPTION(XCHAL_HAVE_DIV32, XTENSA_OPTION_32_BIT_IDIV) | \
+    XCHAL_OPTION(XCHAL_HAVE_MAC16, XTENSA_OPTION_MAC16) | \
+    XCHAL_OPTION(XCHAL_HAVE_NSA, XTENSA_OPTION_MISC_OP_NSA) | \
+    XCHAL_OPTION(XCHAL_HAVE_MINMAX, XTENSA_OPTION_MISC_OP_MINMAX) | \
+    XCHAL_OPTION(XCHAL_HAVE_SEXT, XTENSA_OPTION_MISC_OP_SEXT) | \
+    XCHAL_OPTION(XCHAL_HAVE_CLAMPS, XTENSA_OPTION_MISC_OP_CLAMPS) | \
+    XCHAL_OPTION(XCHAL_HAVE_CP, XTENSA_OPTION_COPROCESSOR) | \
+    XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \
+    XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \
+    XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \
+    /* Interrupts and exceptions */ \
+    XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \
+    XCHAL_OPTION(XCHAL_HAVE_VECBASE, XTENSA_OPTION_RELOCATABLE_VECTOR) | \
+    XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_EXCEPTION, \
+        XTENSA_OPTION_UNALIGNED_EXCEPTION) | \
+    XCHAL_OPTION(XCHAL_HAVE_INTERRUPTS, XTENSA_OPTION_INTERRUPT) | \
+    XCHAL_OPTION(XCHAL_HAVE_HIGHPRI_INTERRUPTS, \
+        XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT) | \
+    XCHAL_OPTION(XCHAL_HAVE_CCOUNT, XTENSA_OPTION_TIMER_INTERRUPT) | \
+    /* Local memory, TODO */ \
+    XCHAL_OPTION(XCHAL_ICACHE_WAYS, XTENSA_OPTION_ICACHE) | \
+    XCHAL_OPTION(XCHAL_ICACHE_LINE_LOCKABLE, \
+            XTENSA_OPTION_ICACHE_INDEX_LOCK) | \
+    XCHAL_OPTION(XCHAL_DCACHE_WAYS, XTENSA_OPTION_DCACHE) | \
+    XCHAL_OPTION(XCHAL_DCACHE_LINE_LOCKABLE, \
+            XTENSA_OPTION_DCACHE_INDEX_LOCK) | \
+    XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_HW, XTENSA_OPTION_HW_ALIGNMENT) | \
+    /* Memory protection and translation */ \
+    XCHAL_OPTION(XCHAL_HAVE_MIMIC_CACHEATTR, \
+            XTENSA_OPTION_REGION_PROTECTION) | \
+    XCHAL_OPTION(XCHAL_HAVE_XLT_CACHEATTR, \
+            XTENSA_OPTION_REGION_TRANSLATION) | \
+    XCHAL_OPTION(XCHAL_HAVE_PTP_MMU, XTENSA_OPTION_MMU) | \
+    /* Other, TODO */ \
+    XCHAL_OPTION(XCHAL_HAVE_WINDOWED, XTENSA_OPTION_WINDOWED_REGISTER) | \
+    XCHAL_OPTION(XCHAL_HAVE_DEBUG, XTENSA_OPTION_DEBUG))
+
+#ifndef XCHAL_WINDOW_OF4_VECOFS
+#define XCHAL_WINDOW_OF4_VECOFS         0x00000000
+#define XCHAL_WINDOW_UF4_VECOFS         0x00000040
+#define XCHAL_WINDOW_OF8_VECOFS         0x00000080
+#define XCHAL_WINDOW_UF8_VECOFS         0x000000C0
+#define XCHAL_WINDOW_OF12_VECOFS        0x00000100
+#define XCHAL_WINDOW_UF12_VECOFS        0x00000140
+#endif
+
+#define EXCEPTION_VECTORS { \
+        [EXC_RESET] = XCHAL_RESET_VECTOR_VADDR, \
+        [EXC_WINDOW_OVERFLOW4] = XCHAL_WINDOW_OF4_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_WINDOW_UNDERFLOW4] = XCHAL_WINDOW_UF4_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_WINDOW_OVERFLOW8] = XCHAL_WINDOW_OF8_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_WINDOW_UNDERFLOW8] = XCHAL_WINDOW_UF8_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_WINDOW_OVERFLOW12] = XCHAL_WINDOW_OF12_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_WINDOW_UNDERFLOW12] = XCHAL_WINDOW_UF12_VECOFS + \
+            XCHAL_WINDOW_VECTORS_VADDR, \
+        [EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \
+        [EXC_USER] = XCHAL_USER_VECTOR_VADDR, \
+        [EXC_DOUBLE] = XCHAL_DOUBLEEXC_VECTOR_VADDR, \
+    }
+
+#define INTERRUPT_VECTORS { \
+        0, \
+        0, \
+        XCHAL_INTLEVEL2_VECTOR_VADDR, \
+        XCHAL_INTLEVEL3_VECTOR_VADDR, \
+        XCHAL_INTLEVEL4_VECTOR_VADDR, \
+        XCHAL_INTLEVEL5_VECTOR_VADDR, \
+        XCHAL_INTLEVEL6_VECTOR_VADDR, \
+        XCHAL_INTLEVEL7_VECTOR_VADDR, \
+    }
+
+#define LEVEL_MASKS { \
+        [1] = XCHAL_INTLEVEL1_MASK, \
+        [2] = XCHAL_INTLEVEL2_MASK, \
+        [3] = XCHAL_INTLEVEL3_MASK, \
+        [4] = XCHAL_INTLEVEL4_MASK, \
+        [5] = XCHAL_INTLEVEL5_MASK, \
+        [6] = XCHAL_INTLEVEL6_MASK, \
+        [7] = XCHAL_INTLEVEL7_MASK, \
+    }
+
+#define INTTYPE_MASKS { \
+        [INTTYPE_EDGE] = XCHAL_INTTYPE_MASK_EXTERN_EDGE, \
+        [INTTYPE_NMI] = XCHAL_INTTYPE_MASK_NMI, \
+        [INTTYPE_SOFTWARE] = XCHAL_INTTYPE_MASK_SOFTWARE, \
+    }
+
+#define XTHAL_INTTYPE_EXTERN_LEVEL INTTYPE_LEVEL
+#define XTHAL_INTTYPE_EXTERN_EDGE INTTYPE_EDGE
+#define XTHAL_INTTYPE_NMI INTTYPE_NMI
+#define XTHAL_INTTYPE_SOFTWARE INTTYPE_SOFTWARE
+#define XTHAL_INTTYPE_TIMER INTTYPE_TIMER
+#define XTHAL_INTTYPE_TBD1 INTTYPE_DEBUG
+#define XTHAL_INTTYPE_TBD2 INTTYPE_WRITE_ERR
+#define XTHAL_INTTYPE_WRITE_ERROR INTTYPE_WRITE_ERR
+
+
+#define INTERRUPT(i) { \
+        .level = XCHAL_INT ## i ## _LEVEL, \
+        .inttype = XCHAL_INT ## i ## _TYPE, \
+    }
+
+#define INTERRUPTS { \
+        [0] = INTERRUPT(0), \
+        [1] = INTERRUPT(1), \
+        [2] = INTERRUPT(2), \
+        [3] = INTERRUPT(3), \
+        [4] = INTERRUPT(4), \
+        [5] = INTERRUPT(5), \
+        [6] = INTERRUPT(6), \
+        [7] = INTERRUPT(7), \
+        [8] = INTERRUPT(8), \
+        [9] = INTERRUPT(9), \
+        [10] = INTERRUPT(10), \
+        [11] = INTERRUPT(11), \
+        [12] = INTERRUPT(12), \
+        [13] = INTERRUPT(13), \
+        [14] = INTERRUPT(14), \
+        [15] = INTERRUPT(15), \
+        [16] = INTERRUPT(16), \
+        [17] = INTERRUPT(17), \
+        [18] = INTERRUPT(18), \
+        [19] = INTERRUPT(19), \
+        [20] = INTERRUPT(20), \
+        [21] = INTERRUPT(21), \
+        [22] = INTERRUPT(22), \
+        [23] = INTERRUPT(23), \
+        [24] = INTERRUPT(24), \
+        [25] = INTERRUPT(25), \
+        [26] = INTERRUPT(26), \
+        [27] = INTERRUPT(27), \
+        [28] = INTERRUPT(28), \
+        [29] = INTERRUPT(29), \
+        [30] = INTERRUPT(30), \
+        [31] = INTERRUPT(31), \
+    }
+
+#define TIMERINTS { \
+        [0] = XCHAL_TIMER0_INTERRUPT, \
+        [1] = XCHAL_TIMER1_INTERRUPT, \
+        [2] = XCHAL_TIMER2_INTERRUPT, \
+    }
+
+#define EXTINTS { \
+        [0] = XCHAL_EXTINT0_NUM, \
+        [1] = XCHAL_EXTINT1_NUM, \
+        [2] = XCHAL_EXTINT2_NUM, \
+        [3] = XCHAL_EXTINT3_NUM, \
+        [4] = XCHAL_EXTINT4_NUM, \
+        [5] = XCHAL_EXTINT5_NUM, \
+        [6] = XCHAL_EXTINT6_NUM, \
+        [7] = XCHAL_EXTINT7_NUM, \
+        [8] = XCHAL_EXTINT8_NUM, \
+        [9] = XCHAL_EXTINT9_NUM, \
+        [10] = XCHAL_EXTINT10_NUM, \
+        [11] = XCHAL_EXTINT11_NUM, \
+        [12] = XCHAL_EXTINT12_NUM, \
+        [13] = XCHAL_EXTINT13_NUM, \
+        [14] = XCHAL_EXTINT14_NUM, \
+        [15] = XCHAL_EXTINT15_NUM, \
+        [16] = XCHAL_EXTINT16_NUM, \
+        [17] = XCHAL_EXTINT17_NUM, \
+        [18] = XCHAL_EXTINT18_NUM, \
+        [19] = XCHAL_EXTINT19_NUM, \
+        [20] = XCHAL_EXTINT20_NUM, \
+        [21] = XCHAL_EXTINT21_NUM, \
+        [22] = XCHAL_EXTINT22_NUM, \
+        [23] = XCHAL_EXTINT23_NUM, \
+        [24] = XCHAL_EXTINT24_NUM, \
+        [25] = XCHAL_EXTINT25_NUM, \
+        [26] = XCHAL_EXTINT26_NUM, \
+        [27] = XCHAL_EXTINT27_NUM, \
+        [28] = XCHAL_EXTINT28_NUM, \
+        [29] = XCHAL_EXTINT29_NUM, \
+        [30] = XCHAL_EXTINT30_NUM, \
+        [31] = XCHAL_EXTINT31_NUM, \
+    }
+
+#define EXCEPTIONS_SECTION \
+    .excm_level = XCHAL_EXCM_LEVEL, \
+    .vecbase = XCHAL_VECBASE_RESET_VADDR, \
+    .exception_vector = EXCEPTION_VECTORS
+
+#define INTERRUPTS_SECTION \
+    .ninterrupt = XCHAL_NUM_INTERRUPTS, \
+    .nlevel = XCHAL_NUM_INTLEVELS, \
+    .interrupt_vector = INTERRUPT_VECTORS, \
+    .level_mask = LEVEL_MASKS, \
+    .inttype_mask = INTTYPE_MASKS, \
+    .interrupt = INTERRUPTS, \
+    .nccompare = XCHAL_NUM_TIMERS, \
+    .timerint = TIMERINTS, \
+    .nextint = XCHAL_NUM_EXTINTERRUPTS, \
+    .extint = EXTINTS
+
+#define TLB_TEMPLATE(ways, refill_way_size, way56) { \
+        .nways = ways, \
+        .way_size = { \
+            (refill_way_size), (refill_way_size), \
+            (refill_way_size), (refill_way_size), \
+            4, (way56) ? 4 : 2, (way56) ? 8 : 2, 1, 1, 1, \
+        }, \
+        .varway56 = (way56), \
+        .nrefillentries = (refill_way_size) * 4, \
+    }
+
+#define ITLB(varway56) \
+    TLB_TEMPLATE(7, 1 << XCHAL_ITLB_ARF_ENTRIES_LOG2, varway56)
+
+#define DTLB(varway56) \
+    TLB_TEMPLATE(10, 1 << XCHAL_DTLB_ARF_ENTRIES_LOG2, varway56)
+
+#if XCHAL_HAVE_PTP_MMU
+#define TLB_SECTION \
+    .itlb = ITLB(XCHAL_HAVE_SPANNING_WAY), \
+    .dtlb = DTLB(XCHAL_HAVE_SPANNING_WAY)
+#else
+#endif
+
+#if (defined(TARGET_WORDS_BIGENDIAN) != 0) == (XCHAL_HAVE_BE != 0)
+#define REGISTER_CORE(core) \
+    static void __attribute__((constructor)) register_core(void) \
+    { \
+        static XtensaConfigList node = { \
+            .config = &core, \
+        }; \
+        xtensa_register_core(&node); \
+    }
+#else
+#define REGISTER_CORE(core)
+#endif
+
+
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 2
+#define XCHAL_INTLEVEL2_VECTOR_VADDR 0
+#endif
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 3
+#define XCHAL_INTLEVEL3_VECTOR_VADDR 0
+#endif
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 4
+#define XCHAL_INTLEVEL4_VECTOR_VADDR 0
+#endif
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 5
+#define XCHAL_INTLEVEL5_VECTOR_VADDR 0
+#endif
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 6
+#define XCHAL_INTLEVEL6_VECTOR_VADDR 0
+#endif
+#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 7
+#define XCHAL_INTLEVEL7_VECTOR_VADDR 0
+#endif
+
+
+#if XCHAL_NUM_INTERRUPTS <= 0
+#define XCHAL_INT0_LEVEL 0
+#define XCHAL_INT0_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 1
+#define XCHAL_INT1_LEVEL 0
+#define XCHAL_INT1_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 2
+#define XCHAL_INT2_LEVEL 0
+#define XCHAL_INT2_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 3
+#define XCHAL_INT3_LEVEL 0
+#define XCHAL_INT3_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 4
+#define XCHAL_INT4_LEVEL 0
+#define XCHAL_INT4_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 5
+#define XCHAL_INT5_LEVEL 0
+#define XCHAL_INT5_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 6
+#define XCHAL_INT6_LEVEL 0
+#define XCHAL_INT6_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 7
+#define XCHAL_INT7_LEVEL 0
+#define XCHAL_INT7_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 8
+#define XCHAL_INT8_LEVEL 0
+#define XCHAL_INT8_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 9
+#define XCHAL_INT9_LEVEL 0
+#define XCHAL_INT9_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 10
+#define XCHAL_INT10_LEVEL 0
+#define XCHAL_INT10_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 11
+#define XCHAL_INT11_LEVEL 0
+#define XCHAL_INT11_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 12
+#define XCHAL_INT12_LEVEL 0
+#define XCHAL_INT12_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 13
+#define XCHAL_INT13_LEVEL 0
+#define XCHAL_INT13_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 14
+#define XCHAL_INT14_LEVEL 0
+#define XCHAL_INT14_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 15
+#define XCHAL_INT15_LEVEL 0
+#define XCHAL_INT15_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 16
+#define XCHAL_INT16_LEVEL 0
+#define XCHAL_INT16_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 17
+#define XCHAL_INT17_LEVEL 0
+#define XCHAL_INT17_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 18
+#define XCHAL_INT18_LEVEL 0
+#define XCHAL_INT18_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 19
+#define XCHAL_INT19_LEVEL 0
+#define XCHAL_INT19_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 20
+#define XCHAL_INT20_LEVEL 0
+#define XCHAL_INT20_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 21
+#define XCHAL_INT21_LEVEL 0
+#define XCHAL_INT21_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 22
+#define XCHAL_INT22_LEVEL 0
+#define XCHAL_INT22_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 23
+#define XCHAL_INT23_LEVEL 0
+#define XCHAL_INT23_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 24
+#define XCHAL_INT24_LEVEL 0
+#define XCHAL_INT24_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 25
+#define XCHAL_INT25_LEVEL 0
+#define XCHAL_INT25_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 26
+#define XCHAL_INT26_LEVEL 0
+#define XCHAL_INT26_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 27
+#define XCHAL_INT27_LEVEL 0
+#define XCHAL_INT27_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 28
+#define XCHAL_INT28_LEVEL 0
+#define XCHAL_INT28_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 29
+#define XCHAL_INT29_LEVEL 0
+#define XCHAL_INT29_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 30
+#define XCHAL_INT30_LEVEL 0
+#define XCHAL_INT30_TYPE 0
+#endif
+#if XCHAL_NUM_INTERRUPTS <= 31
+#define XCHAL_INT31_LEVEL 0
+#define XCHAL_INT31_TYPE 0
+#endif
+
+
+#if XCHAL_NUM_EXTINTERRUPTS <= 0
+#define XCHAL_EXTINT0_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 1
+#define XCHAL_EXTINT1_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 2
+#define XCHAL_EXTINT2_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 3
+#define XCHAL_EXTINT3_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 4
+#define XCHAL_EXTINT4_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 5
+#define XCHAL_EXTINT5_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 6
+#define XCHAL_EXTINT6_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 7
+#define XCHAL_EXTINT7_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 8
+#define XCHAL_EXTINT8_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 9
+#define XCHAL_EXTINT9_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 10
+#define XCHAL_EXTINT10_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 11
+#define XCHAL_EXTINT11_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 12
+#define XCHAL_EXTINT12_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 13
+#define XCHAL_EXTINT13_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 14
+#define XCHAL_EXTINT14_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 15
+#define XCHAL_EXTINT15_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 16
+#define XCHAL_EXTINT16_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 17
+#define XCHAL_EXTINT17_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 18
+#define XCHAL_EXTINT18_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 19
+#define XCHAL_EXTINT19_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 20
+#define XCHAL_EXTINT20_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 21
+#define XCHAL_EXTINT21_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 22
+#define XCHAL_EXTINT22_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 23
+#define XCHAL_EXTINT23_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 24
+#define XCHAL_EXTINT24_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 25
+#define XCHAL_EXTINT25_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 26
+#define XCHAL_EXTINT26_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 27
+#define XCHAL_EXTINT27_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 28
+#define XCHAL_EXTINT28_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 29
+#define XCHAL_EXTINT29_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 30
+#define XCHAL_EXTINT30_NUM 0
+#endif
+#if XCHAL_NUM_EXTINTERRUPTS <= 31
+#define XCHAL_EXTINT31_NUM 0
+#endif
+
+
+#define XTHAL_TIMER_UNCONFIGURED 0
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
new file mode 100644 (file)
index 0000000..c81450d
--- /dev/null
@@ -0,0 +1,2552 @@
+/*
+ * Xtensa ISA:
+ * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+#include "sysemu.h"
+
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext {
+    const XtensaConfig *config;
+    TranslationBlock *tb;
+    uint32_t pc;
+    uint32_t next_pc;
+    int cring;
+    int ring;
+    uint32_t lbeg;
+    uint32_t lend;
+    TCGv_i32 litbase;
+    int is_jmp;
+    int singlestep_enabled;
+
+    bool sar_5bit;
+    bool sar_m32_5bit;
+    bool sar_m32_allocated;
+    TCGv_i32 sar_m32;
+
+    uint32_t ccount_delta;
+    unsigned used_window;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_pc;
+static TCGv_i32 cpu_R[16];
+static TCGv_i32 cpu_SR[256];
+static TCGv_i32 cpu_UR[256];
+
+#include "gen-icount.h"
+
+static const char * const sregnames[256] = {
+    [LBEG] = "LBEG",
+    [LEND] = "LEND",
+    [LCOUNT] = "LCOUNT",
+    [SAR] = "SAR",
+    [BR] = "BR",
+    [LITBASE] = "LITBASE",
+    [SCOMPARE1] = "SCOMPARE1",
+    [ACCLO] = "ACCLO",
+    [ACCHI] = "ACCHI",
+    [MR] = "MR0",
+    [MR + 1] = "MR1",
+    [MR + 2] = "MR2",
+    [MR + 3] = "MR3",
+    [WINDOW_BASE] = "WINDOW_BASE",
+    [WINDOW_START] = "WINDOW_START",
+    [PTEVADDR] = "PTEVADDR",
+    [RASID] = "RASID",
+    [ITLBCFG] = "ITLBCFG",
+    [DTLBCFG] = "DTLBCFG",
+    [EPC1] = "EPC1",
+    [EPC1 + 1] = "EPC2",
+    [EPC1 + 2] = "EPC3",
+    [EPC1 + 3] = "EPC4",
+    [EPC1 + 4] = "EPC5",
+    [EPC1 + 5] = "EPC6",
+    [EPC1 + 6] = "EPC7",
+    [DEPC] = "DEPC",
+    [EPS2] = "EPS2",
+    [EPS2 + 1] = "EPS3",
+    [EPS2 + 2] = "EPS4",
+    [EPS2 + 3] = "EPS5",
+    [EPS2 + 4] = "EPS6",
+    [EPS2 + 5] = "EPS7",
+    [EXCSAVE1] = "EXCSAVE1",
+    [EXCSAVE1 + 1] = "EXCSAVE2",
+    [EXCSAVE1 + 2] = "EXCSAVE3",
+    [EXCSAVE1 + 3] = "EXCSAVE4",
+    [EXCSAVE1 + 4] = "EXCSAVE5",
+    [EXCSAVE1 + 5] = "EXCSAVE6",
+    [EXCSAVE1 + 6] = "EXCSAVE7",
+    [CPENABLE] = "CPENABLE",
+    [INTSET] = "INTSET",
+    [INTCLEAR] = "INTCLEAR",
+    [INTENABLE] = "INTENABLE",
+    [PS] = "PS",
+    [VECBASE] = "VECBASE",
+    [EXCCAUSE] = "EXCCAUSE",
+    [CCOUNT] = "CCOUNT",
+    [PRID] = "PRID",
+    [EXCVADDR] = "EXCVADDR",
+    [CCOMPARE] = "CCOMPARE0",
+    [CCOMPARE + 1] = "CCOMPARE1",
+    [CCOMPARE + 2] = "CCOMPARE2",
+};
+
+static const char * const uregnames[256] = {
+    [THREADPTR] = "THREADPTR",
+    [FCR] = "FCR",
+    [FSR] = "FSR",
+};
+
+void xtensa_translate_init(void)
+{
+    static const char * const regnames[] = {
+        "ar0", "ar1", "ar2", "ar3",
+        "ar4", "ar5", "ar6", "ar7",
+        "ar8", "ar9", "ar10", "ar11",
+        "ar12", "ar13", "ar14", "ar15",
+    };
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
+            offsetof(CPUState, pc), "pc");
+
+    for (i = 0; i < 16; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                offsetof(CPUState, regs[i]),
+                regnames[i]);
+    }
+
+    for (i = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, sregs[i]),
+                    sregnames[i]);
+        }
+    }
+
+    for (i = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, uregs[i]),
+                    uregnames[i]);
+        }
+    }
+#define GEN_HELPER 2
+#include "helpers.h"
+}
+
+static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
+{
+    return xtensa_option_bits_enabled(dc->config, opt);
+}
+
+static inline bool option_enabled(DisasContext *dc, int opt)
+{
+    return xtensa_option_enabled(dc->config, opt);
+}
+
+static void init_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        dc->litbase = tcg_temp_local_new_i32();
+        tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000);
+    }
+}
+
+static void reset_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        tcg_temp_free(dc->litbase);
+    }
+}
+
+static void init_sar_tracker(DisasContext *dc)
+{
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+    dc->sar_m32_allocated = false;
+}
+
+static void reset_sar_tracker(DisasContext *dc)
+{
+    if (dc->sar_m32_allocated) {
+        tcg_temp_free(dc->sar_m32);
+    }
+}
+
+static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    tcg_gen_andi_i32(cpu_SR[SAR], sa, 0x1f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = true;
+    dc->sar_m32_5bit = false;
+}
+
+static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    TCGv_i32 tmp = tcg_const_i32(32);
+    if (!dc->sar_m32_allocated) {
+        dc->sar_m32 = tcg_temp_local_new_i32();
+        dc->sar_m32_allocated = true;
+    }
+    tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f);
+    tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32);
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = true;
+    tcg_temp_free(tmp);
+}
+
+static void gen_advance_ccount(DisasContext *dc)
+{
+    if (dc->ccount_delta > 0) {
+        TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
+        dc->ccount_delta = 0;
+        gen_helper_advance_ccount(tmp);
+        tcg_temp_free(tmp);
+    }
+}
+
+static void reset_used_window(DisasContext *dc)
+{
+    dc->used_window = 0;
+}
+
+static void gen_exception(DisasContext *dc, int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_advance_ccount(dc);
+    gen_helper_exception(tmp);
+    tcg_temp_free(tmp);
+}
+
+static void gen_exception_cause(DisasContext *dc, uint32_t cause)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
+    gen_helper_exception_cause(tpc, tcause);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+    if (cause == ILLEGAL_INSTRUCTION_CAUSE ||
+            cause == SYSCALL_CAUSE) {
+        dc->is_jmp = DISAS_UPDATE;
+    }
+}
+
+static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
+        TCGv_i32 vaddr)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
+    gen_helper_exception_cause_vaddr(tpc, tcause, vaddr);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+}
+
+static void gen_check_privilege(DisasContext *dc)
+{
+    if (dc->cring) {
+        gen_exception_cause(dc, PRIVILEGED_CAUSE);
+        dc->is_jmp = DISAS_UPDATE;
+    }
+}
+
+static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
+{
+    tcg_gen_mov_i32(cpu_pc, dest);
+    if (dc->singlestep_enabled) {
+        gen_exception(dc, EXCP_DEBUG);
+    } else {
+        gen_advance_ccount(dc);
+        if (slot >= 0) {
+            tcg_gen_goto_tb(slot);
+            tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+    }
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_jump(DisasContext *dc, TCGv dest)
+{
+    gen_jump_slot(dc, dest, -1);
+}
+
+static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_jump_slot(dc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
+static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest,
+        int slot)
+{
+    TCGv_i32 tcallinc = tcg_const_i32(callinc);
+
+    tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS],
+            tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN);
+    tcg_temp_free(tcallinc);
+    tcg_gen_movi_i32(cpu_R[callinc << 2],
+            (callinc << 30) | (dc->next_pc & 0x3fffffff));
+    gen_jump_slot(dc, dest, slot);
+}
+
+static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest)
+{
+    gen_callw_slot(dc, callinc, dest, -1);
+}
+
+static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_callw_slot(dc, callinc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
+static bool gen_check_loop_end(DisasContext *dc, int slot)
+{
+    if (option_enabled(dc, XTENSA_OPTION_LOOP) &&
+            !(dc->tb->flags & XTENSA_TBFLAG_EXCM) &&
+            dc->next_pc == dc->lend) {
+        int label = gen_new_label();
+
+        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
+        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
+        gen_jumpi(dc, dc->lbeg, slot);
+        gen_set_label(label);
+        gen_jumpi(dc, dc->next_pc, -1);
+        return true;
+    }
+    return false;
+}
+
+static void gen_jumpi_check_loop_end(DisasContext *dc, int slot)
+{
+    if (!gen_check_loop_end(dc, slot)) {
+        gen_jumpi(dc, dc->next_pc, slot);
+    }
+}
+
+static void gen_brcond(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
+{
+    int label = gen_new_label();
+
+    tcg_gen_brcond_i32(cond, t0, t1, label);
+    gen_jumpi_check_loop_end(dc, 0);
+    gen_set_label(label);
+    gen_jumpi(dc, dc->pc + offset, 1);
+}
+
+static void gen_brcondi(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, uint32_t t1, uint32_t offset)
+{
+    TCGv_i32 tmp = tcg_const_i32(t1);
+    gen_brcond(dc, cond, t0, tmp, offset);
+    tcg_temp_free(tmp);
+}
+
+static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    gen_advance_ccount(dc);
+    tcg_gen_mov_i32(d, cpu_SR[sr]);
+}
+
+static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10);
+    tcg_gen_or_i32(d, d, cpu_SR[sr]);
+    tcg_gen_andi_i32(d, d, 0xfffffffc);
+}
+
+static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    static void (* const rsr_handler[256])(DisasContext *dc,
+            TCGv_i32 d, uint32_t sr) = {
+        [CCOUNT] = gen_rsr_ccount,
+        [PTEVADDR] = gen_rsr_ptevaddr,
+    };
+
+    if (sregnames[sr]) {
+        if (rsr_handler[sr]) {
+            rsr_handler[sr](dc, d, sr);
+        } else {
+            tcg_gen_mov_i32(d, cpu_SR[sr]);
+        }
+    } else {
+        qemu_log("RSR %d not implemented, ", sr);
+    }
+}
+
+static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lbeg(s);
+}
+
+static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lend(s);
+}
+
+static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+}
+
+static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff);
+}
+
+static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_ext8s_i32(cpu_SR[sr], s);
+}
+
+static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_windowbase(v);
+    reset_used_window(dc);
+}
+
+static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
+    reset_used_window(dc);
+}
+
+static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000);
+}
+
+static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_rasid(v);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
+}
+
+static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v,
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_andi_i32(tmp, v,
+            dc->config->inttype_mask[INTTYPE_EDGE] |
+            dc->config->inttype_mask[INTTYPE_NMI] |
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp);
+    tcg_temp_free(tmp);
+    gen_helper_check_interrupts(cpu_env);
+}
+
+static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_mov_i32(cpu_SR[sr], v);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
+        PS_UM | PS_EXCM | PS_INTLEVEL;
+
+    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+        mask |= PS_RING;
+    }
+    tcg_gen_andi_i32(cpu_SR[sr], v, mask);
+    reset_used_window(dc);
+    gen_helper_check_interrupts(cpu_env);
+    /* This can change mmu index and tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+}
+
+static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t id = sr - CCOMPARE;
+    if (id < dc->config->nccompare) {
+        uint32_t int_bit = 1 << dc->config->timerint[id];
+        gen_advance_ccount(dc);
+        tcg_gen_mov_i32(cpu_SR[sr], v);
+        tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit);
+        gen_helper_check_interrupts(cpu_env);
+    }
+}
+
+static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    static void (* const wsr_handler[256])(DisasContext *dc,
+            uint32_t sr, TCGv_i32 v) = {
+        [LBEG] = gen_wsr_lbeg,
+        [LEND] = gen_wsr_lend,
+        [SAR] = gen_wsr_sar,
+        [BR] = gen_wsr_br,
+        [LITBASE] = gen_wsr_litbase,
+        [ACCHI] = gen_wsr_acchi,
+        [WINDOW_BASE] = gen_wsr_windowbase,
+        [WINDOW_START] = gen_wsr_windowstart,
+        [PTEVADDR] = gen_wsr_ptevaddr,
+        [RASID] = gen_wsr_rasid,
+        [ITLBCFG] = gen_wsr_tlbcfg,
+        [DTLBCFG] = gen_wsr_tlbcfg,
+        [INTSET] = gen_wsr_intset,
+        [INTCLEAR] = gen_wsr_intclear,
+        [INTENABLE] = gen_wsr_intenable,
+        [PS] = gen_wsr_ps,
+        [PRID] = gen_wsr_prid,
+        [CCOMPARE] = gen_wsr_ccompare,
+        [CCOMPARE + 1] = gen_wsr_ccompare,
+        [CCOMPARE + 2] = gen_wsr_ccompare,
+    };
+
+    if (sregnames[sr]) {
+        if (wsr_handler[sr]) {
+            wsr_handler[sr](dc, sr, s);
+        } else {
+            tcg_gen_mov_i32(cpu_SR[sr], s);
+        }
+    } else {
+        qemu_log("WSR %d not implemented, ", sr);
+    }
+}
+
+static void gen_load_store_alignment(DisasContext *dc, int shift,
+        TCGv_i32 addr, bool no_hw_alignment)
+{
+    if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) {
+        tcg_gen_andi_i32(addr, addr, ~0 << shift);
+    } else if (option_enabled(dc, XTENSA_OPTION_HW_ALIGNMENT) &&
+            no_hw_alignment) {
+        int label = gen_new_label();
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_andi_i32(tmp, addr, ~(~0 << shift));
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        gen_exception_cause_vaddr(dc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+        gen_set_label(label);
+        tcg_temp_free(tmp);
+    }
+}
+
+static void gen_waiti(DisasContext *dc, uint32_t imm4)
+{
+    TCGv_i32 pc = tcg_const_i32(dc->next_pc);
+    TCGv_i32 intlevel = tcg_const_i32(imm4);
+    gen_advance_ccount(dc);
+    gen_helper_waiti(pc, intlevel);
+    tcg_temp_free(pc);
+    tcg_temp_free(intlevel);
+}
+
+static void gen_window_check1(DisasContext *dc, unsigned r1)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
+        return;
+    }
+    if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) &&
+            r1 / 4 > dc->used_window) {
+        TCGv_i32 pc = tcg_const_i32(dc->pc);
+        TCGv_i32 w = tcg_const_i32(r1 / 4);
+
+        dc->used_window = r1 / 4;
+        gen_advance_ccount(dc);
+        gen_helper_window_check(pc, w);
+
+        tcg_temp_free(w);
+        tcg_temp_free(pc);
+    }
+}
+
+static void gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2)
+{
+    gen_window_check1(dc, r1 > r2 ? r1 : r2);
+}
+
+static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2,
+        unsigned r3)
+{
+    gen_window_check2(dc, r1, r2 > r3 ? r2 : r3);
+}
+
+static TCGv_i32 gen_mac16_m(TCGv_i32 v, bool hi, bool is_unsigned)
+{
+    TCGv_i32 m = tcg_temp_new_i32();
+
+    if (hi) {
+        (is_unsigned ? tcg_gen_shri_i32 : tcg_gen_sari_i32)(m, v, 16);
+    } else {
+        (is_unsigned ? tcg_gen_ext16u_i32 : tcg_gen_ext16s_i32)(m, v);
+    }
+    return m;
+}
+
+static void disas_xtensa_insn(DisasContext *dc)
+{
+#define HAS_OPTION_BITS(opt) do { \
+        if (!option_bits_enabled(dc, opt)) { \
+            qemu_log("Option is not enabled %s:%d\n", \
+                    __FILE__, __LINE__); \
+            goto invalid_opcode; \
+        } \
+    } while (0)
+
+#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt))
+
+#define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__)
+#define RESERVED() do { \
+        qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \
+                dc->pc, b0, b1, b2, __FILE__, __LINE__); \
+        goto invalid_opcode; \
+    } while (0)
+
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define OP0 (((b0) & 0xf0) >> 4)
+#define OP1 (((b2) & 0xf0) >> 4)
+#define OP2 ((b2) & 0xf)
+#define RRR_R ((b1) & 0xf)
+#define RRR_S (((b1) & 0xf0) >> 4)
+#define RRR_T ((b0) & 0xf)
+#else
+#define OP0 (((b0) & 0xf))
+#define OP1 (((b2) & 0xf))
+#define OP2 (((b2) & 0xf0) >> 4)
+#define RRR_R (((b1) & 0xf0) >> 4)
+#define RRR_S (((b1) & 0xf))
+#define RRR_T (((b0) & 0xf0) >> 4)
+#endif
+#define RRR_X ((RRR_R & 0x4) >> 2)
+#define RRR_Y ((RRR_T & 0x4) >> 2)
+#define RRR_W (RRR_R & 0x3)
+
+#define RRRN_R RRR_R
+#define RRRN_S RRR_S
+#define RRRN_T RRR_T
+
+#define RRI8_R RRR_R
+#define RRI8_S RRR_S
+#define RRI8_T RRR_T
+#define RRI8_IMM8 (b2)
+#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8)
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define RI16_IMM16 (((b1) << 8) | (b2))
+#else
+#define RI16_IMM16 (((b2) << 8) | (b1))
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALL_N (((b0) & 0xc) >> 2)
+#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
+#else
+#define CALL_N (((b0) & 0x30) >> 4)
+#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
+#endif
+#define CALL_OFFSET_SE \
+    (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET)
+
+#define CALLX_N CALL_N
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALLX_M ((b0) & 0x3)
+#else
+#define CALLX_M (((b0) & 0xc0) >> 6)
+#endif
+#define CALLX_S RRR_S
+
+#define BRI12_M CALLX_M
+#define BRI12_S RRR_S
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2))
+#else
+#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
+#endif
+#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12)
+
+#define BRI8_M BRI12_M
+#define BRI8_R RRI8_R
+#define BRI8_S RRI8_S
+#define BRI8_IMM8 RRI8_IMM8
+#define BRI8_IMM8_SE RRI8_IMM8_SE
+
+#define RSR_SR (b1)
+
+    uint8_t b0 = ldub_code(dc->pc);
+    uint8_t b1 = ldub_code(dc->pc + 1);
+    uint8_t b2 = ldub_code(dc->pc + 2);
+
+    static const uint32_t B4CONST[] = {
+        0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
+    static const uint32_t B4CONSTU[] = {
+        32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
+    if (OP0 >= 8) {
+        dc->next_pc = dc->pc + 2;
+        HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
+    } else {
+        dc->next_pc = dc->pc + 3;
+    }
+
+    switch (OP0) {
+    case 0: /*QRST*/
+        switch (OP1) {
+        case 0: /*RST0*/
+            switch (OP2) {
+            case 0: /*ST0*/
+                if ((RRR_R & 0xc) == 0x8) {
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                }
+
+                switch (RRR_R) {
+                case 0: /*SNM0*/
+                    switch (CALLX_M) {
+                    case 0: /*ILL*/
+                        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        break;
+
+                    case 1: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    case 2: /*JR*/
+                        switch (CALLX_N) {
+                        case 0: /*RET*/
+                        case 2: /*JX*/
+                            gen_window_check1(dc, CALLX_S);
+                            gen_jump(dc, cpu_R[CALLX_S]);
+                            break;
+
+                        case 1: /*RETWw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                                gen_advance_ccount(dc);
+                                gen_helper_retw(tmp, tmp);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        case 3: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 3: /*CALLX*/
+                        gen_window_check2(dc, CALLX_S, CALLX_N << 2);
+                        switch (CALLX_N) {
+                        case 0: /*CALLX0*/
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        case 1: /*CALLX4w*/
+                        case 2: /*CALLX8w*/
+                        case 3: /*CALLX12w*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                gen_callw(dc, CALLX_N, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+                        }
+                        break;
+                    }
+                    break;
+
+                case 1: /*MOVSPw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    gen_window_check2(dc, RRR_T, RRR_S);
+                    {
+                        TCGv_i32 pc = tcg_const_i32(dc->pc);
+                        gen_advance_ccount(dc);
+                        gen_helper_movsp(pc);
+                        tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
+                        tcg_temp_free(pc);
+                    }
+                    break;
+
+                case 2: /*SYNC*/
+                    switch (RRR_T) {
+                    case 0: /*ISYNC*/
+                        break;
+
+                    case 1: /*RSYNC*/
+                        break;
+
+                    case 2: /*ESYNC*/
+                        break;
+
+                    case 3: /*DSYNC*/
+                        break;
+
+                    case 8: /*EXCW*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        break;
+
+                    case 12: /*MEMW*/
+                        break;
+
+                    case 13: /*EXTW*/
+                        break;
+
+                    case 15: /*NOP*/
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+                    }
+                    break;
+
+                case 3: /*RFEIx*/
+                    switch (RRR_T) {
+                    case 0: /*RFETx*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        switch (RRR_S) {
+                        case 0: /*RFEx*/
+                            gen_check_privilege(dc);
+                            tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                            gen_helper_check_interrupts(cpu_env);
+                            gen_jump(dc, cpu_SR[EPC1]);
+                            break;
+
+                        case 1: /*RFUEx*/
+                            RESERVED();
+                            break;
+
+                        case 2: /*RFDEx*/
+                            gen_check_privilege(dc);
+                            gen_jump(dc, cpu_SR[
+                                    dc->config->ndepc ? DEPC : EPC1]);
+                            break;
+
+                        case 4: /*RFWOw*/
+                        case 5: /*RFWUw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            gen_check_privilege(dc);
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(1);
+
+                                tcg_gen_andi_i32(
+                                        cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                                tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]);
+
+                                if (RRR_S == 4) {
+                                    tcg_gen_andc_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                } else {
+                                    tcg_gen_or_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                }
+
+                                gen_helper_restore_owb();
+                                gen_helper_check_interrupts(cpu_env);
+                                gen_jump(dc, cpu_SR[EPC1]);
+
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        default: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 1: /*RFIx*/
+                        HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT);
+                        if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) {
+                            gen_check_privilege(dc);
+                            tcg_gen_mov_i32(cpu_SR[PS],
+                                    cpu_SR[EPS2 + RRR_S - 2]);
+                            gen_helper_check_interrupts(cpu_env);
+                            gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]);
+                        } else {
+                            qemu_log("RFI %d is illegal\n", RRR_S);
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
+                        break;
+
+                    case 2: /*RFME*/
+                        TBD();
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    }
+                    break;
+
+                case 4: /*BREAKx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    TBD();
+                    break;
+
+                case 5: /*SYSCALLx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    switch (RRR_S) {
+                    case 0: /*SYSCALLx*/
+                        gen_exception_cause(dc, SYSCALL_CAUSE);
+                        break;
+
+                    case 1: /*SIMCALL*/
+                        if (semihosting_enabled) {
+                            gen_check_privilege(dc);
+                            gen_helper_simcall(cpu_env);
+                        } else {
+                            qemu_log("SIMCALL but semihosting is disabled\n");
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
+                        break;
+
+                    default:
+                        RESERVED();
+                        break;
+                    }
+                    break;
+
+                case 6: /*RSILx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    gen_check_privilege(dc);
+                    gen_window_check1(dc, RRR_T);
+                    tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
+                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
+                    tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
+                    gen_helper_check_interrupts(cpu_env);
+                    gen_jumpi_check_loop_end(dc, 0);
+                    break;
+
+                case 7: /*WAITIx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    gen_check_privilege(dc);
+                    gen_waiti(dc, RRR_S);
+                    break;
+
+                case 8: /*ANY4p*/
+                case 9: /*ALL4p*/
+                case 10: /*ANY8p*/
+                case 11: /*ALL8p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    {
+                        const unsigned shift = (RRR_R & 2) ? 8 : 4;
+                        TCGv_i32 mask = tcg_const_i32(
+                                ((1 << shift) - 1) << RRR_S);
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+
+                        tcg_gen_and_i32(tmp, cpu_SR[BR], mask);
+                        if (RRR_R & 1) { /*ALL*/
+                            tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S);
+                        } else { /*ANY*/
+                            tcg_gen_add_i32(tmp, tmp, mask);
+                        }
+                        tcg_gen_shri_i32(tmp, tmp, RRR_S + shift);
+                        tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR],
+                                tmp, RRR_T, 1);
+                        tcg_temp_free(mask);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 1: /*AND*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 2: /*OR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 3: /*XOR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 4: /*ST1*/
+                switch (RRR_R) {
+                case 0: /*SSR*/
+                    gen_window_check1(dc, RRR_S);
+                    gen_right_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 1: /*SSL*/
+                    gen_window_check1(dc, RRR_S);
+                    gen_left_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 2: /*SSA8L*/
+                    gen_window_check1(dc, RRR_S);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 3: /*SSA8B*/
+                    gen_window_check1(dc, RRR_S);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_left_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 4: /*SSAI*/
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_S | ((RRR_T & 1) << 4));
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 6: /*RER*/
+                    TBD();
+                    break;
+
+                case 7: /*WER*/
+                    TBD();
+                    break;
+
+                case 8: /*ROTWw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    gen_check_privilege(dc);
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
+                        gen_helper_rotw(tmp);
+                        tcg_temp_free(tmp);
+                        reset_used_window(dc);
+                    }
+                    break;
+
+                case 14: /*NSAu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
+                    gen_window_check2(dc, RRR_S, RRR_T);
+                    gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                case 15: /*NSAUu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
+                    gen_window_check2(dc, RRR_S, RRR_T);
+                    gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 5: /*TLB*/
+                HAS_OPTION_BITS(
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION));
+                gen_check_privilege(dc);
+                gen_window_check2(dc, RRR_S, RRR_T);
+                {
+                    TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0);
+
+                    switch (RRR_R & 7) {
+                    case 3: /*RITLB0*/ /*RDTLB0*/
+                        gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 4: /*IITLB*/ /*IDTLB*/
+                        gen_helper_itlb(cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 5: /*PITLB*/ /*PDTLB*/
+                        tcg_gen_movi_i32(cpu_pc, dc->pc);
+                        gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 6: /*WITLB*/ /*WDTLB*/
+                        gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 7: /*RITLB1*/ /*RDTLB1*/
+                        gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    default:
+                        tcg_temp_free(dtlb);
+                        RESERVED();
+                        break;
+                    }
+                    tcg_temp_free(dtlb);
+                }
+                break;
+
+            case 6: /*RT0*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                switch (RRR_S) {
+                case 0: /*NEG*/
+                    tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    break;
+
+                case 1: /*ABS*/
+                    {
+                        int label = gen_new_label();
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        tcg_gen_brcondi_i32(
+                                TCG_COND_GE, cpu_R[RRR_R], 0, label);
+                        tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        gen_set_label(label);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 7: /*reserved*/
+                RESERVED();
+                break;
+
+            case 8: /*ADD*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 9: /*ADD**/
+            case 10:
+            case 11:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8);
+                    tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 12: /*SUB*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*SUB**/
+            case 14:
+            case 15:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12);
+                    tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+            }
+            break;
+
+        case 1: /*RST1*/
+            switch (OP2) {
+            case 0: /*SLLI*/
+            case 1:
+                gen_window_check2(dc, RRR_R, RRR_S);
+                tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S],
+                        32 - (RRR_T | ((OP2 & 1) << 4)));
+                break;
+
+            case 2: /*SRAI*/
+            case 3:
+                gen_window_check2(dc, RRR_R, RRR_T);
+                tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T],
+                        RRR_S | ((OP2 & 1) << 4));
+                break;
+
+            case 4: /*SRLI*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S);
+                break;
+
+            case 6: /*XSR*/
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    if (RSR_SR >= 64) {
+                        gen_check_privilege(dc);
+                    }
+                    gen_window_check1(dc, RRR_T);
+                    tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
+                    gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                    gen_wsr(dc, RSR_SR, tmp);
+                    tcg_temp_free(tmp);
+                    if (!sregnames[RSR_SR]) {
+                        TBD();
+                    }
+                }
+                break;
+
+                /*
+                 * Note: 64 bit ops are used here solely because SAR values
+                 * have range 0..63
+                 */
+#define gen_shift_reg(cmd, reg) do { \
+                    TCGv_i64 tmp = tcg_temp_new_i64(); \
+                    tcg_gen_extu_i32_i64(tmp, reg); \
+                    tcg_gen_##cmd##_i64(v, v, tmp); \
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], v); \
+                    tcg_temp_free_i64(v); \
+                    tcg_temp_free_i64(tmp); \
+                } while (0)
+
+#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR])
+
+            case 8: /*SRC*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 9: /*SRL*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                if (dc->sar_5bit) {
+                    tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 10: /*SLL*/
+                gen_window_check2(dc, RRR_R, RRR_S);
+                if (dc->sar_m32_5bit) {
+                    tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    TCGv_i32 s = tcg_const_i32(32);
+                    tcg_gen_sub_i32(s, s, cpu_SR[SAR]);
+                    tcg_gen_andi_i32(s, s, 0x3f);
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]);
+                    gen_shift_reg(shl, s);
+                    tcg_temp_free(s);
+                }
+                break;
+
+            case 11: /*SRA*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                if (dc->sar_5bit) {
+                    tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(sar);
+                }
+                break;
+#undef gen_shift
+#undef gen_shift_reg
+
+            case 12: /*MUL16U*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            case 13: /*MUL16S*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 2: /*RST2*/
+            if (OP2 >= 8) {
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+            }
+
+            if (OP2 >= 12) {
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV);
+                int label = gen_new_label();
+                tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label);
+                gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE);
+                gen_set_label(label);
+            }
+
+            switch (OP2) {
+#define BOOLEAN_LOGIC(fn, r, s, t) \
+                do { \
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); \
+                    TCGv_i32 tmp1 = tcg_temp_new_i32(); \
+                    TCGv_i32 tmp2 = tcg_temp_new_i32(); \
+                    \
+                    tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \
+                    tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \
+                    tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \
+                    tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \
+                    tcg_temp_free(tmp1); \
+                    tcg_temp_free(tmp2); \
+                } while (0)
+
+            case 0: /*ANDBp*/
+                BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 1: /*ANDBCp*/
+                BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 2: /*ORBp*/
+                BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 3: /*ORBCp*/
+                BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 4: /*XORBp*/
+                BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T);
+                break;
+
+#undef BOOLEAN_LOGIC
+
+            case 8: /*MULLi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+                tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 10: /*MULUHi*/
+            case 11: /*MULSHi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH);
+                {
+                    TCGv_i64 r = tcg_temp_new_i64();
+                    TCGv_i64 s = tcg_temp_new_i64();
+                    TCGv_i64 t = tcg_temp_new_i64();
+
+                    if (OP2 == 10) {
+                        tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]);
+                    }
+                    tcg_gen_mul_i64(r, s, t);
+                    tcg_gen_shri_i64(r, r, 32);
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r);
+
+                    tcg_temp_free_i64(r);
+                    tcg_temp_free_i64(s);
+                    tcg_temp_free_i64(t);
+                }
+                break;
+
+            case 12: /*QUOUi*/
+                tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*QUOSi*/
+            case 15: /*REMSi*/
+                {
+                    int label1 = gen_new_label();
+                    int label2 = gen_new_label();
+
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000,
+                            label1);
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff,
+                            label1);
+                    tcg_gen_movi_i32(cpu_R[RRR_R],
+                            OP2 == 13 ? 0x80000000 : 0);
+                    tcg_gen_br(label2);
+                    gen_set_label(label1);
+                    if (OP2 == 13) {
+                        tcg_gen_div_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_rem_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    }
+                    gen_set_label(label2);
+                }
+                break;
+
+            case 14: /*REMUi*/
+                tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 3: /*RST3*/
+            switch (OP2) {
+            case 0: /*RSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
+                gen_window_check1(dc, RRR_T);
+                gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
+                break;
+
+            case 1: /*WSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
+                gen_window_check1(dc, RRR_T);
+                gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
+                break;
+
+            case 2: /*SEXTu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP_SEXT);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    int shift = 24 - RRR_T;
+
+                    if (shift == 24) {
+                        tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else if (shift == 16) {
+                        tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift);
+                        tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift);
+                        tcg_temp_free(tmp);
+                    }
+                }
+                break;
+
+            case 3: /*CLAMPSu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP_CLAMPS);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    TCGv_i32 tmp1 = tcg_temp_new_i32();
+                    TCGv_i32 tmp2 = tcg_temp_new_i32();
+                    int label = gen_new_label();
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T);
+                    tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]);
+                    tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7));
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    tcg_gen_brcondi_i32(TCG_COND_EQ, tmp2, 0, label);
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31);
+                    tcg_gen_xori_i32(cpu_R[RRR_R], tmp1,
+                            0xffffffff >> (25 - RRR_T));
+
+                    gen_set_label(label);
+
+                    tcg_temp_free(tmp1);
+                    tcg_temp_free(tmp2);
+                }
+                break;
+
+            case 4: /*MINu*/
+            case 5: /*MAXu*/
+            case 6: /*MINUu*/
+            case 7: /*MAXUu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP_MINMAX);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_LE,
+                        TCG_COND_GE,
+                        TCG_COND_LEU,
+                        TCG_COND_GEU
+                    };
+                    int label = gen_new_label();
+
+                    if (RRR_R != RRR_T) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_S], cpu_R[RRR_T], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_T], cpu_R[RRR_S], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    }
+                    gen_set_label(label);
+                }
+                break;
+
+            case 8: /*MOVEQZ*/
+            case 9: /*MOVNEZ*/
+            case 10: /*MOVLTZ*/
+            case 11: /*MOVGEZ*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_NE,
+                        TCG_COND_EQ,
+                        TCG_COND_GE,
+                        TCG_COND_LT
+                    };
+                    int label = gen_new_label();
+                    tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                }
+                break;
+
+            case 12: /*MOVFp*/
+            case 13: /*MOVTp*/
+                HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    int label = gen_new_label();
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+
+                    tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T);
+                    tcg_gen_brcondi_i32(
+                            OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE,
+                            tmp, 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 14: /*RUR*/
+                gen_window_check1(dc, RRR_R);
+                {
+                    int st = (RRR_S << 4) + RRR_T;
+                    if (uregnames[st]) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]);
+                    } else {
+                        qemu_log("RUR %d not implemented, ", st);
+                        TBD();
+                    }
+                }
+                break;
+
+            case 15: /*WUR*/
+                gen_window_check1(dc, RRR_T);
+                {
+                    if (uregnames[RSR_SR]) {
+                        tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]);
+                    } else {
+                        qemu_log("WUR %d not implemented, ", RSR_SR);
+                        TBD();
+                    }
+                }
+                break;
+
+            }
+            break;
+
+        case 4: /*EXTUI*/
+        case 5:
+            gen_window_check2(dc, RRR_R, RRR_T);
+            {
+                int shiftimm = RRR_S | (OP1 << 4);
+                int maskimm = (1 << (OP2 + 1)) - 1;
+
+                TCGv_i32 tmp = tcg_temp_new_i32();
+                tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm);
+                tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm);
+                tcg_temp_free(tmp);
+            }
+            break;
+
+        case 6: /*CUST0*/
+            RESERVED();
+            break;
+
+        case 7: /*CUST1*/
+            RESERVED();
+            break;
+
+        case 8: /*LSCXp*/
+            HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+            TBD();
+            break;
+
+        case 9: /*LSC4*/
+            gen_window_check2(dc, RRR_S, RRR_T);
+            switch (OP2) {
+            case 0: /*L32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            case 4: /*S32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            default:
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 10: /*FP0*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
+            break;
+
+        case 11: /*FP1*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
+            break;
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    case 1: /*L32R*/
+        gen_window_check1(dc, RRR_T);
+        {
+            TCGv_i32 tmp = tcg_const_i32(
+                    ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ?
+                     0 : ((dc->pc + 3) & ~3)) +
+                    (0xfffc0000 | (RI16_IMM16 << 2)));
+
+            if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+                tcg_gen_add_i32(tmp, tmp, dc->litbase);
+            }
+            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring);
+            tcg_temp_free(tmp);
+        }
+        break;
+
+    case 2: /*LSAI*/
+#define gen_load_store(type, shift) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
+            if (shift) { \
+                gen_load_store_alignment(dc, shift, addr, false); \
+            } \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+        switch (RRI8_R) {
+        case 0: /*L8UI*/
+            gen_load_store(ld8u, 0);
+            break;
+
+        case 1: /*L16UI*/
+            gen_load_store(ld16u, 1);
+            break;
+
+        case 2: /*L32I*/
+            gen_load_store(ld32u, 2);
+            break;
+
+        case 4: /*S8I*/
+            gen_load_store(st8, 0);
+            break;
+
+        case 5: /*S16I*/
+            gen_load_store(st16, 1);
+            break;
+
+        case 6: /*S32I*/
+            gen_load_store(st32, 2);
+            break;
+
+        case 7: /*CACHEc*/
+            if (RRI8_T < 8) {
+                HAS_OPTION(XTENSA_OPTION_DCACHE);
+            }
+
+            switch (RRI8_T) {
+            case 0: /*DPFRc*/
+                break;
+
+            case 1: /*DPFWc*/
+                break;
+
+            case 2: /*DPFROc*/
+                break;
+
+            case 3: /*DPFWOc*/
+                break;
+
+            case 4: /*DHWBc*/
+                break;
+
+            case 5: /*DHWBIc*/
+                break;
+
+            case 6: /*DHIc*/
+                break;
+
+            case 7: /*DIIc*/
+                break;
+
+            case 8: /*DCEc*/
+                switch (OP1) {
+                case 0: /*DPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*DHUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*DIUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 4: /*DIWBc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                case 5: /*DIWBIc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 12: /*IPFc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 13: /*ICEc*/
+                switch (OP1) {
+                case 0: /*IPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*IHUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*IIUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 14: /*IHIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 15: /*IIIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 9: /*L16SI*/
+            gen_load_store(ld16s, 1);
+            break;
+#undef gen_load_store
+
+        case 10: /*MOVI*/
+            gen_window_check1(dc, RRI8_T);
+            tcg_gen_movi_i32(cpu_R[RRI8_T],
+                    RRI8_IMM8 | (RRI8_S << 8) |
+                    ((RRI8_S & 0x8) ? 0xfffff000 : 0));
+            break;
+
+#define gen_load_store_no_hw_align(type) do { \
+            TCGv_i32 addr = tcg_temp_local_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \
+            gen_load_store_alignment(dc, 2, addr, true); \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+        case 11: /*L32AIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/
+            break;
+
+        case 12: /*ADDI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE);
+            break;
+
+        case 13: /*ADDMI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8);
+            break;
+
+        case 14: /*S32C1Iy*/
+            HAS_OPTION(XTENSA_OPTION_CONDITIONAL_STORE);
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            {
+                int label = gen_new_label();
+                TCGv_i32 tmp = tcg_temp_local_new_i32();
+                TCGv_i32 addr = tcg_temp_local_new_i32();
+
+                tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]);
+                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
+                gen_load_store_alignment(dc, 2, addr, true);
+                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring);
+                tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T],
+                        cpu_SR[SCOMPARE1], label);
+
+                tcg_gen_qemu_st32(tmp, addr, dc->cring);
+
+                gen_set_label(label);
+                tcg_temp_free(addr);
+                tcg_temp_free(tmp);
+            }
+            break;
+
+        case 15: /*S32RIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store_no_hw_align(st32); /*TODO release?*/
+            break;
+#undef gen_load_store_no_hw_align
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    case 3: /*LSCIp*/
+        HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+        TBD();
+        break;
+
+    case 4: /*MAC16d*/
+        HAS_OPTION(XTENSA_OPTION_MAC16);
+        {
+            enum {
+                MAC16_UMUL = 0x0,
+                MAC16_MUL  = 0x4,
+                MAC16_MULA = 0x8,
+                MAC16_MULS = 0xc,
+                MAC16_NONE = 0xf,
+            } op = OP1 & 0xc;
+            bool is_m1_sr = (OP2 & 0x3) == 2;
+            bool is_m2_sr = (OP2 & 0xc) == 0;
+            uint32_t ld_offset = 0;
+
+            if (OP2 > 9) {
+                RESERVED();
+            }
+
+            switch (OP2 & 2) {
+            case 0: /*MACI?/MACC?*/
+                is_m1_sr = true;
+                ld_offset = (OP2 & 1) ? -4 : 4;
+
+                if (OP2 >= 8) { /*MACI/MACC*/
+                    if (OP1 == 0) { /*LDINC/LDDEC*/
+                        op = MAC16_NONE;
+                    } else {
+                        RESERVED();
+                    }
+                } else if (op != MAC16_MULA) { /*MULA.*.*.LDINC/LDDEC*/
+                    RESERVED();
+                }
+                break;
+
+            case 2: /*MACD?/MACA?*/
+                if (op == MAC16_UMUL && OP2 != 7) { /*UMUL only in MACAA*/
+                    RESERVED();
+                }
+                break;
+            }
+
+            if (op != MAC16_NONE) {
+                if (!is_m1_sr) {
+                    gen_window_check1(dc, RRR_S);
+                }
+                if (!is_m2_sr) {
+                    gen_window_check1(dc, RRR_T);
+                }
+            }
+
+            {
+                TCGv_i32 vaddr = tcg_temp_new_i32();
+                TCGv_i32 mem32 = tcg_temp_new_i32();
+
+                if (ld_offset) {
+                    gen_window_check1(dc, RRR_S);
+                    tcg_gen_addi_i32(vaddr, cpu_R[RRR_S], ld_offset);
+                    gen_load_store_alignment(dc, 2, vaddr, false);
+                    tcg_gen_qemu_ld32u(mem32, vaddr, dc->cring);
+                }
+                if (op != MAC16_NONE) {
+                    TCGv_i32 m1 = gen_mac16_m(
+                            is_m1_sr ? cpu_SR[MR + RRR_X] : cpu_R[RRR_S],
+                            OP1 & 1, op == MAC16_UMUL);
+                    TCGv_i32 m2 = gen_mac16_m(
+                            is_m2_sr ? cpu_SR[MR + 2 + RRR_Y] : cpu_R[RRR_T],
+                            OP1 & 2, op == MAC16_UMUL);
+
+                    if (op == MAC16_MUL || op == MAC16_UMUL) {
+                        tcg_gen_mul_i32(cpu_SR[ACCLO], m1, m2);
+                        if (op == MAC16_UMUL) {
+                            tcg_gen_movi_i32(cpu_SR[ACCHI], 0);
+                        } else {
+                            tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31);
+                        }
+                    } else {
+                        TCGv_i32 res = tcg_temp_new_i32();
+                        TCGv_i64 res64 = tcg_temp_new_i64();
+                        TCGv_i64 tmp = tcg_temp_new_i64();
+
+                        tcg_gen_mul_i32(res, m1, m2);
+                        tcg_gen_ext_i32_i64(res64, res);
+                        tcg_gen_concat_i32_i64(tmp,
+                                cpu_SR[ACCLO], cpu_SR[ACCHI]);
+                        if (op == MAC16_MULA) {
+                            tcg_gen_add_i64(tmp, tmp, res64);
+                        } else {
+                            tcg_gen_sub_i64(tmp, tmp, res64);
+                        }
+                        tcg_gen_trunc_i64_i32(cpu_SR[ACCLO], tmp);
+                        tcg_gen_shri_i64(tmp, tmp, 32);
+                        tcg_gen_trunc_i64_i32(cpu_SR[ACCHI], tmp);
+                        tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]);
+
+                        tcg_temp_free(res);
+                        tcg_temp_free_i64(res64);
+                        tcg_temp_free_i64(tmp);
+                    }
+                    tcg_temp_free(m1);
+                    tcg_temp_free(m2);
+                }
+                if (ld_offset) {
+                    tcg_gen_mov_i32(cpu_R[RRR_S], vaddr);
+                    tcg_gen_mov_i32(cpu_SR[MR + RRR_W], mem32);
+                }
+                tcg_temp_free(vaddr);
+                tcg_temp_free(mem32);
+            }
+        }
+        break;
+
+    case 5: /*CALLN*/
+        switch (CALL_N) {
+        case 0: /*CALL0*/
+            tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+            gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
+            break;
+
+        case 1: /*CALL4w*/
+        case 2: /*CALL8w*/
+        case 3: /*CALL12w*/
+            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            gen_window_check1(dc, CALL_N << 2);
+            gen_callwi(dc, CALL_N,
+                    (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
+            break;
+        }
+        break;
+
+    case 6: /*SI*/
+        switch (CALL_N) {
+        case 0: /*J*/
+            gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0);
+            break;
+
+        case 1: /*BZ*/
+            gen_window_check1(dc, BRI12_S);
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQZ*/
+                    TCG_COND_NE, /*BNEZ*/
+                    TCG_COND_LT, /*BLTZ*/
+                    TCG_COND_GE, /*BGEZ*/
+                };
+
+                gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0,
+                        4 + BRI12_IMM12_SE);
+            }
+            break;
+
+        case 2: /*BI0*/
+            gen_window_check1(dc, BRI8_S);
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQI*/
+                    TCG_COND_NE, /*BNEI*/
+                    TCG_COND_LT, /*BLTI*/
+                    TCG_COND_GE, /*BGEI*/
+                };
+
+                gen_brcondi(dc, cond[BRI8_M & 3],
+                        cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE);
+            }
+            break;
+
+        case 3: /*BI1*/
+            switch (BRI8_M) {
+            case 0: /*ENTRYw*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                {
+                    TCGv_i32 pc = tcg_const_i32(dc->pc);
+                    TCGv_i32 s = tcg_const_i32(BRI12_S);
+                    TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
+                    gen_advance_ccount(dc);
+                    gen_helper_entry(pc, s, imm);
+                    tcg_temp_free(imm);
+                    tcg_temp_free(s);
+                    tcg_temp_free(pc);
+                    reset_used_window(dc);
+                }
+                break;
+
+            case 1: /*B1*/
+                switch (BRI8_R) {
+                case 0: /*BFp*/
+                case 1: /*BTp*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S);
+                        gen_brcondi(dc,
+                                BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ,
+                                tmp, 0, 4 + RRI8_IMM8_SE);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 8: /*LOOP*/
+                case 9: /*LOOPNEZ*/
+                case 10: /*LOOPGTZ*/
+                    HAS_OPTION(XTENSA_OPTION_LOOP);
+                    gen_window_check1(dc, RRI8_S);
+                    {
+                        uint32_t lend = dc->pc + RRI8_IMM8 + 4;
+                        TCGv_i32 tmp = tcg_const_i32(lend);
+
+                        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
+                        tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
+                        gen_wsr_lend(dc, LEND, tmp);
+                        tcg_temp_free(tmp);
+
+                        if (BRI8_R > 8) {
+                            int label = gen_new_label();
+                            tcg_gen_brcondi_i32(
+                                    BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT,
+                                    cpu_R[RRI8_S], 0, label);
+                            gen_jumpi(dc, lend, 1);
+                            gen_set_label(label);
+                        }
+
+                        gen_jumpi(dc, dc->next_pc, 0);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 2: /*BLTUI*/
+            case 3: /*BGEUI*/
+                gen_window_check1(dc, BRI8_S);
+                gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU,
+                        cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE);
+                break;
+            }
+            break;
+
+        }
+        break;
+
+    case 7: /*B*/
+        {
+            TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ;
+
+            switch (RRI8_R & 7) {
+            case 0: /*BNONE*/ /*BANY*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 1: /*BEQ*/ /*BNE*/
+            case 2: /*BLT*/ /*BGE*/
+            case 3: /*BLTU*/ /*BGEU*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    static const TCGCond cond[] = {
+                        [1] = TCG_COND_EQ,
+                        [2] = TCG_COND_LT,
+                        [3] = TCG_COND_LTU,
+                        [9] = TCG_COND_NE,
+                        [10] = TCG_COND_GE,
+                        [11] = TCG_COND_GEU,
+                    };
+                    gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                }
+                break;
+
+            case 4: /*BALL*/ /*BNALL*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 5: /*BBC*/ /*BBS*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 bit = tcg_const_i32(1);
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f);
+                    tcg_gen_shl_i32(bit, bit, tmp);
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                    tcg_temp_free(bit);
+                }
+                break;
+
+            case 6: /*BBCI*/ /*BBSI*/
+            case 7:
+                gen_window_check1(dc, RRI8_S);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_S],
+                            1 << (((RRI8_R & 1) << 4) | RRI8_T));
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            }
+        }
+        break;
+
+#define gen_narrow_load_store(type) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRRN_S, RRRN_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
+            gen_load_store_alignment(dc, 2, addr, false); \
+            tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+    case 8: /*L32I.Nn*/
+        gen_narrow_load_store(ld32u);
+        break;
+
+    case 9: /*S32I.Nn*/
+        gen_narrow_load_store(st32);
+        break;
+#undef gen_narrow_load_store
+
+    case 10: /*ADD.Nn*/
+        gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T);
+        tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]);
+        break;
+
+    case 11: /*ADDI.Nn*/
+        gen_window_check2(dc, RRRN_R, RRRN_S);
+        tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1);
+        break;
+
+    case 12: /*ST2n*/
+        gen_window_check1(dc, RRRN_S);
+        if (RRRN_T < 8) { /*MOVI.Nn*/
+            tcg_gen_movi_i32(cpu_R[RRRN_S],
+                    RRRN_R | (RRRN_T << 4) |
+                    ((RRRN_T & 6) == 6 ? 0xffffff80 : 0));
+        } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/
+            TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ;
+
+            gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0,
+                    4 + (RRRN_R | ((RRRN_T & 3) << 4)));
+        }
+        break;
+
+    case 13: /*ST3n*/
+        switch (RRRN_R) {
+        case 0: /*MOV.Nn*/
+            gen_window_check2(dc, RRRN_S, RRRN_T);
+            tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]);
+            break;
+
+        case 15: /*S3*/
+            switch (RRRN_T) {
+            case 0: /*RET.Nn*/
+                gen_jump(dc, cpu_R[0]);
+                break;
+
+            case 1: /*RETW.Nn*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                {
+                    TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                    gen_advance_ccount(dc);
+                    gen_helper_retw(tmp, tmp);
+                    gen_jump(dc, tmp);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 2: /*BREAK.Nn*/
+                TBD();
+                break;
+
+            case 3: /*NOP.Nn*/
+                break;
+
+            case 6: /*ILL.Nn*/
+                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    default: /*reserved*/
+        RESERVED();
+        break;
+    }
+
+    gen_check_loop_end(dc, 0);
+    dc->pc = dc->next_pc;
+
+    return;
+
+invalid_opcode:
+    qemu_log("INVALID(pc = %08x)\n", dc->pc);
+    gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+#undef HAS_OPTION
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_i32(cpu_pc, dc->pc);
+                gen_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+static void gen_intermediate_code_internal(
+        CPUState *env, TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc;
+    int insn_count = 0;
+    int j, lj = -1;
+    uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    int max_insns = tb->cflags & CF_COUNT_MASK;
+    uint32_t pc_start = tb->pc;
+    uint32_t next_page_start =
+        (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    dc.config = env->config;
+    dc.singlestep_enabled = env->singlestep_enabled;
+    dc.tb = tb;
+    dc.pc = pc_start;
+    dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
+    dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring;
+    dc.lbeg = env->sregs[LBEG];
+    dc.lend = env->sregs[LEND];
+    dc.is_jmp = DISAS_NEXT;
+    dc.ccount_delta = 0;
+
+    init_litbase(&dc);
+    init_sar_tracker(&dc);
+    reset_used_window(&dc);
+
+    gen_icount_start();
+
+    if (env->singlestep_enabled && env->exception_taken) {
+        env->exception_taken = 0;
+        tcg_gen_movi_i32(cpu_pc, dc.pc);
+        gen_exception(&dc, EXCP_DEBUG);
+    }
+
+    do {
+        check_breakpoint(env, &dc);
+
+        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] = insn_count;
+        }
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc.pc);
+        }
+
+        ++dc.ccount_delta;
+
+        if (insn_count + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        disas_xtensa_insn(&dc);
+        ++insn_count;
+        if (env->singlestep_enabled) {
+            tcg_gen_movi_i32(cpu_pc, dc.pc);
+            gen_exception(&dc, EXCP_DEBUG);
+            break;
+        }
+    } while (dc.is_jmp == DISAS_NEXT &&
+            insn_count < max_insns &&
+            dc.pc < next_page_start &&
+            gen_opc_ptr < gen_opc_end);
+
+    reset_litbase(&dc);
+    reset_sar_tracker(&dc);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    if (dc.is_jmp == DISAS_NEXT) {
+        gen_jumpi(&dc, dc.pc, 0);
+    }
+    gen_icount_end(tb, insn_count);
+    *gen_opc_ptr = INDEX_op_end;
+
+    if (!search_pc) {
+        tb->size = dc.pc - pc_start;
+        tb->icount = insn_count;
+    }
+}
+
+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);
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+        int flags)
+{
+    int i, j;
+
+    cpu_fprintf(f, "PC=%08x\n\n", env->pc);
+
+    for (i = j = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", sregnames[i], env->sregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
+
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+
+    for (i = j = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", uregnames[i], env->uregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
+
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+
+    for (i = 0; i < 16; ++i) {
+        cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
+
+    cpu_fprintf(f, "\n");
+
+    for (i = 0; i < env->config->nareg; ++i) {
+        cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
index 660012281f64882faebf5638e5a532245f6a21f9..cfdfd96d0953cda6f8619799f4a0935ea363f6ac 100644 (file)
@@ -504,7 +504,15 @@ register.
 - Don't hesitate to use helpers for complicated or seldom used target
   instructions. There is little performance advantage in using TCG to
   implement target instructions taking more than about twenty TCG
-  instructions.
+  instructions. Note that this rule of thumb is more applicable to
+  helpers doing complex logic or arithmetic, where the C compiler has
+  scope to do a good job of optimisation; it is less relevant where
+  the instruction is mostly doing loads and stores, and in those cases
+  inline TCG may still be faster for longer sequences.
+
+- The hard limit on the number of TCG instructions you can generate
+  per target instruction is set by MAX_OP_PER_INSTR in exec-all.h --
+  you cannot exceed this without risking a buffer overrun.
 
 - Use the 'discard' instruction if you know that TCG won't be able to
   prove that a given global is "dead" at a given program point. The
index 918e2f73cb811e566b13dd3ac65e2147f1d371b7..e05a64f75c649bbc56b46b290c837a6b8ffbc0fd 100644 (file)
@@ -375,6 +375,12 @@ static inline void tcg_out_blx(TCGContext *s, int cond, int rn)
     tcg_out32(s, (cond << 28) | 0x012fff30 | rn);
 }
 
+static inline void tcg_out_blx_imm(TCGContext *s, int32_t offset)
+{
+    tcg_out32(s, 0xfa000000 | ((offset & 2) << 23) |
+                (((offset - 8) >> 2) & 0x00ffffff));
+}
+
 static inline void tcg_out_dat_reg(TCGContext *s,
                 int cond, int opc, int rd, int rn, int rm, int shift)
 {
@@ -840,6 +846,11 @@ static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
 {
     int32_t val;
 
+    if (addr & 1) {
+        /* goto to a Thumb destination isn't supported */
+        tcg_abort();
+    }
+
     val = addr - (tcg_target_long) s->code_ptr;
     if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
         tcg_out_b(s, cond, val);
@@ -860,14 +871,22 @@ static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
     }
 }
 
-static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr)
+static inline void tcg_out_call(TCGContext *s, uint32_t addr)
 {
     int32_t val;
 
     val = addr - (tcg_target_long) s->code_ptr;
-    if (val < 0x01fffffd && val > -0x01fffffd)
-        tcg_out_bl(s, cond, val);
-    else {
+    if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) {
+        if (addr & 1) {
+            /* Use BLX if the target is in Thumb mode */
+            if (!use_armv5_instructions) {
+                tcg_abort();
+            }
+            tcg_out_blx_imm(s, val);
+        } else {
+            tcg_out_bl(s, COND_AL, val);
+        }
+    } else {
 #if 1
         tcg_abort();
 #else
@@ -1063,8 +1082,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
                     TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
     tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
 # endif
-    tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_ld_helpers[s_bits] -
-                    (tcg_target_long) s->code_ptr);
+    tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
 
     switch (opc) {
     case 0 | 4:
@@ -1330,8 +1348,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
     }
 # endif
 
-    tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_st_helpers[s_bits] -
-                    (tcg_target_long) s->code_ptr);
+    tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
     if (opc == 3)
         tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
 
@@ -1443,7 +1460,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
     case INDEX_op_call:
         if (const_args[0])
-            tcg_out_call(s, COND_AL, args[0]);
+            tcg_out_call(s, args[0]);
         else
             tcg_out_callr(s, COND_AL, args[0]);
         break;
@@ -1787,57 +1804,48 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
 
     tcg_add_target_add_op_defs(arm_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
 
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
-                int arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
 }
 
-static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
-                int arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_st32(s, COND_AL, arg, arg1, arg2);
 }
 
-static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
-    if (val > 0)
-        if (val < 0x100)
-            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
-        else
-            tcg_abort();
-    else if (val < 0) {
-        if (val > -0x100)
-            tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
-        else
-            tcg_abort();
-    }
-}
-
-static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+                               TCGReg ret, TCGReg arg)
 {
     tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
 }
 
 static inline void tcg_out_movi(TCGContext *s, TCGType type,
-                int ret, tcg_target_long arg)
+                                TCGReg ret, tcg_target_long arg)
 {
     tcg_out_movi32(s, COND_AL, ret, arg);
 }
 
 static void tcg_target_qemu_prologue(TCGContext *s)
 {
-    /* There is no need to save r7, it is used to store the address
-       of the env structure and is not modified by GCC. */
+    /* Calling convention requires us to save r4-r11 and lr;
+     * save also r12 to maintain stack 8-alignment.
+     */
+
+    /* stmdb sp!, { r4 - r12, lr } */
+    tcg_out32(s, (COND_AL << 28) | 0x092d5ff0);
 
-    /* stmdb sp!, { r4 - r6, r8 - r11, lr } */
-    tcg_out32(s, (COND_AL << 28) | 0x092d4f70);
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
 
-    tcg_out_bx(s, COND_AL, TCG_REG_R0);
+    tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]);
     tb_ret_addr = s->code_ptr;
 
-    /* ldmia sp!, { r4 - r6, r8 - r11, pc } */
-    tcg_out32(s, (COND_AL << 28) | 0x08bd8f70);
+    /* ldmia sp!, { r4 - r12, pc } */
+    tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0);
 }
index d8d7d948ce166785eb2f468c04824b1ac6423aa7..48586c3e601831d7fdeee952fd00fd9924db96cd 100644 (file)
  */
 #define TCG_TARGET_ARM 1
 
-#define TCG_TARGET_REG_BITS 32
 #undef TCG_TARGET_WORDS_BIGENDIAN
 #undef TCG_TARGET_STACK_GROWSUP
 
-enum {
+typedef enum {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
     TCG_REG_R2,
@@ -45,7 +44,7 @@ enum {
     TCG_REG_R13,
     TCG_REG_R14,
     TCG_REG_PC,
-};
+} TCGReg;
 
 #define TCG_TARGET_NB_REGS 16
 
@@ -58,20 +57,22 @@ enum {
 #define TCG_TARGET_CALL_STACK_OFFSET   0
 
 /* optional instructions */
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#undef TCG_TARGET_HAS_ext8u_i32       /* and r0, r1, #0xff */
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
-// #define TCG_TARGET_HAS_eqv_i32
-// #define TCG_TARGET_HAS_nand_i32
-// #define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_div_i32          0
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        0 /* and r0, r1, #0xff */
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_andc_i32         1
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      0
 
 #define TCG_TARGET_HAS_GUEST_BASE
 
index 7f4653e342a03b53afdd26adb8be0b8d901206c2..59d4d12ba684e1391cc82691d498dff8298e676f 100644 (file)
@@ -338,7 +338,7 @@ static int tcg_target_const_match(tcg_target_long val,
 /* supplied by libgcc */
 extern void *__canonicalize_funcptr_for_compare(void *);
 
-static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
 {
     /* PA1.1 defines COPY as OR r,0,t; PA2.0 defines COPY as LDO 0(r),t
        but hppa-dis.c is unaware of this definition */
@@ -349,7 +349,7 @@ static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
 }
 
 static void tcg_out_movi(TCGContext *s, TCGType type,
-                         int ret, tcg_target_long arg)
+                         TCGReg ret, tcg_target_long arg)
 {
     if (check_fit_tl(arg, 14)) {
         tcg_out32(s, INSN_LDO | INSN_R1(ret)
@@ -393,15 +393,15 @@ static void tcg_out_ldst(TCGContext *s, int ret, int addr,
 }
 
 /* This function is required by tcg.c.  */
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_ldst(s, ret, arg1, arg2, INSN_LDW);
 }
 
 /* This function is required by tcg.c.  */
-static inline void tcg_out_st(TCGContext *s, TCGType type, int ret,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg ret,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_ldst(s, ret, arg1, arg2, INSN_STW);
 }
@@ -467,6 +467,14 @@ static inline void tcg_out_dep(TCGContext *s, int ret, int arg,
               | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len));
 }
 
+static inline void tcg_out_depi(TCGContext *s, int ret, int arg,
+                                unsigned ofs, unsigned len)
+{
+    assert(ofs < 32 && len <= 32 - ofs);
+    tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(arg)
+              | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len));
+}
+
 static inline void tcg_out_shd(TCGContext *s, int ret, int hi, int lo,
                                unsigned count)
 {
@@ -499,8 +507,7 @@ static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m)
     assert(bs1 == 32 || (1ul << bs1) > m);
 
     tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
-    tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1)
-              | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0));
+    tcg_out_depi(s, ret, -1, bs0, bs1 - bs0);
 }
 
 static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m)
@@ -529,8 +536,7 @@ static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m)
         tcg_out_extr(s, ret, arg, 0, ls0, 0);
     } else {
         tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
-        tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0)
-                  | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0));
+        tcg_out_depi(s, ret, 0, ls0, ls1 - ls0);
     }
 }
 
@@ -646,14 +652,14 @@ static void tcg_out_xmpyu(TCGContext *s, int retl, int reth,
                           int arg1, int arg2)
 {
     /* Store both words into the stack for copy to the FPU.  */
-    tcg_out_ldst(s, arg1, TCG_REG_SP, STACK_TEMP_OFS, INSN_STW);
-    tcg_out_ldst(s, arg2, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_STW);
+    tcg_out_ldst(s, arg1, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_STW);
+    tcg_out_ldst(s, arg2, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4, INSN_STW);
 
     /* Load both words into the FPU at the same time.  We get away
        with this because we can address the left and right half of the
        FPU registers individually once loaded.  */
     /* fldds stack_temp(sp),fr22 */
-    tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_SP)
+    tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_CALL_STACK)
               | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
 
     /* xmpyu fr22r,fr22,fr22 */
@@ -661,15 +667,16 @@ static void tcg_out_xmpyu(TCGContext *s, int retl, int reth,
 
     /* Store the 64-bit result back into the stack.  */
     /* fstds stack_temp(sp),fr22 */
-    tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_SP)
+    tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_CALL_STACK)
               | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
 
     /* Load the pieces of the result that the caller requested.  */
     if (reth) {
-        tcg_out_ldst(s, reth, TCG_REG_SP, STACK_TEMP_OFS, INSN_LDW);
+        tcg_out_ldst(s, reth, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_LDW);
     }
     if (retl) {
-        tcg_out_ldst(s, retl, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_LDW);
+        tcg_out_ldst(s, retl, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4,
+                     INSN_LDW);
     }
 }
 
@@ -1198,7 +1205,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
         }
         tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg);
         tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg);
-        tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP,
+        tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_CALL_STACK,
                    TCG_TARGET_CALL_STACK_OFFSET - 4);
         break;
     default:
@@ -1458,6 +1465,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
                      args[4], args[5], const_args[2], const_args[4]);
         break;
 
+    case INDEX_op_deposit_i32:
+        if (const_args[2]) {
+            tcg_out_depi(s, args[0], args[2], args[3], args[4]);
+        } else {
+            tcg_out_dep(s, args[0], args[2], args[3], args[4]);
+        }
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1551,6 +1566,8 @@ static const TCGTargetOpDef hppa_op_defs[] = {
     { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rI", "rZ" } },
     { INDEX_op_sub2_i32, { "r", "r", "rI", "rZ", "rK", "rZ" } },
 
+    { INDEX_op_deposit_i32, { "r", "0", "rJ" } },
+
 #if TARGET_LONG_BITS == 32
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
@@ -1596,7 +1613,7 @@ static int tcg_target_callee_save_regs[] = {
     TCG_REG_R14,
     TCG_REG_R15,
     TCG_REG_R16,
-    /* R17 is the global env, so no need to save.  */
+    TCG_REG_R17, /* R17 is the global env.  */
     TCG_REG_R18
 };
 
@@ -1611,23 +1628,30 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     /* Allocate space for the saved registers.  */
     frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
 
+    /* Allocate space for the TCG temps. */
+    frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long);
+
     /* Align the allocated space.  */
     frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1)
                   & -TCG_TARGET_STACK_ALIGN);
 
     /* The return address is stored in the caller's frame.  */
-    tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -20);
+    tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, -20);
 
     /* Allocate stack frame, saving the first register at the same time.  */
     tcg_out_ldst(s, tcg_target_callee_save_regs[0],
-                 TCG_REG_SP, frame_size, INSN_STWM);
+                 TCG_REG_CALL_STACK, frame_size, INSN_STWM);
 
     /* Save all callee saved registers.  */
     for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
         tcg_out_st(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
-                   TCG_REG_SP, -frame_size + i * 4);
+                   TCG_REG_CALL_STACK, -frame_size + i * 4);
     }
 
+    /* Record the location of the TCG temps.  */
+    tcg_set_frame(s, TCG_REG_CALL_STACK, -frame_size + i * 4,
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
 #ifdef CONFIG_USE_GUEST_BASE
     if (GUEST_BASE != 0) {
         tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
@@ -1635,21 +1659,24 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     }
 #endif
 
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+
     /* Jump to TB, and adjust R18 to be the return address.  */
-    tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26));
+    tcg_out32(s, INSN_BLE_SR4 | INSN_R2(tcg_target_call_iarg_regs[1]));
     tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R18, TCG_REG_R31);
 
     /* Restore callee saved registers.  */
-    tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -frame_size - 20);
+    tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK,
+               -frame_size - 20);
     for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
         tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
-                   TCG_REG_SP, -frame_size + i * 4);
+                   TCG_REG_CALL_STACK, -frame_size + i * 4);
     }
 
     /* Deallocate stack frame and return.  */
     tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_RP));
     tcg_out_ldst(s, tcg_target_callee_save_regs[0],
-                 TCG_REG_SP, -frame_size, INSN_LDWM);
+                 TCG_REG_CALL_STACK, -frame_size, INSN_LDWM);
 }
 
 static void tcg_target_init(TCGContext *s)
@@ -1676,7 +1703,7 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP);  /* data pointer */
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);  /* stack pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);  /* stack pointer */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */
 
     tcg_add_target_add_op_defs(hppa_op_defs);
index a5cc440d49b255f82c16b3396c76228a4322cb60..7f3c4cc3e57290f21ddaccf002ec38846924fd68 100644 (file)
@@ -24,9 +24,7 @@
 
 #define TCG_TARGET_HPPA 1
 
-#if defined(_PA_RISC1_1)
-#define TCG_TARGET_REG_BITS 32
-#else
+#if TCG_TARGET_REG_BITS != 32
 #error unsupported
 #endif
 
@@ -34,7 +32,7 @@
 
 #define TCG_TARGET_NB_REGS 32
 
-enum {
+typedef enum {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
     TCG_REG_RP,
@@ -67,7 +65,7 @@ enum {
     TCG_REG_RET1,
     TCG_REG_SP,
     TCG_REG_R31,
-};
+} TCGReg;
 
 #define TCG_CT_CONST_0    0x0100
 #define TCG_CT_CONST_S5   0x0200
@@ -85,20 +83,24 @@ enum {
 #define TCG_TARGET_STACK_GROWSUP
 
 /* optional instructions */
-// #define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_div_i32          0
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_andc_i32         1
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      1
 
 /* optional instructions automatically implemented */
-#undef TCG_TARGET_HAS_neg_i32           /* sub rd, 0, rs */
-#undef TCG_TARGET_HAS_ext8u_i32         /* and rd, rs, 0xff */
-#undef TCG_TARGET_HAS_ext16u_i32        /* and rd, rs, 0xffff */
+#define TCG_TARGET_HAS_neg_i32          0 /* sub rd, 0, rs */
+#define TCG_TARGET_HAS_ext8u_i32        0 /* and rd, rs, 0xff */
+#define TCG_TARGET_HAS_ext16u_i32       0 /* and rd, rs, 0xffff */
 
 #define TCG_TARGET_HAS_GUEST_BASE
 
index cc750b46f4be0dd25f1aeeff3ff1d69b27946b8f..7705733e5b1ee540e2ccb841bc437f02f5bbf713 100644 (file)
@@ -76,9 +76,11 @@ static const int tcg_target_call_iarg_regs[] = {
 #endif
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_EAX,
+#if TCG_TARGET_REG_BITS == 32
     TCG_REG_EDX
+#endif
 };
 
 static uint8_t *tb_ret_addr;
@@ -166,6 +168,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
             tcg_regset_set32(ct->u.regs, 0, 0xf);
         }
         break;
+    case 'Q':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xf);
+        break;
     case 'r':
         ct->ct |= TCG_CT_REG;
         if (TCG_TARGET_REG_BITS == 64) {
@@ -512,7 +518,8 @@ static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
     tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3) + ext, dest, src);
 }
 
-static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+                               TCGReg ret, TCGReg arg)
 {
     if (arg != ret) {
         int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
@@ -521,7 +528,7 @@ static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
 }
 
 static void tcg_out_movi(TCGContext *s, TCGType type,
-                         int ret, tcg_target_long arg)
+                         TCGReg ret, tcg_target_long arg)
 {
     if (arg == 0) {
         tgen_arithr(s, ARITH_XOR, ret, ret);
@@ -562,15 +569,15 @@ static inline void tcg_out_pop(TCGContext *s, int reg)
     tcg_out_opc(s, OPC_POP_r32 + LOWREGMASK(reg), 0, reg, 0);
 }
 
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
     tcg_out_modrm_offset(s, opc, ret, arg1, arg2);
 }
 
-static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     int opc = OPC_MOVL_EvGv + (type == TCG_TYPE_I64 ? P_REXW : 0);
     tcg_out_modrm_offset(s, opc, arg, arg1, arg2);
@@ -960,6 +967,7 @@ static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
 
 #include "../../softmmu_defs.h"
 
+#if !defined(CONFIG_QEMU_LDST_OPTIMIZATION)
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -973,6 +981,7 @@ static void *qemu_st_helpers[4] = {
     __stl_mmu,
     __stq_mmu,
 };
+#endif  /* !CONFIG_QEMU_LDST_OPTIMIZATION */
 
 /* Perform the TLB load and compare.
 
@@ -1132,9 +1141,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
     }
 }
 
-#if !defined(CONFIG_TCG_TARGET_X86_OPT)
-/* to suppress warnings */
-
+#if !defined(CONFIG_QEMU_LDST_OPTIMIZATION)
 /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
    EAX. It will be useful once fixed registers globals are less
    common. */
@@ -1252,7 +1259,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     }
 #endif
 }
-#endif  /* !CONFIG_TCG_TARGET_X86_OPT */
+#endif  /* !defined(CONFIG_QEMU_LDST_OPTIMIZATION) */
 
 static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
                                    int base, tcg_target_long ofs, int sizeop)
@@ -1313,9 +1320,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
     }
 }
 
-#if !defined(CONFIG_TCG_TARGET_X86_OPT)
-/* to suppress warnings */
-
+#if !defined(CONFIG_QEMU_LDST_OPTIMIZATION)
 static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
                             int opc)
 {
@@ -1405,7 +1410,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
         /* Pop and discard.  This is 2 bytes smaller than the add.  */
         tcg_out_pop(s, TCG_REG_ECX);
     } else if (stack_adjust != 0) {
-        tcg_out_addi(s, TCG_REG_ESP, stack_adjust);
+        tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust);
     }
 
     /* label2: */
@@ -1433,10 +1438,10 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     }
 #endif
 }
-#endif  /* !CONFIG_TCG_TARGET_X86_OPT */
+#endif  /* !defined(CONFIG_QEMU_LDST_OPTIMIZATION) */
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT)
-/* optimization to reduce jump overheads */
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION)
+/* optimization to reduce jump overheads for qemu_ld/st IRs */
 
 /* extened versions of MMU helpers */
 static void *qemu_ldext_helpers[4] = {
@@ -1453,27 +1458,27 @@ static void *qemu_stext_helpers[4] = {
 };
 
 /*
- * qemu_ld/st code generator call add_helper_label,
+ * qemu_ld/st code generator call add_qemu_ldst_label,
  * so that slow case(TLB miss or I/O rw) is handled at the end of TB
  */
-static void add_helper_label(TCGContext *s,
-                             int opc_ext,
-                             int data_reg,
-                             int data_reg2,
-                             int addrlo_reg,
-                             int addrhi_reg,
-                             int mem_index,
-                             uint8_t *raddr,
-                             uint32_t **label_ptr)
+static void add_qemu_ldst_label(TCGContext *s,
+                                int opc_ext,
+                                int data_reg,
+                                int data_reg2,
+                                int addrlo_reg,
+                                int addrhi_reg,
+                                int mem_index,
+                                uint8_t *raddr,
+                                uint32_t **label_ptr)
 {
     int idx;
-    HelperLabel *label;
+    TCGLabelQemuLdst *label;
 
-    if (s->nb_helper_labels >= TCG_MAX_HELPER_LABELS)
+    if (s->nb_qemu_ldst_labels >= TCG_MAX_QEMU_LDST)
         tcg_abort();
 
-    idx = s->nb_helper_labels++;
-    label = (HelperLabel *)&s->helper_labels[idx];
+    idx = s->nb_qemu_ldst_labels++;
+    label = (TCGLabelQemuLdst *)&s->qemu_ldst_labels[idx];
     label->opc_ext = opc_ext;
     label->datalo_reg = data_reg;
     label->datahi_reg = data_reg2;
@@ -1489,7 +1494,7 @@ static void add_helper_label(TCGContext *s,
 }
 
 /* generates slow case of qemu_ld at the end of TB */
-static void tcg_out_qemu_ld_helper_call(TCGContext *s, HelperLabel *label)
+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label)
 {
     int s_bits, arg_idx;
     int opc = label->opc_ext & HL_OPC_MASK;
@@ -1572,7 +1577,7 @@ static void tcg_out_qemu_ld_helper_call(TCGContext *s, HelperLabel *label)
 }
 
 /* generates slow case of qemu_st at the end of TB */
-static void tcg_out_qemu_st_helper_call(TCGContext *s, HelperLabel *label)
+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *label)
 {
     int s_bits;
     int stack_adjust;
@@ -1655,17 +1660,17 @@ static void tcg_out_qemu_st_helper_call(TCGContext *s, HelperLabel *label)
 }
 
 /* generates all of the slow cases of qemu_ld/st at the end of TB */
-void tcg_out_qemu_ldst_helper_calls(TCGContext *s)
+void tcg_out_qemu_ldst_slow_path(TCGContext *s)
 {
     int i;
-    HelperLabel *label;
+    TCGLabelQemuLdst *label;
 
-    for (i = 0; i < s->nb_helper_labels; i++) {
-        label = (HelperLabel *)&s->helper_labels[i];
+    for (i = 0; i < s->nb_qemu_ldst_labels; i++) {
+        label = (TCGLabelQemuLdst *)&s->qemu_ldst_labels[i];
         if (IS_QEMU_LD_LABEL(label)) {
-            tcg_out_qemu_ld_helper_call(s, label);
+            tcg_out_qemu_ld_slow_path(s, label);
         } else {
-            tcg_out_qemu_st_helper_call(s, label);
+            tcg_out_qemu_st_slow_path(s, label);
         }
     }
 }
@@ -1765,10 +1770,15 @@ static void tcg_out_qemu_ld_opt(TCGContext *s, const TCGArg *args,
                            tcg_target_call_iarg_regs[0], 0, opc);
 
     /* helper stub will be jumped back here */
-    add_helper_label(s, opc, data_reg, data_reg2,
-                     args[addrlo_idx],
-                     (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) ? args[addrlo_idx + 1] : 0,
-                     mem_index, s->code_ptr, label_ptr);
+    add_qemu_ldst_label(s,
+                        opc,
+                        data_reg,
+                        data_reg2,
+                        args[addrlo_idx],
+                        args[addrlo_idx + 1],
+                        mem_index,
+                        s->code_ptr,
+                        label_ptr);
 
 }
 
@@ -1798,13 +1808,17 @@ static void tcg_out_qemu_st_opt(TCGContext *s, const TCGArg *args,
                            tcg_target_call_iarg_regs[0], 0, opc);
 
     /* helper stub will be jumped back here */
-    add_helper_label(s, opc | HL_ST_MASK, data_reg, data_reg2,
-                     args[addrlo_idx],
-                     (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) ? args[addrlo_idx + 1] : 0,
-                     mem_index, s->code_ptr, label_ptr);
+    add_qemu_ldst_label(s,
+                        opc | HL_ST_MASK,
+                        data_reg,
+                        data_reg2,
+                        args[addrlo_idx],
+                        args[addrlo_idx + 1],
+                        mem_index,
+                        s->code_ptr,
+                        label_ptr);
 }
-
-#endif  /* CONFIG_TCG_TARGET_X86_OPT */
+#endif  /* defined(CONFIG_QEMU_LDST_OPTIMIZATION) */
 
 static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
                               const TCGArg *args, const int *const_args)
@@ -2018,9 +2032,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         tcg_out_ext16u(s, args[0], args[1]);
         break;
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
 #define tcg_out_qemu_ld(S, ARGS, OPC)   tcg_out_qemu_ld_opt(S, ARGS, OPC)
-#endif /* CONFIG_TCG_TARGET_X86_OPT */
+#endif /* defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) */
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -2043,9 +2057,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         tcg_out_qemu_ld(s, args, 3);
         break;
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
 #define tcg_out_qemu_st(S, ARGS, OPC)   tcg_out_qemu_st_opt(S, ARGS, OPC)
-#endif /* CONFIG_TCG_TARGET_X86_OPT */
+#endif /* defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) */
     case INDEX_op_qemu_st8:
         tcg_out_qemu_st(s, args, 0);
         break;
@@ -2130,6 +2144,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
 #endif
 
+    OP_32_64(deposit):
+        if (args[3] == 0 && args[4] == 8) {
+            /* load bits 0..7 */
+            tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM,
+                          args[2], args[0]);
+        } else if (args[3] == 8 && args[4] == 8) {
+            /* load bits 8..15 */
+            tcg_out_modrm(s, OPC_MOVB_EvGv, args[2], args[0] + 4);
+        } else if (args[3] == 0 && args[4] == 16) {
+            /* load bits 0..15 */
+            tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, args[2], args[0]);
+        } else {
+            tcg_abort();
+        }
+        break;
+
     default:
         tcg_abort();
     }
@@ -2185,6 +2215,8 @@ static const TCGTargetOpDef x86_op_defs[] = {
 
     { INDEX_op_setcond_i32, { "q", "r", "ri" } },
 
+    { INDEX_op_deposit_i32, { "Q", "0", "Q" } },
+
 #if TCG_TARGET_REG_BITS == 32
     { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
     { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
@@ -2236,6 +2268,8 @@ static const TCGTargetOpDef x86_op_defs[] = {
     { INDEX_op_ext8u_i64, { "r", "r" } },
     { INDEX_op_ext16u_i64, { "r", "r" } },
     { INDEX_op_ext32u_i64, { "r", "r" } },
+
+    { INDEX_op_deposit_i64, { "Q", "0", "Q" } },
 #endif
 
 #if TCG_TARGET_REG_BITS == 64
@@ -2276,9 +2310,6 @@ static const TCGTargetOpDef x86_op_defs[] = {
     { INDEX_op_qemu_st16, { "L", "L", "L" } },
     { INDEX_op_qemu_st32, { "L", "L", "L" } },
     { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
-#endif
-#ifdef CONFIG_EXEC_PROFILE
-    { INDEX_op_prof_tbexec, { } },
 #endif
     { -1 },
 };
@@ -2289,10 +2320,10 @@ static int tcg_target_callee_save_regs[] = {
     TCG_REG_RBX,
     TCG_REG_R12,
     TCG_REG_R13,
-    /* TCG_REG_R14, */ /* Currently used for the global env. */
+    TCG_REG_R14, /* Currently used for the global env. */
     TCG_REG_R15,
 #else
-    /* TCG_REG_EBP, */ /* Currently used for the global env. */
+    TCG_REG_EBP, /* Currently used for the global env. */
     TCG_REG_EBX,
     TCG_REG_ESI,
     TCG_REG_EDI,
@@ -2306,28 +2337,34 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 
     /* TB prologue */
 
-    /* Save all callee saved registers.  */
-    for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
-        tcg_out_push(s, tcg_target_callee_save_regs[i]);
-    }
-
-    /* Reserve some stack space.  */
+    /* Reserve some stack space, also for TCG temps.  */
     push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
     push_size *= TCG_TARGET_REG_BITS / 8;
 
-    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
+        CPU_TEMP_BUF_NLONGS * sizeof(long);
     frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
         ~(TCG_TARGET_STACK_ALIGN - 1);
     stack_addend = frame_size - push_size;
+    tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
+    /* Save all callee saved registers.  */
+    for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_push(s, tcg_target_callee_save_regs[i]);
+    }
+
     tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
 
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+
     /* jmp *tb.  */
-    tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[0]);
+    tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]);
 
     /* TB epilogue */
     tb_ret_addr = s->code_ptr;
 
-    tcg_out_addi(s, TCG_REG_ESP, stack_addend);
+    tcg_out_addi(s, TCG_REG_CALL_STACK, stack_addend);
 
     for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
         tcg_out_pop(s, tcg_target_callee_save_regs[i]);
@@ -2364,7 +2401,7 @@ static void tcg_target_init(TCGContext *s)
     }
 
     tcg_regset_clear(s->reserved_regs);
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
 
     tcg_add_target_add_op_defs(x86_op_defs);
 }
index bfafbfcbae66c1438bb6152cca82b5a9fb4fe5cb..7756e7b03c7bf83661607e1f07c162e357f0464b 100644 (file)
@@ -36,7 +36,7 @@
 # define TCG_TARGET_NB_REGS 8
 #endif
 
-enum {
+typedef enum {
     TCG_REG_EAX = 0,
     TCG_REG_ECX,
     TCG_REG_EDX,
@@ -64,7 +64,7 @@ enum {
     TCG_REG_RBP = TCG_REG_EBP,
     TCG_REG_RSI = TCG_REG_ESI,
     TCG_REG_RDI = TCG_REG_EDI,
-};
+} TCGReg;
 
 #define TCG_CT_CONST_S32 0x100
 #define TCG_CT_CONST_U32 0x200
@@ -75,43 +75,50 @@ enum {
 #define TCG_TARGET_CALL_STACK_OFFSET 0
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div2_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_not_i32
-// #define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
-// #define TCG_TARGET_HAS_eqv_i32
-// #define TCG_TARGET_HAS_nand_i32
-// #define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_div2_i32         1
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        1
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_andc_i32         0
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      1
 
 #if TCG_TARGET_REG_BITS == 64
-#define TCG_TARGET_HAS_div2_i64
-#define TCG_TARGET_HAS_rot_i64
-#define TCG_TARGET_HAS_ext8s_i64
-#define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-#define TCG_TARGET_HAS_ext8u_i64
-#define TCG_TARGET_HAS_ext16u_i64
-#define TCG_TARGET_HAS_ext32u_i64
-#define TCG_TARGET_HAS_bswap16_i64
-#define TCG_TARGET_HAS_bswap32_i64
-#define TCG_TARGET_HAS_bswap64_i64
-#define TCG_TARGET_HAS_neg_i64
-#define TCG_TARGET_HAS_not_i64
-// #define TCG_TARGET_HAS_andc_i64
-// #define TCG_TARGET_HAS_orc_i64
-// #define TCG_TARGET_HAS_eqv_i64
-// #define TCG_TARGET_HAS_nand_i64
-// #define TCG_TARGET_HAS_nor_i64
+#define TCG_TARGET_HAS_div2_i64         1
+#define TCG_TARGET_HAS_rot_i64          1
+#define TCG_TARGET_HAS_ext8s_i64        1
+#define TCG_TARGET_HAS_ext16s_i64       1
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i64        1
+#define TCG_TARGET_HAS_ext16u_i64       1
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_bswap16_i64      1
+#define TCG_TARGET_HAS_bswap32_i64      1
+#define TCG_TARGET_HAS_bswap64_i64      1
+#define TCG_TARGET_HAS_neg_i64          1
+#define TCG_TARGET_HAS_not_i64          1
+#define TCG_TARGET_HAS_andc_i64         0
+#define TCG_TARGET_HAS_orc_i64          0
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_deposit_i64      1
 #endif
 
+#define TCG_TARGET_deposit_i32_valid(ofs, len) \
+    (((ofs) == 0 && (len) == 8) || ((ofs) == 8 && (len) == 8) || \
+     ((ofs) == 0 && (len) == 16))
+#define TCG_TARGET_deposit_i64_valid    TCG_TARGET_deposit_i32_valid
+
 #define TCG_TARGET_HAS_GUEST_BASE
 
 /* Note: must be synced with dyngen-exec.h */
index 8dac7f72fd855369760d0ed85eade2c9f79d898b..e3de79fdb6ca4ef43e3b7a4ed7ff2b7f86a98540 100644 (file)
@@ -172,9 +172,8 @@ static const int tcg_target_call_iarg_regs[8] = {
     TCG_REG_R63,
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
-    TCG_REG_R8,
-    TCG_REG_R9
+static const int tcg_target_call_oarg_regs[] = {
+    TCG_REG_R8
 };
 
 /* maximum number of register used for input function arguments */
@@ -831,7 +830,7 @@ static inline void tcg_out_bundle(TCGContext *s, int template,
 }
 
 static inline void tcg_out_mov(TCGContext *s, TCGType type,
-                               TCGArg ret, TCGArg arg)
+                               TCGReg ret, TCGReg arg)
 {
     tcg_out_bundle(s, mmI,
                    tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
@@ -840,7 +839,7 @@ static inline void tcg_out_mov(TCGContext *s, TCGType type,
 }
 
 static inline void tcg_out_movi(TCGContext *s, TCGType type,
-                                TCGArg reg, tcg_target_long arg)
+                                TCGReg reg, tcg_target_long arg)
 {
     tcg_out_bundle(s, mLX,
                    tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
@@ -848,25 +847,6 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
                    tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, reg, arg));
 }
 
-static inline void tcg_out_addi(TCGContext *s, TCGArg reg, tcg_target_long val)
-{
-    if (val == ((int32_t)val << 10) >> 10) {
-        tcg_out_bundle(s, MmI,
-                       tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
-                                  TCG_REG_R2, val, TCG_REG_R0),
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
-                                   reg, TCG_REG_R2));
-    } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, val);
-        tcg_out_bundle(s, mmI,
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
-                                   reg, TCG_REG_R2));
-    }
-}
-
 static void tcg_out_br(TCGContext *s, int label_index)
 {
     TCGLabel *l = &s->labels[label_index];
@@ -992,8 +972,8 @@ static inline void tcg_out_st_rel(TCGContext *s, uint64_t opc_m4, TCGArg arg,
     }
 }
 
-static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGArg arg,
-                              TCGArg arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32) {
         tcg_out_ld_rel(s, OPC_LD4_M1, arg, arg1, arg2);
@@ -1002,8 +982,8 @@ static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGArg arg,
     }
 }
 
-static inline void tcg_out_st(TCGContext *s, TCGType type, TCGArg arg,
-                              TCGArg arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32) {
         tcg_out_st_rel(s, OPC_ST4_M4, arg, arg1, arg2);
@@ -2292,7 +2272,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
                    tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
                                TCG_REG_R33, 32, 24, 0),
                    tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
-                               TCG_REG_B6, TCG_REG_R32, 0),
+                               TCG_REG_B6, TCG_REG_R33, 0),
                    tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
                                TCG_REG_R32, TCG_REG_B0));
 
@@ -2308,7 +2288,8 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     }
 
     tcg_out_bundle(s, miB,
-                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+                               TCG_AREG0, 0, TCG_REG_R32),
                    tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
                                TCG_REG_R12, -frame_size, TCG_REG_R12),
                    tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
@@ -2387,4 +2368,6 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6);
 
     tcg_add_target_add_op_defs(ia64_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
index e56e88fe91cfbecfa6e9958207f907cc91b2578c..c3880890048307a49545d2338bfe60c438de82f8 100644 (file)
  */
 #define TCG_TARGET_IA64 1
 
-#define TCG_TARGET_REG_BITS 64
-
 /* We only map the first 64 registers */
 #define TCG_TARGET_NB_REGS 64
-enum {
+typedef enum {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
     TCG_REG_R2,
@@ -93,7 +91,7 @@ enum {
     TCG_REG_R61,
     TCG_REG_R62,
     TCG_REG_R63,
-};
+} TCGReg;
 
 #define TCG_CT_CONST_ZERO 0x100
 #define TCG_CT_CONST_S22 0x200
@@ -104,39 +102,43 @@ enum {
 #define TCG_TARGET_CALL_STACK_OFFSET 16
 
 /* optional instructions */
-#define TCG_TARGET_HAS_andc_i32
-#define TCG_TARGET_HAS_andc_i64
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap16_i64
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_bswap32_i64
-#define TCG_TARGET_HAS_bswap64_i64
-#define TCG_TARGET_HAS_eqv_i32
-#define TCG_TARGET_HAS_eqv_i64
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_ext8s_i64
-#define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_ext8u_i64
-#define TCG_TARGET_HAS_ext16u_i64
-#define TCG_TARGET_HAS_ext32u_i64
-#define TCG_TARGET_HAS_nand_i32
-#define TCG_TARGET_HAS_nand_i64
-#define TCG_TARGET_HAS_nor_i32
-#define TCG_TARGET_HAS_nor_i64
-#define TCG_TARGET_HAS_orc_i32
-#define TCG_TARGET_HAS_orc_i64
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_div_i32          0
+#define TCG_TARGET_HAS_div_i64          0
+#define TCG_TARGET_HAS_andc_i32         1
+#define TCG_TARGET_HAS_andc_i64         1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap16_i64      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_bswap32_i64      1
+#define TCG_TARGET_HAS_bswap64_i64      1
+#define TCG_TARGET_HAS_eqv_i32          1
+#define TCG_TARGET_HAS_eqv_i64          1
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8s_i64        1
+#define TCG_TARGET_HAS_ext16s_i64       1
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i32        1
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_ext8u_i64        1
+#define TCG_TARGET_HAS_ext16u_i64       1
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_nand_i32         1
+#define TCG_TARGET_HAS_nand_i64         1
+#define TCG_TARGET_HAS_nor_i32          1
+#define TCG_TARGET_HAS_nor_i64          1
+#define TCG_TARGET_HAS_orc_i32          1
+#define TCG_TARGET_HAS_orc_i64          1
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_rot_i64          1
+#define TCG_TARGET_HAS_deposit_i32      0
+#define TCG_TARGET_HAS_deposit_i64      0
 
 /* optional instructions automatically implemented */
-#undef TCG_TARGET_HAS_neg_i32   /* sub r1, r0, r3 */
-#undef TCG_TARGET_HAS_neg_i64   /* sub r1, r0, r3 */
-#undef TCG_TARGET_HAS_not_i32   /* xor r1, -1, r3 */
-#undef TCG_TARGET_HAS_not_i64   /* xor r1, -1, r3 */
+#define TCG_TARGET_HAS_neg_i32          0 /* sub r1, r0, r3 */
+#define TCG_TARGET_HAS_neg_i64          0 /* sub r1, r0, r3 */
+#define TCG_TARGET_HAS_not_i32          0 /* xor r1, -1, r3 */
+#define TCG_TARGET_HAS_not_i64          0 /* xor r1, -1, r3 */
 
 /* Note: must be synced with dyngen-exec.h */
 #define TCG_AREG0 TCG_REG_R7
index e04b0dc32f373d021cc6fe58132de66c0dbcb235..c5c32825f0f870ec1ccccd8c0f893cbd87a037d7 100644 (file)
@@ -379,13 +379,14 @@ static inline void tcg_out_nop(TCGContext *s)
     tcg_out32(s, 0);
 }
 
-static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+                               TCGReg ret, TCGReg arg)
 {
     tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
 }
 
 static inline void tcg_out_movi(TCGContext *s, TCGType type,
-                                int reg, int32_t arg)
+                                TCGReg reg, tcg_target_long arg)
 {
     if (arg == (int16_t)arg) {
         tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg);
@@ -480,14 +481,14 @@ static inline void tcg_out_ldst(TCGContext *s, int opc, int arg,
     }
 }
 
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
 }
 
-static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
 }
@@ -1452,9 +1453,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
 };
 
 static int tcg_target_callee_save_regs[] = {
-#if 0 /* used for the global env (TCG_AREG0), so no need to save */
-    TCG_REG_S0,
-#endif
+    TCG_REG_S0,       /* used for the global env (TCG_AREG0) */
     TCG_REG_S1,
     TCG_REG_S2,
     TCG_REG_S3,
@@ -1486,8 +1485,8 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     }
 
     /* Call generated code */
-    tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0);
-    tcg_out_nop(s);
+    tcg_out_opc_reg(s, OPC_JR, 0, tcg_target_call_iarg_regs[1], 0);
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
     tb_ret_addr = s->code_ptr;
 
     /* TB epilogue */
@@ -1530,4 +1529,6 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);   /* stack pointer */
 
     tcg_add_target_add_op_defs(mips_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
index 0028bfa562350dbe6f0276f4da427ba857cbcc48..477bc38b016bf74a16b654c6081a8108da6d292f 100644 (file)
  */
 #define TCG_TARGET_MIPS 1
 
-#define TCG_TARGET_REG_BITS 32
 #ifdef __MIPSEB__
 # define TCG_TARGET_WORDS_BIGENDIAN
 #endif
 
 #define TCG_TARGET_NB_REGS 32
 
-enum {
+typedef enum {
     TCG_REG_ZERO = 0,
     TCG_REG_AT,
     TCG_REG_V0,
@@ -65,7 +64,7 @@ enum {
     TCG_REG_SP,
     TCG_REG_FP,
     TCG_REG_RA,
-};
+} TCGReg;
 
 #define TCG_CT_CONST_ZERO 0x100
 #define TCG_CT_CONST_U16  0x200
@@ -78,23 +77,24 @@ enum {
 #define TCG_TARGET_CALL_ALIGN_ARGS 1
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_nor_i32
-#undef TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#undef TCG_TARGET_HAS_bswap32_i32
-#undef TCG_TARGET_HAS_bswap16_i32
-#undef TCG_TARGET_HAS_andc_i32
-#undef TCG_TARGET_HAS_orc_i32
-#undef TCG_TARGET_HAS_eqv_i32
-#undef TCG_TARGET_HAS_nand_i32
+#define TCG_TARGET_HAS_div_i32          1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_nor_i32          1
+#define TCG_TARGET_HAS_rot_i32          0
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_bswap32_i32      0
+#define TCG_TARGET_HAS_bswap16_i32      0
+#define TCG_TARGET_HAS_andc_i32         0
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_deposit_i32      0
 
 /* optional instructions automatically implemented */
-#undef TCG_TARGET_HAS_neg_i32      /* sub  rd, zero, rt   */
-#undef TCG_TARGET_HAS_ext8u_i32    /* andi rt, rs, 0xff   */
-#undef TCG_TARGET_HAS_ext16u_i32   /* andi rt, rs, 0xffff */
+#define TCG_TARGET_HAS_neg_i32          0 /* sub  rd, zero, rt   */
+#define TCG_TARGET_HAS_ext8u_i32        0 /* andi rt, rs, 0xff   */
+#define TCG_TARGET_HAS_ext16u_i32       0 /* andi rt, rs, 0xffff */
 
 /* Note: must be synced with dyngen-exec.h */
 #define TCG_AREG0 TCG_REG_S0
@@ -102,7 +102,11 @@ enum {
 /* guest base is supported */
 #define TCG_TARGET_HAS_GUEST_BASE
 
+#ifdef __OpenBSD__
+#include <machine/sysarch.h>
+#else
 #include <sys/cachectl.h>
+#endif
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
index 07710080b0a0ecd994e3363484a64eae7a0c22f1..9c65474a8c77962d4e1eddb78959c37b4cf25fca 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Optimizations for Tiny Code Generator for QEMU
  *
- * Copyright (c) 2010 Kirill Batuzov
+ * Copyright (c) 2010 Samsung Electronics.
+ * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#ifdef _WIN32
-#include <malloc.h>
-#endif
-#ifdef _AIX
-#include <alloca.h>
-#endif
 
 #include "qemu-common.h"
-#include "cache-utils.h"
-#include "host-utils.h"
-#define NO_CPU_IO_DEFS
-#include "cpu.h"
-#include "exec-all.h"
-
 #include "tcg-op.h"
-#include "elf.h"
-
-#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
-#error GUEST_BASE not supported on this host.
-#endif
-
-typedef enum { TCG_TEMP_UNDEF = 0, TCG_TEMP_CONST, TCG_TEMP_COPY, TCG_TEMP_ANY } tcg_temp_state;
 
-const int mov_opc[] = {
-    INDEX_op_mov_i32,
-#if TCG_TARGET_REG_BITS == 64
-    INDEX_op_mov_i64,
-#endif
+#define CASE_OP_32_64(x)                        \
+        glue(glue(case INDEX_op_, x), _i32):    \
+        glue(glue(case INDEX_op_, x), _i64)
+
+typedef enum {
+    TCG_TEMP_UNDEF = 0,
+    TCG_TEMP_CONST,
+    TCG_TEMP_COPY,
+    TCG_TEMP_HAS_COPY,
+    TCG_TEMP_ANY
+} tcg_temp_state;
+
+struct tcg_temp_info {
+    tcg_temp_state state;
+    uint16_t prev_copy;
+    uint16_t next_copy;
+    tcg_target_ulong val;
 };
 
-static int op_to_opi(int op)
+static struct tcg_temp_info temps[TCG_MAX_TEMPS];
+
+/* Reset TEMP's state to TCG_TEMP_ANY.  If TEMP was a representative of some
+   class of equivalent temp's, a new representative should be chosen in this
+   class. */
+static void reset_temp(TCGArg temp, int nb_temps, int nb_globals)
 {
-    switch(op) {
-        case INDEX_op_mov_i32: return INDEX_op_movi_i32;
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_mov_i64: return INDEX_op_movi_i64;
-#endif
-        default:
-            fprintf(stderr, "INTERNAL ERROR: TCG optimizer encountered an "
-                            "unrecognized operation in op_to_opi.\n");
-            exit(1);
+    int i;
+    TCGArg new_base = (TCGArg)-1;
+    if (temps[temp].state == TCG_TEMP_HAS_COPY) {
+        for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
+            if (i >= nb_globals) {
+                temps[i].state = TCG_TEMP_HAS_COPY;
+                new_base = i;
+                break;
+            }
+        }
+        for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) {
+            if (new_base == (TCGArg)-1) {
+                temps[i].state = TCG_TEMP_ANY;
+            } else {
+                temps[i].val = new_base;
+            }
+        }
+        temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
+        temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
+    } else if (temps[temp].state == TCG_TEMP_COPY) {
+        temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy;
+        temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy;
+        new_base = temps[temp].val;
+    }
+    temps[temp].state = TCG_TEMP_ANY;
+    if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) {
+        temps[new_base].state = TCG_TEMP_ANY;
     }
 }
 
-static int op_bits(int op)
+static int op_bits(TCGOpcode op)
 {
-    switch(op) {
-        case INDEX_op_mov_i32:
-        case INDEX_op_add_i32:
-        case INDEX_op_sub_i32:
-        case INDEX_op_mul_i32:
-        case INDEX_op_and_i32:
-        case INDEX_op_or_i32:
-        case INDEX_op_xor_i32:
-        case INDEX_op_shl_i32:
-        case INDEX_op_shr_i32:
-        case INDEX_op_sar_i32:
-        case INDEX_op_rotl_i32:
-        case INDEX_op_rotr_i32:
-            return 32;
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_mov_i64:
-        case INDEX_op_add_i64:
-        case INDEX_op_sub_i64:
-        case INDEX_op_mul_i64:
-        case INDEX_op_and_i64:
-        case INDEX_op_or_i64:
-        case INDEX_op_xor_i64:
-        case INDEX_op_shl_i64:
-        case INDEX_op_shr_i64:
-        case INDEX_op_sar_i64:
-        case INDEX_op_rotl_i64:
-        case INDEX_op_rotr_i64:
-            return 64;
-#endif
-        default:
-            fprintf(stderr, "INTERNAL ERROR: TCG optimizer encountered an "
-                            "unrecognized operation in op_bits.\n");
-            exit(1);
-    }
+    const TCGOpDef *def = &tcg_op_defs[op];
+    return def->flags & TCG_OPF_64BIT ? 64 : 32;
 }
 
-static int op_to_movi(int op)
+static TCGOpcode op_to_movi(TCGOpcode op)
 {
-    if (op_bits(op) == 32)
+    switch (op_bits(op)) {
+    case 32:
         return INDEX_op_movi_i32;
-#if TCG_TARGET_REG_BITS == 64
-    if (op_bits(op) == 64)
+    case 64:
         return INDEX_op_movi_i64;
-#endif
-    fprintf(stderr, "INTERNAL ERROR: TCG optimizer encountered an "
-                    "unrecognized operation in op_to_movi.\n");
-    exit(1);
+    default:
+        fprintf(stderr, "op_to_movi: unexpected return value of "
+                "function op_bits.\n");
+        tcg_abort();
+    }
 }
 
-static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
+static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst,
+                            TCGArg src, int nb_temps, int nb_globals)
 {
-    TCGArg r;
-    switch(op) {
-        case INDEX_op_add_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_add_i64:
-#endif
-            return x + y;
-
-        case INDEX_op_sub_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_sub_i64:
-#endif
-            return x - y;
-
-        case INDEX_op_mul_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_mul_i64:
-#endif
-            return x * y;
-
-        case INDEX_op_and_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_and_i64:
-#endif
-            return x & y;
-
-        case INDEX_op_or_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_or_i64:
-#endif
-            return x | y;
-
-        case INDEX_op_xor_i32:
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_xor_i64:
-#endif
-            return x ^ y;
-
-        case INDEX_op_shl_i32:
-#if TCG_TARGET_REG_BITS == 64
-            y &= 0xffffffff;
-        case INDEX_op_shl_i64:
-#endif
-            return x << y;
-
-        case INDEX_op_shr_i32:
-#if TCG_TARGET_REG_BITS == 64
-            x &= 0xffffffff;
-            y &= 0xffffffff;
-        case INDEX_op_shr_i64:
-#endif
-            /* Assuming TCGArg to be unsigned */
-            return x >> y;
-
-        case INDEX_op_sar_i32:
-#if TCG_TARGET_REG_BITS == 64
-            x &= 0xffffffff;
-            y &= 0xffffffff;
-#endif
-            r = x & 0x80000000;
-            x &= ~0x80000000;
-            x >>= y;
-            r |= r - (r >> y);
-            x |= r;
-            return x;
-
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_sar_i64:
-            r = x & 0x8000000000000000ULL;
-            x &= ~0x8000000000000000ULL;
-            x >>= y;
-            r |= r - (r >> y);
-            x |= r;
-            return x;
-#endif
-
-        case INDEX_op_rotr_i32:
-#if TCG_TARGET_REG_BITS == 64
-            x &= 0xffffffff;
-            y &= 0xffffffff;
-#endif
-            x = (x << (32 - y)) | (x >> y);
-            return x;
-
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_rotr_i64:
-            x = (x << (64 - y)) | (x >> y);
-            return x;
-#endif
-
-        case INDEX_op_rotl_i32:
-#if TCG_TARGET_REG_BITS == 64
-            x &= 0xffffffff;
-            y &= 0xffffffff;
-#endif
-            x = (x << y) | (x >> (32 - y));
-            return x;
-
-#if TCG_TARGET_REG_BITS == 64
-        case INDEX_op_rotl_i64:
-            x = (x << y) | (x >> (64 - y));
-            return x;
-#endif
+        reset_temp(dst, nb_temps, nb_globals);
+        assert(temps[src].state != TCG_TEMP_COPY);
+        /* Don't try to copy if one of temps is a global or either one
+           is local and another is register */
+        if (src >= nb_globals && dst >= nb_globals &&
+            tcg_arg_is_local(s, src) == tcg_arg_is_local(s, dst)) {
+            assert(temps[src].state != TCG_TEMP_CONST);
+            if (temps[src].state != TCG_TEMP_HAS_COPY) {
+                temps[src].state = TCG_TEMP_HAS_COPY;
+                temps[src].next_copy = src;
+                temps[src].prev_copy = src;
+            }
+            temps[dst].state = TCG_TEMP_COPY;
+            temps[dst].val = src;
+            temps[dst].next_copy = temps[src].next_copy;
+            temps[dst].prev_copy = src;
+            temps[temps[dst].next_copy].prev_copy = dst;
+            temps[src].next_copy = dst;
+        }
+        gen_args[0] = dst;
+        gen_args[1] = src;
+}
 
-        default:
-            fprintf(stderr, "INTERNAL ERROR: TCG optimizer encountered an "
-                            "unrecognized operation in do_constant_folding.\n");
-            exit(1);
-    }
+static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val,
+                             int nb_temps, int nb_globals)
+{
+        reset_temp(dst, nb_temps, nb_globals);
+        temps[dst].state = TCG_TEMP_CONST;
+        temps[dst].val = val;
+        gen_args[0] = dst;
+        gen_args[1] = val;
 }
 
-static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
+static TCGOpcode op_to_mov(TCGOpcode op)
 {
-    TCGArg res = do_constant_folding_2(op, x, y);
-#if TCG_TARGET_REG_BITS == 64
-    if (op_bits(op) == 32) {
-        res &= 0xffffffff;
+    switch (op_bits(op)) {
+    case 32:
+        return INDEX_op_mov_i32;
+    case 64:
+        return INDEX_op_mov_i64;
+    default:
+        fprintf(stderr, "op_to_mov: unexpected return value of "
+                "function op_bits.\n");
+        tcg_abort();
     }
-#endif
-    return res;
 }
 
-static void reset_temp(tcg_temp_state *state, tcg_target_ulong *vals,
-        TCGArg temp, int nb_temps, int nb_globals)
+static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
 {
-    int i;
-    TCGArg new_base;
-    new_base = (TCGArg)-1;
-#if 0
-    for (i = 0; i < nb_temps; i++) {
-        if (state[i] == TCG_TEMP_COPY && vals[i] == temp) {
-            if (new_base == ((TCGArg)-1)) {
-                new_base = (TCGArg)i;
-                state[i] = TCG_TEMP_ANY;
-            } else {
-                vals[i] = new_base;
-            }
-        }
-    }
-#else
-    for (i = nb_globals; i < nb_temps; i++) {
-        if (state[i] == TCG_TEMP_COPY && vals[i] == temp) {
-            if (new_base == ((TCGArg)-1)) {
-                new_base = (TCGArg)i;
-                state[i] = TCG_TEMP_ANY;
-            } else {
-                vals[i] = new_base;
-            }
-        }
+    switch (op) {
+    CASE_OP_32_64(add):
+        return x + y;
+
+    CASE_OP_32_64(sub):
+        return x - y;
+
+    CASE_OP_32_64(mul):
+        return x * y;
+
+    CASE_OP_32_64(and):
+        return x & y;
+
+    CASE_OP_32_64(or):
+        return x | y;
+
+    CASE_OP_32_64(xor):
+        return x ^ y;
+
+    case INDEX_op_shl_i32:
+        return (uint32_t)x << (uint32_t)y;
+
+    case INDEX_op_shl_i64:
+        return (uint64_t)x << (uint64_t)y;
+
+    case INDEX_op_shr_i32:
+        return (uint32_t)x >> (uint32_t)y;
+
+    case INDEX_op_shr_i64:
+        return (uint64_t)x >> (uint64_t)y;
+
+    case INDEX_op_sar_i32:
+        return (int32_t)x >> (int32_t)y;
+
+    case INDEX_op_sar_i64:
+        return (int64_t)x >> (int64_t)y;
+
+    case INDEX_op_rotr_i32:
+        x = ((uint32_t)x << (32 - y)) | ((uint32_t)x >> y);
+        return x;
+
+    case INDEX_op_rotr_i64:
+        x = ((uint64_t)x << (64 - y)) | ((uint64_t)x >> y);
+        return x;
+
+    case INDEX_op_rotl_i32:
+        x = ((uint32_t)x << y) | ((uint32_t)x >> (32 - y));
+        return x;
+
+    case INDEX_op_rotl_i64:
+        x = ((uint64_t)x << y) | ((uint64_t)x >> (64 - y));
+        return x;
+
+    CASE_OP_32_64(not):
+        return ~x;
+
+    CASE_OP_32_64(neg):
+        return -x;
+
+    CASE_OP_32_64(andc):
+        return x & ~y;
+
+    CASE_OP_32_64(orc):
+        return x | ~y;
+
+    CASE_OP_32_64(eqv):
+        return ~(x ^ y);
+
+    CASE_OP_32_64(nand):
+        return ~(x & y);
+
+    CASE_OP_32_64(nor):
+        return ~(x | y);
+
+    CASE_OP_32_64(ext8s):
+        return (int8_t)x;
+
+    CASE_OP_32_64(ext16s):
+        return (int16_t)x;
+
+    CASE_OP_32_64(ext8u):
+        return (uint8_t)x;
+
+    CASE_OP_32_64(ext16u):
+        return (uint16_t)x;
+
+    case INDEX_op_ext32s_i64:
+        return (int32_t)x;
+
+    case INDEX_op_ext32u_i64:
+        return (uint32_t)x;
+
+    default:
+        fprintf(stderr,
+                "Unrecognized operation %d in do_constant_folding.\n", op);
+        tcg_abort();
     }
-    for (i = 0; i < nb_globals; i++) {
-        if (state[i] == TCG_TEMP_COPY && vals[i] == temp) {
-            if (new_base == ((TCGArg)-1)) {
-                state[i] = TCG_TEMP_ANY;
-            } else {
-                vals[i] = new_base;
-            }
-        }
+}
+
+static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
+{
+    TCGArg res = do_constant_folding_2(op, x, y);
+    if (op_bits(op) == 32) {
+        res &= 0xffffffff;
     }
-#endif
-    state[temp] = TCG_TEMP_ANY;
+    return res;
 }
 
+/* Propagate constants and copies, fold constant expressions. */
 static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                                     TCGArg *args, TCGOpDef *tcg_op_defs)
 {
-    int i, nb_ops, op_index, op, nb_temps, nb_globals;
+    int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args;
+    TCGOpcode op;
     const TCGOpDef *def;
     TCGArg *gen_args;
-    tcg_target_ulong *vals;
-    tcg_temp_state *state;
+    TCGArg tmp;
+    /* Array VALS has an element for each temp.
+       If this temp holds a constant then its value is kept in VALS' element.
+       If this temp is a copy of other ones then this equivalence class'
+       representative is kept in VALS' element.
+       If this temp is neither copy nor constant then corresponding VALS'
+       element is unused. */
 
     nb_temps = s->nb_temps;
     nb_globals = s->nb_globals;
-    state = (tcg_temp_state *)malloc(sizeof(tcg_temp_state) * nb_temps);
-    vals = (tcg_target_ulong *)malloc(sizeof(tcg_target_ulong) * nb_temps);
-    memset(state, 0, nb_temps * sizeof(tcg_temp_state));
-
-    // gen_opc_ptr++; /* Skip end? What is this? */
+    memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
 
     nb_ops = tcg_opc_ptr - gen_opc_buf;
     gen_args = args;
@@ -311,170 +293,226 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         op = gen_opc_buf[op_index];
         def = &tcg_op_defs[op];
         /* Do copy propagation */
-        if (op != INDEX_op_call) {
+        if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) {
+            assert(op != INDEX_op_call);
             for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) {
-                if (state[args[i]] == TCG_TEMP_COPY
-                    && !(def->args_ct[i].ct & TCG_CT_IALIAS)
-                    /* TODO: is this check really needed??? */
-                    && (def->args_ct[i].ct & TCG_CT_REG)) {
-/*                    if (vals[args[i]] < s->nb_globals)
-                        printf("Fuuu\n");*/
-                    args[i] = vals[args[i]];
+                if (temps[args[i]].state == TCG_TEMP_COPY) {
+                    args[i] = temps[args[i]].val;
                 }
             }
         }
 
-        /* Propagate constants through copy operations and do constant
-           folding.  Constants will be substituted to arguments by register
-           allocator where needed and possible.  Also detect copies. */
-        switch(op) {
-            case INDEX_op_mov_i32:
-#if TCG_TARGET_REG_BITS == 64
-            case INDEX_op_mov_i64:
-#endif
-                if ((state[args[1]] == TCG_TEMP_COPY
-                    && vals[args[1]] == args[0])
+        /* For commutative operations make constant second argument */
+        switch (op) {
+        CASE_OP_32_64(add):
+        CASE_OP_32_64(mul):
+        CASE_OP_32_64(and):
+        CASE_OP_32_64(or):
+        CASE_OP_32_64(xor):
+        CASE_OP_32_64(eqv):
+        CASE_OP_32_64(nand):
+        CASE_OP_32_64(nor):
+            if (temps[args[1]].state == TCG_TEMP_CONST) {
+                tmp = args[1];
+                args[1] = args[2];
+                args[2] = tmp;
+            }
+            break;
+        default:
+            break;
+        }
+
+        /* Simplify expression if possible. */
+        switch (op) {
+        CASE_OP_32_64(add):
+        CASE_OP_32_64(sub):
+        CASE_OP_32_64(shl):
+        CASE_OP_32_64(shr):
+        CASE_OP_32_64(sar):
+        CASE_OP_32_64(rotl):
+        CASE_OP_32_64(rotr):
+            if (temps[args[1]].state == TCG_TEMP_CONST) {
+                /* Proceed with possible constant folding. */
+                break;
+            }
+            if (temps[args[2]].state == TCG_TEMP_CONST
+                && temps[args[2]].val == 0) {
+                if ((temps[args[0]].state == TCG_TEMP_COPY
+                    && temps[args[0]].val == args[1])
                     || args[0] == args[1]) {
-                    args += 2;
+                    args += 3;
                     gen_opc_buf[op_index] = INDEX_op_nop;
-                    break;
-                }
-                if (state[args[1]] != TCG_TEMP_CONST) {
-                    reset_temp(state, vals, args[0], nb_temps, nb_globals);
-                    if (args[1] >= s->nb_globals) {
-                        state[args[0]] = TCG_TEMP_COPY;
-                        vals[args[0]] = args[1];
-                    }
-                    gen_args[0] = args[0];
-                    gen_args[1] = args[1];
+                } else {
+                    gen_opc_buf[op_index] = op_to_mov(op);
+                    tcg_opt_gen_mov(s, gen_args, args[0], args[1],
+                                    nb_temps, nb_globals);
                     gen_args += 2;
-                    args += 2;
-                    break;
+                    args += 3;
+                }
+                continue;
+            }
+            break;
+        CASE_OP_32_64(mul):
+            if ((temps[args[2]].state == TCG_TEMP_CONST
+                && temps[args[2]].val == 0)) {
+                gen_opc_buf[op_index] = op_to_movi(op);
+                tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals);
+                args += 3;
+                gen_args += 2;
+                continue;
+            }
+            break;
+        CASE_OP_32_64(or):
+        CASE_OP_32_64(and):
+            if (args[1] == args[2]) {
+                if (args[1] == args[0]) {
+                    args += 3;
+                    gen_opc_buf[op_index] = INDEX_op_nop;
                 } else {
-                    /* Source argument is constant.  Rewrite the operation and
-                       let movi case handle it. */
-                    op = op_to_opi(op);
-                    gen_opc_buf[op_index] = op;
-                    args[1] = vals[args[1]];
-                    /* fallthrough */
+                    gen_opc_buf[op_index] = op_to_mov(op);
+                    tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps,
+                                    nb_globals);
+                    gen_args += 2;
+                    args += 3;
                 }
-            case INDEX_op_movi_i32:
-#if TCG_TARGET_REG_BITS == 64
-            case INDEX_op_movi_i64:
-#endif
-                reset_temp(state, vals, args[0], nb_temps, nb_globals);
-                state[args[0]] = TCG_TEMP_CONST;
-                vals[args[0]] = args[1];
+                continue;
+            }
+            break;
+        default:
+            break;
+        }
+
+        /* Propagate constants through copy operations and do constant
+           folding.  Constants will be substituted to arguments by register
+           allocator where needed and possible.  Also detect copies. */
+        switch (op) {
+        CASE_OP_32_64(mov):
+            if ((temps[args[1]].state == TCG_TEMP_COPY
+                && temps[args[1]].val == args[0])
+                || args[0] == args[1]) {
+                args += 2;
+                gen_opc_buf[op_index] = INDEX_op_nop;
+                break;
+            }
+            if (temps[args[1]].state != TCG_TEMP_CONST) {
+                tcg_opt_gen_mov(s, gen_args, args[0], args[1],
+                                nb_temps, nb_globals);
+                gen_args += 2;
+                args += 2;
+                break;
+            }
+            /* Source argument is constant.  Rewrite the operation and
+               let movi case handle it. */
+            op = op_to_movi(op);
+            gen_opc_buf[op_index] = op;
+            args[1] = temps[args[1]].val;
+            /* fallthrough */
+        CASE_OP_32_64(movi):
+            tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals);
+            gen_args += 2;
+            args += 2;
+            break;
+        CASE_OP_32_64(not):
+        CASE_OP_32_64(neg):
+        CASE_OP_32_64(ext8s):
+        CASE_OP_32_64(ext8u):
+        CASE_OP_32_64(ext16s):
+        CASE_OP_32_64(ext16u):
+        case INDEX_op_ext32s_i64:
+        case INDEX_op_ext32u_i64:
+            if (temps[args[1]].state == TCG_TEMP_CONST) {
+                gen_opc_buf[op_index] = op_to_movi(op);
+                tmp = do_constant_folding(op, temps[args[1]].val, 0);
+                tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
+                gen_args += 2;
+                args += 2;
+                break;
+            } else {
+                reset_temp(args[0], nb_temps, nb_globals);
                 gen_args[0] = args[0];
                 gen_args[1] = args[1];
                 gen_args += 2;
                 args += 2;
                 break;
-            case INDEX_op_or_i32:
-            case INDEX_op_and_i32:
-#if TCG_TARGET_REG_BITS == 64
-            case INDEX_op_and_i64:
-            case INDEX_op_or_i64:
-#endif
-                if (args[1] == args[2]) {
-                    if (args[1] == args[0]) {
-                        args += 3;
-                        gen_opc_buf[op_index] = INDEX_op_nop;
-                    } else {
-                        reset_temp(state, vals, args[0], nb_temps, nb_globals);
-                        if (args[1] >= s->nb_globals) {
-                            state[args[0]] = TCG_TEMP_COPY;
-                            vals[args[0]] = args[1];
-                        }
-                        gen_opc_buf[op_index] = mov_opc[op_bits(op) / 32 - 1];
-                        gen_args[0] = args[0];
-                        gen_args[1] = args[1];
-                        gen_args += 2;
-                        args += 3;
-                    }
-                    break;
-                }
-                /* Proceede with default binary operation handling */
-            case INDEX_op_add_i32:
-            case INDEX_op_sub_i32:
-            case INDEX_op_xor_i32:
-            case INDEX_op_mul_i32:
-            case INDEX_op_shl_i32:
-            case INDEX_op_shr_i32:
-            case INDEX_op_sar_i32:
-            case INDEX_op_rotl_i32:
-            case INDEX_op_rotr_i32:
-#if TCG_TARGET_REG_BITS == 64
-            case INDEX_op_add_i64:
-            case INDEX_op_sub_i64:
-            case INDEX_op_xor_i64:
-            case INDEX_op_mul_i64:
-            case INDEX_op_shl_i64:
-            case INDEX_op_shr_i64:
-            case INDEX_op_sar_i64:
-            case INDEX_op_rotl_i64:
-            case INDEX_op_rotr_i64:
-#endif
-                if (state[args[1]] == TCG_TEMP_CONST
-                    && state[args[2]] == TCG_TEMP_CONST)
-                {
-                    gen_opc_buf[op_index] = op_to_movi(op);
-                    gen_args[0] = args[0];
-                    gen_args[1] = do_constant_folding(op, vals[args[1]], vals[args[2]]);
-                    reset_temp(state, vals, gen_args[0], nb_temps, nb_globals);
-                    state[gen_args[0]] = TCG_TEMP_CONST;
-                    vals[gen_args[0]] = gen_args[1];
-                    gen_args += 2;
-                    args += 3;
-                    break;
-                } else {
-                    reset_temp(state, vals, args[0], nb_temps, nb_globals);
-                    gen_args[0] = args[0];
-                    gen_args[1] = args[1];
-                    gen_args[2] = args[2];
-                    gen_args += 3;
-                    args += 3;
-                    break;
-                }
-            case INDEX_op_call:
-            case INDEX_op_jmp:
-            case INDEX_op_br:
-            case INDEX_op_brcond_i32:
-            case INDEX_op_set_label:
-#if TCG_TARGET_REG_BITS == 64
-            case INDEX_op_brcond_i64:
-#endif
-                memset(state, 0, nb_temps * sizeof(tcg_temp_state));
-                i = (op == INDEX_op_call) ?
-                    (args[0] >> 16) + (args[0] & 0xffff) + 3 :
-                    def->nb_args;
-                while (i) {
-                    *gen_args = *args;
-                    args++;
-                    gen_args++;
-                    i--;
-                }
+            }
+        CASE_OP_32_64(add):
+        CASE_OP_32_64(sub):
+        CASE_OP_32_64(mul):
+        CASE_OP_32_64(or):
+        CASE_OP_32_64(and):
+        CASE_OP_32_64(xor):
+        CASE_OP_32_64(shl):
+        CASE_OP_32_64(shr):
+        CASE_OP_32_64(sar):
+        CASE_OP_32_64(rotl):
+        CASE_OP_32_64(rotr):
+        CASE_OP_32_64(andc):
+        CASE_OP_32_64(orc):
+        CASE_OP_32_64(eqv):
+        CASE_OP_32_64(nand):
+        CASE_OP_32_64(nor):
+            if (temps[args[1]].state == TCG_TEMP_CONST
+                && temps[args[2]].state == TCG_TEMP_CONST) {
+                gen_opc_buf[op_index] = op_to_movi(op);
+                tmp = do_constant_folding(op, temps[args[1]].val,
+                                          temps[args[2]].val);
+                tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals);
+                gen_args += 2;
+                args += 3;
                 break;
-            default:
-                /* Default case: we do know nothing about operation so no
-                   propagation is done.  We only trash output args.  */
-                for (i = 0; i < def->nb_oargs; i++) {
-                    reset_temp(state, vals, args[i], nb_temps, nb_globals);
-                }
-                for (i = 0; i < def->nb_args; i++) {
-                    gen_args[i] = args[i];
-                }
-                args += def->nb_args;
-                gen_args += def->nb_args;
+            } else {
+                reset_temp(args[0], nb_temps, nb_globals);
+                gen_args[0] = args[0];
+                gen_args[1] = args[1];
+                gen_args[2] = args[2];
+                gen_args += 3;
+                args += 3;
                 break;
+            }
+        case INDEX_op_call:
+            nb_call_args = (args[0] >> 16) + (args[0] & 0xffff);
+            if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) {
+                for (i = 0; i < nb_globals; i++) {
+                    reset_temp(i, nb_temps, nb_globals);
+                }
+            }
+            for (i = 0; i < (args[0] >> 16); i++) {
+                reset_temp(args[i + 1], nb_temps, nb_globals);
+            }
+            i = nb_call_args + 3;
+            while (i) {
+                *gen_args = *args;
+                args++;
+                gen_args++;
+                i--;
+            }
+            break;
+        case INDEX_op_set_label:
+        case INDEX_op_jmp:
+        case INDEX_op_br:
+        CASE_OP_32_64(brcond):
+            memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info));
+            for (i = 0; i < def->nb_args; i++) {
+                *gen_args = *args;
+                args++;
+                gen_args++;
+            }
+            break;
+        default:
+            /* Default case: we do know nothing about operation so no
+               propagation is done.  We only trash output args.  */
+            for (i = 0; i < def->nb_oargs; i++) {
+                reset_temp(args[i], nb_temps, nb_globals);
+            }
+            for (i = 0; i < def->nb_args; i++) {
+                gen_args[i] = args[i];
+            }
+            args += def->nb_args;
+            gen_args += def->nb_args;
+            break;
         }
     }
 
-       if (vals)
-               free(vals);
-       if (state)
-               free(state);
-
     return gen_args;
 }
 
index 7970268e5a89243369808c5db61b2f67a829a468..f5d9bf3b00b5bbab8f815abee8172aed18abdc6a 100644 (file)
@@ -160,8 +160,7 @@ static const int tcg_target_callee_save_regs[] = {
     TCG_REG_R24,
     TCG_REG_R25,
     TCG_REG_R26,
-    /* TCG_REG_R27, */ /* currently used for the global env, so no
-                          need to save */
+    TCG_REG_R27, /* currently used for the global env */
     TCG_REG_R28,
     TCG_REG_R29,
     TCG_REG_R30,
@@ -437,13 +436,13 @@ static const uint32_t tcg_to_bc[10] = {
     [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
 };
 
-static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
 {
     tcg_out32 (s, OR | SAB (arg, ret, arg));
 }
 
 static void tcg_out_movi(TCGContext *s, TCGType type,
-                         int ret, tcg_target_long arg)
+                         TCGReg ret, tcg_target_long arg)
 {
     if (arg == (int16_t) arg)
         tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
@@ -526,13 +525,13 @@ static void *qemu_st_helpers[4] = {
 
 static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 {
-    int addr_reg, data_reg, data_reg2, r0, r1, rbase, mem_index, s_bits, bswap;
+    int addr_reg, data_reg, data_reg2, r0, r1, rbase, bswap;
 #ifdef CONFIG_SOFTMMU
-    int r2;
+    int mem_index, s_bits, r2;
     void *label1_ptr, *label2_ptr;
-#endif
 #if TARGET_LONG_BITS == 64
     int addr_reg2;
+#endif
 #endif
 
     data_reg = *args++;
@@ -541,13 +540,13 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     else
         data_reg2 = 0;
     addr_reg = *args++;
+
+#ifdef CONFIG_SOFTMMU
 #if TARGET_LONG_BITS == 64
     addr_reg2 = *args++;
 #endif
     mem_index = *args;
     s_bits = opc & 3;
-
-#ifdef CONFIG_SOFTMMU
     r0 = 3;
     r1 = 4;
     r2 = 0;
@@ -723,13 +722,13 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 
 static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
 {
-    int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap, rbase;
+    int addr_reg, r0, r1, data_reg, data_reg2, bswap, rbase;
 #ifdef CONFIG_SOFTMMU
-    int r2, ir;
+    int mem_index, r2, ir;
     void *label1_ptr, *label2_ptr;
-#endif
 #if TARGET_LONG_BITS == 64
     int addr_reg2;
+#endif
 #endif
 
     data_reg = *args++;
@@ -738,12 +737,12 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     else
         data_reg2 = 0;
     addr_reg = *args++;
+
+#ifdef CONFIG_SOFTMMU
 #if TARGET_LONG_BITS == 64
     addr_reg2 = *args++;
 #endif
     mem_index = *args;
-
-#ifdef CONFIG_SOFTMMU
     r0 = 3;
     r1 = 4;
     r2 = 0;
@@ -908,9 +907,14 @@ static void tcg_target_qemu_prologue (TCGContext *s)
         + LINKAGE_AREA_SIZE
         + TCG_STATIC_CALL_ARGS_SIZE
         + ARRAY_SIZE (tcg_target_callee_save_regs) * 4
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
         ;
     frame_size = (frame_size + 15) & ~15;
 
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
 #ifdef _CALL_AIX
     {
         uint32_t addr;
@@ -939,7 +943,8 @@ static void tcg_target_qemu_prologue (TCGContext *s)
     }
 #endif
 
-    tcg_out32 (s, MTSPR | RS (3) | CTR);
+    tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
     tcg_out32 (s, BCCTR | BO_ALWAYS);
     tb_ret_addr = s->code_ptr;
 
@@ -956,13 +961,13 @@ static void tcg_target_qemu_prologue (TCGContext *s)
     tcg_out32 (s, BCLR | BO_ALWAYS);
 }
 
-static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+static void tcg_out_ld (TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
                         tcg_target_long arg2)
 {
     tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
 }
 
-static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+static void tcg_out_st (TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
                         tcg_target_long arg2)
 {
     tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
@@ -982,11 +987,6 @@ static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si)
     }
 }
 
-static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
-    ppc_addi (s, reg, reg, val);
-}
-
 static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
                          int const_arg2, int cr)
 {
@@ -1790,6 +1790,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
         }
         break;
 
+    case INDEX_op_deposit_i32:
+        tcg_out32 (s, RLWIMI
+                   | RA (args[0])
+                   | RS (args[2])
+                   | SH (args[3])
+                   | MB (32 - args[3] - args[4])
+                   | ME (31 - args[3])
+            );
+        break;
+
     default:
         tcg_dump_ops (s, stderr);
         tcg_abort ();
@@ -1885,6 +1895,8 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { INDEX_op_ext16s_i32, { "r", "r" } },
     { INDEX_op_ext16u_i32, { "r", "r" } },
 
+    { INDEX_op_deposit_i32, { "r", "0", "r" } },
+
     { -1 },
 };
 
index a1f85997c6a1a8bcc7cc89812fdbf81a3b76fcb8..3f22aaac9d3b7f15b435d32f873803be48ac7acf 100644 (file)
  */
 #define TCG_TARGET_PPC 1
 
-#define TCG_TARGET_REG_BITS 32
 #define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
-enum {
+typedef enum {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
     TCG_REG_R2,
@@ -60,7 +59,7 @@ enum {
     TCG_REG_R29,
     TCG_REG_R30,
     TCG_REG_R31
-};
+} TCGReg;
 
 /* used for function call generation */
 #define TCG_REG_CALL_STACK TCG_REG_R1
@@ -77,22 +76,27 @@ enum {
 #endif
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_andc_i32
-#define TCG_TARGET_HAS_orc_i32
-#define TCG_TARGET_HAS_eqv_i32
-#define TCG_TARGET_HAS_nand_i32
-#define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_div_i32          1
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        1
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_andc_i32         1
+#define TCG_TARGET_HAS_orc_i32          1
+#define TCG_TARGET_HAS_eqv_i32          1
+#define TCG_TARGET_HAS_nand_i32         1
+#define TCG_TARGET_HAS_nor_i32          1
+#define TCG_TARGET_HAS_deposit_i32      1
 
 #define TCG_AREG0 TCG_REG_R27
 
 #define TCG_TARGET_HAS_GUEST_BASE
+
+#define tcg_qemu_tb_exec(env, tb_ptr) \
+    ((long REGPARM __attribute__ ((longcall)) \
+      (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
index ebbee343fdf65c78bdbbea48f55cb99b36c77223..44193784f25b12ff5234c136dd98fc592942c024 100644 (file)
@@ -130,7 +130,7 @@ static const int tcg_target_call_iarg_regs[] = {
     TCG_REG_R10
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_R3
 };
 
@@ -151,8 +151,7 @@ static const int tcg_target_callee_save_regs[] = {
     TCG_REG_R24,
     TCG_REG_R25,
     TCG_REG_R26,
-    /* TCG_REG_R27, */ /* currently used for the global env, so no
-                          need to save */
+    TCG_REG_R27, /* currently used for the global env */
     TCG_REG_R28,
     TCG_REG_R29,
     TCG_REG_R30,
@@ -356,6 +355,7 @@ static int tcg_target_const_match (tcg_target_long val,
 #define SRAWI  XO31(824)
 #define NEG    XO31(104)
 #define MFCR   XO31( 19)
+#define NOR    XO31(124)
 #define CNTLZW XO31( 26)
 #define CNTLZD XO31( 58)
 
@@ -435,7 +435,7 @@ static const uint32_t tcg_to_bc[10] = {
     [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
 };
 
-static void tcg_out_mov (TCGContext *s, TCGType type, int ret, int arg)
+static void tcg_out_mov (TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
 {
     tcg_out32 (s, OR | SAB (arg, ret, arg));
 }
@@ -459,7 +459,7 @@ static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg)
 }
 
 static void tcg_out_movi (TCGContext *s, TCGType type,
-                          int ret, tcg_target_long arg)
+                          TCGReg ret, tcg_target_long arg)
 {
     int32_t arg32 = arg;
     arg = type == TCG_TYPE_I32 ? arg & 0xffffffff : arg;
@@ -616,18 +616,19 @@ static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2,
 
 static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 {
-    int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap;
+    int addr_reg, data_reg, r0, r1, rbase, bswap;
 #ifdef CONFIG_SOFTMMU
-    int r2;
+    int r2, mem_index, s_bits;
     void *label1_ptr, *label2_ptr;
 #endif
 
     data_reg = *args++;
     addr_reg = *args++;
+
+#ifdef CONFIG_SOFTMMU
     mem_index = *args;
     s_bits = opc & 3;
 
-#ifdef CONFIG_SOFTMMU
     r0 = 3;
     r1 = 4;
     r2 = 0;
@@ -763,17 +764,18 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 
 static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
 {
-    int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap;
+    int addr_reg, r0, r1, rbase, data_reg, bswap;
 #ifdef CONFIG_SOFTMMU
-    int r2;
+    int r2, mem_index;
     void *label1_ptr, *label2_ptr;
 #endif
 
     data_reg = *args++;
     addr_reg = *args++;
-    mem_index = *args;
 
 #ifdef CONFIG_SOFTMMU
+    mem_index = *args;
+
     r0 = 3;
     r1 = 4;
     r2 = 0;
@@ -876,9 +878,14 @@ static void tcg_target_qemu_prologue (TCGContext *s)
         + 8                     /* TOC save area */
         + TCG_STATIC_CALL_ARGS_SIZE
         + ARRAY_SIZE (tcg_target_callee_save_regs) * 8
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
         ;
     frame_size = (frame_size + 15) & ~15;
 
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
 #ifndef __APPLE__
     /* First emit adhoc function descriptor */
     addr = (uint64_t) s->code_ptr + 24;
@@ -905,7 +912,8 @@ static void tcg_target_qemu_prologue (TCGContext *s)
     }
 #endif
 
-    tcg_out32 (s, MTSPR | RS (3) | CTR);
+    tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
     tcg_out32 (s, BCCTR | BO_ALWAYS);
 
     /* Epilogue */
@@ -924,7 +932,7 @@ static void tcg_target_qemu_prologue (TCGContext *s)
     tcg_out32 (s, BCLR | BO_ALWAYS);
 }
 
-static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+static void tcg_out_ld (TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
                         tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32)
@@ -933,7 +941,7 @@ static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
         tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX);
 }
 
-static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+static void tcg_out_st (TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
                         tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32)
@@ -968,11 +976,6 @@ static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si)
     }
 }
 
-static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val)
-{
-    ppc_addi64 (s, reg, reg, val);
-}
-
 static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
                          int const_arg2, int cr, int arch64)
 {
@@ -1449,6 +1452,11 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
         tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
         break;
 
+    case INDEX_op_not_i32:
+    case INDEX_op_not_i64:
+        tcg_out32 (s, NOR | SAB (args[1], args[0], args[1]));
+        break;
+
     case INDEX_op_add_i64:
         if (const_args[2])
             ppc_addi64 (s, args[0], args[1], args[2]);
@@ -1553,6 +1561,10 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
         tcg_out32 (s, c | RS (args[1]) | RA (args[0]));
         break;
 
+    case INDEX_op_ext32u_i64:
+        tcg_out_rld (s, RLDICL, args[0], args[1], 0, 32);
+        break;
+
     case INDEX_op_setcond_i32:
         tcg_out_setcond (s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
                          const_args[2]);
@@ -1621,6 +1633,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { INDEX_op_brcond_i64, { "r", "ri" } },
 
     { INDEX_op_neg_i32, { "r", "r" } },
+    { INDEX_op_not_i32, { "r", "r" } },
 
     { INDEX_op_add_i64, { "r", "r", "ri" } },
     { INDEX_op_sub_i64, { "r", "r", "ri" } },
@@ -1639,6 +1652,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { INDEX_op_remu_i64, { "r", "r", "r" } },
 
     { INDEX_op_neg_i64, { "r", "r" } },
+    { INDEX_op_not_i64, { "r", "r" } },
 
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
@@ -1659,6 +1673,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { INDEX_op_ext8s_i64, { "r", "r" } },
     { INDEX_op_ext16s_i64, { "r", "r" } },
     { INDEX_op_ext32s_i64, { "r", "r" } },
+    { INDEX_op_ext32u_i64, { "r", "r" } },
 
     { INDEX_op_setcond_i32, { "r", "r", "ri" } },
     { INDEX_op_setcond_i64, { "r", "r", "ri" } },
index 8a6db111a7ea4701df667b764408710bdd261036..97eec0843de243c69c34fca45a7b8dedb7380665 100644 (file)
  */
 #define TCG_TARGET_PPC64 1
 
-#define TCG_TARGET_REG_BITS 64
 #define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
-enum {
+typedef enum {
     TCG_REG_R0 = 0,
     TCG_REG_R1,
     TCG_REG_R2,
@@ -60,7 +59,7 @@ enum {
     TCG_REG_R29,
     TCG_REG_R30,
     TCG_REG_R31
-};
+} TCGReg;
 
 /* used for function call generation */
 #define TCG_REG_CALL_STACK TCG_REG_R1
@@ -68,40 +67,42 @@ enum {
 #define TCG_TARGET_CALL_STACK_OFFSET 48
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div_i32
-/* #define TCG_TARGET_HAS_rot_i32 */
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-/* #define TCG_TARGET_HAS_ext8u_i32 */
-/* #define TCG_TARGET_HAS_ext16u_i32 */
-/* #define TCG_TARGET_HAS_bswap16_i32 */
-/* #define TCG_TARGET_HAS_bswap32_i32 */
-/* #define TCG_TARGET_HAS_not_i32 */
-#define TCG_TARGET_HAS_neg_i32
-/* #define TCG_TARGET_HAS_andc_i32 */
-/* #define TCG_TARGET_HAS_orc_i32 */
-/* #define TCG_TARGET_HAS_eqv_i32 */
-/* #define TCG_TARGET_HAS_nand_i32 */
-/* #define TCG_TARGET_HAS_nor_i32 */
+#define TCG_TARGET_HAS_div_i32          1
+#define TCG_TARGET_HAS_rot_i32          0
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        0
+#define TCG_TARGET_HAS_ext16u_i32       0
+#define TCG_TARGET_HAS_bswap16_i32      0
+#define TCG_TARGET_HAS_bswap32_i32      0
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_andc_i32         0
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      0
 
-#define TCG_TARGET_HAS_div_i64
-/* #define TCG_TARGET_HAS_rot_i64 */
-#define TCG_TARGET_HAS_ext8s_i64
-#define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-/* #define TCG_TARGET_HAS_ext8u_i64 */
-/* #define TCG_TARGET_HAS_ext16u_i64 */
-/* #define TCG_TARGET_HAS_ext32u_i64 */
-/* #define TCG_TARGET_HAS_bswap16_i64 */
-/* #define TCG_TARGET_HAS_bswap32_i64 */
-/* #define TCG_TARGET_HAS_bswap64_i64 */
-/* #define TCG_TARGET_HAS_not_i64 */
-#define TCG_TARGET_HAS_neg_i64
-/* #define TCG_TARGET_HAS_andc_i64 */
-/* #define TCG_TARGET_HAS_orc_i64 */
-/* #define TCG_TARGET_HAS_eqv_i64 */
-/* #define TCG_TARGET_HAS_nand_i64 */
-/* #define TCG_TARGET_HAS_nor_i64 */
+#define TCG_TARGET_HAS_div_i64          1
+#define TCG_TARGET_HAS_rot_i64          0
+#define TCG_TARGET_HAS_ext8s_i64        1
+#define TCG_TARGET_HAS_ext16s_i64       1
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i64        0
+#define TCG_TARGET_HAS_ext16u_i64       0
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_bswap16_i64      0
+#define TCG_TARGET_HAS_bswap32_i64      0
+#define TCG_TARGET_HAS_bswap64_i64      0
+#define TCG_TARGET_HAS_not_i64          1
+#define TCG_TARGET_HAS_neg_i64          1
+#define TCG_TARGET_HAS_andc_i64         0
+#define TCG_TARGET_HAS_orc_i64          0
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_deposit_i64      0
 
 #define TCG_AREG0 TCG_REG_R27
 
index 450fcabd705af41a6cf53bbef8c9e464d96cbbf3..9317fe88ef2d08f006de907dd4f744a487b570cc 100644 (file)
@@ -252,7 +252,9 @@ static const int tcg_target_call_iarg_regs[] = {
 
 static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_R2,
-    TCG_REG_R3,
+#if TCG_TARGET_REG_BITS == 32
+    TCG_REG_R3
+#endif
 };
 
 #define S390_CC_EQ      8
@@ -2291,6 +2293,8 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
 
     tcg_add_target_add_op_defs(s390_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
 
 static void tcg_target_qemu_prologue(TCGContext *s)
@@ -2306,8 +2310,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
         tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
     }
 
-    /* br %r2 (go to TB) */
-    tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R2);
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    /* br %r3 (go to TB) */
+    tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]);
 
     tb_ret_addr = s->code_ptr;
 
@@ -2317,8 +2322,3 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     /* br %r14 (return) */
     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
 }
-
-static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
-    tcg_abort();
-}
index 4e45cf31410c93fb2e49327e9febc7a96f609e3c..e4cd6418a9adb9b6506cbb372365a96eb9a86b57 100644 (file)
  */
 #define TCG_TARGET_S390 1
 
-#ifdef __s390x__
-#define TCG_TARGET_REG_BITS 64
-#else
-#define TCG_TARGET_REG_BITS 32
-#endif
-
 #define TCG_TARGET_WORDS_BIGENDIAN
 
 typedef enum TCGReg {
@@ -53,41 +47,43 @@ typedef enum TCGReg {
 #define TCG_TARGET_NB_REGS 16
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div2_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-// #define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_neg_i32
-// #define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
-// #define TCG_TARGET_HAS_eqv_i32
-// #define TCG_TARGET_HAS_nand_i32
-// #define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_div2_i32         1
+#define TCG_TARGET_HAS_rot_i32          1
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        1
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+#define TCG_TARGET_HAS_not_i32          0
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_andc_i32         0
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      0
 
 #if TCG_TARGET_REG_BITS == 64
-#define TCG_TARGET_HAS_div2_i64
-#define TCG_TARGET_HAS_rot_i64
-#define TCG_TARGET_HAS_ext8s_i64
-#define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-#define TCG_TARGET_HAS_ext8u_i64
-#define TCG_TARGET_HAS_ext16u_i64
-#define TCG_TARGET_HAS_ext32u_i64
-#define TCG_TARGET_HAS_bswap16_i64
-#define TCG_TARGET_HAS_bswap32_i64
-#define TCG_TARGET_HAS_bswap64_i64
-// #define TCG_TARGET_HAS_not_i64
-#define TCG_TARGET_HAS_neg_i64
-// #define TCG_TARGET_HAS_andc_i64
-// #define TCG_TARGET_HAS_orc_i64
-// #define TCG_TARGET_HAS_eqv_i64
-// #define TCG_TARGET_HAS_nand_i64
-// #define TCG_TARGET_HAS_nor_i64
+#define TCG_TARGET_HAS_div2_i64         1
+#define TCG_TARGET_HAS_rot_i64          1
+#define TCG_TARGET_HAS_ext8s_i64        1
+#define TCG_TARGET_HAS_ext16s_i64       1
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i64        1
+#define TCG_TARGET_HAS_ext16u_i64       1
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_bswap16_i64      1
+#define TCG_TARGET_HAS_bswap32_i64      1
+#define TCG_TARGET_HAS_bswap64_i64      1
+#define TCG_TARGET_HAS_not_i64          0
+#define TCG_TARGET_HAS_neg_i64          1
+#define TCG_TARGET_HAS_andc_i64         0
+#define TCG_TARGET_HAS_orc_i64          0
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_deposit_i64      0
 #endif
 
 #define TCG_TARGET_HAS_GUEST_BASE
index 5f1353adf84b4c47370f7117a118232b8b98a3e2..5cd5a3b6f6eddc5e5aae90b8a7ce44e48714a1a8 100644 (file)
@@ -84,9 +84,11 @@ static const int tcg_target_call_iarg_regs[6] = {
     TCG_REG_O5,
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_O0,
-    TCG_REG_O1,
+#if TCG_TARGET_REG_BITS == 32
+    TCG_REG_O1
+#endif
 };
 
 static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
@@ -304,7 +306,8 @@ static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
               | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
 }
 
-static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+                               TCGReg ret, TCGReg arg)
 {
     tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR);
 }
@@ -331,7 +334,7 @@ static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg)
 }
 
 static inline void tcg_out_movi(TCGContext *s, TCGType type,
-                                int ret, tcg_target_long arg)
+                                TCGReg ret, tcg_target_long arg)
 {
     /* All 32-bit constants, as well as 64-bit constants with
        no high bits set go through movi_imm32.  */
@@ -396,8 +399,8 @@ static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr,
               INSN_ASI(asi) | INSN_RS2(addr));
 }
 
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32)
         tcg_out_ldst(s, ret, arg1, arg2, LDUW);
@@ -405,8 +408,8 @@ static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
         tcg_out_ldst(s, ret, arg1, arg2, LDX);
 }
 
-static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
-                              int arg1, tcg_target_long arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+                              TCGReg arg1, tcg_target_long arg2)
 {
     if (type == TCG_TYPE_I32)
         tcg_out_ldst(s, arg, arg1, arg2, STW);
@@ -470,11 +473,9 @@ static inline void tcg_out_nop(TCGContext *s)
 
 static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
 {
-    int32_t val;
     TCGLabel *l = &s->labels[label_index];
 
     if (l->has_value) {
-        val = l->u.value - (tcg_target_long)s->code_ptr;
         tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2)
                       | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr)));
     } else {
@@ -486,11 +487,9 @@ static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
 #if TCG_TARGET_REG_BITS == 64
 static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index)
 {
-    int32_t val;
     TCGLabel *l = &s->labels[label_index];
 
     if (l->has_value) {
-        val = l->u.value - (tcg_target_long)s->code_ptr;
         tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
                       (0x5 << 19) |
                       INSN_OFF19(l->u.value - (unsigned long)s->code_ptr)));
@@ -693,11 +692,14 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
 /* Generate global QEMU prologue and epilogue code */
 static void tcg_target_qemu_prologue(TCGContext *s)
 {
+    tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_CALL_STACK_OFFSET,
+                  CPU_TEMP_BUF_NLONGS * (int)sizeof(long));
     tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
-              INSN_IMM13(-TCG_TARGET_STACK_MINFRAME));
-    tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) |
+              INSN_IMM13(-(TCG_TARGET_STACK_MINFRAME +
+                           CPU_TEMP_BUF_NLONGS * (int)sizeof(long))));
+    tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I1) |
               INSN_RS2(TCG_REG_G0));
-    tcg_out_nop(s);
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_I0);
 }
 
 #if defined(CONFIG_SOFTMMU)
index df0785ec6877537ebb0371dca9ea0592c17cfa1c..c3fe1311193fcdb69719528b9aea17944292ba34 100644 (file)
  */
 #define TCG_TARGET_SPARC 1
 
-#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
-#define TCG_TARGET_REG_BITS 64
-#else
-#define TCG_TARGET_REG_BITS 32
-#endif
-
 #define TCG_TARGET_WORDS_BIGENDIAN
 
 #define TCG_TARGET_NB_REGS 32
 
-enum {
+typedef enum {
     TCG_REG_G0 = 0,
     TCG_REG_G1,
     TCG_REG_G2,
@@ -66,7 +60,7 @@ enum {
     TCG_REG_I5,
     TCG_REG_I6,
     TCG_REG_I7,
-};
+} TCGReg;
 
 #define TCG_CT_CONST_S11 0x100
 #define TCG_CT_CONST_S13 0x200
@@ -92,41 +86,43 @@ enum {
 #endif
 
 /* optional instructions */
-#define TCG_TARGET_HAS_div_i32
-// #define TCG_TARGET_HAS_rot_i32
-// #define TCG_TARGET_HAS_ext8s_i32
-// #define TCG_TARGET_HAS_ext16s_i32
-// #define TCG_TARGET_HAS_ext8u_i32
-// #define TCG_TARGET_HAS_ext16u_i32
-// #define TCG_TARGET_HAS_bswap16_i32
-// #define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_andc_i32
-#define TCG_TARGET_HAS_orc_i32
-// #define TCG_TARGET_HAS_eqv_i32
-// #define TCG_TARGET_HAS_nand_i32
-// #define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_div_i32         1
+#define TCG_TARGET_HAS_rot_i32          0
+#define TCG_TARGET_HAS_ext8s_i32        0
+#define TCG_TARGET_HAS_ext16s_i32       0
+#define TCG_TARGET_HAS_ext8u_i32        0
+#define TCG_TARGET_HAS_ext16u_i32       0
+#define TCG_TARGET_HAS_bswap16_i32      0
+#define TCG_TARGET_HAS_bswap32_i32      0
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_andc_i32         1
+#define TCG_TARGET_HAS_orc_i32          1
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_deposit_i32      0
 
 #if TCG_TARGET_REG_BITS == 64
-#define TCG_TARGET_HAS_div_i64
-// #define TCG_TARGET_HAS_rot_i64
-// #define TCG_TARGET_HAS_ext8s_i64
-// #define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-// #define TCG_TARGET_HAS_ext8u_i64
-// #define TCG_TARGET_HAS_ext16u_i64
-#define TCG_TARGET_HAS_ext32u_i64
-// #define TCG_TARGET_HAS_bswap16_i64
-// #define TCG_TARGET_HAS_bswap32_i64
-// #define TCG_TARGET_HAS_bswap64_i64
-#define TCG_TARGET_HAS_neg_i64
-#define TCG_TARGET_HAS_not_i64
-#define TCG_TARGET_HAS_andc_i64
-#define TCG_TARGET_HAS_orc_i64
-// #define TCG_TARGET_HAS_eqv_i64
-// #define TCG_TARGET_HAS_nand_i64
-// #define TCG_TARGET_HAS_nor_i64
+#define TCG_TARGET_HAS_div_i64          1
+#define TCG_TARGET_HAS_rot_i64          0
+#define TCG_TARGET_HAS_ext8s_i64        0
+#define TCG_TARGET_HAS_ext16s_i64       0
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i64        0
+#define TCG_TARGET_HAS_ext16u_i64       0
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_bswap16_i64      0
+#define TCG_TARGET_HAS_bswap32_i64      0
+#define TCG_TARGET_HAS_bswap64_i64      0
+#define TCG_TARGET_HAS_neg_i64          1
+#define TCG_TARGET_HAS_not_i64          1
+#define TCG_TARGET_HAS_andc_i64         1
+#define TCG_TARGET_HAS_orc_i64          1
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_deposit_i64      0
 #endif
 
 /* Note: must be synced with dyngen-exec.h */
index 2b93b7d20fbbe9513d7b32af0dd9286d0eb0de03..82e04e7f30813b61cbd921761c27a5e474f89e9f 100644 (file)
@@ -664,107 +664,81 @@ static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
     tcg_temp_free_i32(t0);
 }
 
-#ifdef TCG_TARGET_HAS_div_i32
 static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
-}
-#elif defined(TCG_TARGET_HAS_div2_i32)
-static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_sari_i32(t0, arg1, 31);
-    tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
-    tcg_temp_free_i32(t0);
-}
-
-static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_sari_i32(t0, arg1, 31);
-    tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
-    tcg_temp_free_i32(t0);
-}
-
-static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_movi_i32(t0, 0);
-    tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
-    tcg_temp_free_i32(t0);
-}
-
-static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_movi_i32(t0, 0);
-    tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
-    tcg_temp_free_i32(t0);
-}
-#else
-static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    int sizemask = 0;
-    /* Return value and both arguments are 32-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 0, 1);
-    sizemask |= tcg_gen_sizemask(1, 0, 1);
-    sizemask |= tcg_gen_sizemask(2, 0, 1);
-
-    tcg_gen_helper32(tcg_helper_div_i32, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i32) {
+        tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i32) {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_sari_i32(t0, arg1, 31);
+        tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
+        tcg_temp_free_i32(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 32-bit and signed.  */
+        sizemask |= tcg_gen_sizemask(0, 0, 1);
+        sizemask |= tcg_gen_sizemask(1, 0, 1);
+        sizemask |= tcg_gen_sizemask(2, 0, 1);
+        tcg_gen_helper32(tcg_helper_div_i32, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 32-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 0, 1);
-    sizemask |= tcg_gen_sizemask(1, 0, 1);
-    sizemask |= tcg_gen_sizemask(2, 0, 1);
-
-    tcg_gen_helper32(tcg_helper_rem_i32, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i32) {
+        tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i32) {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_sari_i32(t0, arg1, 31);
+        tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
+        tcg_temp_free_i32(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 32-bit and signed.  */
+        sizemask |= tcg_gen_sizemask(0, 0, 1);
+        sizemask |= tcg_gen_sizemask(1, 0, 1);
+        sizemask |= tcg_gen_sizemask(2, 0, 1);
+        tcg_gen_helper32(tcg_helper_rem_i32, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 32-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 0, 0);
-    sizemask |= tcg_gen_sizemask(1, 0, 0);
-    sizemask |= tcg_gen_sizemask(2, 0, 0);
-
-    tcg_gen_helper32(tcg_helper_divu_i32, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i32) {
+        tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i32) {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_movi_i32(t0, 0);
+        tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
+        tcg_temp_free_i32(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 32-bit and unsigned.  */
+        sizemask |= tcg_gen_sizemask(0, 0, 0);
+        sizemask |= tcg_gen_sizemask(1, 0, 0);
+        sizemask |= tcg_gen_sizemask(2, 0, 0);
+        tcg_gen_helper32(tcg_helper_divu_i32, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 32-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 0, 0);
-    sizemask |= tcg_gen_sizemask(1, 0, 0);
-    sizemask |= tcg_gen_sizemask(2, 0, 0);
-
-    tcg_gen_helper32(tcg_helper_remu_i32, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i32) {
+        tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i32) {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_movi_i32(t0, 0);
+        tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
+        tcg_temp_free_i32(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 32-bit and unsigned.  */
+        sizemask |= tcg_gen_sizemask(0, 0, 0);
+        sizemask |= tcg_gen_sizemask(1, 0, 0);
+        sizemask |= tcg_gen_sizemask(2, 0, 0);
+        tcg_gen_helper32(tcg_helper_remu_i32, sizemask, ret, arg1, arg2);
+    }
 }
-#endif
 
 #if TCG_TARGET_REG_BITS == 32
 
@@ -1063,66 +1037,66 @@ static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
     tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg);
 }
 
-static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                     tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                     tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                      tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                      tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                      tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
                                      tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset)
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
                                    tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
                                     tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
                                     tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset)
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
 {
     tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset);
 }
@@ -1250,109 +1224,82 @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
     tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2);
 }
 
-#ifdef TCG_TARGET_HAS_div_i64
-static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
-}
-#elif defined(TCG_TARGET_HAS_div2_i64)
-static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_sari_i64(t0, arg1, 63);
-    tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
-    tcg_temp_free_i64(t0);
-}
-
-static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_sari_i64(t0, arg1, 63);
-    tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
-    tcg_temp_free_i64(t0);
-}
-
-static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_movi_i64(t0, 0);
-    tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
-    tcg_temp_free_i64(t0);
-}
-
-static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
-{
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_movi_i64(t0, 0);
-    tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
-    tcg_temp_free_i64(t0);
-}
-#else
 static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i64) {
+        tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i64) {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_sari_i64(t0, arg1, 63);
+        tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
+        tcg_temp_free_i64(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 64-bit and signed.  */
+        sizemask |= tcg_gen_sizemask(0, 1, 1);
+        sizemask |= tcg_gen_sizemask(1, 1, 1);
+        sizemask |= tcg_gen_sizemask(2, 1, 1);
+        tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i64) {
+        tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i64) {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_sari_i64(t0, arg1, 63);
+        tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
+        tcg_temp_free_i64(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 64-bit and signed.  */
+        sizemask |= tcg_gen_sizemask(0, 1, 1);
+        sizemask |= tcg_gen_sizemask(1, 1, 1);
+        sizemask |= tcg_gen_sizemask(2, 1, 1);
+        tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 0);
-    sizemask |= tcg_gen_sizemask(1, 1, 0);
-    sizemask |= tcg_gen_sizemask(2, 1, 0);
-
-    tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i64) {
+        tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i64) {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_movi_i64(t0, 0);
+        tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
+        tcg_temp_free_i64(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 64-bit and unsigned.  */
+        sizemask |= tcg_gen_sizemask(0, 1, 0);
+        sizemask |= tcg_gen_sizemask(1, 1, 0);
+        sizemask |= tcg_gen_sizemask(2, 1, 0);
+        tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+    }
 }
 
 static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 0);
-    sizemask |= tcg_gen_sizemask(1, 1, 0);
-    sizemask |= tcg_gen_sizemask(2, 1, 0);
-
-    tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+    if (TCG_TARGET_HAS_div_i64) {
+        tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
+    } else if (TCG_TARGET_HAS_div2_i64) {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_movi_i64(t0, 0);
+        tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
+        tcg_temp_free_i64(t0);
+    } else {
+        int sizemask = 0;
+        /* Return value and both arguments are 64-bit and unsigned.  */
+        sizemask |= tcg_gen_sizemask(0, 1, 0);
+        sizemask |= tcg_gen_sizemask(1, 1, 0);
+        sizemask |= tcg_gen_sizemask(2, 1, 0);
+        tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+    }
 }
-#endif
-
-#endif
+#endif /* TCG_TARGET_REG_BITS == 32 */
 
 static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
@@ -1413,82 +1360,82 @@ static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 
 static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_ext8s_i32
-    tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
-#else
-    tcg_gen_shli_i32(ret, arg, 24);
-    tcg_gen_sari_i32(ret, ret, 24);
-#endif
+    if (TCG_TARGET_HAS_ext8s_i32) {
+        tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
+    } else {
+        tcg_gen_shli_i32(ret, arg, 24);
+        tcg_gen_sari_i32(ret, ret, 24);
+    }
 }
 
 static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_ext16s_i32
-    tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
-#else
-    tcg_gen_shli_i32(ret, arg, 16);
-    tcg_gen_sari_i32(ret, ret, 16);
-#endif
+    if (TCG_TARGET_HAS_ext16s_i32) {
+        tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
+    } else {
+        tcg_gen_shli_i32(ret, arg, 16);
+        tcg_gen_sari_i32(ret, ret, 16);
+    }
 }
 
 static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_ext8u_i32
-    tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
-#else
-    tcg_gen_andi_i32(ret, arg, 0xffu);
-#endif
+    if (TCG_TARGET_HAS_ext8u_i32) {
+        tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
+    } else {
+        tcg_gen_andi_i32(ret, arg, 0xffu);
+    }
 }
 
 static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_ext16u_i32
-    tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
-#else
-    tcg_gen_andi_i32(ret, arg, 0xffffu);
-#endif
+    if (TCG_TARGET_HAS_ext16u_i32) {
+        tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
+    } else {
+        tcg_gen_andi_i32(ret, arg, 0xffffu);
+    }
 }
 
 /* Note: we assume the two high bytes are set to zero */
 static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap16_i32
-    tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
-#else
-    TCGv_i32 t0 = tcg_temp_new_i32();
-
-    tcg_gen_ext8u_i32(t0, arg);
-    tcg_gen_shli_i32(t0, t0, 8);
-    tcg_gen_shri_i32(ret, arg, 8);
-    tcg_gen_or_i32(ret, ret, t0);
-    tcg_temp_free_i32(t0);
-#endif
+    if (TCG_TARGET_HAS_bswap16_i32) {
+        tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
+    } else {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+    
+        tcg_gen_ext8u_i32(t0, arg);
+        tcg_gen_shli_i32(t0, t0, 8);
+        tcg_gen_shri_i32(ret, arg, 8);
+        tcg_gen_or_i32(ret, ret, t0);
+        tcg_temp_free_i32(t0);
+    }
 }
 
 static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap32_i32
-    tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
-#else
-    TCGv_i32 t0, t1;
-    t0 = tcg_temp_new_i32();
-    t1 = tcg_temp_new_i32();
-
-    tcg_gen_shli_i32(t0, arg, 24);
-
-    tcg_gen_andi_i32(t1, arg, 0x0000ff00);
-    tcg_gen_shli_i32(t1, t1, 8);
-    tcg_gen_or_i32(t0, t0, t1);
-
-    tcg_gen_shri_i32(t1, arg, 8);
-    tcg_gen_andi_i32(t1, t1, 0x0000ff00);
-    tcg_gen_or_i32(t0, t0, t1);
-
-    tcg_gen_shri_i32(t1, arg, 24);
-    tcg_gen_or_i32(ret, t0, t1);
-    tcg_temp_free_i32(t0);
-    tcg_temp_free_i32(t1);
-#endif
+    if (TCG_TARGET_HAS_bswap32_i32) {
+        tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
+    } else {
+        TCGv_i32 t0, t1;
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+    
+        tcg_gen_shli_i32(t0, arg, 24);
+    
+        tcg_gen_andi_i32(t1, arg, 0x0000ff00);
+        tcg_gen_shli_i32(t1, t1, 8);
+        tcg_gen_or_i32(t0, t0, t1);
+    
+        tcg_gen_shri_i32(t1, arg, 8);
+        tcg_gen_andi_i32(t1, t1, 0x0000ff00);
+        tcg_gen_or_i32(t0, t0, t1);
+    
+        tcg_gen_shri_i32(t1, arg, 24);
+        tcg_gen_or_i32(ret, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+    }
 }
 
 #if TCG_TARGET_REG_BITS == 32
@@ -1576,59 +1523,59 @@ static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
 
 static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext8s_i64
-    tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
-#else
-    tcg_gen_shli_i64(ret, arg, 56);
-    tcg_gen_sari_i64(ret, ret, 56);
-#endif
+    if (TCG_TARGET_HAS_ext8s_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
+    } else {
+        tcg_gen_shli_i64(ret, arg, 56);
+        tcg_gen_sari_i64(ret, ret, 56);
+    }
 }
 
 static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext16s_i64
-    tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
-#else
-    tcg_gen_shli_i64(ret, arg, 48);
-    tcg_gen_sari_i64(ret, ret, 48);
-#endif
+    if (TCG_TARGET_HAS_ext16s_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
+    } else {
+        tcg_gen_shli_i64(ret, arg, 48);
+        tcg_gen_sari_i64(ret, ret, 48);
+    }
 }
 
 static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext32s_i64
-    tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
-#else
-    tcg_gen_shli_i64(ret, arg, 32);
-    tcg_gen_sari_i64(ret, ret, 32);
-#endif
+    if (TCG_TARGET_HAS_ext32s_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
+    } else {
+        tcg_gen_shli_i64(ret, arg, 32);
+        tcg_gen_sari_i64(ret, ret, 32);
+    }
 }
 
 static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext8u_i64
-    tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
-#else
-    tcg_gen_andi_i64(ret, arg, 0xffu);
-#endif
+    if (TCG_TARGET_HAS_ext8u_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
+    } else {
+        tcg_gen_andi_i64(ret, arg, 0xffu);
+    }
 }
 
 static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext16u_i64
-    tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
-#else
-    tcg_gen_andi_i64(ret, arg, 0xffffu);
-#endif
+    if (TCG_TARGET_HAS_ext16u_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
+    } else {
+        tcg_gen_andi_i64(ret, arg, 0xffffu);
+    }
 }
 
 static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_ext32u_i64
-    tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
-#else
-    tcg_gen_andi_i64(ret, arg, 0xffffffffu);
-#endif
+    if (TCG_TARGET_HAS_ext32u_i64) {
+        tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
+    } else {
+        tcg_gen_andi_i64(ret, arg, 0xffffffffu);
+    }
 }
 
 /* Note: we assume the target supports move between 32 and 64 bit
@@ -1655,130 +1602,132 @@ static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
 /* Note: we assume the six high bytes are set to zero */
 static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap16_i64
-    tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
-#else
-    TCGv_i64 t0 = tcg_temp_new_i64();
+    if (TCG_TARGET_HAS_bswap16_i64) {
+        tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
+    } else {
+        TCGv_i64 t0 = tcg_temp_new_i64();
 
-    tcg_gen_ext8u_i64(t0, arg);
-    tcg_gen_shli_i64(t0, t0, 8);
-    tcg_gen_shri_i64(ret, arg, 8);
-    tcg_gen_or_i64(ret, ret, t0);
-    tcg_temp_free_i64(t0);
-#endif
+        tcg_gen_ext8u_i64(t0, arg);
+        tcg_gen_shli_i64(t0, t0, 8);
+        tcg_gen_shri_i64(ret, arg, 8);
+        tcg_gen_or_i64(ret, ret, t0);
+        tcg_temp_free_i64(t0);
+    }
 }
 
 /* Note: we assume the four high bytes are set to zero */
 static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap32_i64
-    tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
-#else
-    TCGv_i64 t0, t1;
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
+    if (TCG_TARGET_HAS_bswap32_i64) {
+        tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
+    } else {
+        TCGv_i64 t0, t1;
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
 
-    tcg_gen_shli_i64(t0, arg, 24);
-    tcg_gen_ext32u_i64(t0, t0);
+        tcg_gen_shli_i64(t0, arg, 24);
+        tcg_gen_ext32u_i64(t0, t0);
 
-    tcg_gen_andi_i64(t1, arg, 0x0000ff00);
-    tcg_gen_shli_i64(t1, t1, 8);
-    tcg_gen_or_i64(t0, t0, t1);
+        tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+        tcg_gen_shli_i64(t1, t1, 8);
+        tcg_gen_or_i64(t0, t0, t1);
 
-    tcg_gen_shri_i64(t1, arg, 8);
-    tcg_gen_andi_i64(t1, t1, 0x0000ff00);
-    tcg_gen_or_i64(t0, t0, t1);
+        tcg_gen_shri_i64(t1, arg, 8);
+        tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+        tcg_gen_or_i64(t0, t0, t1);
 
-    tcg_gen_shri_i64(t1, arg, 24);
-    tcg_gen_or_i64(ret, t0, t1);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-#endif
+        tcg_gen_shri_i64(t1, arg, 24);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+    }
 }
 
 static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap64_i64
-    tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
-#else
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-
-    tcg_gen_shli_i64(t0, arg, 56);
-
-    tcg_gen_andi_i64(t1, arg, 0x0000ff00);
-    tcg_gen_shli_i64(t1, t1, 40);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_andi_i64(t1, arg, 0x00ff0000);
-    tcg_gen_shli_i64(t1, t1, 24);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_andi_i64(t1, arg, 0xff000000);
-    tcg_gen_shli_i64(t1, t1, 8);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_shri_i64(t1, arg, 8);
-    tcg_gen_andi_i64(t1, t1, 0xff000000);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_shri_i64(t1, arg, 24);
-    tcg_gen_andi_i64(t1, t1, 0x00ff0000);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_shri_i64(t1, arg, 40);
-    tcg_gen_andi_i64(t1, t1, 0x0000ff00);
-    tcg_gen_or_i64(t0, t0, t1);
-
-    tcg_gen_shri_i64(t1, arg, 56);
-    tcg_gen_or_i64(ret, t0, t1);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-#endif
+    if (TCG_TARGET_HAS_bswap64_i64) {
+        tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
+    } else {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        TCGv_i64 t1 = tcg_temp_new_i64();
+    
+        tcg_gen_shli_i64(t0, arg, 56);
+    
+        tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+        tcg_gen_shli_i64(t1, t1, 40);
+        tcg_gen_or_i64(t0, t0, t1);
+    
+        tcg_gen_andi_i64(t1, arg, 0x00ff0000);
+        tcg_gen_shli_i64(t1, t1, 24);
+        tcg_gen_or_i64(t0, t0, t1);
+
+        tcg_gen_andi_i64(t1, arg, 0xff000000);
+        tcg_gen_shli_i64(t1, t1, 8);
+        tcg_gen_or_i64(t0, t0, t1);
+
+        tcg_gen_shri_i64(t1, arg, 8);
+        tcg_gen_andi_i64(t1, t1, 0xff000000);
+        tcg_gen_or_i64(t0, t0, t1);
+    
+        tcg_gen_shri_i64(t1, arg, 24);
+        tcg_gen_andi_i64(t1, t1, 0x00ff0000);
+        tcg_gen_or_i64(t0, t0, t1);
+
+        tcg_gen_shri_i64(t1, arg, 40);
+        tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+        tcg_gen_or_i64(t0, t0, t1);
+
+        tcg_gen_shri_i64(t1, arg, 56);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+    }
 }
 
 #endif
 
 static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_neg_i32
-    tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg);
-#else
-    TCGv_i32 t0 = tcg_const_i32(0);
-    tcg_gen_sub_i32(ret, t0, arg);
-    tcg_temp_free_i32(t0);
-#endif
+    if (TCG_TARGET_HAS_neg_i32) {
+        tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(0);
+        tcg_gen_sub_i32(ret, t0, arg);
+        tcg_temp_free_i32(t0);
+    }
 }
 
 static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_neg_i64
-    tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg);
-#else
-    TCGv_i64 t0 = tcg_const_i64(0);
-    tcg_gen_sub_i64(ret, t0, arg);
-    tcg_temp_free_i64(t0);
-#endif
+    if (TCG_TARGET_HAS_neg_i64) {
+        tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(0);
+        tcg_gen_sub_i64(ret, t0, arg);
+        tcg_temp_free_i64(t0);
+    }
 }
 
 static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_not_i32
-    tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg);
-#else
-    tcg_gen_xori_i32(ret, arg, -1);
-#endif
+    if (TCG_TARGET_HAS_not_i32) {
+        tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg);
+    } else {
+        tcg_gen_xori_i32(ret, arg, -1);
+    }
 }
 
 static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_not_i64
-    tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
-#elif defined(TCG_TARGET_HAS_not_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_not_i64) {
+        tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
+    } else {
+        tcg_gen_xori_i64(ret, arg, -1);
+    }
+#else
     tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg));
     tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
-#else
-    tcg_gen_xori_i64(ret, arg, -1);
 #endif
 }
 
@@ -1787,18 +1736,15 @@ static inline void tcg_gen_discard_i32(TCGv_i32 arg)
     tcg_gen_op1_i32(INDEX_op_discard, arg);
 }
 
-#if TCG_TARGET_REG_BITS == 32
 static inline void tcg_gen_discard_i64(TCGv_i64 arg)
 {
+#if TCG_TARGET_REG_BITS == 32
     tcg_gen_discard_i32(TCGV_LOW(arg));
     tcg_gen_discard_i32(TCGV_HIGH(arg));
-}
 #else
-static inline void tcg_gen_discard_i64(TCGv_i64 arg)
-{
     tcg_gen_op1_i64(INDEX_op_discard, arg);
-}
 #endif
+}
 
 static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
 {
@@ -1832,165 +1778,170 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 hi
 
 static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_andc_i32
-    tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
-#else
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_not_i32(t0, arg2);
-    tcg_gen_and_i32(ret, arg1, t0);
-    tcg_temp_free_i32(t0);
-#endif
+    if (TCG_TARGET_HAS_andc_i32) {
+        tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
+    } else {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_not_i32(t0, arg2);
+        tcg_gen_and_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
 }
 
 static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_andc_i64
-    tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
-#elif defined(TCG_TARGET_HAS_andc_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_andc_i64) {
+        tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
+    } else {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_not_i64(t0, arg2);
+        tcg_gen_and_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+#else
     tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
-#else
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_not_i64(t0, arg2);
-    tcg_gen_and_i64(ret, arg1, t0);
-    tcg_temp_free_i64(t0);
 #endif
 }
 
 static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_eqv_i32
-    tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2);
-#else
-    tcg_gen_xor_i32(ret, arg1, arg2);
-    tcg_gen_not_i32(ret, ret);
-#endif
+    if (TCG_TARGET_HAS_eqv_i32) {
+        tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2);
+    } else {
+        tcg_gen_xor_i32(ret, arg1, arg2);
+        tcg_gen_not_i32(ret, ret);
+    }
 }
 
 static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_eqv_i64
-    tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
-#elif defined(TCG_TARGET_HAS_eqv_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_eqv_i64) {
+        tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
+    } else {
+        tcg_gen_xor_i64(ret, arg1, arg2);
+        tcg_gen_not_i64(ret, ret);
+    }
+#else
     tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
-#else
-    tcg_gen_xor_i64(ret, arg1, arg2);
-    tcg_gen_not_i64(ret, ret);
 #endif
 }
 
 static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_nand_i32
-    tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2);
-#else
-    tcg_gen_and_i32(ret, arg1, arg2);
-    tcg_gen_not_i32(ret, ret);
-#endif
+    if (TCG_TARGET_HAS_nand_i32) {
+        tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2);
+    } else {
+        tcg_gen_and_i32(ret, arg1, arg2);
+        tcg_gen_not_i32(ret, ret);
+    }
 }
 
 static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_nand_i64
-    tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
-#elif defined(TCG_TARGET_HAS_nand_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_nand_i64) {
+        tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
+    } else {
+        tcg_gen_and_i64(ret, arg1, arg2);
+        tcg_gen_not_i64(ret, ret);
+    }
+#else
     tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
-#else
-    tcg_gen_and_i64(ret, arg1, arg2);
-    tcg_gen_not_i64(ret, ret);
 #endif
 }
 
 static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_nor_i32
-    tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2);
-#else
-    tcg_gen_or_i32(ret, arg1, arg2);
-    tcg_gen_not_i32(ret, ret);
-#endif
+    if (TCG_TARGET_HAS_nor_i32) {
+        tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2);
+    } else {
+        tcg_gen_or_i32(ret, arg1, arg2);
+        tcg_gen_not_i32(ret, ret);
+    }
 }
 
 static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_nor_i64
-    tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
-#elif defined(TCG_TARGET_HAS_nor_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_nor_i64) {
+        tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
+    } else {
+        tcg_gen_or_i64(ret, arg1, arg2);
+        tcg_gen_not_i64(ret, ret);
+    }
+#else
     tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
-#else
-    tcg_gen_or_i64(ret, arg1, arg2);
-    tcg_gen_not_i64(ret, ret);
 #endif
 }
 
 static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_orc_i32
-    tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
-#else
-    TCGv_i32 t0;
-    t0 = tcg_temp_new_i32();
-    tcg_gen_not_i32(t0, arg2);
-    tcg_gen_or_i32(ret, arg1, t0);
-    tcg_temp_free_i32(t0);
-#endif
+    if (TCG_TARGET_HAS_orc_i32) {
+        tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
+    } else {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_not_i32(t0, arg2);
+        tcg_gen_or_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
 }
 
 static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_orc_i64
-    tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
-#elif defined(TCG_TARGET_HAS_orc_i32) && TCG_TARGET_REG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+    if (TCG_TARGET_HAS_orc_i64) {
+        tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
+    } else {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_not_i64(t0, arg2);
+        tcg_gen_or_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+#else
     tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
-#else
-    TCGv_i64 t0;
-    t0 = tcg_temp_new_i64();
-    tcg_gen_not_i64(t0, arg2);
-    tcg_gen_or_i64(ret, arg1, t0);
-    tcg_temp_free_i64(t0);
 #endif
 }
 
 static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_rot_i32
-    tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
-#else
-    TCGv_i32 t0, t1;
+    if (TCG_TARGET_HAS_rot_i32) {
+        tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
+    } else {
+        TCGv_i32 t0, t1;
 
-    t0 = tcg_temp_new_i32();
-    t1 = tcg_temp_new_i32();
-    tcg_gen_shl_i32(t0, arg1, arg2);
-    tcg_gen_subfi_i32(t1, 32, arg2);
-    tcg_gen_shr_i32(t1, arg1, t1);
-    tcg_gen_or_i32(ret, t0, t1);
-    tcg_temp_free_i32(t0);
-    tcg_temp_free_i32(t1);
-#endif
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+        tcg_gen_shl_i32(t0, arg1, arg2);
+        tcg_gen_subfi_i32(t1, 32, arg2);
+        tcg_gen_shr_i32(t1, arg1, t1);
+        tcg_gen_or_i32(ret, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+    }
 }
 
 static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_rot_i64
-    tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
-#else
-    TCGv_i64 t0, t1;
-
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
-    tcg_gen_shl_i64(t0, arg1, arg2);
-    tcg_gen_subfi_i64(t1, 64, arg2);
-    tcg_gen_shr_i64(t1, arg1, t1);
-    tcg_gen_or_i64(ret, t0, t1);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-#endif
+    if (TCG_TARGET_HAS_rot_i64) {
+        tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
+    } else {
+        TCGv_i64 t0, t1;
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
+        tcg_gen_shl_i64(t0, arg1, arg2);
+        tcg_gen_subfi_i64(t1, 64, arg2);
+        tcg_gen_shr_i64(t1, arg1, t1);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+    }
 }
 
 static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
@@ -1998,12 +1949,11 @@ static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
     /* some cases can be optimized here */
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
-    } else {
-#ifdef TCG_TARGET_HAS_rot_i32
+    } else if (TCG_TARGET_HAS_rot_i32) {
         TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_rotl_i32(ret, arg1, t0);
         tcg_temp_free_i32(t0);
-#else
+    } else {
         TCGv_i32 t0, t1;
         t0 = tcg_temp_new_i32();
         t1 = tcg_temp_new_i32();
@@ -2012,7 +1962,6 @@ static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
         tcg_gen_or_i32(ret, t0, t1);
         tcg_temp_free_i32(t0);
         tcg_temp_free_i32(t1);
-#endif
     }
 }
 
@@ -2021,12 +1970,11 @@ static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
     /* some cases can be optimized here */
     if (arg2 == 0) {
         tcg_gen_mov_i64(ret, arg1);
-    } else {
-#ifdef TCG_TARGET_HAS_rot_i64
+    } else if (TCG_TARGET_HAS_rot_i64) {
         TCGv_i64 t0 = tcg_const_i64(arg2);
         tcg_gen_rotl_i64(ret, arg1, t0);
         tcg_temp_free_i64(t0);
-#else
+    } else {
         TCGv_i64 t0, t1;
         t0 = tcg_temp_new_i64();
         t1 = tcg_temp_new_i64();
@@ -2035,44 +1983,42 @@ static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
         tcg_gen_or_i64(ret, t0, t1);
         tcg_temp_free_i64(t0);
         tcg_temp_free_i64(t1);
-#endif
     }
 }
 
 static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-#ifdef TCG_TARGET_HAS_rot_i32
-    tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
-#else
-    TCGv_i32 t0, t1;
+    if (TCG_TARGET_HAS_rot_i32) {
+        tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
+    } else {
+        TCGv_i32 t0, t1;
 
-    t0 = tcg_temp_new_i32();
-    t1 = tcg_temp_new_i32();
-    tcg_gen_shr_i32(t0, arg1, arg2);
-    tcg_gen_subfi_i32(t1, 32, arg2);
-    tcg_gen_shl_i32(t1, arg1, t1);
-    tcg_gen_or_i32(ret, t0, t1);
-    tcg_temp_free_i32(t0);
-    tcg_temp_free_i32(t1);
-#endif
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+        tcg_gen_shr_i32(t0, arg1, arg2);
+        tcg_gen_subfi_i32(t1, 32, arg2);
+        tcg_gen_shl_i32(t1, arg1, t1);
+        tcg_gen_or_i32(ret, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+    }
 }
 
 static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-#ifdef TCG_TARGET_HAS_rot_i64
-    tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
-#else
-    TCGv_i64 t0, t1;
-
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
-    tcg_gen_shr_i64(t0, arg1, arg2);
-    tcg_gen_subfi_i64(t1, 64, arg2);
-    tcg_gen_shl_i64(t1, arg1, t1);
-    tcg_gen_or_i64(ret, t0, t1);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-#endif
+    if (TCG_TARGET_HAS_rot_i64) {
+        tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
+    } else {
+        TCGv_i64 t0, t1;
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
+        tcg_gen_shr_i64(t0, arg1, arg2);
+        tcg_gen_subfi_i64(t1, 64, arg2);
+        tcg_gen_shl_i64(t1, arg1, t1);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+    }
 }
 
 static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
@@ -2096,41 +2042,80 @@ static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 }
 
 static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
-                                      TCGv_i32 arg2, unsigned int ofs,
-                                      unsigned int len)
+                                       TCGv_i32 arg2, unsigned int ofs,
+                                       unsigned int len)
 {
-#ifdef TCG_TARGET_HAS_deposit_i32
-  tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
-#else
-  uint32_t mask = (1u << len) - 1;
-  TCGv_i32 t1 = tcg_temp_new_i32 ();
+    uint32_t mask;
+    TCGv_i32 t1;
 
-  tcg_gen_andi_i32(t1, arg2, mask);
-  tcg_gen_shli_i32(t1, t1, ofs);
-  tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
-  tcg_gen_or_i32(ret, ret, t1);
+    if (ofs == 0 && len == 32) {
+        tcg_gen_mov_i32(ret, arg2);
+        return;
+    }
+    if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) {
+        tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
+        return;
+    }
 
-  tcg_temp_free_i32(t1);
-#endif
+    mask = (1u << len) - 1;
+    t1 = tcg_temp_new_i32();
+
+    if (ofs + len < 32) {
+        tcg_gen_andi_i32(t1, arg2, mask);
+        tcg_gen_shli_i32(t1, t1, ofs);
+    } else {
+        tcg_gen_shli_i32(t1, arg2, ofs);
+    }
+    tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
+    tcg_gen_or_i32(ret, ret, t1);
+
+    tcg_temp_free_i32(t1);
 }
 
 static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
-                                      TCGv_i64 arg2, unsigned int ofs,
-                                      unsigned int len)
+                                       TCGv_i64 arg2, unsigned int ofs,
+                                       unsigned int len)
 {
-#ifdef TCG_TARGET_HAS_deposit_i64
-  tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
-#else
-  uint64_t mask = (1ull << len) - 1;
-  TCGv_i64 t1 = tcg_temp_new_i64 ();
+    uint64_t mask;
+    TCGv_i64 t1;
 
-  tcg_gen_andi_i64(t1, arg2, mask);
-  tcg_gen_shli_i64(t1, t1, ofs);
-  tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
-  tcg_gen_or_i64(ret, ret, t1);
+    if (ofs == 0 && len == 64) {
+        tcg_gen_mov_i64(ret, arg2);
+        return;
+    }
+    if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) {
+        tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
+        return;
+    }
 
-  tcg_temp_free_i64(t1);
+#if TCG_TARGET_REG_BITS == 32
+    if (ofs >= 32) {
+        tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
+        tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1),
+                            TCGV_LOW(arg2), ofs - 32, len);
+        return;
+    }
+    if (ofs + len <= 32) {
+        tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1),
+                            TCGV_LOW(arg2), ofs, len);
+        tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
+        return;
+    }
 #endif
+
+    mask = (1ull << len) - 1;
+    t1 = tcg_temp_new_i64();
+
+    if (ofs + len < 64) {
+        tcg_gen_andi_i64(t1, arg2, mask);
+        tcg_gen_shli_i64(t1, t1, ofs);
+    } else {
+        tcg_gen_shli_i64(t1, arg2, ofs);
+    }
+    tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
+    tcg_gen_or_i64(ret, ret, t1);
+
+    tcg_temp_free_i64(t1);
 }
 
 /***************************************/
@@ -2169,22 +2154,13 @@ static inline void tcg_gen_debug_insn_start(uint64_t pc)
 {
     /* XXX: must really use a 32 bit size for TCGArg in all cases */
 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
-    tcg_gen_op2ii(INDEX_op_debug_insn_start,
+    tcg_gen_op2ii(INDEX_op_debug_insn_start, 
                   (uint32_t)(pc), (uint32_t)(pc >> 32));
 #else
     tcg_gen_op1i(INDEX_op_debug_insn_start, pc);
 #endif
 }
 
-#ifdef CONFIG_EXEC_PROFILE
-static inline void tcg_gen_prof_tbexec(int idx)
-{
-    tcg_gen_op1i(INDEX_op_prof_tbexec, idx);
-}
-#else
-# define tcg_gen_prof_tbexec(idx)
-#endif  /* CONFIG_EXEC_PROFILE */
-
 static inline void tcg_gen_exit_tb(tcg_target_long val)
 {
     tcg_gen_op1i(INDEX_op_exit_tb, val);
@@ -2313,8 +2289,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
 #endif
 }
 
-#define tcg_gen_ld_ptr tcg_gen_ld_i32
-#define tcg_gen_discard_ptr tcg_gen_discard_i32
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i32(TCGV_PTR_TO_NAT(A))
 
 #else /* TCG_TARGET_REG_BITS == 32 */
 
@@ -2381,8 +2357,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
     tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index);
 }
 
-#define tcg_gen_ld_ptr tcg_gen_ld_i64
-#define tcg_gen_discard_ptr tcg_gen_discard_i64
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i64(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i64(TCGV_PTR_TO_NAT(A))
 
 #endif /* TCG_TARGET_REG_BITS != 32 */
 
@@ -2532,11 +2508,17 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
 #endif
 
 #if TCG_TARGET_REG_BITS == 32
-#define tcg_gen_add_ptr tcg_gen_add_i32
-#define tcg_gen_addi_ptr tcg_gen_addi_i32
-#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i32(TCGV_PTR_TO_NAT(R), \
+                                               TCGV_PTR_TO_NAT(A), \
+                                               TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i32(TCGV_PTR_TO_NAT(R), \
+                                                 TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_mov_i32(TCGV_PTR_TO_NAT(R), (A))
 #else /* TCG_TARGET_REG_BITS == 32 */
-#define tcg_gen_add_ptr tcg_gen_add_i64
-#define tcg_gen_addi_ptr tcg_gen_addi_i64
-#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i64(TCGV_PTR_TO_NAT(R), \
+                                               TCGV_PTR_TO_NAT(A), \
+                                               TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R),   \
+                                                 TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
 #endif /* TCG_TARGET_REG_BITS != 32 */
index bca40bb636d02a0a223b25d842a2edd0595dc710..8e06d03b17e2b2ad06068966465576cfb32921d8 100644 (file)
@@ -41,6 +41,13 @@ DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
 DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 
+#define IMPL(X) (X ? 0 : TCG_OPF_NOT_PRESENT)
+#if TCG_TARGET_REG_BITS == 32
+# define IMPL64  TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT
+#else
+# define IMPL64  TCG_OPF_64BIT
+#endif
+
 DEF(mov_i32, 1, 1, 0, 0)
 DEF(movi_i32, 1, 0, 1, 0)
 DEF(setcond_i32, 1, 2, 1, 0)
@@ -57,16 +64,12 @@ DEF(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
 DEF(add_i32, 1, 2, 0, 0)
 DEF(sub_i32, 1, 2, 0, 0)
 DEF(mul_i32, 1, 2, 0, 0)
-#ifdef TCG_TARGET_HAS_div_i32
-DEF(div_i32, 1, 2, 0, 0)
-DEF(divu_i32, 1, 2, 0, 0)
-DEF(rem_i32, 1, 2, 0, 0)
-DEF(remu_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_div2_i32
-DEF(div2_i32, 2, 3, 0, 0)
-DEF(divu2_i32, 2, 3, 0, 0)
-#endif
+DEF(div_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32))
+DEF(divu_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32))
+DEF(rem_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32))
+DEF(remu_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32))
+DEF(div2_i32, 2, 3, 0, IMPL(TCG_TARGET_HAS_div2_i32))
+DEF(divu2_i32, 2, 3, 0, IMPL(TCG_TARGET_HAS_div2_i32))
 DEF(and_i32, 1, 2, 0, 0)
 DEF(or_i32, 1, 2, 0, 0)
 DEF(xor_i32, 1, 2, 0, 0)
@@ -74,157 +77,86 @@ DEF(xor_i32, 1, 2, 0, 0)
 DEF(shl_i32, 1, 2, 0, 0)
 DEF(shr_i32, 1, 2, 0, 0)
 DEF(sar_i32, 1, 2, 0, 0)
-#ifdef TCG_TARGET_HAS_rot_i32
-DEF(rotl_i32, 1, 2, 0, 0)
-DEF(rotr_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_deposit_i32
-DEF(deposit_i32, 1, 2, 2, 0)
-#endif
+DEF(rotl_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32))
+DEF(rotr_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32))
+DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32))
 
 DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-#if TCG_TARGET_REG_BITS == 32
-DEF(add2_i32, 2, 4, 0, 0)
-DEF(sub2_i32, 2, 4, 0, 0)
-DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-DEF(mulu2_i32, 2, 2, 0, 0)
-DEF(setcond2_i32, 1, 4, 1, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext8s_i32
-DEF(ext8s_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext16s_i32
-DEF(ext16s_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext8u_i32
-DEF(ext8u_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext16u_i32
-DEF(ext16u_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_bswap16_i32
-DEF(bswap16_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_bswap32_i32
-DEF(bswap32_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_not_i32
-DEF(not_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_neg_i32
-DEF(neg_i32, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_andc_i32
-DEF(andc_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_orc_i32
-DEF(orc_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_eqv_i32
-DEF(eqv_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_nand_i32
-DEF(nand_i32, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_nor_i32
-DEF(nor_i32, 1, 2, 0, 0)
-#endif
 
-#if TCG_TARGET_REG_BITS == 64
-DEF(mov_i64, 1, 1, 0, 0)
-DEF(movi_i64, 1, 0, 1, 0)
-DEF(setcond_i64, 1, 2, 1, 0)
+DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32))
+DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32))
+DEF(brcond2_i32, 0, 4, 2,
+    TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS | IMPL(TCG_TARGET_REG_BITS == 32))
+DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_REG_BITS == 32))
+DEF(setcond2_i32, 1, 4, 1, IMPL(TCG_TARGET_REG_BITS == 32))
+
+DEF(ext8s_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext8s_i32))
+DEF(ext16s_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext16s_i32))
+DEF(ext8u_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext8u_i32))
+DEF(ext16u_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext16u_i32))
+DEF(bswap16_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_bswap16_i32))
+DEF(bswap32_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_bswap32_i32))
+DEF(not_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_not_i32))
+DEF(neg_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_neg_i32))
+DEF(andc_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_andc_i32))
+DEF(orc_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_orc_i32))
+DEF(eqv_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_eqv_i32))
+DEF(nand_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nand_i32))
+DEF(nor_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nor_i32))
+
+DEF(mov_i64, 1, 1, 0, IMPL64)
+DEF(movi_i64, 1, 0, 1, IMPL64)
+DEF(setcond_i64, 1, 2, 1, IMPL64)
 /* load/store */
-DEF(ld8u_i64, 1, 1, 1, 0)
-DEF(ld8s_i64, 1, 1, 1, 0)
-DEF(ld16u_i64, 1, 1, 1, 0)
-DEF(ld16s_i64, 1, 1, 1, 0)
-DEF(ld32u_i64, 1, 1, 1, 0)
-DEF(ld32s_i64, 1, 1, 1, 0)
-DEF(ld_i64, 1, 1, 1, 0)
-DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(ld8u_i64, 1, 1, 1, IMPL64)
+DEF(ld8s_i64, 1, 1, 1, IMPL64)
+DEF(ld16u_i64, 1, 1, 1, IMPL64)
+DEF(ld16s_i64, 1, 1, 1, IMPL64)
+DEF(ld32u_i64, 1, 1, 1, IMPL64)
+DEF(ld32s_i64, 1, 1, 1, IMPL64)
+DEF(ld_i64, 1, 1, 1, IMPL64)
+DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64)
+DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64)
+DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64)
+DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64)
 /* arith */
-DEF(add_i64, 1, 2, 0, 0)
-DEF(sub_i64, 1, 2, 0, 0)
-DEF(mul_i64, 1, 2, 0, 0)
-#ifdef TCG_TARGET_HAS_div_i64
-DEF(div_i64, 1, 2, 0, 0)
-DEF(divu_i64, 1, 2, 0, 0)
-DEF(rem_i64, 1, 2, 0, 0)
-DEF(remu_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_div2_i64
-DEF(div2_i64, 2, 3, 0, 0)
-DEF(divu2_i64, 2, 3, 0, 0)
-#endif
-DEF(and_i64, 1, 2, 0, 0)
-DEF(or_i64, 1, 2, 0, 0)
-DEF(xor_i64, 1, 2, 0, 0)
+DEF(add_i64, 1, 2, 0, IMPL64)
+DEF(sub_i64, 1, 2, 0, IMPL64)
+DEF(mul_i64, 1, 2, 0, IMPL64)
+DEF(div_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64))
+DEF(divu_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64))
+DEF(rem_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64))
+DEF(remu_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64))
+DEF(div2_i64, 2, 3, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div2_i64))
+DEF(divu2_i64, 2, 3, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div2_i64))
+DEF(and_i64, 1, 2, 0, IMPL64)
+DEF(or_i64, 1, 2, 0, IMPL64)
+DEF(xor_i64, 1, 2, 0, IMPL64)
 /* shifts/rotates */
-DEF(shl_i64, 1, 2, 0, 0)
-DEF(shr_i64, 1, 2, 0, 0)
-DEF(sar_i64, 1, 2, 0, 0)
-#ifdef TCG_TARGET_HAS_rot_i64
-DEF(rotl_i64, 1, 2, 0, 0)
-DEF(rotr_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_deposit_i64
-DEF(deposit_i64, 1, 2, 2, 0)
-#endif
-
-DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-#ifdef TCG_TARGET_HAS_ext8s_i64
-DEF(ext8s_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext16s_i64
-DEF(ext16s_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext32s_i64
-DEF(ext32s_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext8u_i64
-DEF(ext8u_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext16u_i64
-DEF(ext16u_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_ext32u_i64
-DEF(ext32u_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_bswap16_i64
-DEF(bswap16_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_bswap32_i64
-DEF(bswap32_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_bswap64_i64
-DEF(bswap64_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_not_i64
-DEF(not_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_neg_i64
-DEF(neg_i64, 1, 1, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_andc_i64
-DEF(andc_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_orc_i64
-DEF(orc_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_eqv_i64
-DEF(eqv_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_nand_i64
-DEF(nand_i64, 1, 2, 0, 0)
-#endif
-#ifdef TCG_TARGET_HAS_nor_i64
-DEF(nor_i64, 1, 2, 0, 0)
-#endif
-#endif
+DEF(shl_i64, 1, 2, 0, IMPL64)
+DEF(shr_i64, 1, 2, 0, IMPL64)
+DEF(sar_i64, 1, 2, 0, IMPL64)
+DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
+DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
+DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64))
+
+DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS | IMPL64)
+DEF(ext8s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8s_i64))
+DEF(ext16s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16s_i64))
+DEF(ext32s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext32s_i64))
+DEF(ext8u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8u_i64))
+DEF(ext16u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16u_i64))
+DEF(ext32u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext32u_i64))
+DEF(bswap16_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap16_i64))
+DEF(bswap32_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap32_i64))
+DEF(bswap64_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap64_i64))
+DEF(not_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_not_i64))
+DEF(neg_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_neg_i64))
+DEF(andc_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_andc_i64))
+DEF(orc_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_orc_i64))
+DEF(eqv_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_eqv_i64))
+DEF(nand_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nand_i64))
+DEF(nor_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nor_i64))
 
 /* QEMU specific */
 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
@@ -307,8 +239,6 @@ DEF(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 
 #endif /* TCG_TARGET_REG_BITS != 32 */
 
-#ifdef CONFIG_EXEC_PROFILE
-DEF(prof_tbexec, 0, 1, 0, 0)
-#endif  /* CONFIG_EXEC_PROFILE */
-
+#undef IMPL
+#undef IMPL64
 #undef DEF
index 777a4232a3d8cc0c7e3fdd6e54786d0d2bab3ebf..bea603199e8c8d2d4a641283d8af92145fa40a2e 100644 (file)
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -26,7 +26,6 @@
 #define USE_LIVENESS_ANALYSIS
 #define USE_TCG_OPTIMIZATIONS
 
-
 #include "config.h"
 
 #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
@@ -56,7 +55,6 @@
    instructions */
 #define NO_CPU_IO_DEFS
 #include "cpu.h"
-#include "exec-all.h"
 
 #include "tcg-op.h"
 #include "elf.h"
 #error GUEST_BASE not supported on this host.
 #endif
 
+/* Forward declarations for functions declared in tcg-target.c and used here. */
 static void tcg_target_init(TCGContext *s);
 static void tcg_target_qemu_prologue(TCGContext *s);
 static void patch_reloc(uint8_t *code_ptr, int type,
                         tcg_target_long value, tcg_target_long addend);
 
-static TCGOpDef tcg_op_defs[] = {
+/* Forward declarations for functions declared and used in tcg-target.c. */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
+                       tcg_target_long arg2);
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         TCGReg ret, tcg_target_long arg);
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                       const int *const_args);
+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
+                       tcg_target_long arg2);
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct);
+static int tcg_target_get_call_iarg_regs_count(int flags);
+
+TCGOpDef tcg_op_defs[] = {
 #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
 #include "tcg-opc.h"
 #undef DEF
 };
+const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs);
 
 static TCGRegSet tcg_target_available_regs[2];
 static TCGRegSet tcg_target_call_clobber_regs;
@@ -168,7 +183,7 @@ void *tcg_malloc_internal(TCGContext *s, int size)
 
     if (size > TCG_POOL_CHUNK_SIZE) {
         /* big malloc: insert a new pool (XXX: could optimize) */
-        p = qemu_malloc(sizeof(TCGPool) + size);
+        p = g_malloc(sizeof(TCGPool) + size);
         p->size = size;
         if (s->pool_current)
             s->pool_current->next = p;
@@ -185,7 +200,7 @@ void *tcg_malloc_internal(TCGContext *s, int size)
             if (!p->next) {
             new_pool:
                 pool_size = TCG_POOL_CHUNK_SIZE;
-                p = qemu_malloc(sizeof(TCGPool) + pool_size);
+                p = g_malloc(sizeof(TCGPool) + pool_size);
                 p->size = pool_size;
                 p->next = NULL;
                 if (s->pool_current)
@@ -229,8 +244,8 @@ void tcg_context_init(TCGContext *s)
         total_args += n;
     }
 
-    args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
-    sorted_args = qemu_malloc(sizeof(int) * total_args);
+    args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
+    sorted_args = g_malloc(sizeof(int) * total_args);
 
     for(op = 0; op < NB_OPS; op++) {
         def = &tcg_op_defs[op];
@@ -275,12 +290,15 @@ void tcg_func_start(TCGContext *s)
 
     gen_opc_ptr = gen_opc_buf;
     gen_opparam_ptr = gen_opparam_buf;
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
-    s->helper_labels = tcg_malloc(sizeof(HelperLabel) * TCG_MAX_HELPER_LABELS);
-    if (!s->helper_labels) {
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
+    /* initialize qemu_ld/st labels which help to generate TLB miss case codes at the end of TB */
+#if defined(__i386__) || defined(__x86_64__)
+    s->qemu_ldst_labels = tcg_malloc(sizeof(TCGLabelQemuLdst) * TCG_MAX_QEMU_LDST);
+    if (!s->qemu_ldst_labels) {
         tcg_abort();
     }
-    s->nb_helper_labels = 0;
+    s->nb_qemu_ldst_labels = 0;
+#endif
 #endif
 }
 
@@ -459,6 +477,10 @@ static inline int tcg_temp_new_internal(TCGType type, int temp_local)
             s->nb_temps++;
         }
     }
+
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use++;
+#endif
     return idx;
 }
 
@@ -484,6 +506,13 @@ static inline void tcg_temp_free_internal(int idx)
     TCGTemp *ts;
     int k;
 
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use--;
+    if (s->temps_in_use < 0) {
+        fprintf(stderr, "More temporaries freed than allocated!\n");
+    }
+#endif
+
     assert(idx >= s->nb_globals && idx < s->nb_temps);
     ts = &s->temps[idx];
     assert(ts->temp_allocated != 0);
@@ -537,6 +566,27 @@ TCGv_i64 tcg_const_local_i64(int64_t val)
     return t0;
 }
 
+#if defined(CONFIG_DEBUG_TCG)
+void tcg_clear_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    s->temps_in_use = 0;
+}
+
+int tcg_check_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    if (s->temps_in_use) {
+        /* Clear the count so that we don't give another
+         * warning immediately next time around.
+         */
+        s->temps_in_use = 0;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
 void tcg_register_helper(void *func, const char *name)
 {
     TCGContext *s = &tcg_ctx;
@@ -562,7 +612,7 @@ void tcg_register_helper(void *func, const char *name)
 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
                    int sizemask, TCGArg ret, int nargs, TCGArg *args)
 {
-#ifdef TCG_TARGET_I386
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
     int call_type;
 #endif
     int i;
@@ -589,7 +639,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
 
     *gen_opc_ptr++ = INDEX_op_call;
     nparam = gen_opparam_ptr++;
-#ifdef TCG_TARGET_I386
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
     call_type = (flags & TCG_CALL_TYPE_MASK);
 #endif
     if (ret != TCG_CALL_DUMMY_ARG) {
@@ -755,7 +805,9 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
 {
     TCGTemp *ts;
 
+    assert(idx >= 0 && idx < s->nb_temps);
     ts = &s->temps[idx];
+    assert(ts);
     if (idx < s->nb_globals) {
         pstrcpy(buf, buf_size, ts->name);
     } else {
@@ -1105,18 +1157,19 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
 #if defined(CONFIG_DEBUG_TCG)
     i = 0;
     for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
-        if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+        const TCGOpDef *def = &tcg_op_defs[op];
+        if (op < INDEX_op_call
+            || op == INDEX_op_debug_insn_start
+            || (def->flags & TCG_OPF_NOT_PRESENT)) {
             /* Wrong entry in op definitions? */
-            if (tcg_op_defs[op].used) {
-                fprintf(stderr, "Invalid op definition for %s\n",
-                        tcg_op_defs[op].name);
+            if (def->used) {
+                fprintf(stderr, "Invalid op definition for %s\n", def->name);
                 i = 1;
             }
         } else {
             /* Missing entry in op definitions? */
-            if (!tcg_op_defs[op].used) {
-                fprintf(stderr, "Missing op definition for %s\n",
-                        tcg_op_defs[op].name);
+            if (!def->used) {
+                fprintf(stderr, "Missing op definition for %s\n", def->name);
                 i = 1;
             }
         }
@@ -1170,7 +1223,7 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
     }
 }
 
-/* Liveness analysis : update the opc_dead_iargs array to tell if a
+/* Liveness analysis : update the opc_dead_args array to tell if a
    given input arguments is dead. Instructions updating dead
    temporaries are removed. */
 static void tcg_liveness_analysis(TCGContext *s)
@@ -1180,13 +1233,13 @@ static void tcg_liveness_analysis(TCGContext *s)
     TCGArg *args;
     const TCGOpDef *def;
     uint8_t *dead_temps;
-    unsigned int dead_iargs;
+    unsigned int dead_args;
 
     gen_opc_ptr++; /* skip end */
 
     nb_ops = gen_opc_ptr - gen_opc_buf;
 
-    s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
+    s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
 
     dead_temps = tcg_malloc(s->nb_temps);
     memset(dead_temps, 1, s->nb_temps);
@@ -1222,8 +1275,12 @@ static void tcg_liveness_analysis(TCGContext *s)
                 do_not_remove_call:
 
                     /* output args are dead */
+                    dead_args = 0;
                     for(i = 0; i < nb_oargs; i++) {
                         arg = args[i];
+                        if (dead_temps[arg]) {
+                            dead_args |= (1 << i);
+                        }
                         dead_temps[arg] = 1;
                     }
 
@@ -1233,17 +1290,16 @@ static void tcg_liveness_analysis(TCGContext *s)
                     }
 
                     /* input args are live */
-                    dead_iargs = 0;
-                    for(i = 0; i < nb_iargs; i++) {
-                        arg = args[i + nb_oargs];
+                    for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+                        arg = args[i];
                         if (arg != TCG_CALL_DUMMY_ARG) {
                             if (dead_temps[arg]) {
-                                dead_iargs |= (1 << i);
+                                dead_args |= (1 << i);
                             }
                             dead_temps[arg] = 0;
                         }
                     }
-                    s->op_dead_iargs[op_index] = dead_iargs;
+                    s->op_dead_args[op_index] = dead_args;
                 }
                 args--;
             }
@@ -1290,8 +1346,12 @@ static void tcg_liveness_analysis(TCGContext *s)
             do_not_remove:
 
                 /* output args are dead */
+                dead_args = 0;
                 for(i = 0; i < nb_oargs; i++) {
                     arg = args[i];
+                    if (dead_temps[arg]) {
+                        dead_args |= (1 << i);
+                    }
                     dead_temps[arg] = 1;
                 }
 
@@ -1304,15 +1364,14 @@ static void tcg_liveness_analysis(TCGContext *s)
                 }
 
                 /* input args are live */
-                dead_iargs = 0;
-                for(i = 0; i < nb_iargs; i++) {
-                    arg = args[i + nb_oargs];
+                for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+                    arg = args[i];
                     if (dead_temps[arg]) {
-                        dead_iargs |= (1 << i);
+                        dead_args |= (1 << i);
                     }
                     dead_temps[arg] = 0;
                 }
-                s->op_dead_iargs[op_index] = dead_iargs;
+                s->op_dead_args[op_index] = dead_args;
             }
             break;
         }
@@ -1329,8 +1388,8 @@ static void tcg_liveness_analysis(TCGContext *s)
     int nb_ops;
     nb_ops = gen_opc_ptr - gen_opc_buf;
 
-    s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
-    memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
+    s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
+    memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t));
 }
 #endif
 
@@ -1411,13 +1470,19 @@ static void temp_allocate_frame(TCGContext *s, int temp)
 {
     TCGTemp *ts;
     ts = &s->temps[temp];
-    s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
-    if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
+#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */
+    s->current_frame_offset = (s->current_frame_offset +
+                               (tcg_target_long)sizeof(tcg_target_long) - 1) &
+        ~(sizeof(tcg_target_long) - 1);
+#endif
+    if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
+        s->frame_end) {
         tcg_abort();
+    }
     ts->mem_offset = s->current_frame_offset;
     ts->mem_reg = s->frame_reg;
     ts->mem_allocated = 1;
-    s->current_frame_offset += sizeof(tcg_target_long);
+    s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long);
 }
 
 /* free register 'reg' by spilling the corresponding temporary if necessary */
@@ -1534,7 +1599,7 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
     save_globals(s, allocated_regs);
 }
 
-#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
+#define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
 
 static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
 {
@@ -1559,7 +1624,7 @@ static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
 
 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
                               const TCGArg *args,
-                              unsigned int dead_iargs)
+                              unsigned int dead_args)
 {
     TCGTemp *ts, *ots;
     int reg;
@@ -1569,9 +1634,9 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
     ts = &s->temps[args[1]];
     arg_ct = &def->args_ct[0];
 
-    /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
+    /* XXX: always mark arg dead if IS_DEAD_ARG(1) */
     if (ts->val_type == TEMP_VAL_REG) {
-        if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
+        if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
             /* the mov can be suppressed */
             if (ots->val_type == TEMP_VAL_REG)
                 s->reg_to_temp[ots->reg] = -1;
@@ -1619,7 +1684,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
 static void tcg_reg_alloc_op(TCGContext *s,
                              const TCGOpDef *def, TCGOpcode opc,
                              const TCGArg *args,
-                             unsigned int dead_iargs)
+                             unsigned int dead_args)
 {
     TCGRegSet allocated_regs;
     int i, k, nb_iargs, nb_oargs, reg;
@@ -1678,8 +1743,9 @@ static void tcg_reg_alloc_op(TCGContext *s,
                 /* if the input is aliased to an output and if it is
                    not dead after the instruction, we must allocate
                    a new register and move it */
-                if (!IS_DEAD_IARG(i - nb_oargs))
+                if (!IS_DEAD_ARG(i)) {
                     goto allocate_in_reg;
+                }
             }
         }
         reg = ts->reg;
@@ -1702,9 +1768,9 @@ static void tcg_reg_alloc_op(TCGContext *s,
         tcg_reg_alloc_bb_end(s, allocated_regs);
     } else {
         /* mark dead temporaries and free the associated registers */
-        for(i = 0; i < nb_iargs; i++) {
-            arg = args[nb_oargs + i];
-            if (IS_DEAD_IARG(i)) {
+        for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+            arg = args[i];
+            if (IS_DEAD_ARG(i)) {
                 ts = &s->temps[arg];
                 if (!ts->fixed_reg) {
                     if (ts->val_type == TEMP_VAL_REG)
@@ -1752,12 +1818,16 @@ static void tcg_reg_alloc_op(TCGContext *s,
             if (!ts->fixed_reg) {
                 if (ts->val_type == TEMP_VAL_REG)
                     s->reg_to_temp[ts->reg] = -1;
-                ts->val_type = TEMP_VAL_REG;
-                ts->reg = reg;
-                /* temp value is modified, so the value kept in memory is
-                   potentially not the same */
-                ts->mem_coherent = 0;
-                s->reg_to_temp[reg] = arg;
+                if (IS_DEAD_ARG(i)) {
+                    ts->val_type = TEMP_VAL_DEAD;
+                } else {
+                    ts->val_type = TEMP_VAL_REG;
+                    ts->reg = reg;
+                    /* temp value is modified, so the value kept in memory is
+                       potentially not the same */
+                    ts->mem_coherent = 0;
+                    s->reg_to_temp[reg] = arg;
+               }
             }
         oarg_end:
             new_args[i] = reg;
@@ -1785,7 +1855,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
 
 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
                               TCGOpcode opc, const TCGArg *args,
-                              unsigned int dead_iargs)
+                              unsigned int dead_args)
 {
     int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
     TCGArg arg, func_arg;
@@ -1808,13 +1878,14 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
         nb_regs = nb_params;
 
     /* assign stack slots first */
-    /* XXX: preallocate call stack */
     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
         ~(TCG_TARGET_STACK_ALIGN - 1);
     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
     if (allocate_args) {
-        tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
+        /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
+           preallocate call stack */
+        tcg_abort();
     }
 
     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
@@ -1907,9 +1978,9 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
 
 
     /* mark dead temporaries and free the associated registers */
-    for(i = 0; i < nb_iargs; i++) {
-        arg = args[nb_oargs + i];
-        if (IS_DEAD_IARG(i)) {
+    for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+        arg = args[i];
+        if (IS_DEAD_ARG(i)) {
             ts = &s->temps[arg];
             if (!ts->fixed_reg) {
                 if (ts->val_type == TEMP_VAL_REG)
@@ -1934,10 +2005,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
 
     tcg_out_op(s, opc, &func_arg, &const_func_arg);
 
-    if (allocate_args) {
-        tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
-    }
-
     /* assign output registers and emit moves if needed */
     for(i = 0; i < nb_oargs; i++) {
         arg = args[i];
@@ -1951,10 +2018,14 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
         } else {
             if (ts->val_type == TEMP_VAL_REG)
                 s->reg_to_temp[ts->reg] = -1;
-            ts->val_type = TEMP_VAL_REG;
-            ts->reg = reg;
-            ts->mem_coherent = 0;
-            s->reg_to_temp[reg] = arg;
+            if (IS_DEAD_ARG(i)) {
+                ts->val_type = TEMP_VAL_DEAD;
+            } else {
+                ts->val_type = TEMP_VAL_REG;
+                ts->reg = reg;
+                ts->mem_coherent = 0;
+                s->reg_to_temp[reg] = arg;
+            }
         }
     }
 
@@ -1984,7 +2055,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
     TCGOpcode opc;
     int op_index;
     const TCGOpDef *def;
-    unsigned int dead_iargs;
+    unsigned int dead_args;
     const TCGArg *args;
 
 #ifdef DEBUG_DISAS
@@ -1996,38 +2067,9 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
 #endif
 
 #ifdef USE_TCG_OPTIMIZATIONS
-#ifdef HARDCORE_DEBUG
-    if (gen_opc_buf[0] != INDEX_op_debug_insn_start) {
-        fprintf(stderr, "FUUUUUUUUUUUUUUUUUUUUU!!!!!!!!!!!!!!!!\n");
-        exit(1);
-    }
-#define OPT_START_ADDR 0x40a5cf1c
-#define OPT_END_ADDR   0x40a5cf1f
-    if (gen_opparam_buf[0] >= OPT_START_ADDR && gen_opparam_buf[0] <= OPT_END_ADDR) {
+    gen_opparam_ptr =
+        tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs);
 #endif
-#ifdef CONFIG_PROFILER
-        s->la_time -= profile_getclock();
-#endif
-        gen_opparam_ptr = tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs);
-#ifdef CONFIG_PROFILER
-        s->la_time += profile_getclock();
-#endif
-#ifdef HARDCORE_DEBUG
-    }
-#undef OPT_START_ADDR
-#undef OPT_END_ADDR
-#endif /* HARDCORE DEBUG */
-#endif /* USE_TCG_OPTIMIZATIONS */
-
-#ifdef DEBUG_DISAS
-    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
-        qemu_log("OP after optimizations:\n");
-        tcg_dump_ops(s, logfile);
-        qemu_log("\n");
-    }
-#endif
-
-
 
 #ifdef CONFIG_PROFILER
     s->la_time -= profile_getclock();
@@ -2069,8 +2111,8 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
 #if TCG_TARGET_REG_BITS == 64
         case INDEX_op_mov_i64:
 #endif
-            dead_iargs = s->op_dead_iargs[op_index];
-            tcg_reg_alloc_mov(s, def, args, dead_iargs);
+            dead_args = s->op_dead_args[op_index];
+            tcg_reg_alloc_mov(s, def, args, dead_args);
             break;
         case INDEX_op_movi_i32:
 #if TCG_TARGET_REG_BITS == 64
@@ -2106,33 +2148,21 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
             tcg_out_label(s, args[0], (long)s->code_ptr);
             break;
         case INDEX_op_call:
-            dead_iargs = s->op_dead_iargs[op_index];
-            args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
+            dead_args = s->op_dead_args[op_index];
+            args += tcg_reg_alloc_call(s, def, opc, args, dead_args);
             goto next;
         case INDEX_op_end:
             goto the_end;
-#ifdef CONFIG_PROFILER_EX
-        case INDEX_op_qemu_ld8u:
-        case INDEX_op_qemu_ld8s:
-        case INDEX_op_qemu_ld16u:
-        case INDEX_op_qemu_ld16s:
-        case INDEX_op_qemu_ld32:
-        case INDEX_op_qemu_ld64:
-            s->qemu_ld_count++;
-            goto gen;
-        case INDEX_op_qemu_st8:
-        case INDEX_op_qemu_st16:
-        case INDEX_op_qemu_st32:
-        case INDEX_op_qemu_st64:
-            s->qemu_st_count++;
-        gen:
-#endif
         default:
+            /* Sanity check that we've not introduced any unhandled opcodes. */
+            if (def->flags & TCG_OPF_NOT_PRESENT) {
+                tcg_abort();
+            }
             /* Note: in order to speed up the code, it would be much
                faster to have specialized register allocator functions for
                some common argument patterns */
-            dead_iargs = s->op_dead_iargs[op_index];
-            tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
+            dead_args = s->op_dead_args[op_index];
+            tcg_reg_alloc_op(s, def, opc, args, dead_args);
             break;
         }
         args += def->nb_args;
@@ -2146,9 +2176,11 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
 #endif
     }
  the_end:
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
+#if defined(__i386__) || defined(__x86_64__)
     /* Generate MMU call helpers at the end of block (currently only for qemu_ld/st) */
-    tcg_out_qemu_ldst_helper_calls(s);
+    tcg_out_qemu_ldst_slow_path(s);
+#endif
 #endif
     return -1;
 }
index a3061c11c4575433d5867a40df6ddceec79a3146..05682807e4e32604c0befbd4a2d6cdda1531aae4 100644 (file)
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
  * THE SOFTWARE.
  */
 #include "qemu-common.h"
+
+/* Target word size (must be identical to pointer size). */
+#if UINTPTR_MAX == UINT32_MAX
+# define TCG_TARGET_REG_BITS 32
+#elif UINTPTR_MAX == UINT64_MAX
+# define TCG_TARGET_REG_BITS 64
+#else
+# error Unknown pointer size for tcg target
+#endif
+
 #include "tcg-target.h"
 #include "tcg-runtime.h"
 
@@ -47,6 +57,49 @@ typedef uint64_t TCGRegSet;
 #error unsupported
 #endif
 
+/* Turn some undef macros into false macros.  */
+#if TCG_TARGET_REG_BITS == 32
+#define TCG_TARGET_HAS_div_i64          0
+#define TCG_TARGET_HAS_div2_i64         0
+#define TCG_TARGET_HAS_rot_i64          0
+#define TCG_TARGET_HAS_ext8s_i64        0
+#define TCG_TARGET_HAS_ext16s_i64       0
+#define TCG_TARGET_HAS_ext32s_i64       0
+#define TCG_TARGET_HAS_ext8u_i64        0
+#define TCG_TARGET_HAS_ext16u_i64       0
+#define TCG_TARGET_HAS_ext32u_i64       0
+#define TCG_TARGET_HAS_bswap16_i64      0
+#define TCG_TARGET_HAS_bswap32_i64      0
+#define TCG_TARGET_HAS_bswap64_i64      0
+#define TCG_TARGET_HAS_neg_i64          0
+#define TCG_TARGET_HAS_not_i64          0
+#define TCG_TARGET_HAS_andc_i64         0
+#define TCG_TARGET_HAS_orc_i64          0
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_deposit_i64      0
+#endif
+
+#ifndef TCG_TARGET_deposit_i32_valid
+#define TCG_TARGET_deposit_i32_valid(ofs, len) 1
+#endif
+#ifndef TCG_TARGET_deposit_i64_valid
+#define TCG_TARGET_deposit_i64_valid(ofs, len) 1
+#endif
+
+/* Only one of DIV or DIV2 should be defined.  */
+#if defined(TCG_TARGET_HAS_div_i32)
+#define TCG_TARGET_HAS_div2_i32         0
+#elif defined(TCG_TARGET_HAS_div2_i32)
+#define TCG_TARGET_HAS_div_i32          0
+#endif
+#if defined(TCG_TARGET_HAS_div_i64)
+#define TCG_TARGET_HAS_div2_i64         0
+#elif defined(TCG_TARGET_HAS_div2_i64)
+#define TCG_TARGET_HAS_div_i64          0
+#endif
+
 typedef enum TCGOpcode {
 #define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
 #include "tcg-opc.h"
@@ -122,20 +175,23 @@ typedef enum TCGType {
 
 typedef tcg_target_ulong TCGArg;
 
-/* Define a type and accessor macros for varables.  Using a struct is
+/* Define a type and accessor macros for variables.  Using a struct is
    nice because it gives some level of type safely.  Ideally the compiler
    be able to see through all this.  However in practice this is not true,
    expecially on targets with braindamaged ABIs (e.g. i386).
    We use plain int by default to avoid this runtime overhead.
    Users of tcg_gen_* don't need to know about any of this, and should
    treat TCGv as an opaque type.
-   In additon we do typechecking for different types of variables.  TCGv_i32
+   In addition we do typechecking for different types of variables.  TCGv_i32
    and TCGv_i64 are 32/64-bit variables respectively.  TCGv and TCGv_ptr
    are aliases for target_ulong and host pointer sized values respectively.
  */
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
-#define TCG_MAX_HELPER_LABELS   200
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
+#if defined(__i386__) || defined(__x86_64__)
+/* Macros and structures for qemu_ld/st IR code optimization:
+   It looks good for TCG_MAX_HELPER_LABELS to be half of OPC_BUF_SIZE in exec-all.h. */
+#define TCG_MAX_QEMU_LDST       320
 #define HL_LDST_SHIFT           4
 #define HL_LDST_MASK            (1 << HL_LDST_SHIFT)
 #define HL_ST_MASK              HL_LDST_MASK
@@ -143,17 +199,18 @@ typedef tcg_target_ulong TCGArg;
 #define IS_QEMU_LD_LABEL(L)     (!((L)->opc_ext & HL_LDST_MASK))
 #define IS_QEMU_ST_LABEL(L)     ((L)->opc_ext & HL_LDST_MASK)
 
-typedef struct HelperLabel {
-    int opc_ext;
-    int datalo_reg;
-    int datahi_reg;
-    int addrlo_reg;
-    int addrhi_reg;
-    int mem_index;
-    uint8_t *raddr;             /* return address */
-    uint32_t *label_ptr[2];     /* label pointer to be updated */
-} HelperLabel;
-#endif  /* CONFIG_TCG_TARGET_X86_OPT */
+typedef struct TCGLabelQemuLdst {
+    int opc_ext;                /* | 27bit (reserved) | 1bit (ld/st flag) | 4bit (opc) | */
+    int addrlo_reg;             /* reg index for the low word of guest virtual address */
+    int addrhi_reg;             /* reg index for the high word of guest virtual address */
+    int datalo_reg;             /* reg index for the low word to be loaded or to be stored */
+    int datahi_reg;             /* reg index for the high word to be loaded or to be stored */
+    int mem_index;              /* soft MMU memory index */
+    uint8_t *raddr;             /* return address (located end of TB) */
+    uint32_t *label_ptr[2];     /* label pointers to be updated */
+} TCGLabelQemuLdst;
+#endif
+#endif  /* CONFIG_QEMU_LDST_OPTIMIZATION */
 
 #ifdef CONFIG_DEBUG_TCG
 #define DEBUG_TCGV 1
@@ -171,12 +228,19 @@ typedef struct
     int i64;
 } TCGv_i64;
 
+typedef struct {
+    int iptr;
+} TCGv_ptr;
+
 #define MAKE_TCGV_I32(i) __extension__                  \
     ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
 #define MAKE_TCGV_I64(i) __extension__                  \
     ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_PTR(i) __extension__                  \
+    ({ TCGv_ptr make_tcgv_tmp = {i}; make_tcgv_tmp; })
 #define GET_TCGV_I32(t) ((t).i32)
 #define GET_TCGV_I64(t) ((t).i64)
+#define GET_TCGV_PTR(t) ((t).iptr)
 #if TCG_TARGET_REG_BITS == 32
 #define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
 #define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
@@ -186,10 +250,17 @@ typedef struct
 
 typedef int TCGv_i32;
 typedef int TCGv_i64;
+#if TCG_TARGET_REG_BITS == 32
+#define TCGv_ptr TCGv_i32
+#else
+#define TCGv_ptr TCGv_i64
+#endif
 #define MAKE_TCGV_I32(x) (x)
 #define MAKE_TCGV_I64(x) (x)
+#define MAKE_TCGV_PTR(x) (x)
 #define GET_TCGV_I32(t) (t)
 #define GET_TCGV_I64(t) (t)
+#define GET_TCGV_PTR(t) (t)
 
 #if TCG_TARGET_REG_BITS == 32
 #define TCGV_LOW(t) (t)
@@ -273,9 +344,9 @@ typedef struct TCGTemp {
     unsigned int fixed_reg:1;
     unsigned int mem_coherent:1;
     unsigned int mem_allocated:1;
-    unsigned int temp_local:1; /* If true, the temp is saved accross
+    unsigned int temp_local:1; /* If true, the temp is saved across
                                   basic blocks. Otherwise, it is not
-                                  preserved accross basic blocks. */
+                                  preserved across basic blocks. */
     unsigned int temp_allocated:1; /* never used for code gen */
     /* index of next free temp of same base type, -1 if end */
     int next_free_temp;
@@ -307,8 +378,8 @@ struct TCGContext {
     uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
 
     /* liveness analysis */
-    uint16_t *op_dead_iargs; /* for each operation, each bit tells if the
-                                corresponding input argument is dead */
+    uint16_t *op_dead_args; /* for each operation, each bit tells if the
+                               corresponding argument is dead */
 
     /* tells in which temporary a given register is. It does not take
        into account fixed registers */
@@ -343,14 +414,17 @@ struct TCGContext {
     int64_t la_time;
     int64_t restore_count;
     int64_t restore_time;
-#ifdef CONFIG_PROFILER_EX
-    int64_t qemu_ld_count;
-    int64_t qemu_st_count;
 #endif
+
+#ifdef CONFIG_DEBUG_TCG
+    int temps_in_use;
 #endif
-#if defined(CONFIG_TCG_TARGET_X86_OPT) && defined(CONFIG_SOFTMMU)
-    HelperLabel *helper_labels;
-    int nb_helper_labels;
+
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
+    /* labels info for qemu_ld/st IRs
+       The labels help to generate TLB miss case codes at the end of TB */
+    TCGLabelQemuLdst *qemu_ldst_labels;
+    int nb_qemu_ldst_labels;
 #endif
 };
 
@@ -421,6 +495,24 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void)
 void tcg_temp_free_i64(TCGv_i64 arg);
 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
 
+static inline bool tcg_arg_is_local(TCGContext *s, TCGArg arg)
+{
+    return s->temps[arg].temp_local;
+}
+
+#if defined(CONFIG_DEBUG_TCG)
+/* If you call tcg_clear_temp_count() at the start of a section of
+ * code which is not supposed to leak any TCG temporaries, then
+ * calling tcg_check_temp_count() at the end of the section will
+ * return 1 if the section did in fact leak a temporary.
+ */
+void tcg_clear_temp_count(void);
+int tcg_check_temp_count(void);
+#else
+#define tcg_clear_temp_count() do { } while (0)
+#define tcg_check_temp_count() 0
+#endif
+
 void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
 
 #define TCG_CT_ALIAS  0x80
@@ -438,13 +530,20 @@ typedef struct TCGArgConstraint {
 
 #define TCG_MAX_OP_ARGS 16
 
-#define TCG_OPF_BB_END     0x01 /* instruction defines the end of a basic
-                                   block */
-#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers
-                                   and potentially update globals. */
-#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
-                                     cannot be removed if its output
-                                     are not used */
+/* Bits for TCGOpDef->flags, 8 bits available.  */
+enum {
+    /* Instruction defines the end of a basic block.  */
+    TCG_OPF_BB_END       = 0x01,
+    /* Instruction clobbers call registers and potentially update globals.  */
+    TCG_OPF_CALL_CLOBBER = 0x02,
+    /* Instruction has side effects: it cannot be removed
+       if its outputs are not used.  */
+    TCG_OPF_SIDE_EFFECTS = 0x04,
+    /* Instruction operands are 64-bits (otherwise 32-bits).  */
+    TCG_OPF_64BIT        = 0x08,
+    /* Instruction is optional and not implemented by the host.  */
+    TCG_OPF_NOT_PRESENT  = 0x10,
+};
 
 typedef struct TCGOpDef {
     const char *name;
@@ -457,6 +556,9 @@ typedef struct TCGOpDef {
 #endif
 } TCGOpDef;
 
+extern TCGOpDef tcg_op_defs[];
+extern const size_t tcg_op_defs_max;
+
 typedef struct TCGTargetOpDef {
     TCGOpcode op;
     const char *args_ct_str[TCG_MAX_OP_ARGS];
@@ -471,25 +573,27 @@ do {\
 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
 
 #if TCG_TARGET_REG_BITS == 32
-#define tcg_const_ptr tcg_const_i32
-#define tcg_add_ptr tcg_add_i32
-#define tcg_sub_ptr tcg_sub_i32
-#define TCGv_ptr TCGv_i32
-#define GET_TCGV_PTR GET_TCGV_I32
-#define tcg_global_reg_new_ptr tcg_global_reg_new_i32
-#define tcg_global_mem_new_ptr tcg_global_mem_new_i32
-#define tcg_temp_new_ptr tcg_temp_new_i32
-#define tcg_temp_free_ptr tcg_temp_free_i32
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32(V))
+#define tcg_global_reg_new_ptr(R, N) \
+    TCGV_NAT_TO_PTR(tcg_global_reg_new_i32((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+    TCGV_NAT_TO_PTR(tcg_global_mem_new_i32((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i32())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i32(TCGV_PTR_TO_NAT(T))
 #else
-#define tcg_const_ptr tcg_const_i64
-#define tcg_add_ptr tcg_add_i64
-#define tcg_sub_ptr tcg_sub_i64
-#define TCGv_ptr TCGv_i64
-#define GET_TCGV_PTR GET_TCGV_I64
-#define tcg_global_reg_new_ptr tcg_global_reg_new_i64
-#define tcg_global_mem_new_ptr tcg_global_mem_new_i64
-#define tcg_temp_new_ptr tcg_temp_new_i64
-#define tcg_temp_free_ptr tcg_temp_free_i64
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I64(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I64(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64(V))
+#define tcg_global_reg_new_ptr(R, N) \
+    TCGV_NAT_TO_PTR(tcg_global_reg_new_i64((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+    TCGV_NAT_TO_PTR(tcg_global_mem_new_i64((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i64())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
 #endif
 
 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
@@ -498,9 +602,8 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
                         int c, int right, int arith);
 
-TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr,
-        TCGArg *args, TCGOpDef *tcg_op_defs);
-
+TCGArg *tcg_optimize(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args,
+                     TCGOpDef *tcg_op_def);
 
 /* only used for debugging purposes */
 void tcg_register_helper(void *func, const char *name);
@@ -514,13 +617,14 @@ TCGv_i32 tcg_const_local_i32(int32_t val);
 TCGv_i64 tcg_const_local_i64(int64_t val);
 
 extern uint8_t code_gen_prologue[];
-#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
-#define tcg_qemu_tb_exec(tb_ptr) \
-    ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr)
-#else
-#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)
+
+/* TCG targets may use a different definition of tcg_qemu_tb_exec. */
+#if !defined(tcg_qemu_tb_exec)
+# define tcg_qemu_tb_exec(env, tb_ptr) \
+    ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 #endif
 
-#if defined(CONFIG_TCG_TARGET_X86_OPT)
-void tcg_out_qemu_ldst_helper_calls(TCGContext *s);
+#if defined(CONFIG_QEMU_LDST_OPTIMIZATION)
+/* qemu_ld/st generation at the end of TB */
+void tcg_out_qemu_ldst_slow_path(TCGContext *s);
 #endif
diff --git a/tcg/tci/README b/tcg/tci/README
new file mode 100644 (file)
index 0000000..6ac1ac9
--- /dev/null
@@ -0,0 +1,130 @@
+TCG Interpreter (TCI) - Copyright (c) 2011 Stefan Weil.
+
+This file is released under the BSD license.
+
+1) Introduction
+
+TCG (Tiny Code Generator) is a code generator which translates
+code fragments ("basic blocks") from target code (any of the
+targets supported by QEMU) to a code representation which
+can be run on a host.
+
+QEMU can create native code for some hosts (arm, hppa, i386, ia64, ppc, ppc64,
+s390, sparc, x86_64). For others, unofficial host support was written.
+
+By adding a code generator for a virtual machine and using an
+interpreter for the generated bytecode, it is possible to
+support (almost) any host.
+
+This is what TCI (Tiny Code Interpreter) does.
+
+2) Implementation
+
+Like each TCG host frontend, TCI implements the code generator in
+tcg-target.c, tcg-target.h. Both files are in directory tcg/tci.
+
+The additional file tcg/tci.c adds the interpreter.
+
+The bytecode consists of opcodes (same numeric values as those used by
+TCG), command length and arguments of variable size and number.
+
+3) Usage
+
+For hosts without native TCG, the interpreter TCI must be enabled by
+
+        configure --enable-tcg-interpreter
+
+If configure is called without --enable-tcg-interpreter, it will
+suggest using this option. Setting it automatically would need
+additional code in configure which must be fixed when new native TCG
+implementations are added.
+
+System emulation should work on any 32 or 64 bit host.
+User mode emulation might work. Maybe a new linker script (*.ld)
+is needed. Byte order might be wrong (on big endian hosts)
+and need fixes in configure.
+
+For hosts with native TCG, the interpreter TCI can be enabled by
+
+        configure --enable-tcg-interpreter
+
+The only difference from running QEMU with TCI to running without TCI
+should be speed. Especially during development of TCI, it was very
+useful to compare runs with and without TCI. Create /tmp/qemu.log by
+
+        qemu-system-i386 -d in_asm,op_opt,cpu -singlestep
+
+once with interpreter and once without interpreter and compare the resulting
+qemu.log files. This is also useful to see the effects of additional
+registers or additional opcodes (it is easy to modify the virtual machine).
+It can also be used to verify native TCGs.
+
+Hosts with native TCG can also enable TCI by claiming to be unsupported:
+
+        configure --cpu=unknown --enable-tcg-interpreter
+
+configure then no longer uses the native linker script (*.ld) for
+user mode emulation.
+
+
+4) Status
+
+TCI needs special implementation for 32 and 64 bit host, 32 and 64 bit target,
+host and target with same or different endianness.
+
+            | host (le)                     host (be)
+            | 32             64             32             64
+------------+------------------------------------------------------------
+target (le) | s0, u0         s1, u1         s?, u?         s?, u?
+32 bit      |
+            |
+target (le) | sc, uc         s1, u1         s?, u?         s?, u?
+64 bit      |
+            |
+target (be) | sc, u0         sc, uc         s?, u?         s?, u?
+32 bit      |
+            |
+target (be) | sc, uc         sc, uc         s?, u?         s?, u?
+64 bit      |
+            |
+
+System emulation
+s? = untested
+sc = compiles
+s0 = bios works
+s1 = grub works
+s2 = Linux boots
+
+Linux user mode emulation
+u? = untested
+uc = compiles
+u0 = static hello works
+u1 = linux-user-test works
+
+5) Todo list
+
+* TCI is not widely tested. It was written and tested on a x86_64 host
+  running i386 and x86_64 system emulation and Linux user mode.
+  A cross compiled QEMU for i386 host also works with the same basic tests.
+  A cross compiled QEMU for mipsel host works, too. It is terribly slow
+  because I run it in a mips malta emulation, so it is an interpreted
+  emulation in an emulation.
+  A cross compiled QEMU for arm host works (tested with pc bios).
+  A cross compiled QEMU for ppc host works at least partially:
+  i386-linux-user/qemu-i386 can run a simple hello-world program
+  (tested in a ppc emulation).
+
+* Some TCG opcodes are either missing in the code generator and/or
+  in the interpreter. These opcodes raise a runtime exception, so it is
+  possible to see where code must be added.
+
+* The pseudo code is not optimized and still ugly. For hosts with special
+  alignment requirements, it needs some fixes (maybe aligned bytecode
+  would also improve speed for hosts which support byte alignment).
+
+* A better disassembler for the pseudo code would be nice (a very primitive
+  disassembler is included in tcg-target.c).
+
+* It might be useful to have a runtime option which selects the native TCG
+  or TCI, so QEMU would have to include two TCGs. Today, selecting TCI
+  is a configure option, so you need two compilations of QEMU.
diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c
new file mode 100644 (file)
index 0000000..fc0880c
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009, 2011 Stefan Weil
+ *
+ * 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 list:
+ * - See TODO comments in code.
+ */
+
+/* Marker for missing code. */
+#define TODO() \
+    do { \
+        fprintf(stderr, "TODO %s:%u: %s()\n", \
+                __FILE__, __LINE__, __func__); \
+        tcg_abort(); \
+    } while (0)
+
+/* Single bit n. */
+#define BIT(n) (1 << (n))
+
+/* Bitfield n...m (in 32 bit value). */
+#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
+
+/* Used for function call generation. */
+#define TCG_REG_CALL_STACK              TCG_REG_R4
+#define TCG_TARGET_STACK_ALIGN          16
+#define TCG_TARGET_CALL_STACK_OFFSET    0
+
+/* TODO: documentation. */
+static uint8_t *tb_ret_addr;
+
+/* Macros used in tcg_target_op_defs. */
+#define R       "r"
+#define RI      "ri"
+#if TCG_TARGET_REG_BITS == 32
+# define R64    "r", "r"
+#else
+# define R64    "r"
+#endif
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+# define L      "L", "L"
+# define S      "S", "S"
+#else
+# define L      "L"
+# define S      "S"
+#endif
+
+/* TODO: documentation. */
+static const TCGTargetOpDef tcg_target_op_defs[] = {
+    { INDEX_op_exit_tb, { NULL } },
+    { INDEX_op_goto_tb, { NULL } },
+    { INDEX_op_call, { RI } },
+    { INDEX_op_jmp, { RI } },
+    { INDEX_op_br, { NULL } },
+
+    { INDEX_op_mov_i32, { R, R } },
+    { INDEX_op_movi_i32, { R } },
+
+    { INDEX_op_ld8u_i32, { R, R } },
+    { INDEX_op_ld8s_i32, { R, R } },
+    { INDEX_op_ld16u_i32, { R, R } },
+    { INDEX_op_ld16s_i32, { R, R } },
+    { INDEX_op_ld_i32, { R, R } },
+    { INDEX_op_st8_i32, { R, R } },
+    { INDEX_op_st16_i32, { R, R } },
+    { INDEX_op_st_i32, { R, R } },
+
+    { INDEX_op_add_i32, { R, RI, RI } },
+    { INDEX_op_sub_i32, { R, RI, RI } },
+    { INDEX_op_mul_i32, { R, RI, RI } },
+#if TCG_TARGET_HAS_div_i32
+    { INDEX_op_div_i32, { R, R, R } },
+    { INDEX_op_divu_i32, { R, R, R } },
+    { INDEX_op_rem_i32, { R, R, R } },
+    { INDEX_op_remu_i32, { R, R, R } },
+#elif TCG_TARGET_HAS_div2_i32
+    { INDEX_op_div2_i32, { R, R, "0", "1", R } },
+    { INDEX_op_divu2_i32, { R, R, "0", "1", R } },
+#endif
+    /* TODO: Does R, RI, RI result in faster code than R, R, RI?
+       If both operands are constants, we can optimize. */
+    { INDEX_op_and_i32, { R, RI, RI } },
+#if TCG_TARGET_HAS_andc_i32
+    { INDEX_op_andc_i32, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_eqv_i32
+    { INDEX_op_eqv_i32, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_nand_i32
+    { INDEX_op_nand_i32, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_nor_i32
+    { INDEX_op_nor_i32, { R, RI, RI } },
+#endif
+    { INDEX_op_or_i32, { R, RI, RI } },
+#if TCG_TARGET_HAS_orc_i32
+    { INDEX_op_orc_i32, { R, RI, RI } },
+#endif
+    { INDEX_op_xor_i32, { R, RI, RI } },
+    { INDEX_op_shl_i32, { R, RI, RI } },
+    { INDEX_op_shr_i32, { R, RI, RI } },
+    { INDEX_op_sar_i32, { R, RI, RI } },
+#if TCG_TARGET_HAS_rot_i32
+    { INDEX_op_rotl_i32, { R, RI, RI } },
+    { INDEX_op_rotr_i32, { R, RI, RI } },
+#endif
+
+    { INDEX_op_brcond_i32, { R, RI } },
+
+    { INDEX_op_setcond_i32, { R, R, RI } },
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_setcond_i64, { R, R, RI } },
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+#if TCG_TARGET_REG_BITS == 32
+    /* TODO: Support R, R, R, R, RI, RI? Will it be faster? */
+    { INDEX_op_add2_i32, { R, R, R, R, R, R } },
+    { INDEX_op_sub2_i32, { R, R, R, R, R, R } },
+    { INDEX_op_brcond2_i32, { R, R, RI, RI } },
+    { INDEX_op_mulu2_i32, { R, R, R, R } },
+    { INDEX_op_setcond2_i32, { R, R, R, RI, RI } },
+#endif
+
+#if TCG_TARGET_HAS_not_i32
+    { INDEX_op_not_i32, { R, R } },
+#endif
+#if TCG_TARGET_HAS_neg_i32
+    { INDEX_op_neg_i32, { R, R } },
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_mov_i64, { R, R } },
+    { INDEX_op_movi_i64, { R } },
+
+    { INDEX_op_ld8u_i64, { R, R } },
+    { INDEX_op_ld8s_i64, { R, R } },
+    { INDEX_op_ld16u_i64, { R, R } },
+    { INDEX_op_ld16s_i64, { R, R } },
+    { INDEX_op_ld32u_i64, { R, R } },
+    { INDEX_op_ld32s_i64, { R, R } },
+    { INDEX_op_ld_i64, { R, R } },
+
+    { INDEX_op_st8_i64, { R, R } },
+    { INDEX_op_st16_i64, { R, R } },
+    { INDEX_op_st32_i64, { R, R } },
+    { INDEX_op_st_i64, { R, R } },
+
+    { INDEX_op_add_i64, { R, RI, RI } },
+    { INDEX_op_sub_i64, { R, RI, RI } },
+    { INDEX_op_mul_i64, { R, RI, RI } },
+#if TCG_TARGET_HAS_div_i64
+    { INDEX_op_div_i64, { R, R, R } },
+    { INDEX_op_divu_i64, { R, R, R } },
+    { INDEX_op_rem_i64, { R, R, R } },
+    { INDEX_op_remu_i64, { R, R, R } },
+#elif TCG_TARGET_HAS_div2_i64
+    { INDEX_op_div2_i64, { R, R, "0", "1", R } },
+    { INDEX_op_divu2_i64, { R, R, "0", "1", R } },
+#endif
+    { INDEX_op_and_i64, { R, RI, RI } },
+#if TCG_TARGET_HAS_andc_i64
+    { INDEX_op_andc_i64, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_eqv_i64
+    { INDEX_op_eqv_i64, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_nand_i64
+    { INDEX_op_nand_i64, { R, RI, RI } },
+#endif
+#if TCG_TARGET_HAS_nor_i64
+    { INDEX_op_nor_i64, { R, RI, RI } },
+#endif
+    { INDEX_op_or_i64, { R, RI, RI } },
+#if TCG_TARGET_HAS_orc_i64
+    { INDEX_op_orc_i64, { R, RI, RI } },
+#endif
+    { INDEX_op_xor_i64, { R, RI, RI } },
+    { INDEX_op_shl_i64, { R, RI, RI } },
+    { INDEX_op_shr_i64, { R, RI, RI } },
+    { INDEX_op_sar_i64, { R, RI, RI } },
+#if TCG_TARGET_HAS_rot_i64
+    { INDEX_op_rotl_i64, { R, RI, RI } },
+    { INDEX_op_rotr_i64, { R, RI, RI } },
+#endif
+    { INDEX_op_brcond_i64, { R, RI } },
+
+#if TCG_TARGET_HAS_ext8s_i64
+    { INDEX_op_ext8s_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext16s_i64
+    { INDEX_op_ext16s_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext32s_i64
+    { INDEX_op_ext32s_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext8u_i64
+    { INDEX_op_ext8u_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext16u_i64
+    { INDEX_op_ext16u_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext32u_i64
+    { INDEX_op_ext32u_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_bswap16_i64
+    { INDEX_op_bswap16_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_bswap32_i64
+    { INDEX_op_bswap32_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_bswap64_i64
+    { INDEX_op_bswap64_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_not_i64
+    { INDEX_op_not_i64, { R, R } },
+#endif
+#if TCG_TARGET_HAS_neg_i64
+    { INDEX_op_neg_i64, { R, R } },
+#endif
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+    { INDEX_op_qemu_ld8u, { R, L } },
+    { INDEX_op_qemu_ld8s, { R, L } },
+    { INDEX_op_qemu_ld16u, { R, L } },
+    { INDEX_op_qemu_ld16s, { R, L } },
+    { INDEX_op_qemu_ld32, { R, L } },
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_qemu_ld32u, { R, L } },
+    { INDEX_op_qemu_ld32s, { R, L } },
+#endif
+    { INDEX_op_qemu_ld64, { R64, L } },
+
+    { INDEX_op_qemu_st8, { R, S } },
+    { INDEX_op_qemu_st16, { R, S } },
+    { INDEX_op_qemu_st32, { R, S } },
+    { INDEX_op_qemu_st64, { R64, S } },
+
+#if TCG_TARGET_HAS_ext8s_i32
+    { INDEX_op_ext8s_i32, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext16s_i32
+    { INDEX_op_ext16s_i32, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext8u_i32
+    { INDEX_op_ext8u_i32, { R, R } },
+#endif
+#if TCG_TARGET_HAS_ext16u_i32
+    { INDEX_op_ext16u_i32, { R, R } },
+#endif
+
+#if TCG_TARGET_HAS_bswap16_i32
+    { INDEX_op_bswap16_i32, { R, R } },
+#endif
+#if TCG_TARGET_HAS_bswap32_i32
+    { INDEX_op_bswap32_i32, { R, R } },
+#endif
+
+    { -1 },
+};
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+#if 0 /* used for TCG_REG_CALL_STACK */
+    TCG_REG_R4,
+#endif
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+#if TCG_TARGET_NB_REGS >= 16
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+#endif
+};
+
+#if MAX_OPC_PARAM_IARGS != 4
+# error Fix needed, number of supported input arguments changed!
+#endif
+
+static const int tcg_target_call_iarg_regs[] = {
+    TCG_REG_R0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+#if TCG_TARGET_REG_BITS == 32
+    /* 32 bit hosts need 2 * MAX_OPC_PARAM_IARGS registers. */
+#if 0 /* used for TCG_REG_CALL_STACK */
+    TCG_REG_R4,
+#endif
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+#if TCG_TARGET_NB_REGS >= 16
+    TCG_REG_R8,
+#else
+# error Too few input registers available
+#endif
+#endif
+};
+
+static const int tcg_target_call_oarg_regs[] = {
+    TCG_REG_R0,
+#if TCG_TARGET_REG_BITS == 32
+    TCG_REG_R1
+#endif
+};
+
+#ifndef NDEBUG
+static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "r00",
+    "r01",
+    "r02",
+    "r03",
+    "r04",
+    "r05",
+    "r06",
+    "r07",
+#if TCG_TARGET_NB_REGS >= 16
+    "r08",
+    "r09",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "r14",
+    "r15",
+#if TCG_TARGET_NB_REGS >= 32
+    "r16",
+    "r17",
+    "r18",
+    "r19",
+    "r20",
+    "r21",
+    "r22",
+    "r23",
+    "r24",
+    "r25",
+    "r26",
+    "r27",
+    "r28",
+    "r29",
+    "r30",
+    "r31"
+#endif
+#endif
+};
+#endif
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    /* tcg_out_reloc always uses the same type, addend. */
+    assert(type == sizeof(tcg_target_long));
+    assert(addend == 0);
+    assert(value != 0);
+    *(tcg_target_long *)code_ptr = value;
+}
+
+/* Parse target specific constraints. */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'r':
+    case 'L':                   /* qemu_ld constraint */
+    case 'S':                   /* qemu_st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, BIT(TCG_TARGET_NB_REGS) - 1);
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+#if defined(CONFIG_DEBUG_TCG_INTERPRETER)
+/* Show current bytecode. Used by tcg interpreter. */
+void tci_disas(uint8_t opc)
+{
+    const TCGOpDef *def = &tcg_op_defs[opc];
+    fprintf(stderr, "TCG %s %u, %u, %u\n",
+            def->name, def->nb_oargs, def->nb_iargs, def->nb_cargs);
+}
+#endif
+
+/* Write value (native size). */
+static void tcg_out_i(TCGContext *s, tcg_target_ulong v)
+{
+    *(tcg_target_ulong *)s->code_ptr = v;
+    s->code_ptr += sizeof(tcg_target_ulong);
+}
+
+/* Write 64 bit value. */
+static void tcg_out64(TCGContext *s, uint64_t v)
+{
+    *(uint64_t *)s->code_ptr = v;
+    s->code_ptr += sizeof(v);
+}
+
+/* Write opcode. */
+static void tcg_out_op_t(TCGContext *s, TCGOpcode op)
+{
+    tcg_out8(s, op);
+    tcg_out8(s, 0);
+}
+
+/* Write register. */
+static void tcg_out_r(TCGContext *s, TCGArg t0)
+{
+    assert(t0 < TCG_TARGET_NB_REGS);
+    tcg_out8(s, t0);
+}
+
+/* Write register or constant (native size). */
+static void tcg_out_ri(TCGContext *s, int const_arg, TCGArg arg)
+{
+    if (const_arg) {
+        assert(const_arg == 1);
+        tcg_out8(s, TCG_CONST);
+        tcg_out_i(s, arg);
+    } else {
+        tcg_out_r(s, arg);
+    }
+}
+
+/* Write register or constant (32 bit). */
+static void tcg_out_ri32(TCGContext *s, int const_arg, TCGArg arg)
+{
+    if (const_arg) {
+        assert(const_arg == 1);
+        tcg_out8(s, TCG_CONST);
+        tcg_out32(s, arg);
+    } else {
+        tcg_out_r(s, arg);
+    }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+/* Write register or constant (64 bit). */
+static void tcg_out_ri64(TCGContext *s, int const_arg, TCGArg arg)
+{
+    if (const_arg) {
+        assert(const_arg == 1);
+        tcg_out8(s, TCG_CONST);
+        tcg_out64(s, arg);
+    } else {
+        tcg_out_r(s, arg);
+    }
+}
+#endif
+
+/* Write label. */
+static void tci_out_label(TCGContext *s, TCGArg arg)
+{
+    TCGLabel *label = &s->labels[arg];
+    if (label->has_value) {
+        tcg_out_i(s, label->u.value);
+        assert(label->u.value);
+    } else {
+        tcg_out_reloc(s, s->code_ptr, sizeof(tcg_target_ulong), arg, 0);
+        tcg_out_i(s, 0);
+    }
+}
+
+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
+                       tcg_target_long arg2)
+{
+    uint8_t *old_code_ptr = s->code_ptr;
+    if (type == TCG_TYPE_I32) {
+        tcg_out_op_t(s, INDEX_op_ld_i32);
+        tcg_out_r(s, ret);
+        tcg_out_r(s, arg1);
+        tcg_out32(s, arg2);
+    } else {
+        assert(type == TCG_TYPE_I64);
+#if TCG_TARGET_REG_BITS == 64
+        tcg_out_op_t(s, INDEX_op_ld_i64);
+        tcg_out_r(s, ret);
+        tcg_out_r(s, arg1);
+        assert(arg2 == (uint32_t)arg2);
+        tcg_out32(s, arg2);
+#else
+        TODO();
+#endif
+    }
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
+}
+
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
+{
+    uint8_t *old_code_ptr = s->code_ptr;
+    assert(ret != arg);
+#if TCG_TARGET_REG_BITS == 32
+    tcg_out_op_t(s, INDEX_op_mov_i32);
+#else
+    tcg_out_op_t(s, INDEX_op_mov_i64);
+#endif
+    tcg_out_r(s, ret);
+    tcg_out_r(s, arg);
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         TCGReg t0, tcg_target_long arg)
+{
+    uint8_t *old_code_ptr = s->code_ptr;
+    uint32_t arg32 = arg;
+    if (type == TCG_TYPE_I32 || arg == arg32) {
+        tcg_out_op_t(s, INDEX_op_movi_i32);
+        tcg_out_r(s, t0);
+        tcg_out32(s, arg32);
+    } else {
+        assert(type == TCG_TYPE_I64);
+#if TCG_TARGET_REG_BITS == 64
+        tcg_out_op_t(s, INDEX_op_movi_i64);
+        tcg_out_r(s, t0);
+        tcg_out64(s, arg);
+#else
+        TODO();
+#endif
+    }
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
+}
+
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                       const int *const_args)
+{
+    uint8_t *old_code_ptr = s->code_ptr;
+
+    tcg_out_op_t(s, opc);
+
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        tcg_out64(s, args[0]);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* Direct jump method. */
+            assert(args[0] < ARRAY_SIZE(s->tb_jmp_offset));
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            tcg_out32(s, 0);
+        } else {
+            /* Indirect jump method. */
+            TODO();
+        }
+        assert(args[0] < ARRAY_SIZE(s->tb_next_offset));
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_br:
+        tci_out_label(s, args[0]);
+        break;
+    case INDEX_op_call:
+        tcg_out_ri(s, const_args[0], args[0]);
+        break;
+    case INDEX_op_jmp:
+        TODO();
+        break;
+    case INDEX_op_setcond_i32:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_ri32(s, const_args[2], args[2]);
+        tcg_out8(s, args[3]);   /* condition */
+        break;
+#if TCG_TARGET_REG_BITS == 32
+    case INDEX_op_setcond2_i32:
+        /* setcond2_i32 cond, t0, t1_low, t1_high, t2_low, t2_high */
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_r(s, args[2]);
+        tcg_out_ri32(s, const_args[3], args[3]);
+        tcg_out_ri32(s, const_args[4], args[4]);
+        tcg_out8(s, args[5]);   /* condition */
+        break;
+#elif TCG_TARGET_REG_BITS == 64
+    case INDEX_op_setcond_i64:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_ri64(s, const_args[2], args[2]);
+        tcg_out8(s, args[3]);   /* condition */
+        break;
+#endif
+    case INDEX_op_movi_i32:
+        TODO(); /* Handled by tcg_out_movi? */
+        break;
+    case INDEX_op_ld8u_i32:
+    case INDEX_op_ld8s_i32:
+    case INDEX_op_ld16u_i32:
+    case INDEX_op_ld16s_i32:
+    case INDEX_op_ld_i32:
+    case INDEX_op_st8_i32:
+    case INDEX_op_st16_i32:
+    case INDEX_op_st_i32:
+    case INDEX_op_ld8u_i64:
+    case INDEX_op_ld8s_i64:
+    case INDEX_op_ld16u_i64:
+    case INDEX_op_ld16s_i64:
+    case INDEX_op_ld32u_i64:
+    case INDEX_op_ld32s_i64:
+    case INDEX_op_ld_i64:
+    case INDEX_op_st8_i64:
+    case INDEX_op_st16_i64:
+    case INDEX_op_st32_i64:
+    case INDEX_op_st_i64:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        assert(args[2] == (uint32_t)args[2]);
+        tcg_out32(s, args[2]);
+        break;
+    case INDEX_op_add_i32:
+    case INDEX_op_sub_i32:
+    case INDEX_op_mul_i32:
+    case INDEX_op_and_i32:
+    case INDEX_op_andc_i32:     /* Optional (TCG_TARGET_HAS_andc_i32). */
+    case INDEX_op_eqv_i32:      /* Optional (TCG_TARGET_HAS_eqv_i32). */
+    case INDEX_op_nand_i32:     /* Optional (TCG_TARGET_HAS_nand_i32). */
+    case INDEX_op_nor_i32:      /* Optional (TCG_TARGET_HAS_nor_i32). */
+    case INDEX_op_or_i32:
+    case INDEX_op_orc_i32:      /* Optional (TCG_TARGET_HAS_orc_i32). */
+    case INDEX_op_xor_i32:
+    case INDEX_op_shl_i32:
+    case INDEX_op_shr_i32:
+    case INDEX_op_sar_i32:
+    case INDEX_op_rotl_i32:     /* Optional (TCG_TARGET_HAS_rot_i32). */
+    case INDEX_op_rotr_i32:     /* Optional (TCG_TARGET_HAS_rot_i32). */
+        tcg_out_r(s, args[0]);
+        tcg_out_ri32(s, const_args[1], args[1]);
+        tcg_out_ri32(s, const_args[2], args[2]);
+        break;
+
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_mov_i64:
+    case INDEX_op_movi_i64:
+        TODO();
+        break;
+    case INDEX_op_add_i64:
+    case INDEX_op_sub_i64:
+    case INDEX_op_mul_i64:
+    case INDEX_op_and_i64:
+    case INDEX_op_andc_i64:     /* Optional (TCG_TARGET_HAS_andc_i64). */
+    case INDEX_op_eqv_i64:      /* Optional (TCG_TARGET_HAS_eqv_i64). */
+    case INDEX_op_nand_i64:     /* Optional (TCG_TARGET_HAS_nand_i64). */
+    case INDEX_op_nor_i64:      /* Optional (TCG_TARGET_HAS_nor_i64). */
+    case INDEX_op_or_i64:
+    case INDEX_op_orc_i64:      /* Optional (TCG_TARGET_HAS_orc_i64). */
+    case INDEX_op_xor_i64:
+    case INDEX_op_shl_i64:
+    case INDEX_op_shr_i64:
+    case INDEX_op_sar_i64:
+        /* TODO: Implementation of rotl_i64, rotr_i64 missing in tci.c. */
+    case INDEX_op_rotl_i64:     /* Optional (TCG_TARGET_HAS_rot_i64). */
+    case INDEX_op_rotr_i64:     /* Optional (TCG_TARGET_HAS_rot_i64). */
+        tcg_out_r(s, args[0]);
+        tcg_out_ri64(s, const_args[1], args[1]);
+        tcg_out_ri64(s, const_args[2], args[2]);
+        break;
+    case INDEX_op_div_i64:      /* Optional (TCG_TARGET_HAS_div_i64). */
+    case INDEX_op_divu_i64:     /* Optional (TCG_TARGET_HAS_div_i64). */
+    case INDEX_op_rem_i64:      /* Optional (TCG_TARGET_HAS_div_i64). */
+    case INDEX_op_remu_i64:     /* Optional (TCG_TARGET_HAS_div_i64). */
+        TODO();
+        break;
+    case INDEX_op_div2_i64:     /* Optional (TCG_TARGET_HAS_div2_i64). */
+    case INDEX_op_divu2_i64:    /* Optional (TCG_TARGET_HAS_div2_i64). */
+        TODO();
+        break;
+    case INDEX_op_brcond_i64:
+        tcg_out_r(s, args[0]);
+        tcg_out_ri64(s, const_args[1], args[1]);
+        tcg_out8(s, args[2]);           /* condition */
+        tci_out_label(s, args[3]);
+        break;
+    case INDEX_op_bswap16_i64:  /* Optional (TCG_TARGET_HAS_bswap16_i64). */
+    case INDEX_op_bswap32_i64:  /* Optional (TCG_TARGET_HAS_bswap32_i64). */
+    case INDEX_op_bswap64_i64:  /* Optional (TCG_TARGET_HAS_bswap64_i64). */
+    case INDEX_op_not_i64:      /* Optional (TCG_TARGET_HAS_not_i64). */
+    case INDEX_op_neg_i64:      /* Optional (TCG_TARGET_HAS_neg_i64). */
+    case INDEX_op_ext8s_i64:    /* Optional (TCG_TARGET_HAS_ext8s_i64). */
+    case INDEX_op_ext8u_i64:    /* Optional (TCG_TARGET_HAS_ext8u_i64). */
+    case INDEX_op_ext16s_i64:   /* Optional (TCG_TARGET_HAS_ext16s_i64). */
+    case INDEX_op_ext16u_i64:   /* Optional (TCG_TARGET_HAS_ext16u_i64). */
+    case INDEX_op_ext32s_i64:   /* Optional (TCG_TARGET_HAS_ext32s_i64). */
+    case INDEX_op_ext32u_i64:   /* Optional (TCG_TARGET_HAS_ext32u_i64). */
+#endif /* TCG_TARGET_REG_BITS == 64 */
+    case INDEX_op_neg_i32:      /* Optional (TCG_TARGET_HAS_neg_i32). */
+    case INDEX_op_not_i32:      /* Optional (TCG_TARGET_HAS_not_i32). */
+    case INDEX_op_ext8s_i32:    /* Optional (TCG_TARGET_HAS_ext8s_i32). */
+    case INDEX_op_ext16s_i32:   /* Optional (TCG_TARGET_HAS_ext16s_i32). */
+    case INDEX_op_ext8u_i32:    /* Optional (TCG_TARGET_HAS_ext8u_i32). */
+    case INDEX_op_ext16u_i32:   /* Optional (TCG_TARGET_HAS_ext16u_i32). */
+    case INDEX_op_bswap16_i32:  /* Optional (TCG_TARGET_HAS_bswap16_i32). */
+    case INDEX_op_bswap32_i32:  /* Optional (TCG_TARGET_HAS_bswap32_i32). */
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        break;
+    case INDEX_op_div_i32:      /* Optional (TCG_TARGET_HAS_div_i32). */
+    case INDEX_op_divu_i32:     /* Optional (TCG_TARGET_HAS_div_i32). */
+    case INDEX_op_rem_i32:      /* Optional (TCG_TARGET_HAS_div_i32). */
+    case INDEX_op_remu_i32:     /* Optional (TCG_TARGET_HAS_div_i32). */
+        tcg_out_r(s, args[0]);
+        tcg_out_ri32(s, const_args[1], args[1]);
+        tcg_out_ri32(s, const_args[2], args[2]);
+        break;
+    case INDEX_op_div2_i32:     /* Optional (TCG_TARGET_HAS_div2_i32). */
+    case INDEX_op_divu2_i32:    /* Optional (TCG_TARGET_HAS_div2_i32). */
+        TODO();
+        break;
+#if TCG_TARGET_REG_BITS == 32
+    case INDEX_op_add2_i32:
+    case INDEX_op_sub2_i32:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_r(s, args[2]);
+        tcg_out_r(s, args[3]);
+        tcg_out_r(s, args[4]);
+        tcg_out_r(s, args[5]);
+        break;
+    case INDEX_op_brcond2_i32:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_ri32(s, const_args[2], args[2]);
+        tcg_out_ri32(s, const_args[3], args[3]);
+        tcg_out8(s, args[4]);           /* condition */
+        tci_out_label(s, args[5]);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_r(s, args[0]);
+        tcg_out_r(s, args[1]);
+        tcg_out_r(s, args[2]);
+        tcg_out_r(s, args[3]);
+        break;
+#endif
+    case INDEX_op_brcond_i32:
+        tcg_out_r(s, args[0]);
+        tcg_out_ri32(s, const_args[1], args[1]);
+        tcg_out8(s, args[2]);           /* condition */
+        tci_out_label(s, args[3]);
+        break;
+    case INDEX_op_qemu_ld8u:
+    case INDEX_op_qemu_ld8s:
+    case INDEX_op_qemu_ld16u:
+    case INDEX_op_qemu_ld16s:
+    case INDEX_op_qemu_ld32:
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_qemu_ld32s:
+    case INDEX_op_qemu_ld32u:
+#endif
+        tcg_out_r(s, *args++);
+        tcg_out_r(s, *args++);
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+        tcg_out_r(s, *args++);
+#endif
+#ifdef CONFIG_SOFTMMU
+        tcg_out_i(s, *args);
+#endif
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_r(s, *args++);
+#if TCG_TARGET_REG_BITS == 32
+        tcg_out_r(s, *args++);
+#endif
+        tcg_out_r(s, *args++);
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+        tcg_out_r(s, *args++);
+#endif
+#ifdef CONFIG_SOFTMMU
+        tcg_out_i(s, *args);
+#endif
+        break;
+    case INDEX_op_qemu_st8:
+    case INDEX_op_qemu_st16:
+    case INDEX_op_qemu_st32:
+        tcg_out_r(s, *args++);
+        tcg_out_r(s, *args++);
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+        tcg_out_r(s, *args++);
+#endif
+#ifdef CONFIG_SOFTMMU
+        tcg_out_i(s, *args);
+#endif
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_r(s, *args++);
+#if TCG_TARGET_REG_BITS == 32
+        tcg_out_r(s, *args++);
+#endif
+        tcg_out_r(s, *args++);
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+        tcg_out_r(s, *args++);
+#endif
+#ifdef CONFIG_SOFTMMU
+        tcg_out_i(s, *args);
+#endif
+        break;
+    case INDEX_op_end:
+        TODO();
+        break;
+    default:
+        fprintf(stderr, "Missing: %s\n", tcg_op_defs[opc].name);
+        tcg_abort();
+    }
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
+}
+
+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
+                       tcg_target_long arg2)
+{
+    uint8_t *old_code_ptr = s->code_ptr;
+    if (type == TCG_TYPE_I32) {
+        tcg_out_op_t(s, INDEX_op_st_i32);
+        tcg_out_r(s, arg);
+        tcg_out_r(s, arg1);
+        tcg_out32(s, arg2);
+    } else {
+        assert(type == TCG_TYPE_I64);
+#if TCG_TARGET_REG_BITS == 64
+        tcg_out_op_t(s, INDEX_op_st_i64);
+        tcg_out_r(s, arg);
+        tcg_out_r(s, arg1);
+        tcg_out32(s, arg2);
+#else
+        TODO();
+#endif
+    }
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
+}
+
+/* Test if a constant matches the constraint. */
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct)
+{
+    /* No need to return 0 or 1, 0 or != 0 is good enough. */
+    return arg_ct->ct & TCG_CT_CONST;
+}
+
+/* Maximum number of register used for input function arguments. */
+static int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return ARRAY_SIZE(tcg_target_call_iarg_regs);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+#if defined(CONFIG_DEBUG_TCG_INTERPRETER)
+    const char *envval = getenv("DEBUG_TCG");
+    if (envval) {
+        loglevel = strtol(envval, NULL, 0);
+    }
+#endif
+
+    /* The current code uses uint8_t for tcg operations. */
+    assert(ARRAY_SIZE(tcg_op_defs) <= UINT8_MAX);
+
+    /* Registers available for 32 bit operations. */
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0,
+                     BIT(TCG_TARGET_NB_REGS) - 1);
+    /* Registers available for 64 bit operations. */
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0,
+                     BIT(TCG_TARGET_NB_REGS) - 1);
+    /* TODO: Which registers should be set here? */
+    tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+                     BIT(TCG_TARGET_NB_REGS) - 1);
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+    tcg_add_target_add_op_defs(tcg_target_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+}
+
+/* Generate global QEMU prologue and epilogue code. */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    tb_ret_addr = s->code_ptr;
+}
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
new file mode 100644 (file)
index 0000000..03e0fd1
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009, 2011 Stefan Weil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * This code implements a TCG which does not generate machine code for some
+ * real target machine but which generates virtual machine code for an
+ * interpreter. Interpreted pseudo code is slow, but it works on any host.
+ *
+ * Some remarks might help in understanding the code:
+ *
+ * "target" or "TCG target" is the machine which runs the generated code.
+ * This is different to the usual meaning in QEMU where "target" is the
+ * emulated machine. So normally QEMU host is identical to TCG target.
+ * Here the TCG target is a virtual machine, but this virtual machine must
+ * use the same word size like the real machine.
+ * Therefore, we need both 32 and 64 bit virtual machines (interpreter).
+ */
+
+#if !defined(TCG_TARGET_H)
+#define TCG_TARGET_H
+
+#include "config-host.h"
+
+#define TCG_TARGET_INTERPRETER 1
+
+#ifdef CONFIG_DEBUG_TCG
+/* Enable debug output. */
+#define CONFIG_DEBUG_TCG_INTERPRETER
+#endif
+
+#if 0 /* TCI tries to emulate a little endian host. */
+#if defined(HOST_WORDS_BIGENDIAN)
+# define TCG_TARGET_WORDS_BIGENDIAN
+#endif
+#endif
+
+/* Optional instructions. */
+
+#define TCG_TARGET_HAS_bswap16_i32      1
+#define TCG_TARGET_HAS_bswap32_i32      1
+/* Not more than one of the next two defines must be 1. */
+#define TCG_TARGET_HAS_div_i32          1
+#define TCG_TARGET_HAS_div2_i32         0
+#define TCG_TARGET_HAS_ext8s_i32        1
+#define TCG_TARGET_HAS_ext16s_i32       1
+#define TCG_TARGET_HAS_ext8u_i32        1
+#define TCG_TARGET_HAS_ext16u_i32       1
+#define TCG_TARGET_HAS_andc_i32         0
+#define TCG_TARGET_HAS_deposit_i32      0
+#define TCG_TARGET_HAS_eqv_i32          0
+#define TCG_TARGET_HAS_nand_i32         0
+#define TCG_TARGET_HAS_nor_i32          0
+#define TCG_TARGET_HAS_neg_i32          1
+#define TCG_TARGET_HAS_not_i32          1
+#define TCG_TARGET_HAS_orc_i32          0
+#define TCG_TARGET_HAS_rot_i32          1
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_bswap16_i64      1
+#define TCG_TARGET_HAS_bswap32_i64      1
+#define TCG_TARGET_HAS_bswap64_i64      1
+#define TCG_TARGET_HAS_deposit_i64      0
+/* Not more than one of the next two defines must be 1. */
+#define TCG_TARGET_HAS_div_i64          0
+#define TCG_TARGET_HAS_div2_i64         0
+#define TCG_TARGET_HAS_ext8s_i64        1
+#define TCG_TARGET_HAS_ext16s_i64       1
+#define TCG_TARGET_HAS_ext32s_i64       1
+#define TCG_TARGET_HAS_ext8u_i64        1
+#define TCG_TARGET_HAS_ext16u_i64       1
+#define TCG_TARGET_HAS_ext32u_i64       1
+#define TCG_TARGET_HAS_andc_i64         0
+#define TCG_TARGET_HAS_eqv_i64          0
+#define TCG_TARGET_HAS_nand_i64         0
+#define TCG_TARGET_HAS_nor_i64          0
+#define TCG_TARGET_HAS_neg_i64          1
+#define TCG_TARGET_HAS_not_i64          1
+#define TCG_TARGET_HAS_orc_i64          0
+#define TCG_TARGET_HAS_rot_i64          1
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+/* Offset to user memory in user mode. */
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* Number of registers available.
+   For 32 bit hosts, we need more than 8 registers (call arguments). */
+/* #define TCG_TARGET_NB_REGS 8 */
+#define TCG_TARGET_NB_REGS 16
+/* #define TCG_TARGET_NB_REGS 32 */
+
+/* List of registers which are used by TCG. */
+typedef enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_AREG0 = TCG_REG_R7,
+#if TCG_TARGET_NB_REGS >= 16
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+#if TCG_TARGET_NB_REGS >= 32
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31,
+#endif
+#endif
+    /* Special value UINT8_MAX is used by TCI to encode constant values. */
+    TCG_CONST = UINT8_MAX
+} TCGReg;
+
+void tci_disas(uint8_t opc);
+
+unsigned long tcg_qemu_tb_exec(CPUState *env, uint8_t *tb_ptr);
+#define tcg_qemu_tb_exec tcg_qemu_tb_exec
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#endif /* TCG_TARGET_H */
diff --git a/tci-dis.c b/tci-dis.c
new file mode 100644 (file)
index 0000000..10c411b
--- /dev/null
+++ b/tci-dis.c
@@ -0,0 +1,59 @@
+/*
+ * Tiny Code Interpreter for QEMU - disassembler
+ *
+ * Copyright (c) 2011 Stefan Weil
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dis-asm.h"
+#include "tcg/tcg.h"
+
+/* Disassemble TCI bytecode. */
+int print_insn_tci(bfd_vma addr, disassemble_info *info)
+{
+    int length;
+    uint8_t byte;
+    int status;
+    TCGOpcode op;
+
+    status = info->read_memory_func(addr, &byte, 1, info);
+    if (status != 0) {
+        info->memory_error_func(status, addr, info);
+        return -1;
+    }
+    op = byte;
+
+    addr++;
+    status = info->read_memory_func(addr, &byte, 1, info);
+    if (status != 0) {
+        info->memory_error_func(status, addr, info);
+        return -1;
+    }
+    length = byte;
+
+    if (op >= tcg_op_defs_max) {
+        info->fprintf_func(info->stream, "illegal opcode %d", op);
+    } else {
+        const TCGOpDef *def = &tcg_op_defs[op];
+        int nb_oargs = def->nb_oargs;
+        int nb_iargs = def->nb_iargs;
+        int nb_cargs = def->nb_cargs;
+        /* TODO: Improve disassembler output. */
+        info->fprintf_func(info->stream, "%s\to=%d i=%d c=%d",
+                           def->name, nb_oargs, nb_iargs, nb_cargs);
+    }
+
+    return length;
+}
diff --git a/tci.c b/tci.c
new file mode 100644 (file)
index 0000000..a20a714
--- /dev/null
+++ b/tci.c
@@ -0,0 +1,1208 @@
+/*
+ * Tiny Code Interpreter for QEMU
+ *
+ * Copyright (c) 2009, 2011 Stefan Weil
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+/* Defining NDEBUG disables assertions (which makes the code faster). */
+#if !defined(CONFIG_TCG_DEBUG) && !defined(NDEBUG)
+# define NDEBUG
+#endif
+
+#include "qemu-common.h"
+#include "dyngen-exec.h"        /* env */
+#include "exec-all.h"           /* MAX_OPC_PARAM_IARGS */
+#include "tcg-op.h"
+
+/* Marker for missing code. */
+#define TODO() \
+    do { \
+        fprintf(stderr, "TODO %s:%u: %s()\n", \
+                __FILE__, __LINE__, __func__); \
+        tcg_abort(); \
+    } while (0)
+
+#if MAX_OPC_PARAM_IARGS != 4
+# error Fix needed, number of supported input arguments changed!
+#endif
+#if TCG_TARGET_REG_BITS == 32
+typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong,
+                                    tcg_target_ulong, tcg_target_ulong,
+                                    tcg_target_ulong, tcg_target_ulong,
+                                    tcg_target_ulong, tcg_target_ulong);
+#else
+typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong,
+                                    tcg_target_ulong, tcg_target_ulong);
+#endif
+
+/* TCI can optionally use a global register variable for env. */
+#if !defined(AREG0)
+CPUState *env;
+#endif
+
+/* Targets which don't use GETPC also don't need tci_tb_ptr
+   which makes them a little faster. */
+#if defined(GETPC)
+void *tci_tb_ptr;
+#endif
+
+static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS];
+
+static tcg_target_ulong tci_read_reg(TCGReg index)
+{
+    assert(index < ARRAY_SIZE(tci_reg));
+    return tci_reg[index];
+}
+
+#if TCG_TARGET_HAS_ext8s_i32 || TCG_TARGET_HAS_ext8s_i64
+static int8_t tci_read_reg8s(TCGReg index)
+{
+    return (int8_t)tci_read_reg(index);
+}
+#endif
+
+#if TCG_TARGET_HAS_ext16s_i32 || TCG_TARGET_HAS_ext16s_i64
+static int16_t tci_read_reg16s(TCGReg index)
+{
+    return (int16_t)tci_read_reg(index);
+}
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+static int32_t tci_read_reg32s(TCGReg index)
+{
+    return (int32_t)tci_read_reg(index);
+}
+#endif
+
+static uint8_t tci_read_reg8(TCGReg index)
+{
+    return (uint8_t)tci_read_reg(index);
+}
+
+static uint16_t tci_read_reg16(TCGReg index)
+{
+    return (uint16_t)tci_read_reg(index);
+}
+
+static uint32_t tci_read_reg32(TCGReg index)
+{
+    return (uint32_t)tci_read_reg(index);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static uint64_t tci_read_reg64(TCGReg index)
+{
+    return tci_read_reg(index);
+}
+#endif
+
+static void tci_write_reg(TCGReg index, tcg_target_ulong value)
+{
+    assert(index < ARRAY_SIZE(tci_reg));
+    assert(index != TCG_AREG0);
+    tci_reg[index] = value;
+}
+
+static void tci_write_reg8s(TCGReg index, int8_t value)
+{
+    tci_write_reg(index, value);
+}
+
+static void tci_write_reg16s(TCGReg index, int16_t value)
+{
+    tci_write_reg(index, value);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tci_write_reg32s(TCGReg index, int32_t value)
+{
+    tci_write_reg(index, value);
+}
+#endif
+
+static void tci_write_reg8(TCGReg index, uint8_t value)
+{
+    tci_write_reg(index, value);
+}
+
+static void tci_write_reg16(TCGReg index, uint16_t value)
+{
+    tci_write_reg(index, value);
+}
+
+static void tci_write_reg32(TCGReg index, uint32_t value)
+{
+    tci_write_reg(index, value);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static void tci_write_reg64(uint32_t high_index, uint32_t low_index,
+                            uint64_t value)
+{
+    tci_write_reg(low_index, value);
+    tci_write_reg(high_index, value >> 32);
+}
+#elif TCG_TARGET_REG_BITS == 64
+static void tci_write_reg64(TCGReg index, uint64_t value)
+{
+    tci_write_reg(index, value);
+}
+#endif
+
+#if TCG_TARGET_REG_BITS == 32
+/* Create a 64 bit value from two 32 bit values. */
+static uint64_t tci_uint64(uint32_t high, uint32_t low)
+{
+    return ((uint64_t)high << 32) + low;
+}
+#endif
+
+/* Read constant (native size) from bytecode. */
+static tcg_target_ulong tci_read_i(uint8_t **tb_ptr)
+{
+    tcg_target_ulong value = *(tcg_target_ulong *)(*tb_ptr);
+    *tb_ptr += sizeof(value);
+    return value;
+}
+
+/* Read constant (32 bit) from bytecode. */
+static uint32_t tci_read_i32(uint8_t **tb_ptr)
+{
+    uint32_t value = *(uint32_t *)(*tb_ptr);
+    *tb_ptr += sizeof(value);
+    return value;
+}
+
+#if TCG_TARGET_REG_BITS == 64
+/* Read constant (64 bit) from bytecode. */
+static uint64_t tci_read_i64(uint8_t **tb_ptr)
+{
+    uint64_t value = *(uint64_t *)(*tb_ptr);
+    *tb_ptr += sizeof(value);
+    return value;
+}
+#endif
+
+/* Read indexed register (native size) from bytecode. */
+static tcg_target_ulong tci_read_r(uint8_t **tb_ptr)
+{
+    tcg_target_ulong value = tci_read_reg(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+
+/* Read indexed register (8 bit) from bytecode. */
+static uint8_t tci_read_r8(uint8_t **tb_ptr)
+{
+    uint8_t value = tci_read_reg8(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+
+#if TCG_TARGET_HAS_ext8s_i32 || TCG_TARGET_HAS_ext8s_i64
+/* Read indexed register (8 bit signed) from bytecode. */
+static int8_t tci_read_r8s(uint8_t **tb_ptr)
+{
+    int8_t value = tci_read_reg8s(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+#endif
+
+/* Read indexed register (16 bit) from bytecode. */
+static uint16_t tci_read_r16(uint8_t **tb_ptr)
+{
+    uint16_t value = tci_read_reg16(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+
+#if TCG_TARGET_HAS_ext16s_i32 || TCG_TARGET_HAS_ext16s_i64
+/* Read indexed register (16 bit signed) from bytecode. */
+static int16_t tci_read_r16s(uint8_t **tb_ptr)
+{
+    int16_t value = tci_read_reg16s(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+#endif
+
+/* Read indexed register (32 bit) from bytecode. */
+static uint32_t tci_read_r32(uint8_t **tb_ptr)
+{
+    uint32_t value = tci_read_reg32(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+
+#if TCG_TARGET_REG_BITS == 32
+/* Read two indexed registers (2 * 32 bit) from bytecode. */
+static uint64_t tci_read_r64(uint8_t **tb_ptr)
+{
+    uint32_t low = tci_read_r32(tb_ptr);
+    return tci_uint64(tci_read_r32(tb_ptr), low);
+}
+#elif TCG_TARGET_REG_BITS == 64
+/* Read indexed register (32 bit signed) from bytecode. */
+static int32_t tci_read_r32s(uint8_t **tb_ptr)
+{
+    int32_t value = tci_read_reg32s(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+
+/* Read indexed register (64 bit) from bytecode. */
+static uint64_t tci_read_r64(uint8_t **tb_ptr)
+{
+    uint64_t value = tci_read_reg64(**tb_ptr);
+    *tb_ptr += 1;
+    return value;
+}
+#endif
+
+/* Read indexed register(s) with target address from bytecode. */
+static target_ulong tci_read_ulong(uint8_t **tb_ptr)
+{
+    target_ulong taddr = tci_read_r(tb_ptr);
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+    taddr += (uint64_t)tci_read_r(tb_ptr) << 32;
+#endif
+    return taddr;
+}
+
+/* Read indexed register or constant (native size) from bytecode. */
+static tcg_target_ulong tci_read_ri(uint8_t **tb_ptr)
+{
+    tcg_target_ulong value;
+    TCGReg r = **tb_ptr;
+    *tb_ptr += 1;
+    if (r == TCG_CONST) {
+        value = tci_read_i(tb_ptr);
+    } else {
+        value = tci_read_reg(r);
+    }
+    return value;
+}
+
+/* Read indexed register or constant (32 bit) from bytecode. */
+static uint32_t tci_read_ri32(uint8_t **tb_ptr)
+{
+    uint32_t value;
+    TCGReg r = **tb_ptr;
+    *tb_ptr += 1;
+    if (r == TCG_CONST) {
+        value = tci_read_i32(tb_ptr);
+    } else {
+        value = tci_read_reg32(r);
+    }
+    return value;
+}
+
+#if TCG_TARGET_REG_BITS == 32
+/* Read two indexed registers or constants (2 * 32 bit) from bytecode. */
+static uint64_t tci_read_ri64(uint8_t **tb_ptr)
+{
+    uint32_t low = tci_read_ri32(tb_ptr);
+    return tci_uint64(tci_read_ri32(tb_ptr), low);
+}
+#elif TCG_TARGET_REG_BITS == 64
+/* Read indexed register or constant (64 bit) from bytecode. */
+static uint64_t tci_read_ri64(uint8_t **tb_ptr)
+{
+    uint64_t value;
+    TCGReg r = **tb_ptr;
+    *tb_ptr += 1;
+    if (r == TCG_CONST) {
+        value = tci_read_i64(tb_ptr);
+    } else {
+        value = tci_read_reg64(r);
+    }
+    return value;
+}
+#endif
+
+static target_ulong tci_read_label(uint8_t **tb_ptr)
+{
+    target_ulong label = tci_read_i(tb_ptr);
+    assert(label != 0);
+    return label;
+}
+
+static bool tci_compare32(uint32_t u0, uint32_t u1, TCGCond condition)
+{
+    bool result = false;
+    int32_t i0 = u0;
+    int32_t i1 = u1;
+    switch (condition) {
+    case TCG_COND_EQ:
+        result = (u0 == u1);
+        break;
+    case TCG_COND_NE:
+        result = (u0 != u1);
+        break;
+    case TCG_COND_LT:
+        result = (i0 < i1);
+        break;
+    case TCG_COND_GE:
+        result = (i0 >= i1);
+        break;
+    case TCG_COND_LE:
+        result = (i0 <= i1);
+        break;
+    case TCG_COND_GT:
+        result = (i0 > i1);
+        break;
+    case TCG_COND_LTU:
+        result = (u0 < u1);
+        break;
+    case TCG_COND_GEU:
+        result = (u0 >= u1);
+        break;
+    case TCG_COND_LEU:
+        result = (u0 <= u1);
+        break;
+    case TCG_COND_GTU:
+        result = (u0 > u1);
+        break;
+    default:
+        TODO();
+    }
+    return result;
+}
+
+static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
+{
+    bool result = false;
+    int64_t i0 = u0;
+    int64_t i1 = u1;
+    switch (condition) {
+    case TCG_COND_EQ:
+        result = (u0 == u1);
+        break;
+    case TCG_COND_NE:
+        result = (u0 != u1);
+        break;
+    case TCG_COND_LT:
+        result = (i0 < i1);
+        break;
+    case TCG_COND_GE:
+        result = (i0 >= i1);
+        break;
+    case TCG_COND_LE:
+        result = (i0 <= i1);
+        break;
+    case TCG_COND_GT:
+        result = (i0 > i1);
+        break;
+    case TCG_COND_LTU:
+        result = (u0 < u1);
+        break;
+    case TCG_COND_GEU:
+        result = (u0 >= u1);
+        break;
+    case TCG_COND_LEU:
+        result = (u0 <= u1);
+        break;
+    case TCG_COND_GTU:
+        result = (u0 > u1);
+        break;
+    default:
+        TODO();
+    }
+    return result;
+}
+
+/* Interpret pseudo code in tb. */
+unsigned long tcg_qemu_tb_exec(CPUState *cpustate, uint8_t *tb_ptr)
+{
+    unsigned long next_tb = 0;
+
+    env = cpustate;
+    tci_reg[TCG_AREG0] = (tcg_target_ulong)env;
+    assert(tb_ptr);
+
+    for (;;) {
+#if defined(GETPC)
+        tci_tb_ptr = tb_ptr;
+#endif
+        TCGOpcode opc = tb_ptr[0];
+#if !defined(NDEBUG)
+        uint8_t op_size = tb_ptr[1];
+        uint8_t *old_code_ptr = tb_ptr;
+#endif
+        tcg_target_ulong t0;
+        tcg_target_ulong t1;
+        tcg_target_ulong t2;
+        tcg_target_ulong label;
+        TCGCond condition;
+        target_ulong taddr;
+#ifndef CONFIG_SOFTMMU
+        tcg_target_ulong host_addr;
+#endif
+        uint8_t tmp8;
+        uint16_t tmp16;
+        uint32_t tmp32;
+        uint64_t tmp64;
+#if TCG_TARGET_REG_BITS == 32
+        uint64_t v64;
+#endif
+
+        /* Skip opcode and size entry. */
+        tb_ptr += 2;
+
+        switch (opc) {
+        case INDEX_op_end:
+        case INDEX_op_nop:
+            break;
+        case INDEX_op_nop1:
+        case INDEX_op_nop2:
+        case INDEX_op_nop3:
+        case INDEX_op_nopn:
+        case INDEX_op_discard:
+            TODO();
+            break;
+        case INDEX_op_set_label:
+            TODO();
+            break;
+        case INDEX_op_call:
+            t0 = tci_read_ri(&tb_ptr);
+#if TCG_TARGET_REG_BITS == 32
+            tmp64 = ((helper_function)t0)(tci_read_reg(TCG_REG_R0),
+                                          tci_read_reg(TCG_REG_R1),
+                                          tci_read_reg(TCG_REG_R2),
+                                          tci_read_reg(TCG_REG_R3),
+                                          tci_read_reg(TCG_REG_R5),
+                                          tci_read_reg(TCG_REG_R6),
+                                          tci_read_reg(TCG_REG_R7),
+                                          tci_read_reg(TCG_REG_R8));
+            tci_write_reg(TCG_REG_R0, tmp64);
+            tci_write_reg(TCG_REG_R1, tmp64 >> 32);
+#else
+            tmp64 = ((helper_function)t0)(tci_read_reg(TCG_REG_R0),
+                                          tci_read_reg(TCG_REG_R1),
+                                          tci_read_reg(TCG_REG_R2),
+                                          tci_read_reg(TCG_REG_R3));
+            tci_write_reg(TCG_REG_R0, tmp64);
+#endif
+            break;
+        case INDEX_op_jmp:
+        case INDEX_op_br:
+            label = tci_read_label(&tb_ptr);
+            assert(tb_ptr == old_code_ptr + op_size);
+            tb_ptr = (uint8_t *)label;
+            continue;
+        case INDEX_op_setcond_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            condition = *tb_ptr++;
+            tci_write_reg32(t0, tci_compare32(t1, t2, condition));
+            break;
+#if TCG_TARGET_REG_BITS == 32
+        case INDEX_op_setcond2_i32:
+            t0 = *tb_ptr++;
+            tmp64 = tci_read_r64(&tb_ptr);
+            v64 = tci_read_ri64(&tb_ptr);
+            condition = *tb_ptr++;
+            tci_write_reg32(t0, tci_compare64(tmp64, v64, condition));
+            break;
+#elif TCG_TARGET_REG_BITS == 64
+        case INDEX_op_setcond_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            condition = *tb_ptr++;
+            tci_write_reg64(t0, tci_compare64(t1, t2, condition));
+            break;
+#endif
+        case INDEX_op_mov_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+        case INDEX_op_movi_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_i32(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+
+            /* Load/store operations (32 bit). */
+
+        case INDEX_op_ld8u_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg8(t0, *(uint8_t *)(t1 + t2));
+            break;
+        case INDEX_op_ld8s_i32:
+        case INDEX_op_ld16u_i32:
+            TODO();
+            break;
+        case INDEX_op_ld16s_i32:
+            TODO();
+            break;
+        case INDEX_op_ld_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg32(t0, *(uint32_t *)(t1 + t2));
+            break;
+        case INDEX_op_st8_i32:
+            t0 = tci_read_r8(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint8_t *)(t1 + t2) = t0;
+            break;
+        case INDEX_op_st16_i32:
+            t0 = tci_read_r16(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint16_t *)(t1 + t2) = t0;
+            break;
+        case INDEX_op_st_i32:
+            t0 = tci_read_r32(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint32_t *)(t1 + t2) = t0;
+            break;
+
+            /* Arithmetic operations (32 bit). */
+
+        case INDEX_op_add_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 + t2);
+            break;
+        case INDEX_op_sub_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 - t2);
+            break;
+        case INDEX_op_mul_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 * t2);
+            break;
+#if TCG_TARGET_HAS_div_i32
+        case INDEX_op_div_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, (int32_t)t1 / (int32_t)t2);
+            break;
+        case INDEX_op_divu_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 / t2);
+            break;
+        case INDEX_op_rem_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, (int32_t)t1 % (int32_t)t2);
+            break;
+        case INDEX_op_remu_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 % t2);
+            break;
+#elif TCG_TARGET_HAS_div2_i32
+        case INDEX_op_div2_i32:
+        case INDEX_op_divu2_i32:
+            TODO();
+            break;
+#endif
+        case INDEX_op_and_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 & t2);
+            break;
+        case INDEX_op_or_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 | t2);
+            break;
+        case INDEX_op_xor_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 ^ t2);
+            break;
+
+            /* Shift/rotate operations (32 bit). */
+
+        case INDEX_op_shl_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 << t2);
+            break;
+        case INDEX_op_shr_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, t1 >> t2);
+            break;
+        case INDEX_op_sar_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, ((int32_t)t1 >> t2));
+            break;
+#if TCG_TARGET_HAS_rot_i32
+        case INDEX_op_rotl_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, (t1 << t2) | (t1 >> (32 - t2)));
+            break;
+        case INDEX_op_rotr_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri32(&tb_ptr);
+            t2 = tci_read_ri32(&tb_ptr);
+            tci_write_reg32(t0, (t1 >> t2) | (t1 << (32 - t2)));
+            break;
+#endif
+        case INDEX_op_brcond_i32:
+            t0 = tci_read_r32(&tb_ptr);
+            t1 = tci_read_ri32(&tb_ptr);
+            condition = *tb_ptr++;
+            label = tci_read_label(&tb_ptr);
+            if (tci_compare32(t0, t1, condition)) {
+                assert(tb_ptr == old_code_ptr + op_size);
+                tb_ptr = (uint8_t *)label;
+                continue;
+            }
+            break;
+#if TCG_TARGET_REG_BITS == 32
+        case INDEX_op_add2_i32:
+            t0 = *tb_ptr++;
+            t1 = *tb_ptr++;
+            tmp64 = tci_read_r64(&tb_ptr);
+            tmp64 += tci_read_r64(&tb_ptr);
+            tci_write_reg64(t1, t0, tmp64);
+            break;
+        case INDEX_op_sub2_i32:
+            t0 = *tb_ptr++;
+            t1 = *tb_ptr++;
+            tmp64 = tci_read_r64(&tb_ptr);
+            tmp64 -= tci_read_r64(&tb_ptr);
+            tci_write_reg64(t1, t0, tmp64);
+            break;
+        case INDEX_op_brcond2_i32:
+            tmp64 = tci_read_r64(&tb_ptr);
+            v64 = tci_read_ri64(&tb_ptr);
+            condition = *tb_ptr++;
+            label = tci_read_label(&tb_ptr);
+            if (tci_compare64(tmp64, v64, condition)) {
+                assert(tb_ptr == old_code_ptr + op_size);
+                tb_ptr = (uint8_t *)label;
+                continue;
+            }
+            break;
+        case INDEX_op_mulu2_i32:
+            t0 = *tb_ptr++;
+            t1 = *tb_ptr++;
+            t2 = tci_read_r32(&tb_ptr);
+            tmp64 = tci_read_r32(&tb_ptr);
+            tci_write_reg64(t1, t0, t2 * tmp64);
+            break;
+#endif /* TCG_TARGET_REG_BITS == 32 */
+#if TCG_TARGET_HAS_ext8s_i32
+        case INDEX_op_ext8s_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r8s(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext16s_i32
+        case INDEX_op_ext16s_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16s(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext8u_i32
+        case INDEX_op_ext8u_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r8(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext16u_i32
+        case INDEX_op_ext16u_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16(&tb_ptr);
+            tci_write_reg32(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_bswap16_i32
+        case INDEX_op_bswap16_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16(&tb_ptr);
+            tci_write_reg32(t0, bswap16(t1));
+            break;
+#endif
+#if TCG_TARGET_HAS_bswap32_i32
+        case INDEX_op_bswap32_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg32(t0, bswap32(t1));
+            break;
+#endif
+#if TCG_TARGET_HAS_not_i32
+        case INDEX_op_not_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg32(t0, ~t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_neg_i32
+        case INDEX_op_neg_i32:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg32(t0, -t1);
+            break;
+#endif
+#if TCG_TARGET_REG_BITS == 64
+        case INDEX_op_mov_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r64(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+        case INDEX_op_movi_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_i64(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+
+            /* Load/store operations (64 bit). */
+
+        case INDEX_op_ld8u_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg8(t0, *(uint8_t *)(t1 + t2));
+            break;
+        case INDEX_op_ld8s_i64:
+        case INDEX_op_ld16u_i64:
+        case INDEX_op_ld16s_i64:
+            TODO();
+            break;
+        case INDEX_op_ld32u_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg32(t0, *(uint32_t *)(t1 + t2));
+            break;
+        case INDEX_op_ld32s_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg32s(t0, *(int32_t *)(t1 + t2));
+            break;
+        case INDEX_op_ld_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            tci_write_reg64(t0, *(uint64_t *)(t1 + t2));
+            break;
+        case INDEX_op_st8_i64:
+            t0 = tci_read_r8(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint8_t *)(t1 + t2) = t0;
+            break;
+        case INDEX_op_st16_i64:
+            t0 = tci_read_r16(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint16_t *)(t1 + t2) = t0;
+            break;
+        case INDEX_op_st32_i64:
+            t0 = tci_read_r32(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint32_t *)(t1 + t2) = t0;
+            break;
+        case INDEX_op_st_i64:
+            t0 = tci_read_r64(&tb_ptr);
+            t1 = tci_read_r(&tb_ptr);
+            t2 = tci_read_i32(&tb_ptr);
+            *(uint64_t *)(t1 + t2) = t0;
+            break;
+
+            /* Arithmetic operations (64 bit). */
+
+        case INDEX_op_add_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 + t2);
+            break;
+        case INDEX_op_sub_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 - t2);
+            break;
+        case INDEX_op_mul_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 * t2);
+            break;
+#if TCG_TARGET_HAS_div_i64
+        case INDEX_op_div_i64:
+        case INDEX_op_divu_i64:
+        case INDEX_op_rem_i64:
+        case INDEX_op_remu_i64:
+            TODO();
+            break;
+#elif TCG_TARGET_HAS_div2_i64
+        case INDEX_op_div2_i64:
+        case INDEX_op_divu2_i64:
+            TODO();
+            break;
+#endif
+        case INDEX_op_and_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 & t2);
+            break;
+        case INDEX_op_or_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 | t2);
+            break;
+        case INDEX_op_xor_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 ^ t2);
+            break;
+
+            /* Shift/rotate operations (64 bit). */
+
+        case INDEX_op_shl_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 << t2);
+            break;
+        case INDEX_op_shr_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, t1 >> t2);
+            break;
+        case INDEX_op_sar_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_ri64(&tb_ptr);
+            t2 = tci_read_ri64(&tb_ptr);
+            tci_write_reg64(t0, ((int64_t)t1 >> t2));
+            break;
+#if TCG_TARGET_HAS_rot_i64
+        case INDEX_op_rotl_i64:
+        case INDEX_op_rotr_i64:
+            TODO();
+            break;
+#endif
+        case INDEX_op_brcond_i64:
+            t0 = tci_read_r64(&tb_ptr);
+            t1 = tci_read_ri64(&tb_ptr);
+            condition = *tb_ptr++;
+            label = tci_read_label(&tb_ptr);
+            if (tci_compare64(t0, t1, condition)) {
+                assert(tb_ptr == old_code_ptr + op_size);
+                tb_ptr = (uint8_t *)label;
+                continue;
+            }
+            break;
+#if TCG_TARGET_HAS_ext8u_i64
+        case INDEX_op_ext8u_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r8(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext8s_i64
+        case INDEX_op_ext8s_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r8s(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext16s_i64
+        case INDEX_op_ext16s_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16s(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext16u_i64
+        case INDEX_op_ext16u_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext32s_i64
+        case INDEX_op_ext32s_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32s(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_ext32u_i64
+        case INDEX_op_ext32u_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg64(t0, t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_bswap16_i64
+        case INDEX_op_bswap16_i64:
+            TODO();
+            t0 = *tb_ptr++;
+            t1 = tci_read_r16(&tb_ptr);
+            tci_write_reg64(t0, bswap16(t1));
+            break;
+#endif
+#if TCG_TARGET_HAS_bswap32_i64
+        case INDEX_op_bswap32_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r32(&tb_ptr);
+            tci_write_reg64(t0, bswap32(t1));
+            break;
+#endif
+#if TCG_TARGET_HAS_bswap64_i64
+        case INDEX_op_bswap64_i64:
+            TODO();
+            t0 = *tb_ptr++;
+            t1 = tci_read_r64(&tb_ptr);
+            tci_write_reg64(t0, bswap64(t1));
+            break;
+#endif
+#if TCG_TARGET_HAS_not_i64
+        case INDEX_op_not_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r64(&tb_ptr);
+            tci_write_reg64(t0, ~t1);
+            break;
+#endif
+#if TCG_TARGET_HAS_neg_i64
+        case INDEX_op_neg_i64:
+            t0 = *tb_ptr++;
+            t1 = tci_read_r64(&tb_ptr);
+            tci_write_reg64(t0, -t1);
+            break;
+#endif
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+            /* QEMU specific operations. */
+
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+        case INDEX_op_debug_insn_start:
+            TODO();
+            break;
+#else
+        case INDEX_op_debug_insn_start:
+            TODO();
+            break;
+#endif
+        case INDEX_op_exit_tb:
+            next_tb = *(uint64_t *)tb_ptr;
+            goto exit;
+            break;
+        case INDEX_op_goto_tb:
+            t0 = tci_read_i32(&tb_ptr);
+            assert(tb_ptr == old_code_ptr + op_size);
+            tb_ptr += (int32_t)t0;
+            continue;
+        case INDEX_op_qemu_ld8u:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp8 = __ldb_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp8 = *(uint8_t *)(host_addr + GUEST_BASE);
+#endif
+            tci_write_reg8(t0, tmp8);
+            break;
+        case INDEX_op_qemu_ld8s:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp8 = __ldb_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp8 = *(uint8_t *)(host_addr + GUEST_BASE);
+#endif
+            tci_write_reg8s(t0, tmp8);
+            break;
+        case INDEX_op_qemu_ld16u:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp16 = __ldw_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp16 = tswap16(*(uint16_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg16(t0, tmp16);
+            break;
+        case INDEX_op_qemu_ld16s:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp16 = __ldw_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp16 = tswap16(*(uint16_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg16s(t0, tmp16);
+            break;
+#if TCG_TARGET_REG_BITS == 64
+        case INDEX_op_qemu_ld32u:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg32(t0, tmp32);
+            break;
+        case INDEX_op_qemu_ld32s:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg32s(t0, tmp32);
+            break;
+#endif /* TCG_TARGET_REG_BITS == 64 */
+        case INDEX_op_qemu_ld32:
+            t0 = *tb_ptr++;
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg32(t0, tmp32);
+            break;
+        case INDEX_op_qemu_ld64:
+            t0 = *tb_ptr++;
+#if TCG_TARGET_REG_BITS == 32
+            t1 = *tb_ptr++;
+#endif
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            tmp64 = __ldq_mmu(taddr, tci_read_i(&tb_ptr));
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            tmp64 = tswap64(*(uint64_t *)(host_addr + GUEST_BASE));
+#endif
+            tci_write_reg(t0, tmp64);
+#if TCG_TARGET_REG_BITS == 32
+            tci_write_reg(t1, tmp64 >> 32);
+#endif
+            break;
+        case INDEX_op_qemu_st8:
+            t0 = tci_read_r8(&tb_ptr);
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            t2 = tci_read_i(&tb_ptr);
+            __stb_mmu(taddr, t0, t2);
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            *(uint8_t *)(host_addr + GUEST_BASE) = t0;
+#endif
+            break;
+        case INDEX_op_qemu_st16:
+            t0 = tci_read_r16(&tb_ptr);
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            t2 = tci_read_i(&tb_ptr);
+            __stw_mmu(taddr, t0, t2);
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            *(uint16_t *)(host_addr + GUEST_BASE) = tswap16(t0);
+#endif
+            break;
+        case INDEX_op_qemu_st32:
+            t0 = tci_read_r32(&tb_ptr);
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            t2 = tci_read_i(&tb_ptr);
+            __stl_mmu(taddr, t0, t2);
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            *(uint32_t *)(host_addr + GUEST_BASE) = tswap32(t0);
+#endif
+            break;
+        case INDEX_op_qemu_st64:
+            tmp64 = tci_read_r64(&tb_ptr);
+            taddr = tci_read_ulong(&tb_ptr);
+#ifdef CONFIG_SOFTMMU
+            t2 = tci_read_i(&tb_ptr);
+            __stq_mmu(taddr, tmp64, t2);
+#else
+            host_addr = (tcg_target_ulong)taddr;
+            assert(taddr == host_addr);
+            *(uint64_t *)(host_addr + GUEST_BASE) = tswap64(tmp64);
+#endif
+            break;
+        default:
+            TODO();
+            break;
+        }
+        assert(tb_ptr == old_code_ptr + op_size);
+    }
+exit:
+    return next_tb;
+}
diff --git a/test-coroutine.c b/test-coroutine.c
new file mode 100644 (file)
index 0000000..bf9f3e9
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Coroutine tests
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include "qemu-coroutine.h"
+
+/*
+ * Check that qemu_in_coroutine() works
+ */
+
+static void coroutine_fn verify_in_coroutine(void *opaque)
+{
+    g_assert(qemu_in_coroutine());
+}
+
+static void test_in_coroutine(void)
+{
+    Coroutine *coroutine;
+
+    g_assert(!qemu_in_coroutine());
+
+    coroutine = qemu_coroutine_create(verify_in_coroutine);
+    qemu_coroutine_enter(coroutine, NULL);
+}
+
+/*
+ * Check that qemu_coroutine_self() works
+ */
+
+static void coroutine_fn verify_self(void *opaque)
+{
+    g_assert(qemu_coroutine_self() == opaque);
+}
+
+static void test_self(void)
+{
+    Coroutine *coroutine;
+
+    coroutine = qemu_coroutine_create(verify_self);
+    qemu_coroutine_enter(coroutine, coroutine);
+}
+
+/*
+ * Check that coroutines may nest multiple levels
+ */
+
+typedef struct {
+    unsigned int n_enter;   /* num coroutines entered */
+    unsigned int n_return;  /* num coroutines returned */
+    unsigned int max;       /* maximum level of nesting */
+} NestData;
+
+static void coroutine_fn nest(void *opaque)
+{
+    NestData *nd = opaque;
+
+    nd->n_enter++;
+
+    if (nd->n_enter < nd->max) {
+        Coroutine *child;
+
+        child = qemu_coroutine_create(nest);
+        qemu_coroutine_enter(child, nd);
+    }
+
+    nd->n_return++;
+}
+
+static void test_nesting(void)
+{
+    Coroutine *root;
+    NestData nd = {
+        .n_enter  = 0,
+        .n_return = 0,
+        .max      = 128,
+    };
+
+    root = qemu_coroutine_create(nest);
+    qemu_coroutine_enter(root, &nd);
+
+    /* Must enter and return from max nesting level */
+    g_assert_cmpint(nd.n_enter, ==, nd.max);
+    g_assert_cmpint(nd.n_return, ==, nd.max);
+}
+
+/*
+ * Check that yield/enter transfer control correctly
+ */
+
+static void coroutine_fn yield_5_times(void *opaque)
+{
+    bool *done = opaque;
+    int i;
+
+    for (i = 0; i < 5; i++) {
+        qemu_coroutine_yield();
+    }
+    *done = true;
+}
+
+static void test_yield(void)
+{
+    Coroutine *coroutine;
+    bool done = false;
+    int i = -1; /* one extra time to return from coroutine */
+
+    coroutine = qemu_coroutine_create(yield_5_times);
+    while (!done) {
+        qemu_coroutine_enter(coroutine, &done);
+        i++;
+    }
+    g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
+}
+
+/*
+ * Check that creation, enter, and return work
+ */
+
+static void coroutine_fn set_and_exit(void *opaque)
+{
+    bool *done = opaque;
+
+    *done = true;
+}
+
+static void test_lifecycle(void)
+{
+    Coroutine *coroutine;
+    bool done = false;
+
+    /* Create, enter, and return from coroutine */
+    coroutine = qemu_coroutine_create(set_and_exit);
+    qemu_coroutine_enter(coroutine, &done);
+    g_assert(done); /* expect done to be true (first time) */
+
+    /* Repeat to check that no state affects this test */
+    done = false;
+    coroutine = qemu_coroutine_create(set_and_exit);
+    qemu_coroutine_enter(coroutine, &done);
+    g_assert(done); /* expect done to be true (second time) */
+}
+
+/*
+ * Lifecycle benchmark
+ */
+
+static void coroutine_fn empty_coroutine(void *opaque)
+{
+    /* Do nothing */
+}
+
+static void perf_lifecycle(void)
+{
+    Coroutine *coroutine;
+    unsigned int i, max;
+    double duration;
+
+    max = 1000000;
+
+    g_test_timer_start();
+    for (i = 0; i < max; i++) {
+        coroutine = qemu_coroutine_create(empty_coroutine);
+        qemu_coroutine_enter(coroutine, NULL);
+    }
+    duration = g_test_timer_elapsed();
+
+    g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/basic/lifecycle", test_lifecycle);
+    g_test_add_func("/basic/yield", test_yield);
+    g_test_add_func("/basic/nesting", test_nesting);
+    g_test_add_func("/basic/self", test_self);
+    g_test_add_func("/basic/in_coroutine", test_in_coroutine);
+    if (g_test_perf()) {
+        g_test_add_func("/perf/lifecycle", perf_lifecycle);
+    }
+    return g_test_run();
+}
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
new file mode 100644 (file)
index 0000000..fa5a7bd
--- /dev/null
@@ -0,0 +1,142 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "test-qmp-commands.h"
+#include "qapi/qmp-core.h"
+#include "module.h"
+
+void qmp_user_def_cmd(Error **errp)
+{
+}
+
+void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
+{
+}
+
+UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
+{
+    UserDefTwo *ret;
+    UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne));
+    UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));
+
+    ud1c->string = strdup(ud1a->string);
+    ud1c->integer = ud1a->integer;
+    ud1d->string = strdup(ud1b->string);
+    ud1d->integer = ud1b->integer;
+
+    ret = g_malloc0(sizeof(UserDefTwo));
+    ret->string = strdup("blah1");
+    ret->dict.string = strdup("blah2");
+    ret->dict.dict.userdef = ud1c;
+    ret->dict.dict.string = strdup("blah3");
+    ret->dict.has_dict2 = true;
+    ret->dict.dict2.userdef = ud1d;
+    ret->dict.dict2.string = strdup("blah4");
+
+    return ret;
+}
+
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_error(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that involve both input parameters and return values */
+static void test_dispatch_cmd_io(void)
+{
+    QDict *req = qdict_new();
+    QDict *args = qdict_new();
+    QDict *ud1a = qdict_new();
+    QDict *ud1b = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
+    qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
+    qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
+    qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
+    qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
+    qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
+    qdict_put_obj(req, "arguments", QOBJECT(args));
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    /* TODO: put in full payload and check for errors */
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test generated dealloc functions for generated types */
+static void test_dealloc_types(void)
+{
+    UserDefOne *ud1test, *ud1a, *ud1b;
+    UserDefOneList *ud1list;
+
+    ud1test = g_malloc0(sizeof(UserDefOne));
+    ud1test->integer = 42;
+    ud1test->string = g_strdup("hi there 42");
+
+    qapi_free_UserDefOne(ud1test);
+
+    ud1a = g_malloc0(sizeof(UserDefOne));
+    ud1a->integer = 43;
+    ud1a->string = g_strdup("hi there 43");
+
+    ud1b = g_malloc0(sizeof(UserDefOne));
+    ud1b->integer = 44;
+    ud1b->string = g_strdup("hi there 44");
+
+    ud1list = g_malloc0(sizeof(UserDefOneList));
+    ud1list->value = ud1a;
+    ud1list->next = g_malloc0(sizeof(UserDefOneList));
+    ud1list->next->value = ud1b;
+
+    qapi_free_UserDefOneList(ud1list);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
+    g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
+    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+    g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
+
+    module_call_init(MODULE_INIT_QAPI);
+    g_test_run();
+
+    return 0;
+}
diff --git a/test-visitor.c b/test-visitor.c
new file mode 100644 (file)
index 0000000..847ce14
--- /dev/null
@@ -0,0 +1,338 @@
+#include <glib.h>
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestStruct
+{
+    int64_t x;
+    int64_t y;
+} TestStruct;
+
+typedef struct TestStructList
+{
+    TestStruct *value;
+    struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), errp);
+    visit_type_int(v, &(*obj)->x, "x", errp);
+    visit_type_int(v, &(*obj)->y, "y", errp);
+    visit_end_struct(v, errp);
+}
+
+static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
+{
+    GenericList *i, **head = (GenericList **)obj;
+
+    visit_start_list(m, name, errp);
+
+    for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
+        TestStructList *native_i = (TestStructList *)i;
+        visit_type_TestStruct(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+
+/* test core visitor methods */
+static void test_visitor_core(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    TestStruct ts = { 42, 82 };
+    TestStruct *pts = &ts;
+    TestStructList *lts = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QList *qlist;
+    QDict *qdict;
+    QString *str;
+    int64_t value = 0;
+
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+
+    obj = qmp_output_get_qobject(mo);
+
+    str = qobject_to_json(obj);
+
+    printf("%s\n", qstring_get_str(str));
+
+    QDECREF(str);
+
+    obj = QOBJECT(qint_from_int(0x42));
+
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_int(v, &value, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(value == 0x42);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("{'x': 42, 'y': 84}");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    pts = NULL;
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(pts != NULL);
+    g_assert(pts->x == 42);
+    g_assert(pts->y == 84);
+
+    qobject_decref(obj);
+    g_free(pts);
+
+    /* test list input visitor */
+    obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(lts != NULL);
+    g_assert(lts->value->x == 42);
+    g_assert(lts->value->y == 84);
+
+    g_assert(lts->next != NULL);
+    g_assert(lts->next->value->x == 12);
+    g_assert(lts->next->value->y == 24);
+    g_assert(lts->next->next == NULL);
+
+    qobject_decref(obj);
+
+    /* test list output visitor */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj)));
+
+    qlist = qobject_to_qlist(obj);
+    assert(qlist);
+    obj = qlist_pop(qlist);
+    qdict = qobject_to_qdict(obj);
+    assert(qdict);
+    assert(qdict_get_int(qdict, "x") == 42);
+    assert(qdict_get_int(qdict, "y") == 84);
+    qobject_decref(obj);
+
+    obj = qlist_pop(qlist);
+    qdict = qobject_to_qdict(obj);
+    assert(qdict);
+    assert(qdict_get_int(qdict, "x") == 12);
+    assert(qdict_get_int(qdict, "y") == 24);
+    qobject_decref(obj);
+
+    qmp_output_visitor_cleanup(mo);
+    QDECREF(qlist);
+}
+
+/* test deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    UserDefOne ud1;
+    UserDefOne *ud1_p = &ud1, *ud1c_p = NULL;
+    UserDefTwo ud2;
+    UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    ud1.integer = 42;
+    ud1.string = strdup("fourty two");
+
+    /* sanity check */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefOne(v, &ud1_p, "o_O", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    qobject_decref(obj);
+
+    ud2.string = strdup("fourty three");
+    ud2.dict.string = strdup("fourty four");
+    ud2.dict.dict.userdef = ud1_p;
+    ud2.dict.dict.string = strdup("fourty five");
+    ud2.dict.has_dict2 = true;
+    ud2.dict.dict2.userdef = ud1_p;
+    ud2.dict.dict2.string = strdup("fourty six");
+
+    /* c type -> qobject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefTwo(v, &ud2_p, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* qobject -> c type, should match original struct */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_UserDefTwo(v, &ud2c_p, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(!g_strcmp0(ud2c_p->string, ud2.string));
+    g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict2.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string));
+    g_free(ud1.string);
+    g_free(ud2.string);
+    g_free(ud2.dict.string);
+    g_free(ud2.dict.dict.string);
+    g_free(ud2.dict.dict2.string);
+
+    qapi_free_UserDefTwo(ud2c_p);
+
+    qobject_decref(obj);
+}
+
+/* test enum values */
+static void test_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    EnumOne enum1 = ENUM_ONE_VALUE2, enum1_cpy = ENUM_ONE_VALUE1;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_EnumOne(v, &enum1, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+    g_assert(g_strcmp0(qstring_get_str(qobject_to_qstring(obj)), "value2") == 0);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_EnumOne(v, &enum1_cpy, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_debug("enum1_cpy, enum1: %d, %d", enum1_cpy, enum1);
+    g_assert(enum1_cpy == enum1);
+
+    qobject_decref(obj);
+}
+
+/* test enum values nested in schema-defined structs */
+static void test_nested_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    nested_enums = g_malloc0(sizeof(NestedEnumsOne));
+    nested_enums->enum1 = ENUM_ONE_VALUE1;
+    nested_enums->enum2 = ENUM_ONE_VALUE2;
+    nested_enums->enum3 = ENUM_ONE_VALUE3;
+    nested_enums->enum4 = ENUM_ONE_VALUE3;
+    nested_enums->has_enum2 = false;
+    nested_enums->has_enum4 = true;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_assert(nested_enums_cpy);
+    g_assert(nested_enums_cpy->enum1 == nested_enums->enum1);
+    g_assert(nested_enums_cpy->enum3 == nested_enums->enum3);
+    g_assert(nested_enums_cpy->enum4 == nested_enums->enum4);
+    g_assert(nested_enums_cpy->has_enum2 == false);
+    g_assert(nested_enums_cpy->has_enum4 == true);
+
+    qmp_output_visitor_cleanup(mo);
+    qmp_input_visitor_cleanup(mi);
+    qapi_free_NestedEnumsOne(nested_enums);
+    qapi_free_NestedEnumsOne(nested_enums_cpy);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/0.15/visitor_core", test_visitor_core);
+    g_test_add_func("/0.15/nested_structs", test_nested_structs);
+    g_test_add_func("/0.15/enums", test_enums);
+    g_test_add_func("/0.15/nested_enums", test_nested_enums);
+
+    g_test_run();
+
+    return 0;
+}
index 9ded4b73494e69defdc44c8d599117ed391fdb5f..430e0c177657ea07486695c8461891d36ad41494 100644 (file)
@@ -142,6 +142,10 @@ hello-mipsel: hello-mips.c
 test-cris:
        $(MAKE) -C cris check
 
+# testsuite for the LM32 port.
+test-lm32:
+       $(MAKE) -C lm32 check
+
 clean:
        rm -f *~ *.o test-i386.out test-i386.ref \
            test-x86_64.log test-x86_64.ref qruncom $(TESTS)
diff --git a/tests/cris/.gdbinit b/tests/cris/.gdbinit
new file mode 100644 (file)
index 0000000..5e8c1d3
--- /dev/null
@@ -0,0 +1,11 @@
+b main
+b _fail
+b exit
+display /i $pc
+display /x $srp
+display /x $r0
+display /x $r1
+display /x $r2
+display /x $r3
+display /x $r4
+display /t $ccs
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 9986e299b21b1de521a3f9bcdf65c59194033ecc..2e4a746ac3b94311a5717528a8750019c2f37b6e 100644 (file)
@@ -426,7 +426,9 @@ void test_clone(void)
                            CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
 
     while (waitpid(pid1, &status1, 0) != pid1);
+    free(stack1);
     while (waitpid(pid2, &status2, 0) != pid2);
+    free(stack2);
     if (thread1_res != 5 ||
         thread2_res != 6)
         error("clone");
diff --git a/tests/lm32/Makefile b/tests/lm32/Makefile
new file mode 100644 (file)
index 0000000..03a1abb
--- /dev/null
@@ -0,0 +1,102 @@
+-include ../../config-host.mak
+
+CROSS=lm32-elf-
+
+SIM = qemu-system-lm32
+SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)as
+AS      = $(CC) -x assembler
+SIZE    = $(CROSS)size
+LD      = $(CC)
+OBJCOPY = $(CROSS)objcopy
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o
+TESTCASES += test_add.tst
+TESTCASES += test_addi.tst
+TESTCASES += test_and.tst
+TESTCASES += test_andhi.tst
+TESTCASES += test_andi.tst
+TESTCASES += test_b.tst
+TESTCASES += test_be.tst
+TESTCASES += test_bg.tst
+TESTCASES += test_bge.tst
+TESTCASES += test_bgeu.tst
+TESTCASES += test_bgu.tst
+TESTCASES += test_bi.tst
+TESTCASES += test_bne.tst
+TESTCASES += test_break.tst
+TESTCASES += test_bret.tst
+TESTCASES += test_call.tst
+TESTCASES += test_calli.tst
+TESTCASES += test_cmpe.tst
+TESTCASES += test_cmpei.tst
+TESTCASES += test_cmpg.tst
+TESTCASES += test_cmpgi.tst
+TESTCASES += test_cmpge.tst
+TESTCASES += test_cmpgei.tst
+TESTCASES += test_cmpgeu.tst
+TESTCASES += test_cmpgeui.tst
+TESTCASES += test_cmpgu.tst
+TESTCASES += test_cmpgui.tst
+TESTCASES += test_cmpne.tst
+TESTCASES += test_cmpnei.tst
+TESTCASES += test_divu.tst
+TESTCASES += test_eret.tst
+TESTCASES += test_lb.tst
+TESTCASES += test_lbu.tst
+TESTCASES += test_lh.tst
+TESTCASES += test_lhu.tst
+TESTCASES += test_lw.tst
+TESTCASES += test_modu.tst
+TESTCASES += test_mul.tst
+TESTCASES += test_muli.tst
+TESTCASES += test_nor.tst
+TESTCASES += test_nori.tst
+TESTCASES += test_or.tst
+TESTCASES += test_ori.tst
+TESTCASES += test_orhi.tst
+#TESTCASES += test_rcsr.tst
+TESTCASES += test_ret.tst
+TESTCASES += test_sb.tst
+TESTCASES += test_scall.tst
+TESTCASES += test_sextb.tst
+TESTCASES += test_sexth.tst
+TESTCASES += test_sh.tst
+TESTCASES += test_sl.tst
+TESTCASES += test_sli.tst
+TESTCASES += test_sr.tst
+TESTCASES += test_sri.tst
+TESTCASES += test_sru.tst
+TESTCASES += test_srui.tst
+TESTCASES += test_sub.tst
+TESTCASES += test_sw.tst
+#TESTCASES += test_wcsr.tst
+TESTCASES += test_xnor.tst
+TESTCASES += test_xnori.tst
+TESTCASES += test_xor.tst
+TESTCASES += test_xori.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/lm32/%.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/lm32/%.S
+       $(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT)
+       $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(CRT) $(TESTCASES)
+
+check: $(CRT) $(SYS) $(TESTCASES)
+       @for case in $(TESTCASES); do \
+               $(SIM) $(SIMFLAGS) ./$$case; \
+       done
+
+clean:
+       $(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/lm32/crt.S b/tests/lm32/crt.S
new file mode 100644 (file)
index 0000000..5f9cfd9
--- /dev/null
@@ -0,0 +1,84 @@
+.text
+.global _start
+
+_start:
+_reset_handler:
+       xor r0, r0, r0
+       mvhi r1, hi(_start)
+       ori r1, r1, lo(_start)
+       wcsr eba, r1
+       wcsr deba, r1
+       bi _main
+       nop
+       nop
+
+_breakpoint_handler:
+       ori r25, r25, 1
+       addi ra, ba, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_instruction_bus_error_handler:
+       ori r25, r25, 2
+       addi ra, ea, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_watchpoint_handler:
+       ori r25, r25, 4
+       addi ra, ba, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_data_bus_error_handler:
+       ori r25, r25, 8
+       addi ra, ea, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_divide_by_zero_handler:
+       ori r25, r25, 16
+       addi ra, ea, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_interrupt_handler:
+       ori r25, r25, 32
+       addi ra, ea, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
+_system_call_handler:
+       ori r25, r25, 64
+       addi ra, ea, 4
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+
diff --git a/tests/lm32/linker.ld b/tests/lm32/linker.ld
new file mode 100644 (file)
index 0000000..52d43a4
--- /dev/null
@@ -0,0 +1,55 @@
+OUTPUT_FORMAT("elf32-lm32")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+       ram : ORIGIN = 0x08000000, LENGTH = 0x04000000  /* 64M */
+}
+
+SECTIONS
+{
+       .text :
+       {
+               _ftext = .;
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+               _etext = .;
+       } > ram
+
+       .rodata :
+       {
+               . = ALIGN(4);
+               _frodata = .;
+               *(.rodata .rodata.* .gnu.linkonce.r.*)
+               *(.rodata1)
+               _erodata = .;
+       } > ram
+
+       .data :
+       {
+               . = ALIGN(4);
+               _fdata = .;
+               *(.data .data.* .gnu.linkonce.d.*)
+               *(.data1)
+               _gp = ALIGN(16);
+               *(.sdata .sdata.* .gnu.linkonce.s.*)
+               _edata = .;
+       } > ram
+
+       .bss :
+       {
+               . = ALIGN(4);
+               _fbss = .;
+               *(.dynsbss)
+               *(.sbss .sbss.* .gnu.linkonce.sb.*)
+               *(.scommon)
+               *(.dynbss)
+               *(.bss .bss.* .gnu.linkonce.b.*)
+               *(COMMON)
+               _ebss = .;
+               _end = .;
+       } > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
+
diff --git a/tests/lm32/macros.inc b/tests/lm32/macros.inc
new file mode 100644 (file)
index 0000000..367c7c5
--- /dev/null
@@ -0,0 +1,79 @@
+
+.macro test_name name
+       .data
+tn_\name:
+       .asciz "\name"
+       .text
+       mvhi r13, hi(tn_\name)
+       ori r13, r13, lo(tn_\name)
+       sw (r12+8), r13
+.endm
+
+.macro load reg val
+       mvhi \reg, hi(\val)
+       ori \reg, \reg, lo(\val)
+.endm
+
+.macro tc_pass
+       mvi r13, 0
+       sw (r12+4), r13
+.endm
+
+.macro tc_fail
+       mvi r13, 1
+       sw (r12+4), r13
+.endm
+
+.macro check_r3 val
+       mvhi r13, hi(\val)
+       ori r13, r13, lo(\val)
+       be r3, r13, 1f
+       tc_fail
+       bi 2f
+1:
+       tc_pass
+2:
+.endm
+
+.macro check_mem adr val
+       mvhi r13, hi(\adr)
+       ori r13, r13, lo(\adr)
+       mvhi r14, hi(\val)
+       ori r14, r14, lo(\val)
+       lw r13, (r13+0)
+       be r13, r14, 1f
+       tc_fail
+       bi 2f
+1:
+       tc_pass
+2:
+.endm
+
+.macro check_excp excp
+       andi r13, r25, \excp
+       bne r13, r0, 1f
+       tc_fail
+       bi 2f
+1:
+       tc_pass
+2:
+.endm
+
+.macro start
+       .global _main
+       .text
+_main:
+       mvhi r12, hi(0xffff0000)      # base address of test block
+       ori r12, r12, lo(0xffff0000)
+.endm
+
+.macro end
+       sw (r12+0), r0
+1:
+       bi 1b
+.endm
+
+# base +
+#  0  ctrl
+#  4  pass/fail
+#  8  ptr to test name
diff --git a/tests/lm32/test_add.S b/tests/lm32/test_add.S
new file mode 100644 (file)
index 0000000..030ad19
--- /dev/null
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name ADD_1
+mvi r1, 0
+mvi r2, 0
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_2
+mvi r1, 0
+mvi r2, 1
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_3
+mvi r1, 1
+mvi r2, 0
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_4
+mvi r1, 1
+mvi r2, -1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_5
+mvi r1, -1
+mvi r2, 1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_6
+mvi r1, -1
+mvi r2, 0
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_7
+mvi r1, 0
+mvi r2, -1
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_8
+mvi r3, 2
+add r3, r3, r3
+check_r3 4
+
+test_name ADD_9
+mvi r1, 4
+mvi r3, 2
+add r3, r1, r3
+check_r3 6
+
+test_name ADD_10
+mvi r1, 4
+mvi r3, 2
+add r3, r3, r1
+check_r3 6
+
+test_name ADD_11
+mvi r1, 4
+add r3, r1, r1
+check_r3 8
+
+test_name ADD_12
+load r1 0x12345678
+load r2 0xabcdef97
+add r3, r1, r2
+check_r3 0xbe02460f
+
+end
diff --git a/tests/lm32/test_addi.S b/tests/lm32/test_addi.S
new file mode 100644 (file)
index 0000000..68e766d
--- /dev/null
@@ -0,0 +1,56 @@
+.include "macros.inc"
+
+start
+
+test_name ADDI_1
+mvi r1, 0
+addi r3, r1, 0
+check_r3 0
+
+test_name ADDI_2
+mvi r1, 0
+addi r3, r1, 1
+check_r3 1
+
+test_name ADDI_3
+mvi r1, 1
+addi r3, r1, 0
+check_r3 1
+
+test_name ADDI_4
+mvi r1, 1
+addi r3, r1, -1
+check_r3 0
+
+test_name ADDI_5
+mvi r1, -1
+addi r3, r1, 1
+check_r3 0
+
+test_name ADDI_6
+mvi r1, -1
+addi r3, r1, 0
+check_r3 -1
+
+test_name ADDI_7
+mvi r1, 0
+addi r3, r1, -1
+check_r3 -1
+
+test_name ADDI_8
+mvi r3, 4
+addi r3, r3, 4
+check_r3 8
+
+test_name ADDI_9
+mvi r3, 4
+addi r3, r3, -4
+check_r3 0
+
+test_name ADDI_10
+mvi r3, 4
+addi r3, r3, -5
+check_r3 -1
+
+end
+
diff --git a/tests/lm32/test_and.S b/tests/lm32/test_and.S
new file mode 100644 (file)
index 0000000..80962ce
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name AND_1
+mvi r1, 0
+mvi r2, 0
+and r3, r1, r2
+check_r3 0
+
+test_name AND_2
+mvi r1, 0
+mvi r2, 1
+and r3, r1, r2
+check_r3 0
+
+test_name AND_3
+mvi r1, 1
+mvi r2, 1
+and r3, r1, r2
+check_r3 1
+
+test_name AND_4
+mvi r3, 7
+and r3, r3, r3
+check_r3 7
+
+test_name AND_5
+mvi r1, 7
+and r3, r1, r1
+check_r3 7
+
+test_name AND_6
+mvi r1, 7
+mvi r3, 0
+and r3, r1, r3
+check_r3 0
+
+test_name AND_7
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+and r3, r1, r2
+check_r3 0
+
+end
diff --git a/tests/lm32/test_andhi.S b/tests/lm32/test_andhi.S
new file mode 100644 (file)
index 0000000..4f73af5
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDHI_1
+mvi r1, 0
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_2
+mvi r1, 1
+andhi r3, r1, 1
+check_r3 0
+
+test_name ANDHI_3
+load r1 0x000f0000
+andhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ANDHI_4
+load r1 0xffffffff
+andhi r3, r1, 0xffff
+check_r3 0xffff0000
+
+test_name ANDHI_5
+load r1 0xffffffff
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_6
+load r3 0x55aaffff
+andhi r3, r3, 0xaaaa
+check_r3 0x00aa0000
+
+end
diff --git a/tests/lm32/test_andi.S b/tests/lm32/test_andi.S
new file mode 100644 (file)
index 0000000..da1b0a3
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDI_1
+mvi r1, 0
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_2
+mvi r1, 1
+andi r3, r1, 1
+check_r3 1
+
+test_name ANDI_3
+load r1 0x000f0000
+andi r3, r1, 1
+check_r3 0
+
+test_name ANDI_4
+load r1 0xffffffff
+andi r3, r1, 0xffff
+check_r3 0xffff
+
+test_name ANDI_5
+load r1 0xffffffff
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_6
+load r3 0xffff55aa
+andi r3, r3, 0xaaaa
+check_r3 0x000000aa
+
+end
diff --git a/tests/lm32/test_b.S b/tests/lm32/test_b.S
new file mode 100644 (file)
index 0000000..98172d8
--- /dev/null
@@ -0,0 +1,13 @@
+.include "macros.inc"
+
+start
+
+test_name B_1
+load r1 jump
+b r1
+tc_fail
+end
+
+jump:
+tc_pass
+end
diff --git a/tests/lm32/test_be.S b/tests/lm32/test_be.S
new file mode 100644 (file)
index 0000000..635caba
--- /dev/null
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BE_1
+mvi r1, 0
+mvi r2, 0
+be r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BE_2
+mvi r1, 1
+mvi r2, 0
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BE_3
+mvi r1, 0
+mvi r2, 1
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BE_4
+mvi r1, 1
+mvi r2, 1
+be r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bg.S b/tests/lm32/test_bg.S
new file mode 100644 (file)
index 0000000..81823c2
--- /dev/null
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BG_1
+mvi r1, 0
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_2
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_3
+mvi r1, 0
+mvi r2, 1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_4
+mvi r1, 0
+mvi r2, -1
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_5
+mvi r1, -1
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_6
+mvi r1, -1
+mvi r2, -1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BG_7
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bge.S b/tests/lm32/test_bge.S
new file mode 100644 (file)
index 0000000..6684d15
--- /dev/null
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGE_1
+mvi r1, 0
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_2
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_3
+mvi r1, 0
+mvi r2, 1
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_4
+mvi r1, 0
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_5
+mvi r1, -1
+mvi r2, 0
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_6
+mvi r1, -1
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGE_7
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bgeu.S b/tests/lm32/test_bgeu.S
new file mode 100644 (file)
index 0000000..be44030
--- /dev/null
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGEU_1
+mvi r1, 0
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_2
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_3
+mvi r1, 0
+mvi r2, 1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_4
+mvi r1, 0
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_5
+mvi r1, -1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_6
+mvi r1, -1
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGEU_7
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bgu.S b/tests/lm32/test_bgu.S
new file mode 100644 (file)
index 0000000..8cc695b
--- /dev/null
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGU_1
+mvi r1, 0
+mvi r2, 0
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_2
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_3
+mvi r1, 0
+mvi r2, 1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_4
+mvi r1, 0
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_5
+mvi r1, -1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_6
+mvi r1, -1
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGU_7
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bi.S b/tests/lm32/test_bi.S
new file mode 100644 (file)
index 0000000..a1fbd6f
--- /dev/null
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+start
+
+test_name BI_1
+bi jump
+tc_fail
+end
+
+jump_back:
+tc_pass
+end
+
+jump:
+tc_pass
+
+test_name BI_2
+bi jump_back
+tc_fail
+
+end
+
+
diff --git a/tests/lm32/test_bne.S b/tests/lm32/test_bne.S
new file mode 100644 (file)
index 0000000..871a006
--- /dev/null
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BNE_1
+mvi r1, 0
+mvi r2, 0
+bne r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BNE_2
+mvi r1, 1
+mvi r2, 0
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BNE_3
+mvi r1, 0
+mvi r2, 1
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_fail
+bi 3f
+2:
+test_name BNE_4
+mvi r1, 1
+mvi r2, 1
+bne r1, r2, 1b
+tc_pass
+3:
+
+end
+
diff --git a/tests/lm32/test_break.S b/tests/lm32/test_break.S
new file mode 100644 (file)
index 0000000..0384fc6
--- /dev/null
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name BREAK_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+break
+check_excp 1
+
+test_name BREAK_2
+mv r3, ba
+check_r3 insn
+
+test_name BREAK_3
+rcsr r3, IE
+check_r3 4
+
+end
diff --git a/tests/lm32/test_bret.S b/tests/lm32/test_bret.S
new file mode 100644 (file)
index 0000000..645210e
--- /dev/null
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name BRET_1
+mvi r1, 4
+wcsr IE, r1
+load ba mark
+bret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name BRET_2
+rcsr r3, IE
+check_r3 5
+
+test_name BRET_3
+mvi r1, 0
+wcsr IE, r1
+load ba mark2
+bret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name BRET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/tests/lm32/test_call.S b/tests/lm32/test_call.S
new file mode 100644 (file)
index 0000000..1b91a5f
--- /dev/null
@@ -0,0 +1,16 @@
+.include "macros.inc"
+
+start
+
+test_name CALL_1
+load r1 mark
+call r1
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/tests/lm32/test_calli.S b/tests/lm32/test_calli.S
new file mode 100644 (file)
index 0000000..1d87ae6
--- /dev/null
@@ -0,0 +1,15 @@
+.include "macros.inc"
+
+start
+
+test_name CALLI_1
+calli mark
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/tests/lm32/test_cmpe.S b/tests/lm32/test_cmpe.S
new file mode 100644 (file)
index 0000000..60a8855
--- /dev/null
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPE_1
+mvi r1, 0
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 1
+
+test_name CMPE_2
+mvi r1, 0
+mvi r2, 1
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_3
+mvi r1, 1
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_4
+mvi r3, 0
+mvi r2, 1
+cmpe r3, r3, r2
+check_r3 0
+
+test_name CMPE_5
+mvi r3, 0
+mvi r2, 0
+cmpe r3, r3, r2
+check_r3 1
+
+test_name CMPE_6
+mvi r3, 0
+cmpe r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpei.S b/tests/lm32/test_cmpei.S
new file mode 100644 (file)
index 0000000..c3d3566
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPEI_1
+mvi r1, 0
+cmpei r3, r1, 0
+check_r3 1
+
+test_name CMPEI_2
+mvi r1, 0
+cmpei r3, r1, 1
+check_r3 0
+
+test_name CMPEI_3
+mvi r1, 1
+cmpei r3, r1, 0
+check_r3 0
+
+test_name CMPEI_4
+load r1 0xffffffff
+cmpei r3, r1, -1
+check_r3 1
+
+test_name CMPEI_5
+mvi r3, 0
+cmpei r3, r3, 0
+check_r3 1
+
+test_name CMPEI_6
+mvi r3, 0
+cmpei r3, r3, 1
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpg.S b/tests/lm32/test_cmpg.S
new file mode 100644 (file)
index 0000000..0124078
--- /dev/null
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPG_1
+mvi r1, 0
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_2
+mvi r1, 0
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_3
+mvi r1, 1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_4
+mvi r1, 1
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_5
+mvi r1, 0
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_6
+mvi r1, -1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_7
+mvi r1, -1
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_8
+mvi r3, 0
+mvi r2, 1
+cmpg r3, r3, r2
+check_r3 0
+
+test_name CMPG_9
+mvi r3, 1
+mvi r2, 0
+cmpg r3, r3, r2
+check_r3 1
+
+test_name CMPG_10
+mvi r3, 0
+cmpg r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpge.S b/tests/lm32/test_cmpge.S
new file mode 100644 (file)
index 0000000..84620a0
--- /dev/null
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGE_1
+mvi r1, 0
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_2
+mvi r1, 0
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_3
+mvi r1, 1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_4
+mvi r1, 1
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_5
+mvi r1, 0
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_6
+mvi r1, -1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_7
+mvi r1, -1
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_8
+mvi r3, 0
+mvi r2, 1
+cmpge r3, r3, r2
+check_r3 0
+
+test_name CMPGE_9
+mvi r3, 1
+mvi r2, 0
+cmpge r3, r3, r2
+check_r3 1
+
+test_name CMPGE_10
+mvi r3, 0
+cmpge r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgei.S b/tests/lm32/test_cmpgei.S
new file mode 100644 (file)
index 0000000..6a8870f
--- /dev/null
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEI_1
+mvi r1, 0
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_2
+mvi r1, 0
+cmpgei r3, r1, 1
+check_r3 0
+
+test_name CMPGEI_3
+mvi r1, 1
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_4
+mvi r1, 1
+cmpgei r3, r1, 1
+check_r3 1
+
+test_name CMPGEI_5
+mvi r1, 0
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_6
+mvi r1, -1
+cmpgei r3, r1, 0
+check_r3 0
+
+test_name CMPGEI_7
+mvi r1, -1
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_8
+mvi r3, 0
+cmpgei r3, r3, 1
+check_r3 0
+
+test_name CMPGEI_9
+mvi r3, 1
+cmpgei r3, r3, 0
+check_r3 1
+
+test_name CMPGEI_10
+mvi r3, 0
+cmpgei r3, r3, 0
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgeu.S b/tests/lm32/test_cmpgeu.S
new file mode 100644 (file)
index 0000000..2110ccb
--- /dev/null
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEU_1
+mvi r1, 0
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_2
+mvi r1, 0
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_3
+mvi r1, 1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_4
+mvi r1, 1
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_5
+mvi r1, 0
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_6
+mvi r1, -1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_7
+mvi r1, -1
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_8
+mvi r3, 0
+mvi r2, 1
+cmpgeu r3, r3, r2
+check_r3 0
+
+test_name CMPGEU_9
+mvi r3, 1
+mvi r2, 0
+cmpgeu r3, r3, r2
+check_r3 1
+
+test_name CMPGEU_10
+mvi r3, 0
+cmpgeu r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgeui.S b/tests/lm32/test_cmpgeui.S
new file mode 100644 (file)
index 0000000..b9d1755
--- /dev/null
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEUI_1
+mvi r1, 0
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_2
+mvi r1, 0
+cmpgeui r3, r1, 1
+check_r3 0
+
+test_name CMPGEUI_3
+mvi r1, 1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_4
+mvi r1, 1
+cmpgeui r3, r1, 1
+check_r3 1
+
+test_name CMPGEUI_5
+mvi r1, 0
+cmpgeui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGEUI_6
+mvi r1, -1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_7
+mvi r1, -1
+cmpgeui r3, r1, 0xffff
+check_r3 1
+
+test_name CMPGEUI_8
+mvi r3, 0
+cmpgeui r3, r3, 1
+check_r3 0
+
+test_name CMPGEUI_9
+mvi r3, 1
+cmpgeui r3, r3, 0
+check_r3 1
+
+test_name CMPGEUI_10
+mvi r3, 0
+cmpgeui r3, r3, 0
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgi.S b/tests/lm32/test_cmpgi.S
new file mode 100644 (file)
index 0000000..1f622d2
--- /dev/null
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGI_1
+mvi r1, 0
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_2
+mvi r1, 0
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_3
+mvi r1, 1
+cmpgi r3, r1, 0
+check_r3 1
+
+test_name CMPGI_4
+mvi r1, 1
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_5
+mvi r1, 0
+cmpgi r3, r1, -1
+check_r3 1
+
+test_name CMPGI_6
+mvi r1, -1
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_7
+mvi r1, -1
+cmpgi r3, r1, -1
+check_r3 0
+
+test_name CMPGI_8
+mvi r3, 0
+cmpgi r3, r3, 1
+check_r3 0
+
+test_name CMPGI_9
+mvi r3, 1
+cmpgi r3, r3, 0
+check_r3 1
+
+test_name CMPGI_10
+mvi r3, 0
+cmpgi r3, r3, 0
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpgu.S b/tests/lm32/test_cmpgu.S
new file mode 100644 (file)
index 0000000..dd46547
--- /dev/null
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGU_1
+mvi r1, 0
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_2
+mvi r1, 0
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_3
+mvi r1, 1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_4
+mvi r1, 1
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_5
+mvi r1, 0
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_6
+mvi r1, -1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_7
+mvi r1, -1
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_8
+mvi r3, 0
+mvi r2, 1
+cmpgu r3, r3, r2
+check_r3 0
+
+test_name CMPGU_9
+mvi r3, 1
+mvi r2, 0
+cmpgu r3, r3, r2
+check_r3 1
+
+test_name CMPGU_10
+mvi r3, 0
+cmpgu r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpgui.S b/tests/lm32/test_cmpgui.S
new file mode 100644 (file)
index 0000000..759bb64
--- /dev/null
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGUI_1
+mvi r1, 0
+cmpgui r3, r1, 0
+check_r3 0
+
+test_name CMPGUI_2
+mvi r1, 0
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_3
+mvi r1, 1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_4
+mvi r1, 1
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_5
+mvi r1, 0
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_6
+mvi r1, -1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_7
+mvi r1, -1
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_8
+mvi r3, 0
+cmpgui r3, r3, 1
+check_r3 0
+
+test_name CMPGUI_9
+mvi r3, 1
+cmpgui r3, r3, 0
+check_r3 1
+
+test_name CMPGUI_10
+mvi r3, 0
+cmpgui r3, r3, 0
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpne.S b/tests/lm32/test_cmpne.S
new file mode 100644 (file)
index 0000000..0f10781
--- /dev/null
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNE_1
+mvi r1, 0
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 0
+
+test_name CMPNE_2
+mvi r1, 0
+mvi r2, 1
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_3
+mvi r1, 1
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_4
+mvi r3, 0
+mvi r2, 1
+cmpne r3, r3, r2
+check_r3 1
+
+test_name CMPNE_5
+mvi r3, 0
+mvi r2, 0
+cmpne r3, r3, r2
+check_r3 0
+
+test_name CMPNE_6
+mvi r3, 0
+cmpne r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpnei.S b/tests/lm32/test_cmpnei.S
new file mode 100644 (file)
index 0000000..060dd9d
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNEI_1
+mvi r1, 0
+cmpnei r3, r1, 0
+check_r3 0
+
+test_name CMPNEI_2
+mvi r1, 0
+cmpnei r3, r1, 1
+check_r3 1
+
+test_name CMPNEI_3
+mvi r1, 1
+cmpnei r3, r1, 0
+check_r3 1
+
+test_name CMPNEI_4
+load r1 0xffffffff
+cmpnei r3, r1, -1
+check_r3 0
+
+test_name CMPNEI_5
+mvi r3, 0
+cmpnei r3, r3, 0
+check_r3 0
+
+test_name CMPNEI_6
+mvi r3, 0
+cmpnei r3, r3, 1
+check_r3 1
+
+end
diff --git a/tests/lm32/test_divu.S b/tests/lm32/test_divu.S
new file mode 100644 (file)
index 0000000..f381d09
--- /dev/null
@@ -0,0 +1,29 @@
+.include "macros.inc"
+
+start
+
+test_name DIVU_1
+mvi r1, 0
+mvi r2, 1
+divu r3, r1, r2
+check_r3 0
+
+test_name DIVU_2
+mvi r1, 1
+mvi r2, 1
+divu r3, r1, r2
+check_r3 1
+
+test_name DIVU_3
+mvi r1, 0
+mvi r2, 0
+divu r3, r1, r2
+check_excp 16
+
+test_name DIVU_4
+load r1 0xabcdef12
+load r2 0x12345
+divu r3, r1, r2
+check_r3 0x9700
+
+end
diff --git a/tests/lm32/test_eret.S b/tests/lm32/test_eret.S
new file mode 100644 (file)
index 0000000..6830bd1
--- /dev/null
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name ERET_1
+mvi r1, 2
+wcsr IE, r1
+load ea mark
+eret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name ERET_2
+rcsr r3, IE
+check_r3 3
+
+test_name ERET_3
+mvi r1, 0
+wcsr IE, r1
+load ea mark2
+eret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name ERET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/tests/lm32/test_lb.S b/tests/lm32/test_lb.S
new file mode 100644 (file)
index 0000000..f84d21e
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LB_1
+load r1 data
+lb r3, (r1+0)
+check_r3 0x7e
+
+test_name LB_2
+lb r3, (r1+1)
+check_r3 0x7f
+
+test_name LB_3
+lb r3, (r1+-1)
+check_r3 0x7d
+
+test_name LB_4
+load r1 data_msb
+lb r3, (r1+0)
+check_r3 0xfffffffe
+
+test_name LB_5
+lb r3, (r1+1)
+check_r3 0xffffffff
+
+test_name LB_6
+lb r3, (r1+-1)
+check_r3 0xfffffffd
+
+test_name LB_7
+load r3 data
+lb r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+       .align 4
+       .byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+       .byte 0x7e, 0x7f, 0x70, 0x71
+       .byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+       .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lbu.S b/tests/lm32/test_lbu.S
new file mode 100644 (file)
index 0000000..4c1786a
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LBU_1
+load r1 data
+lbu r3, (r1+0)
+check_r3 0x7e
+
+test_name LBU_2
+lbu r3, (r1+1)
+check_r3 0x7f
+
+test_name LBU_3
+lbu r3, (r1+-1)
+check_r3 0x7d
+
+test_name LBU_4
+load r1 data_msb
+lbu r3, (r1+0)
+check_r3 0xfe
+
+test_name LBU_5
+lbu r3, (r1+1)
+check_r3 0xff
+
+test_name LBU_6
+lbu r3, (r1+-1)
+check_r3 0xfd
+
+test_name LBU_7
+load r3 data
+lbu r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+       .align 4
+       .byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+       .byte 0x7e, 0x7f, 0x70, 0x71
+       .byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+       .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lh.S b/tests/lm32/test_lh.S
new file mode 100644 (file)
index 0000000..e57d9e3
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LH_1
+load r1 data
+lh r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LH_2
+lh r3, (r1+2)
+check_r3 0x7071
+
+test_name LH_3
+lh r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LH_4
+load r1 data_msb
+lh r3, (r1+0)
+check_r3 0xfffffeff
+
+test_name LH_5
+lh r3, (r1+2)
+check_r3 0xfffff0f1
+
+test_name LH_6
+lh r3, (r1+-2)
+check_r3 0xfffffcfd
+
+test_name LH_7
+load r3 data
+lh r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+       .align 4
+       .byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+       .byte 0x7e, 0x7f, 0x70, 0x71
+       .byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+       .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lhu.S b/tests/lm32/test_lhu.S
new file mode 100644 (file)
index 0000000..e648775
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LHU_1
+load r1 data
+lhu r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LHU_2
+lhu r3, (r1+2)
+check_r3 0x7071
+
+test_name LHU_3
+lhu r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LHU_4
+load r1 data_msb
+lhu r3, (r1+0)
+check_r3 0xfeff
+
+test_name LHU_5
+lhu r3, (r1+2)
+check_r3 0xf0f1
+
+test_name LHU_6
+lhu r3, (r1+-2)
+check_r3 0xfcfd
+
+test_name LHU_7
+load r3 data
+lhu r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+       .align 4
+       .byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+       .byte 0x7e, 0x7f, 0x70, 0x71
+       .byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+       .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lw.S b/tests/lm32/test_lw.S
new file mode 100644 (file)
index 0000000..f8c919d
--- /dev/null
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name LW_1
+load r1 data
+lw r3, (r1+0)
+check_r3 0x7e7f7071
+
+test_name LW_2
+lw r3, (r1+4)
+check_r3 0x72737475
+
+test_name LW_3
+lw r3, (r1+-4)
+check_r3 0x7a7b7c7d
+
+test_name LW_4
+load r3 data
+lw r3, (r3+0)
+check_r3 0x7e7f7071
+
+end
+
+.data
+       .align 4
+       .byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+       .byte 0x7e, 0x7f, 0x70, 0x71
+       .byte 0x72, 0x73, 0x74, 0x75
diff --git a/tests/lm32/test_modu.S b/tests/lm32/test_modu.S
new file mode 100644 (file)
index 0000000..4248690
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name MODU_1
+mvi r1, 0
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_2
+mvi r1, 1
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_3
+mvi r1, 3
+mvi r2, 2
+modu r3, r1, r2
+check_r3 1
+
+test_name MODU_4
+mvi r1, 0
+mvi r2, 0
+modu r3, r1, r2
+check_excp 16
+
+test_name MODU_5
+load r1 0xabcdef12
+load r2 0x12345
+modu r3, r1, r2
+check_r3 0x3c12
+
+end
diff --git a/tests/lm32/test_mul.S b/tests/lm32/test_mul.S
new file mode 100644 (file)
index 0000000..e9b937e
--- /dev/null
@@ -0,0 +1,70 @@
+.include "macros.inc"
+
+start
+
+test_name MUL_1
+mvi r1, 0
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_2
+mvi r1, 1
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_3
+mvi r1, 0
+mvi r2, 1
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_4
+mvi r1, 1
+mvi r2, 1
+mul r3, r1, r2
+check_r3 1
+
+test_name MUL_5
+mvi r1, 2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 -2
+
+test_name MUL_6
+mvi r1, -2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 2
+
+test_name MUL_7
+mvi r1, 0x1234
+mvi r2, 0x789
+mul r3, r1, r2
+check_r3 0x8929d4
+
+test_name MUL_8
+mvi r3, 4
+mul r3, r3, r3
+check_r3 16
+
+test_name MUL_9
+mvi r2, 2
+mvi r3, 4
+mul r3, r3, r2
+check_r3 8
+
+test_name MUL_10
+load r1 0x12345678
+load r2 0x7bcdef12
+mul r3, r1, r2
+check_r3 0xa801c70
+
+test_name MUL_11
+load r1 0x12345678
+load r2 0xabcdef12
+mul r3, r1, r2
+check_r3 0x8a801c70
+
+end
diff --git a/tests/lm32/test_muli.S b/tests/lm32/test_muli.S
new file mode 100644 (file)
index 0000000..d6dd4a0
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name MULI_1
+mvi r1, 0
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_2
+mvi r1, 1
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_3
+mvi r1, 0
+muli r3, r1, 1
+check_r3 0
+
+test_name MULI_4
+mvi r1, 1
+muli r3, r1, 1
+check_r3 1
+
+test_name MULI_5
+mvi r1, 2
+muli r3, r1, -1
+check_r3 -2
+
+test_name MULI_6
+mvi r1, -2
+muli r3, r1, -1
+check_r3 2
+
+test_name MULI_7
+mvi r1, 0x1234
+muli r3, r1, 0x789
+check_r3 0x8929d4
+
+test_name MULI_8
+mvi r3, 4
+muli r3, r3, 4
+check_r3 16
+
+end
diff --git a/tests/lm32/test_nor.S b/tests/lm32/test_nor.S
new file mode 100644 (file)
index 0000000..74d7592
--- /dev/null
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name NOR_1
+mvi r1, 0
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xffffffff
+
+test_name NOR_2
+mvi r1, 0
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_3
+mvi r1, 1
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_4
+mvi r1, 1
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+nor r3, r1, r2
+check_r3 0
+
+test_name NOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+nor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name NOR_7
+load r1 0xaa55aa55
+nor r3, r1, r1
+check_r3 0x55aa55aa
+
+test_name NOR_8
+load r3 0xaa55aa55
+nor r3, r3, r3
+check_r3 0x55aa55aa
+
+end
diff --git a/tests/lm32/test_nori.S b/tests/lm32/test_nori.S
new file mode 100644 (file)
index 0000000..d00309c
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name NORI_1
+mvi r1, 0
+nori r3, r1, 0
+check_r3 0xffffffff
+
+test_name NORI_2
+mvi r1, 0
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_3
+mvi r1, 1
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_4
+mvi r1, 1
+nori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name NORI_5
+load r1 0xaa55aa55
+nori r3, r1, 0x55aa
+check_r3 0x55aa0000
+
+test_name NORI_6
+load r3 0xaa55aa55
+nori r3, r3, 0x55aa
+check_r3 0x55aa0000
+
+end
diff --git a/tests/lm32/test_or.S b/tests/lm32/test_or.S
new file mode 100644 (file)
index 0000000..4ed2923
--- /dev/null
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name OR_1
+mvi r1, 0
+mvi r2, 0
+or r3, r1, r2
+check_r3 0
+
+test_name OR_2
+mvi r1, 0
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_3
+mvi r1, 1
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_4
+mvi r1, 1
+mvi r2, 0
+or r3, r1, r2
+check_r3 1
+
+test_name OR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+or r3, r1, r2
+check_r3 0xffffffff
+
+test_name OR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+or r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name OR_7
+load r1 0xaa55aa55
+or r3, r1, r1
+check_r3 0xaa55aa55
+
+test_name OR_8
+load r3 0xaa55aa55
+or r3, r3, r3
+check_r3 0xaa55aa55
+
+end
diff --git a/tests/lm32/test_orhi.S b/tests/lm32/test_orhi.S
new file mode 100644 (file)
index 0000000..78b7600
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORHI_1
+mvi r1, 0
+orhi r3, r1, 0
+check_r3 0
+
+test_name ORHI_2
+mvi r1, 0
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_3
+load r1 0x00010000
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_4
+mvi r1, 1
+orhi r3, r1, 0
+check_r3 1
+
+test_name ORHI_5
+load r1 0xaa55aa55
+orhi r3, r1, 0x55aa
+check_r3 0xffffaa55
+
+test_name ORHI_6
+load r3 0xaa55aa55
+orhi r3, r3, 0x55aa
+check_r3 0xffffaa55
+
+end
diff --git a/tests/lm32/test_ori.S b/tests/lm32/test_ori.S
new file mode 100644 (file)
index 0000000..3d576cd
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORI_1
+mvi r1, 0
+ori r3, r1, 0
+check_r3 0
+
+test_name ORI_2
+mvi r1, 0
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_3
+mvi r1, 1
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_4
+mvi r1, 1
+ori r3, r1, 0
+check_r3 1
+
+test_name ORI_5
+load r1 0xaa55aa55
+ori r3, r1, 0x55aa
+check_r3 0xaa55ffff
+
+test_name ORI_6
+load r3 0xaa55aa55
+ori r3, r3, 0x55aa
+check_r3 0xaa55ffff
+
+end
diff --git a/tests/lm32/test_ret.S b/tests/lm32/test_ret.S
new file mode 100644 (file)
index 0000000..320264f
--- /dev/null
@@ -0,0 +1,14 @@
+.include "macros.inc"
+
+start
+
+test_name RET_1
+load ra mark
+ret
+
+tc_fail
+end
+
+mark:
+tc_pass
+end
diff --git a/tests/lm32/test_sb.S b/tests/lm32/test_sb.S
new file mode 100644 (file)
index 0000000..89e39d6
--- /dev/null
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SB_1
+load r1 data
+load r2 0xf0f1f2aa
+sb (r1+0), r2
+check_mem data 0xaa000000
+
+test_name SB_2
+load r2 0xf0f1f2bb
+sb (r1+1), r2
+check_mem data 0xaabb0000
+
+test_name SB_3
+load r2 0xf0f1f2cc
+sb (r1+-1), r2
+check_mem data0 0x000000cc
+
+end
+
+.data
+       .align 4
+data0:
+       .byte 0, 0, 0, 0
+data:
+       .byte 0, 0, 0, 0
+data1:
+       .byte 0, 0, 0, 0
diff --git a/tests/lm32/test_scall.S b/tests/lm32/test_scall.S
new file mode 100644 (file)
index 0000000..b442e32
--- /dev/null
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SCALL_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+scall
+check_excp 64
+
+test_name SCALL_2
+mv r3, ea
+check_r3 insn
+
+test_name SCALL_3
+rcsr r3, IE
+check_r3 2
+
+end
diff --git a/tests/lm32/test_sextb.S b/tests/lm32/test_sextb.S
new file mode 100644 (file)
index 0000000..58db8ee
--- /dev/null
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTB_1
+mvi r1, 0
+sextb r3, r1
+check_r3 0
+
+test_name SEXTB_2
+mvi r1, 0x7f
+sextb r3, r1
+check_r3 0x0000007f
+
+test_name SEXTB_3
+mvi r1, 0x80
+sextb r3, r1
+check_r3 0xffffff80
+
+end
diff --git a/tests/lm32/test_sexth.S b/tests/lm32/test_sexth.S
new file mode 100644 (file)
index 0000000..a059ec3
--- /dev/null
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTH_1
+mvi r1, 0
+sexth r3, r1
+check_r3 0
+
+test_name SEXTH_2
+load r1 0x7fff
+sexth r3, r1
+check_r3 0x00007fff
+
+test_name SEXTH_3
+load r1 0x8000
+sexth r3, r1
+check_r3 0xffff8000
+
+end
diff --git a/tests/lm32/test_sh.S b/tests/lm32/test_sh.S
new file mode 100644 (file)
index 0000000..ea8b3f2
--- /dev/null
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SH_1
+load r1 data
+load r2 0xf0f1aaaa
+sh (r1+0), r2
+check_mem data 0xaaaa0000
+
+test_name SH_2
+load r2 0xf0f1bbbb
+sh (r1+2), r2
+check_mem data 0xaaaabbbb
+
+test_name SH_3
+load r2 0xf0f1cccc
+sh (r1+-2), r2
+check_mem data0 0x0000cccc
+
+end
+
+.data
+       .align 4
+data0:
+       .byte 0, 0, 0, 0
+data:
+       .byte 0, 0, 0, 0
+data1:
+       .byte 0, 0, 0, 0
diff --git a/tests/lm32/test_sl.S b/tests/lm32/test_sl.S
new file mode 100644 (file)
index 0000000..0aee17f
--- /dev/null
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name SL_1
+mvi r1, 1
+mvi r2, 0
+sl r3, r1, r2
+check_r3 1
+
+test_name SL_2
+mvi r1, 0
+mvi r2, 1
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_3
+mvi r1, 1
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0x80000000
+
+test_name SL_4
+mvi r1, 16
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_5
+mvi r1, 1
+mvi r2, 34
+sl r3, r1, r2
+check_r3 4
+
+test_name SL_6
+mvi r1, 2
+sl r3, r1, r1
+check_r3 8
+
+test_name SL_7
+mvi r3, 2
+sl r3, r3, r3
+check_r3 8
+
+end
diff --git a/tests/lm32/test_sli.S b/tests/lm32/test_sli.S
new file mode 100644 (file)
index 0000000..a421de9
--- /dev/null
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SLI_1
+mvi r1, 1
+sli r3, r1, 0
+check_r3 1
+
+test_name SLI_2
+mvi r1, 0
+sli r3, r1, 1
+check_r3 0
+
+test_name SLI_3
+mvi r1, 1
+sli r3, r1, 31
+check_r3 0x80000000
+
+test_name SLI_4
+mvi r1, 16
+sli r3, r1, 31
+check_r3 0
+
+test_name SLI_7
+mvi r3, 2
+sli r3, r3, 2
+check_r3 8
+
+end
diff --git a/tests/lm32/test_sr.S b/tests/lm32/test_sr.S
new file mode 100644 (file)
index 0000000..62431a9
--- /dev/null
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SR_1
+mvi r1, 1
+mvi r2, 0
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_2
+mvi r1, 0
+mvi r2, 1
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_3
+load r1 0x40000000
+mvi r2, 30
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_4
+load r1 0x40000000
+mvi r2, 31
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_5
+mvi r1, 16
+mvi r2, 34
+sr r3, r1, r2
+check_r3 4
+
+test_name SR_6
+mvi r1, 2
+sr r3, r1, r1
+check_r3 0
+
+test_name SR_7
+mvi r3, 2
+sr r3, r3, r3
+check_r3 0
+
+test_name SR_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sr r3, r1, r2
+check_r3 0xfffffffc
+
+test_name SR_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sr r3, r1, r2
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_sri.S b/tests/lm32/test_sri.S
new file mode 100644 (file)
index 0000000..c1be907
--- /dev/null
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRI_1
+mvi r1, 1
+sri r3, r1, 0
+check_r3 1
+
+test_name SRI_2
+mvi r1, 0
+sri r3, r1, 1
+check_r3 0
+
+test_name SRI_3
+load r1 0x40000000
+sri r3, r1, 30
+check_r3 1
+
+test_name SRI_4
+load r1 0x40000000
+sri r3, r1, 31
+check_r3 0
+
+test_name SRI_5
+mvi r3, 2
+sri r3, r3, 2
+check_r3 0
+
+test_name SRI_6
+mvi r1, 0xfffffff0
+sri r3, r1, 2
+check_r3 0xfffffffc
+
+test_name SRI_7
+mvi r1, 0xfffffff0
+sri r3, r1, 4
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_sru.S b/tests/lm32/test_sru.S
new file mode 100644 (file)
index 0000000..2ab0b54
--- /dev/null
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SRU_1
+mvi r1, 1
+mvi r2, 0
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_2
+mvi r1, 0
+mvi r2, 1
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_3
+load r1 0x40000000
+mvi r2, 30
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_4
+load r1 0x40000000
+mvi r2, 31
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_5
+mvi r1, 16
+mvi r2, 34
+sru r3, r1, r2
+check_r3 4
+
+test_name SRU_6
+mvi r1, 2
+sru r3, r1, r1
+check_r3 0
+
+test_name SRU_7
+mvi r3, 2
+sru r3, r3, r3
+check_r3 0
+
+test_name SRU_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sru r3, r1, r2
+check_r3 0x3ffffffc
+
+test_name SRU_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sru r3, r1, r2
+check_r3 0x0fffffff
+
+end
diff --git a/tests/lm32/test_srui.S b/tests/lm32/test_srui.S
new file mode 100644 (file)
index 0000000..872c374
--- /dev/null
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRUI_1
+mvi r1, 1
+srui r3, r1, 0
+check_r3 1
+
+test_name SRUI_2
+mvi r1, 0
+srui r3, r1, 1
+check_r3 0
+
+test_name SRUI_3
+load r1 0x40000000
+srui r3, r1, 30
+check_r3 1
+
+test_name SRUI_4
+load r1 0x40000000
+srui r3, r1, 31
+check_r3 0
+
+test_name SRUI_5
+mvi r3, 2
+srui r3, r3, 2
+check_r3 0
+
+test_name SRUI_6
+mvi r1, 0xfffffff0
+srui r3, r1, 2
+check_r3 0x3ffffffc
+
+test_name SRUI_7
+mvi r1, 0xfffffff0
+srui r3, r1, 4
+check_r3 0x0fffffff
+
+end
diff --git a/tests/lm32/test_sub.S b/tests/lm32/test_sub.S
new file mode 100644 (file)
index 0000000..44b74a9
--- /dev/null
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name SUB_1
+mvi r1, 0
+mvi r2, 0
+sub r3, r1, r2
+check_r3 0
+
+test_name SUB_2
+mvi r1, 0
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_3
+mvi r1, 1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_4
+mvi r1, 1
+mvi r2, -1
+sub r3, r1, r2
+check_r3 2
+
+test_name SUB_5
+mvi r1, -1
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -2
+
+test_name SUB_6
+mvi r1, -1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_7
+mvi r1, 0
+mvi r2, -1
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_8
+mvi r3, 2
+sub r3, r3, r3
+check_r3 0
+
+test_name SUB_9
+mvi r1, 4
+mvi r3, 2
+sub r3, r1, r3
+check_r3 2
+
+test_name SUB_10
+mvi r1, 4
+mvi r3, 2
+sub r3, r3, r1
+check_r3 -2
+
+test_name SUB_11
+mvi r1, 4
+sub r3, r1, r1
+check_r3 0
+
+test_name SUB_12
+load r1 0x12345678
+load r2 0xabcdef97
+sub r3, r1, r2
+check_r3 0x666666e1
+
+end
diff --git a/tests/lm32/test_sw.S b/tests/lm32/test_sw.S
new file mode 100644 (file)
index 0000000..d1fdadc
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name SW_1
+load r1 data
+load r2 0xaabbccdd
+sw (r1+0), r2
+check_mem data 0xaabbccdd
+
+test_name SW_2
+load r2 0x00112233
+sw (r1+4), r2
+check_mem data1 0x00112233
+
+test_name SW_3
+load r2 0x44556677
+sw (r1+-4), r2
+check_mem data0 0x44556677
+
+test_name SW_4
+sw (r1+0), r1
+lw r3, (r1+0)
+check_r3 data
+
+end
+
+.data
+       .align 4
+data0:
+       .byte 0, 0, 0, 0
+data:
+       .byte 0, 0, 0, 0
+data1:
+       .byte 0, 0, 0, 0
diff --git a/tests/lm32/test_xnor.S b/tests/lm32/test_xnor.S
new file mode 100644 (file)
index 0000000..14a6207
--- /dev/null
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XNOR_1
+mvi r1, 0
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_2
+mvi r1, 0
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_3
+mvi r1, 1
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_4
+mvi r1, 1
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xnor r3, r1, r2
+check_r3 0
+
+test_name XNOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xnor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name XNOR_7
+load r1 0xaa55aa55
+xnor r3, r1, r1
+check_r3 0xffffffff
+
+test_name XNOR_8
+load r3 0xaa55aa55
+xnor r3, r3, r3
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_xnori.S b/tests/lm32/test_xnori.S
new file mode 100644 (file)
index 0000000..9d9c3c6
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XNORI_1
+mvi r1, 0
+xnori r3, r1, 0
+check_r3 0xffffffff
+
+test_name XNORI_2
+mvi r1, 0
+xnori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name XNORI_3
+mvi r1, 1
+xnori r3, r1, 1
+check_r3 0xffffffff
+
+test_name XNORI_4
+mvi r1, 1
+xnori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name XNORI_5
+load r1 0xaa55aa55
+xnori r3, r1, 0x5555
+check_r3 0x55aa00ff
+
+test_name XNORI_6
+load r3 0xaa55aa55
+xnori r3, r3, 0x5555
+check_r3 0x55aa00ff
+
+end
diff --git a/tests/lm32/test_xor.S b/tests/lm32/test_xor.S
new file mode 100644 (file)
index 0000000..6c6e712
--- /dev/null
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XOR_1
+mvi r1, 0
+mvi r2, 0
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_2
+mvi r1, 0
+mvi r2, 1
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_3
+mvi r1, 1
+mvi r2, 1
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_4
+mvi r1, 1
+mvi r2, 0
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xor r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name XOR_7
+load r1 0xaa55aa55
+xor r3, r1, r1
+check_r3 0
+
+test_name XOR_8
+load r3 0xaa55aa55
+xor r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_xori.S b/tests/lm32/test_xori.S
new file mode 100644 (file)
index 0000000..2051699
--- /dev/null
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XORI_1
+mvi r1, 0
+xori r3, r1, 0
+check_r3 0
+
+test_name XORI_2
+mvi r1, 0
+xori r3, r1, 1
+check_r3 1
+
+test_name XORI_3
+mvi r1, 1
+xori r3, r1, 1
+check_r3 0
+
+test_name XORI_4
+mvi r1, 1
+xori r3, r1, 0
+check_r3 1
+
+test_name XORI_5
+load r1 0xaa55aa55
+xori r3, r1, 0x5555
+check_r3 0xaa55ff00
+
+test_name XORI_6
+load r3 0xaa55aa55
+xori r3, r3, 0x5555
+check_r3 0xaa55ff00
+
+end
index 079f7a297309f7f7f6c1853394817c4ce21ce25f..2e93aafb87bcee804cd066a0c38b7f72c375ca5f 100644 (file)
@@ -44,20 +44,20 @@ static void set_idt(int n, unsigned int dpl)
     set_gate(idt_table + n, 0, dpl, 0, 0);
 }
 
-void qemu_free(void *ptr)
+void g_free(void *ptr)
 {
     free(ptr);
 }
 
-void *qemu_malloc(size_t size)
+void *g_malloc(size_t size)
 {
     return malloc(size);
 }
 
-void *qemu_mallocz(size_t size)
+void *g_malloc0(size_t size)
 {
     void *ptr;
-    ptr = qemu_malloc(size);
+    ptr = g_malloc(size);
     if (!ptr)
         return NULL;
     memset(ptr, 0, size);
index 8f481c7f7ad01c10ae5bbc8e8d9b7f0fdde2ad2a..8e64bbaf38a2aa952b290037bf22949730ab7354 100644 (file)
@@ -773,7 +773,7 @@ void test_fops(double a, double b)
 
 void fpu_clear_exceptions(void)
 {
-    struct __attribute__((packed)) {
+    struct QEMU_PACKED {
         uint16_t fpuc;
         uint16_t dummy1;
         uint16_t fpus;
@@ -802,7 +802,7 @@ void test_fcmp(double a, double b)
         "fstsw %%ax\n"
         : "=a" (fpus)
         : "t" (a), "u" (b));
-    printf("fcom(%f %f)=%04lx \n",
+    printf("fcom(%f %f)=%04lx\n",
            a, b, fpus & (0x4500 | FPUS_EMASK));
     fpu_clear_exceptions();
     asm("fucom %2\n"
@@ -924,7 +924,7 @@ void test_fbcd(double a)
 
 void test_fenv(void)
 {
-    struct __attribute__((packed)) {
+    struct QEMU_PACKED {
         uint16_t fpuc;
         uint16_t dummy1;
         uint16_t fpus;
@@ -934,7 +934,7 @@ void test_fenv(void)
         uint32_t ignored[4];
         long double fpregs[8];
     } float_env32;
-    struct __attribute__((packed)) {
+    struct QEMU_PACKED {
         uint16_t fpuc;
         uint16_t fpus;
         uint16_t fptag;
@@ -1279,7 +1279,7 @@ void test_segs(void)
     struct {
         uint32_t offset;
         uint16_t seg;
-    } __attribute__((packed)) segoff;
+    } QEMU_PACKED segoff;
 
     ldt.entry_number = 1;
     ldt.base_addr = (unsigned long)&seg_data1;
@@ -1441,7 +1441,7 @@ void test_misc(void)
         /* XXX: see if Intel Core2 and AMD64 behavior really
            differ. Here we implemented the Intel way which is not
            compatible yet with QEMU. */
-        static struct __attribute__((packed)) {
+        static struct QEMU_PACKED {
             uint64_t offset;
             uint16_t seg;
         } desc;
@@ -2281,7 +2281,7 @@ void test_sse_comi(double a1, double b1)
 }
 
 /* Force %xmm0 usage to avoid the case where both register index are 0
-   to test intruction decoding more extensively */
+   to test instruction decoding more extensively */
 #define CVT_OP_XMM2MMX(op)\
 {\
     asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \
index fcb365f40ccd75255b465532c061b8480c8ea841..c67174a260397148938c596fcc232eee98e00795 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);
@@ -322,7 +322,7 @@ void check_file_unfixed_eof_mmaps(void)
                fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
                             == ((test_fsize - sizeof *p1) / sizeof *p1));
 
-               /* Verify that the end of page is accessable and zeroed.  */
+               /* Verify that the end of page is accessible and zeroed.  */
                cp = (void *) p1;
                fail_unless (cp[pagesize - 4] == 0);
                munmap (p1, pagesize);
@@ -365,7 +365,7 @@ void check_file_fixed_eof_mmaps(void)
                fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
                             == ((test_fsize - sizeof *p1) / sizeof *p1));
 
-               /* Verify that the end of page is accessable and zeroed.  */
+               /* Verify that the end of page is accessible and zeroed.  */
                cp = (void *)p1;
                fail_unless (cp[pagesize - 4] == 0);
                munmap (p1, pagesize);
index 234ed97088d308eaa947cc970a10f0a33eef07a5..7265a9445d0f8e0c3b0c281180fb5701656c5af1 100644 (file)
@@ -4,7 +4,7 @@
 #include "../cutils.c"
 #include "../path.c"
 #include "../trace.c"
-#ifdef CONFIG_SIMPLE_TRACE
+#ifdef CONFIG_TRACE_SIMPLE
 #include "../simpletrace.c"
 #endif
 
diff --git a/tests/xtensa/Makefile b/tests/xtensa/Makefile
new file mode 100644 (file)
index 0000000..8713af1
--- /dev/null
@@ -0,0 +1,75 @@
+-include ../../config-host.mak
+
+CROSS=xtensa-dc232b-elf-
+
+ifndef XT
+SIM = qemu-system-xtensa
+SIMFLAGS = -M sim -cpu dc232b -nographic -semihosting $(EXTFLAGS) -kernel
+SIMDEBUG = -s -S
+else
+SIM = xt-run
+SIMFLAGS = --xtensa-core=DC_B_232L --exit_with_target_code $(EXTFLAGS)
+SIMDEBUG = --gdbserve=0
+endif
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)gcc -x assembler
+LD      = $(CROSS)ld
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o vectors.o
+
+TESTCASES += test_b.tst
+TESTCASES += test_bi.tst
+#TESTCASES += test_boolean.tst
+TESTCASES += test_bz.tst
+TESTCASES += test_clamps.tst
+TESTCASES += test_fail.tst
+TESTCASES += test_interrupt.tst
+TESTCASES += test_loop.tst
+TESTCASES += test_mac16.tst
+TESTCASES += test_max.tst
+TESTCASES += test_min.tst
+TESTCASES += test_mmu.tst
+TESTCASES += test_mul16.tst
+TESTCASES += test_mul32.tst
+TESTCASES += test_nsa.tst
+ifdef XT
+TESTCASES += test_pipeline.tst
+endif
+TESTCASES += test_quo.tst
+TESTCASES += test_rem.tst
+TESTCASES += test_rst0.tst
+TESTCASES += test_sar.tst
+TESTCASES += test_sext.tst
+TESTCASES += test_shift.tst
+TESTCASES += test_timer.tst
+TESTCASES += test_windowed.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/xtensa/%.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/xtensa/%.S
+       $(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT) Makefile
+       $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(TESTCASES)
+
+check: $(addprefix run-, $(TESTCASES))
+
+run-%.tst: %.tst
+       $(SIM) $(SIMFLAGS) ./$<
+
+run-test_fail.tst: test_fail.tst
+       ! $(SIM) $(SIMFLAGS) ./$<
+
+debug-%.tst: %.tst
+       $(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$<
+
+clean:
+       $(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/xtensa/crt.S b/tests/xtensa/crt.S
new file mode 100644 (file)
index 0000000..d9846ac
--- /dev/null
@@ -0,0 +1,24 @@
+.section .init
+    j       1f
+.section .init.text
+1:
+    movi    a2, _start
+    jx      a2
+
+.text
+.global _start
+_start:
+    movi    a2, 1
+    wsr     a2, windowstart
+    movi    a2, 0
+    wsr     a2, windowbase
+    movi    a1, _fstack
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+
+    call0   main
+
+    mov     a3, a2
+    movi    a2, 1
+    simcall
diff --git a/tests/xtensa/linker.ld b/tests/xtensa/linker.ld
new file mode 100644 (file)
index 0000000..4d0b307
--- /dev/null
@@ -0,0 +1,112 @@
+OUTPUT_FORMAT("elf32-xtensa-le")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+       ram : ORIGIN = 0xd0000000, LENGTH = 0x08000000  /* 128M */
+       rom : ORIGIN = 0xfe000000, LENGTH = 0x00001000  /* 4k */
+}
+
+SECTIONS
+{
+    .init :
+    {
+        *(.init)
+               *(.init.*)
+    } > rom
+
+    .vector :
+    {
+    . = 0x00000000;
+        *(.vector.window_overflow_4)
+        *(.vector.window_overflow_4.*)
+    . = 0x00000040;
+        *(.vector.window_underflow_4)
+        *(.vector.window_underflow_4.*)
+    . = 0x00000080;
+        *(.vector.window_overflow_8)
+        *(.vector.window_overflow_8.*)
+    . = 0x000000c0;
+        *(.vector.window_underflow_8)
+        *(.vector.window_underflow_8.*)
+    . = 0x00000100;
+        *(.vector.window_overflow_12)
+        *(.vector.window_overflow_12.*)
+    . = 0x00000140;
+        *(.vector.window_underflow_12)
+        *(.vector.window_underflow_12.*)
+
+    . = 0x00000180;
+        *(.vector.level2)
+        *(.vector.level2.*)
+    . = 0x000001c0;
+        *(.vector.level3)
+        *(.vector.level3.*)
+    . = 0x00000200;
+        *(.vector.level4)
+        *(.vector.level4.*)
+    . = 0x00000240;
+        *(.vector.level5)
+        *(.vector.level5.*)
+    . = 0x00000280;
+        *(.vector.level6)
+        *(.vector.level6.*)
+    . = 0x000002c0;
+        *(.vector.level7)
+        *(.vector.level7.*)
+
+    . = 0x00000300;
+        *(.vector.kernel)
+        *(.vector.kernel.*)
+    . = 0x00000340;
+        *(.vector.user)
+        *(.vector.user.*)
+    . = 0x000003c0;
+        *(.vector.double)
+        *(.vector.double.*)
+    } > ram
+
+       .text :
+       {
+               _ftext = .;
+               *(.text .stub .text.* .gnu.linkonce.t.* .literal .literal.*)
+               _etext = .;
+       } > ram
+
+       .rodata :
+       {
+               . = ALIGN(4);
+               _frodata = .;
+               *(.rodata .rodata.* .gnu.linkonce.r.*)
+               *(.rodata1)
+               _erodata = .;
+       } > ram
+
+       .data :
+       {
+               . = ALIGN(4);
+               _fdata = .;
+               *(.data .data.* .gnu.linkonce.d.*)
+               *(.data1)
+               _gp = ALIGN(16);
+               *(.sdata .sdata.* .gnu.linkonce.s.*)
+               _edata = .;
+       } > ram
+
+       .bss :
+       {
+               . = ALIGN(4);
+               _fbss = .;
+               *(.dynsbss)
+               *(.sbss .sbss.* .gnu.linkonce.sb.*)
+               *(.scommon)
+               *(.dynbss)
+               *(.bss .bss.* .gnu.linkonce.b.*)
+               *(COMMON)
+               _ebss = .;
+               _end = .;
+       } > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
diff --git a/tests/xtensa/macros.inc b/tests/xtensa/macros.inc
new file mode 100644 (file)
index 0000000..2d4515e
--- /dev/null
@@ -0,0 +1,68 @@
+.macro test_suite name
+.data
+status: .word result
+result: .space 20
+.text
+.global main
+.align 4
+main:
+.endm
+
+.macro reset_ps
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+.endm
+
+.macro test_suite_end
+    reset_ps
+    movi    a0, status
+    l32i    a2, a0, 0
+    movi    a0, result
+    sub     a2, a2, a0
+    movi    a3, 0
+    loopnez a2, 1f
+    l8ui    a2, a0, 0
+    or      a3, a3, a2
+    addi    a0, a0, 1
+1:
+    exit
+.endm
+
+.macro test name
+.endm
+
+.macro test_end
+99:
+    reset_ps
+    movi    a2, status
+    l32i    a3, a2, 0
+    addi    a3, a3, 1
+    s32i    a3, a2, 0
+.endm
+
+.macro exit
+    movi    a2, 1
+    simcall
+.endm
+
+.macro test_fail
+    movi    a2, status
+    l32i    a2, a2, 0
+    movi    a3, 1
+    s8i     a3, a2, 0
+    j       99f
+.endm
+
+.macro assert cond, arg1, arg2
+    b\cond  \arg1, \arg2, 90f
+    test_fail
+90:
+    nop
+.endm
+
+.macro set_vector vector, addr
+    movi    a2, handler_\vector
+    movi    a3, \addr
+    s32i    a3, a2, 0
+.endm
diff --git a/tests/xtensa/test_b.S b/tests/xtensa/test_b.S
new file mode 100644 (file)
index 0000000..6cbe5f1
--- /dev/null
@@ -0,0 +1,221 @@
+.include "macros.inc"
+
+test_suite b
+
+test bnone
+    movi    a2, 0xa5a5ff00
+    movi    a3, 0x5a5a00ff
+    bnone   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff01
+    bnone   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test beq
+    movi    a2, 0
+    movi    a3, 0
+    beq     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beq     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blt
+    movi    a2, 6
+    movi    a3, 7
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blt     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltu
+    movi    a2, 6
+    movi    a3, 7
+    bltu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test ball
+    movi    a2, 0xa5a5ffa5
+    movi    a3, 0xa5a5ff00
+    ball    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5a5a5
+    ball    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbc
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbc     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbc     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbci
+    movi    a2, 0xfffdffff
+    bbci    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0x00020000
+    bbci    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bany
+    movi    a2, 0xa5a5ff01
+    movi    a3, 0x5a5a00ff
+    bany    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff00
+    bany    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bne
+    movi    a2, 1
+    movi    a3, 0
+    bne     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bne     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bge
+    movi    a2, 7
+    movi    a3, 7
+    bge     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeu
+    movi    a2, 7
+    movi    a3, 7
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnall
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0xa5a5ff00
+    bnall   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ffa5
+    bnall   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbs
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbs     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbs     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbsi
+    movi    a2, 0x00020000
+    bbsi    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0xfffdffff
+    bbsi    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bi.S b/tests/xtensa/test_bi.S
new file mode 100644 (file)
index 0000000..6a5f1df
--- /dev/null
@@ -0,0 +1,103 @@
+.include "macros.inc"
+
+test_suite bi
+
+test beqi
+    movi    a2, 7
+    beqi    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beqi    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnei
+    movi    a2, 1
+    bnei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bnei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blti
+    movi    a2, 6
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blti    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgei
+    movi    a2, 7
+    bgei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltui
+    movi    a2, 6
+    bltui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeui
+    movi    a2, 7
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_boolean.S b/tests/xtensa/test_boolean.S
new file mode 100644 (file)
index 0000000..50e6d2c
--- /dev/null
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+test_suite boolean
+
+test all4
+    movi    a2, 0xfec0
+    wsr     a2, br
+    all4    b0, b0
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b4
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b8
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b12
+    rsr     a3, br
+    addi    a2, a2, 1
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bz.S b/tests/xtensa/test_bz.S
new file mode 100644 (file)
index 0000000..f9ba6e2
--- /dev/null
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+test_suite bz
+
+test beqz
+    movi    a2, 0
+    _beqz   a2, 1f
+    test_fail
+1:
+    movi    a2, 1
+    _beqz   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnez
+    movi    a2, 1
+    _bnez   a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    _bnez   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltz
+    movi    a2, 0xffffffff
+    bltz    a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bltz    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgez
+    movi    a2, 0
+    bgez    a2, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgez    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_clamps.S b/tests/xtensa/test_clamps.S
new file mode 100644 (file)
index 0000000..c186cc9
--- /dev/null
@@ -0,0 +1,42 @@
+.include "macros.inc"
+
+test_suite clamps
+
+test clamps
+    movi    a2, 0
+    movi    a3, 0
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x7f
+    movi    a3, 0x7f
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffff80
+    movi    a3, 0xffffff80
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x80
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0xffffff7f
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x7fffffff
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x80000000
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_fail.S b/tests/xtensa/test_fail.S
new file mode 100644 (file)
index 0000000..e8d1b42
--- /dev/null
@@ -0,0 +1,9 @@
+.include "macros.inc"
+
+test_suite fail
+
+test fail
+    test_fail
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_interrupt.S b/tests/xtensa/test_interrupt.S
new file mode 100644 (file)
index 0000000..68b3ee1
--- /dev/null
@@ -0,0 +1,194 @@
+.include "macros.inc"
+
+test_suite interrupt
+
+.macro clear_interrupts
+    movi    a2, 0
+    wsr     a2, intenable
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+    esync
+    rsr     a2, interrupt
+    wsr     a2, intclear
+
+    esync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+.endm
+
+.macro check_l1
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    assert  eqi, a2, 0x10   /* only EXCM is set for level-1 interrupt */
+    rsr     a2, exccause
+    assert  eqi, a2, 4
+.endm
+
+test rsil
+    clear_interrupts
+
+    rsr     a2, ps
+    rsil    a3, 7
+    rsr     a4, ps
+    assert  eq, a2, a3
+    movi    a2, 0xf
+    and     a2, a4, a2
+    assert  eqi, a2, 7
+    xor     a3, a3, a4
+    movi    a2, 0xfffffff0
+    and     a2, a3, a2
+    assert  eqi, a2, 0
+test_end
+
+test soft_disabled
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intclear
+    esync
+    rsr     a3, interrupt
+    assert  eqi, a3, 0
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test soft_intenable
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    rsil    a3, 0
+    wsr     a2, intenable
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_rsil
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_waiti
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    waiti   0
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_user
+    set_vector kernel, 1f
+    set_vector user, 2f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+
+    rsr     a2, ps
+    movi    a3, 0x20
+    or      a2, a2, a3
+    wsr     a2, ps
+    waiti   0
+1:
+    test_fail
+2:
+    check_l1
+test_end
+
+test soft_priority
+    set_vector kernel, 1f
+    set_vector level3, 2f
+    clear_interrupts
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    wsr     a2, intset
+    esync
+1:
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    movi    a3, 0x13
+    assert  eq, a2, a3      /* EXCM and INTMASK are set
+                               for high-priority interrupt */
+test_end
+
+test eps_epc_rfi
+    set_vector level3, 3f
+    clear_interrupts
+    reset_ps
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    rsr     a3, ps
+    esync
+    wsr     a2, intset
+1:
+    esync
+2:
+    test_fail
+3:
+    rsr     a2, eps3
+    assert  eq, a2, a3
+    rsr     a2, epc3
+    movi    a3, 1b
+    assert  ge, a2, a3
+    movi    a3, 2b
+    assert  ge, a3, a2
+    movi    a2, 4f
+    wsr     a2, epc3
+    movi    a2, 0x40003
+    wsr     a2, eps3
+    rfi     3
+    test_fail
+4:
+    rsr     a2, ps
+    movi    a3, 0x40003
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_loop.S b/tests/xtensa/test_loop.S
new file mode 100644 (file)
index 0000000..a5ea933
--- /dev/null
@@ -0,0 +1,77 @@
+.include "macros.inc"
+
+test_suite loop
+
+test loop
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    assert  eqi, a2, 5
+test_end
+
+test loop0
+    movi    a2, 0
+    loop    a2, 1f
+    rsr     a2, lcount
+    assert  eqi, a2, -1
+    j       1f
+1:
+test_end
+
+test loop_jump
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    j       1f
+1:
+    assert  eqi, a2, 1
+test_end
+
+test loop_branch
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    beqi    a2, 3, 1f
+1:
+    assert  eqi, a2, 3
+test_end
+
+test loop_manual
+    movi    a2, 0
+    movi    a3, 5
+    movi    a4, 1f
+    movi    a5, 2f
+    wsr     a3, lcount
+    wsr     a4, lbeg
+    wsr     a5, lend
+    isync
+    j       1f
+.align 4
+1:
+    addi    a2, a2, 1
+2:
+    assert  eqi, a2, 6
+test_end
+
+test loop_excm
+    movi    a2, 0
+    movi    a3, 5
+    rsr     a4, ps
+    movi    a5, 0x10
+    or      a4, a4, a5
+    wsr     a4, ps
+    isync
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    xor     a4, a4, a5
+    isync
+    wsr     a4, ps
+    assert  eqi, a2, 1
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mac16.S b/tests/xtensa/test_mac16.S
new file mode 100644 (file)
index 0000000..5ddd160
--- /dev/null
@@ -0,0 +1,243 @@
+.include "macros.inc"
+
+test_suite mac16
+
+#define ext16(v) (((v) & 0xffff) | (((v) & 0x8000) * 0x1ffffffe))
+#define mul16(a, b) ((ext16(a) * ext16(b)))
+
+.macro assert_acc_value v
+    rsr     a4, ACCLO
+    movi    a5, (\v) & 0xffffffff
+    assert  eq, a4, a5
+    rsr     a4, ACCHI
+    movi    a5, (\v) >> 32
+    sext    a5, a5, 7
+    assert  eq, a4, a5
+.endm
+
+.macro init_reg sr, reg, val
+    .if (\sr)
+    movi    a4, \val
+    wsr     a4, \reg
+    .else
+    movi    \reg, \val
+    .endif
+.endm
+
+.macro test_mulxx mulop, comb, s, t, a, b
+    init_reg \comb & 2, \s, \a
+    init_reg \comb & 1, \t, \b
+
+    \mulop\().ll \s, \t
+    assert_acc_value mul16(\a, \b)
+
+    \mulop\().lh \s, \t
+    assert_acc_value mul16(\a, (\b >> 16))
+
+    \mulop\().hl \s, \t
+    assert_acc_value mul16((\a >> 16), \b)
+
+    \mulop\().hh \s, \t
+    assert_acc_value mul16((\a >> 16), (\b >> 16))
+.endm
+
+test mul_aa
+    test_mulxx mul.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f
+test_end
+
+test mul_ad
+    test_mulxx mul.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f
+test_end
+
+test mul_da
+    test_mulxx mul.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f
+test_end
+
+test mul_dd
+    test_mulxx mul.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f
+test_end
+
+
+.macro init_acc iv
+    movi    a4, (\iv) & 0xffffffff
+    wsr     a4, ACCLO
+    movi    a4, (\iv) >> 32
+    wsr     a4, ACCHI
+.endm
+
+.macro test_mulxxx mulop, comb, s, t, a, b, iv, op
+    init_reg \comb & 2, \s, \a
+    init_reg \comb & 1, \t, \b
+
+    init_acc \iv
+    \mulop\().ll \s, \t
+    assert_acc_value (\iv \op mul16(\a, \b))
+
+    init_acc \iv
+    \mulop\().lh \s, \t
+    assert_acc_value (\iv \op mul16(\a, (\b >> 16)))
+
+    init_acc \iv
+    \mulop\().hl \s, \t
+    assert_acc_value (\iv \op mul16((\a >> 16), \b))
+
+    init_acc \iv
+    \mulop\().hh \s, \t
+    assert_acc_value (\iv \op mul16((\a >> 16), (\b >> 16)))
+.endm
+
+
+test mula_aa
+    test_mulxxx mula.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, +
+test_end
+
+test mula_ad
+    test_mulxxx mula.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, +
+test_end
+
+test mula_da
+    test_mulxxx mula.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+test_end
+
+test mula_dd
+    test_mulxxx mula.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+test_end
+
+
+test muls_aa
+    test_mulxxx muls.aa, 0, a2, a3, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, -
+test_end
+
+test muls_ad
+    test_mulxxx muls.ad, 1, a2, m2, 0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, -
+test_end
+
+test muls_da
+    test_mulxxx muls.da, 2, m1, a3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, -
+test_end
+
+test muls_dd
+    test_mulxxx muls.dd, 3, m0, m3, 0xf7315a5a, 0xa5a5137f, 0xfff73155aa, -
+test_end
+
+test ldinc
+    movi    a2, 1f - 4
+    ldinc   m0, a2
+    movi    a3, 1f
+    assert  eq, a2, a3
+    rsr     a3, m0
+    movi    a4, 0x55aa137f
+    assert  eq, a3, a4
+    ldinc   m1, a2
+    movi    a3, 1f + 4
+    assert  eq, a2, a3
+    rsr     a3, m1
+    movi    a4, 0x12345678
+    assert  eq, a3, a4
+
+.data
+1:  .word 0x55aa137f, 0x12345678, 0x137fa5a5
+.text
+test_end
+
+test lddec
+    movi    a2, 1f
+    lddec   m2, a2
+    movi    a3, 1f - 4
+    assert  eq, a2, a3
+    rsr     a3, m2
+    movi    a4, 0x12345678
+    assert  eq, a3, a4
+    lddec   m3, a2
+    movi    a3, 1f - 8
+    assert  eq, a2, a3
+    rsr     a3, m3
+    movi    a4, 0x55aa137f
+    assert  eq, a3, a4
+.data
+    .word 0x55aa137f, 0x12345678
+1:
+.text
+test_end
+
+
+.macro test_mulxxx_ld mulop, ldop, comb, w, x, s, t, a, b, iv, op
+    init_reg \comb & 2, \s, \a
+    init_reg \comb & 1, \t, \b
+
+    init_acc \iv
+    \mulop\().ll.\ldop \w, \x, \s, \t
+    assert_acc_value (\iv \op mul16(\a, \b))
+
+    init_acc \iv
+    \mulop\().lh.\ldop \w, \x, \s, \t
+    assert_acc_value (\iv \op mul16(\a, (\b >> 16)))
+
+    init_acc \iv
+    \mulop\().hl.\ldop \w, \x, \s, \t
+    assert_acc_value (\iv \op mul16((\a >> 16), \b))
+
+    init_acc \iv
+    \mulop\().hh.\ldop \w, \x, \s, \t
+    assert_acc_value (\iv \op mul16((\a >> 16), (\b >> 16)))
+.endm
+
+test mula_da_ldinc
+    movi    a2, 1f - 4
+    test_mulxxx_ld mula.da, ldinc, 2, m1, a2, m1, a3, \
+        0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+    movi    a3, 1f + 12
+    assert  eq, a2, a3
+    rsr     a2, m1
+    movi    a3, 0x12345678
+    assert  eq, a2, a3
+.data
+1:  .word 0xf7315a5a, 0xf7315a5a, 0xf7315a5a, 0x12345678
+.text
+test_end
+
+test mula_dd_ldinc
+    movi    a2, 1f - 4
+    test_mulxxx_ld mula.dd, ldinc, 3, m2, a2, m1, m2, \
+        0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+    movi    a3, 1f + 12
+    assert  eq, a2, a3
+    rsr     a2, m2
+    movi    a3, 0x12345678
+    assert  eq, a2, a3
+.data
+1:  .word 0xa5a5137f, 0xa5a5137f, 0xa5a5137f, 0x12345678
+.text
+test_end
+
+test mula_da_lddec
+    movi    a2, 1f
+    test_mulxxx_ld mula.da, lddec, 2, m1, a2, m1, a3, \
+        0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+    movi    a3, 1f - 16
+    assert  eq, a2, a3
+    rsr     a2, m1
+    movi    a3, 0x12345678
+    assert  eq, a2, a3
+.data
+    .word 0x12345678, 0xf7315a5a, 0xf7315a5a, 0xf7315a5a
+1:
+.text
+test_end
+
+test mula_dd_lddec
+    movi    a2, 1f
+    test_mulxxx_ld mula.dd, lddec, 3, m2, a2, m1, m2, \
+        0xf7315a5a, 0xa5a5137f, 0x0ff73155aa, +
+    movi    a3, 1f - 16
+    assert  eq, a2, a3
+    rsr     a2, m2
+    movi    a3, 0x12345678
+    assert  eq, a2, a3
+.data
+    .word 0x12345678, 0xa5a5137f, 0xa5a5137f, 0xa5a5137f
+1:
+.text
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_max.S b/tests/xtensa/test_max.S
new file mode 100644 (file)
index 0000000..2534c9d
--- /dev/null
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite max
+
+test max
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test maxu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_min.S b/tests/xtensa/test_min.S
new file mode 100644 (file)
index 0000000..6d9ddeb
--- /dev/null
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite min
+
+test min
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test minu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mmu.S b/tests/xtensa/test_mmu.S
new file mode 100644 (file)
index 0000000..52d5774
--- /dev/null
@@ -0,0 +1,318 @@
+.include "macros.inc"
+
+test_suite mmu
+
+.purgem test
+
+.macro test name
+    movi    a2, 0x00000004
+    idtlb   a2
+    movi    a2, 0x00100004
+    idtlb   a2
+    movi    a2, 0x00200004
+    idtlb   a2
+    movi    a2, 0x00300004
+    idtlb   a2
+    movi    a2, 0x00000007
+    idtlb   a2
+.endm
+
+test tlb_group
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    witlb   a2, a3
+    movi    a3, 0x00200004
+    rdtlb0  a1, a3
+    ritlb0  a2, a3
+    movi    a3, 0x01000001
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    rdtlb1  a1, a3
+    ritlb1  a2, a3
+    movi    a3, 0x04000002
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x01234014
+    assert  eq, a1, a3
+    movi    a3, 0x0123400c
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    idtlb   a3
+    iitlb   a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x00000010
+    and     a1, a1, a3
+    assert  eqi, a1, 0
+    movi    a3, 0x00000008
+    and     a2, a2, a3
+    assert  eqi, a2, 0
+test_end
+
+test itlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    jx      a3
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 16
+    assert  eq, a2, a3
+test_end
+
+test dtlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    l8ui    a2, a3, 0
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 24
+    assert  eq, a2, a3
+test_end
+
+test itlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0xf0000004 /* VPN */
+    witlb   a2, a3
+    movi    a3, 0xf0000000
+    pitlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 17
+    assert  eq, a2, a3
+test_end
+
+test dtlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200007 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200000
+    pdtlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 25
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_privilege
+    set_vector kernel, 3f
+
+    movi    a2, 0x4004f
+    wsr     a2, ps
+1:
+    isync
+    nop
+2:
+    test_fail
+3:
+    movi    a1, 1b
+    rsr     a2, excvaddr
+    rsr     a3, epc1
+    assert  ge, a2, a1
+    assert  ge, a3, a1
+    movi    a1, 2b
+    assert  lt, a2, a1
+    assert  lt, a3, a1
+    rsr     a2, exccause
+    movi    a3, 18
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test load_store_privilege
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0x10
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200001
+    movi    a2, 0x4004f
+    jx      a1
+10:
+    wsr     a2, ps
+    isync
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    movi    a1, 0x000fffff
+    and     a3, a3, a1
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test cring_load_store_privilege
+    set_vector kernel, 0
+    set_vector double, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200004
+    movi    a2, 0x4005f    /* ring 1 + excm => cring == 0 */
+    wsr     a2, ps
+    isync
+    l8ui    a2, a3, 0      /* cring used */
+1:
+    l32e    a2, a3, -4     /* ring used */
+    test_fail
+2:
+    rsr     a2, excvaddr
+    addi    a2, a2, 4
+    assert  eq, a2, a3
+    rsr     a2, depc
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_prohibited
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0xfffff000
+    and     a2, a2, a1
+    movi    a1, 0x4
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+    jx      a1
+    .align  4
+10:
+    nop
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a1
+    rsr     a2, epc1
+    assert  eq, a2, a1
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+test_end
+
+test load_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200002
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+test_end
+
+test store_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000001 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200003
+    l8ui    a2, a3, 0
+1:
+    s8i     a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 29
+    assert  eq, a2, a3
+test_end
+
+test dtlb_autoload
+    set_vector kernel, 0
+
+    movi    a2, 0xd4000000
+    wsr     a2, ptevaddr
+    movi    a3, 0x00001013
+    s32i    a3, a2, 4
+    pdtlb   a2, a3
+    movi    a1, 0x10
+    and     a1, a1, a2
+    assert  eqi, a1, 0
+    l8ui    a1, a3, 0
+    pdtlb   a2, a3
+    movi    a1, 0xfffff010
+    and     a1, a1, a2
+    movi    a3, 0x00001010
+    assert  eq, a1, a3
+    movi    a1, 0xf
+    and     a1, a1, a2
+    assert  lti, a1, 4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul16.S b/tests/xtensa/test_mul16.S
new file mode 100644 (file)
index 0000000..bf94376
--- /dev/null
@@ -0,0 +1,83 @@
+.include "macros.inc"
+
+test_suite mul16
+
+test mul16u_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x0c9d6bdb
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x9ff1e795
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf91e6bdb
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x031be795
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul32.S b/tests/xtensa/test_mul32.S
new file mode 100644 (file)
index 0000000..fdaf573
--- /dev/null
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+test_suite mul32
+
+test mull
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x5de480a6
+    mull    a5, a2, a4
+    assert  eq, a5, a6
+    mull    a2, a2, a4
+    assert  eq, a2, a6
+    mull    a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+/* unfortunately dc232b doesn't have muluh/mulsh*/
+
+test_suite_end
diff --git a/tests/xtensa/test_nsa.S b/tests/xtensa/test_nsa.S
new file mode 100644 (file)
index 0000000..a5fe5de
--- /dev/null
@@ -0,0 +1,59 @@
+.include "macros.inc"
+
+test_suite nsa
+
+test nsa
+    movi    a2, 0
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0xfffffffe
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+test_end
+
+test nsau
+    movi    a2, 0
+    movi    a3, 32
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 0
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 31
+    nsau    a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 1
+    nsau    a2, a2
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_pipeline.S b/tests/xtensa/test_pipeline.S
new file mode 100644 (file)
index 0000000..6be6085
--- /dev/null
@@ -0,0 +1,157 @@
+.include "macros.inc"
+
+.purgem test
+.macro test name
+    movi    a2, 1f
+    movi    a3, 99f
+0:
+    ipf     a2, 0
+    ipf     a2, 4
+    ipf     a2, 8
+    ipf     a2, 12
+    addi    a2, a2, 16
+    blt     a2, a3, 0b
+    j       1f
+    .align 4
+1:
+.endm
+
+test_suite pipeline
+
+test register_no_stall
+    rsr     a3, ccount
+    add     a5, a6, a6
+    add     a6, a5, a5
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 3
+test_end
+
+test register_stall
+    l32i    a5, a1, 0   /* data cache preload */
+    nop
+    rsr     a3, ccount
+    l32i    a5, a1, 0
+    add     a6, a5, a5  /* M-to-E interlock */
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j0_stall
+    rsr     a3, ccount
+    j       1f          /* E + 2-cycle penalty */
+1:
+    rsr     a4, ccount  /* E */
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j1_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j5_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b_no_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 2, 1f
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 2
+1:
+test_end
+
+test b1_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b5_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+/* PS *SYNC */
+
+test ps_dsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    dsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_esync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    esync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_rsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    rsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_isync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    isync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    movi    a4, 9
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_quo.S b/tests/xtensa/test_quo.S
new file mode 100644 (file)
index 0000000..12debf1
--- /dev/null
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite quo
+
+test quou_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x8
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x1
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quou    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test quos_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xfffffffc
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0xfffffff6
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0x80000000
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test quos_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quos    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rem.S b/tests/xtensa/test_rem.S
new file mode 100644 (file)
index 0000000..bb0d5fe
--- /dev/null
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite rem
+
+test remu_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x9aa40af
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x5a5a137f
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x518c46db
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    remu    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test rems_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xf3a27ce7
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x02479b03
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf7315a5a
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test rems_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    rems    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rst0.S b/tests/xtensa/test_rst0.S
new file mode 100644 (file)
index 0000000..3eda565
--- /dev/null
@@ -0,0 +1,148 @@
+.include "macros.inc"
+
+test_suite rst0
+
+test and
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x01250125
+    and     a5, a2, a4
+    assert  eq, a5, a6
+    and     a2, a2, a4
+    assert  eq, a2, a6
+    and     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test or
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb7ffb7ff
+    or      a5, a2, a4
+    assert  eq, a5, a6
+    or      a2, a2, a4
+    assert  eq, a2, a6
+    or      a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test xor
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb6dab6da
+    xor     a5, a2, a4
+    assert  eq, a5, a6
+    xor     a2, a2, a4
+    assert  eq, a2, a6
+    xor     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test add
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb924b924
+    add     a5, a2, a4
+    assert  eq, a5, a6
+    add     a2, a2, a4
+    assert  eq, a2, a6
+    add     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xcca45ec9
+    addx2   a5, a2, a4
+    assert  eq, a5, a6
+    addx2   a2, a2, a4
+    assert  eq, a2, a6
+    addx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf3a3aa13
+    addx4   a5, a2, a4
+    assert  eq, a5, a6
+    addx4   a2, a2, a4
+    assert  eq, a2, a6
+    addx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x41a240a7
+    addx8   a5, a2, a4
+    assert  eq, a5, a6
+    addx8   a2, a2, a4
+    assert  eq, a2, a6
+    addx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test sub
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x6dda9226
+    sub     a5, a2, a4
+    assert  eq, a5, a6
+    sub     a2, a2, a4
+    assert  eq, a2, a6
+    sub     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x815a37cb
+    subx2   a5, a2, a4
+    assert  eq, a5, a6
+    subx2   a2, a2, a4
+    assert  eq, a2, a6
+    subx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xa8598315
+    subx4   a5, a2, a4
+    assert  eq, a5, a6
+    subx4   a2, a2, a4
+    assert  eq, a2, a6
+    subx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf65819a9
+    subx8   a5, a2, a4
+    assert  eq, a5, a6
+    subx8   a2, a2, a4
+    assert  eq, a2, a6
+    subx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sar.S b/tests/xtensa/test_sar.S
new file mode 100644 (file)
index 0000000..40c649f
--- /dev/null
@@ -0,0 +1,111 @@
+.include "macros.inc"
+
+test_suite sar
+
+.macro test_sar prefix, imm
+    \prefix\()_set \imm
+    \prefix\()_ver \imm
+.endm
+
+.macro tests_sar prefix
+    test_sar \prefix, 0
+    test_sar \prefix, 1
+    test_sar \prefix, 2
+    test_sar \prefix, 3
+    test_sar \prefix, 0x1f
+    test_sar \prefix, 0x20
+    test_sar \prefix, 0x3f
+    test_sar \prefix, 0x40
+    test_sar \prefix, 0xfffffffe
+.endm
+
+.macro sar_set imm
+    movi    a2, \imm
+    wsr     a2, sar
+.endm
+
+.macro sar_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x3f
+    assert  eq, a2, a3
+.endm
+
+test sar
+    tests_sar sar
+test_end
+
+.macro ssr_set imm
+    movi    a2, \imm
+    ssr     a2
+.endm
+
+.macro ssr_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssr
+    tests_sar ssr
+test_end
+
+.macro ssl_set imm
+    movi    a2, \imm
+    ssl     a2
+.endm
+
+.macro ssl_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - (\imm & 0x1f)
+    assert  eq, a2, a3
+.endm
+
+test ssl
+    tests_sar ssl
+test_end
+
+.macro ssa8l_set imm
+    movi    a2, \imm
+    ssa8l   a2
+.endm
+
+.macro ssa8l_ver imm
+    rsr     a3, sar
+    movi    a2, (\imm & 0x3) << 3
+    assert  eq, a2, a3
+.endm
+
+test ssa8l
+    tests_sar ssa8l
+test_end
+
+.macro ssa8b_set imm
+    movi    a2, \imm
+    ssa8b   a2
+.endm
+
+.macro ssa8b_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - ((\imm & 0x3) << 3)
+    assert  eq, a2, a3
+.endm
+
+test ssa8b
+    tests_sar ssa8b
+test_end
+
+.macro ssai_set imm
+    ssai    \imm & 0x1f
+.endm
+
+.macro ssai_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssai
+    tests_sar ssai
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sext.S b/tests/xtensa/test_sext.S
new file mode 100644 (file)
index 0000000..04dc650
--- /dev/null
@@ -0,0 +1,69 @@
+.include "macros.inc"
+
+test_suite sext
+
+test sext
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xfffffaa5
+    movi    a3, 0x000000a5
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000055a
+    movi    a3, 0xffffff5a
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0xffff5a5a
+    movi    a3, 0x00005a5a
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000a5a5
+    movi    a3, 0xffffa5a5
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x00055a5a
+    movi    a3, 0xffff5a5a
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x000aa5a5
+    movi    a3, 0x0000a5a5
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x005a5a5a
+    movi    a3, 0xffda5a5a
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+
+    movi    a2, 0xffa5a5a5
+    movi    a3, 0x0025a5a5
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+test_end
+
+test sext_same_rs
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_shift.S b/tests/xtensa/test_shift.S
new file mode 100644 (file)
index 0000000..a8e4364
--- /dev/null
@@ -0,0 +1,206 @@
+.include "macros.inc"
+
+test_suite shift
+
+.macro test_shift prefix, dst, src, v, imm
+    \prefix\()_set \dst, \src, \v, \imm
+    \prefix\()_ver \dst, \v, \imm
+.endm
+
+.macro test_shift_sd prefix, v, imm
+    test_shift \prefix, a3, a2, \v, \imm
+    test_shift \prefix, a2, a2, \v, \imm
+.endm
+
+.macro tests_imm_shift prefix, v
+    test_shift_sd \prefix, \v, 1
+    test_shift_sd \prefix, \v, 2
+    test_shift_sd \prefix, \v, 7
+    test_shift_sd \prefix, \v, 8
+    test_shift_sd \prefix, \v, 15
+    test_shift_sd \prefix, \v, 16
+    test_shift_sd \prefix, \v, 31
+.endm
+
+.macro tests_shift prefix, v
+    test_shift_sd \prefix, \v, 0
+    tests_imm_shift \prefix, \v
+    test_shift_sd \prefix, \v, 32
+.endm
+
+
+.macro slli_set dst, src, v, imm
+    movi    \src, \v
+    slli    \dst, \src, \imm
+.endm
+
+.macro slli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) << (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test slli
+    tests_imm_shift slli, 0xa3c51249
+test_end
+
+
+.macro srai_set dst, src, v, imm
+    movi    \src, \v
+    srai    \dst, \src, \imm
+.endm
+
+.macro srai_ver dst, v, imm
+    mov     a2, \dst
+    .if (\imm)
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff) | \
+                ~((((\v) & 0x80000000) >> ((\imm) - 1)) - 1)
+    .else
+    movi    a3, \v
+    .endif
+    assert  eq, a2, a3
+.endm
+
+test srai
+    tests_imm_shift srai, 0x49a3c512
+    tests_imm_shift srai, 0xa3c51249
+test_end
+
+
+.macro srli_set dst, src, v, imm
+    movi    \src, \v
+    srli    \dst, \src, \imm
+.endm
+
+.macro srli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff)
+    assert  eq, a2, a3
+.endm
+
+test srli
+    tests_imm_shift srli, 0x49a3c512
+    tests_imm_shift srli, 0xa3c51249
+test_end
+
+
+.macro sll_set dst, src, v, imm
+    movi    a2, \imm
+    ssl     a2
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_sar_set dst, src, v, imm
+    movi    a2, 32 - \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_ver dst, v, imm
+    slli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sll_sar_ver dst, v, imm
+    slli_ver \dst, \v, \imm
+.endm
+
+test sll
+    tests_shift sll, 0xa3c51249
+    tests_shift sll_sar, 0xa3c51249
+test_end
+
+
+.macro srl_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_ver dst, v, imm
+    srli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro srl_sar_ver dst, v, imm
+    srli_ver \dst, \v, \imm
+.endm
+
+test srl
+    tests_shift srl, 0xa3c51249
+    tests_shift srl_sar, 0xa3c51249
+    tests_shift srl, 0x49a3c512
+    tests_shift srl_sar, 0x49a3c512
+test_end
+
+
+.macro sra_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_ver dst, v, imm
+    srai_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sra_sar_ver dst, v, imm
+    srai_ver \dst, \v, \imm
+.endm
+
+test sra
+    tests_shift sra, 0xa3c51249
+    tests_shift sra_sar, 0xa3c51249
+    tests_shift sra, 0x49a3c512
+    tests_shift sra_sar, 0x49a3c512
+test_end
+
+
+.macro src_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_ver dst, v, imm
+    src_sar_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro src_sar_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) >> (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test src
+    tests_shift src, 0xa3c51249215c3a94
+    tests_shift src_sar, 0xa3c51249215c3a94
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S
new file mode 100644 (file)
index 0000000..1041cc6
--- /dev/null
@@ -0,0 +1,178 @@
+.include "macros.inc"
+
+test_suite timer
+
+test ccount
+    rsr     a3, ccount
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 1
+test_end
+
+test ccompare
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    loop    a3, 1f
+    rsr     a3, interrupt
+    bnez    a3, 2f
+1:
+    test_fail
+2:
+test_end
+
+test ccompare0_interrupt
+    set_vector kernel, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+
+    movi    a2, 0x40
+    wsr     a2, intenable
+    rsil    a2, 0
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
+test_end
+
+test ccompare1_interrupt
+    set_vector level3, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare0
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare1
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x400
+    wsr     a2, intenable
+    rsil    a2, 2
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test ccompare2_interrupt
+    set_vector level5, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare2
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x2000
+    wsr     a2, intenable
+    rsil    a2, 4
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test ccompare_interrupt_masked
+    set_vector kernel, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare2
+
+    movi    a3, 40
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare1
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+
+    movi    a2, 0x40
+    wsr     a2, intenable
+    rsil    a2, 0
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
+test_end
+
+test ccompare_interrupt_masked_waiti
+    set_vector kernel, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    movi    a2, 0
+    wsr     a2, ccompare2
+
+    movi    a3, 40
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare1
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+
+    movi    a2, 0x40
+    wsr     a2, intenable
+    waiti   0
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_windowed.S b/tests/xtensa/test_windowed.S
new file mode 100644 (file)
index 0000000..cb2d39e
--- /dev/null
@@ -0,0 +1,302 @@
+.include "macros.inc"
+
+test_suite windowed
+
+.altmacro
+
+.macro reset_window start
+    movi    a2, 0xff
+    wsr     a2, windowstart
+    rsync
+    movi    a2, 0
+    wsr     a2, windowbase
+    rsync
+    movi    a2, \start
+    wsr     a2, windowstart
+    rsync
+.endm
+
+.macro overflow_test shift, window, probe_ok, probe_ex
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    movi    a2, 1 | (((1 << ((\window) / 4)) | 1) << ((\shift) / 4))
+    wsr     a2, windowstart
+    reset_ps
+
+    mov     a2, a\probe_ok
+    set_vector window_overflow_\window, 10f
+1:
+    mov     a2, a\probe_ex
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, windowbase
+    movi    a3, (\shift) / 4
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rfwo
+    test_fail
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    movi    a3, 1 | ((1 << ((\window) / 4)) << ((\shift) / 4))
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+.endm
+
+.macro overflow_tests shift, window, probe
+    .if \probe < 15
+    overflow_test \shift, \window, %((\shift) - 1), \probe
+    overflow_tests \shift, \window, %((\probe) + 1)
+    .endif
+.endm
+
+.macro all_overflow_tests
+    .irp shift, 4, 8, 12
+    .irp window, 4, 8, 12
+    overflow_tests \shift, \window, \shift
+    .endr
+    .endr
+.endm
+
+test overflow
+    all_overflow_tests
+test_end
+
+
+.macro underflow_test window
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    set_vector window_underflow_\window, 10f
+
+    reset_window 1
+    reset_ps
+
+    ssai    2
+    movi    a2, 2f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+1:
+    retw
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  eqi, a2, 1
+    rfwu
+2:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    assert  bsi, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test underflow
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    underflow_test 4
+    underflow_test 8
+    underflow_test 12
+test_end
+
+
+.macro retw_test window
+    reset_window %(1 | (1 << (8 - (\window) / 4)))
+    reset_ps
+
+    ssai    2
+    movi    a2, 1f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+    retw
+    test_fail
+1:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  bci, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test retw
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    retw_test 4
+    retw_test 8
+    retw_test 12
+test_end
+
+test movsp
+    set_vector kernel, 2f
+
+    reset_window 1
+    reset_ps
+1:
+    movsp   a2, a3
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 5
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+
+    set_vector kernel, 0
+
+    reset_window 0x81
+    reset_ps
+
+    movsp   a2, a3
+test_end
+
+test rotw
+    reset_window 0x4b
+    reset_ps
+
+    movi    a3, 0x10
+
+    rotw    1
+    rsr     a2, windowbase
+    assert  eqi, a2, 1
+    movi    a3, 0x11
+    movi    a7, 0x12
+
+    rotw    2
+    rsr     a2, windowbase
+    assert  eqi, a2, 3
+    movi    a3, 0x13
+    movi    a7, 0x14
+    movi    a11, 0x15
+
+    rotw    3
+    rsr     a2, windowbase
+    assert  eqi, a2, 6
+    movi    a3, 0x16
+    movi    a7, 0x17
+
+    movi    a2, 0x44
+    wsr     a2, windowstart
+    rsync
+
+    movi    a2, 0x10
+    assert  eq, a2, a11
+    movi    a11, 0x18
+    movi    a2, 0x11
+    assert  eq, a2, a15
+    movi    a15, 0x19
+
+    rotw    4
+    movi    a2, 0x12
+    assert  eq, a2, a3
+    movi    a2, 0x13
+    assert  eq, a2, a7
+    movi    a2, 0x14
+    assert  eq, a2, a11
+    movi    a2, 0x15
+    assert  eq, a2, a15
+
+    movi    a2, 0x5
+    wsr     a2, windowstart
+    rsync
+
+    rotw    -2
+    movi    a2, 0x18
+    assert  eq, a2, a3
+    movi    a2, 0x19
+    assert  eq, a2, a7
+test_end
+
+.macro callw_test window
+    call\window 2f
+1:
+    test_fail
+    .align  4
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, ps
+    movi    a3, 0x4000f | ((\window) << 14)
+    assert  eq, a2, a3
+    movi    a2, 1b
+    slli    a2, a2, 2
+    ssai    2
+    movi    a3, (\window) / 4
+    src     a2, a3, a2
+    assert  eq, a2, a\window
+.endm
+
+test callw
+    reset_window 0x1
+    reset_ps
+
+    callw_test 4
+    callw_test 8
+    callw_test 12
+test_end
+
+
+.macro entry_test window
+    reset_window 0x1
+    reset_ps
+    movi    a2, 0x4000f | ((\window) << 14)
+    wsr     a2, ps
+    isync
+    movi    a3, 0x12345678
+    j       1f
+    .align  4
+1:
+    entry   a3, 0x5678
+    movi    a2, 0x12340000
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, (\window) / 4
+    rsr     a2, windowstart
+    movi    a3, 1 | (1 << ((\window) / 4))
+    assert  eq, a2, a3
+    rotw    -(\window) / 4
+.endm
+
+test entry
+    entry_test 4
+    entry_test 8
+    entry_test 12
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/vectors.S b/tests/xtensa/vectors.S
new file mode 100644 (file)
index 0000000..265a181
--- /dev/null
@@ -0,0 +1,39 @@
+.macro vector name
+
+.section .vector.\name
+    j       1f
+.section .vector.\name\().text
+1:
+    wsr     a2, excsave1
+    movi    a2, handler_\name
+    l32i    a2, a2, 0
+    beqz    a2, 1f
+    jx      a2
+1:
+    movi    a3, 1b
+    movi    a2, 1
+    simcall
+
+.align 4
+.global handler_\name
+handler_\name\(): .word 0
+
+.endm
+
+vector window_overflow_4
+vector window_overflow_8
+vector window_overflow_12
+vector window_underflow_4
+vector window_underflow_8
+vector window_underflow_12
+
+vector level2
+vector level3
+vector level4
+vector level5
+vector level6
+vector level7
+
+vector kernel
+vector user
+vector double
diff --git a/tizen/Makefile b/tizen/Makefile
new file mode 100644 (file)
index 0000000..05d761f
--- /dev/null
@@ -0,0 +1,14 @@
+all:
+       cd src && $(MAKE)
+check_hax:
+       cd src && $(MAKE) check_hax
+qemu:
+       cd src && $(MAKE) qemu
+skin_client:
+       cd src && $(MAKE) skin_client
+clean:
+       cd src && $(MAKE) clean
+distclean:
+       cd src && $(MAKE) distclean
+install:
+       cd src && $(MAKE) install
index e615c2c0710156108ce9fe745881b02910da94e9..dbc266c1fb0fe905af92d35c722a1fe90e693734 100755 (executable)
@@ -1,7 +1,4 @@
-#!/bin/sh
+#!/bin/sh -xe
 
-#Build-Depends: bison, flex, autoconf, gcc, libglu1-mesa-dev, libsdl1.2-dev, libgtk2.0-dev, libsdl-image1.2-dev, libsdl-gfx1.2-dev, debhelper, libxml2-dev, libasound2-dev
-
-autoconf
-./configure
-make
+./qemu_configure.sh
+make && make install
diff --git a/tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll b/tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll
new file mode 100755 (executable)
index 0000000..5df5968
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avcodec-52.dll b/tizen/distrib/ffmpeg/bin/avcodec-52.dll
new file mode 100755 (executable)
index 0000000..5df5968
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avcodec-52.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avcodec-52.lib b/tizen/distrib/ffmpeg/bin/avcodec-52.lib
new file mode 100644 (file)
index 0000000..9ab5498
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avcodec-52.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avcodec.dll b/tizen/distrib/ffmpeg/bin/avcodec.dll
new file mode 100755 (executable)
index 0000000..5df5968
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avcodec.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avcodec.lib b/tizen/distrib/ffmpeg/bin/avcodec.lib
new file mode 100644 (file)
index 0000000..9ab5498
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avcodec.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll b/tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll
new file mode 100755 (executable)
index 0000000..103660d
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avdevice-52.dll b/tizen/distrib/ffmpeg/bin/avdevice-52.dll
new file mode 100755 (executable)
index 0000000..103660d
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avdevice-52.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avdevice-52.lib b/tizen/distrib/ffmpeg/bin/avdevice-52.lib
new file mode 100644 (file)
index 0000000..4e7928d
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avdevice-52.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avdevice.dll b/tizen/distrib/ffmpeg/bin/avdevice.dll
new file mode 100755 (executable)
index 0000000..103660d
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avdevice.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avdevice.lib b/tizen/distrib/ffmpeg/bin/avdevice.lib
new file mode 100644 (file)
index 0000000..4e7928d
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avdevice.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll b/tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll
new file mode 100755 (executable)
index 0000000..18aa446
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avformat-52.dll b/tizen/distrib/ffmpeg/bin/avformat-52.dll
new file mode 100755 (executable)
index 0000000..18aa446
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avformat-52.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avformat-52.lib b/tizen/distrib/ffmpeg/bin/avformat-52.lib
new file mode 100644 (file)
index 0000000..25f68cf
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avformat-52.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avformat.dll b/tizen/distrib/ffmpeg/bin/avformat.dll
new file mode 100755 (executable)
index 0000000..18aa446
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avformat.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avformat.lib b/tizen/distrib/ffmpeg/bin/avformat.lib
new file mode 100644 (file)
index 0000000..25f68cf
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avformat.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll b/tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll
new file mode 100755 (executable)
index 0000000..9814cc8
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avutil-50.dll b/tizen/distrib/ffmpeg/bin/avutil-50.dll
new file mode 100755 (executable)
index 0000000..9814cc8
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avutil-50.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avutil-50.lib b/tizen/distrib/ffmpeg/bin/avutil-50.lib
new file mode 100644 (file)
index 0000000..74a0329
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avutil-50.lib differ
diff --git a/tizen/distrib/ffmpeg/bin/avutil.dll b/tizen/distrib/ffmpeg/bin/avutil.dll
new file mode 100755 (executable)
index 0000000..9814cc8
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avutil.dll differ
diff --git a/tizen/distrib/ffmpeg/bin/avutil.lib b/tizen/distrib/ffmpeg/bin/avutil.lib
new file mode 100644 (file)
index 0000000..74a0329
Binary files /dev/null and b/tizen/distrib/ffmpeg/bin/avutil.lib differ
index d976f343baa1b63f49be263bc5c8d4943dcb2eb2..b34c93bc04c6a31871bc42d09616dd1a75daab82 100644 (file)
@@ -57,6 +57,9 @@
  *       and that all newly added little endian formats have pix_fmt&1==0
  *       this allows simpler detection of big vs little endian.
  */
+
+#define PixelFormat FFmpeg_PixelFormat
+
 enum PixelFormat {
     PIX_FMT_NONE= -1,
     PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
index 5a0ce4f453969bf719a72e041d887a78815b0c64..3cce24f6429f05b17c900c74149aec6b45a2b1f6 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavcodec.a and b/tizen/distrib/ffmpeg/lib/libavcodec.a differ
index 307f2dbd920057ae3ecb8bfc72b902785fcddee8..fef341bf5e7fe3af6ea9cde1c17e4d24ad817d6f 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavcodec.dll.a and b/tizen/distrib/ffmpeg/lib/libavcodec.dll.a differ
index 2f362427ef33478b5bd567e93196fd30664cbede..e2709b7b2073956a46f2edea0b9759ad733638a5 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavdevice.a and b/tizen/distrib/ffmpeg/lib/libavdevice.a differ
index c4b0709ffc1c9c3c889e788dfa38f956d446c3b2..784bdd47f11b42e2e0d343fda2c72fe16196ee16 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavdevice.dll.a and b/tizen/distrib/ffmpeg/lib/libavdevice.dll.a differ
index 2fc6595ffb380071d5f4fc1c1784d1bd62008e47..88a04a8e780b009934d0324dbcb305dfef0543d2 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavformat.a and b/tizen/distrib/ffmpeg/lib/libavformat.a differ
index ecb47b74f8222ee38766cfd003df57a7452fd09c..15a0f60d6f26d3af151e7b79d8e3f5da283b465f 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavformat.dll.a and b/tizen/distrib/ffmpeg/lib/libavformat.dll.a differ
index 4787c4683383e5eaddbc6a8f3b74c4adab2443a4..d2cce641af0348a80933f4a294357b32d592cc87 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavutil.a and b/tizen/distrib/ffmpeg/lib/libavutil.a differ
index 8ce40ab946cecff5f1324d401768d7e87d6a6529..464d8ec8cd1e85bea94472bb5a5ab6ea73cfd477 100644 (file)
Binary files a/tizen/distrib/ffmpeg/lib/libavutil.dll.a and b/tizen/distrib/ffmpeg/lib/libavutil.dll.a differ
index d976f343baa1b63f49be263bc5c8d4943dcb2eb2..b34c93bc04c6a31871bc42d09616dd1a75daab82 100644 (file)
@@ -57,6 +57,9 @@
  *       and that all newly added little endian formats have pix_fmt&1==0
  *       this allows simpler detection of big vs little endian.
  */
+
+#define PixelFormat FFmpeg_PixelFormat
+
 enum PixelFormat {
     PIX_FMT_NONE= -1,
     PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
index d396440a5f8fdb497ff680d39157e9962ab4449c..2043a14bda45366b0f6853d298232648c80b639c 100755 (executable)
@@ -1,13 +1,11 @@
 #!/bin/sh
-
 TARGET_OS=`uname -s`
-echo "$TARGET_OS"
 
 case $TARGET_OS in
 Linux*)
-./configure --prefix=./ --arch=x86 --enable-static --enable-pic --enable-optimizations --disable-doc --disable-gpl  --disable-postproc --disable-swscale --disable-mmx --enable-neon --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2
+./configure --prefix=./ --arch=x86 --enable-static --enable-pic --enable-optimizations --disable-doc --disable-gpl --disable-postproc --disable-swscale --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2
 ;;
 MINGW*)
-./configure --prefix=./ --arch=x86 --enable-shared --disable-static --enable-optimizations --disable-doc --disable-gpl  --disable-postproc --disable-swscale --disable-mmx --enable-neon --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2
+./configure --prefix=./ --arch=x86 --enable-shared --disable-static --enable-optimizations --enable-memalign-hack --disable-doc --disable-gpl  --disable-postproc --disable-swscale --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2
 ;;
 esac
diff --git a/tizen/qemu_configure.sh b/tizen/qemu_configure.sh
new file mode 100755 (executable)
index 0000000..1a0d421
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+# OS specific
+#--target-list=i386-softmmu,arm-softmmu \
+targetos=`uname -s`
+
+cd ..
+case $targetos in
+Linux*)
+echo "checking for os... targetos $targetos"
+exec ./configure \
+ --target-list=i386-softmmu \
+ --disable-werror \
+ --audio-drv-list=alsa \
+ --enable-mixemu \
+ --disable-vnc-tls \
+ --audio-card-list=ac97 \
+ --enable-ldst-optimization \
+ --enable-maru \
+ --enable-gl
+# --enable-ffmpeg
+# --enable-v4l2 \
+# --enable-debug \
+# --enable-profiler \
+# --enable-gles2 --gles2dir=/usr
+;;
+MINGW*)
+echo "checking for os... targetos $targetos"
+exec ./configure \
+ --target-list=i386-softmmu \
+ --audio-drv-list=winwave \
+ --enable-mixemu \
+ --disable-vnc-tls \
+ --audio-card-list=ac97 \
+ --enable-ldst-optimization \
+ --enable-hax \
+ --enable-maru \
+ --enable-gl
+# --enable-ffmpeg
+# --disable-vnc-jpeg \
+# --disable-jpeg
+;;
+esac
diff --git a/tizen/src/Makefile b/tizen/src/Makefile
new file mode 100755 (executable)
index 0000000..9dd944c
--- /dev/null
@@ -0,0 +1,68 @@
+EMUL_DIR=../Emulator
+
+ifneq ($(wildcard ../../config-host.mak),)
+include ../../config-host.mak
+else
+config-host.mak:
+       @echo "Please call configure before running make!"
+       @exit 1
+endif
+
+all: build_info qemu skin_client check_hax
+qemu:
+       cd ../../ && $(MAKE)
+check_hax:
+ifdef CONFIG_WIN32
+       $(CC) -o check-hax.exe check_hax.c
+else
+       
+endif
+skin_client:
+ifdef CONFIG_WIN32
+       ant -buildfile skin/client/build.xml windows-jar
+else
+ifdef CONFIG_LINUX
+       ant -buildfile skin/client/build.xml linux-jar
+else
+ifdef CONFIG_DARWIN
+       ant -buildfile skin/client/build.xml mac-jar
+endif
+endif
+endif
+build_info:
+       @echo "/* Automatically generated by Makefile - do not modify! */" > build_info.h
+       @echo "const char build_version[] = \"`cat VERSION`\";" >> build_info.h
+       @echo "const char build_date[] = \"`date +"%F %T %Z"`\";" >> build_info.h
+       @echo "const char pkginfo_version[] = \"`sed -n '2p' ./../../package/pkginfo.manifest`\";" >> build_info.h
+
+clean:
+ifdef CONFIG_WIN32
+       rm -f check-hax.exe
+else
+       
+endif
+       cd ../../ && $(MAKE) clean
+distclean:
+       cd ../../ && $(MAKE) distclean
+install: all
+       mkdir -p $(EMUL_DIR)/bin
+       mkdir -p $(EMUL_DIR)/etc
+       mkdir -p $(EMUL_DIR)/x86 
+       mkdir -p $(EMUL_DIR)/x86/data 
+       mkdir -p $(EMUL_DIR)/arm
+       mkdir -p $(EMUL_DIR)/x86/data/pc-bios
+       cp ../../i386-softmmu/qemu-system-i386 $(EMUL_DIR)/bin/emulator-x86
+       cp skin/client/emulator-skin.jar $(EMUL_DIR)/bin
+ifdef CONFIG_WIN32
+       cp check-hax.exe $(EMUL_DIR)/bin
+else
+       
+endif
+       cp ../../qemu-img $(EMUL_DIR)/bin
+       cp -dpr skin/client/skins $(EMUL_DIR)
+       cp -dpr ../license $(EMUL_DIR)
+       cp -dpr ../../pc-bios/bios.bin $(EMUL_DIR)/x86/data/pc-bios
+       cp -dpr ../../pc-bios/linuxboot.bin $(EMUL_DIR)/x86/data/pc-bios
+       cp -dpr ../../pc-bios/pxe-rtl8139.rom $(EMUL_DIR)/x86/data/pc-bios
+       cp -dpr ../../pc-bios/pxe-virtio.rom $(EMUL_DIR)/x86/data/pc-bios
+       cp -dpr ../../pc-bios/vgabios-maruvga.bin $(EMUL_DIR)/x86/data/pc-bios
diff --git a/tizen/src/Makefile.tizen b/tizen/src/Makefile.tizen
new file mode 100755 (executable)
index 0000000..d6c59d3
--- /dev/null
@@ -0,0 +1,102 @@
+# Makefile.tizen
+# for TIZEN-maru board
+
+
+$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/tizen/src:$(SRC_PATH)/tizen/src/hw:$(SRC_PATH)/tizen/src/skin)
+
+QEMU_CFLAGS += -I$(SRC_PATH)/hw -I$(SRC_PATH)/tizen/src
+QEMU_CFLAGS += -I$(SRC_PATH)/tizen/distrib/ffmpeg/include
+QEMU_CFLAGS += -L$(SRC_PATH)/tizen/distrib/ffmpeg/lib
+QEMU_CFLAGS += $(SDL_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
+CFLAGS += -g -O2
+
+ifdef CONFIG_WIN32
+LIBS += -lavformat -lavcodec -lavutil -lm
+else
+LIBS += -lavformat -lavcodec -lavutil -lm -lGL
+endif
+
+ifdef CONFIG_DEBUG_EXEC
+GL_CFLAGS := -Wall -g -O0 -fno-strict-aliasing
+else
+GL_CFLAGS := -Wall -g -O2 -fno-strict-aliasing
+endif
+
+ifndef CONFIG_WIN32
+###########################################################
+## Build openGL
+# i386
+ifeq ($(TARGET_ARCH), i386)
+
+GL_CUR_PATH = $(SRC_PATH)/tizen/src/hw
+
+GL_CFLAGS += -I$(GL_CUR_PATH) -I$(SRC_PATH)/fpu -I$(SRC_PATH)/$(TARGET_DIRS) $(QEMU_CFLAGS) $(CFLAGS)
+
+parse_gl_h: parse_gl_h.c
+       $(CC) -g -o $@ $<
+server_stub.c: parse_gl_h
+       ./parse_gl_h 2>/dev/null
+gl_func.h: parse_gl_h
+       ./parse_gl_h 2>/dev/null
+opengl_func.h: gl_func.h
+helper_opengl.o: helper_opengl.c opengl_func.h server_stub.c opengl_process.h
+       $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< 
+gl_beginend.h: $(GL_CUR_PATH)/beginend_funcs.sh
+       $< > $@
+mesa_mipmap.o : mesa_mipmap.c
+       $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< 
+opengl_exec.o : opengl_exec.c server_stub.c opengl_func.h gl_beginend.h opengl_process.h mesa_mipmap.o
+       $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< 
+
+endif #($(TARGET_ARCH), i386)
+###########################################################
+endif #CONFIG_WIN32
+       
+# maru loader
+obj-y += emulator.o emul_state.o option.o
+
+# maru display
+obj-y += maru_sdl.o sdl_rotate.o maru_finger.o
+
+# sdb
+obj-y += sdb.o
+
+# mloop event
+obj-y += mloop_event.o
+
+# debug channel
+obj-y += debug_ch.o
+
+# maru hardware
+obj-i386-y += maru_board.o
+obj-i386-y += maru_overlay.o
+obj-i386-y += maru_codec.o
+obj-i386-y += maru_pm.o
+obj-i386-y += maru_vga.o
+obj-i386-y += maru_brightness.o
+obj-i386-y += maru_touchscreen.o
+obj-i386-$(CONFIG_PCI) += maru_camera_common_pci.o
+obj-i386-$(CONFIG_LINUX) += maru_camera_linux_pci.o
+obj-i386-$(CONFIG_WIN32) += maru_camera_win32_pci.o
+ifdef CONFIG_LINUX # libs for maru camera on linux host
+LIBS += -lv4l2 -lv4lconvert
+endif
+
+ifdef CONFIG_WIN32 # libs for maru camera on windows host
+LIBS += -lole32 -loleaut32 -luuid -lstrmiids
+endif
+
+
+# maru skin
+obj-i386-y += maruskin_client.o maruskin_server.o maruskin_operation.o maruskin_keymap.o
+
+# guest server
+obj-i386-y += guest_server.o 
+
+ifndef CONFIG_WIN32
+###########################################################
+## opengl library for i386
+obj-i386-y += virtio-gl.o helper_opengl.o opengl_exec.o mesa_mipmap.o gloffscreen_common.o gloffscreen_xcomposite.o gloffscreen_wgl.o gloffscreen_test.o
+###########################################################
+endif
index ac3ef0775f4b6ab31b192df7dcf0a95cc33fac96..c5f46e8dd3c20f38c95dfa01c7671c67c8756257 100644 (file)
@@ -1 +1 @@
-Tizen SDK Beta
+1.0 Larkspur
diff --git a/tizen/src/check_hax.c b/tizen/src/check_hax.c
new file mode 100644 (file)
index 0000000..2ca1de3
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * check if hax is available. reference:target-i386/hax-all.c
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <windows.h>
+#include <winioctl.h>
+
+#define HAX_DEVICE_TYPE 0x4000
+#define HAX_IOCTL_CAPABILITY    CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_MAX_VCPU 0x10
+
+#define HAX_CAP_STATUS_NOTWORKING  0x0
+#define HAX_CAP_WORKSTATUS_MASK 0x1
+#define HAX_CAP_FAILREASON_VT   0x1
+#define HAX_CAP_FAILREASON_NX   0x2
+
+#define HAX_CAP_MEMQUOTA    0x2
+
+typedef HANDLE hax_fd;
+
+struct hax_vm {
+    hax_fd fd;
+    int id;
+    struct hax_vcpu_state *vcpus[HAX_MAX_VCPU];
+};
+
+struct hax_state {
+    hax_fd fd; /* the global hax device interface */
+    uint32_t version;
+    struct hax_vm *vm;
+    uint64_t mem_quota;
+};
+
+struct hax_capabilityinfo {
+    /* bit 0: 1 - working
+     *        0 - not working, possibly because NT/NX disabled
+     * bit 1: 1 - memory limitation working
+     *        0 - no memory limitation
+     */
+    uint16_t wstatus;
+    /* valid when not working
+     * bit 0: VT not enabeld
+     * bit 1: NX not enabled*/
+    uint16_t winfo;
+    uint32_t pad;
+    uint64_t mem_quota;
+};
+
+static inline int hax_invalid_fd( hax_fd fd ) {
+    return ( fd == INVALID_HANDLE_VALUE );
+}
+
+static hax_fd hax_mod_open( void );
+static int hax_open_device( hax_fd *fd );
+static int hax_get_capability( struct hax_state *hax );
+static int hax_capability( struct hax_state *hax, struct hax_capabilityinfo *cap );
+
+static int check_hax( void ) {
+
+    struct hax_state hax;
+    memset( &hax, 0, sizeof( struct hax_state ) );
+
+    hax.fd = hax_mod_open();
+
+    int ret_fd = hax_invalid_fd( hax.fd );
+    if ( ret_fd ) {
+        fprintf( stderr, "Invalid fd:%d\n", ret_fd );
+        return ret_fd;
+    }
+
+    int ret_cap = hax_get_capability( &hax );
+    if ( ret_cap ) {
+        fprintf( stderr, "Not capable:%d\n", ret_cap );
+        return ret_cap;
+    }
+
+    return 0;
+
+}
+
+static hax_fd hax_mod_open( void ) {
+    int ret;
+    hax_fd fd;
+
+    ret = hax_open_device( &fd );
+    if ( ret != 0 ) {
+        fprintf( stderr, "Open HAX device failed\n" );
+    }
+
+    return fd;
+}
+
+static int hax_open_device( hax_fd *fd ) {
+    uint32_t errNum = 0;
+    HANDLE hDevice;
+
+    if ( !fd )
+        return -2;
+
+    hDevice = CreateFile( "\\\\.\\HAX", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+        NULL );
+
+    if ( hDevice == INVALID_HANDLE_VALUE ) {
+        fprintf( stderr, "Failed to open the HAX device!\n" );
+        errNum = GetLastError();
+        if ( errNum == ERROR_FILE_NOT_FOUND )
+            return -1;
+        return -2;
+    }
+    *fd = hDevice;
+    fprintf( stdout, "device fd:%d\n", *fd );
+    return 0;
+}
+
+static int hax_get_capability( struct hax_state *hax ) {
+    int ret;
+    struct hax_capabilityinfo capinfo, *cap = &capinfo;
+
+    ret = hax_capability( hax, cap );
+    if ( ret )
+        return ret;
+
+    if ( ( ( cap->wstatus & HAX_CAP_WORKSTATUS_MASK ) == HAX_CAP_STATUS_NOTWORKING ) ) {
+        if ( cap->winfo & HAX_CAP_FAILREASON_VT )
+            fprintf( stderr, "VTX feature is not enabled. which will cause HAX driver not working.\n" );
+        else if ( cap->winfo & HAX_CAP_FAILREASON_NX )
+            fprintf( stderr, "NX feature is not enabled, which will cause HAX driver not working.\n" );
+        return -ENXIO;
+    }
+
+/*
+    if ( cap->wstatus & HAX_CAP_MEMQUOTA ) {
+        if ( cap->mem_quota < hax->mem_quota ) {
+            fprintf( stderr, "The memory needed by this VM exceeds the driver limit.\n" );
+            return -ENOSPC;
+        }
+    }
+*/
+    return 0;
+}
+
+static int hax_capability( struct hax_state *hax, struct hax_capabilityinfo *cap ) {
+    int ret;
+    HANDLE hDevice = hax->fd; //handle to hax module
+    DWORD dSize = 0;
+    DWORD err = 0;
+
+    if ( hax_invalid_fd( hDevice ) ) {
+        fprintf( stderr, "Invalid fd for hax device!\n" );
+        return -ENODEV;
+    }
+
+    ret = DeviceIoControl( hDevice, HAX_IOCTL_CAPABILITY, NULL, 0, cap, sizeof( *cap ), &dSize, ( LPOVERLAPPED ) NULL );
+
+    if ( !ret ) {
+        err = GetLastError();
+        if ( err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA )
+            fprintf( stderr, "hax capability is too long to hold.\n" );
+        fprintf( stderr, "Failed to get Hax capability:%d\n", err );
+        return -EFAULT;
+    } else
+        return 0;
+
+}
+
+int main(int argc, char* argv[]) {
+    return check_hax();
+}
index 4c6ff8b9cdb7ae673d7af249e338d3686fdb9f6d..7c2e372b192c6e014df21c960de2c9b3fd6c89eb 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include <unistd.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <errno.h>
+#endif
+
+#include "emulator.h"
 #include "debug_ch.h"
-#include "fileio.h"
 
-extern STARTUP_OPTION startup_option;
-static char logfile[256] = { 0, };
-static char debugchfile[256] = {0, };
+// DEBUGCH file is located in binary directory.
+char bin_dir[256] = {0,};
+
+static char logpath[512] = {0,};
+static char debugchfile[512] = {0, };
+#ifdef _WIN32
+static HANDLE handle;
+#endif
+
+void set_log_path(char *path)
+{
+    strcpy(logpath, path);
+}
+
 static inline int interlocked_xchg_add( int *dest, int incr )
 {
        int ret;
@@ -72,6 +90,7 @@ unsigned char _dbg_get_channel_flags( struct _debug_channel *channel )
                debug_init();
 
        if(nb_debug_options){
+                       
                struct _debug_channel *opt;
 
                /* first check for multi channel */
@@ -257,8 +276,23 @@ static void debug_init(void)
                return;  /* already initialized */
 
        nb_debug_options = 0;
+
+#if 0
        strcpy(debugchfile, get_etc_path());
        strcat(debugchfile, "/DEBUGCH");
+#endif
+
+    if ( 0 == strlen( bin_dir ) ) {
+        strcpy( debugchfile, "DEBUGCH" );
+    } else {
+        strcat( debugchfile, bin_dir );
+#ifdef _WIN32
+        strcat( debugchfile, "\\" );
+#else
+        strcat( debugchfile, "/" );
+#endif
+        strcat( debugchfile, "DEBUGCH" );
+    }
 
        fp= fopen(debugchfile, "r");
        if( fp == NULL){
@@ -288,12 +322,19 @@ static void debug_init(void)
        if( tmp != NULL ){
                free(tmp);
        }
-
-       strcpy(logfile, get_virtual_target_log_path(startup_option.vtm));
-       strcat(logfile, EMUL_LOGFILE);
-
-       if(access(logfile, F_OK | R_OK) == 0)
-               remove(logfile);
+       
+#ifdef _WIN32
+       handle = CreateFile(logpath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+               if (handle == INVALID_HANDLE_VALUE) {
+                       fprintf(stderr, "logfile can't open: %s\n", GetLastError());
+                       exit(1);
+               }
+#else
+       if(access(logpath, F_OK | R_OK) == 0) {
+               remove(logpath);
+       }
+#endif
 }
 
 /* allocate some tmp string space */
@@ -337,7 +378,7 @@ static int dbg_vprintf( const char *format, va_list args )
        sprintf(txt, "%s", tmp);
 
        // unlock
-       if ((fp = fopen(logfile, "a+")) == NULL) {
+       if ((fp = fopen(logpath, "a+")) == NULL) {
                fprintf(stdout, "Emulator can't open.\n"
                                "Please check if "
                                "this binary file is running on the right path.\n");
@@ -399,7 +440,6 @@ int dbg_log( enum _debug_class cls, struct _debug_channel *channel,
        int ret = 0;
        char buf[2048];
        va_list valist;
-       FILE *fp;
        
        if (!(_dbg_get_channel_flags( channel ) & (1 << cls)))
                return -1;
@@ -414,18 +454,26 @@ int dbg_log( enum _debug_class cls, struct _debug_channel *channel,
        va_start(valist, format);
        ret += vsnprintf(buf + ret, sizeof(buf) - ret, format, valist );
        va_end(valist);
-
-       if ((fp = fopen(logfile, "a+")) == NULL) {
-               fprintf(stdout, "Emulator can't open.\n"
-                               "Please check if "
-                               "this binary file is running on the right path.\n");
+#ifdef _WIN32
+       DWORD dwWritten;
+       handle = CreateFile(logpath, FILE_APPEND_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+       if (handle == INVALID_HANDLE_VALUE) {
+                       fprintf(stderr, "logfile can't open: %s\n", GetLastError());
+               exit(1);
+       }
+       
+       WriteFile(handle, buf, strlen(buf), &dwWritten, 0);
+       CloseHandle(handle);
+#else
+       FILE *fp;
+       if ((fp = fopen(logpath, "a+")) == NULL) {
+               fprintf(stderr, "logfile can't open: %s\n", strerror(errno));
                exit(1);
        }
        fprintf(fp,"%s", buf);
-//     fputs(buf, fp);
        fclose(fp);
-//     ret = fprintf(logfile, "%s\n", buf);
-//     fflush(stderr);
+#endif
 
        return ret;
 }
index ed8c27ea1299ab779aac31fe1d9e47c42234e1a5..298b7c5bf9e855f008dbf177320858be336e158d 100644 (file)
@@ -33,7 +33,7 @@
 
 #include <sys/types.h>
 
-//#define NO_DEBUG
+// #define NO_DEBUG
 
 #ifdef __cplusplus
 extern "C" {
@@ -57,6 +57,8 @@ struct _debug_channel
        char multiname[15];
 };
 
+void set_log_path(char *path);
+
 #ifndef NO_DEBUG
 #define MSGSIZE_MAX 2048
 #define __GET_DEBUGGING_FIXME(dbch) ((dbch)->flags & (1 << __DBCL_FIXME))
@@ -93,6 +95,9 @@ struct _debug_channel
         (dbg_log(__DBCL##dbcl,(dbch), "") == -1)) ? \
 (void)0 : (void)dbg_printf
 */
+
+extern char bin_dir[256];
+
 extern unsigned char _dbg_get_channel_flags( struct _debug_channel *channel );
 extern int _dbg_set_channel_flags( struct _debug_channel *channel,
                unsigned char set, unsigned char clear );
diff --git a/tizen/src/emul_state.c b/tizen/src/emul_state.c
new file mode 100644 (file)
index 0000000..a455bdb
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Emulator
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "emul_state.h"
+#include "debug_ch.h"
+
+#if defined( __linux__)
+#include <X11/XKBlib.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+MULTI_DEBUG_CHANNEL(qemu, emul_state);
+
+
+static EmulatorConfigInfo _emul_info;
+static EmulatorConfigState _emul_state;
+
+/* start_skin_client or not ? */
+void set_emul_skin_enable(int enable)
+{
+    _emul_info.skin_enable = enable;
+}
+
+int get_emul_skin_enable(void)
+{
+    return _emul_info.skin_enable;
+}
+
+/* current emulator condition */
+int get_emulator_condition(void)
+{
+    return _emul_state.emulator_condition;
+}
+
+void set_emulator_condition(int state)
+{
+    _emul_state.emulator_condition = state;
+}
+
+/* lcd screen size */
+void set_emul_lcd_size(int width, int height)
+{
+    _emul_info.lcd_size_w = width;
+    _emul_info.lcd_size_h = height;
+
+   INFO("emulator graphic resolution = %dx%d\n", _emul_info.lcd_size_w,  _emul_info.lcd_size_h);
+}
+
+int get_emul_lcd_width(void)
+{
+    return _emul_info.lcd_size_w;
+}
+
+int get_emul_lcd_height(void)
+{
+    return _emul_info.lcd_size_h;
+}
+
+/* sdl bits per pixel */
+void set_emul_sdl_bpp(int bpp)
+{
+    _emul_info.sdl_bpp = bpp;
+
+    if (_emul_info.sdl_bpp != 32) {
+        INFO("?? sdl bpp = %d\n", _emul_info.sdl_bpp);
+    }
+}
+
+int get_emul_sdl_bpp(void)
+{
+    return _emul_info.sdl_bpp;
+}
+
+/* maximum number of touch point */
+void set_emul_max_touch_point(int cnt)
+{
+    if (cnt <= 0) {
+        cnt = 1;
+    }
+    _emul_info.max_touch_point = cnt;
+}
+
+int get_emul_max_touch_point(void)
+{
+    if (_emul_info.max_touch_point <= 0) {
+        set_emul_max_touch_point(1);
+    }
+    return _emul_info.max_touch_point;
+}
+
+/* emulator window scale */
+void set_emul_win_scale(double scale_factor)
+{
+    if (scale_factor < 0.0 || scale_factor > 1.0) {
+        INFO("scale_factor is out of range = %lf\n", scale_factor);
+        scale_factor = 1.0;
+    }
+
+    _emul_state.scale_factor = scale_factor;
+    INFO("emulator window scale_factor = %lf\n", _emul_state.scale_factor);
+}
+
+double get_emul_win_scale(void)
+{
+    return _emul_state.scale_factor;
+}
+
+/* emulator rotation */
+void set_emul_rotation(short rotation_type)
+{
+    if (rotation_type < ROTATION_PORTRAIT || rotation_type > ROTATION_REVERSE_LANDSCAPE) {
+        INFO("rotation type is out of range = %d\n", rotation_type);
+        rotation_type = ROTATION_PORTRAIT;
+    }
+
+    _emul_state.rotation_type = rotation_type;
+    INFO("emulator rotation type = %d\n", _emul_state.rotation_type);
+}
+
+short get_emul_rotation(void)
+{
+    return _emul_state.rotation_type;
+}
+
+/* emulator multi-touch */
+MultiTouchState *get_emul_multi_touch_state(void)
+{
+    return &(_emul_state.qemu_mts);
+}
+
+/* retrieves the status of the host lock key */
+int get_host_lock_key_state(int key)
+{
+#if defined( __linux__)
+    unsigned state = 0;
+    Display *display = XOpenDisplay((char*)0);
+    if (display) {
+        XkbGetIndicatorState(display, XkbUseCoreKbd, &state);
+    }
+    XCloseDisplay(display);
+
+
+    if (key == HOST_CAPSLOCK_KEY) {
+        return (state & 0x01) != 0;
+    } else if (key == HOST_NUMLOCK_KEY) {
+        return (state & 0x02) != 0;
+    }
+
+    return -1;
+#elif defined(_WIN32)
+    int nVirtKey = 0;
+
+    if (key == HOST_CAPSLOCK_KEY) {
+        nVirtKey = VK_CAPITAL;
+    } else if (key == HOST_NUMLOCK_KEY) {
+        nVirtKey = VK_NUMLOCK;
+    }
+
+    return (GetKeyState(nVirtKey) & 1) != 0;
+#endif
+
+    return 0;
+}
+
+/* manage CapsLock key state for usb keyboard input */
+void set_emul_caps_lock_state(int state)
+{
+    _emul_state.qemu_caps_lock = state;
+}
+
+int get_emul_caps_lock_state(void)
+{
+    return  _emul_state.qemu_caps_lock;
+}
+
+/* manage NumLock key state for usb keyboard input */
+void set_emul_num_lock_state(int state)
+{
+    _emul_state.qemu_num_lock = state;
+}
+
+int get_emul_num_lock_state(void)
+{
+    return  _emul_state.qemu_num_lock;
+}
+
+
diff --git a/tizen/src/emul_state.h b/tizen/src/emul_state.h
new file mode 100644 (file)
index 0000000..2018f8a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Emulator
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef __EMUL_STATE_H__
+#define __EMUL_STATE_H__
+
+
+#include "maru_common.h"
+#include "maru_finger.h"
+
+/* keep it consistent with emulator-skin definition */
+enum {
+    HARD_KEY_HOME = 101,
+    HARD_KEY_POWER = 103,
+    HARD_KEY_VOL_UP = 115,
+    HARD_KEY_VOL_DOWN = 114,
+};
+
+/* keep it consistent with emulator-skin definition */
+enum {
+    MOUSE_DOWN = 1,
+    MOUSE_UP = 2,
+    MOUSE_DRAG = 3,
+};
+
+/* keep it consistent with emulator-skin definition */
+enum {
+    KEY_PRESSED = 1,
+    KEY_RELEASED = 2,
+};
+
+/* keep it consistent with emulator-skin definition */
+enum {
+    ROTATION_PORTRAIT = 0,
+    ROTATION_LANDSCAPE = 1,
+    ROTATION_REVERSE_PORTRAIT = 2,
+    ROTATION_REVERSE_LANDSCAPE = 3,
+};
+
+enum {
+    HOST_CAPSLOCK_KEY = 1,
+    HOST_NUMLOCK_KEY = 2,
+};
+
+
+typedef  struct EmulatorConfigInfo {
+    int skin_enable;
+    int lcd_size_w;
+    int lcd_size_h;
+    int sdl_bpp;
+    int max_touch_point;
+    //TODO:
+} EmulatorConfigInfo;
+
+typedef struct EmulatorConfigState {
+    int emulator_condition; //TODO : enum
+    double scale_factor;
+    short rotation_type;
+    MultiTouchState qemu_mts;
+    int qemu_caps_lock;
+    int qemu_num_lock;
+    //TODO:
+} EmulatorConfigState;
+
+
+/* setter */
+void set_emul_skin_enable(int enable);
+void set_emul_lcd_size(int width, int height);
+void set_emul_win_scale(double scale);
+void set_emul_sdl_bpp(int bpp);
+void set_emul_max_touch_point(int cnt);
+void set_emulator_condition(int state);
+void set_emul_rotation(short rotation_type);
+void set_emul_caps_lock_state(int state);
+void set_emul_num_lock_state(int state);
+
+/* getter */
+int get_emul_skin_enable(void);
+int get_emul_lcd_width(void);
+int get_emul_lcd_height(void);
+double get_emul_win_scale(void);
+int get_emul_sdl_bpp(void);
+int get_emul_max_touch_point(void);
+int get_emulator_condition(void);
+short get_emul_rotation(void);
+MultiTouchState *get_emul_multi_touch_state(void);
+int get_host_lock_key_state(int key);
+int get_emul_caps_lock_state(void);
+int get_emul_num_lock_state(void);
+
+
+#endif /* __EMUL_STATE_H__ */
index 8a801c38fc5ba2210ff5066e8d6f8e902f4fbf45..cadfdac020a96de098b814cbaf413722446c1c15 100644 (file)
@@ -1,21 +1,14 @@
-/*
+/* 
  * Emulator
  *
- * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
- * Contact:
- * DoHyung Hong <don.hong@samsung.com>
+ * Contact: 
  * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Hyunjun Son <hj79.son@samsung.com>
- * SangJin Kim <sangjin3.kim@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
  * MunKyu Im <munkyu.im@samsung.com>
- * KiTae Kim <kt920.kim@samsung.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * SungMin Ha <sungmin82.ha@samsung.com>
- * JiHye Kim <jihye1128.kim@samsung.com>
  * GiWoong Kim <giwoong.kim@samsung.com>
  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun <dk77.yun@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  */
 
 
-/**
- * @file     emulator.c
- * @brief    main implementation file of emulator for controling player screen, initialization function, etc.
- * @mainpage emulator for ISE
- * @section  INTRO
- *   program module name: ISE emulator
- *   emulator program can run both standalone and with ISE
- */
-
-#include "emulator.h"
-#include "about_version.h"
-#include "vl.h"
-#include "sensor_server.h"
-#include <assert.h>
-
-/* changes for saving emulator state */
-#ifdef __MINGW32__
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#endif
 #include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <pthread.h>
-
-#ifdef __linux__
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/utsname.h>
-#include <linux/version.h>
-#elif _WIN32
-#include <windows.h>
-#endif
-
-#include "opengl_server.h"
+#include <SDL.h>
+#include "maru_common.h"
+#include "emulator.h"
 #include "sdb.h"
-#include "nbd.h"
+#include "string.h"
+#include "skin/maruskin_server.h"
+#include "skin/maruskin_client.h"
+#include "guest_server.h"
 #include "debug_ch.h"
-
-//DEFAULT_DEBUG_CHANNEL(tizen);
-MULTI_DEBUG_CHANNEL(tizen, main);
-
-#define RCVBUFSIZE 40
-#define MAX_COMMANDS 5
-#define MAX_LENGTH 24
-#define MAX_TIME_STR 100
-
-/* enable opengl_server thread */
-#define ENABLE_OPENGL_SERVER
-
-/* configuration : global variable for saving config file
- * sysinfo : global variable for using in this program
- * startup_option : global variable for loading emulator option
- * */
-
-CONFIGURATION configuration;
-SYSINFO SYSTEMINFO;
-STARTUP_OPTION startup_option;
-PHONEMODELINFO *phone_info;
-VIRTUALTARGETINFO virtual_target_info;
-FILE *g_out_fp;
-FILE *g_err_fp;
-
-UIFLAG UISTATE = {
-    .last_index = -1,
-    .button_press_flag = -1,
-    .key_button_press_flag = 0,
-    .frame_buffer_ctrl = 0,
-    .scale = 1.0,
-    .current_mode = 0,
-    .config_flag = 0,
-    .PID_flag = 0,
-    .is_ei_run = FALSE,
-    .is_em_run = FALSE,
-    .is_gps_run = FALSE,
-    .is_compass_run = FALSE,
-    .is_screenshot_run = FALSE,
-    .sub_window_flag = FALSE,
-    .network_read_flag = FALSE,
-};
-
-int _emulator_condition = 0;
-PHONEMODELINFO PHONE;
-GtkWidget *g_main_window;
-
-GtkWidget *pixmap_widget;
-GtkWidget *fixed;
-#ifdef __linux__
-struct utsname host_uname_buf;
+#include "option.h"
+#include "emul_state.h"
+#include "qemu_socket.h"
+#include "build_info.h"
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#if defined( _WIN32)
+//#include <winsock2.h>
+#elif defined(__linux__)
+#include <linux/version.h>
+#include <sys/utsname.h>
 #endif
 
-/* Widgets for savevm */
-GtkWidget *savevm_window;
-GtkProgressBar *savevm_progress;
-GtkWidget *savevm_label;
-int        vmstate=0;
-int        vmsock=-1;
-int        device_count = 0;
-GIOChannel *channel=NULL;
-
-int get_emulator_condition(void)
-{
-    return _emulator_condition;
-}
+#include "mloop_event.h"
 
-void set_emulator_condition(int state)
-{
-    _emulator_condition = state;
-}
+MULTI_DEBUG_CHANNEL(qemu, main);
 
-struct _arglist {
-    char *argv[QEMUARGC];
-    int argc;
-};
 
-static arglist g_qemu_arglist = {{0,}, 0};
+#define IMAGE_PATH_PREFIX   "file="
+#define IMAGE_PATH_SUFFIX   ",if=virtio"
+#define SDB_PORT_PREFIX     "sdb_port="
+#define LOGS_SUFFIX         "/logs/"
+#define LOGFILE             "emulator.log"
+#define MIDBUF  128
 int tizen_base_port = 0;
-void append_argvlist(arglist* al, const char *fmt, ...)
-{
-    char buf[MAXBUF];
-    va_list va;
 
-    va_start(va, fmt);
-    vsnprintf(buf, sizeof buf, fmt, va);
-    va_end(va);
-    al->argv[al->argc++] = strdup(buf);
-    assert(al->argc < QEMUARGC);
-}
+char tizen_target_path[MAXLEN] = {0, };
+char logpath[MAXLEN] = { 0, };
 
-#ifndef _WIN32
-static GSList* emul_process_list = NULL; /**<linked list of running terminal*/
-pthread_t unfsd_thread;
-#else
-DWORD unfsd_thread;
-#endif
-
-#ifdef ENABLE_OPENGL_SERVER
-pthread_t thread_opengl_id;
-#endif  /* ENABLE_OPENGL_SERVER */
-
-#ifndef _WIN32
+static int skin_argc = 0;
+static char** skin_argv = NULL;
+static int qemu_argc = 0;
+static char** qemu_argv = NULL;
 
-static pthread_mutex_t mutex_emul = PTHREAD_MUTEX_INITIALIZER;
-
-void emulator_mutex_lock(void)
-{
-    pthread_mutex_lock(&mutex_emul);
-}
-
-void emulator_mutex_unlock(void)
-{
-    pthread_mutex_unlock(&mutex_emul);
-}
-
-static void emulator_mutex_init(void)
+void exit_emulator(void)
 {
-}
+    cleanup_multi_touch_state();
 
-#else
-
-static HANDLE mutex_emul;
-
-void emulator_mutex_lock(void)
-{
-    WaitForSingleObject(mutex_emul, INFINITE);
-}
+    mloop_ev_stop();
+    shutdown_skin_server();
+    shutdown_guest_server();
 
-void emulator_mutex_unlock(void)
-{
-    ReleaseMutex(mutex_emul);
+    SDL_Quit();
 }
 
-static void emulator_mutex_init(void)
+static void construct_main_window(int skin_argc, char* skin_argv[], int qemu_argc, char* qemu_argv[] )
 {
-    mutex_emul = CreateMutex(NULL, 0, NULL);
-}
+    INFO("construct main window\n");
 
-#endif
+    start_skin_server( skin_argc, skin_argv, qemu_argc, qemu_argv );
 
-#ifndef _WIN32
-/**
- *     @brief  called when command window closed.
- *     it registered with g_child_watch_add function when creating each process
- *     @param  pid: pid of each process been created by emulator
- *     @param  status: dummy
- *     @param  data: dummy
- *     @see    create_cmdwindow
- */
-static void emul_process_close_handle (GPid pid, gint status, gpointer data)
-{
-    TRACE( "remove pid=%d\n", pid);
-    g_spawn_close_pid (pid);
-    emul_process_list = g_slist_remove(emul_process_list, (gpointer) pid);
-    TRACE( "remove complete pid=%d\n", pid);
-}
+    if (get_emul_skin_enable() == 1) { //this line is check for debugging, etc..
+        if ( 0 > start_skin_client(skin_argc, skin_argv) ) {
+            exit( -1 );
+        }
+    }
 
-/**
-  @brief  send SIGTERM to process
-  @param    data: pid of terminal
-  @user_data: dummy
- */
-static void emul_kill_process(gpointer data, gpointer user_data)
-{
-    WARN( "kill terminal pid=%d\n", (int)data);
-    kill( (pid_t)(gpointer)data, SIGTERM);
+    set_emul_caps_lock_state(0);
+    set_emul_num_lock_state(0);
 }
 
-/**
-  @brief    call emul_kill_process for all the node in emul_process_list
- */
-void emul_kill_all_process(void)
+static void parse_options(int argc, char* argv[], int* skin_argc, char*** skin_argv, int* qemu_argc, char*** qemu_argv)
 {
-    g_slist_foreach(emul_process_list, emul_kill_process, NULL);
-}
-
-/**
-  @brief  create a process
-  @param    data: command of starting process
-  @return success: TRUE
- */
-int emul_create_process(const gchar cmd[])
-{
-    GPid pid = 0;
-    GError* error = NULL;
-    gchar **argv_fork;
-    gint argc_fork;
-    int ret = TRUE;
-
-
-    emulator_mutex_lock();
-
-    g_shell_parse_argv (cmd, &argc_fork, &argv_fork, NULL);
-
-    if (g_spawn_async_with_pipes ("./", argv_fork, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL, NULL, NULL, &error) == TRUE) {
-        emul_process_list = g_slist_append(emul_process_list, (gpointer)pid);
-        g_child_watch_add(pid, emul_process_close_handle, NULL);
-    }
+    int i;
+    int j;
 
-    else {
-        //  ERR( "Error in g_spawn_async\n");
-        ret = FALSE;
+// FIXME !!!
+// TODO:
+   
+    for(i = 1; i < argc; ++i)
+    {
+        if(strncmp(argv[i], "--skin-args", 11) == 0)
+        {
+            *skin_argv = &(argv[i + 1]);
+            break;
+        }
     }
+    for(j = i; j < argc; ++j)
+    {
+        if(strncmp(argv[j], "--qemu-args", 11) == 0)
+        {
+            *skin_argc = j - i - 1;
 
-    g_strfreev (argv_fork);
+            *qemu_argc = argc - j - i + 1;
+            *qemu_argv = &(argv[j]);
 
-    if (error) {
-        //g_error(error->message);
-        ret = FALSE;
+            argv[j] = argv[0];
+        }
     }
-
-    TRACE("create PID = %d\n", pid);
-
-    emulator_mutex_unlock();
-
-    return ret;
-
 }
-#else
-void emul_kill_all_process(void)
-{
 
-}
-int emul_create_process(const gchar cmd[])
-{
-    return TRUE;
-}
-#endif
+static void get_bin_dir( char* exec_argv ) {
 
-#ifdef _WIN32
-void socket_cleanup(void)
-{
-    WSACleanup();
-}
-#endif
-
-int socket_init(void)
-{
-#ifdef _WIN32
-    WSADATA Data;
-    int ret, err;
-
-    ret = WSAStartup(MAKEWORD(2,0), &Data);
-    if (ret != 0) {
-        err = WSAGetLastError();
-        fprintf(stderr, "WSAStartup: %d\n", err);
-        return -1;
+    if ( !exec_argv ) {
+        return;
     }
-    atexit(socket_cleanup);
-#endif
-    return 0;
-}
-
-void exit_emulator_post_process( void ) {
-
-    set_emulator_condition(EMUL_SHUTTING_DOWN);
-
-    free_dbi_file(&PHONE);
 
-    /* 1. emulator and driver destroy */
-    destroy_emulator();
-    INFO( "Emulator Stop: destroy emulator \n");
-
-    /* 2. destroy hash */
-    window_hash_destroy();
-
-    /* 3. quit SDL */
-    //  SDL_Quit();
-
-    /* 4. quit main */
-    gtk_main_quit();
-    INFO( "Emulator Stop: shutdown qemu system, gtk_main quit complete \n");
-
-    /* 5. Flush output */
-    fclose(stdout);
-    fclose(stderr);
-
-    /* 6. close fp which is opened when redirect_log() */
-
-    fclose(g_out_fp);
-    fclose(g_err_fp);
-    INFO( "Close fp which is opened when redirect_log()\n");
-
-#ifdef ENABLE_OPENGL_SERVER
-    pthread_cancel(thread_opengl_id);
-    INFO( "opengl_server thread is quited.\n");
-#endif  /* ENABLE_OPENGL_SERVER */
-
-}
-
-#if 0
-static int send_info_to_emuld(char *send_buf, int buf_size)
-{
-    int   s;
-
-    s = tcp_socket_outgoing("127.0.0.1", (uint16_t)(get_sdb_base_port() + SDB_TCP_EMULD_INDEX));
-    if (s < 0) {
-        TRACE( "can't create socket to talk to the sdb forwarding session \n");
-        TRACE( "[127.0.0.1:%d/tcp] connect fail (%d:%s)\n"
-                , get_sdb_base_port() + SDB_TCP_EMULD_INDEX
-                , errno, strerror(errno)
-             );
-        return -1;
+    char* data = strdup( exec_argv );
+    if ( !data ) {
+        fprintf( stderr, "Fail to strdup for paring a binary directory.\n" );
+        return;
     }
 
-    socket_send(s, "system\n\n\n\n", 10);
-    socket_send(s, &buf_size, 4);
-    socket_send(s, send_buf, buf_size);
-
-    INFO( "send(size: %d) te 127.0.0.1:%d/tcp \n"
-            , buf_size, get_sdb_base_port() + SDB_TCP_EMULD_INDEX);
-
-#ifdef _WIN32
-    closesocket(s);
-#else
-    close(s);
-#endif
-
-    return 1;
-}
-#endif
-
-#if 0
-static void *graceful_shutdown_ftn(void* arg)
-{
-    int i;
-
-    INFO("send command shutdown to emuld \n");
-    send_info_to_emuld("shutdown", 8);
-
-    /* wait 7 seconds */
-    INFO("wait 7 seconds \n");
-    for(i=0; i<7; i++){
+    char* p = NULL;
 #ifdef _WIN32
-        Sleep(1000);
-#else
-        usleep(1000000);
-#endif
+    p = strrchr( data, '\\' );
+    if ( !p ) {
+        p = strrchr( data, '/' );
     }
-
-    INFO("qemu_system_shutdown_request call \n");
-    qemu_system_shutdown_request();
-
-    return 0;
-}
-#endif // #if 0
-
-/**
- * @brief    destroy emulator
- * @param    widget
- * @param    gpointer
- * @date     Nov 20. 2008
- */
-void exit_emulator(void)
-{
-
-#if 1 /* graceful shutdown */
-
-    /* 1st way : long press => power key */
-    ps2kbd_put_keycode( 103 & 0x7f );
-#ifdef _WIN32
-    Sleep( 1.6 * 1000 ); // 1.6 seconds
 #else
-    usleep( 1.6 * 1000 * 1000 ); // 1.6 seconds
+    p = strrchr( data, '/' );
 #endif
-    ps2kbd_put_keycode( 103 | 0x80 );
-    // If user selects 'Yes' in Power off poup, 'qemu_system_shutdown_request' in vl.c is supposed to be called.
-
-#if 0
-    /* 2nd way : send command shutdown to emuld in guest image */
-    pthread_t thread_id;
-    if (pthread_create(&thread_id, NULL, graceful_shutdown_ftn, NULL) != 0) {
-        ERR("pthread_create fail \n");
-        qemu_system_shutdown_request();
+    if ( !p ) {
+        free( data );
+        return;
     }
-#endif
-
-#else
-
-    /* 1. emulator and driver destroy */
-
-    destroy_emulator();
-
-    INFO( "Emulator Stop: destroy emulator \n");
-
-    /* 2. destroy hash */
-
-    window_hash_destroy();
-
-    /* 3. quit SDL */
-
-    //  SDL_Quit();
-
-    /* 4. shutdown qemu system */
 
-    qemu_system_shutdown_request();
+    strncpy( bin_dir, data, strlen( data ) - strlen( p ) );
 
-    /* 5. quit main */
-
-    gtk_main_quit();
-    INFO( "Emulator Stop: shutdown qemu system, gtk_main quit complete \n");
-
-#ifdef ENABLE_OPENGL_SERVER
-    pthread_cancel(thread_opengl_id);
-    INFO( "opengl_server thread is quited.\n");
-#endif  /* ENABLE_OPENGL_SERVER */
-
-    exit(0);
-
-#endif /* graceful shutdown */
+    free( data );
 
 }
 
-#ifdef _WIN32
-/**
-  @brief  enumerates display monitors
-  @param dwData: host screen resolution
-  @return success: TRUE
- */
-static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
+void set_image_and_log_path(char* qemu_argv)
 {
-    RECT *pHostScreen;
-    MONITORINFO mi;
-    mi.cbSize = sizeof(MONITORINFO);
-    GetMonitorInfo(hMonitor, &mi);
-
-    pHostScreen = (RECT *)dwData;
-    pHostScreen->left = MIN(lprcMonitor->left, pHostScreen->left);
-    pHostScreen->top = MIN(lprcMonitor->top, pHostScreen->top);
-    pHostScreen->right = MAX(lprcMonitor->right, pHostScreen->right);
-    pHostScreen->bottom = MAX(lprcMonitor->bottom,pHostScreen->bottom);
-
-    return TRUE;
-}
-#endif
-
-static void construct_main_window(void)
-{
-
-    gchar emul_img_dir[512] = {0,};
-    gchar *name;
-    const gchar *skin;
-    GdkBitmap *SkinMask = NULL;
-    GtkWidget *popup_menu = NULL;
-    GtkWidget *sdl_widget = NULL;
-
-    UISTATE.current_mode = 0;
-
-    /* 1. create main_window without border */
-
-    g_main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    add_window (g_main_window, EMULATOR_ID);
-#if GTK_CHECK_VERSION(2,20,0)
-    gtk_widget_set_can_focus(g_main_window,TRUE);
-#else
-    GTK_WIDGET_SET_FLAGS(g_main_window, GTK_CAN_FOCUS);
-#endif
-    GdkColor color;
-    color.red = color.green = color.blue = 0x8888;
-    gtk_widget_modify_bg(g_main_window, GTK_STATE_NORMAL, &color);
-    INFO("sets the emulator window background color (%x, %x, %x)\n", color.red, color.green, color.blue);
-
-    gtk_window_set_decorated (GTK_WINDOW (g_main_window), FALSE);
-
-    /* 2.1 emulator taskbar icon image */
-
-    skin = get_skin_path();
-    if (skin == NULL) {
-        ERR( "getting skin path is failed!!\n");
-        exit (1);
+    int i;
+    int j = 0;
+    int name_len = 0;
+    int prefix_len = 0;
+    int suffix_len = 0;
+    int max = 0;
+    char *path = malloc(MAXLEN);
+    name_len = strlen(qemu_argv);
+    prefix_len = strlen(IMAGE_PATH_PREFIX);
+    suffix_len = strlen(IMAGE_PATH_SUFFIX);
+    max = name_len - suffix_len;
+    for(i = prefix_len , j = 0; i < max; i++)
+    {
+        path[j++] = qemu_argv[i];
     }
-#ifdef _WIN32
-    OSVERSIONINFO osvi;
-    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-    GetVersionEx(&osvi);
-
-    if ((osvi.dwMajorVersion >= 6) && (osvi.dwMinorVersion >= 1))
-        sprintf(emul_img_dir, "%s/icons/Emulator.ico", skin);
+    path[j] = '\0';
+    if(!g_path_is_absolute(path))
+        strcpy(tizen_target_path, g_get_current_dir());
     else
-        sprintf(emul_img_dir, "%s/icons/Emulator_20x20.png", skin);
-
-#else /* _WIN32 */
-    sprintf(emul_img_dir, "%s/icons/Emulator.ico", skin);
-#endif/* _WIN32 */
-
-    if (g_file_test(emul_img_dir, G_FILE_TEST_EXISTS) == FALSE) {
-        ERR( "emulator icon directory %s doesn't exist!!\n", emul_img_dir);
-    }
-    gtk_window_set_icon_from_file(GTK_WINDOW(g_main_window), emul_img_dir, NULL);
-
-
-    /* 2.2 emulator taskbar name */
-
-    name = g_strdup_printf("emulator-%d", get_sdb_base_port());
-    gtk_window_set_title (GTK_WINDOW (g_main_window), name);
-    g_free(name);
-
-    /* 3. skin load */
-
-    if (load_skin_image(&PHONE) < 0) {
-        ERR( "emulator skin image is not loaded.\n");
-        exit(1);
-    }
-
-    /* 4. skin mask process */
-
-    pixmap_widget = gtk_image_new_from_pixbuf (PHONE.mode_SkinImg[UISTATE.current_mode].pPixImg);
-    gdk_pixbuf_render_pixmap_and_mask (PHONE.mode_SkinImg[UISTATE.current_mode].pPixImg, NULL, &SkinMask, 1);
-    gtk_widget_shape_combine_mask (g_main_window, SkinMask, 0, 0);
-    INFO("sets a shape for emulator window\n");
-
-    if (SkinMask != NULL) {
-        g_object_unref (SkinMask);
-    }
-
-    /* 5. emulator container */
-
-    fixed = gtk_fixed_new ();
-    if (!qemu_widget_new(&sdl_widget)) {
-        ERR( "sdl_widget is failed!!\n");
-        exit(1);
-    }
-
-    gtk_fixed_put (GTK_FIXED (fixed), pixmap_widget, 0, 0);
-    gtk_fixed_put (GTK_FIXED (fixed), sdl_widget, PHONE.mode[UISTATE.current_mode].lcd_list[0].lcd_region.x,
-            PHONE.mode[UISTATE.current_mode].lcd_list[0].lcd_region.y);
-    gtk_container_add (GTK_CONTAINER (g_main_window), fixed);
-
-#ifdef __linux__
-    if (strcmp(host_uname_buf.release, "2.6.35-22-generic") == 0) { // for ubuntu 10.10 resize window bug
-        gtk_window_resize (GTK_WINDOW(g_main_window),
-            PHONE.mode_SkinImg[0].nImgHeight, PHONE.mode_SkinImg[0].nImgHeight);
-    }
-#endif
-
-    /* 6. emulator start position */
-    UISTATE.scale = ((float)get_config_type(SYSTEMINFO.virtual_target_info_file, EMULATOR_GROUP, SCALE_KEY)) / 100;
-    if (UISTATE.scale <= 0 || UISTATE.scale > 1.0) {
-        UISTATE.scale = 1.0;
-    }
-    TRACE("scale = %f\n", UISTATE.scale);
+        strcpy(tizen_target_path, g_path_get_dirname(path));
 
+    strcpy(logpath, tizen_target_path);
+    strcat(logpath, LOGS_SUFFIX);
 #ifdef _WIN32
-    RECT host_screen;
-    int emulator_w, emulator_h;
-    int range;
-
-    emulator_w = emulator_h = 0;
-    ZeroMemory(&host_screen, sizeof(RECT));
-    EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&host_screen);
-
-    if (host_screen.left < 0) {
-        int shift = host_screen.left * -1;
-        host_screen.left += shift;
-        host_screen.right += shift;
-    }
-    if (host_screen.top < 0) {
-        int shift = host_screen.top * -1;
-        host_screen.top += shift;
-        host_screen.bottom += shift;
-    }
-
-    emulator_w = PHONE.mode_SkinImg[UISTATE.current_mode].nImgWidth * UISTATE.scale;
-    emulator_h = PHONE.mode_SkinImg[UISTATE.current_mode].nImgHeight * UISTATE.scale;
-
-    // position correction of x
-    range = host_screen.left - emulator_w;
-    if (configuration.main_x <= range)
-    {
-        INFO("configuration.main_x=%d is out of monitor range. (%d ~ %d)\n",
-                configuration.main_x, range, host_screen.right);
-        configuration.main_x = host_screen.left;
-    }
-    else if (configuration.main_x >= host_screen.right)
-    {
-        INFO("configuration.main_x=%d is out of monitor range. (%d ~ %d)\n",
-                configuration.main_x, range, host_screen.right);
-        configuration.main_x = host_screen.right - emulator_w;
-    }
-
-    // position correction of y
-    range = host_screen.top - emulator_h;
-    if (configuration.main_y <= range)
-    {
-        INFO("configuration.main_y=%d is out of monitor range. (%d ~ %d)\n",
-                configuration.main_x, range, host_screen.bottom);
-        configuration.main_y = host_screen.top;
+    if(access(g_win32_locale_filename_from_utf8(logpath), R_OK) != 0) {
+       g_mkdir(g_win32_locale_filename_from_utf8(logpath), 0755); 
     }
-    else if (configuration.main_y >= host_screen.bottom)
-    {
-        INFO("configuration.main_y=%d is out of monitor range. (%d ~ %d)\n",
-                configuration.main_x, range, host_screen.bottom);
-        configuration.main_y = host_screen.bottom - emulator_h;
+#else
+    if(access(logpath, R_OK) != 0) {
+       g_mkdir(logpath, 0755); 
     }
 #endif
-
-    gtk_window_move (GTK_WINDOW (g_main_window), configuration.main_x, configuration.main_y);
-    INFO("emulator window is moved (%d, %d)\n", configuration.main_x, configuration.main_y);
-
-    /* 7. create popup menu */
-    create_popup_menu (&popup_menu, &PHONE, &configuration);
-    INFO("popup menu is created\n");
-
-    /* 8. Signal connect */
-
-    g_signal_connect (G_OBJECT(g_main_window), "motion_notify_event", G_CALLBACK(motion_notify_event_handler), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "button_press_event", G_CALLBACK(motion_notify_event_handler), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "button_release_event", G_CALLBACK(motion_notify_event_handler), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "key_press_event", G_CALLBACK(key_event_handler), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "key_release_event", G_CALLBACK(key_event_handler), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "delete-event", G_CALLBACK(exit_emulator), NULL);
-    g_signal_connect (G_OBJECT(g_main_window), "configure_event", G_CALLBACK(configure_event), NULL);
-
-    gtk_widget_set_has_tooltip(g_main_window, TRUE);
-    g_signal_connect (G_OBJECT(g_main_window), "query-tooltip", G_CALLBACK(query_tooltip_event), NULL);
-
-    gtk_widget_set_events (g_main_window, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK |
-            GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);// | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
-
-    /* 9. widget show all */
-
-    gtk_window_set_keep_above(GTK_WINDOW (g_main_window), configuration.always_on_top);
-    gtk_widget_show_all (g_main_window);
-    gtk_widget_queue_resize (g_main_window);
-
-    if (UISTATE.scale != 1.0) {
-        scale_event_callback(&PHONE, UISTATE.current_mode);
-    }
+       strcat(logpath, LOGFILE);
+    set_log_path(logpath);
 }
 
-static void* run_gtk_main(void* arg)
+void redir_output(void)
 {
-    /* 10. gtk main start */
-    init_sensor_server();
-    gtk_main();
+       FILE *fp;
 
-    return NULL;
-}
+       fp = freopen(logpath, "a+", stdout);
+       if(fp ==NULL)
+               fprintf(stderr, "log file open error\n");
+       fp = freopen(logpath, "a+", stderr);
+       if(fp ==NULL)
+               fprintf(stderr, "log file open error\n");
 
-#ifdef _WIN32
-static void* construct_main_window_and_run_gtk_main(void* arg)
-{
-    construct_main_window();
-    init_sensor_server();
-    gtk_main();
-    return NULL;
+       setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+       setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 }
-#endif
-
-
-
-/**
- * @brief    init startup structure
- * @return   success  0,  fail    -1
- * @date     Nov 3. 2008
- * */
 
-static void init_startup_option(void)
+void extract_info(int qemu_argc, char** qemu_argv)
 {
-    memset(&(startup_option), 0x00, sizeof(startup_option));
-    startup_option.run_level = 5;
-    startup_option.mountPort = 1301;
-    startup_option.telnet_port = 1201;
-    startup_option.ssh_port = 1202;
-    if(ENABLE_MULTI)
+    int i;
+
+    for(i = 0; i < qemu_argc; ++i)
     {
-        while(check_port(LOCALHOST, startup_option.mountPort) == 0)
-            startup_option.mountPort++;
+        if(strstr(qemu_argv[i], IMAGE_PATH_PREFIX) != NULL) {
+            set_image_and_log_path(qemu_argv[i]);
+            break;
+        }
     }
-
-    startup_option.no_dump = FALSE;
-    startup_option.vtm = "default";
+    
+    tizen_base_port = get_sdb_base_port();
 }
 
-
-/**
- * @brief    startup option
- *           kill application and load kernel driver
- *
- * @return   success  0,  fail    -1
- * @date     May 18. 2009
- * */
-
-static int startup_option_parser(int *argc, char ***argv)
+static void system_info(void)
 {
-    /* 1. Goption handling */
-
-    gboolean version = FALSE;
-    GOptionContext *context = NULL;
-    GError *error = NULL;
-    char timeinfo[256] = { 0, };
+#ifdef __linux__
+    char lscmd[MAXLEN] = "lspci >> ";
+#endif
+    char timeinfo[64] = {0, };
     struct tm *tm_time;
     struct timeval tval;
-    char string[MAXBUF];
-    FILE *fp = NULL;
-    char *info_file;
-    char *arch = getenv(EMULATOR_ARCH);
-    const gchar *exec_path = get_exec_path();
-    if(!arch) /* for stand alone */
-    {
-        char *binary = g_path_get_basename(exec_path);
-        if(strstr(binary, EMULATOR_X86))
-            arch = g_strdup_printf(X86);
-        else if(strstr(binary, EMULATOR_ARM))
-            arch = g_strdup_printf(ARM);
-        else
-        {
-            ERR( "binary setting failed\n");
-            exit(1);
-        }
-        free(binary);
-    }
-
-    GOptionEntry options[] = {
-        {"disk", 0, 0, G_OPTION_ARG_STRING, &startup_option.disk, "Disk image path", "\"disk path\""},
-        {"vtm", 0, 0, G_OPTION_ARG_STRING, &startup_option.vtm, "Virtual target image file", "\"*.x86 or *.arm\""},
-        {"run-level", 0, 0, G_OPTION_ARG_INT, &startup_option.run_level, "Run level", "5"},
-        {"version", 0, 0, G_OPTION_ARG_NONE, &version, "Version info", NULL},
-        {"Port", 0, 0, G_OPTION_ARG_INT, &startup_option.mountPort, "Port for NFS mounting", "\"default is 1301\""},
-        {"ssh-port", 0, 0, G_OPTION_ARG_INT, &startup_option.ssh_port, "Port for ssh to guest", NULL},
-        {"telnet-port", 0, 0, G_OPTION_ARG_INT, &startup_option.telnet_port, "Port for telnet to guest", NULL},
-        {"no-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &startup_option.no_dump, "Disable dump feature", NULL},
-        {NULL}
-    };
-
-    /* 2. Goption parsing */
-
-    context = g_option_context_new ("- Tizen SDK Emulator");
-    g_option_context_set_help_enabled(context, FALSE);
-    g_option_context_add_main_entries (context, options, NULL);
-    g_option_context_add_group (context, gtk_get_option_group (TRUE));
 
-    if (!g_option_context_parse (context, argc, argv, &error)) {
-        fprintf(stderr, "%s: option parsing failed\n", (*argv)[0]);
-        exit (1);
-    }
+    INFO("* SDK Version : %s\n", build_version);
+    INFO("* Package %s\n", pkginfo_version);
+    INFO("* User name : %s\n", g_get_real_name());
+#ifdef _WIN32
+    INFO("* Host name : %s\n", g_get_host_name());
+#endif
 
-    /* 3. starting info */
+    /* timestamp */
+    INFO("* Build date : %s\n", build_date);
     gettimeofday(&tval, NULL);
     tm_time = localtime(&(tval.tv_sec));
     strftime(timeinfo, sizeof(timeinfo), "%Y/%m/%d %H:%M:%S", tm_time);
-    INFO("=========INFO START========\n");
-    INFO("Current time : %s\n", timeinfo);
-    INFO("SDK version : %s(%s), Build date : %s\n", build_version, build_git, build_date);
-#ifdef __linux__
-    INFO("Qemu build machine linux kernel version : (%d, %d, %d)\n",
-        LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xff , LINUX_VERSION_CODE & 0xff);
-
-        if (uname(&host_uname_buf) == 0) {
-        INFO("Host uname : %s %s %s %s %s\n", host_uname_buf.sysname, host_uname_buf.nodename,
-            host_uname_buf.release, host_uname_buf.version, host_uname_buf.machine);
-        }
-#endif
-
-    INFO("Host sdl version : (%d, %d, %d)\n", SDL_Linked_Version()->major, SDL_Linked_Version()->minor, SDL_Linked_Version()->patch);
-
-    char *virtual_target_path = get_virtual_target_path(startup_option.vtm);
-    info_file = g_strdup_printf("%sconfig.ini", virtual_target_path);
-    if( (fp = fopen(info_file, "r")) == NULL )
-    {
-        ERR("can't open %s", info_file);
-        exit(1);
-    }
-
-    if (!startup_option.vtm)
-        startup_option.vtm = g_strdup_printf("default");
-    startup_option.disk = g_strdup_printf("%semulimg-%s.%s",virtual_target_path, startup_option.vtm, arch);
-    INFO("target name : %s, disk path : %s\n", startup_option.vtm, startup_option.disk);
-
-    INFO("\n");
-    while(fgets(string, MAXBUF, fp)!=NULL)
-        INFO("%s", string);
-    dbg_printf("\n");
-    INFO("=========INFO END========\n");
-
-    fclose(fp);
-    free(virtual_target_path);
-    free(info_file);
-
-    return 0;
-}
-
-
-/**
- * @brief    init structure
- * @return   success  0,  fail    -1
- * @date     Nov 3. 2008
- * */
-
-static int init_structure(void)
-{
-
-    /* 3. make startup option structure */
-
-    init_startup_option();
-
-    return 0;
-}
-
-
-/**
- * @brief   init emulator
- * @param argc  number of argument
- * @param argv  argument vector
- * @return  void
- * @date    4. 14. 2008
- * */
-
-static void init_emulator(int *argc, char ***argv)
-{
-    /* 1. thread_init */
-
-    emulator_mutex_init();
-#ifndef _WIN32
-    g_thread_init(NULL);
-    XInitThreads();
-#endif
-
-    /* 3. gtk_init */
-
-    gtk_init (argc, argv);
-
-    /* 4. structure init */
-
-    init_structure();
-
-    /* 5. make hash init */
-
-    window_hash_init ();
-}
-
-
-/**
- * @brief    function to load config parsed to qemu option
- * @return   success  0,  fail    -1
- * @date     Apr 22. 2009
- * */
-
-static int load_config_passed_to_qemu (arglist* al, int argc, char **argv)
-{
-    int i;
-
-    /* 1. load configuration and show option window */
-
-    if (load_config_file(&SYSTEMINFO) < 0) {
-        ERR( "load configuration file error!!\n");
-        return -1;
-    }
-
-    TRACE( "load config file complete\n");
+    INFO("* Current time : %s\n", timeinfo);
 
+    /* Gets the version of the dynamically linked SDL library */
+    INFO("* Host sdl version : (%d, %d, %d)\n",
+        SDL_Linked_Version()->major, SDL_Linked_Version()->minor, SDL_Linked_Version()->patch);
 
+#if defined( _WIN32)
+    /* Retrieves information about the current os */
+    OSVERSIONINFO osvi;
+    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 
-    if (determine_skin(&virtual_target_info, &configuration) < 0) {
-        ERR( "invalid skin file\n");
-        return -1;
-    }
-
-    /* 2. skin parse dbi file and fill the structure */
-
-    if (skin_parser(configuration.skin_path, &PHONE) < 0) {
-        ERR( "skin parse error\n");
-        return -1;
-    }
-
-    TRACE( "skin parse complete\n");
-
-    /* 3. parsed to qemu startup option when ok clicked */
-
-    qemu_option_set_to_config(al);
-
-    /*
-     * note: g_option_context_parse modifies argc and argv
-     * Append args after -- to QEMU command line
-     */
-    if (argc > 2 && !strcmp(argv[1], "--")) {
-        for (i=2; i<argc; i++) {
-            /* if snapshot boot set then skip -loadvm snapshot option */
-            if(configuration.qemu_configuration.save_emulator_state == 0 && strcmp(argv[i],"-loadvm") == 0){
-                i++;    // skip snapshot id
-            }
-            else append_argvlist(al, "%s", argv[i]);
-        }
-    }
-
-    return 0;
-}
-
-#ifndef _WIN32
-static void emul_prepare_process(void)
-{
-    gchar cmd[256] = "";
-
-    /* start the vmodem*/
-    if(qemu_arch_is_arm()) {
-        const char* target_path = get_target_path();
-
-        if(configuration.qemu_configuration.diskimg_type)
-            sprintf (cmd, "/opt/tizen_sdk/simulator/vmodem_arm");
-        else
-            sprintf (cmd, "%s/usr/bin/vmodem_arm", target_path);
-
-        if(emul_create_process(cmd) == FALSE)
-            fprintf(stderr, "create vmodem failed\n");
+    if (GetVersionEx(&osvi)) {
+        INFO("* MajorVersion : %d, MinorVersion : %d, BuildNumber : %d, PlatformId : %d, CSDVersion : %s\n",
+            osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, osvi.dwPlatformId, osvi.szCSDVersion);
     }
 
-    /* start serial console */
-    if(configuration.qemu_configuration.serial_console_command_type == 1 &&
-            configuration.qemu_configuration.telnet_type == 1) {
-        sprintf(cmd, "%s", configuration.qemu_configuration.serial_console_command);
+    /* Retrieves information about the current system */
+    SYSTEM_INFO sysi;
+    ZeroMemory(&sysi, sizeof(SYSTEM_INFO));
 
-        if(emul_create_process(cmd) == FALSE)
-            fprintf(stderr, "create serial console failed\n");
-    }
-}
-#endif
+    GetSystemInfo(&sysi);
+    INFO("* Processor type : %d, Number of processors : %d\n", sysi.dwProcessorType,  sysi.dwNumberOfProcessors);
 
-int make_shdmem()
-{
-    char *virtual_target_path = NULL;
-    virtual_target_path = get_virtual_target_path(startup_option.vtm);
-    tizen_base_port = get_sdb_base_port();
-#ifndef _WIN32
-    int shmid;
-    char *shared_memory;
-    shmid = shmget((key_t)tizen_base_port, MAXPATH, 0666|IPC_CREAT);
-    if (shmid == -1)
-    {
-        ERR("shmget failed");
-        return -1;
-    }
-    shared_memory = shmat(shmid, (char*)0x00, 0);
-    if (shared_memory == (void *)-1)
-    {
-        ERR("shmat failed");
-        return -1;
-    }
-    sprintf(shared_memory, "%s", virtual_target_path);
-    INFO( "shared memory key: %d value: %s\n", tizen_base_port, (char*)shared_memory);
-#else
-    HANDLE hMapFile;
-    char* pBuf;
-    char* port_in_use;
-    char *shared_memory;
-    shared_memory = g_strdup_printf("%s", virtual_target_path);
-    port_in_use =  g_strdup_printf("%d", tizen_base_port);
-    hMapFile = CreateFileMapping(
-                 INVALID_HANDLE_VALUE,    // use paging file
-                 NULL,                    // default security
-                 PAGE_READWRITE,          // read/write access
-                 0,                       // maximum object size (high-order DWORD)
-                 50,                // maximum object size (low-order DWORD)
-                 port_in_use);                 // name of mapping object
-    if (hMapFile == NULL)
-    {
-        ERR("Could not create file mapping object (%d).\n", GetLastError());
-        return -1;
-    }
-    pBuf = MapViewOfFile(hMapFile,   // handle to map object
-                        FILE_MAP_ALL_ACCESS, // read/write permission
-                        0,
-                        0,
-                        50);
+#elif defined(__linux__)
+    /* depends on building */
+    INFO("* Qemu build machine linux kernel version : (%d, %d, %d)\n",
+        LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xff , LINUX_VERSION_CODE & 0xff);
 
-    if (pBuf == NULL)
-    {
-        ERR("Could not map view of file (%d).\n", GetLastError());
-        CloseHandle(hMapFile);
-        return -1;
+     /* depends on launching */
+    struct utsname host_uname_buf;
+    if (uname(&host_uname_buf) == 0) {
+        INFO("* Host machine uname : %s %s %s %s %s\n", host_uname_buf.sysname, host_uname_buf.nodename,
+            host_uname_buf.release, host_uname_buf.version, host_uname_buf.machine);
     }
 
-    CopyMemory((PVOID)pBuf, shared_memory, strlen(shared_memory));
-    free(port_in_use);
-    free(shared_memory);
+    /* pci device description */
+    INFO("* Pci devices :\n");
+    strcat(lscmd, logpath);
+    int i = system(lscmd);
+    INFO("system function command : %s, system function returned value : %d\n", lscmd, i);
 #endif
-    free(virtual_target_path);
-    return 0;
 }
 
-
-static void redirect_log(void)
+void prepare_maru(void)
 {
-    static char logfile[256] = { 0, };
+    INFO("Prepare maru specified feature\n");
 
-    strcpy(logfile, get_virtual_target_log_path(startup_option.vtm));
-    strcat(logfile, EMUL_LOGFILE);
+    sdb_setup();
 
-    g_out_fp = freopen(logfile, "a+", stdout);
-    if (g_out_fp ==NULL) {
-        fprintf(stderr, "log file open error\n");
-    }
+    INFO("call construct_main_window\n");
 
-    g_err_fp = freopen(logfile, "a+", stderr);
-    if (g_err_fp ==NULL) {
-        fprintf(stderr, "log file open error\n");
-    }
+    construct_main_window(skin_argc, skin_argv, qemu_argc, qemu_argv );
 
-    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
-    setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+    int guest_server_port = tizen_base_port + SDB_UDP_SENSOR_INDEX;
+    start_guest_server( guest_server_port );
 
+    mloop_ev_init();
 }
 
-/**
- * @brief    function to create emulator
- * @param argc        number of argument
- * @param argv        argument vector
- *
- * @return   success  0,  fail    -1
- * @date     Apr 22. 2009
- * */
+int qemu_main(int argc, char** argv, char** envp);
 
-int main(int argc, char** argv)
+int main(int argc, char* argv[])
 {
-    //int sensor_port = SENSOR_PORT;
-    int i, r;
-    pthread_t thread_gtk_id;
-
-    init_emulator(&argc, &argv);
-
-    startup_option_parser(&argc, &argv);
-
-    /* redirect stderr, stdout to log file */
-
-    redirect_log();
-
-    /* initailize socket for windows */
-
+    parse_options(argc, argv, &skin_argc, &skin_argv, &qemu_argc, &qemu_argv);
+    get_bin_dir( qemu_argv[0] );
     socket_init();
+    extract_info(qemu_argc, qemu_argv);
 
-    /* make shared memory not for launching multiple instance of one target */
-    make_shdmem();
-    INFO("created a shared memory\n");
-
-    /* option parsed and pass to qemu option */
-
-    r = load_config_passed_to_qemu(&g_qemu_arglist, argc, argv);
-    if (r < 0) {
-        ERR( "option parsed and pass to qemu option error!!\n");
-        return -1;
-    }
-    INFO("Arguments : ");
-    for(i=0; i<g_qemu_arglist.argc; i++){
-        dbg_printf_nonewline("%s ", g_qemu_arglist.argv[i]);
-    }
-    dbg_printf("\n");
-
-    /* signal handler */
-
-    register_sig_handler();
-
-#ifndef _WIN32
-    construct_main_window();
-
-    /* create gtk thread  */
-    if (pthread_create(&thread_gtk_id, NULL, run_gtk_main, NULL) != 0) {
-        ERR( "error creating gtk_id thread!!\n");
-        return -1;
-    }
-#else /* _WIN32 */
-    /* if _WIN32, window creation and gtk main must be run in a thread */
-    if (pthread_create(&thread_gtk_id, NULL, construct_main_window_and_run_gtk_main, NULL) != 0) {
-        ERR( "error creating gtk_id thread!!\n");
-        return -1;
-    }
-#endif
-    INFO("run_gtk_main\n");
-
-#ifdef ENABLE_OPENGL_SERVER
-    /* create OPENGL server thread */
-    if (pthread_create(&thread_opengl_id, NULL, init_opengl_server, NULL) != 0) {
-        ERR( "error creating opengl_id thread!!");
-        return -1;
-    }
-#endif  /* ENABLE_OPENGL_SERVER */
-
-    /* create serial console and vmodem, and other processes */
-#ifndef _WIN32
-    emul_prepare_process();
-#endif
-
-    qemu_main(g_qemu_arglist.argc, g_qemu_arglist.argv, NULL);
-
-    return 0;
-}
-
-gboolean  update_progress_bar(GIOChannel *channel, GIOCondition condition, gpointer data)
-{
-    unsigned int len = 0;
-    GIOError error;
-    GIOStatus status;
-    gchar *recvbuffer;
-    time_t rawtime;
-    struct tm *timeinfo;
-    char time_str[MAX_TIME_STR];
-    char telnet_commands[MAX_COMMANDS][MAX_LENGTH] = {
-        "read", //dummy command for local use
-        "delvm snapshot\r",
-        "read", //dummy command for local use
-        "savevm snapshot\r",
-        "read", //dummy command for local use
-    };
-
-    if((condition==G_IO_IN) && !(vmstate%2))
-    {
-        status = g_io_channel_read_line(channel, &recvbuffer, NULL, NULL, NULL);
-        if(status!=G_IO_STATUS_NORMAL)
-        {
-            printf("recv() failed or connection closed prematurely %d\n", status);
-            vmstate = -1;
-            g_io_channel_unref (channel);
-            g_io_channel_shutdown(channel, TRUE, NULL);
-            return FALSE;
-        }
-        else
-        {
-            char *ptr = NULL;
-            if((ptr = strstr(recvbuffer, "Completed="))!=NULL)
-            {
-                ptr[18]='\0';
-                gdouble fraction = atof(ptr+10);
-                gtk_progress_bar_set_fraction(savevm_progress,fraction);
-            }
-            else if (strstr(recvbuffer, "SaveVM Complete"))
-            {
-                gtk_progress_bar_set_fraction(savevm_progress,1);
-                gtk_progress_bar_set_text(savevm_progress,"Save State Successful");
-                gtk_label_set_text(GTK_LABEL(savevm_label), "Please close this dialog");
-                g_free(recvbuffer);
-                g_io_channel_shutdown(channel, TRUE, NULL);
-                g_io_channel_unref (channel);
-                vmstate = 0;
-                rawtime = time(NULL);
-                timeinfo = localtime(&rawtime);
-                strftime(time_str, MAX_TIME_STR, "%Y-%m-%d %H:%M:%S", timeinfo);
-                printf("%s\n", time_str);
-
-                virtual_target_info.snapshot_saved = 1;
-                snprintf(virtual_target_info.snapshot_saved_date, MAXBUF, "%s", time_str);
-                set_config_type(SYSTEMINFO.virtual_target_info_file, ETC_GROUP, SNAPSHOT_SAVED_KEY, virtual_target_info.snapshot_saved);
-                set_config_value(SYSTEMINFO.virtual_target_info_file, ETC_GROUP, SNAPSHOT_SAVED_DATE_KEY, virtual_target_info.snapshot_saved_date);
-
-                return FALSE;
-            }
+    INFO("Emulator start !!!\n");
+    system_info();
 
-            g_free(recvbuffer);
+    INFO("Prepare running...\n");
+    redir_output(); // Redirect stdout, stderr after debug_ch is initialized...
 
-            if(vmstate<(MAX_COMMANDS-1))
-                vmstate++;
-
-            return TRUE;
-        }
-    }
+    int i;
 
-    if(vmstate%2)
+    fprintf(stdout, "qemu args : ==========================================\n");
+    for(i = 0; i < qemu_argc; ++i)
     {
-        error = g_io_channel_write(channel,telnet_commands[vmstate],\
-                strlen(telnet_commands[vmstate]), \
-                &len);
-        if(error!=G_IO_ERROR_NONE)
-        {
-            g_io_channel_unref (channel);
-            g_io_channel_shutdown(channel, TRUE, NULL);
-            vmstate = -1;
-            printf("send() failed or connection closed prematurely %d\n", G_IO_ERROR_UNKNOWN);
-            return FALSE;
-        }
-        else
-        {
-            if(vmstate<MAX_COMMANDS)
-                vmstate++;
-            return TRUE;
-        }
+        fprintf(stdout, "%s ", qemu_argv[i]);
     }
+    fprintf(stdout, "\n");
+    fprintf(stdout, "======================================================\n");
 
-    if(((condition==G_IO_ERR) || (condition==G_IO_HUP))&&(vmstate<=(MAX_COMMANDS-1)))
+    fprintf(stdout, "skin args : ==========================================\n");
+    for(i = 0; i < skin_argc; ++i)
     {
-        g_io_channel_unref (channel);
-        g_io_channel_shutdown(channel, TRUE, NULL);
-        close(vmsock);
-        vmstate = 0;
-        return FALSE;
+        fprintf(stdout, "%s ", skin_argv[i]);
     }
-    return TRUE;
-}
-
-void save_emulator_state(void)
-{
-    /* Connect to the monitor console */
-    struct sockaddr_in server;
-    unsigned short server_port = 9000;
-    char *server_ip = "127.0.0.1";
-
+    fprintf(stdout, "\n");
+    fprintf(stdout, "======================================================\n");
 
-    /* build the UI */
-    GtkBuilder *builder = gtk_builder_new();
-    char full_glade_path[256];
-    sprintf(full_glade_path, "%s/savevm.glade", get_root_path());
-    gtk_builder_add_from_file(builder, full_glade_path, NULL);
+    INFO("qemu main start!\n");
+    qemu_main(qemu_argc, qemu_argv, NULL);
 
-    //get objects from the UI
-    savevm_window = (GtkWidget *)gtk_builder_get_object(builder, "savevm_window");
-    savevm_progress = (GtkProgressBar *)gtk_builder_get_object(builder, "savevm_progress");
-    savevm_label = (GtkWidget *)gtk_builder_get_object(builder, "savevm_label");
-    gtk_progress_bar_set_text(savevm_progress,"Saving State in progress...");
-    //gtk_builder_connect_signals(builder, NULL);
-    gtk_widget_show(savevm_window);
+    exit_emulator();
 
-    if ((vmsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
-    {
-        printf("socket() failed\n");
-        return ;
-    }
-    memset(&server, 0, sizeof(server));
-    server.sin_family      = AF_INET;
-    server.sin_addr.s_addr = inet_addr(server_ip);
-    server.sin_port        = htons(server_port);
-    if (connect(vmsock, (struct sockaddr *) &server, sizeof(server)) < 0)
-    {
-        printf("connect() failed\n");
-        close(vmsock);
-        return ;
-    }
-
-    channel=g_io_channel_unix_new(vmsock);
-    if(channel==NULL)
-    {
-        printf("gnet_tcp_socket_get_io_channel() failed\n");
-        close(vmsock);
-        return ;
-    }
-    //g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
-
-    guint sourceid = g_io_add_watch(channel, G_IO_IN|G_IO_ERR|G_IO_HUP, \
-            update_progress_bar, NULL);
-
-    if(sourceid<=0)
-    {
-        printf("g_io_add_watch() failed\n");
-        g_io_channel_unref(channel);
-        close(vmsock);
-        return ;
-    }
-    printf("Added to gmain loop = %d\n", sourceid);
+    return 0;
 }
+
index b724ee874e6534efddc6e21677b8e9d9243f425c..0c4deb218e2a9dca0982357f390abbb6b4420736 100644 (file)
@@ -1,21 +1,14 @@
 /*
  * Emulator
  *
- * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
- * Contact:
- * DoHyung Hong <don.hong@samsung.com>
+ * Contact: 
  * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Hyunjun Son <hj79.son@samsung.com>
- * SangJin Kim <sangjin3.kim@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
  * MunKyu Im <munkyu.im@samsung.com>
- * KiTae Kim <kt920.kim@samsung.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * SungMin Ha <sungmin82.ha@samsung.com>
- * JiHye Kim <jihye1128.kim@samsung.com>
  * GiWoong Kim <giwoong.kim@samsung.com>
  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun <dk77.yun@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #ifndef __EMULATOR_H__
 #define __EMULATOR_H__
 
-#define ISE_TOOLKIT_NUM             5
+#define MAXLEN  512
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <time.h>
+extern char tizen_target_path[MAXLEN];
 
-#include <stdio.h>
-#include <locale.h>
+void exit_emulator(void);
+void set_image_and_log_path(char *qemu_argv);
+void redir_output(void);
+void extract_info(int qemu_argc, char** qemu_argv);
+void prepare_maru(void);
 
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#ifndef _WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#include <glib/gthread.h>
-#include <process.h>
-#endif
-
-typedef struct _arglist arglist;
-
-#include "utils.h"
-#include "configuration.h"
-#include "emulsignal.h"
-#include "tools.h"
-#include "fileio.h"
-#include "extern.h"
-#include "menu.h"
-#include "vinit_process.h"
-#include "qemu_gtk_widget.h"
-#include "event_handler.h"
-
-void append_argvlist(arglist* al, const char *fmt, ...) __attribute((__format__(__printf__,2,3)));
-
-enum {
-    EMUL_BOOTING = 0, //not used yet
-    EMUL_NORMAL, //not used yet
-    EMUL_SHUTTING_DOWN,
-};
-
-extern void save_emulator_state(void);
-extern void exit_emulator(void);
-extern gboolean  update_progress_bar(GIOChannel *, GIOCondition , gpointer);
-
-extern CONFIGURATION configuration;     /**<    configuration structure which hold system-wide information during running   */
-extern SYSINFO SYSTEMINFO;
-extern STARTUP_OPTION startup_option;   /**<    command line option structure which hold some command line option information   */
-extern PHONEMODELINFO *phone_info;
-
-extern GtkWidget *EventItem1;
-extern GtkWidget *EventItem2;
-
-int get_emulator_condition(void);
-void set_emulator_condition(int state);
-int emul_create_process(const gchar cmd[]);
-void emul_kill_all_process(void);
-extern int qemu_arch_is_arm(void); /* hack */
-int device_set_rotation(int rotation);
-int socket_init(void);
-void exit_emulator_post_process( void );
-int make_shdmem(void);
-#endif
+#endif /* __EMULATOR_H__ */
diff --git a/tizen/src/guest_server.c b/tizen/src/guest_server.c
new file mode 100644 (file)
index 0000000..976cf92
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include "guest_server.h"
+#include "skin/maruskin_server.h"
+#include "debug_ch.h"
+#include "sdb.h"
+
+MULTI_DEBUG_CHANNEL( qemu, guest_server );
+
+#define RECV_BUF_SIZE 32
+
+static void* run_guest_server( void* args );
+
+static int svr_port = 0;
+static int server_sock = 0;
+
+static int parse_val( char *buff, unsigned char data, char *parsbuf );
+
+pthread_t start_guest_server( int server_port ) {
+
+    svr_port = server_port;
+
+    pthread_t thread_id;
+
+    if ( 0 != pthread_create( &thread_id, NULL, run_guest_server, NULL ) ) {
+        ERR( "fail to create guest_server pthread.\n" );
+    }else {
+        INFO( "created guest server thread\n" );
+    }
+
+    return thread_id;
+
+}
+
+static void* run_guest_server( void* args ) {
+
+    INFO( "start guest server thread.\n" );
+
+    uint16_t port;
+    struct sockaddr_in server_addr, client_addr;
+    socklen_t client_len;
+    port = svr_port;
+
+    if ( ( server_sock = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 ) {
+        ERR( "create listen socket error\n" );
+        perror( "create listen socket error\n" );
+        goto cleanup;
+    }
+    memset( &server_addr, '\0', sizeof( server_addr ) );
+    server_addr.sin_family = PF_INET;
+    server_addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
+    server_addr.sin_port = htons( port );
+
+    int opt = 1;
+    setsockopt( server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) );
+
+    if ( 0 > bind( server_sock, (struct sockaddr*) &server_addr, sizeof( server_addr ) ) ) {
+        ERR( "guest server bind error: " );
+        perror( "bind" );
+        goto cleanup;
+    } else {
+        INFO( "success to bind port[127.0.0.1:%d/udp] for guest_server in host \n", port );
+    }
+
+    client_len = sizeof( client_addr );
+
+    char readbuf[RECV_BUF_SIZE];
+
+    INFO( "guest server start...port:%d\n", port );
+
+    while ( 1 ) {
+
+        memset( &readbuf, 0, RECV_BUF_SIZE );
+
+        int read_cnt = recvfrom( server_sock, readbuf, RECV_BUF_SIZE, 0, (struct sockaddr*) &client_addr, &client_len );
+
+        if ( 0 > read_cnt ) {
+            ERR( "fail to recvfrom in guest_server.\n" );
+            perror( "fail to recvfrom in guest_server.:" );
+            break;
+        } else {
+
+            if ( 0 == read_cnt ) {
+                ERR( "read_cnt is 0.\n" );
+                break;
+            }
+
+            TRACE( "================= recv =================\n" );
+            TRACE( "read_cnt:%d\n", read_cnt );
+            TRACE( "readbuf:%s\n", readbuf );
+
+            char command[RECV_BUF_SIZE];
+            memset( command, '\0', sizeof( command ) );
+
+            parse_val( readbuf, 0x0a, command );
+
+            TRACE( "----------------------------------------\n" );
+            if ( strcmp( command, "3\n" ) == 0 ) {
+                TRACE( "command:%s\n", command );
+                notify_sdb_daemon_start();
+                notify_sensor_daemon_start();
+            } else {
+                ERR( "!!! unknown command : %s\n", command );
+            }
+            TRACE( "========================================\n" );
+
+        }
+
+    }
+
+    cleanup:
+#ifdef _WIN32
+    if( server_sock ) {
+        closesocket(server_sock);
+    }
+#else
+    if ( server_sock ) {
+        close( server_sock );
+    }
+#endif
+
+    return NULL;
+}
+
+static int parse_val( char* buff, unsigned char data, char* parsbuf ) {
+
+    int count = 0;
+
+    while ( 1 ) {
+
+        if ( count > 12 ) {
+            return -1;
+        }
+
+        if ( buff[count] == data ) {
+            count++;
+            strncpy( parsbuf, buff, count );
+            return count;
+        }
+
+        count++;
+
+    }
+
+    return 0;
+
+}
+
+void shutdown_guest_server( void ) {
+    INFO( "shutdown_guest_server.\n" );
+#ifdef _WIN32
+    if( server_sock ) {
+        closesocket( server_sock );
+    }
+#else
+    if ( server_sock ) {
+        close( server_sock );
+    }
+#endif
+}
diff --git a/tizen/src/guest_server.h b/tizen/src/guest_server.h
new file mode 100644 (file)
index 0000000..16aa759
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef GUEST_SERVER_H_
+#define GUEST_SERVER_H_
+
+#include <pthread.h>
+
+pthread_t start_guest_server( int server_port );
+void shutdown_guest_server( void );
+
+#endif /* GUEST_SERVER_H_ */
diff --git a/tizen/src/hw/beginend_funcs.sh b/tizen/src/hw/beginend_funcs.sh
new file mode 100755 (executable)
index 0000000..9adf46b
--- /dev/null
@@ -0,0 +1,41 @@
+#! /bin/bash
+# Copyright 2008 (C) Intel 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.
+#
+# echo names of functions that are legal between a glBegin and glEnd pair.
+echo -e MAGIC_MACRO\(glVertex{2,3,4}{s,i,f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glTexCoord{1,2,3,4}{s,i,f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glMultiTexCoord{1,2,3,4}{s,i,f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glNormal3{b,s,i,f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glFogCoord{f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glColor{3,4}{b,s,i,f,d,ub,us,ui}{,v}\)\\n
+echo -e MAGIC_MACRO\(glSecondaryColor3{b,s,i,f,d,ub,us,ui}{,v}\)\\n
+echo -e MAGIC_MACRO\(glIndex{s,i,f,d,ub}{,v}\)\\n
+echo -e MAGIC_MACRO\(glVertexAttrib{1,2,3,4}{s,f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glVertexAttrib4{b,i,ub,us,ui}v\)\\n
+echo -e MAGIC_MACRO\(glVertexAttrib4Nub\)\\n
+echo -e MAGIC_MACRO\(glVertexAttrib4N{b,s,i,ub,us,ui}v\)\\n
+echo -e MAGIC_MACRO\(glArrayElement\)\\n
+echo -e MAGIC_MACRO\(glEvalCoord{1,2}{f,d}{,v}\)\\n
+echo -e MAGIC_MACRO\(glEvalPoint{1,2}\)\\n
+echo -e MAGIC_MACRO\(glMaterial{i,f}{,v}\)\\n
+echo -e MAGIC_MACRO\(glCallList\)\\n
+echo -e MAGIC_MACRO\(glCallLists\)\\n
+echo -e MAGIC_MACRO\(glEdgeFlag{,v}\)\\n
diff --git a/tizen/src/hw/gl_func_perso.h b/tizen/src/hw/gl_func_perso.h
new file mode 100755 (executable)
index 0000000..7ee6278
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  Hand-implemented GL/GLX API
+ * 
+ *  Copyright (c) 2006,2007 Even Rouault
+ *
+ * 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.
+ */
+
+MAGIC_MACRO(_init32),
+MAGIC_MACRO(_init64),
+MAGIC_MACRO(_resize_surface),
+MAGIC_MACRO(_render_surface),
+
+/* When you add a glX call here, you HAVE TO update IS_GLX_CALL */
+MAGIC_MACRO(glXChooseVisual),
+MAGIC_MACRO(glXQueryExtensionsString),
+MAGIC_MACRO(glXQueryServerString),
+MAGIC_MACRO(glXCreateContext),
+MAGIC_MACRO(glXCopyContext),
+MAGIC_MACRO(glXDestroyContext),
+MAGIC_MACRO(glXGetClientString),
+MAGIC_MACRO(glXQueryVersion),
+MAGIC_MACRO(glXMakeCurrent),
+MAGIC_MACRO(glXGetConfig),
+MAGIC_MACRO(glXGetConfig_extended),
+MAGIC_MACRO(glXWaitGL),
+MAGIC_MACRO(glXWaitX),
+MAGIC_MACRO(glXGetFBConfigAttrib_extended),
+MAGIC_MACRO(glXChooseFBConfig),
+MAGIC_MACRO(glXGetFBConfigs),
+MAGIC_MACRO(glXCreateNewContext),
+MAGIC_MACRO(glXGetVisualFromFBConfig),
+MAGIC_MACRO(glXGetFBConfigAttrib),
+MAGIC_MACRO(glXQueryContext),
+MAGIC_MACRO(glXQueryDrawable),
+MAGIC_MACRO(glXUseXFont),
+MAGIC_MACRO(glXIsDirect),
+MAGIC_MACRO(glXGetProcAddress_fake),
+MAGIC_MACRO(glXGetProcAddress_global_fake),
+MAGIC_MACRO(glXSwapBuffers),
+MAGIC_MACRO(glXQueryExtension),
+MAGIC_MACRO(glXGetScreenDriver),
+MAGIC_MACRO(glXGetDriverConfig),
+MAGIC_MACRO(glXSwapIntervalSGI),
+
+MAGIC_MACRO(glGetString),
+
+MAGIC_MACRO(glShaderSourceARB_fake),
+MAGIC_MACRO(glShaderSource_fake),
+MAGIC_MACRO(glVertexPointer_fake),
+MAGIC_MACRO(glNormalPointer_fake),
+MAGIC_MACRO(glColorPointer_fake),
+MAGIC_MACRO(glSecondaryColorPointer_fake),
+MAGIC_MACRO(glIndexPointer_fake),
+MAGIC_MACRO(glTexCoordPointer_fake),
+MAGIC_MACRO(glEdgeFlagPointer_fake),
+MAGIC_MACRO(glVertexAttribPointerARB_fake),
+MAGIC_MACRO(glVertexAttribPointerNV_fake),
+MAGIC_MACRO(glWeightPointerARB_fake),
+MAGIC_MACRO(glMatrixIndexPointerARB_fake),
+MAGIC_MACRO(glFogCoordPointer_fake),
+MAGIC_MACRO(glVariantPointerEXT_fake),
+MAGIC_MACRO(glInterleavedArrays_fake),
+MAGIC_MACRO(glElementPointerATI_fake),
+MAGIC_MACRO(glTuxRacerDrawElements_fake),
+MAGIC_MACRO(glVertexAndNormalPointer_fake),
+MAGIC_MACRO(glTexCoordPointer01_fake),
+MAGIC_MACRO(glTexCoordPointer012_fake),
+MAGIC_MACRO(glVertexNormalPointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorPointerInterlaced_fake),
+MAGIC_MACRO(glVertexColorTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord01PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord012PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord01PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord012PointerInterlaced_fake),
+MAGIC_MACRO(glGenTextures_fake),
+MAGIC_MACRO(glGenBuffersARB_fake),
+MAGIC_MACRO(glGenLists_fake),
+MAGIC_MACRO(_glDrawElements_buffer),
+MAGIC_MACRO(_glDrawRangeElements_buffer),
+MAGIC_MACRO(_glMultiDrawElements_buffer),
+MAGIC_MACRO(_glVertexPointer_buffer),
+MAGIC_MACRO(_glNormalPointer_buffer),
+MAGIC_MACRO(_glColorPointer_buffer),
+MAGIC_MACRO(_glSecondaryColorPointer_buffer),
+MAGIC_MACRO(_glIndexPointer_buffer),
+MAGIC_MACRO(_glTexCoordPointer_buffer),
+MAGIC_MACRO(_glEdgeFlagPointer_buffer),
+MAGIC_MACRO(_glVertexAttribPointerARB_buffer),
+MAGIC_MACRO(_glWeightPointerARB_buffer),
+MAGIC_MACRO(_glMatrixIndexPointerARB_buffer),
+MAGIC_MACRO(_glFogCoordPointer_buffer),
+MAGIC_MACRO(_glVariantPointerEXT_buffer),
+MAGIC_MACRO(_glGetError_fake),
+MAGIC_MACRO(_glReadPixels_pbo),
+MAGIC_MACRO(_glDrawPixels_pbo),
+MAGIC_MACRO(_glMapBufferARB_fake),
+MAGIC_MACRO(_glSelectBuffer_fake),
+MAGIC_MACRO(_glGetSelectBuffer_fake),
+MAGIC_MACRO(_glFeedbackBuffer_fake),
+MAGIC_MACRO(_glGetFeedbackBuffer_fake),
diff --git a/tizen/src/hw/gloffscreen.h b/tizen/src/hw/gloffscreen.h
new file mode 100755 (executable)
index 0000000..e860c07
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  Offscreen OpenGL abstraction layer
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef GLOFFSCREEN_H_
+#define GLOFFSCREEN_H_
+
+/* Used to hold data for the OpenGL context */
+struct _GloContext;
+typedef struct _GloContext GloContext;
+/* Used to hold data for an offscreen surface. */
+struct _GloSurface;
+typedef struct _GloSurface GloSurface;
+
+/* Format flags for glo_surface_create */
+#define GLO_FF_ALPHA_MASK  (0x0001)
+#define GLO_FF_NOALPHA     (0x0000)
+#define GLO_FF_ALPHA       (0x0001)
+
+#define GLO_FF_BITS_MASK   (0x00F0)
+#define GLO_FF_BITS_16     (0x0020)
+#define GLO_FF_BITS_24     (0x0030)
+#define GLO_FF_BITS_32     (0x0040)
+
+#define GLO_FF_DEPTH_MASK   (0x0F00)
+#define GLO_FF_DEPTH_16     (0x0100)
+#define GLO_FF_DEPTH_24     (0x0200)
+#define GLO_FF_DEPTH_32     (0x0300)
+
+#define GLO_FF_STENCIL_MASK   (0xF000)
+#define GLO_FF_STENCIL_8      (0x1000)
+
+/* The only currently supported format */
+#define GLO_FF_DEFAULT     (GLO_FF_BITS_24|GLO_FF_DEPTH_24)
+
+/* Has gloffscreen been previously initialised? */
+extern int glo_initialised(void);
+
+/* Initialise gloffscreen */
+extern int glo_init(void);
+
+/* Uninitialise gloffscreen */
+extern void glo_kill(void);
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+extern void *glo_getprocaddress(const char *procName);
+
+/* OS-independent glXQueryExtensionsString */
+extern const char *glo_glXQueryExtensionsString(void);
+
+/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
+extern GloContext *glo_context_create(int formatFlags, GloContext *shareLists);
+
+/* Destroy a previouslu created OpenGL context */
+extern void glo_context_destroy(GloContext *context);
+
+/* Create a surface with given width and height, */
+extern GloSurface *glo_surface_create(int width, int height, GloContext *context);
+
+/* Destroy the given surface */
+extern void glo_surface_destroy(GloSurface *surface);
+
+/* Make the given surface current */
+extern int glo_surface_makecurrent(GloSurface *surface);
+
+/* Get the contents of the given surface. Note that this is top-down, not
+ * bottom-up as glReadPixels would do. */
+extern void glo_surface_getcontents(GloSurface *surface, int stride, int type, void *data);
+
+/* Return the width and height of the given surface */
+extern void glo_surface_get_size(GloSurface *surface, int *width, int *height);
+
+/* Functions to decode the format flags */
+extern int glo_flags_get_depth_bits(int formatFlags);
+extern int glo_flags_get_stencil_bits(int formatFlags);
+extern void glo_flags_get_rgba_bits(int formatFlags, int *rgba);
+extern int glo_flags_get_bytes_per_pixel(int formatFlags);
+extern void glo_flags_get_readpixel_type(int formatFlags, int *glFormat, int *glType);
+/* Score how close the given format flags match. 0=great, >0 not so great */
+extern int glo_flags_score(int formatFlagsExpected, int formatFlagsReal);
+
+/* Create a set of format flags from a null-terminated list
+ * of GLX fbConfig flags. If assumeBooleans is set, items such
+ * as GLX_RGBA/GLX_DOUBLEBUFFER are treated as booleans, not key-value pairs
+ * (glXChooseVisual treats them as booleans, glXChooseFBConfig as key-value pairs)
+ */
+extern int glo_flags_get_from_glx(const int *fbConfig, int assumeBooleans);
+/* Use in place of glxGetConfig - returns information from flags based on a GLX enum */
+extern int glo_get_glx_from_flags(int formatFlags, int glxEnum);
+
+
+/* In terms of speed, glReadPixels actually seems the best we can do.
+ * * On Windows PFB_DRAW_TO_BITMAP is software-only.
+ * * http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt would be
+ * useful if we didn't want the data right away (as we could avoid flushing the
+ * pipeline).
+ * * The internal data format seems to be GL_BGRA - and this is indeed faster.
+ * * Apple suggests using GL_UNSIGNED_INT_8_8_8_8_REV instead of
+ * GL_UNSIGNED_BYTE, but there don't appear to be any speed increase from
+ * doing this on Windows at least.
+ */
+
+#endif /* GLOFFSCREEN_H_ */
diff --git a/tizen/src/hw/gloffscreen_common.c b/tizen/src/hw/gloffscreen_common.c
new file mode 100755 (executable)
index 0000000..c97b9c1
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ *  Offscreen OpenGL abstraction layer - Common utilities
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by:
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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 "gloffscreen.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *g_malloc(size_t size);
+void *g_realloc(void *ptr, size_t size);
+void g_free(void *ptr);
+
+// ---------------------------------------------------
+//  Copied from glx.h as we need them in windows too
+/*
+ * Tokens for glXChooseVisual and glXGetConfig:
+ */
+#define GLX_USE_GL      1
+#define GLX_BUFFER_SIZE     2
+#define GLX_LEVEL       3
+#define GLX_RGBA        4
+#define GLX_DOUBLEBUFFER    5
+#define GLX_STEREO      6
+#define GLX_AUX_BUFFERS     7
+#define GLX_RED_SIZE        8
+#define GLX_GREEN_SIZE      9
+#define GLX_BLUE_SIZE       10
+#define GLX_ALPHA_SIZE      11
+#define GLX_DEPTH_SIZE      12
+#define GLX_STENCIL_SIZE    13
+#define GLX_ACCUM_RED_SIZE  14
+#define GLX_ACCUM_GREEN_SIZE    15
+#define GLX_ACCUM_BLUE_SIZE 16
+#define GLX_ACCUM_ALPHA_SIZE    17
+/*
+ * GLX 1.3 and later:
+ */
+#define GLX_CONFIG_CAVEAT              0x20
+#define GLX_DONT_CARE                  0xFFFFFFFF
+#define GLX_X_VISUAL_TYPE              0x22
+#define GLX_TRANSPARENT_TYPE           0x23
+#define GLX_TRANSPARENT_INDEX_VALUE    0x24
+#define GLX_TRANSPARENT_RED_VALUE      0x25
+#define GLX_TRANSPARENT_GREEN_VALUE    0x26
+#define GLX_TRANSPARENT_BLUE_VALUE     0x27
+#define GLX_TRANSPARENT_ALPHA_VALUE    0x28
+#define GLX_WINDOW_BIT                 0x00000001
+#define GLX_NONE                       0x8000
+#define GLX_TRUE_COLOR                 0x8002
+#define GLX_VISUAL_ID                  0x800B
+#define GLX_DRAWABLE_TYPE              0x8010
+#define GLX_RENDER_TYPE                        0x8011
+#define GLX_X_RENDERABLE               0x8012
+#define GLX_FBCONFIG_ID                        0x8013
+#define GLX_RGBA_TYPE                  0x8014
+#define GLX_MAX_PBUFFER_WIDTH          0x8016
+#define GLX_MAX_PBUFFER_HEIGHT         0x8017
+#define GLX_MAX_PBUFFER_PIXELS         0x8018
+#define GLX_LARGEST_PBUFFER            0x801C
+#define GLX_RGBA_BIT                   0x00000001
+
+// ---------------------------------------------------
+
+extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
+                                    int bpp, int width, int height, void *data);
+
+// ---------------------------------------------------
+
+int glo_flags_get_depth_bits(int formatFlags) {
+    switch ( formatFlags & GLO_FF_DEPTH_MASK ) {
+        case GLO_FF_DEPTH_16: return 16;
+        case GLO_FF_DEPTH_24: return 24;
+        case GLO_FF_DEPTH_32: return 32;
+        default: return 0;
+    }
+}
+
+int glo_flags_get_stencil_bits(int formatFlags) {
+    switch ( formatFlags & GLO_FF_STENCIL_MASK ) {
+        case GLO_FF_STENCIL_8: return 8;
+        default: return 0;
+    }
+}
+
+void glo_flags_get_rgba_bits(int formatFlags, int *rgba) {
+    int alpha = (formatFlags & GLO_FF_ALPHA) != 0;
+    switch ( formatFlags & GLO_FF_BITS_MASK ) {
+        case GLO_FF_BITS_16:
+            rgba[0] = alpha ? 4 : 5;
+            rgba[1] = alpha ? 4 : 6;
+            rgba[2] = alpha ? 4 : 5;
+            rgba[3] = alpha ? 4 : 0;
+            break;
+        case GLO_FF_BITS_24:
+            // ignore alpha
+            rgba[0] = 8;
+            rgba[1] = 8;
+            rgba[2] = 8;
+            rgba[3] = 0;
+            break;
+        case GLO_FF_BITS_32:
+            rgba[0] = 8;
+            rgba[1] = 8;
+            rgba[2] = 8;
+            rgba[3] = 8;
+            break;
+        default:
+            rgba[0] = 8;
+            rgba[1] = 8;
+            rgba[2] = 8;
+            rgba[3] = 0;
+            break;
+      }
+}
+
+int glo_flags_get_bytes_per_pixel(int formatFlags) {
+    switch ( formatFlags & GLO_FF_BITS_MASK ) {
+        case GLO_FF_BITS_16: return 2;
+        case GLO_FF_BITS_24: return 3;
+        case GLO_FF_BITS_32: return 4;
+        default: return 3;
+    }
+}
+
+void glo_flags_get_readpixel_type(int formatFlags, int *glFormat, int *glType) {
+    GLenum gFormat, gType;
+
+    if (formatFlags & GLO_FF_ALPHA) {
+        switch ( formatFlags & GLO_FF_BITS_MASK ) {
+            case GLO_FF_BITS_16:
+                gFormat = GL_RGBA;
+                gType = GL_UNSIGNED_SHORT_4_4_4_4;
+                break;
+            case GLO_FF_BITS_24:
+            case GLO_FF_BITS_32:
+            default:
+                gFormat = GL_BGRA;
+                gType = GL_UNSIGNED_BYTE;
+                break;
+        }
+    } else {
+        switch ( formatFlags & GLO_FF_BITS_MASK ) {
+            case GLO_FF_BITS_16:
+                gFormat = GL_RGB;
+                gType = GL_UNSIGNED_SHORT_5_6_5;
+                break;
+            case GLO_FF_BITS_24:
+            case GLO_FF_BITS_32:
+            default:
+                gFormat = GL_BGR;
+                gType = GL_UNSIGNED_BYTE;
+                break;
+        }
+    }
+
+    if (glFormat)
+        *glFormat = gFormat;
+    if (glType)
+        *glType = gType;
+}
+
+#if 0
+// seems wrong below.
+int glo_flags_score(int formatFlagsExpected, int formatFlagsReal) {
+
+    if (formatFlagsExpected == formatFlagsReal)
+        return 0;
+
+    int score = 1;
+
+    // we wanted alpha, but we didn't get it
+    if ((formatFlagsExpected&GLO_FF_ALPHA_MASK) <
+        (formatFlagsReal&GLO_FF_ALPHA_MASK))
+        score++;
+    // less bits than we expected
+    if ((formatFlagsExpected&GLO_FF_BITS_MASK) <
+        !(formatFlagsReal&GLO_FF_BITS_MASK))
+        score++;
+    // less depth bits than we expected
+    if ((formatFlagsExpected&GLO_FF_DEPTH_MASK) <
+        !(formatFlagsReal&GLO_FF_DEPTH_MASK))
+        score++;
+    // less stencil bits than we expected
+    if ((formatFlagsExpected&GLO_FF_STENCIL_MASK) <
+        !(formatFlagsReal&GLO_FF_STENCIL_MASK))
+        score++;
+
+    return score;
+}
+#else
+int glo_flags_score(int formatFlagsExpected, int formatFlagsReal) {
+
+    if (formatFlagsExpected == formatFlagsReal)
+        return 0;
+
+    int score = 1;
+
+    // we wanted alpha, but we didn't get it
+    if ((formatFlagsReal & GLO_FF_ALPHA_MASK) <
+        (formatFlagsExpected  & GLO_FF_ALPHA_MASK))
+        score++;
+    // less bits than we expected
+    if ((formatFlagsReal & GLO_FF_BITS_MASK) <
+        (formatFlagsExpected & GLO_FF_BITS_MASK))
+        score++;
+    // less depth bits than we expected
+    if ((formatFlagsReal & GLO_FF_DEPTH_MASK) <
+        (formatFlagsExpected & GLO_FF_DEPTH_MASK))
+        score++;
+    // less stencil bits than we expected
+    if ((formatFlagsReal & GLO_FF_STENCIL_MASK) <
+        (formatFlagsExpected & GLO_FF_STENCIL_MASK))
+        score++;
+
+    return score;
+}
+#endif
+
+int glo_flags_get_from_glx(const int *fbConfig, int assumeBooleans) {
+    int bufferSize = 0;
+    int depthSize = 0;
+    int stencilSize = 0;
+    int rgbaSize[] = {0,0,0,0};
+    int flags = 0;
+
+    while (*fbConfig) {
+        int isSingle = 0;
+        switch (*fbConfig) {
+            case GLX_USE_GL:
+                isSingle = 1;
+                break;
+            case GLX_BUFFER_SIZE:
+                bufferSize = fbConfig[1];
+                break;
+            case GLX_LEVEL:
+                break;
+            case GLX_RGBA:
+                flags |= GLO_FF_ALPHA;
+                break;
+            case GLX_DOUBLEBUFFER:
+                isSingle = 1;
+                break;
+            case GLX_STEREO:
+                isSingle = 1;
+                break;
+            case GLX_AUX_BUFFERS:
+                break;
+            case GLX_RED_SIZE:
+                rgbaSize[0] = fbConfig[1];
+                break;
+            case GLX_GREEN_SIZE:
+                rgbaSize[1] = fbConfig[1];
+                break;
+            case GLX_BLUE_SIZE:
+                rgbaSize[2] = fbConfig[1];
+                break;
+            case GLX_ALPHA_SIZE:
+                rgbaSize[3] = fbConfig[1];
+                break;
+            case GLX_DEPTH_SIZE:
+                depthSize = fbConfig[1];
+                break;
+            case GLX_STENCIL_SIZE:
+                stencilSize = fbConfig[1];
+                break;
+            case GLX_ACCUM_RED_SIZE:
+            case GLX_ACCUM_GREEN_SIZE:
+            case GLX_ACCUM_BLUE_SIZE:
+            case GLX_ACCUM_ALPHA_SIZE:
+                break;
+        }
+
+        // go to next
+        if (isSingle && assumeBooleans)
+            fbConfig++;
+        else
+            fbConfig+=2;
+    }
+
+    if (rgbaSize[3])
+        flags |= GLO_FF_ALPHA;
+    // ensure we have room for *some* alpha
+    if ((flags & GLO_FF_ALPHA) && (rgbaSize[3]==0))
+        rgbaSize[3] = 1;
+    // Buffer size flag
+    if (bufferSize==0)
+        bufferSize = rgbaSize[0]+rgbaSize[1]+rgbaSize[2]+rgbaSize[3];
+    if (bufferSize==0)
+        bufferSize = (flags & GLO_FF_ALPHA) ? 32 : 24;
+    if (bufferSize<=16)
+        flags |= GLO_FF_BITS_16;
+    else if (bufferSize<=24)
+        flags |= GLO_FF_BITS_24;
+    else
+        flags |= GLO_FF_BITS_32;
+
+    // Depth
+    if (depthSize<=16)
+        flags |= GLO_FF_DEPTH_16;
+    else if (depthSize<=24)
+        flags |= GLO_FF_DEPTH_24;
+    else
+        flags |= GLO_FF_DEPTH_32;
+    // Stencil
+    if (stencilSize>0)
+        flags |= GLO_FF_STENCIL_8;
+
+    return flags;
+}
+
+void glo_surface_getcontents_readpixels(int formatFlags, int stride, int bpp,
+                             int width, int height, void *data) {
+    int glFormat, glType, rl, pa;
+    static int once;
+
+    glo_flags_get_readpixel_type(formatFlags, &glFormat, &glType);
+    switch(bpp) {
+        case 24:
+            if(glFormat != GL_BGR) {
+                if(!once) {
+                    fprintf(stderr, "Warning: compressing alpha\n");
+                    once = 1;
+                }
+                glFormat = GL_BGR;
+            }
+            break;
+        case 32:
+            if(glFormat != GL_BGRA) {
+                fprintf(stderr, "Warning: expanding alpha!\n");
+                glFormat = GL_BGRA;
+            }
+            break;
+        default:
+            fprintf(stderr, "Warning: unsupported colourdepth\n");
+            break;
+    }
+
+    // Save guest processes GL state before we ReadPixels()
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &rl);
+    glGetIntegerv(GL_PACK_ALIGNMENT, &pa);
+    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+#ifdef GETCONTENTS_INDIVIDUAL
+    GLubyte *b = (GLubyte *)data;
+    int irow;
+    for(irow = height-1 ; irow >= 0 ; irow--) {
+        glReadPixels(0, irow, width, 1, glFormat, glType, b);
+        b += stride;
+    }
+#else
+    // Faster buffer flip
+    GLubyte *b = (GLubyte *)data;
+    GLubyte *c = &((GLubyte *)data)[stride*(height-1)];
+    GLubyte *tmp = (GLubyte*)g_malloc(stride);
+    int irow;
+
+    glReadPixels(0, 0, width, height, glFormat, glType, data);
+
+    for(irow = 0; irow < height/2; irow++) {
+        memcpy(tmp, b, stride);
+        memcpy(b, c, stride);
+        memcpy(c, tmp, stride);
+        b += stride;
+        c -= stride;
+    }
+    g_free(tmp);
+
+#endif
+
+    // Restore GL state
+    glPixelStorei(GL_PACK_ROW_LENGTH, rl);
+    glPixelStorei(GL_PACK_ALIGNMENT, pa);
+}
+
+int glo_get_glx_from_flags(int formatFlags, int glxEnum) {
+    int rgba[4];
+    glo_flags_get_rgba_bits(formatFlags, rgba);
+
+    switch (glxEnum) {
+        case GLX_USE_GL: return 1;
+        case GLX_BUFFER_SIZE:
+            return glo_flags_get_bytes_per_pixel(formatFlags)*8;
+        case GLX_LEVEL: return 0;
+        case GLX_RGBA: return formatFlags & GLO_FF_ALPHA;
+        case GLX_DOUBLEBUFFER: return 1;
+        case GLX_STEREO: return 0;
+        case GLX_AUX_BUFFERS: return 0;
+        case GLX_RED_SIZE: return rgba[0];
+        case GLX_GREEN_SIZE: return rgba[1];
+        case GLX_BLUE_SIZE: return rgba[2];
+        case GLX_ALPHA_SIZE: return rgba[3];
+        case GLX_DEPTH_SIZE: return glo_flags_get_depth_bits(formatFlags);
+        case GLX_STENCIL_SIZE: return glo_flags_get_stencil_bits(formatFlags);
+        case GLX_ACCUM_RED_SIZE:
+        case GLX_ACCUM_GREEN_SIZE:
+        case GLX_ACCUM_BLUE_SIZE:
+        case GLX_ACCUM_ALPHA_SIZE:
+            return 0;
+        //the attributes for glXGetFBConfigAttrib
+        case GLX_FBCONFIG_ID: return 0;
+        case GLX_RENDER_TYPE: return GLX_RGBA_BIT;
+        case GLX_DRAWABLE_TYPE: return GLX_WINDOW_BIT;
+        case GLX_X_RENDERABLE: return 1;
+        case GLX_VISUAL_ID:
+        case GLX_X_VISUAL_TYPE:
+            // the real value is obtained in client side.
+            return 0;
+        case GLX_CONFIG_CAVEAT: return GLX_NONE;
+        case GLX_TRANSPARENT_TYPE: return GLX_NONE;
+        case GLX_TRANSPARENT_INDEX_VALUE:
+        case GLX_TRANSPARENT_RED_VALUE:
+        case GLX_TRANSPARENT_GREEN_VALUE:
+        case GLX_TRANSPARENT_BLUE_VALUE:
+        case GLX_TRANSPARENT_ALPHA_VALUE:
+            return 0;
+        case GLX_MAX_PBUFFER_WIDTH:
+        case GLX_MAX_PBUFFER_HEIGHT:
+        case GLX_MAX_PBUFFER_PIXELS:
+            return 0;
+    }
+    return 0;
+}
+
diff --git a/tizen/src/hw/gloffscreen_glx.c b/tizen/src/hw/gloffscreen_glx.c
new file mode 100755 (executable)
index 0000000..e807c6b
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  Offscreen OpenGL abstraction layer - GLX specific
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef _WIN32
+#include "gloffscreen.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+
+struct GloMain {
+  Display *dpy;
+  int use_ximage;
+};
+struct GloMain glo;
+int glo_inited = 0;
+
+struct _GloContext {
+  GLuint                formatFlags;
+
+  GLXFBConfig           fbConfig;
+  GLXContext            context;
+};
+
+struct _GloSurface {
+  GLuint                width;
+  GLuint                height;
+
+  GloContext           *context;
+  Pixmap                xPixmap;
+  GLXPixmap             glxPixmap;
+
+  // For use by the 'fast' copy code.
+  XImage               *image;
+  XShmSegmentInfo       shminfo;
+};
+
+extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
+                                    int bpp, int width, int height, void *data);
+static void glo_test_readback_methods(void);
+
+/* ------------------------------------------------------------------------ */
+
+int glo_initialised(void) {
+  return glo_inited;
+}
+
+/* Initialise gloffscreen */
+int glo_init(void) {
+    if (glo_inited) {
+        printf( "gloffscreen already inited\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+    /* Open a connection to the X server */
+    glo.dpy = XOpenDisplay( NULL );
+    if ( glo.dpy == NULL ) {
+        printf( "Unable to open a connection to the X server\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+    glo_inited = 1;
+    glo_test_readback_methods();
+
+       return 0;
+}
+
+/* Uninitialise gloffscreen */
+void glo_kill(void) {
+    XCloseDisplay(glo.dpy);
+    glo.dpy = NULL;
+}
+
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+void *glo_getprocaddress(const char *procName) {
+    if (!glo_inited)
+      glo_init();
+    return glXGetProcAddressARB((const GLubyte *) procName);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
+GloContext *glo_context_create(int formatFlags, GloContext *shareLists) {
+  if (!glo_inited)
+    glo_init();
+
+  GLXFBConfig          *fbConfigs;
+  int                   numReturned;
+  GloContext           *context;
+  int                   rgbaBits[4];
+  int                   bufferAttributes[] = {
+      GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+      GLX_RENDER_TYPE,   GLX_RGBA_BIT,
+      GLX_RED_SIZE,      8,
+      GLX_GREEN_SIZE,    8,
+      GLX_BLUE_SIZE,     8,
+      GLX_ALPHA_SIZE,    8,
+      GLX_DEPTH_SIZE,    0,
+      GLX_STENCIL_SIZE,  0,
+      None
+  };
+
+  if (!glo_inited)
+    glo_init();
+
+  // set up the surface format from the flags we were given
+  glo_flags_get_rgba_bits(formatFlags, rgbaBits);
+  bufferAttributes[5]  = rgbaBits[0];
+  bufferAttributes[7]  = rgbaBits[1];
+  bufferAttributes[9]  = rgbaBits[2];
+  bufferAttributes[11] = rgbaBits[3];
+  bufferAttributes[13] = glo_flags_get_depth_bits(formatFlags);
+  bufferAttributes[15] = glo_flags_get_stencil_bits(formatFlags);
+
+  //printf("Got R%d, G%d, B%d, A%d\n", rgbaBits[0], rgbaBits[1], rgbaBits[2], rgbaBits[3]);
+
+  fbConfigs = glXChooseFBConfig( glo.dpy, DefaultScreen(glo.dpy),
+                                 bufferAttributes, &numReturned );
+  if (numReturned==0) {
+      printf( "No matching configs found.\n" );
+      //exit( EXIT_FAILURE );
+         return NULL;
+  }
+  context = (GloContext*)qemu_malloc(sizeof(GloContext));
+  memset(context, 0, sizeof(GloContext));
+  context->formatFlags = formatFlags;
+  context->fbConfig = fbConfigs[0];
+
+  /* Create a GLX context for OpenGL rendering */
+  context->context = glXCreateNewContext(glo.dpy, context->fbConfig,
+                                         GLX_RGBA_TYPE,
+                                         shareLists ? shareLists->context: NULL,
+                                         True );
+
+  if (!context->context) {
+    printf( "glXCreateNewContext failed\n" );
+    //exit( EXIT_FAILURE );
+       return NULL;
+  }
+
+  return context;
+}
+
+/* Destroy a previouslu created OpenGL context */
+void glo_context_destroy(GloContext *context) {
+  if (!context) return;
+  // TODO: check for GloSurfaces using this?
+  glXDestroyContext( glo.dpy, context->context);
+  qemu_free(context);
+}
+
+static void glo_surface_free_xshm_image(GloSurface *surface) {
+      XShmDetach(glo.dpy, &surface->shminfo);
+      surface->image->data = NULL;
+      XDestroyImage(surface->image);
+      shmdt(surface->shminfo.shmaddr);
+      shmctl(surface->shminfo.shmid, IPC_RMID, NULL);
+}
+
+//FIXMEIM - handle failure to allocate.
+static void glo_surface_try_alloc_xshm_image(GloSurface *surface) {
+    if(surface->image)
+      glo_surface_free_xshm_image(surface);
+
+    surface->image =
+      XShmCreateImage(glo.dpy, DefaultVisual(glo.dpy, 0), 24, ZPixmap, NULL,
+                      &surface->shminfo, surface->width, surface->height);
+    surface->shminfo.shmid = shmget(IPC_PRIVATE,
+                                    surface->image->bytes_per_line *
+                                                           surface->height,
+                                    IPC_CREAT | 0777);
+    surface->shminfo.shmaddr = shmat(surface->shminfo.shmid, NULL, 0);
+    surface->image->data = surface->shminfo.shmaddr;
+    surface->shminfo.readOnly = False;
+    XShmAttach(glo.dpy, &surface->shminfo);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create a surface with given width and height, formatflags are from the
+ * GLO_ constants */
+GloSurface *glo_surface_create(int width, int height, GloContext *context) {
+    GloSurface           *surface;
+
+    if (!context) return 0;
+
+    surface = (GloSurface*)qemu_malloc(sizeof(GloSurface));
+    memset(surface, 0, sizeof(GloSurface));
+    surface->width = width;
+    surface->height = height;
+    surface->context = context;
+    surface->xPixmap = XCreatePixmap( glo.dpy, DefaultRootWindow(glo.dpy),
+                                      width, height,
+                                      glo_flags_get_bytes_per_pixel(context->formatFlags)*8);
+
+    if (!surface->xPixmap) {
+      printf( "XCreatePixmap failed\n" );
+      //exit( EXIT_FAILURE );
+         return NULL;
+    }
+
+    /* Create a GLX window to associate the frame buffer configuration
+    ** with the created X window */
+    surface->glxPixmap = glXCreatePixmap( glo.dpy, context->fbConfig, surface->xPixmap, NULL );
+    if (!surface->glxPixmap) {
+      printf( "glXCreatePixmap failed\n" );
+      //exit( EXIT_FAILURE );
+         return NULL;
+    }
+
+    // If we're using XImages to pull the data from the graphics card...
+    glo_surface_try_alloc_xshm_image(surface);
+
+    return surface;
+}
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface) {
+    glXDestroyPixmap( glo.dpy, surface->glxPixmap);
+    XFreePixmap( glo.dpy, surface->xPixmap);
+    if(surface->image)
+      glo_surface_free_xshm_image(surface);
+    qemu_free(surface);
+}
+
+/* Make the given surface current */
+int glo_surface_makecurrent(GloSurface *surface) {
+    int ret;
+
+    if (!glo_inited)
+      glo_init();
+
+    if (surface) {
+      ret = glXMakeCurrent(glo.dpy, surface->glxPixmap, surface->context->context);
+    } else {
+      ret = glXMakeCurrent(glo.dpy, 0, NULL);
+    }
+
+    return ret;
+}
+
+/*
+#define geti(a) \
+   do { \
+      int b; \
+      glGetIntegerv(a, &b); \
+      fprintf(stderr, "%s: %d\n", #a, b); \
+   } while (0);
+*/
+
+/* Get the contents of the given surface */
+void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
+    static int once;
+    XImage *img;
+
+    if (!surface)
+      return;
+
+    if(glo.use_ximage) {
+      glXWaitGL();
+    
+      if(surface->image) {
+        XShmGetImage (glo.dpy, surface->xPixmap, surface->image, 0, 0, AllPlanes);
+        img = surface->image;
+      }
+      else {
+        img = XGetImage(glo.dpy, surface->xPixmap, 0, 0, surface->width, surface->height, AllPlanes, ZPixmap);
+      }
+
+      if (img) {
+        if(bpp != 32 && bpp != 24 && !once) {
+          fprintf(stderr, "Warning: unsupported colourdepth\n");
+          once = 1;
+        }
+
+        if(bpp == img->bits_per_pixel && stride == img->bytes_per_line)
+        {
+          memcpy(data, img->data, stride * surface->height);
+        }
+        else
+        {
+          int x, y;
+          for(y = 0 ; y < surface->height ; y++) {
+            for(x = 0 ; x < surface->width ; x++) {
+              char *src = ((char*)img->data) + (x*(img->bits_per_pixel/8)) + (y*img->bytes_per_line);
+              char *dst = ((char*)data) + x*(bpp/8) + (y*stride);
+              dst[0] = src[0];
+              dst[1] = src[1];
+              dst[2] = src[2];
+              if(bpp == 32)
+                dst[3] = 0xff; // if guest is 32 bit and host is 24
+            }
+          }
+        }
+  
+       // If we're not using Shm
+       if(!surface->image)
+         XDestroyImage(img);
+
+       return;  // We're done.
+     } 
+     // Uh oh... better fallback. Perhaps get glo.use_ximage to 0?
+   }
+
+   // Compatible / fallback method.
+   glo_surface_getcontents_readpixels(surface->context->formatFlags,
+                                         stride, bpp, surface->width,
+                                         surface->height, data);
+}
+
+//    while(0) {
+//        char fname[30];
+//        int y;
+//        sprintf(fname, "dbg_%08x_%dx%d.rgb", surface, surface->width, surface->height);
+//        FILE *d = fopen(fname, "wb");
+//        for(y = 0 ; y < surface->height ; y++)
+//          fwrite(data + (y*stride), surface->width*3, 1, d);
+//        fclose(d);
+//    }
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
+    if (width)
+      *width = surface->width;
+    if (height)
+      *height = surface->height;
+}
+
+/* Abstract glXQueryExtensionString() */
+const char *glo_glXQueryExtensionsString(void) {
+  return glXQueryExtensionsString(glo.dpy, 0);
+}
+
+
+#define TX (17)
+#define TY (16)
+
+static int glo_can_readback(void) {
+    GloContext *context;
+    GloSurface *surface;
+
+    unsigned char *datain = (unsigned char *)qemu_malloc(4*TX*TY);
+    unsigned char *datain_flip = (unsigned char *)qemu_malloc(4*TX*TY); // flipped input data (for GL)
+    unsigned char *dataout = (unsigned char *)qemu_malloc(4*TX*TY);
+    unsigned char *p;
+    int x,y;
+
+    const int bufferAttributes[] = {
+            GLX_RED_SIZE,      8,
+            GLX_GREEN_SIZE,    8,
+            GLX_BLUE_SIZE,     8,
+            GLX_ALPHA_SIZE,    8,
+            GLX_DEPTH_SIZE,    0,
+            GLX_STENCIL_SIZE,  0,
+            0,
+        };
+
+    int bufferFlags = glo_flags_get_from_glx(bufferAttributes, 0);
+    int bpp = glo_flags_get_bytes_per_pixel(bufferFlags);
+    int glFormat, glType;
+
+    memset(datain_flip, 0, TX*TY*4);
+    memset(datain, 0, TX*TY*4);
+
+    p = datain;
+    for (y=0;y<TY;y++) {
+      for (x=0;x<TX;x++) {
+        p[0] = x;
+        p[1] = y;
+        //if (y&1) { p[0]=0; p[1]=0; }
+        if (bpp>2) p[2] = 0;
+        if (bpp>3) p[3] = 0xFF;
+        p+=bpp;
+      }
+      memcpy(&datain_flip[((TY-1)-y)*bpp*TX], &datain[y*bpp*TX], bpp*TX);
+    }
+
+    context = glo_context_create(bufferFlags, 0);
+    surface = glo_surface_create(TX, TY, context);
+
+    glo_surface_makecurrent(surface);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0,TX, 0,TY, 0, 1);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glRasterPos2f(0,0);
+    glo_flags_get_readpixel_type(bufferFlags, &glFormat, &glType);
+    glDrawPixels(TX,TY,glFormat, glType, datain_flip);
+    glFlush();
+
+    memset(dataout, 0, bpp*TX*TY);
+
+    glo_surface_getcontents(surface, TX*4, bpp*8, dataout);
+
+    glo_surface_destroy(surface);
+    glo_context_destroy(context);
+
+    if (memcmp(datain, dataout, bpp*TX*TY)==0)
+        return 1;
+
+    return 0;
+}
+
+static void glo_test_readback_methods(void) {
+    glo.use_ximage = 1;
+    if(!glo_can_readback())
+      glo.use_ximage = 0;
+
+    fprintf(stderr, "VM GL: Using %s readback\n", glo.use_ximage?"XImage":"glReadPixels");
+}
+
+#endif
diff --git a/tizen/src/hw/gloffscreen_test.c b/tizen/src/hw/gloffscreen_test.c
new file mode 100755 (executable)
index 0000000..95a2c51
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *  Offscreen OpenGL abstraction layer
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *
+ * 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 "gloffscreen.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#else
+#include <GL/gl.h>
+#include <sys/time.h>
+#endif
+
+// ---------------------------------------------------
+//  Copied from glx.h as we need them in windows too
+/*
+ * Tokens for glXChooseVisual and glXGetConfig:
+ */
+#define GLX_USE_GL      1
+#define GLX_BUFFER_SIZE     2
+#define GLX_LEVEL       3
+#define GLX_RGBA        4
+#define GLX_DOUBLEBUFFER    5
+#define GLX_STEREO      6
+#define GLX_AUX_BUFFERS     7
+#define GLX_RED_SIZE        8
+#define GLX_GREEN_SIZE      9
+#define GLX_BLUE_SIZE       10
+#define GLX_ALPHA_SIZE      11
+#define GLX_DEPTH_SIZE      12
+#define GLX_STENCIL_SIZE    13
+#define GLX_ACCUM_RED_SIZE  14
+#define GLX_ACCUM_GREEN_SIZE    15
+#define GLX_ACCUM_BLUE_SIZE 16
+#define GLX_ACCUM_ALPHA_SIZE    17
+// ---------------------------------------------------
+
+#define TX (32)
+#define TY (32)
+
+int gl_acceleration_capability_check (void) {
+    int test_failure = 0;
+    GloContext *context;
+    GloSurface *surface;
+    unsigned char *datain = (unsigned char *)malloc(4*TX*TY);
+    unsigned char *datain_flip = (unsigned char *)malloc(4*TX*TY); // flipped input data (for GL)
+    unsigned char *dataout = (unsigned char *)malloc(4*TX*TY);
+    unsigned char *p;
+    int x,y;
+    unsigned int bufferAttributes[] = {
+            GLX_RED_SIZE,      8,
+            GLX_GREEN_SIZE,    8,
+            GLX_BLUE_SIZE,     8,
+            GLX_ALPHA_SIZE,    8,
+            GLX_DEPTH_SIZE,    0,
+            GLX_STENCIL_SIZE,  0,
+            0,
+        };
+    int bufferFlags = glo_flags_get_from_glx(bufferAttributes, 0);
+    int bpp = glo_flags_get_bytes_per_pixel(bufferFlags);
+    int glFormat, glType;
+
+    if (glo_sanity_test () != 0) {
+        // test failed.
+        return 1;
+    }
+
+    memset(datain_flip, 0, TX*TY*4);
+    memset(datain, 0, TX*TY*4);
+    p = datain;
+    for (y=0;y<TY;y++) {
+      for (x=0;x<TX;x++) {
+        p[0] = x;
+        p[1] = y;
+        //if (y&1) { p[0]=0; p[1]=0; }
+        if (bpp>2) p[2] = 0;
+        if (bpp>3) p[3] = 0xFF;
+        p+=bpp;
+      }
+      memcpy(&datain_flip[((TY-1)-y)*bpp*TX], &datain[y*bpp*TX], bpp*TX);
+    }
+
+    glo_init();
+    // new surface
+    context = glo_context_create(bufferFlags, 0);
+       if (context == NULL)
+               return 1;
+
+    surface = glo_surface_create(TX, TY, context);
+       if (surface == NULL)
+               return 1;
+
+    glo_surface_makecurrent(surface);
+    printf("GL VENDOR %s\n", glGetString(GL_VENDOR));
+    printf("GL RENDERER %s\n", glGetString(GL_RENDERER));
+    printf("GL VERSION %s\n", glGetString(GL_VERSION));
+
+    if (strstr (glGetString(GL_RENDERER), "Software")) {
+        printf ("Host does not have GL hardware acceleration!\n");
+        test_failure = 1;
+        goto TEST_END;
+    }
+
+    // fill with stuff (in correctly ordered way)
+    glClear(GL_COLOR_BUFFER_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0,TX, 0,TY, 0, 1);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glRasterPos2f(0,0);
+    glo_flags_get_readpixel_type(bufferFlags, &glFormat, &glType);
+    printf("glFormat: 0x%08X glType: 0x%08X\n", glFormat, glType);
+    glDrawPixels(TX,TY,glFormat, glType, datain_flip);
+    glFlush();
+
+    memset(dataout, 0, bpp*TX*TY);
+
+    glo_surface_getcontents(surface, TX*bpp, bpp*8, dataout);
+
+    // destroy surface
+    glo_surface_destroy(surface);
+    glo_context_destroy(context);
+    // compare
+    if (memcmp(datain, dataout, bpp*TX*TY)!=0) {
+      test_failure = 1;
+    }
+TEST_END:
+    //glo_kill();
+    //printf ("Testing %s\n", (test_failure ? "FAILED" : "PASSED"));
+    free (datain);
+    free (datain_flip);
+    free (dataout);
+    return test_failure;
+}
diff --git a/tizen/src/hw/gloffscreen_wgl.c b/tizen/src/hw/gloffscreen_wgl.c
new file mode 100755 (executable)
index 0000000..ec86ceb
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ *  Offscreen OpenGL abstraction layer - WGL (windows) specific
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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.
+ */
+#ifdef _WIN32
+#include "gloffscreen.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <windows.h>
+#include <wingdi.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/wglext.h>
+
+/* In Windows, you must create a window *before* you can create a pbuffer or
+ * get a context. So we create a hidden Window on startup (see glo_init/GloMain).
+ *
+ * Also, you can't share contexts that have different pixel formats, so we can't just
+ * create a new context from the window. We must create a whole new PBuffer just for
+ * a context :(
+ */
+
+struct GloMain {
+    HINSTANCE             hInstance;
+    HDC                   hDC;
+    HWND                  hWnd; /* Our hidden window */
+    HGLRC                 hContext;
+};
+struct GloMain glo;
+int glo_inited = 0;
+
+struct _GloContext {
+    int                   formatFlags;
+
+    /* Pixel format returned by wglChoosePixelFormat */
+    int                   wglPixelFormat;
+    /* We need a pbuffer to make a context of the right pixelformat :( */
+    HPBUFFERARB           hPBuffer; 
+    HDC                   hDC;
+    HGLRC                 hContext;
+};
+
+struct _GloSurface {
+    GLuint                width;
+    GLuint                height;  
+
+    GloContext           *context;
+    HPBUFFERARB           hPBuffer;
+    HDC                   hDC;
+};
+
+#define GLO_WINDOW_CLASS "QEmuGLClass"
+#define DEFAULT_DEPTH_BUFFER (16)
+
+PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
+PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
+PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
+
+/* ------------------------------------------------------------------------ */
+
+extern const char *glo_glXQueryExtensionsString(void);
+
+extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
+                                    int bpp, int width, int height, void *data);
+
+/* ------------------------------------------------------------------------ */
+
+int glo_initialised(void) {
+    return glo_inited;
+}
+
+/* Sanity test of the host GL capabilities to see whether the gl offscreen
+ * could be well supported
+ */
+int glo_sanity_test (void) {
+    PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+    PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
+    PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+    PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
+    PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
+
+    wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+    wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
+    wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
+    wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
+    wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
+    if (!wglChoosePixelFormatARB ||
+        !wglGetPbufferDCARB ||
+        !wglReleasePbufferDCARB ||
+        !wglCreatePbufferARB ||
+        !wglDestroyPbufferARB) {
+        fprintf (stderr, "Unable to load the required WGL extensions\n");
+        return 1;
+    }
+    // check the shader support. It is for mcompositor to run.
+
+    if (!wglGetProcAddress("glShaderSource")) {
+        fprintf (stderr, "Unable to find shader support\n");
+        return 1;
+    }
+    return 0;
+}
+
+/* Initialise gloffscreen */
+int glo_init(void) {
+    WNDCLASSEX wcx;
+    PIXELFORMATDESCRIPTOR pfd;
+
+    if (glo_inited) {
+        printf( "gloffscreen already inited\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+
+    glo.hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
+
+    wcx.cbSize = sizeof(wcx);
+    wcx.style = 0;
+    wcx.lpfnWndProc = DefWindowProc;
+    wcx.cbClsExtra = 0;
+    wcx.cbWndExtra = 0;
+    wcx.hInstance = glo.hInstance;
+    wcx.hIcon = NULL;
+    wcx.hCursor = NULL;
+    wcx.hbrBackground = NULL;
+    wcx.lpszMenuName =  NULL;
+    wcx.lpszClassName = GLO_WINDOW_CLASS;
+    wcx.hIconSm = NULL;
+    RegisterClassEx(&wcx);
+    glo.hWnd = CreateWindow(
+        GLO_WINDOW_CLASS,
+        "QEmuGL",
+        0,0,0,0,0,
+        (HWND)NULL, (HMENU)NULL,
+        glo.hInstance,
+        (LPVOID) NULL);
+
+    if (!glo.hWnd) {
+        printf( "Unable to create window\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+    glo.hDC = GetDC(glo.hWnd);
+
+    memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
+    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+    pfd.nVersion = 1;
+    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+    pfd.iPixelType = PFD_TYPE_RGBA;
+    pfd.cColorBits = 24;
+    pfd.iLayerType = PFD_MAIN_PLANE;
+    unsigned int pixelFormat = ChoosePixelFormat(glo.hDC, &pfd);
+    DescribePixelFormat(glo.hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+    if (!SetPixelFormat(glo.hDC, pixelFormat, &pfd))
+        return 1;
+
+    glo.hContext = wglCreateContext(glo.hDC);
+    if (glo.hContext == NULL) {
+        printf( "Unable to create GL context\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+    wglMakeCurrent(glo.hDC, glo.hContext);
+
+    // FIXME GW
+    // Need to share lists AND copy state
+
+    // load in the extensions we need
+    //const char       *ext = wglGetExtensionsStringARB(hdc);
+    //"WGL_ARB_pixel_format" "WGL_ARB_pbuffer"
+
+    wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+    wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
+    wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
+    wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
+    wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
+    if (!wglChoosePixelFormatARB ||
+        !wglGetPbufferDCARB ||
+        !wglReleasePbufferDCARB ||
+        !wglCreatePbufferARB ||
+        !wglDestroyPbufferARB) {
+        printf( "Unable to load the required WGL extensions\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+
+    glo_inited = 1;
+
+       return 0
+}
+
+/* Uninitialise gloffscreen */
+void glo_kill(void) {
+    if (glo.hContext) {
+        wglMakeCurrent(NULL, NULL);
+        wglDeleteContext(glo.hContext);
+        glo.hContext = NULL;
+    }
+    if (glo.hDC) {
+        ReleaseDC(glo.hWnd, glo.hDC);
+        glo.hDC = NULL;
+    }
+    if (glo.hWnd) {
+        DestroyWindow(glo.hWnd);
+        glo.hWnd = NULL;
+    }
+    UnregisterClass(GLO_WINDOW_CLASS, glo.hInstance);
+}
+
+const char *glo_glXQueryExtensionsString(void) {
+    return "";
+}
+
+
+static const char *STANDARD_GL_FUNCTIONS ={
+/* Miscellaneous */
+"glClearIndex\0"                       
+"glClearColor\0"                       
+"glClear\0"                            
+"glIndexMask\0"                        
+"glColorMask\0"                        
+"glAlphaFunc\0"                        
+"glBlendFunc\0"                        
+"glLogicOp\0"                          
+"glCullFace\0"                         
+"glFrontFace\0"                        
+"glPointSize\0"                        
+"glLineWidth\0"                        
+"glLineStipple\0"                      
+"glPolygonMode\0"                      
+"glPolygonOffset\0"                    
+"glPolygonStipple\0"                   
+"glGetPolygonStipple\0"                
+"glEdgeFlag\0"                         
+"glEdgeFlagv\0"                        
+"glScissor\0"                          
+"glClipPlane\0"                        
+"glGetClipPlane\0"                     
+"glDrawBuffer\0"                       
+"glReadBuffer\0"                       
+"glEnable\0"                           
+"glDisable\0"                          
+"glIsEnabled\0"                        
+"glEnableClientState\0"                
+"glDisableClientState\0"               
+"glGetBooleanv\0"                      
+"glGetDoublev\0"                       
+"glGetFloatv\0"                        
+"glGetIntegerv\0"                      
+"glPushAttrib\0"                       
+"glPopAttrib\0"                        
+"glPushClientAttrib\0"                 
+"glPopClientAttrib\0"                  
+"glRenderMode\0"                       
+"glGetError\0"                         
+"glGetString\0"                        
+"glFinish\0"                           
+"glFlush\0"                            
+"glHint\0"                             
+/* Depth Buffer */
+"glClearDepth\0"                       
+"glDepthFunc\0"                        
+"glDepthMask\0"                        
+"glDepthRange\0"                       
+/* Accumulation Buffer */
+"glClearAccum\0"                       
+"glAccum\0"                            
+/* Transformation */
+"glMatrixMode\0"                       
+"glOrtho\0"                            
+"glFrustum\0"                          
+"glViewport\0"                         
+"glPushMatrix\0"                       
+"glPopMatrix\0"                        
+"glLoadIdentity\0"                     
+"glLoadMatrixd\0"                      
+"glLoadMatrixf\0"                      
+"glMultMatrixd\0"                      
+"glMultMatrixf\0"                      
+"glRotated\0"                          
+"glRotatef\0"                          
+"glScaled\0"                           
+"glScalef\0"                           
+"glTranslated\0"                       
+"glTranslatef\0"                       
+/* Display Lists */
+"glIsList\0"                           
+"glDeleteLists\0"                      
+"glGenLists\0"                         
+"glNewList\0"                          
+"glEndList\0"                          
+"glCallList\0"                         
+"glCallLists\0"                        
+"glListBase\0"                         
+/* Drawing Functions */
+"glBegin\0"                            
+"glEnd\0"                              
+"glVertex2d\0"                         
+"glVertex2f\0"                         
+"glVertex2i\0"                         
+"glVertex2s\0"                         
+"glVertex3d\0"                         
+"glVertex3f\0"                         
+"glVertex3i\0"                         
+"glVertex3s\0"                         
+"glVertex4d\0"                         
+"glVertex4f\0"                         
+"glVertex4i\0"                         
+"glVertex4s\0"                         
+"glVertex2dv\0"                        
+"glVertex2fv\0"                        
+"glVertex2iv\0"                        
+"glVertex2sv\0"                        
+"glVertex3dv\0"                        
+"glVertex3fv\0"                        
+"glVertex3iv\0"                        
+"glVertex3sv\0"                        
+"glVertex4dv\0"                        
+"glVertex4fv\0"                        
+"glVertex4iv\0"                        
+"glVertex4sv\0"                        
+"glNormal3b\0"                         
+"glNormal3d\0"                         
+"glNormal3f\0"                         
+"glNormal3i\0"                         
+"glNormal3s\0"                         
+"glNormal3bv\0"                        
+"glNormal3dv\0"                        
+"glNormal3fv\0"                        
+"glNormal3iv\0"                        
+"glNormal3sv\0"                        
+"glIndexd\0"                           
+"glIndexf\0"                           
+"glIndexi\0"                           
+"glIndexs\0"                           
+"glIndexub\0"                          
+"glIndexdv\0"                          
+"glIndexfv\0"                          
+"glIndexiv\0"                          
+"glIndexsv\0"                          
+"glIndexubv\0"                         
+"glColor3b\0"                          
+"glColor3d\0"                          
+"glColor3f\0"                          
+"glColor3i\0"                          
+"glColor3s\0"                          
+"glColor3ub\0"                         
+"glColor3ui\0"                         
+"glColor3us\0"                         
+"glColor4b\0"                          
+"glColor4d\0"                          
+"glColor4f\0"                          
+"glColor4i\0"                          
+"glColor4s\0"                          
+"glColor4ub\0"                         
+"glColor4ui\0"                         
+"glColor4us\0"                         
+"glColor3bv\0"                         
+"glColor3dv\0"                         
+"glColor3fv\0"                         
+"glColor3iv\0"                         
+"glColor3sv\0"                         
+"glColor3ubv\0"                        
+"glColor3uiv\0"                        
+"glColor3usv\0"                        
+"glColor4bv\0"                         
+"glColor4dv\0"                         
+"glColor4fv\0"                         
+"glColor4iv\0"                         
+"glColor4sv\0"                         
+"glColor4ubv\0"                        
+"glColor4uiv\0"                        
+"glColor4usv\0"                        
+"glTexCoord1d\0"                       
+"glTexCoord1f\0"                       
+"glTexCoord1i\0"                       
+"glTexCoord1s\0"                       
+"glTexCoord2d\0"                       
+"glTexCoord2f\0"                       
+"glTexCoord2i\0"                       
+"glTexCoord2s\0"                       
+"glTexCoord3d\0"                       
+"glTexCoord3f\0"                       
+"glTexCoord3i\0"                       
+"glTexCoord3s\0"                       
+"glTexCoord4d\0"                       
+"glTexCoord4f\0"                       
+"glTexCoord4i\0"                       
+"glTexCoord4s\0"                       
+"glTexCoord1dv\0"                      
+"glTexCoord1fv\0"                      
+"glTexCoord1iv\0"                      
+"glTexCoord1sv\0"                      
+"glTexCoord2dv\0"                      
+"glTexCoord2fv\0"                      
+"glTexCoord2iv\0"                      
+"glTexCoord2sv\0"                      
+"glTexCoord3dv\0"                      
+"glTexCoord3fv\0"                      
+"glTexCoord3iv\0"                      
+"glTexCoord3sv\0"                      
+"glTexCoord4dv\0"                      
+"glTexCoord4fv\0"                      
+"glTexCoord4iv\0"                      
+"glTexCoord4sv\0"                      
+"glRasterPos2d\0"                      
+"glRasterPos2f\0"                      
+"glRasterPos2i\0"                      
+"glRasterPos2s\0"                      
+"glRasterPos3d\0"                      
+"glRasterPos3f\0"                      
+"glRasterPos3i\0"                      
+"glRasterPos3s\0"                      
+"glRasterPos4d\0"                      
+"glRasterPos4f\0"                      
+"glRasterPos4i\0"                      
+"glRasterPos4s\0"                      
+"glRasterPos2dv\0"                     
+"glRasterPos2fv\0"                     
+"glRasterPos2iv\0"                     
+"glRasterPos2sv\0"                     
+"glRasterPos3dv\0"                     
+"glRasterPos3fv\0"                     
+"glRasterPos3iv\0"                     
+"glRasterPos3sv\0"                     
+"glRasterPos4dv\0"                     
+"glRasterPos4fv\0"                     
+"glRasterPos4iv\0"                     
+"glRasterPos4sv\0"                     
+"glRectd\0"                            
+"glRectf\0"                            
+"glRecti\0"                            
+"glRects\0"                            
+"glRectdv\0"                           
+"glRectfv\0"                           
+"glRectiv\0"                           
+"glRectsv\0"                           
+/* Lighting */
+"glShadeModel\0"                       
+"glLightf\0"                           
+"glLighti\0"                           
+"glLightfv\0"                          
+"glLightiv\0"                          
+"glGetLightfv\0"                       
+"glGetLightiv\0"                       
+"glLightModelf\0"                      
+"glLightModeli\0"                      
+"glLightModelfv\0"                     
+"glLightModeliv\0"                     
+"glMaterialf\0"                        
+"glMateriali\0"                        
+"glMaterialfv\0"                       
+"glMaterialiv\0"                       
+"glGetMaterialfv\0"                    
+"glGetMaterialiv\0"                    
+"glColorMaterial\0"                    
+/* Raster functions */
+"glPixelZoom\0"                        
+"glPixelStoref\0"                      
+"glPixelStorei\0"                      
+"glPixelTransferf\0"                   
+"glPixelTransferi\0"                   
+"glPixelMapfv\0"                       
+"glPixelMapuiv\0"                      
+"glPixelMapusv\0"                      
+"glGetPixelMapfv\0"                    
+"glGetPixelMapuiv\0"                   
+"glGetPixelMapusv\0"                   
+"glBitmap\0"                           
+"glReadPixels\0"                       
+"glDrawPixels\0"                       
+"glCopyPixels\0"                       
+/* Stenciling */
+"glStencilFunc\0"                      
+"glStencilMask\0"                      
+"glStencilOp\0"                        
+"glClearStencil\0"                     
+/* Texture mapping */
+"glTexGend\0"                          
+"glTexGenf\0"                          
+"glTexGeni\0"                          
+"glTexGendv\0"                         
+"glTexGenfv\0"                         
+"glTexGeniv\0"                         
+"glGetTexGendv\0"                      
+"glGetTexGenfv\0"                      
+"glGetTexGeniv\0"                      
+"glTexEnvf\0"                          
+"glTexEnvi\0"                          
+"glTexEnvfv\0"                         
+"glTexEnviv\0"                         
+"glGetTexEnvfv\0"                      
+"glGetTexEnviv\0"                      
+"glTexParameterf\0"                    
+"glTexParameteri\0"                    
+"glTexParameterfv\0"                   
+"glTexParameteriv\0"                   
+"glGetTexParameterfv\0"                
+"glGetTexParameteriv\0"                
+"glGetTexLevelParameterfv\0"           
+"glGetTexLevelParameteriv\0"           
+"glTexImage1D\0"                       
+"glTexImage2D\0"                       
+"glGetTexImage\0"                      
+/* Evaluators */
+"glMap1d\0"                            
+"glMap1f\0"                            
+"glMap2d\0"                            
+"glMap2f\0"                            
+"glGetMapdv\0"                         
+"glGetMapfv\0"                         
+"glGetMapiv\0"                         
+"glEvalCoord1d\0"                      
+"glEvalCoord1f\0"                      
+"glEvalCoord1dv\0"                     
+"glEvalCoord1fv\0"                     
+"glEvalCoord2d\0"                      
+"glEvalCoord2f\0"                      
+"glEvalCoord2dv\0"                     
+"glEvalCoord2fv\0"                     
+"glMapGrid1d\0"                        
+"glMapGrid1f\0"                        
+"glMapGrid2d\0"                        
+"glMapGrid2f\0"                        
+"glEvalPoint1\0"                       
+"glEvalPoint2\0"                       
+"glEvalMesh1\0"                        
+"glEvalMesh2\0"                        
+/* Fog */
+"glFogf\0"                             
+"glFogi\0"                             
+"glFogfv\0"                            
+"glFogiv\0"                            
+/* Selection and Feedback */
+"glFeedbackBuffer\0"                   
+"glPassThrough\0"                      
+"glSelectBuffer\0"                     
+"glInitNames\0"                        
+"glLoadName\0"                         
+"glPushName\0"                         
+"glPopName\0"                          
+/* 1.1 functions */
+/* texture objects */
+"glGenTextures\0"                      
+"glDeleteTextures\0"                   
+"glBindTexture\0"                      
+"glPrioritizeTextures\0"               
+"glAreTexturesResident\0"              
+"glIsTexture\0"                        
+/* texture mapping */
+"glTexSubImage1D\0"                    
+"glTexSubImage2D\0"                    
+"glCopyTexImage1D\0"                   
+"glCopyTexImage2D\0"                   
+"glCopyTexSubImage1D\0"                
+"glCopyTexSubImage2D\0"                
+/* vertex arrays */
+"glVertexPointer\0"                    
+"glNormalPointer\0"                    
+"glColorPointer\0"                     
+"glIndexPointer\0"                     
+"glTexCoordPointer\0"                  
+"glEdgeFlagPointer\0"                  
+"glGetPointerv\0"                      
+"glArrayElement\0"                     
+"glDrawArrays\0"                       
+"glDrawElements\0"                     
+"glInterleavedArrays\0"                
+/* GLX */
+"glXChooseVisual\0"
+"glXQueryExtensionsString\0"
+"glXQueryServerString\0"
+"glXGetClientString\0"
+"glXCreateContext\0"
+"glXCreateNewContext\0"
+"glXCopyContext\0"
+"glXDestroyContext\0"
+"glXQueryVersion\0"
+"glXMakeCurrent\0"
+"glXSwapBuffers\0"
+"glXGetConfig\0"
+"glXQueryExtension\0"
+"glXChooseFBConfig\0"
+"glXGetFBConfigs\0"
+"glXGetFBConfigAttrib\0"
+"glXQueryContext\0"
+"glXQueryDrawable\0"
+"glXGetVisualFromFBConfig\0"
+"glXIsDirect\0"
+"\0"
+};
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+void *glo_getprocaddress(const char *procName) {
+    HGLRC oldCtx;
+    HDC oldDC;
+    if (!glo_inited)
+        glo_init();
+
+    oldCtx = wglGetCurrentContext();
+    oldDC = wglGetCurrentDC();
+    if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
+        wglMakeCurrent(glo.hDC, glo.hContext);
+
+    void *procAddr = wglGetProcAddress(procName);
+
+    if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
+        wglMakeCurrent(oldDC, oldCtx);
+
+    /* wgl doesn't know about the glx functions - but
+    we never call these anyway (they're implemented in
+    opengl_exec), so all we need to do is return a nunzero value...
+
+    But we also have to check for 'standard' GL function names
+    too as wgl doesn't return those either! */ 
+    if (procAddr==0) {
+        const char *p = STANDARD_GL_FUNCTIONS;
+        while (*p) {
+            if (!strcmp(procName, p)) {
+                procAddr = (void*)1;
+                break;
+            }
+            // skip to the next '0' and then just over it
+            while (*p) p++;
+            p++;
+        }
+    }
+
+    /*printf("wglGetProcAddress '%s' -> %p\n", procName, procAddr);
+    fflush(stdout);*/
+
+    return procAddr;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
+GloContext *glo_context_create(int formatFlags, GloContext *shareLists) {
+    GloContext *context;
+    // pixel format attributes
+    int          pf_attri[] = {
+        WGL_SUPPORT_OPENGL_ARB, TRUE,      
+        WGL_DRAW_TO_PBUFFER_ARB, TRUE,     
+        WGL_RED_BITS_ARB, 8,             
+        WGL_GREEN_BITS_ARB, 8,            
+        WGL_BLUE_BITS_ARB, 8,            
+        WGL_ALPHA_BITS_ARB, 8,
+        WGL_DEPTH_BITS_ARB, 0,
+        WGL_STENCIL_BITS_ARB, 0,
+        WGL_DOUBLE_BUFFER_ARB, FALSE,      
+        0                                
+    };
+    float        pf_attrf[] = {0, 0};
+    unsigned int numReturned = 0;
+    int          pb_attr[] = { 0 };
+    int          rgbaBits[4];
+
+
+    if (!glo_inited)
+        glo_init();
+
+    context = (GloContext*)malloc(sizeof(GloContext));
+    memset(context, 0, sizeof(GloContext));
+    context->formatFlags = formatFlags;
+
+    // set up the surface format from the flags we were given
+    glo_flags_get_rgba_bits(context->formatFlags, rgbaBits);
+    pf_attri[5]  = rgbaBits[0];
+    pf_attri[7]  = rgbaBits[1];
+    pf_attri[9]  = rgbaBits[2];
+    pf_attri[11] = rgbaBits[3];
+    pf_attri[13] = glo_flags_get_depth_bits(context->formatFlags);
+    pf_attri[15] = glo_flags_get_stencil_bits(context->formatFlags);
+
+    // find out what pixel format to use
+    wglChoosePixelFormatARB( glo.hDC, pf_attri, pf_attrf, 1, &context->wglPixelFormat, &numReturned);
+    if( numReturned == 0 ) {
+        printf( "No matching configs found.\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    // We create a tiny pbuffer - just so we can make a context of the right pixel format
+    context->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat, 
+                                             16, 16, pb_attr );
+    if( !context->hPBuffer ) {
+        printf( "Couldn't create the PBuffer\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+    context->hDC      = wglGetPbufferDCARB( context->hPBuffer );
+    if( !context->hDC ) {
+        printf( "Couldn't create the DC\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    context->hContext = wglCreateContext(context->hDC);
+    if (context->hContext == NULL) {
+        printf( "Unable to create GL context\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    if (shareLists) {
+        // Need to share lists...
+        wglShareLists(shareLists->hContext, context->hContext);
+    }
+
+    return context;
+}
+
+/* Destroy a previouslu created OpenGL context */
+void glo_context_destroy(GloContext *context) {
+    if (!context) return;
+
+    wglMakeCurrent( NULL, NULL );
+    if( context->hPBuffer != NULL ) {
+        wglReleasePbufferDCARB( context->hPBuffer, context->hDC );
+        wglDestroyPbufferARB( context->hPBuffer );
+    }
+    if( context->hDC != NULL ) {
+        ReleaseDC( glo.hWnd, context->hDC );
+    }
+    if (context->hContext) {
+        wglDeleteContext(context->hContext);
+    }
+    free(context);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create a surface with given width and height, formatflags are from the
+ * GLO_ constants */
+GloSurface *glo_surface_create(int width, int height, GloContext *context) {
+    GloSurface           *surface;
+    int                   pb_attr[] = { 0 };
+    
+    // Create the p-buffer...
+    surface = (GloSurface*)malloc(sizeof(GloSurface));
+    memset(surface, 0, sizeof(GloSurface));
+    surface->width = width;
+    surface->height = height;
+    surface->context = context;
+
+    surface->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat, 
+                                             surface->width, surface->height, pb_attr );
+    if( !surface->hPBuffer ) {
+        printf( "Couldn't create the PBuffer\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+    surface->hDC      = wglGetPbufferDCARB( surface->hPBuffer );
+    if( !surface->hDC ) {
+        printf( "Couldn't create the DC\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    return surface;
+}
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface) {
+    if (!surface) return;
+
+    wglMakeCurrent( NULL, NULL );
+    if( surface->hPBuffer != NULL ) {
+        wglReleasePbufferDCARB( surface->hPBuffer, surface->hDC );
+        wglDestroyPbufferARB( surface->hPBuffer );
+    }
+    if( surface->hDC != NULL ) {
+        ReleaseDC( glo.hWnd, surface->hDC );
+    }
+    free(surface);
+}
+
+/* Make the given surface current */
+int glo_surface_makecurrent(GloSurface *surface) {
+  if (surface) {
+      return wglMakeCurrent( surface->hDC, surface->context->hContext );
+  } else {
+      return wglMakeCurrent( NULL, NULL );
+  }
+}
+
+/* Get the contents of the given surface */
+void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
+
+  if (!surface)
+      return;
+  // Compatible / fallback method.
+  glo_surface_getcontents_readpixels(surface->context->formatFlags,
+                                        stride, bpp, surface->width,
+                                        surface->height, data);
+}
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
+    if (width)
+        *width = surface->width;
+    if (height)
+        *height = surface->height;
+}
+
+#endif
diff --git a/tizen/src/hw/gloffscreen_xcomposite.c b/tizen/src/hw/gloffscreen_xcomposite.c
new file mode 100755 (executable)
index 0000000..8c74067
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ *  Offscreen OpenGL abstraction layer - GLX specific
+ *
+ *  Copyright (c) 2010 Intel
+ *  Written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef _WIN32
+#include "gloffscreen.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xcomposite.h>
+
+void *g_malloc(size_t size);
+void *g_realloc(void *ptr, size_t size);
+void g_free(void *ptr);
+
+struct GloMain {
+    Display *dpy;
+    int use_ximage;
+};
+struct GloMain glo;
+int glo_inited = 0;
+
+struct _GloContext {
+    GLuint                formatFlags;
+
+    GLXFBConfig           fbConfig;
+    GLXContext            context;
+};
+
+struct _GloSurface {
+    GLuint                width;
+    GLuint                height;
+
+    GloContext           *context;
+    Window                window;
+
+    // For use by the 'fast' copy code.
+    Pixmap             pixmap;
+    XImage               *image;
+    XShmSegmentInfo       shminfo;
+};
+
+extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
+                                    int bpp, int width, int height, void *data);
+static void glo_test_readback_methods(void);
+
+/* ------------------------------------------------------------------------ */
+
+int glo_initialised(void) {
+    return glo_inited;
+}
+
+/* 
+ * The X error was disabled, otherwise QEMU will abort. Printing more error
+ * messages inside below function could help debug potential bugs. On the 
+ * other hand, since the X errors could be caused by the GL calls forwarded
+ * from client OS side, which does not make sense to abort the whole QEMU,
+ * so it is reasonable to redirect error handler here.
+ *
+ */
+static int x_errhandler(Display *dpy, XErrorEvent *e)
+{
+    //fprintf (stderr, "X Error Happened!\n");
+    return 0;
+}
+
+/* Sanity test of the host GL capabilities to see whether the gl offscreen
+ * could be well supported
+ */
+int glo_sanity_test (void) {
+    return 0;
+}
+
+/* Initialise gloffscreen */
+int glo_init(void) {
+    if (glo_inited) {
+        printf( "gloffscreen already inited\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+
+    /* Open a connection to the X server */
+    glo.dpy = XOpenDisplay( NULL );
+    if ( glo.dpy == NULL ) {
+        printf( "Unable to open a connection to the X server\n" );
+        //exit( EXIT_FAILURE );
+               return 1;
+    }
+
+    glo_inited = 1; // safe because we are single threaded. Otherwise we cause
+                    // recursion on the next call.
+    // set the X error handler.
+    XErrorHandler old_handler = XSetErrorHandler (x_errhandler);
+    glo_test_readback_methods();
+       return 0;
+}
+
+/* Uninitialise gloffscreen */
+void glo_kill(void) {
+    XCloseDisplay(glo.dpy);
+    glo.dpy = NULL;
+}
+
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+void *glo_getprocaddress(const char *procName) {
+    if (!glo_inited)
+        glo_init();
+
+    return glXGetProcAddressARB((const GLubyte *) procName);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create an OpenGL context for a certain pixel format.
+   formatflags are from the GLO_ constants */
+
+GloContext *glo_context_create(int formatFlags, GloContext *shareLists) {
+    if (!glo_inited)
+        glo_init();
+
+    GLXFBConfig          *fbConfigs;
+    int                   numReturned;
+    GloContext           *context;
+    int                   rgbaBits[4];
+    int                   bufferAttributes[] = {
+        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
+        GLX_RED_SIZE,      8,
+        GLX_GREEN_SIZE,    8,
+        GLX_BLUE_SIZE,     8,
+        GLX_ALPHA_SIZE,    8,
+        GLX_DEPTH_SIZE,    0,
+        GLX_STENCIL_SIZE,  0,
+        None
+    };
+
+    if (!glo_inited)
+        glo_init();
+
+    // set up the surface format from the flags we were given
+    glo_flags_get_rgba_bits(formatFlags, rgbaBits);
+    bufferAttributes[5]  = rgbaBits[0];
+    bufferAttributes[7]  = rgbaBits[1];
+    bufferAttributes[9]  = rgbaBits[2];
+    bufferAttributes[11] = rgbaBits[3];
+    bufferAttributes[13] = glo_flags_get_depth_bits(formatFlags);
+    bufferAttributes[15] = glo_flags_get_stencil_bits(formatFlags);
+
+    fbConfigs = glXChooseFBConfig( glo.dpy, DefaultScreen(glo.dpy),
+                                   bufferAttributes, &numReturned );
+    if (numReturned==0) {
+        printf( "No matching configs found.\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+    context = (GloContext*)g_malloc(sizeof(GloContext));
+    memset(context, 0, sizeof(GloContext));
+    context->formatFlags = formatFlags;
+    context->fbConfig = fbConfigs[0];
+
+    /* Create a GLX context for OpenGL rendering */
+    context->context = glXCreateNewContext(glo.dpy, context->fbConfig,
+                                         GLX_RGBA_TYPE,
+                                         shareLists ? shareLists->context: NULL,
+                                         True );
+
+    if (!context->context) {
+        printf( "glXCreateNewContext failed\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    return context;
+}
+
+/* Destroy a previously created OpenGL context */
+void glo_context_destroy(GloContext *context) {
+    if (!context) return;
+
+    // TODO: check for GloSurfaces using this?
+    glXDestroyContext( glo.dpy, context->context);
+    g_free(context);
+}
+
+static void glo_surface_free_xshm_image(GloSurface *surface) {
+    XShmDetach(glo.dpy, &surface->shminfo);
+    surface->image->data = NULL;
+    XDestroyImage(surface->image);
+    shmdt(surface->shminfo.shmaddr);
+    shmctl(surface->shminfo.shmid, IPC_RMID, NULL);
+}
+
+//FIXMEIM - handle failure to allocate.
+static void glo_surface_try_alloc_xshm_image(GloSurface *surface) {
+
+    if(surface->image)
+        glo_surface_free_xshm_image(surface);
+
+    surface->image =
+        XShmCreateImage(glo.dpy, DefaultVisual(glo.dpy, 0), 24, ZPixmap, NULL,
+                        &surface->shminfo, surface->width, surface->height);
+
+    surface->shminfo.shmid = shmget(IPC_PRIVATE,
+                                    surface->image->bytes_per_line *
+                                    surface->height,
+                                    IPC_CREAT | 0777);
+    surface->shminfo.shmaddr = shmat(surface->shminfo.shmid, NULL, 0);
+    surface->image->data = surface->shminfo.shmaddr;
+    surface->shminfo.readOnly = False;
+    XShmAttach(glo.dpy, &surface->shminfo);
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Create a surface with given width and height, formatflags are from the
+ * GLO_ constants */
+GloSurface *glo_surface_create(int width, int height, GloContext *context) {
+    GloSurface           *surface;
+    XSetWindowAttributes attr = { 0 };
+    unsigned long mask;
+    XVisualInfo *vis;
+
+    if (!context)
+      return 0;
+
+    surface = (GloSurface*)g_malloc(sizeof(GloSurface));
+    memset(surface, 0, sizeof(GloSurface));
+    surface->width = width;
+    surface->height = height;
+    surface->context = context;
+
+    vis = glXGetVisualFromFBConfig(glo.dpy, ((struct _GloContext*)context)->fbConfig);
+
+    attr.background_pixel = 0xff000000;
+    attr.border_pixel = 0;
+    attr.colormap = XCreateColormap(glo.dpy, DefaultRootWindow(glo.dpy),
+                                    vis->visual, AllocNone);
+    attr.event_mask = 0;
+    attr.save_under = True;
+    attr.override_redirect = True;
+    attr.cursor = None;
+    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask |
+           CWOverrideRedirect | CWSaveUnder;
+
+    surface->window = XCreateWindow(glo.dpy, DefaultRootWindow(glo.dpy), -width-1000, 0, width, height, 0, vis->depth, InputOutput, vis->visual, mask, &attr);
+
+    if (!surface->window) {
+        printf( "XCreateWindow failed\n" );
+        //exit( EXIT_FAILURE );
+               return NULL;
+    }
+
+    XMapWindow(glo.dpy, surface->window);
+    XCompositeRedirectWindow (glo.dpy, surface->window, CompositeRedirectAutomatic);
+
+    if(glo.use_ximage) {
+        surface->pixmap = XCompositeNameWindowPixmap(glo.dpy, surface->window);
+    } else {
+        surface->pixmap = XCreatePixmap( glo.dpy, DefaultRootWindow(glo.dpy),
+                                         width, height,
+                                         glo_flags_get_bytes_per_pixel(context->formatFlags)*8);
+    }
+
+    if(surface->pixmap == 0) {
+        fprintf(stderr, "Failed to allocate pixmap!\n");
+        //exit(EXIT_FAILURE);
+               return NULL;
+    }
+
+    XSync(glo.dpy, 0);
+
+    /* set hints and properties */
+    {
+        XSizeHints sizehints;
+
+        sizehints.x = 0;
+        sizehints.y = 0;
+        sizehints.width = width;
+        sizehints.height = height;
+        sizehints.flags = USSize | USPosition;
+        XSetWMNormalHints(glo.dpy, surface->window, &sizehints);
+        XSetStandardProperties(glo.dpy, surface->window, "", "", None,
+                               (char **) NULL, 0, &sizehints);
+    }
+
+    XSync(glo.dpy, 0);
+
+    // If we're using XImages to pull the data from the graphics card...
+    glo_surface_try_alloc_xshm_image(surface);
+
+    return surface;
+}
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface) {
+
+    if(surface->pixmap)
+        XFreePixmap( glo.dpy, surface->pixmap);
+    XDestroyWindow( glo.dpy, surface->window);
+    if(surface->image)
+        glo_surface_free_xshm_image(surface);
+    g_free(surface);
+
+}
+
+/* Make the given surface current */
+int glo_surface_makecurrent(GloSurface *surface) {
+    int ret;
+
+    if (!glo_inited)
+        glo_init();
+
+    if (surface)
+        ret = glXMakeCurrent(glo.dpy, surface->window,
+                             surface->context->context);
+    else
+        ret = glXMakeCurrent(glo.dpy, 0, NULL);
+
+    return ret;
+}
+
+/* Get the contents of the given surface */
+void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
+    static int once;
+    XImage *img;
+
+    if (!surface)
+        return;
+
+    if(glo.use_ximage) {
+        glXWaitGL();
+    
+        if(surface->image) {
+            XShmGetImage (glo.dpy, surface->pixmap, surface->image, 0, 0, AllPlanes);
+            img = surface->image;
+        }
+        else {
+            img = XGetImage(glo.dpy, surface->pixmap, 0, 0, surface->width, surface->height, AllPlanes, ZPixmap);
+        }
+
+        if (img) {
+            if(bpp != 32 && bpp != 24 && !once) {
+                fprintf(stderr, "Warning: unsupported colourdepth\n");
+                once = 1;
+            }
+
+            if(bpp == img->bits_per_pixel && stride == img->bytes_per_line)
+            {
+                 memcpy(data, img->data, stride * surface->height);
+            }
+            else
+            {
+                int x, y;
+                for(y = 0 ; y < surface->height ; y++) {
+                    for(x = 0 ; x < surface->width ; x++) {
+                        char *src = ((char*)img->data) +
+                                    (x*(img->bits_per_pixel/8)) +
+                                    (y*img->bytes_per_line);
+                        char *dst = ((char*)data) + x*(bpp/8) + (y*stride);
+                        dst[0] = src[0];
+                        dst[1] = src[1];
+                        dst[2] = src[2];
+                        if(bpp == 32)
+                              dst[3] = 0xff; // if guest is 32 bit and host is 24
+                    }
+                }
+            }
+  
+            // If we're not using Shm
+            if(!surface->image)
+                XDestroyImage(img);
+
+            return;  // We're done.
+        } 
+    // Uh oh... better fallback. Perhaps get glo.use_ximage to 0?
+    }
+
+    // Compatible / fallback method.
+    glo_surface_getcontents_readpixels(surface->context->formatFlags,
+                                       stride, bpp, surface->width,
+                                       surface->height, data);
+}
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
+    if (width)
+        *width = surface->width;
+    if (height)
+        *height = surface->height;
+}
+
+/* Abstract glXQueryExtensionString() */
+const char *glo_glXQueryExtensionsString(void) {
+    return glXQueryExtensionsString(glo.dpy, 0);
+}
+
+
+#define TX (17)
+#define TY (16)
+
+static int glo_can_readback(void) {
+    GloContext *context;
+    GloSurface *surface;
+
+    unsigned char *datain = (unsigned char *)g_malloc(4*TX*TY);
+    unsigned char *datain_flip = (unsigned char *)g_malloc(4*TX*TY); // flipped input data (for GL)
+    unsigned char *dataout = (unsigned char *)g_malloc(4*TX*TY);
+    unsigned char *p;
+    int x,y;
+
+    const int bufferAttributes[] = {
+            GLX_RED_SIZE,      8,
+            GLX_GREEN_SIZE,    8,
+            GLX_BLUE_SIZE,     8,
+            GLX_ALPHA_SIZE,    8,
+            GLX_DEPTH_SIZE,    0,
+            GLX_STENCIL_SIZE,  0,
+            0,
+        };
+
+    int bufferFlags = glo_flags_get_from_glx(bufferAttributes, 0);
+    int bpp = glo_flags_get_bytes_per_pixel(bufferFlags);
+    int glFormat, glType;
+
+    memset(datain_flip, 0, TX*TY*4);
+    memset(datain, 0, TX*TY*4);
+
+    p = datain;
+    for (y=0;y<TY;y++) {
+        for (x=0;x<TX;x++) {
+            p[0] = x;
+            p[1] = y;
+            if (bpp>2) p[2] = 0;
+            if (bpp>3) p[3] = 0xFF;
+            p+=bpp;
+        }
+        memcpy(&datain_flip[((TY-1)-y)*bpp*TX], &datain[y*bpp*TX], bpp*TX);
+    }
+
+    context = glo_context_create(bufferFlags, 0);
+       if (context == NULL)
+               return 1;
+
+    surface = glo_surface_create(TX, TY, context);
+       if (surface == NULL)
+               return 1;
+
+    glo_surface_makecurrent(surface);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0,TX, 0,TY, 0, 1);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glRasterPos2f(0,0);
+    glo_flags_get_readpixel_type(bufferFlags, &glFormat, &glType);
+    glDrawPixels(TX,TY,glFormat, glType, datain_flip);
+    glFlush();
+
+    memset(dataout, 0, bpp*TX*TY);
+
+    glo_surface_getcontents(surface, TX*4, bpp*8, dataout);
+
+    glo_surface_destroy(surface);
+    glo_context_destroy(context);
+
+    if (memcmp(datain, dataout, bpp*TX*TY)==0)
+        return 1;
+
+    return 0;
+}
+
+static void glo_test_readback_methods(void) {
+    glo.use_ximage = 1;
+    if(!glo_can_readback())
+        glo.use_ximage = 0;
+
+    //fprintf(stderr, "VM GL: Using %s readback\n", glo.use_ximage?"XImage":"glReadPixels");
+}
+
+#endif
diff --git a/tizen/src/hw/helper_opengl.c b/tizen/src/hw/helper_opengl.c
new file mode 100755 (executable)
index 0000000..c5cd4fa
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  Host-side implementation of GL/GLX API
+ *
+ *  Copyright (c) 2006,2007 Even Rouault
+ *  Modified by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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 _XOPEN_SOURCE 600
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "osdep.h"
+#include "opengl_func.h"
+#include "opengl_process.h"
+#include "opengl_exec.h"
+
+#include "tizen/src/debug_ch.h"
+MULTI_DEBUG_CHANNEL(qemu, opengl);
+#define DEBUGF         TRACE
+
+#if 0
+#ifdef _WIN32
+#define DEBUGF(...) printf(__VA_ARGS__)
+#else
+extern struct FILE *stderr;            /* Standard error output stream.  */
+#define DEBUGF(...) fprintf(stderr, __VA_ARGS__)
+#endif
+#endif
+
+/* do_decode_call_int()
+ *
+ * Loop through the buffered command stream executing each OpenGL call in
+ * sequence. due to the way calls are buffered, only the last call in the
+ * buffer may have 'out' parameters or a non-void return code. This allows
+ * for efficient buffering whilst avoiding un-necessary buffer flushes.
+ */
+
+typedef unsigned long host_ptr;
+
+static inline int do_decode_call_int(ProcessStruct *process, void *args_in, int args_len, char *r_buffer)
+{
+    Signature *signature;
+    int i, ret;
+    char *argptr, *tmp;
+    static void* args[50];
+    int func_number;
+
+    if(!args_len)
+       return 0;
+
+    argptr = args_in;
+
+    while((char*)argptr < (char*)args_in + args_len) {
+        func_number = *(short*)argptr;
+        argptr += 2;
+
+        if(func_number >= GL_N_CALLS) {
+            DEBUGF("Bad function number or corrupt command queue\n");
+            return 0;
+        }
+
+        signature = (Signature *) tab_opengl_calls[func_number];
+
+        tmp = argptr;
+
+        for (i = 0; i < signature->nb_args; i++) {
+            int args_size = *(int*)argptr;
+            argptr+=4;
+            switch (signature->args_type[i]) {
+                case TYPE_UNSIGNED_INT:
+                case TYPE_INT:
+                case TYPE_UNSIGNED_CHAR:
+                case TYPE_CHAR:
+                case TYPE_UNSIGNED_SHORT:
+                case TYPE_SHORT:
+                case TYPE_FLOAT:
+                   args[i] = *(int*)argptr;
+                break;
+
+                case TYPE_NULL_TERMINATED_STRING:
+                CASE_IN_UNKNOWN_SIZE_POINTERS:
+                {
+                    if(*(int*)argptr)
+                        args[i] = (host_ptr)argptr+4;
+                    else
+                        args[i] = (host_ptr)NULL;
+
+                    if ((args[i] == 0 && args_size == 0 &&
+                        !IS_NULL_POINTER_OK_FOR_FUNC(func_number)) ||
+                        (args[i] == 0 && args_size != 0) ||
+                        (args[i] != 0 && args_size == 0))
+                            return 0;
+
+                    argptr += 4;
+                    break;
+                }
+
+                CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS:
+                {
+                    if(*(int*)argptr)
+                        args[i] = (host_ptr)argptr+4;
+                    else
+                        args[i] = (host_ptr)NULL;
+
+                    if (args[i] == 0 && args_size != 0)
+                        return 0;
+
+                    argptr += 4;
+                    break;
+                }
+
+                CASE_OUT_POINTERS:
+                {
+                                       /* NULL pointer is used as output pointer
+                                          since the argument size is zero. */
+                                       if (args_size == 0) {
+                                               *(int*)r_buffer = 0;
+                                               r_buffer += 4;
+                                               args[i] = NULL;
+                                       } else if(*(int*)argptr) {
+                        *(int*)r_buffer = args_size;
+                        r_buffer+=4;
+                        args[i] = (host_ptr)r_buffer;
+                        r_buffer += args_size;
+                    }
+                    else {
+                        args[i] = 0;
+                    }
+
+                    argptr += 4;
+                    args_size = 0;
+                    break;
+                } 
+
+                case TYPE_DOUBLE:
+                CASE_IN_KNOWN_SIZE_POINTERS:
+                {
+                    if(*(int*)argptr)
+                        args[i] = (host_ptr)argptr+4;
+                    else
+                        args[i] = (host_ptr)NULL;
+
+                    if (args[i] == 0 && args_size != 0)
+                        return 0;
+
+                    argptr += 4;
+                    break;
+                }
+
+                case TYPE_IN_IGNORED_POINTER:
+                    args[i] = 0;
+                    break;
+
+                default:
+                    DEBUGF( "Oops : call %s arg %d pid=%d\n",
+                            tab_opengl_calls_name[func_number], i,
+                            process->process_id);
+                    return 0;
+            }
+            argptr += args_size;
+        }
+
+        if((char*)argptr > (char*)args_in + args_len) {
+            DEBUGF("Client bug: malformed command, killing process\n");
+            return 0;
+        }
+
+        if (signature->ret_type == TYPE_CONST_CHAR)
+            r_buffer[0] = 0; // In case high bits are set.
+
+        ret = do_function_call(process, func_number, args, r_buffer);
+
+    }  // endwhile
+
+    switch(signature->ret_type) {
+        case TYPE_INT:
+        case TYPE_UNSIGNED_INT:
+            memcpy(r_buffer, &ret, sizeof(int));
+            break;
+        case TYPE_CHAR:
+        case TYPE_UNSIGNED_CHAR:
+            *r_buffer = ret & 0xff;
+            break;
+        case TYPE_CONST_CHAR:
+        case TYPE_NONE:
+            break;
+        default:
+           DEBUGF("Unsupported GL API return type %i!\n", signature->ret_type);
+           exit (-1);
+    }
+
+    return 1;
+}
+#define GL_PASSINGTHROUGH_ABI 1
+
+#define GLINIT_FAIL_ABI 3
+#define GLINIT_QUEUE 2
+#define GLINIT_NOQUEUE 1
+
+int decode_call_int(ProcessStruct *process, char *in_args, int args_len, char *r_buffer)
+{
+       static ProcessStruct *cur_process = NULL;
+       int ret;
+       int first_func = *(short*)in_args;
+
+       /* Select the appropriate context for this pid if it isnt already active
+        * Note: if we're about to execute glXMakeCurrent() then we tell the
+        * renderer not to waste its time switching contexts
+        */
+
+       if (cur_process != process) {
+               cur_process = process;
+               vmgl_context_switch(cur_process, (first_func == glXMakeCurrent_func)?0:1);
+       }
+
+       if(unlikely(first_func == _init32_func || first_func == _init64_func)) {
+               if(!cur_process->wordsize) {
+                       int *version = (int*)(in_args+2);
+                       cur_process->wordsize = first_func == _init32_func?4:8;
+
+                       if((version[0] != 1) || (version[1] < GL_PASSINGTHROUGH_ABI)) {
+                               *(int*)r_buffer = GLINIT_FAIL_ABI; // ABI check FAIL
+                               TRACE("Error! The GL passing through package in the image does not match the version of QEMUGL. Please update the image!\n");
+                               exit (1);
+                       } else if(version[1] > GL_PASSINGTHROUGH_ABI) {
+                               *(int*)r_buffer = GLINIT_FAIL_ABI; // ABI check FAIL
+                               TRACE("Error! The GL passing through package in the image does not match the version of QEMUGL. Please update the QEMUGL!\n");
+                               exit (1);
+                       }
+                       else
+                               *(int*)r_buffer = GLINIT_QUEUE; // Indicate that we can buffer commands
+
+                       return 1; // Initialisation done
+               }
+               else {
+                       DEBUGF("Attempt to init twice. Continuing regardless.\n");
+                       return 1;
+               }
+       }
+
+       if(unlikely(first_func == -1 || !cur_process->wordsize)) {
+               if(!cur_process->wordsize && first_func != -1)
+                       DEBUGF("commands submitted before process init.\n");
+               ret = 0;
+       }
+       else {
+               ret = do_decode_call_int(cur_process, in_args, args_len, r_buffer);
+       }
+
+       if(!ret)
+               cur_process = NULL;
+
+       return ret;
+}
diff --git a/tizen/src/hw/maru_board.c b/tizen/src/hw/maru_board.c
new file mode 100644 (file)
index 0000000..fc6e31b
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * TIZEN base board
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun <dk77.yun@samsung.com>
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ * x86 board from pc_piix.c...
+ * add some TIZEN-speciaized device...
+ */
+
+#include <glib.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "apic.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "usb-ohci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "kvm.h"
+#include "kvmclock.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "arch_init.h"
+#include "blockdev.h"
+#include "smbus.h"
+#include "xen.h"
+#include "memory.h"
+#include "exec-memory.h"
+#ifdef CONFIG_XEN
+#  include <xen/hvm/hvm_info_table.h>
+#endif
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
+static void ioapic_init(GSIState *gsi_state)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "ioapic");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+    sysbus_mmio_map(d, 0, 0xfec00000);
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+}
+
+static void maru_x86_machine_init(MemoryRegion *system_memory,
+                     MemoryRegion *system_io,
+                     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,
+                     int pci_enabled,
+                     int kvmclock_enabled)
+{
+    int i;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size;
+    PCIBus *pci_bus;
+    PCII440FXState *i440fx_state;
+    int piix3_devfn = -1;
+    qemu_irq *cpu_irq;
+    qemu_irq *gsi;
+    qemu_irq *i8259;
+    qemu_irq *cmos_s3;
+    qemu_irq *smi_irq;
+    GSIState *gsi_state;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BusState *idebus[MAX_IDE_BUS];
+    ISADevice *rtc_state;
+    ISADevice *floppy;
+    MemoryRegion *ram_memory;
+    MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
+
+    pc_cpus_init(cpu_model);
+
+    if (kvmclock_enabled) {
+        kvmclock_create();
+    }
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        above_4g_mem_size = 0;
+        below_4g_mem_size = ram_size;
+    }
+
+    if (pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = system_memory;
+    }
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        pc_memory_init(system_memory,
+                       kernel_filename, kernel_cmdline, initrd_filename,
+                       below_4g_mem_size, above_4g_mem_size,
+                       pci_enabled ? rom_memory : system_memory, &ram_memory);
+    }
+
+    gsi_state = g_malloc0(sizeof(*gsi_state));
+    gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+
+    if (pci_enabled) {
+        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, gsi,
+                              system_memory, system_io, ram_size,
+                              below_4g_mem_size,
+                              0x100000000ULL - below_4g_mem_size,
+                              0x100000000ULL + above_4g_mem_size,
+                              (sizeof(target_phys_addr_t) == 4
+                               ? 0
+                               : ((uint64_t)1 << 62)),
+                              pci_memory, ram_memory);
+    } else {
+        pci_bus = NULL;
+        i440fx_state = NULL;
+        isa_bus_new(NULL, system_io);
+        no_hpet = 1;
+    }
+    isa_bus_irqs(gsi);
+
+    if (!xen_enabled()) {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(cpu_irq[0]);
+    } else {
+        i8259 = xen_interrupt_controller_init();
+    }
+
+    for (i = 0; i < ISA_NUM_IRQS; i++) {
+        gsi_state->i8259_irq[i] = i8259[i];
+    }
+    if (pci_enabled) {
+        ioapic_init(gsi_state);
+    }
+
+
+    pc_register_ferr_irq(gsi[13]);
+
+    pc_vga_init(pci_enabled? pci_bus: NULL);
+
+    if (xen_enabled()) {
+        pci_create_simple(pci_bus, -1, "xen-platform");
+    }
+    /* init basic PC hardware */
+    pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled());
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
+            pc_init_ne2k_isa(nd);
+        else
+            pci_nic_init_nofail(nd, "e1000", NULL);
+    }
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    if (pci_enabled) {
+        PCIDevice *dev;
+        if (xen_enabled()) {
+            dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
+        } else {
+            dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+        }
+        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+    } else {
+        for(i = 0; i < MAX_IDE_BUS; i++) {
+            ISADevice *dev;
+            dev = isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+            idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        }
+    }
+
+// commented out by caramis... for use 'tizen-ac97'...
+// reopen for qemu 1.0 merging...
+    audio_init(gsi, pci_enabled ? pci_bus : NULL);
+
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+                 floppy, idebus[0], idebus[1], rtc_state);
+
+    if (pci_enabled && usb_enabled) {
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (pci_enabled && acpi_enabled) {
+        i2c_bus *smbus;
+
+        if (!xen_enabled()) {
+            cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+        } else {
+            cmos_s3 = qemu_allocate_irqs(xen_cmos_set_s3_resume, rtc_state, 1);
+        }
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = maru_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                              gsi[9], *cmos_s3, *smi_irq,
+                              kvm_enabled());
+        smbus_eeprom_init(smbus, 8, NULL, 0);
+    }
+
+    if (pci_enabled) {
+        pc_pci_device_init(pci_bus);
+    }
+
+// maru specialized device init...
+    if (pci_enabled) {
+               maru_camera_pci_init(pci_bus);
+       //tizen_ac97_init(pci_bus);
+               codec_init(pci_bus);        
+    }
+}
+
+static void maru_arm_machine_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)
+{
+}
+
+static void maru_common_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)
+{
+// prepare for universal virtual board...
+#if defined(TARGET_I386)
+#elif defined(TARGET_ARM)
+#endif
+}
+
+static void maru_x86_board_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)
+{
+    maru_x86_machine_init(get_system_memory(),
+             get_system_io(),
+             ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 1);
+    maru_common_init(ram_size, boot_device, kernel_filename, 
+                        kernel_cmdline, initrd_filename, cpu_model);
+}
+static void maru_arm_board_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)
+{
+    maru_arm_machine_init(ram_size, boot_device, kernel_filename, 
+                        kernel_cmdline, initrd_filename, cpu_model);
+    maru_common_init(ram_size, boot_device, kernel_filename, 
+                        kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine maru_x86_machine = {
+    .name = "maru-x86-machine",
+    .desc = "maru board(x86)",
+    .init = maru_x86_board_init,
+    .max_cpus = 255,
+};
+
+static QEMUMachine maru_arm_machine = {
+    .name = "maru-arm-machine",
+    .desc = "maru board(ARM)",
+    .init = maru_arm_board_init,
+    .max_cpus = 255,
+};
+
+static void maru_machine_init(void)
+{
+#if defined(TARGET_I386)
+    qemu_register_machine(&maru_x86_machine);
+#elif defined(TARGET_ARM)
+    qemu_register_machine(&maru_arm_machine);
+#else
+#error
+#endif
+}
+
+machine_init(maru_machine_init);
diff --git a/tizen/src/hw/maru_brightness.c b/tizen/src/hw/maru_brightness.c
new file mode 100644 (file)
index 0000000..a7d1fe1
--- /dev/null
@@ -0,0 +1,152 @@
+/* 
+ * Maru brightness device for VGA
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun <dk77.yun@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "pc.h"
+#include "pci.h"
+#include "maru_pci_ids.h"
+#include "maru_brightness.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL( qemu, maru_brightness );
+
+#define QEMU_DEV_NAME           "MARU_BRIGHTNESS"
+
+#define BRIGHTNESS_MEM_SIZE     (4 * 1024)             /* 4KB */
+#define BRIGHTNESS_REG_SIZE     256
+
+typedef struct BrightnessState {
+    PCIDevice       dev;
+    ram_addr_t      vram_offset;
+    MemoryRegion    mmio_addr;
+} BrightnessState;
+
+enum {
+    BRIGHTNESS_LEVEL = 0x00,
+    BRIGHTNESS_OFF = 0x04,
+};
+
+uint32_t brightness_level = 24;
+uint32_t brightness_off = 0;
+
+// level : 0 ~ 23, interval : 6 or 7.
+uint8_t brightness_tbl[] = {110, 110, 116, 122, 128, 134, 140, 146, 152, 158, 164, 170,
+                            176, 182, 188, 194, 200, 206, 213, 220, 227, 234, 241, 248};
+
+static uint64_t brightness_reg_read( void *opaque, target_phys_addr_t addr, unsigned size ) {
+    switch ( addr & 0xFF ) {
+    case BRIGHTNESS_LEVEL:
+        INFO("brightness_reg_read: brightness_level = %d\n", brightness_level);
+        return brightness_level;
+    case BRIGHTNESS_OFF:
+        INFO("brightness_reg_read: brightness_off = %d\n", brightness_off);
+        return brightness_off;
+    default:
+        ERR("wrong brightness register read - addr : %d\n", (int)addr);
+        break;
+    }
+
+    return 0;
+}
+
+static void brightness_reg_write( void *opaque, target_phys_addr_t addr, uint64_t val, unsigned size ) {
+#if BRIGHTNESS_MIN > 0
+    if (val < BRIGHTNESS_MIN || val > BRIGHTNESS_MAX) {
+#else
+    if ( val > BRIGHTNESS_MAX ) {
+#endif
+        ERR("brightness_reg_write: Invalide brightness level.\n");
+    }
+
+    switch ( addr & 0xFF ) {
+    case BRIGHTNESS_LEVEL:
+        brightness_level = val;
+        INFO("brightness_level : %lld\n", val);
+        return;
+    case BRIGHTNESS_OFF:
+        INFO("brightness_off : %lld\n", val);
+        brightness_off = val;
+        return;
+    default:
+        ERR("wrong brightness register write - addr : %d\n", (int)addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps brightness_mmio_ops = {
+    .read = brightness_reg_read,
+    .write = brightness_reg_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int brightness_initfn( PCIDevice *dev ) {
+    BrightnessState *s = DO_UPCAST(BrightnessState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_config_set_vendor_id( pci_conf, PCI_VENDOR_ID_TIZEN );
+    pci_config_set_device_id( pci_conf, PCI_DEVICE_ID_VIRTUAL_BRIGHTNESS );
+    pci_config_set_class( pci_conf, PCI_CLASS_DISPLAY_OTHER );
+
+    memory_region_init_io( &s->mmio_addr, &brightness_mmio_ops, s, "maru_brightness_mmio", BRIGHTNESS_REG_SIZE );
+    pci_register_bar( &s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_addr );
+
+    return 0;
+}
+
+/* external interface */
+int pci_get_brightness( void ) {
+    return brightness_level;
+}
+
+int pci_maru_brightness_init( PCIBus *bus ) {
+    pci_create_simple( bus, -1, QEMU_DEV_NAME );
+    return 0;
+}
+
+static PCIDeviceInfo brightness_info = {
+    .qdev.name  = QEMU_DEV_NAME,
+    .qdev.size  = sizeof(BrightnessState),
+    .no_hotplug = 1,
+    .init       = brightness_initfn,
+};
+
+static void brightness_register( void ) {
+    pci_qdev_register( &brightness_info );
+}
+
+device_init(brightness_register);
diff --git a/tizen/src/hw/maru_brightness.h b/tizen/src/hw/maru_brightness.h
new file mode 100644 (file)
index 0000000..6e3da40
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Maru brightness device for VGA
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_BRIGHTNESS_H_
+#define MARU_BRIGHTNESS_H_
+
+#include "qemu-common.h"
+
+#define BRIGHTNESS_MIN          (0)
+#define BRIGHTNESS_MAX          (24)
+
+extern uint32_t brightness_level;
+extern uint32_t brightness_off;
+extern uint8_t brightness_tbl[];
+
+int pci_get_brightness( void );
+int pci_maru_brightness_init( PCIBus *bus );
+
+#endif /* MARU_BRIGHTNESS_H_ */
diff --git a/tizen/src/hw/maru_camera_common.h b/tizen/src/hw/maru_camera_common.h
new file mode 100644 (file)
index 0000000..6d45c39
--- /dev/null
@@ -0,0 +1,108 @@
+/*\r
+ * Common header of MARU Virtual Camera device.\r
+ *\r
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * JinHyung Jo <jinhyung.jo@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#ifndef _MARU_CAMERA_COMMON_H_\r
+#define _MARU_CAMERA_COMMON_H_\r
+\r
+#include "pci.h"\r
+#include "qemu-thread.h"\r
+\r
+#define MARUCAM_MAX_PARAM    20\r
+\r
+/* must sync with GUEST camera_driver */\r
+#define MARUCAM_CMD_INIT           0x00\r
+#define MARUCAM_CMD_OPEN           0x04\r
+#define MARUCAM_CMD_CLOSE          0x08\r
+#define MARUCAM_CMD_ISSTREAM       0x0C\r
+#define MARUCAM_CMD_START_PREVIEW  0x10\r
+#define MARUCAM_CMD_STOP_PREVIEW   0x14\r
+#define MARUCAM_CMD_S_PARAM        0x18\r
+#define MARUCAM_CMD_G_PARAM        0x1C\r
+#define MARUCAM_CMD_ENUM_FMT       0x20\r
+#define MARUCAM_CMD_TRY_FMT        0x24\r
+#define MARUCAM_CMD_S_FMT          0x28\r
+#define MARUCAM_CMD_G_FMT          0x2C\r
+#define MARUCAM_CMD_QCTRL          0x30\r
+#define MARUCAM_CMD_S_CTRL         0x34\r
+#define MARUCAM_CMD_G_CTRL         0x38\r
+#define MARUCAM_CMD_ENUM_FSIZES    0x3C\r
+#define MARUCAM_CMD_ENUM_FINTV     0x40\r
+#define MARUCAM_CMD_S_DATA         0x44\r
+#define MARUCAM_CMD_G_DATA         0x48\r
+#define MARUCAM_CMD_CLRIRQ         0x4C\r
+#define MARUCAM_CMD_DATACLR        0x50\r
+#define MARUCAM_CMD_REQFRAME       0x54\r
+\r
+typedef struct MaruCamState MaruCamState;\r
+typedef struct MaruCamParam MaruCamParam;\r
+\r
+struct MaruCamParam {\r
+    uint32_t    top;\r
+    uint32_t    retVal;\r
+    uint32_t    errCode;\r
+    uint32_t    stack[MARUCAM_MAX_PARAM];\r
+};\r
+\r
+struct MaruCamState {\r
+    PCIDevice           dev;\r
+    MaruCamParam        *param;\r
+    QemuThread          thread_id;\r
+    QemuMutex           thread_mutex;;\r
+    QemuCond            thread_cond;\r
+\r
+    void                *vaddr;     /* vram ptr */\r
+    uint32_t            streamon;\r
+    uint32_t            buf_size;\r
+    uint32_t            req_frame;\r
+\r
+    MemoryRegion        vram;\r
+    MemoryRegion        mmio;\r
+};\r
+\r
+/* ----------------------------------------------------------------------------- */\r
+/* Fucntion prototype                                                            */\r
+/* ----------------------------------------------------------------------------- */\r
+void marucam_device_init(MaruCamState *state);\r
+void marucam_device_open(MaruCamState *state);\r
+void marucam_device_close(MaruCamState *state);\r
+void marucam_device_start_preview(MaruCamState *state);\r
+void marucam_device_stop_preview(MaruCamState *state);\r
+void marucam_device_s_param(MaruCamState *state);\r
+void marucam_device_g_param(MaruCamState *state);\r
+void marucam_device_s_fmt(MaruCamState *state);\r
+void marucam_device_g_fmt(MaruCamState *state);\r
+void marucam_device_try_fmt(MaruCamState *state);\r
+void marucam_device_enum_fmt(MaruCamState *state);\r
+void marucam_device_qctrl(MaruCamState *state);\r
+void marucam_device_s_ctrl(MaruCamState *state);\r
+void marucam_device_g_ctrl(MaruCamState *state);\r
+void marucam_device_enum_fsizes(MaruCamState *state);\r
+void marucam_device_enum_fintv(MaruCamState *state);\r
+\r
+\r
+#endif  /* _MARU_CAMERA_COMMON_H_ */\r
diff --git a/tizen/src/hw/maru_camera_common_pci.c b/tizen/src/hw/maru_camera_common_pci.c
new file mode 100644 (file)
index 0000000..996fa42
--- /dev/null
@@ -0,0 +1,249 @@
+/*\r
+ * Common implementation of MARU Virtual Camera device by PCI bus.\r
+ *\r
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * JinHyung Jo <jinhyung.jo@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+\r
+#include <stdarg.h>\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <inttypes.h>\r
+#include <signal.h>\r
+\r
+#include "qemu-common.h"\r
+#include "cpu-common.h"\r
+\r
+#include "pci.h"\r
+#include "pci_ids.h"\r
+#include "maru_pci_ids.h"\r
+\r
+#include "maru_camera_common.h"\r
+#include "tizen/src/debug_ch.h"\r
+\r
+MULTI_DEBUG_CHANNEL(tizen, camera_pci);\r
+\r
+#define MARU_PCI_CAMERA_DEVICE_NAME     "maru_camera_pci"\r
+\r
+#define MARUCAM_MEM_SIZE        (4 * 1024 * 1024)   // 4MB\r
+#define MARUCAM_REG_SIZE        (256)               // 64 * 4\r
+\r
+/*\r
+ *  I/O functions\r
+ */\r
+static inline uint32_t marucam_mmio_read(void *opaque, target_phys_addr_t offset)\r
+{\r
+    uint32_t ret = 0;\r
+    MaruCamState *state = (MaruCamState*)opaque;\r
+\r
+    switch (offset & 0xFF) {\r
+    case MARUCAM_CMD_ISSTREAM:\r
+        qemu_mutex_lock(&state->thread_mutex);\r
+        ret = state->streamon;\r
+        qemu_mutex_unlock(&state->thread_mutex);\r
+        break;\r
+    case MARUCAM_CMD_G_DATA:\r
+        ret = state->param->stack[state->param->top++];\r
+        break;\r
+    case MARUCAM_CMD_OPEN:\r
+    case MARUCAM_CMD_CLOSE:\r
+    case MARUCAM_CMD_START_PREVIEW:\r
+    case MARUCAM_CMD_STOP_PREVIEW:\r
+    case MARUCAM_CMD_S_PARAM:\r
+    case MARUCAM_CMD_G_PARAM:\r
+    case MARUCAM_CMD_ENUM_FMT:\r
+    case MARUCAM_CMD_TRY_FMT:\r
+    case MARUCAM_CMD_S_FMT:\r
+    case MARUCAM_CMD_G_FMT:\r
+    case MARUCAM_CMD_QCTRL:\r
+    case MARUCAM_CMD_S_CTRL:\r
+    case MARUCAM_CMD_G_CTRL:\r
+    case MARUCAM_CMD_ENUM_FSIZES:\r
+    case MARUCAM_CMD_ENUM_FINTV:\r
+        ret = state->param->errCode;\r
+        state->param->errCode = 0;\r
+        break;\r
+    default:\r
+        WARN("Not supported command!!\n");\r
+        break;\r
+    }\r
+    return ret;\r
+}\r
+\r
+static inline void marucam_mmio_write(void *opaque, target_phys_addr_t offset, uint32_t value)\r
+{\r
+    MaruCamState *state = (MaruCamState*)opaque;\r
+    \r
+    switch(offset & 0xFF) {\r
+    case MARUCAM_CMD_OPEN:\r
+        marucam_device_open(state);\r
+        break;\r
+    case MARUCAM_CMD_CLOSE:\r
+        marucam_device_close(state);\r
+        break;\r
+    case MARUCAM_CMD_START_PREVIEW:\r
+        marucam_device_start_preview(state);\r
+        break;\r
+    case MARUCAM_CMD_STOP_PREVIEW:\r
+        marucam_device_stop_preview(state);\r
+        break;\r
+    case MARUCAM_CMD_S_PARAM:\r
+        marucam_device_s_param(state);\r
+        break;\r
+    case MARUCAM_CMD_G_PARAM:\r
+        marucam_device_g_param(state);\r
+        break;\r
+    case MARUCAM_CMD_ENUM_FMT:\r
+        marucam_device_enum_fmt(state);\r
+        break;\r
+    case MARUCAM_CMD_TRY_FMT:\r
+        marucam_device_try_fmt(state);\r
+        break;\r
+    case MARUCAM_CMD_S_FMT:\r
+        marucam_device_s_fmt(state);\r
+        break;\r
+    case MARUCAM_CMD_G_FMT:\r
+        marucam_device_g_fmt(state);\r
+        break;\r
+    case MARUCAM_CMD_QCTRL:\r
+        marucam_device_qctrl(state);\r
+        break;\r
+    case MARUCAM_CMD_S_CTRL:\r
+        marucam_device_s_ctrl(state);\r
+        break;\r
+    case MARUCAM_CMD_G_CTRL:\r
+        marucam_device_g_ctrl(state);\r
+        break;\r
+    case MARUCAM_CMD_ENUM_FSIZES:\r
+        marucam_device_enum_fsizes(state);\r
+        break;\r
+    case MARUCAM_CMD_ENUM_FINTV:\r
+        marucam_device_enum_fintv(state);\r
+        break;\r
+    case MARUCAM_CMD_S_DATA:\r
+        state->param->stack[state->param->top++] = value;\r
+        break;\r
+    case MARUCAM_CMD_DATACLR:\r
+        memset(state->param, 0, sizeof(MaruCamParam));\r
+        break;\r
+    case MARUCAM_CMD_CLRIRQ:\r
+        qemu_irq_lower(state->dev.irq[2]);\r
+        break;\r
+    case MARUCAM_CMD_REQFRAME:\r
+        qemu_mutex_lock(&state->thread_mutex);\r
+        state->req_frame = value + 1;\r
+        qemu_mutex_unlock(&state->thread_mutex);\r
+        break;\r
+    default:\r
+        WARN("Not supported command!!\n");\r
+        break;\r
+    }\r
+}\r
+\r
+static const MemoryRegionOps maru_camera_mmio_ops = {\r
+    .old_mmio = {\r
+        .read = {\r
+            marucam_mmio_read,\r
+            marucam_mmio_read,\r
+            marucam_mmio_read,\r
+        },\r
+        .write = {\r
+            marucam_mmio_write,\r
+            marucam_mmio_write,\r
+            marucam_mmio_write,\r
+        },\r
+    },\r
+    .endianness = DEVICE_LITTLE_ENDIAN,\r
+};\r
+\r
+/*\r
+ *  Initialization function\r
+ */\r
+static int marucam_initfn(PCIDevice *dev)\r
+{\r
+    MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);\r
+    uint8_t *pci_conf = s->dev.config;\r
+\r
+    pci_config_set_interrupt_pin(pci_conf, 0x03);\r
+\r
+    memory_region_init_ram(&s->vram, NULL, "marucamera.ram", MARUCAM_MEM_SIZE);\r
+    s->vaddr = memory_region_get_ram_ptr(&s->vram);\r
+\r
+    memory_region_init_io (&s->mmio, &maru_camera_mmio_ops, s, "maru-camera-mmio", MARUCAM_REG_SIZE);\r
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);\r
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);\r
+\r
+    /* for worker thread */\r
+    s->param = (MaruCamParam*)g_malloc0(sizeof(MaruCamParam));\r
+    qemu_cond_init(&s->thread_cond);\r
+    qemu_mutex_init(&s->thread_mutex);\r
+\r
+    marucam_device_init(s);\r
+\r
+    return 0;\r
+}\r
+\r
+/*\r
+ *  Termination function\r
+ */\r
+static int marucam_exitfn(PCIDevice *dev)\r
+{\r
+    MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);\r
+\r
+    g_free((gpointer)s->param);\r
+    qemu_cond_destroy(&s->thread_cond);\r
+    qemu_mutex_destroy(&s->thread_mutex);\r
+\r
+    memory_region_destroy (&s->vram);\r
+    memory_region_destroy (&s->mmio);\r
+    return 0;\r
+}\r
+\r
+int maru_camera_pci_init(PCIBus *bus)\r
+{\r
+    INFO("[%s] camera device was initialized.\n", __func__);\r
+    pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME);\r
+    return 0;\r
+}\r
+\r
+static PCIDeviceInfo maru_camera_info = {\r
+    .qdev.name    = MARU_PCI_CAMERA_DEVICE_NAME,\r
+    .qdev.desc    = "MARU Virtual Camera device for Tizen emulator",\r
+    .qdev.size    = sizeof(MaruCamState),\r
+    .no_hotplug   = 1,\r
+    .init         = marucam_initfn,\r
+    .exit         = marucam_exitfn,\r
+    .vendor_id    = PCI_VENDOR_ID_TIZEN,\r
+    .device_id    = PCI_DEVICE_ID_VIRTUAL_CAMERA,\r
+    .class_id     = PCI_CLASS_OTHERS,\r
+};\r
+\r
+static void maru_camera_pci_register(void)\r
+{\r
+    pci_qdev_register(&maru_camera_info);\r
+}\r
+\r
+device_init(maru_camera_pci_register);\r
diff --git a/tizen/src/hw/maru_camera_linux_pci.c b/tizen/src/hw/maru_camera_linux_pci.c
new file mode 100644 (file)
index 0000000..970cfc3
--- /dev/null
@@ -0,0 +1,667 @@
+/*\r
+ * Implementation of MARU Virtual Camera device by PCI bus on Linux.\r
+ *\r
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * JinHyung Jo <jinhyung.jo@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#include "qemu-common.h"\r
+#include "qemu-common.h"\r
+#include "maru_camera_common.h"\r
+#include "pci.h"\r
+#include "kvm.h"\r
+#include "tizen/src/debug_ch.h"\r
+\r
+#include <linux/videodev2.h>\r
+\r
+#include <libv4l2.h>\r
+#include <libv4lconvert.h>\r
+\r
+MULTI_DEBUG_CHANNEL(tizen, camera_linux);\r
+\r
+static int v4l2_fd;\r
+static int convert_trial;\r
+\r
+static struct v4l2_format dst_fmt;\r
+\r
+static int xioctl(int fd, int req, void *arg)\r
+{\r
+    int r;\r
+\r
+    do {\r
+        r = v4l2_ioctl(fd, req, arg);\r
+    } while ( r < 0 && errno == EINTR);\r
+\r
+    return r;\r
+}\r
+\r
+#define MARUCAM_CTRL_VALUE_MAX      20\r
+#define MARUCAM_CTRL_VALUE_MIN      1\r
+#define MARUCAM_CTRL_VALUE_MID      10\r
+#define MARUCAM_CTRL_VALUE_STEP     1\r
+\r
+struct marucam_qctrl {\r
+    uint32_t id;\r
+    uint32_t hit;\r
+    int32_t min;\r
+    int32_t max;\r
+    int32_t step;\r
+    int32_t init_val;\r
+};\r
+\r
+static struct marucam_qctrl qctrl_tbl[] = {\r
+    { V4L2_CID_BRIGHTNESS, 0, },\r
+    { V4L2_CID_CONTRAST, 0, },\r
+    { V4L2_CID_SATURATION,0, },\r
+    { V4L2_CID_SHARPNESS, 0, },\r
+};\r
+\r
+static void marucam_reset_controls(void)\r
+{\r
+    uint32_t i;\r
+    for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {\r
+        if (qctrl_tbl[i].hit) {\r
+            struct v4l2_control ctrl = {0,};\r
+            ctrl.id = qctrl_tbl[i].id;\r
+            ctrl.value = qctrl_tbl[i].init_val;\r
+            if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {\r
+                ERR("failed to set video control value while reset values : %s\n", strerror(errno));\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value)\r
+{\r
+    double rate = 0.0;\r
+    int32_t dist = 0, ret = 0;\r
+\r
+    dist = max - min;\r
+\r
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
+        ret = min + (int32_t)(value / rate);\r
+    } else {\r
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
+        ret = min + (int32_t)(rate * value);\r
+    }\r
+    return ret;\r
+}\r
+\r
+static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)\r
+{\r
+    double rate  = 0.0;\r
+    int32_t dist = 0, ret = 0;\r
+\r
+    dist = max - min;\r
+\r
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
+        ret = (int32_t)((double)(value - min) * rate);\r
+    } else {\r
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
+        ret = (int32_t)((double)(value - min) / rate);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int __v4l2_grab(MaruCamState *state)\r
+{\r
+    fd_set fds;\r
+    static uint32_t index = 0;\r
+    struct timeval tv;\r
+    void *buf;\r
+    int ret;\r
+    \r
+    FD_ZERO(&fds);\r
+    FD_SET(v4l2_fd, &fds);\r
+\r
+    tv.tv_sec = 2;\r
+    tv.tv_usec = 0;\r
+\r
+    ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);\r
+    if ( ret < 0) {\r
+        if (errno == EINTR)\r
+            return 0;\r
+        ERR("select : %s\n", strerror(errno));\r
+        return -1;\r
+    }\r
+    if (!ret) {\r
+        WARN("Timed out\n");\r
+        return 0;\r
+    }\r
+\r
+    if (!v4l2_fd || (v4l2_fd == -1)) {\r
+        WARN("file descriptor is closed or not opened \n");\r
+        return -1;\r
+    }\r
+\r
+       qemu_mutex_lock(&state->thread_mutex);\r
+       ret = state->streamon;\r
+       qemu_mutex_unlock(&state->thread_mutex);\r
+       if (!ret)\r
+              return -1;\r
+\r
+    buf = state->vaddr + (state->buf_size * index);\r
+    ret = v4l2_read(v4l2_fd, buf, state->buf_size);\r
+    if ( ret < 0) {\r
+        switch (errno) {\r
+        case EINVAL:\r
+        case ENOMEM:\r
+            ERR("v4l2_read failed : %s\n", strerror(errno));\r
+            return -1;\r
+        case EAGAIN:\r
+        case EIO:\r
+        case EINTR:\r
+        default:\r
+            if (convert_trial-- == -1) {\r
+                ERR("Try count for v4l2_read is exceeded\n");\r
+                return -1;\r
+            }\r
+            return 0;\r
+        }\r
+    }\r
+\r
+    index = !index;\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    if (state->streamon) {\r
+        if (state->req_frame) {\r
+            qemu_irq_raise(state->dev.irq[2]);\r
+            state->req_frame = 0;\r
+        }\r
+        ret = 1;\r
+    } else {\r
+        ret = -1;\r
+    }\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+\r
+    return ret;\r
+}\r
+\r
+// Worker thread\r
+static void *marucam_worker_thread(void *thread_param)\r
+{\r
+    MaruCamState *state = (MaruCamState*)thread_param;\r
+\r
+wait_worker_thread:\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->streamon = 0;\r
+    convert_trial = 10;\r
+    qemu_cond_wait(&state->thread_cond, &state->thread_mutex);\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+    INFO("Streaming on ......\n");\r
+\r
+    while (1)\r
+    {\r
+        qemu_mutex_lock(&state->thread_mutex);\r
+        if (state->streamon) {\r
+            qemu_mutex_unlock(&state->thread_mutex);\r
+            if (__v4l2_grab(state) < 0) {\r
+                INFO("...... Streaming off\n");\r
+                goto wait_worker_thread;\r
+            }\r
+        } else {\r
+            qemu_mutex_unlock(&state->thread_mutex);\r
+            INFO("...... Streaming off\n");\r
+            goto wait_worker_thread;\r
+        }\r
+    }\r
+    qemu_thread_exit((void*)0);\r
+}\r
+\r
+void marucam_device_init(MaruCamState* state)\r
+{\r
+    qemu_thread_create(&state->thread_id, marucam_worker_thread, (void*)state);\r
+}\r
+\r
+// MARUCAM_CMD_OPEN\r
+void marucam_device_open(MaruCamState* state)\r
+{\r
+    struct v4l2_capability cap;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    v4l2_fd = v4l2_open("/dev/video0", O_RDWR);\r
+    if (v4l2_fd < 0) {\r
+        ERR("v4l2 device open failed.(/dev/video0)\n");\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    if (xioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap) < 0) {\r
+        ERR("Could not qeury video capabilities\n");\r
+        v4l2_close(v4l2_fd);\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||\r
+            !(cap.capabilities & V4L2_CAP_STREAMING)) {\r
+        ERR("Not supported video driver.\n");\r
+        v4l2_close(v4l2_fd);\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    memset(&dst_fmt, 0, sizeof(dst_fmt));\r
+    INFO("Opened\n");\r
+}\r
+\r
+// MARUCAM_CMD_START_PREVIEW\r
+void marucam_device_start_preview(MaruCamState* state)\r
+{\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->streamon = 1;\r
+    state->buf_size = dst_fmt.fmt.pix.sizeimage;\r
+    qemu_cond_signal(&state->thread_cond);\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+       INFO("Starting preview!\n");\r
+}\r
+\r
+// MARUCAM_CMD_STOP_PREVIEW\r
+void marucam_device_stop_preview(MaruCamState* state)\r
+{\r
+       struct timespec req;\r
+       req.tv_sec = 0;\r
+       req.tv_nsec = 333333333;\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->streamon = 0;\r
+    state->buf_size = 0;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+    nanosleep(&req, NULL);\r
+       INFO("Stopping preview!\n");\r
+}\r
+\r
+void marucam_device_s_param(MaruCamState* state)\r
+{\r
+    struct v4l2_streamparm sp;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&sp, 0, sizeof(struct v4l2_streamparm));\r
+    sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+    sp.parm.capture.timeperframe.numerator = param->stack[0];\r
+    sp.parm.capture.timeperframe.denominator = param->stack[1];\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {\r
+        ERR("failed to set FPS: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+    }\r
+}\r
+\r
+void marucam_device_g_param(MaruCamState* state)\r
+{\r
+    struct v4l2_streamparm sp;\r
+    MaruCamParam *param = state->param;\r
+    \r
+    param->top = 0;\r
+    memset(&sp, 0, sizeof(struct v4l2_streamparm));\r
+    sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_G_PARM, &sp) < 0) {\r
+        ERR("failed to get FPS: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+    param->stack[0] = sp.parm.capture.capability;\r
+    param->stack[1] = sp.parm.capture.timeperframe.numerator;\r
+    param->stack[2] = sp.parm.capture.timeperframe.denominator;\r
+}\r
+\r
+void marucam_device_s_fmt(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&dst_fmt, 0, sizeof(struct v4l2_format));\r
+    dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+    dst_fmt.fmt.pix.width = param->stack[0];\r
+    dst_fmt.fmt.pix.height = param->stack[1];\r
+    dst_fmt.fmt.pix.pixelformat = param->stack[2];\r
+    dst_fmt.fmt.pix.field = param->stack[3];\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {\r
+        ERR("failed to set video format: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+\r
+    param->stack[0] = dst_fmt.fmt.pix.width;\r
+    param->stack[1] = dst_fmt.fmt.pix.height;\r
+    param->stack[2] = dst_fmt.fmt.pix.field;\r
+    param->stack[3] = dst_fmt.fmt.pix.pixelformat;\r
+    param->stack[4] = dst_fmt.fmt.pix.bytesperline;\r
+    param->stack[5] = dst_fmt.fmt.pix.sizeimage;\r
+    param->stack[6] = dst_fmt.fmt.pix.colorspace;\r
+    param->stack[7] = dst_fmt.fmt.pix.priv;\r
+}\r
+\r
+void marucam_device_g_fmt(MaruCamState* state)\r
+{\r
+    struct v4l2_format format;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&format, 0, sizeof(struct v4l2_format));\r
+    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {\r
+        ERR("failed to get video format: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+    } else {\r
+        param->stack[0] = format.fmt.pix.width;\r
+        param->stack[1] = format.fmt.pix.height;\r
+        param->stack[2] = format.fmt.pix.field;\r
+        param->stack[3] = format.fmt.pix.pixelformat;\r
+        param->stack[4] = format.fmt.pix.bytesperline;\r
+        param->stack[5] = format.fmt.pix.sizeimage;\r
+        param->stack[6] = format.fmt.pix.colorspace;\r
+        param->stack[7] = format.fmt.pix.priv;\r
+        memcpy(&dst_fmt, &format, sizeof(format));\r
+    }\r
+}\r
+\r
+void marucam_device_try_fmt(MaruCamState* state)\r
+{\r
+    struct v4l2_format format;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&format, 0, sizeof(struct v4l2_format));\r
+    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+    format.fmt.pix.width = param->stack[0];\r
+    format.fmt.pix.height = param->stack[1];\r
+    format.fmt.pix.pixelformat = param->stack[2];\r
+    format.fmt.pix.field = param->stack[3];\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {\r
+        ERR("failed to check video format: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+    param->stack[0] = format.fmt.pix.width;\r
+    param->stack[1] = format.fmt.pix.height;\r
+    param->stack[2] = format.fmt.pix.field;\r
+    param->stack[3] = format.fmt.pix.pixelformat;\r
+    param->stack[4] = format.fmt.pix.bytesperline;\r
+    param->stack[5] = format.fmt.pix.sizeimage;\r
+    param->stack[6] = format.fmt.pix.colorspace;\r
+    param->stack[7] = format.fmt.pix.priv;\r
+}\r
+\r
+void marucam_device_enum_fmt(MaruCamState* state)\r
+{\r
+    struct v4l2_fmtdesc format;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&format, 0, sizeof(struct v4l2_fmtdesc));\r
+    format.index = param->stack[0];\r
+    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) {\r
+        if (errno != EINVAL)\r
+            ERR("failed to enumerate video formats: %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+    param->stack[0] = format.index;\r
+    param->stack[1] = format.flags;\r
+    param->stack[2] = format.pixelformat;\r
+    /* set description */\r
+    memcpy(&param->stack[3], format.description, sizeof(format.description));\r
+}\r
+\r
+void marucam_device_qctrl(MaruCamState* state)\r
+{\r
+    uint32_t i;\r
+    char name[32] = {0,};\r
+    struct v4l2_queryctrl ctrl;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&ctrl, 0, sizeof(struct v4l2_queryctrl));\r
+    ctrl.id = param->stack[0];\r
+\r
+    switch (ctrl.id) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        TRACE("Query : BRIGHTNESS\n");\r
+        memcpy((void*)name, (void*)"brightness", 32);\r
+        i = 0;\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        TRACE("Query : CONTRAST\n");\r
+        memcpy((void*)name, (void*)"contrast", 32);\r
+        i = 1;\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        TRACE("Query : SATURATION\n");\r
+        memcpy((void*)name, (void*)"saturation", 32);\r
+        i = 2;\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        TRACE("Query : SHARPNESS\n");\r
+        memcpy((void*)name, (void*)"sharpness", 32);\r
+        i = 3;\r
+        break;\r
+    default:\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) {\r
+        if (errno != EINVAL)\r
+            ERR("failed to query video controls : %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    } else {\r
+        struct v4l2_control sctrl;\r
+        memset(&sctrl, 0, sizeof(struct v4l2_control));\r
+        sctrl.id = ctrl.id;\r
+        if ((ctrl.maximum + ctrl.minimum) == 0) {\r
+            sctrl.value = 0;\r
+        } else {\r
+            sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;\r
+        }\r
+        if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {\r
+            ERR("failed to set video control value : %s\n", strerror(errno));\r
+            param->errCode = errno;\r
+            return;\r
+        }\r
+        qctrl_tbl[i].hit = 1;\r
+        qctrl_tbl[i].min = ctrl.minimum;\r
+        qctrl_tbl[i].max = ctrl.maximum;\r
+        qctrl_tbl[i].step = ctrl.step;\r
+        qctrl_tbl[i].init_val = ctrl.default_value;\r
+    }\r
+\r
+    // set fixed values by FW configuration file\r
+    param->stack[0] = ctrl.id;\r
+    param->stack[1] = MARUCAM_CTRL_VALUE_MIN;   // minimum\r
+    param->stack[2] = MARUCAM_CTRL_VALUE_MAX;   // maximum\r
+    param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step\r
+    param->stack[4] = MARUCAM_CTRL_VALUE_MID;   // default_value\r
+    param->stack[5] = ctrl.flags;\r
+    /* name field setting */\r
+    memcpy(&param->stack[6], (void*)name, sizeof(ctrl.name));\r
+}\r
+\r
+void marucam_device_s_ctrl(MaruCamState* state)\r
+{\r
+    uint32_t i;\r
+    struct v4l2_control ctrl;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&ctrl, 0, sizeof(struct v4l2_control));\r
+    ctrl.id = param->stack[0];\r
+\r
+    switch (ctrl.id) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        i = 0;\r
+        TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]);\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        i = 1;\r
+        TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]);\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        i = 2;\r
+        TRACE("%d is set to the value of the SATURATION\n", param->stack[1]);\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        i = 3;\r
+        TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]);\r
+        break;\r
+    default:\r
+        ERR("our emulator does not support this control : 0x%x\n", ctrl.id);\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,\r
+            qctrl_tbl[i].max, param->stack[1]);\r
+    if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {\r
+        ERR("failed to set video control value : value(%d), %s\n", param->stack[1], strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+}\r
+\r
+void marucam_device_g_ctrl(MaruCamState* state)\r
+{\r
+    uint32_t i;\r
+    struct v4l2_control ctrl;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&ctrl, 0, sizeof(struct v4l2_control));\r
+    ctrl.id = param->stack[0];\r
+\r
+    switch (ctrl.id) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        TRACE("Gets the value of the BRIGHTNESS\n");\r
+        i = 0;\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        TRACE("Gets the value of the CONTRAST\n");\r
+        i = 1;\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        TRACE("Gets the value of the SATURATION\n");\r
+        i = 2;\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        TRACE("Gets the value of the SHARPNESS\n");\r
+        i = 3;\r
+        break;\r
+    default:\r
+        ERR("our emulator does not support this control : 0x%x\n", ctrl.id);\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) {\r
+        ERR("failed to get video control value : %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+    param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min,\r
+            qctrl_tbl[i].max, ctrl.value);\r
+    TRACE("Value : %d\n", param->stack[0]);\r
+}\r
+\r
+void marucam_device_enum_fsizes(MaruCamState* state)\r
+{\r
+    struct v4l2_frmsizeenum fsize;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&fsize, 0, sizeof(struct v4l2_frmsizeenum));\r
+    fsize.index = param->stack[0];\r
+    fsize.pixel_format = param->stack[1];\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) {\r
+        if (errno != EINVAL)\r
+            ERR("failed to get frame sizes : %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+\r
+    if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {\r
+        param->stack[0] = fsize.discrete.width;\r
+        param->stack[1] = fsize.discrete.height;\r
+    } else {\r
+        param->errCode = EINVAL;\r
+        ERR("Not Supported mode, we only support DISCRETE\n");\r
+    }\r
+}\r
+\r
+void marucam_device_enum_fintv(MaruCamState* state)\r
+{\r
+    struct v4l2_frmivalenum ival;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    memset(&ival, 0, sizeof(struct v4l2_frmivalenum));\r
+    ival.index = param->stack[0];\r
+    ival.pixel_format = param->stack[1];\r
+    ival.width = param->stack[2];\r
+    ival.height = param->stack[3];\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {\r
+        if (errno != EINVAL)\r
+            ERR("failed to get frame intervals : %s\n", strerror(errno));\r
+        param->errCode = errno;\r
+        return;\r
+    }\r
+\r
+    if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {\r
+        param->stack[0] = ival.discrete.numerator;\r
+        param->stack[1] = ival.discrete.denominator;\r
+    } else {\r
+        param->errCode = EINVAL;\r
+        ERR("Not Supported mode, we only support DISCRETE\n");\r
+    }\r
+}\r
+\r
+// MARUCAM_CMD_CLOSE\r
+void marucam_device_close(MaruCamState* state)\r
+{\r
+       uint32_t is_streamon;\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    is_streamon = state->streamon;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+\r
+       if (is_streamon)\r
+              marucam_device_stop_preview(state);\r
+\r
+    marucam_reset_controls();\r
+\r
+    v4l2_close(v4l2_fd);\r
+    v4l2_fd = 0;\r
+    INFO("Closed\n");\r
+}\r
diff --git a/tizen/src/hw/maru_camera_win32_interface.h b/tizen/src/hw/maru_camera_win32_interface.h
new file mode 100644 (file)
index 0000000..6ae5e20
--- /dev/null
@@ -0,0 +1,932 @@
+/*\r
+ * Interface definition header for Windows host.\r
+ *\r
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * JinHyung Jo <jinhyung.jo@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#ifndef _MARU_CAMERA_INTERFACE_H_\r
+#define _MARU_CAMERA_INTERFACE_H_\r
+\r
+static const WCHAR HWCPinName[] = L"HWCInputPin\0";\r
+static const WCHAR HWCFilterName[] = L"HWCFilter\0";\r
+\r
+/* Forward Declarations */\r
+FWD_DECL(IBaseFilter);\r
+FWD_DECL(IFilterGraph);\r
+\r
+/* defines */\r
+#define MAX_PIN_NAME     128\r
+#define MAX_FILTER_NAME  128\r
+\r
+typedef LONGLONG REFERENCE_TIME;\r
+typedef long OAFilterState;\r
+typedef DWORD_PTR HSEMAPHORE;\r
+typedef DWORD_PTR HEVENT;\r
+\r
+typedef enum _FilterState {\r
+  State_Stopped,\r
+  State_Paused,\r
+  State_Running\r
+} FILTER_STATE;\r
+\r
+typedef struct _FilterInfo {\r
+  WCHAR achName[MAX_FILTER_NAME];\r
+  IFilterGraph *pGraph;\r
+} FILTER_INFO;\r
+\r
+typedef enum _PinDirection\r
+{   PINDIR_INPUT    = 0,\r
+    PINDIR_OUTPUT   = ( PINDIR_INPUT + 1 )\r
+} PIN_DIRECTION;\r
+\r
+typedef struct _PinInfo {\r
+  IBaseFilter *pFilter;\r
+  PIN_DIRECTION dir;\r
+  WCHAR achName[MAX_PIN_NAME];\r
+} PIN_INFO;\r
+\r
+typedef struct _AllocatorProperties {\r
+  long cBuffers;\r
+  long cbBuffer;\r
+  long cbAlign;\r
+  long cbPrefix;\r
+} ALLOCATOR_PROPERTIES;\r
+\r
+typedef struct _AMMediaType {\r
+  GUID majortype;\r
+  GUID subtype;\r
+  BOOL bFixedSizeSamples;\r
+  BOOL bTemporalCompression;\r
+  ULONG lSampleSize;\r
+  GUID formattype;\r
+  IUnknown *pUnk;\r
+  ULONG cbFormat;\r
+  BYTE *pbFormat;\r
+} AM_MEDIA_TYPE;\r
+\r
+typedef enum tagVideoProcAmpFlags {\r
+    VideoProcAmp_Flags_Auto = 0x0001,\r
+    VideoProcAmp_Flags_Manual = 0x0002\r
+} VideoProcAmpFlags;\r
+\r
+typedef enum tagVideoProcAmpProperty {\r
+    VideoProcAmp_Brightness,\r
+    VideoProcAmp_Contrast,\r
+    VideoProcAmp_Hue,\r
+    VideoProcAmp_Saturation,\r
+    VideoProcAmp_Sharpness,\r
+    VideoProcAmp_Gamma,\r
+    VideoProcAmp_ColorEnable,\r
+    VideoProcAmp_WhiteBalance,\r
+    VideoProcAmp_BacklightCompensation,\r
+    VideoProcAmp_Gain\r
+} VideoProcAmpProperty;\r
+\r
+typedef struct tagVIDEOINFOHEADER {\r
+    RECT rcSource;\r
+    RECT rcTarget;\r
+    DWORD dwBitRate;\r
+    DWORD dwBitErrorRate;\r
+    REFERENCE_TIME AvgTimePerFrame;\r
+    BITMAPINFOHEADER bmiHeader;\r
+} VIDEOINFOHEADER;\r
+\r
+typedef struct _VIDEO_STREAM_CONFIG_CAPS\r
+{\r
+  GUID guid;\r
+  ULONG VideoStandard;\r
+  SIZE InputSize;\r
+  SIZE MinCroppingSize;\r
+  SIZE MaxCroppingSize;\r
+  int CropGranularityX;\r
+  int CropGranularityY;\r
+  int CropAlignX;\r
+  int CropAlignY;\r
+  SIZE MinOutputSize;\r
+  SIZE MaxOutputSize;\r
+  int OutputGranularityX;\r
+  int OutputGranularityY;\r
+  int StretchTapsX;\r
+  int StretchTapsY;\r
+  int ShrinkTapsX;\r
+  int ShrinkTapsY;\r
+  LONGLONG MinFrameInterval;\r
+  LONGLONG MaxFrameInterval;\r
+  LONG MinBitsPerSecond;\r
+  LONG MaxBitsPerSecond;\r
+} VIDEO_STREAM_CONFIG_CAPS;\r
+\r
+\r
+/* Interface & Class GUIDs */\r
+static const IID IID_IGrabCallback   = {0x4C337035,0xC89E,0x4B42,{0x9B,0x0C,0x36,0x74,0x44,0xDD,0x70,0xDD}};\r
+\r
+EXTERN_C const IID IID_IBaseFilter;\r
+EXTERN_C const IID IID_ICreateDevEnum;\r
+EXTERN_C const IID IID_IGraphBuilder;\r
+EXTERN_C const IID IID_IMediaSeeking;\r
+EXTERN_C const IID IID_IMediaEventSink;\r
+EXTERN_C const IID IID_IMemInputPin;\r
+EXTERN_C const IID IID_IEnumPins;\r
+EXTERN_C const IID IID_IMediaFilter;\r
+EXTERN_C const IID IID_IEnumMediaTypes;\r
+EXTERN_C const IID IID_IMemAllocator;\r
+EXTERN_C const IID IID_IPin;\r
+EXTERN_C const IID IID_ICaptureGraphBuilder2;\r
+EXTERN_C const IID IID_IFileSinkFilter;\r
+EXTERN_C const IID IID_IAMCopyCaptureFileProgress;\r
+EXTERN_C const IID IID_IEnumFilters;\r
+EXTERN_C const IID IID_IMediaSample;\r
+EXTERN_C const IID IID_IMediaControl;\r
+EXTERN_C const IID IID_IAMStreamConfig;\r
+EXTERN_C const IID IID_IAMVideoProcAmp;\r
+\r
+EXTERN_C const IID CLSID_CaptureGraphBuilder2;\r
+EXTERN_C const IID CLSID_VideoInputDeviceCategory;\r
+EXTERN_C const IID CLSID_AudioRender;\r
+EXTERN_C const IID CLSID_SystemDeviceEnum;\r
+EXTERN_C const IID CLSID_AudioRendererCategory;\r
+EXTERN_C const IID CLSID_FilterGraph;\r
+EXTERN_C const IID CLSID_InfTee;\r
+EXTERN_C const IID CLSID_VideoMixingRenderer9;\r
+EXTERN_C const IID CLSID_MemoryAllocator;\r
+\r
+\r
+/* other types GUIDs*/\r
+EXTERN_C const IID MEDIATYPE_Audio;\r
+EXTERN_C const IID MEDIATYPE_Video;\r
+EXTERN_C const IID MEDIATYPE_Stream;\r
+EXTERN_C const IID MEDIASUBTYPE_PCM;\r
+EXTERN_C const IID MEDIASUBTYPE_WAVE;\r
+EXTERN_C const IID MEDIASUBTYPE_Avi;\r
+EXTERN_C const IID MEDIASUBTYPE_RGB32;\r
+EXTERN_C const IID MEDIASUBTYPE_YV12;\r
+EXTERN_C const IID MEDIASUBTYPE_YUY2;\r
+EXTERN_C const IID MEDIASUBTYPE_I420;\r
+EXTERN_C const IID MEDIASUBTYPE_YUYV;\r
+EXTERN_C const IID FORMAT_WaveFormatEx;\r
+EXTERN_C const IID FORMAT_VideoInfo;\r
+EXTERN_C const IID FORMAT_VideoInfo2;\r
+EXTERN_C const IID PIN_CATEGORY_CAPTURE;\r
+EXTERN_C const IID PIN_CATEGORY_PREVIEW;\r
+\r
+\r
+#define MEDIATYPE_NULL       GUID_NULL\r
+#define MEDIASUBTYPE_NULL    GUID_NULL\r
+\r
+#define INTERFACE IGrabCallback\r
+DECLARE_INTERFACE_(IGrabCallback, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Grab)(THIS_ ULONG,BYTE*) PURE;\r
+};\r
+#undef INTERFACE\r
+\r
+#ifdef COBJMACROS\r
+#define IGrabCallback_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b)\r
+#define IGrabCallback_AddRef(T) (T)->lpVtbl->AddRef(T)\r
+#define IGrabCallback_Release(T) (T)->lpVtbl->Release(T)\r
+#define IGrabCallback_Grab(T,a,b) (T)->lpVtbl->Grab(T,a,b)\r
+#endif /* COBJMACROS */\r
+\r
+#define INTERFACE IAMCopyCaptureFileProgress\r
+DECLARE_INTERFACE_(IAMCopyCaptureFileProgress, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Progress)(THIS_ int) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IReferenceClock\r
+DECLARE_INTERFACE_(IReferenceClock, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *) PURE;\r
+    STDMETHOD(AdviseTime)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HEVENT, DWORD_PTR *) PURE;\r
+    STDMETHOD(AdvisePeriodic)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HSEMAPHORE, DWORD_PTR *) PURE;\r
+    STDMETHOD(Unadvise)(THIS_ DWORD_PTR) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IEnumFilters\r
+DECLARE_INTERFACE_(IEnumFilters, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Next)(THIS_ ULONG, IBaseFilter **, ULONG *) PURE;\r
+    STDMETHOD(Skip)(THIS_ ULONG) PURE;\r
+    STDMETHOD(Reset)(THIS) PURE;\r
+    STDMETHOD(Clone)(THIS_ IEnumFilters **) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IEnumMediaTypes\r
+DECLARE_INTERFACE_(IEnumMediaTypes, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Next)(THIS_ ULONG, AM_MEDIA_TYPE **, ULONG *) PURE;\r
+    STDMETHOD(Skip)(THIS_ ULONG) PURE;\r
+    STDMETHOD(Reset)(THIS) PURE;\r
+    STDMETHOD(Clone)(THIS_ IEnumMediaTypes **) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IPin\r
+DECLARE_INTERFACE_(IPin, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Connect)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(ReceiveConnection)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(Disconnect)(THIS) PURE;\r
+    STDMETHOD(ConnectedTo)(THIS_ IPin **) PURE;\r
+    STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO *) PURE;\r
+    STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION *) PURE;\r
+    STDMETHOD(QueryId)(THIS_ LPWSTR *) PURE;\r
+    STDMETHOD(QueryAccept)(THIS_ const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(EnumMediaTypes)(THIS_ IEnumMediaTypes **) PURE;\r
+    STDMETHOD(QueryInternalConnections)(THIS_ IPin **, ULONG *) PURE;\r
+    STDMETHOD(EndOfStream)(THIS) PURE;\r
+    STDMETHOD(BeginFlush)(THIS) PURE;\r
+    STDMETHOD(EndFlush)(THIS) PURE;\r
+    STDMETHOD(NewSegment)(THIS_ REFERENCE_TIME, REFERENCE_TIME, double) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IEnumPins\r
+DECLARE_INTERFACE_(IEnumPins, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(Next)(THIS_ ULONG, IPin **, ULONG *) PURE;\r
+    STDMETHOD(Skip)(THIS_ ULONG) PURE;\r
+    STDMETHOD(Reset)(THIS) PURE;\r
+    STDMETHOD(Clone)(THIS_ IEnumPins **) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IMediaFilter\r
+DECLARE_INTERFACE_(IMediaFilter, IPersist)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;\r
+    STDMETHOD(Stop)(THIS) PURE;\r
+    STDMETHOD(Pause)(THIS) PURE;\r
+    STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;\r
+    STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;\r
+    STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;\r
+    STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IBaseFilter\r
+//DECLARE_INTERFACE_(IBaseFilter, IMediaFilter)\r
+_COM_interface IBaseFilter { CONST_VTABLE struct IBaseFilterVtbl *lpVtbl; };\r
+typedef CONST_VTABLE struct IBaseFilterVtbl IBaseFilterVtbl;\r
+CONST_VTABLE struct IBaseFilterVtbl\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;\r
+    STDMETHOD(Stop)(THIS) PURE;\r
+    STDMETHOD(Pause)(THIS) PURE;\r
+    STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;\r
+    STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;\r
+    STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;\r
+    STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;\r
+    STDMETHOD(EnumPins)(THIS_ IEnumPins **) PURE;\r
+    STDMETHOD(FindPin)(THIS_ LPCWSTR, IPin **) PURE;\r
+    STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO *) PURE;\r
+    STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph *, LPCWSTR) PURE;\r
+    STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR *) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IFilterGraph\r
+//DECLARE_INTERFACE_(IFilterGraph ,IUnknown)\r
+_COM_interface IFilterGraph { CONST_VTABLE struct IFilterGraphVtbl *lpVtbl; };\r
+typedef CONST_VTABLE struct IFilterGraphVtbl IFilterGraphVtbl;\r
+CONST_VTABLE struct IFilterGraphVtbl\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;\r
+    STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;\r
+    STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;\r
+    STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;\r
+    STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(Reconnect)(THIS_ IPin *) PURE;\r
+    STDMETHOD(Disconnect)(THIS_ IPin *) PURE;\r
+    STDMETHOD(SetDefaultSyncSource)(THIS) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IGraphBuilder\r
+DECLARE_INTERFACE_(IGraphBuilder ,IFilterGraph)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;\r
+    STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;\r
+    STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;\r
+    STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;\r
+    STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(Reconnect)(THIS_ IPin *) PURE;\r
+    STDMETHOD(Disconnect)(THIS_ IPin *) PURE;\r
+    STDMETHOD(SetDefaultSyncSource)(THIS) PURE;\r
+    STDMETHOD(Connect)(THIS_ IPin *, IPin *) PURE;\r
+    STDMETHOD(Render)(THIS_ IPin *) PURE;\r
+    STDMETHOD(RenderFile)(THIS_ LPCWSTR, LPCWSTR) PURE;\r
+    STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR, LPCWSTR, IBaseFilter **) PURE;\r
+    STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE;\r
+    STDMETHOD(Abort)(THIS) PURE;\r
+    STDMETHOD(ShouldOperationContinue)(THIS) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE ICreateDevEnum\r
+DECLARE_INTERFACE_(ICreateDevEnum, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(CreateClassEnumerator)(THIS_ REFCLSID, IEnumMoniker **, DWORD) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IMediaSample\r
+DECLARE_INTERFACE_(IMediaSample, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;\r
+    STDMETHOD_(long, GetSize)(THIS) PURE;\r
+    STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;\r
+    STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;\r
+    STDMETHOD(IsSyncPoint)(THIS) PURE;\r
+    STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE;\r
+    STDMETHOD(IsPreroll)(THIS) PURE;\r
+    STDMETHOD(SetPreroll)(THIS_ BOOL) PURE;\r
+    STDMETHOD_(long, GetActualDataLength)(THIS) PURE;\r
+    STDMETHOD(SetActualDataLength)(THIS_ long) PURE;\r
+    STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE;\r
+    STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(IsDiscontinuity)(THIS) PURE;\r
+    STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE;\r
+    STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;\r
+    STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IMemAllocator\r
+DECLARE_INTERFACE_(IMemAllocator, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES *, ALLOCATOR_PROPERTIES *) PURE;\r
+    STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES *) PURE;\r
+    STDMETHOD(Commit)(THIS) PURE;\r
+    STDMETHOD(Decommit)(THIS) PURE;\r
+    STDMETHOD(GetBuffer)(THIS_ IMediaSample **, REFERENCE_TIME *, REFERENCE_TIME *, DWORD) PURE;\r
+    STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample *) PURE;\r
+\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IMemInputPin\r
+DECLARE_INTERFACE_(IMemInputPin, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetAllocator)(THIS_ IMemAllocator **) PURE;\r
+    STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator *, BOOL) PURE;\r
+    STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES *) PURE;\r
+    STDMETHOD(Receive)(THIS_ IMediaSample *) PURE;\r
+    STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample **, long, long *) PURE;\r
+    STDMETHOD(ReceiveCanBlock)(THIS) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IFileSinkFilter\r
+DECLARE_INTERFACE_(IFileSinkFilter, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(SetFileName)(THIS_ LPCOLESTR,const AM_MEDIA_TYPE *) PURE;\r
+    STDMETHOD(GetCurFile)(THIS_ LPOLESTR *,AM_MEDIA_TYPE*) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE ICaptureGraphBuilder2\r
+DECLARE_INTERFACE_(ICaptureGraphBuilder2, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(SetFiltergraph)(THIS_ IGraphBuilder*) PURE;\r
+    STDMETHOD(GetFiltergraph)(THIS_ IGraphBuilder**) PURE;\r
+    STDMETHOD(SetOutputFileName)(THIS_ const GUID*,LPCOLESTR,IBaseFilter**,IFileSinkFilter**) PURE;\r
+    STDMETHOD(FindInterface)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFIID,void**) PURE;\r
+    STDMETHOD(RenderStream)(THIS_ const GUID*,const GUID*,IUnknown*,IBaseFilter*,IBaseFilter*) PURE;\r
+    STDMETHOD(ControlStream)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFERENCE_TIME*,REFERENCE_TIME*,WORD,WORD) PURE;\r
+    STDMETHOD(AllocCapFile)(THIS_ LPCOLESTR,DWORDLONG) PURE;\r
+    STDMETHOD(CopyCaptureFile)(THIS_ LPOLESTR,LPOLESTR,int,IAMCopyCaptureFileProgress*) PURE;\r
+    STDMETHOD(FindPin)(THIS_ IUnknown*,PIN_DIRECTION,const GUID*,const GUID*,BOOL,int,IPin**) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IAMStreamConfig\r
+DECLARE_INTERFACE_(IAMStreamConfig, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE;\r
+    STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE;\r
+    STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE;\r
+    STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IAMVideoProcAmp\r
+DECLARE_INTERFACE_(IAMVideoProcAmp, IUnknown)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetRange)(THIS_ long,long*,long*,long*,long*,long*) PURE;\r
+    STDMETHOD(Set)(THIS_ long,long,long) PURE;\r
+    STDMETHOD(Get)(THIS_ long,long*,long*) PURE;\r
+};\r
+#undef INTERFACE\r
+#define INTERFACE IMediaControl\r
+DECLARE_INTERFACE_(IMediaControl, IDispatch)\r
+{\r
+    STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;\r
+    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r
+    STDMETHOD_(ULONG,Release)(THIS) PURE;\r
+    STDMETHOD(GetTypeInfoCount)(THIS_ UINT*);\r
+    STDMETHOD(GetTypeInfo)(THIS_ UINT,LCID,ITypeInfo**);\r
+    STDMETHOD(GetIDsOfNames)(THIS_ REFIID,LPOLESTR*,UINT,LCID,DISPID*);\r
+    STDMETHOD(Invoke)(THIS_ DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);\r
+    STDMETHOD(Run)(THIS);\r
+    STDMETHOD(Pause)(THIS);\r
+    STDMETHOD(Stop)(THIS);\r
+    STDMETHOD(GetState)(THIS_ LONG, OAFilterState*);\r
+    STDMETHOD(RenderFile)(THIS_ BSTR);\r
+    STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**);\r
+    STDMETHOD(get_FilterCollection)(THIS_ IDispatch**);\r
+    STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**);\r
+    STDMETHOD(StopWhenReady)(THIS);\r
+};\r
+#undef INTERFACE\r
+\r
+#ifdef COBJMACROS\r
+#define ICreateDevEnum_QueryInterface(This,riid,ppvObject)  \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define ICreateDevEnum_AddRef(This) \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define ICreateDevEnum_Release(This)    \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define ICreateDevEnum_CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags)   \\r
+    ( (This)->lpVtbl -> CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IPin_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IPin_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IPin_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IPin_Connect(This,pReceivePin,pmt)  \\r
+    ( (This)->lpVtbl -> Connect(This,pReceivePin,pmt) )\r
+#define IPin_ReceiveConnection(This,pConnector,pmt) \\r
+    ( (This)->lpVtbl -> ReceiveConnection(This,pConnector,pmt) )\r
+#define IPin_Disconnect(This)   \\r
+    ( (This)->lpVtbl -> Disconnect(This) )\r
+#define IPin_ConnectedTo(This,pPin) \\r
+    ( (This)->lpVtbl -> ConnectedTo(This,pPin) )\r
+#define IPin_ConnectionMediaType(This,pmt)  \\r
+    ( (This)->lpVtbl -> ConnectionMediaType(This,pmt) )\r
+#define IPin_QueryPinInfo(This,pInfo)   \\r
+    ( (This)->lpVtbl -> QueryPinInfo(This,pInfo) )\r
+#define IPin_QueryDirection(This,pPinDir)   \\r
+    ( (This)->lpVtbl -> QueryDirection(This,pPinDir) )\r
+#define IPin_QueryId(This,Id)   \\r
+    ( (This)->lpVtbl -> QueryId(This,Id) )\r
+#define IPin_QueryAccept(This,pmt)  \\r
+    ( (This)->lpVtbl -> QueryAccept(This,pmt) )\r
+#define IPin_EnumMediaTypes(This,ppEnum)    \\r
+    ( (This)->lpVtbl -> EnumMediaTypes(This,ppEnum) )\r
+#define IPin_QueryInternalConnections(This,apPin,nPin)  \\r
+    ( (This)->lpVtbl -> QueryInternalConnections(This,apPin,nPin) )\r
+#define IPin_EndOfStream(This)  \\r
+    ( (This)->lpVtbl -> EndOfStream(This) )\r
+#define IPin_BeginFlush(This)   \\r
+    ( (This)->lpVtbl -> BeginFlush(This) )\r
+#define IPin_EndFlush(This) \\r
+    ( (This)->lpVtbl -> EndFlush(This) )\r
+#define IPin_NewSegment(This,tStart,tStop,dRate)    \\r
+    ( (This)->lpVtbl -> NewSegment(This,tStart,tStop,dRate) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IEnumPins_QueryInterface(This,riid,ppvObject)   \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IEnumPins_AddRef(This)  \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IEnumPins_Release(This) \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IEnumPins_Next(This,cPins,ppPins,pcFetched) \\r
+    ( (This)->lpVtbl -> Next(This,cPins,ppPins,pcFetched) )\r
+#define IEnumPins_Skip(This,cPins)  \\r
+    ( (This)->lpVtbl -> Skip(This,cPins) )\r
+#define IEnumPins_Reset(This)   \\r
+    ( (This)->lpVtbl -> Reset(This) )\r
+#define IEnumPins_Clone(This,ppEnum)    \\r
+    ( (This)->lpVtbl -> Clone(This,ppEnum) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IAMStreamConfig_QueryInterface(This,riid,ppvObject) \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IAMStreamConfig_AddRef(This)    \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IAMStreamConfig_Release(This)   \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IAMStreamConfig_SetFormat(This,pmt) \\r
+    ( (This)->lpVtbl -> SetFormat(This,pmt) )\r
+#define IAMStreamConfig_GetFormat(This,ppmt)    \\r
+    ( (This)->lpVtbl -> GetFormat(This,ppmt) )\r
+#define IAMStreamConfig_GetNumberOfCapabilities(This,piCount,piSize)    \\r
+    ( (This)->lpVtbl -> GetNumberOfCapabilities(This,piCount,piSize) )\r
+#define IAMStreamConfig_GetStreamCaps(This,iIndex,ppmt,pSCC)    \\r
+    ( (This)->lpVtbl -> GetStreamCaps(This,iIndex,ppmt,pSCC) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IFilterGraph_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IFilterGraph_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IFilterGraph_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IFilterGraph_AddFilter(This,pFilter,pName)  \\r
+    ( (This)->lpVtbl -> AddFilter(This,pFilter,pName) )\r
+#define IFilterGraph_RemoveFilter(This,pFilter) \\r
+    ( (This)->lpVtbl -> RemoveFilter(This,pFilter) )\r
+#define IFilterGraph_EnumFilters(This,ppEnum)   \\r
+    ( (This)->lpVtbl -> EnumFilters(This,ppEnum) )\r
+#define IFilterGraph_FindFilterByName(This,pName,ppFilter)  \\r
+    ( (This)->lpVtbl -> FindFilterByName(This,pName,ppFilter) )\r
+#define IFilterGraph_ConnectDirect(This,ppinOut,ppinIn,pmt) \\r
+    ( (This)->lpVtbl -> ConnectDirect(This,ppinOut,ppinIn,pmt) )\r
+#define IFilterGraph_Reconnect(This,ppin)   \\r
+    ( (This)->lpVtbl -> Reconnect(This,ppin) )\r
+#define IFilterGraph_Disconnect(This,ppin)  \\r
+    ( (This)->lpVtbl -> Disconnect(This,ppin) )\r
+#define IFilterGraph_SetDefaultSyncSource(This) \\r
+    ( (This)->lpVtbl -> SetDefaultSyncSource(This) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IMediaFilter_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IMediaFilter_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IMediaFilter_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IMediaFilter_GetClassID(This,pClassID)  \\r
+    ( (This)->lpVtbl -> GetClassID(This,pClassID) )\r
+#define IMediaFilter_Stop(This) \\r
+    ( (This)->lpVtbl -> Stop(This) )\r
+#define IMediaFilter_Pause(This)    \\r
+    ( (This)->lpVtbl -> Pause(This) )\r
+#define IMediaFilter_Run(This,tStart)   \\r
+    ( (This)->lpVtbl -> Run(This,tStart) )\r
+#define IMediaFilter_GetState(This,dwMilliSecsTimeout,State)    \\r
+    ( (This)->lpVtbl -> GetState(This,dwMilliSecsTimeout,State) )\r
+#define IMediaFilter_SetSyncSource(This,pClock) \\r
+    ( (This)->lpVtbl -> SetSyncSource(This,pClock) )\r
+#define IMediaFilter_GetSyncSource(This,pClock) \\r
+    ( (This)->lpVtbl -> GetSyncSource(This,pClock) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IBaseFilter_QueryInterface(This,riid,ppvObject) \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IBaseFilter_AddRef(This)    \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IBaseFilter_Release(This)   \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IBaseFilter_GetClassID(This,pClassID)   \\r
+    ( (This)->lpVtbl -> GetClassID(This,pClassID) )\r
+#define IBaseFilter_Stop(This)  \\r
+    ( (This)->lpVtbl -> Stop(This) )\r
+#define IBaseFilter_Pause(This) \\r
+    ( (This)->lpVtbl -> Pause(This) )\r
+#define IBaseFilter_Run(This,tStart)    \\r
+    ( (This)->lpVtbl -> Run(This,tStart) )\r
+#define IBaseFilter_GetState(This,dwMilliSecsTimeout,State) \\r
+    ( (This)->lpVtbl -> GetState(This,dwMilliSecsTimeout,State) )\r
+#define IBaseFilter_SetSyncSource(This,pClock)  \\r
+    ( (This)->lpVtbl -> SetSyncSource(This,pClock) )\r
+#define IBaseFilter_GetSyncSource(This,pClock)  \\r
+    ( (This)->lpVtbl -> GetSyncSource(This,pClock) )\r
+#define IBaseFilter_EnumPins(This,ppEnum)   \\r
+    ( (This)->lpVtbl -> EnumPins(This,ppEnum) )\r
+#define IBaseFilter_FindPin(This,Id,ppPin)  \\r
+    ( (This)->lpVtbl -> FindPin(This,Id,ppPin) )\r
+#define IBaseFilter_QueryFilterInfo(This,pInfo) \\r
+    ( (This)->lpVtbl -> QueryFilterInfo(This,pInfo) )\r
+#define IBaseFilter_JoinFilterGraph(This,pGraph,pName)  \\r
+    ( (This)->lpVtbl -> JoinFilterGraph(This,pGraph,pName) )\r
+#define IBaseFilter_QueryVendorInfo(This,pVendorInfo)   \\r
+    ( (This)->lpVtbl -> QueryVendorInfo(This,pVendorInfo) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IMediaSample_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IMediaSample_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IMediaSample_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IMediaSample_GetPointer(This,ppBuffer)  \\r
+    ( (This)->lpVtbl -> GetPointer(This,ppBuffer) )\r
+#define IMediaSample_GetSize(This)  \\r
+        ( (This)->lpVtbl -> GetSize(This) )\r
+#define IMediaSample_GetTime(This,pTimeStart,pTimeEnd)  \\r
+    ( (This)->lpVtbl -> GetTime(This,pTimeStart,pTimeEnd) )\r
+#define IMediaSample_SetTime(This,pTimeStart,pTimeEnd)  \\r
+    ( (This)->lpVtbl -> SetTime(This,pTimeStart,pTimeEnd) )\r
+#define IMediaSample_IsSyncPoint(This)  \\r
+    ( (This)->lpVtbl -> IsSyncPoint(This) )\r
+#define IMediaSample_SetSyncPoint(This,bIsSyncPoint)    \\r
+    ( (This)->lpVtbl -> SetSyncPoint(This,bIsSyncPoint) )\r
+#define IMediaSample_IsPreroll(This)    \\r
+    ( (This)->lpVtbl -> IsPreroll(This) )\r
+#define IMediaSample_SetPreroll(This,bIsPreroll)    \\r
+    ( (This)->lpVtbl -> SetPreroll(This,bIsPreroll) )\r
+#define IMediaSample_GetActualDataLength(This)  \\r
+    ( (This)->lpVtbl -> GetActualDataLength(This) )\r
+#define IMediaSample_SetActualDataLength(This,length)   \\r
+    ( (This)->lpVtbl -> SetActualDataLength(This,length) )\r
+#define IMediaSample_GetMediaType(This,ppMediaType) \\r
+    ( (This)->lpVtbl -> GetMediaType(This,ppMediaType) )\r
+#define IMediaSample_SetMediaType(This,pMediaType)  \\r
+    ( (This)->lpVtbl -> SetMediaType(This,pMediaType) )\r
+#define IMediaSample_IsDiscontinuity(This)  \\r
+    ( (This)->lpVtbl -> IsDiscontinuity(This) )\r
+#define IMediaSample_SetDiscontinuity(This,bDiscontinuity)  \\r
+    ( (This)->lpVtbl -> SetDiscontinuity(This,bDiscontinuity) )\r
+#define IMediaSample_GetMediaTime(This,pTimeStart,pTimeEnd) \\r
+    ( (This)->lpVtbl -> GetMediaTime(This,pTimeStart,pTimeEnd) )\r
+#define IMediaSample_SetMediaTime(This,pTimeStart,pTimeEnd) \\r
+    ( (This)->lpVtbl -> SetMediaTime(This,pTimeStart,pTimeEnd) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IEnumFilters_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IEnumFilters_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IEnumFilters_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IEnumFilters_Next(This,cFilters,ppFilter,pcFetched) \\r
+    ( (This)->lpVtbl -> Next(This,cFilters,ppFilter,pcFetched) )\r
+#define IEnumFilters_Skip(This,cFilters)    \\r
+    ( (This)->lpVtbl -> Skip(This,cFilters) )\r
+#define IEnumFilters_Reset(This)    \\r
+    ( (This)->lpVtbl -> Reset(This) )\r
+#define IEnumFilters_Clone(This,ppEnum) \\r
+    ( (This)->lpVtbl -> Clone(This,ppEnum) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IMemAllocator_QueryInterface(This,riid,ppvObject)   \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IMemAllocator_AddRef(This)  \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IMemAllocator_Release(This) \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IMemAllocator_SetProperties(This,pRequest,pActual)  \\r
+    ( (This)->lpVtbl -> SetProperties(This,pRequest,pActual) )\r
+#define IMemAllocator_GetProperties(This,pProps)    \\r
+    ( (This)->lpVtbl -> GetProperties(This,pProps) )\r
+#define IMemAllocator_Commit(This)  \\r
+    ( (This)->lpVtbl -> Commit(This) )\r
+#define IMemAllocator_Decommit(This)    \\r
+    ( (This)->lpVtbl -> Decommit(This) )\r
+#define IMemAllocator_GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags)  \\r
+    ( (This)->lpVtbl -> GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags) )\r
+#define IMemAllocator_ReleaseBuffer(This,pBuffer)   \\r
+    ( (This)->lpVtbl -> ReleaseBuffer(This,pBuffer) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IMemInputPin_QueryInterface(This,riid,ppvObject)    \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IMemInputPin_AddRef(This)   \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IMemInputPin_Release(This)  \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IMemInputPin_GetAllocator(This,ppAllocator) \\r
+    ( (This)->lpVtbl -> GetAllocator(This,ppAllocator) )\r
+#define IMemInputPin_NotifyAllocator(This,pAllocator,bReadOnly) \\r
+    ( (This)->lpVtbl -> NotifyAllocator(This,pAllocator,bReadOnly) )\r
+#define IMemInputPin_GetAllocatorRequirements(This,pProps)  \\r
+    ( (This)->lpVtbl -> GetAllocatorRequirements(This,pProps) )\r
+#define IMemInputPin_Receive(This,pSample)  \\r
+    ( (This)->lpVtbl -> Receive(This,pSample) )\r
+#define IMemInputPin_ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed)  \\r
+    ( (This)->lpVtbl -> ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed) )\r
+#define IMemInputPin_ReceiveCanBlock(This)  \\r
+    ( (This)->lpVtbl -> ReceiveCanBlock(This) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IGraphBuilder_QueryInterface(This,riid,ppvObject)   \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IGraphBuilder_AddRef(This)  \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IGraphBuilder_Release(This) \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IGraphBuilder_AddFilter(This,pFilter,pName) \\r
+    ( (This)->lpVtbl -> AddFilter(This,pFilter,pName) )\r
+#define IGraphBuilder_RemoveFilter(This,pFilter)    \\r
+    ( (This)->lpVtbl -> RemoveFilter(This,pFilter) )\r
+#define IGraphBuilder_EnumFilters(This,ppEnum)  \\r
+    ( (This)->lpVtbl -> EnumFilters(This,ppEnum) )\r
+#define IGraphBuilder_FindFilterByName(This,pName,ppFilter) \\r
+    ( (This)->lpVtbl -> FindFilterByName(This,pName,ppFilter) )\r
+#define IGraphBuilder_ConnectDirect(This,ppinOut,ppinIn,pmt)    \\r
+    ( (This)->lpVtbl -> ConnectDirect(This,ppinOut,ppinIn,pmt) )\r
+#define IGraphBuilder_Reconnect(This,ppin)  \\r
+    ( (This)->lpVtbl -> Reconnect(This,ppin) )\r
+#define IGraphBuilder_Disconnect(This,ppin) \\r
+    ( (This)->lpVtbl -> Disconnect(This,ppin) )\r
+#define IGraphBuilder_SetDefaultSyncSource(This)    \\r
+    ( (This)->lpVtbl -> SetDefaultSyncSource(This) )\r
+#define IGraphBuilder_Connect(This,ppinOut,ppinIn)  \\r
+    ( (This)->lpVtbl -> Connect(This,ppinOut,ppinIn) )\r
+#define IGraphBuilder_Render(This,ppinOut)  \\r
+    ( (This)->lpVtbl -> Render(This,ppinOut) )\r
+#define IGraphBuilder_RenderFile(This,lpcwstrFile,lpcwstrPlayList)  \\r
+    ( (This)->lpVtbl -> RenderFile(This,lpcwstrFile,lpcwstrPlayList) )\r
+#define IGraphBuilder_AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter)  \\r
+    ( (This)->lpVtbl -> AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) )\r
+#define IGraphBuilder_SetLogFile(This,hFile)    \\r
+    ( (This)->lpVtbl -> SetLogFile(This,hFile) )\r
+#define IGraphBuilder_Abort(This)   \\r
+    ( (This)->lpVtbl -> Abort(This) )\r
+#define IGraphBuilder_ShouldOperationContinue(This) \\r
+    ( (This)->lpVtbl -> ShouldOperationContinue(This) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IEnumMediaTypes_QueryInterface(This,riid,ppvObject) \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IEnumMediaTypes_AddRef(This)    \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IEnumMediaTypes_Release(This)   \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IEnumMediaTypes_Next(This,cMediaTypes,ppMediaTypes,pcFetched)   \\r
+    ( (This)->lpVtbl -> Next(This,cMediaTypes,ppMediaTypes,pcFetched) )\r
+#define IEnumMediaTypes_Skip(This,cMediaTypes)  \\r
+    ( (This)->lpVtbl -> Skip(This,cMediaTypes) )\r
+#define IEnumMediaTypes_Reset(This) \\r
+    ( (This)->lpVtbl -> Reset(This) )\r
+#define IEnumMediaTypes_Clone(This,ppEnum)  \\r
+    ( (This)->lpVtbl -> Clone(This,ppEnum) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IMediaControl_QueryInterface(This,riid,ppvObject)   \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IMediaControl_AddRef(This)  \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IMediaControl_Release(This) \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IMediaControl_GetTypeInfoCount(This,pctinfo)    \\r
+    ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) )\r
+#define IMediaControl_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \\r
+    ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) )\r
+#define IMediaControl_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)   \\r
+    ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) )\r
+#define IMediaControl_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \\r
+    ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) )\r
+#define IMediaControl_Run(This) \\r
+    ( (This)->lpVtbl -> Run(This) )\r
+#define IMediaControl_Pause(This)   \\r
+    ( (This)->lpVtbl -> Pause(This) )\r
+#define IMediaControl_Stop(This)    \\r
+    ( (This)->lpVtbl -> Stop(This) )\r
+#define IMediaControl_GetState(This,msTimeout,pfs)  \\r
+    ( (This)->lpVtbl -> GetState(This,msTimeout,pfs) )\r
+#define IMediaControl_RenderFile(This,strFilename)  \\r
+    ( (This)->lpVtbl -> RenderFile(This,strFilename) )\r
+#define IMediaControl_AddSourceFilter(This,strFilename,ppUnk)   \\r
+    ( (This)->lpVtbl -> AddSourceFilter(This,strFilename,ppUnk) )\r
+#define IMediaControl_get_FilterCollection(This,ppUnk)  \\r
+    ( (This)->lpVtbl -> get_FilterCollection(This,ppUnk) )\r
+#define IMediaControl_get_RegFilterCollection(This,ppUnk)   \\r
+    ( (This)->lpVtbl -> get_RegFilterCollection(This,ppUnk) )\r
+#define IMediaControl_StopWhenReady(This)   \\r
+    ( (This)->lpVtbl -> StopWhenReady(This) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IAMVideoProcAmp_QueryInterface(This,riid,ppvObject) \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IAMVideoProcAmp_AddRef(This)    \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IAMVideoProcAmp_Release(This)   \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IAMVideoProcAmp_GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags)    \\r
+    ( (This)->lpVtbl -> GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags) )\r
+#define IAMVideoProcAmp_Set(This,Property,lValue,Flags) \\r
+    ( (This)->lpVtbl -> Set(This,Property,lValue,Flags) )\r
+#define IAMVideoProcAmp_Get(This,Property,lValue,Flags) \\r
+    ( (This)->lpVtbl -> Get(This,Property,lValue,Flags) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IFileSinkFilter_QueryInterface(This,riid,ppvObject) \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IFileSinkFilter_AddRef(This)    \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IFileSinkFilter_Release(This)   \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IFileSinkFilter_SetFileName(This,pszFileName,pmt)   \\r
+    ( (This)->lpVtbl -> SetFileName(This,pszFileName,pmt) )\r
+#define IFileSinkFilter_GetCurFile(This,ppszFileName,pmt)   \\r
+    ( (This)->lpVtbl -> GetCurFile(This,ppszFileName,pmt) )\r
+#endif /* COBJMACROS */\r
+\r
+#ifdef COBJMACROS\r
+#define IAMCopyCaptureFileProgress_QueryInterface(This,riid,ppvObject)  \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define IAMCopyCaptureFileProgress_AddRef(This) \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define IAMCopyCaptureFileProgress_Release(This)    \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define IAMCopyCaptureFileProgress_Progress(This,iProgress) \\r
+    ( (This)->lpVtbl -> Progress(This,iProgress) )\r
+#endif /* COBJMACROS */\r
+\r
+\r
+#ifdef COBJMACROS\r
+#define ICaptureGraphBuilder2_QueryInterface(This,riid,ppvObject)   \\r
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )\r
+#define ICaptureGraphBuilder2_AddRef(This)  \\r
+    ( (This)->lpVtbl -> AddRef(This) )\r
+#define ICaptureGraphBuilder2_Release(This) \\r
+    ( (This)->lpVtbl -> Release(This) )\r
+#define ICaptureGraphBuilder2_SetFiltergraph(This,pfg)  \\r
+    ( (This)->lpVtbl -> SetFiltergraph(This,pfg) )\r
+#define ICaptureGraphBuilder2_GetFiltergraph(This,ppfg) \\r
+    ( (This)->lpVtbl -> GetFiltergraph(This,ppfg) )\r
+#define ICaptureGraphBuilder2_SetOutputFileName(This,pType,lpstrFile,ppf,ppSink)    \\r
+    ( (This)->lpVtbl -> SetOutputFileName(This,pType,lpstrFile,ppf,ppSink) )\r
+#define ICaptureGraphBuilder2_FindInterface(This,pCategory,pType,pf,riid,ppint) \\r
+    ( (This)->lpVtbl -> FindInterface(This,pCategory,pType,pf,riid,ppint) )\r
+#define ICaptureGraphBuilder2_RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer)    \\r
+    ( (This)->lpVtbl -> RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer) )\r
+#define ICaptureGraphBuilder2_ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) \\r
+    ( (This)->lpVtbl -> ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) )\r
+#define ICaptureGraphBuilder2_AllocCapFile(This,lpstr,dwlSize)  \\r
+    ( (This)->lpVtbl -> AllocCapFile(This,lpstr,dwlSize) )\r
+#define ICaptureGraphBuilder2_CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback)    \\r
+    ( (This)->lpVtbl -> CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback) )\r
+#define ICaptureGraphBuilder2_FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin)   \\r
+    ( (This)->lpVtbl -> FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin) )\r
+#endif /* COBJMACROS */\r
+\r
+#endif // _MARU_CAMERA_INTERFACE_H_\r
diff --git a/tizen/src/hw/maru_camera_win32_pci.c b/tizen/src/hw/maru_camera_win32_pci.c
new file mode 100644 (file)
index 0000000..acd1ee7
--- /dev/null
@@ -0,0 +1,1971 @@
+/*\r
+ * Implementation of MARU Virtual Camera device by PCI bus on Windows.\r
+ *\r
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * JinHyung Jo <jinhyung.jo@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+\r
+#include "qemu-common.h"\r
+#include "maru_camera_common.h"\r
+#include "tizen/src/debug_ch.h"\r
+#include "tizen/src/mloop_event.h"\r
+\r
+#define CINTERFACE\r
+#define COBJMACROS\r
+#include "ocidl.h"\r
+#include "errors.h"      /* for VFW_E_XXXX */\r
+#include "mmsystem.h"    /* for MAKEFOURCC macro */\r
+#include "maru_camera_win32_interface.h"\r
+\r
+MULTI_DEBUG_CHANNEL(tizen, camera_win32);\r
+\r
+/*\r
+ * COM Interface implementations\r
+ *\r
+ */\r
+\r
+#define SAFE_RELEASE(x) { if (x) x->lpVtbl->Release(x); x = NULL; }\r
+\r
+typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);\r
+\r
+/*\r
+ * HWCGrabCallback\r
+ */\r
+\r
+typedef struct HWCGrabCallback\r
+{\r
+    IGrabCallback IGrabCallback_iface;\r
+    long m_cRef;\r
+    CallbackFn m_pCallback;\r
+    STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);\r
+} HWCGrabCallback;\r
+\r
+static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)\r
+{\r
+    return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);\r
+}\r
+\r
+static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface, REFIID riid, void **ppv)\r
+{\r
+    if (IsEqualIID(riid, &IID_IUnknown)) {\r
+        *ppv = (IUnknown*)iface;\r
+    } else if (IsEqualIID(riid, &IID_IGrabCallback)) {\r
+        *ppv = (IGrabCallback*)iface;\r
+    } else {\r
+        *ppv = NULL;\r
+        return E_NOINTERFACE;\r
+    }\r
+\r
+    IGrabCallback_AddRef(iface);\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)\r
+{\r
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
+\r
+    return InterlockedIncrement(&This->m_cRef);\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)\r
+{\r
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
+\r
+    if( InterlockedDecrement(&This->m_cRef) == 0)\r
+    {\r
+        This->m_pCallback = NULL;\r
+        g_free((void*)This);\r
+        return 0;\r
+    }\r
+\r
+    return This->m_cRef;\r
+}\r
+\r
+static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface, ULONG dwSize, BYTE *pBuffer)\r
+{\r
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
+\r
+    if (This->m_pCallback) {\r
+        This->m_pCallback(dwSize, pBuffer);\r
+        return S_OK;\r
+    }\r
+\r
+    return E_FAIL;\r
+}\r
+\r
+static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface, CallbackFn pCallbackFn)\r
+{\r
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
+\r
+    This->m_pCallback = pCallbackFn;\r
+    return S_OK;\r
+}\r
+\r
+static IGrabCallbackVtbl HWCGrabCallback_Vtbl =\r
+{\r
+        HWCGrabCallback_QueryInterface,\r
+        HWCGrabCallback_AddRef,\r
+        HWCGrabCallback_Release,\r
+        HWCGrabCallback_Grab\r
+};\r
+\r
+static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)\r
+{\r
+    HWCGrabCallback *This = (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));\r
+\r
+    if (!This) {\r
+        return E_OUTOFMEMORY;\r
+    }\r
+\r
+    This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;\r
+    This->m_cRef = 1;\r
+    This->m_pCallback = NULL;\r
+    This->SetCallback = HWCGrabCallback_SetCallback;\r
+    *ppv = &This->IGrabCallback_iface;\r
+    return S_OK;\r
+}\r
+\r
+/*\r
+ * HWCPin\r
+ */\r
+\r
+typedef struct HWCInPin\r
+{\r
+    IPin IPin_iface;\r
+    IMemInputPin IMemInputPin_iface;\r
+    IBaseFilter *m_pCFilter;\r
+    IPin *m_pConnectedPin;\r
+    IGrabCallback *m_pCallback;\r
+    BOOL m_bReadOnly;\r
+    long m_cRef;\r
+    STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);\r
+} HWCInPin;\r
+\r
+static inline HWCInPin *impl_from_IPin(IPin *iface)\r
+{\r
+    return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);\r
+}\r
+\r
+static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)\r
+{\r
+    return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) {\r
+        *ppv = &This->IPin_iface;\r
+        IPin_AddRef((IPin*)*ppv);\r
+    } else if (IsEqualIID(riid, &IID_IMemInputPin)) {\r
+        *ppv = &This->IMemInputPin_iface;\r
+        IPin_AddRef((IMemInputPin*)*ppv);\r
+    } else {\r
+        *ppv = NULL;\r
+        return E_NOINTERFACE;\r
+    }\r
+\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    return InterlockedIncrement(&This->m_cRef);\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if( InterlockedDecrement(&This->m_cRef) == 0)\r
+    {\r
+        if (This->m_pCFilter) {\r
+            IBaseFilter_Release(This->m_pCFilter);\r
+            This->m_pCFilter = NULL;\r
+        }\r
+        if (This->m_pCallback) {\r
+            IGrabCallback_Release(This->m_pCallback);\r
+            This->m_pCallback = NULL;\r
+        }\r
+        if (This->m_pConnectedPin) {\r
+            IPin_Release(This->m_pConnectedPin);\r
+            This->m_pConnectedPin = NULL;\r
+        }\r
+        g_free((void*)This);\r
+        return 0;\r
+    }\r
+    return This->m_cRef;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)\r
+{\r
+    if ( !pmt )\r
+        return S_OK;\r
+    return S_FALSE;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector, const AM_MEDIA_TYPE *pmt)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if (pConnector == NULL || pmt == NULL)\r
+        return E_POINTER;\r
+\r
+    if (This->m_pConnectedPin) {\r
+        return VFW_E_ALREADY_CONNECTED;\r
+    }\r
+    FILTER_STATE fs;\r
+    IBaseFilter_GetState(This->m_pCFilter, 0, &fs);\r
+    if (fs != State_Stopped) {\r
+        return VFW_E_NOT_STOPPED;\r
+    }\r
+    PIN_DIRECTION pd;\r
+    IPin_QueryDirection(pConnector, &pd);\r
+    if (pd == PINDIR_INPUT) {\r
+        return VFW_E_INVALID_DIRECTION;\r
+    }\r
+\r
+    This->m_pConnectedPin = pConnector;\r
+    IPin_AddRef(This->m_pConnectedPin);\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_Disconnect(IPin *iface)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    HRESULT hr;\r
+    if (This->m_pConnectedPin == NULL) {\r
+        hr = S_FALSE;\r
+    } else {\r
+        IPin_Release(This->m_pConnectedPin);\r
+        This->m_pConnectedPin = NULL;\r
+        hr = S_OK;\r
+    }\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **pPin)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if (pPin == NULL)\r
+        return E_POINTER;\r
+\r
+    if (This->m_pConnectedPin == NULL) {\r
+        return VFW_E_NOT_CONNECTED;\r
+    } else {\r
+        *pPin = This->m_pConnectedPin;\r
+        IPin_AddRef(This->m_pConnectedPin);\r
+    }\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)\r
+{\r
+    if (pmt == NULL) {\r
+        return E_POINTER;\r
+    }\r
+    return VFW_E_NOT_CONNECTED;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if (pInfo == NULL)\r
+        return E_POINTER;\r
+\r
+    pInfo->pFilter = This->m_pCFilter;\r
+    if (This->m_pCFilter) {\r
+        IBaseFilter_AddRef(This->m_pCFilter);\r
+    }\r
+    memcpy((void*)pInfo->achName, (void*)HWCPinName, sizeof(HWCPinName));\r
+    pInfo->dir = PINDIR_INPUT;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)\r
+{\r
+    if (pPinDir == NULL)\r
+        return E_POINTER;\r
+    *pPinDir = PINDIR_INPUT;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)\r
+{\r
+    if (Id == NULL)\r
+        return E_POINTER;\r
+    PVOID pId = CoTaskMemAlloc(sizeof(HWCPinName));\r
+    memcpy((void*)pId, (void*)HWCPinName, sizeof(HWCPinName));\r
+    *Id = (LPWSTR)pId;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)\r
+{\r
+    if (pmt == NULL)\r
+        return E_POINTER;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)\r
+{\r
+    if (ppEnum == NULL)\r
+            return E_POINTER;\r
+    return E_NOTIMPL;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface, IPin **ppPin, ULONG *nPin)\r
+{\r
+    return E_NOTIMPL;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)\r
+{\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)\r
+{\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_EndFlush(IPin *iface)\r
+{\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)\r
+{\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)\r
+{\r
+    HWCInPin *This = impl_from_IMemInputPin(iface);\r
+\r
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMemInputPin)) {\r
+        *ppv = &This->IMemInputPin_iface;\r
+        IMemInputPin_AddRef((IMemInputPin*)*ppv);\r
+    } else if (IsEqualIID(riid, &IID_IPin)) {\r
+        *ppv = &This->IPin_iface;\r
+        IPin_AddRef((IPin*)*ppv);\r
+    } else {\r
+        *ppv = NULL;\r
+        return E_NOINTERFACE;\r
+    }\r
+\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)\r
+{\r
+    HWCInPin *This = impl_from_IMemInputPin(iface);\r
+\r
+    return InterlockedIncrement(&This->m_cRef);\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)\r
+{\r
+    HWCInPin *This = impl_from_IMemInputPin(iface);\r
+\r
+    if( InterlockedDecrement(&This->m_cRef) == 0)\r
+    {\r
+        if (This->m_pCFilter) {\r
+            IBaseFilter_Release(This->m_pCFilter);\r
+            This->m_pCFilter = NULL;\r
+        }\r
+        if (This->m_pCallback) {\r
+            IGrabCallback_Release(This->m_pCallback);\r
+            This->m_pCallback = NULL;\r
+        }\r
+        if (This->m_pConnectedPin) {\r
+            IPin_Release(This->m_pConnectedPin);\r
+            This->m_pConnectedPin = NULL;\r
+        }\r
+        g_free((void*)This);\r
+        return 0;\r
+    }\r
+    return This->m_cRef;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **ppAllocator)\r
+{\r
+    if (ppAllocator == NULL)\r
+        return E_POINTER;\r
+    return VFW_E_NO_ALLOCATOR;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)\r
+{\r
+    if (pAllocator == NULL)\r
+        return E_POINTER;\r
+\r
+    return NOERROR;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)\r
+{\r
+    return E_NOTIMPL;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface, IMediaSample *pSample)\r
+{\r
+    HWCInPin *This = impl_from_IMemInputPin(iface);\r
+\r
+    if (pSample == NULL)\r
+        return E_POINTER;\r
+    if (This->m_pCallback != NULL) {\r
+        HRESULT hr;\r
+        BYTE* pBuffer = NULL;\r
+        DWORD dwSize = 0;\r
+        dwSize = IMediaSample_GetSize(pSample);\r
+        hr = IMediaSample_GetPointer(pSample, &pBuffer);\r
+        if (FAILED(hr))\r
+            return hr;\r
+        hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);\r
+        if (FAILED(hr))\r
+            return hr;\r
+    }\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **pSamples, long nSamples, long *nSamplesProcessed)\r
+{\r
+    HRESULT hr = S_OK;\r
+\r
+    if (pSamples == NULL)\r
+        return E_POINTER;\r
+\r
+    *nSamplesProcessed = 0;\r
+\r
+    while (nSamples-- > 0)\r
+    {\r
+        hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);\r
+        if (hr != S_OK)\r
+            break;\r
+        (*nSamplesProcessed)++;\r
+    }\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)\r
+{\r
+    return S_FALSE;\r
+}\r
+\r
+static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)\r
+{\r
+    HWCInPin *This = impl_from_IPin(iface);\r
+\r
+    if (pCaptureCB == NULL) {\r
+        IGrabCallback_Release(This->m_pCallback);\r
+        This->m_pCallback = NULL;\r
+    } else {\r
+        This->m_pCallback = pCaptureCB;\r
+        IGrabCallback_AddRef(This->m_pCallback);\r
+    }\r
+\r
+    return S_OK;\r
+}\r
+\r
+\r
+static IPinVtbl HWCPin_Vtbl =\r
+{\r
+    HWCPin_QueryInterface,\r
+    HWCPin_AddRef,\r
+    HWCPin_Release,\r
+    HWCPin_Connect,\r
+    HWCPin_ReceiveConnection,\r
+    HWCPin_Disconnect,\r
+    HWCPin_ConnectedTo,\r
+    HWCPin_ConnectionMediaType,\r
+    HWCPin_QueryPinInfo,\r
+    HWCPin_QueryDirection,\r
+    HWCPin_QueryId,\r
+    HWCPin_QueryAccept,\r
+    HWCPin_EnumMediaTypes,\r
+    HWCPin_QueryInternalConnections,\r
+    HWCPin_EndOfStream,\r
+    HWCPin_BeginFlush,\r
+    HWCPin_EndFlush,\r
+    HWCPin_NewSegment\r
+};\r
+\r
+static IMemInputPinVtbl HWCMemInputPin_Vtbl =\r
+{\r
+    HWCMemInputPin_QueryInterface,\r
+    HWCMemInputPin_AddRef,\r
+    HWCMemInputPin_Release,\r
+    HWCMemInputPin_GetAllocator,\r
+    HWCMemInputPin_NotifyAllocator,\r
+    HWCMemInputPin_GetAllocatorRequirements,\r
+    HWCMemInputPin_Receive,\r
+    HWCMemInputPin_ReceiveMultiple,\r
+    HWCMemInputPin_ReceiveCanBlock\r
+};\r
+\r
+static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)\r
+{\r
+    HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));\r
+\r
+    if (!This) {\r
+        return E_OUTOFMEMORY;\r
+    }\r
+\r
+    This->IPin_iface.lpVtbl = &HWCPin_Vtbl;\r
+    This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;\r
+    This->m_bReadOnly = FALSE;\r
+    This->m_pCFilter = pFilter;\r
+    if (This->m_pCFilter) {\r
+        IBaseFilter_AddRef(This->m_pCFilter);\r
+    }\r
+    This->m_pConnectedPin = NULL;\r
+    This->m_pCallback = NULL;\r
+    This->m_cRef = 1;\r
+    This->SetGrabCallbackIF = HWCPin_SetCallback;\r
+    *ppv = &This->IPin_iface;\r
+\r
+    return S_OK;\r
+}\r
+\r
+/*\r
+ * HWCEnumPins\r
+ */\r
+\r
+typedef struct HWCEnumPins\r
+{\r
+    IEnumPins IEnumPins_iface;\r
+    IBaseFilter *m_pFilter;\r
+    int m_nPos;\r
+    long m_cRef;\r
+} HWCEnumPins;\r
+\r
+static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)\r
+{\r
+    return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);\r
+}\r
+\r
+static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppv)\r
+{\r
+    if (ppv == NULL)\r
+        return E_POINTER;\r
+\r
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {\r
+        *ppv = iface;\r
+    } else {\r
+        *ppv = NULL;\r
+        return E_NOINTERFACE;\r
+    }\r
+\r
+    IEnumPins_AddRef(iface);\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+\r
+    return InterlockedIncrement(&This->m_cRef);\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+\r
+    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
+        if (This->m_pFilter) {\r
+            IBaseFilter_Release(This->m_pFilter);\r
+            This->m_pFilter = NULL;\r
+        }\r
+        This->m_nPos = 0;\r
+        g_free((void*)This);\r
+        return 0;\r
+    }\r
+    return This->m_cRef;\r
+}\r
+\r
+static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins, IPin **ppPins,\r
+                                ULONG *pcFetched)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+\r
+    if (ppPins == NULL)\r
+            return E_POINTER;\r
+\r
+    ULONG fetched;\r
+    if (This->m_nPos < 1 && cPins > 0) {\r
+        IPin *pPin;\r
+        IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);\r
+        *ppPins = pPin;\r
+        IPin_AddRef(pPin);\r
+        fetched = 1;\r
+        This->m_nPos++;\r
+    } else {\r
+        fetched = 0;\r
+    }\r
+\r
+    if (pcFetched != NULL ) {\r
+        *pcFetched = fetched;\r
+    }\r
+\r
+    return ( fetched == cPins ) ? S_OK : S_FALSE;\r
+}\r
+\r
+static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+    This->m_nPos += cPins;\r
+    return ( This->m_nPos >= 1 ) ? S_FALSE : S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+    This->m_nPos = 0;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter, int nPos, IEnumPins **ppv);\r
+\r
+static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)\r
+{\r
+    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
+\r
+    if (ppEnum == NULL)\r
+        return E_POINTER;\r
+\r
+    HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);\r
+    if (*ppEnum == NULL) {\r
+        return E_OUTOFMEMORY;\r
+    }\r
+\r
+    return S_OK;\r
+}\r
+\r
+static IEnumPinsVtbl HWCEnumPins_Vtbl =\r
+{\r
+    HWCEnumPins_QueryInterface,\r
+    HWCEnumPins_AddRef,\r
+    HWCEnumPins_Release,\r
+    HWCEnumPins_Next,\r
+    HWCEnumPins_Skip,\r
+    HWCEnumPins_Reset,\r
+    HWCEnumPins_Clone\r
+};\r
+\r
+\r
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter, int nPos, IEnumPins **ppv)\r
+{\r
+    HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));\r
+\r
+    if (!This) {\r
+        return E_OUTOFMEMORY;\r
+    }\r
+\r
+    This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;\r
+    This->m_pFilter = pFilter;\r
+    if (This->m_pFilter) {\r
+        IBaseFilter_AddRef(This->m_pFilter);\r
+    }\r
+    This->m_cRef = 1;\r
+    This->m_nPos = nPos;\r
+    *ppv = &This->IEnumPins_iface;\r
+\r
+    return S_OK;\r
+}\r
+\r
+/*\r
+ * HWCFilter\r
+ */\r
+\r
+typedef struct HWCFilter\r
+{\r
+    IBaseFilter IBaseFilter_iface;\r
+    IPin *m_pPin;\r
+    IFilterGraph *m_pFilterGraph;\r
+    FILTER_STATE m_state;\r
+    long m_cRef;\r
+} HWCFilter;\r
+\r
+static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)\r
+{\r
+    return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)\r
+{\r
+    if(IsEqualIID(riid, &IID_IUnknown)) {\r
+        *ppv = (IUnknown*)iface;\r
+    } else if (IsEqualIID(riid, &IID_IPersist)) {\r
+        *ppv = (IPersist*)iface;\r
+    } else if (IsEqualIID(riid, &IID_IMediaFilter)) {\r
+        *ppv = (IMediaFilter*)iface;\r
+    } else if (IsEqualIID(riid, &IID_IBaseFilter)) {\r
+        *ppv = (IBaseFilter*)iface;\r
+    } else {\r
+        *ppv = NULL;\r
+        return E_NOINTERFACE;\r
+    }\r
+\r
+    IBaseFilter_AddRef(iface);\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    return InterlockedIncrement(&This->m_cRef);\r
+}\r
+\r
+static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    if( InterlockedDecrement(&This->m_cRef) == 0) {\r
+        if (This->m_pPin) {\r
+            IPin_Release(This->m_pPin);\r
+            This->m_pPin = NULL;\r
+        }\r
+        if (This->m_pFilterGraph) {\r
+            IFilterGraph_Release(This->m_pFilterGraph);\r
+            This->m_pFilterGraph = NULL;\r
+        }\r
+        g_free((void*)This);\r
+        return 0;\r
+    }\r
+    return This->m_cRef;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)\r
+{\r
+    if (pClsID == NULL)\r
+        return E_POINTER;\r
+    return E_NOTIMPL;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs, FILTER_STATE *State)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+    *State = This->m_state;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock)\r
+{\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **pClock)\r
+{\r
+    *pClock = NULL;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    IPin_EndFlush(This->m_pPin);\r
+    This->m_state = State_Stopped;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+    This->m_state = State_Paused;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    if (This->m_state == State_Stopped){\r
+        HRESULT hr;\r
+        hr = IBaseFilter_Pause(iface);\r
+        if (FAILED(hr)) {\r
+            return hr;\r
+        }\r
+    }\r
+\r
+    This->m_state = State_Running;\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)\r
+{\r
+    if (ppEnum == NULL)\r
+        return E_POINTER;\r
+\r
+    HWCEnumPins_Construct(iface, 0, ppEnum);\r
+    return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    if (ppPin == NULL)\r
+        return E_POINTER;\r
+\r
+    if (memcmp((void*)Id, (void*)HWCPinName, sizeof(HWCPinName))) {\r
+        return VFW_E_NOT_FOUND;\r
+    }\r
+\r
+    if (!This->m_pPin) {\r
+         HWCInPin_Construct(iface, &This->m_pPin);\r
+    }\r
+    *ppPin = This->m_pPin;\r
+\r
+    IPin_AddRef(This->m_pPin);\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    if (pInfo == NULL)\r
+        return E_POINTER;\r
+\r
+    memcpy((void*)pInfo->achName, (void*)HWCFilterName, sizeof(HWCFilterName));\r
+    pInfo->pGraph = This->m_pFilterGraph;\r
+    if(This->m_pFilterGraph) {\r
+        IFilterGraph_AddRef(This->m_pFilterGraph);\r
+    }\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph,\r
+                                        LPCWSTR pName)\r
+{\r
+    HWCFilter *This = impl_from_IBaseFilter(iface);\r
+\r
+    This->m_pFilterGraph = pGraph;\r
+    if (pGraph) {\r
+        IFilterGraph_AddRef(pGraph);\r
+    }\r
+    return S_OK;\r
+}\r
+\r
+static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR* pVendorInfo)\r
+{\r
+    return E_NOTIMPL;\r
+}\r
+\r
+static IBaseFilterVtbl HWCFilter_Vtbl =\r
+{\r
+    HWCFilter_QueryInterface,\r
+    HWCFilter_AddRef,\r
+    HWCFilter_Release,\r
+    HWCFilter_GetClassID,\r
+    HWCFilter_Stop,\r
+    HWCFilter_Pause,\r
+    HWCFilter_Run,\r
+    HWCFilter_GetState,\r
+    HWCFilter_SetSyncSource,\r
+    HWCFilter_GetSyncSource,\r
+    HWCFilter_EnumPins,\r
+    HWCFilter_FindPin,\r
+    HWCFilter_QueryFilterInfo,\r
+    HWCFilter_JoinFilterGraph,\r
+    HWCFilter_QueryVendorInfo\r
+};\r
+\r
+static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)\r
+{\r
+    HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));\r
+\r
+    if (!This) {\r
+        return E_OUTOFMEMORY;\r
+    }\r
+\r
+    This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;\r
+    This->m_pFilterGraph = NULL;\r
+    This->m_state = State_Stopped;\r
+    This->m_cRef = 1;\r
+    HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);\r
+    *ppv = &This->IBaseFilter_iface;\r
+\r
+    return S_OK;\r
+}\r
+\r
+/**********************************************************\r
+ *\r
+ * Virtual device implementations\r
+ *\r
+ **********************************************************/\r
+\r
+\r
+/*\r
+ * Declaration global variables for Win32 COM Interfaces\r
+ */\r
+IGraphBuilder *g_pGB ;\r
+ICaptureGraphBuilder2 *g_pCGB;\r
+IMediaControl *g_pMediaControl;\r
+\r
+IPin *g_pOutputPin;\r
+IPin *g_pInputPin;\r
+IBaseFilter *g_pDstFilter;\r
+IBaseFilter *g_pSrcFilter;\r
+\r
+IGrabCallback *g_pCallback;\r
+\r
+DWORD g_dwFourcc;\r
+LONG g_dwWidth;\r
+LONG g_dwHeight;\r
+REFERENCE_TIME g_dwAvgInterval;\r
+\r
+// V4L2 defines copy from videodev2.h\r
+#define V4L2_CTRL_FLAG_SLIDER       0x0020\r
+\r
+#define V4L2_CTRL_CLASS_USER        0x00980000\r
+#define V4L2_CID_BASE               (V4L2_CTRL_CLASS_USER | 0x900)\r
+#define V4L2_CID_BRIGHTNESS         (V4L2_CID_BASE+0)\r
+#define V4L2_CID_CONTRAST           (V4L2_CID_BASE+1)\r
+#define V4L2_CID_SATURATION         (V4L2_CID_BASE+2)\r
+#define V4L2_CID_SHARPNESS          (V4L2_CID_BASE+27)\r
+\r
+#define V4L2_PIX_FMT_YUYV    MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */\r
+#define V4L2_PIX_FMT_YUV420  MAKEFOURCC('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */\r
+#define V4L2_PIX_FMT_YVU420  MAKEFOURCC('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */\r
+\r
+typedef struct tagMaruCamConvertPixfmt {\r
+    uint32_t fmt;   /* fourcc */\r
+    uint32_t bpp;   /* bits per pixel, 0 for compressed formats */\r
+    uint32_t needs_conversion;\r
+} MaruCamConvertPixfmt;\r
+\r
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {\r
+        { V4L2_PIX_FMT_YUYV, 16, 0 },\r
+        { V4L2_PIX_FMT_YUV420, 12, 0 },\r
+        { V4L2_PIX_FMT_YVU420, 12, 0 },\r
+};\r
+\r
+typedef struct tagMaruCamConvertFrameInfo {\r
+    uint32_t width;\r
+    uint32_t height;\r
+} MaruCamConvertFrameInfo;\r
+\r
+static MaruCamConvertFrameInfo supported_dst_frames[] = {\r
+        { 640, 480 },\r
+        { 352, 288 },\r
+        { 320, 240 },\r
+        { 176, 144 },\r
+        { 160, 120 },\r
+};\r
+\r
+#define MARUCAM_CTRL_VALUE_MAX      20\r
+#define MARUCAM_CTRL_VALUE_MIN      1\r
+#define MARUCAM_CTRL_VALUE_MID      10\r
+#define MARUCAM_CTRL_VALUE_STEP     1\r
+\r
+struct marucam_qctrl {\r
+    uint32_t id;\r
+    uint32_t hit;\r
+    long min;\r
+    long max;\r
+    long step;\r
+    long init_val;\r
+};\r
+\r
+static struct marucam_qctrl qctrl_tbl[] = {\r
+    { V4L2_CID_BRIGHTNESS, 0, },\r
+    { V4L2_CID_CONTRAST, 0, },\r
+    { V4L2_CID_SATURATION,0, },\r
+    { V4L2_CID_SHARPNESS, 0, },\r
+};\r
+\r
+static MaruCamState *g_state = NULL;\r
+\r
+static uint32_t cur_fmt_idx = 0;\r
+static uint32_t cur_frame_idx = 0;\r
+\r
+\r
+/*\r
+ * Helper functions - converting image formats, converting values\r
+ */\r
+\r
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,\r
+        uint32_t width, uint32_t height, uint32_t yvu);\r
+\r
+\r
+static long value_convert_from_guest(long min, long max, long value)\r
+{\r
+    double rate = 0.0;\r
+    long dist = 0, ret = 0;\r
+\r
+    dist = max - min;\r
+\r
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
+        ret = min + (int32_t)(value / rate);\r
+    } else {\r
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
+        ret = min + (int32_t)(rate * value);\r
+    }\r
+    return ret;\r
+}\r
+\r
+static long value_convert_to_guest(long min, long max, long value)\r
+{\r
+    double rate  = 0.0;\r
+    long dist = 0, ret = 0;\r
+\r
+    dist = max - min;\r
+\r
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
+        ret = (int32_t)((double)(value - min) * rate);\r
+    } else {\r
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
+        ret = (int32_t)((double)(value - min) / rate);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ * Callback function for grab frames\r
+ */\r
+static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)\r
+{\r
+    static uint32_t index = 0;\r
+    uint32_t width, height;\r
+    width = supported_dst_frames[cur_frame_idx].width;\r
+    height = supported_dst_frames[cur_frame_idx].height;\r
+    void *buf = g_state->vaddr + (g_state->buf_size * index);\r
+\r
+    switch (supported_dst_pixfmts[cur_fmt_idx].fmt) {\r
+    case V4L2_PIX_FMT_YUV420:\r
+        v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 0);\r
+        break;\r
+    case V4L2_PIX_FMT_YVU420:\r
+        v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1);\r
+        break;\r
+    case V4L2_PIX_FMT_YUYV:\r
+        memcpy(buf, (void*)pBuffer, dwSize);\r
+        break;\r
+    }\r
+    index = !index;\r
+\r
+    if (g_state->req_frame) {\r
+               mloop_evcmd_raise_intr(g_state->dev.irq[2]);\r
+               g_state->req_frame = 0;\r
+    }\r
+    return S_OK;\r
+}\r
+\r
+/*\r
+ * Internal functions for manipulate interfaces\r
+ */\r
+\r
+static STDMETHODIMP_(void) CloseInterfaces(void)\r
+{\r
+    if (g_pMediaControl)\r
+        g_pMediaControl->lpVtbl->Stop(g_pMediaControl);\r
+\r
+    if (g_pOutputPin)\r
+        g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);\r
+\r
+    SAFE_RELEASE(g_pGB);\r
+    SAFE_RELEASE(g_pCGB);\r
+    SAFE_RELEASE(g_pMediaControl);\r
+    SAFE_RELEASE(g_pOutputPin);\r
+    SAFE_RELEASE(g_pInputPin);\r
+    SAFE_RELEASE(g_pDstFilter);\r
+    SAFE_RELEASE(g_pSrcFilter);\r
+    SAFE_RELEASE(g_pCallback);\r
+}\r
+\r
+static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)\r
+{\r
+    if (pmt == NULL) {\r
+        return;\r
+    }\r
+\r
+    if (pmt->cbFormat != 0) {\r
+        CoTaskMemFree((PVOID)pmt->pbFormat);\r
+        pmt->cbFormat = 0;\r
+        pmt->pbFormat = NULL;\r
+    }\r
+    if (pmt->pUnk != NULL) {\r
+        pmt->pUnk->lpVtbl->Release(pmt->pUnk);\r
+        pmt->pUnk = NULL;\r
+    }\r
+\r
+    CoTaskMemFree((PVOID)pmt);\r
+}\r
+\r
+static STDMETHODIMP GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)\r
+{\r
+    HRESULT hr;\r
+    IEnumPins *pEnum = NULL;\r
+    IPin *pPin = NULL;\r
+\r
+    if (ppPin == NULL)\r
+    {\r
+        return E_POINTER;\r
+    }\r
+\r
+    hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    while(pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK)\r
+    {\r
+        PIN_DIRECTION PinDirThis;\r
+        hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);\r
+        if (FAILED(hr))\r
+        {\r
+            SAFE_RELEASE(pPin);\r
+            SAFE_RELEASE(pEnum);\r
+            return hr;\r
+        }\r
+        if (PinDir == PinDirThis)\r
+        {\r
+            *ppPin = pPin;\r
+            SAFE_RELEASE(pEnum);\r
+            return S_OK;\r
+        }\r
+        SAFE_RELEASE(pPin);\r
+    }\r
+\r
+    SAFE_RELEASE(pEnum);\r
+    return S_FALSE;\r
+}\r
+\r
+static STDMETHODIMP GraphBuilder_Init(void)\r
+{\r
+    HRESULT hr;\r
+\r
+    hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC, &IID_IGraphBuilder, (void**)&g_pGB);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, &IID_ICaptureGraphBuilder2, (void**)&g_pCGB);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl, (void **)&g_pMediaControl);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = HWCGrabCallback_Construct(&g_pCallback);\r
+    if (g_pCallback == NULL)\r
+        hr = E_OUTOFMEMORY;\r
+\r
+    hr = ((HWCGrabCallback*)g_pCallback)->SetCallback(g_pCallback, (CallbackFn)marucam_device_callbackfn);\r
+\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP BindSourceFilter(void)\r
+{\r
+    HRESULT hr;\r
+    ICreateDevEnum *pCreateDevEnum = NULL;\r
+    IEnumMoniker *pEnumMK = NULL;\r
+    IMoniker *pMoniKer;\r
+\r
+    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void**)&pCreateDevEnum);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum, &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);\r
+    if (FAILED(hr))\r
+    {\r
+        pCreateDevEnum->lpVtbl->Release(pCreateDevEnum);\r
+        return hr;\r
+    }\r
+\r
+    if (!pEnumMK)\r
+    {\r
+        pCreateDevEnum->lpVtbl->Release(pCreateDevEnum);\r
+        return E_FAIL;\r
+    }\r
+    pEnumMK->lpVtbl->Reset(pEnumMK);\r
+\r
+    hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);\r
+    if (hr == S_FALSE)\r
+    {\r
+        hr = E_FAIL;\r
+    }\r
+    if (SUCCEEDED(hr))\r
+    {\r
+        IPropertyBag *pBag = NULL;\r
+        hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0, &IID_IPropertyBag, (void **)&pBag);\r
+        if(SUCCEEDED(hr))\r
+        {\r
+            VARIANT var;\r
+            var.vt = VT_BSTR;\r
+            hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);\r
+            if (hr == NOERROR)\r
+            {\r
+                hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL, &IID_IBaseFilter, (void**)&g_pSrcFilter);\r
+                if (FAILED(hr))\r
+                {\r
+                    ERR("Counldn't bind moniker to filter object!!\n");\r
+                }\r
+                else\r
+                {\r
+                    g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);\r
+                }\r
+                SysFreeString(var.bstrVal);\r
+            }\r
+            pBag->lpVtbl->Release(pBag);\r
+        }\r
+        pMoniKer->lpVtbl->Release(pMoniKer);\r
+    }\r
+\r
+    if (SUCCEEDED(hr))\r
+    {\r
+        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");\r
+        if (hr != S_OK && hr != S_FALSE)\r
+        {\r
+            ERR("Counldn't add Video Capture filter to our graph!\n");\r
+        }\r
+    }\r
+\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP BindTargetFilter(void)\r
+{\r
+    HRESULT hr;\r
+    hr = HWCFilter_Construct(&g_pDstFilter);\r
+\r
+    if (SUCCEEDED(hr) && g_pDstFilter)\r
+    {\r
+        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");\r
+        if (FAILED(hr))\r
+        {\r
+            ERR("Counldn't add HWCFilterr to our graph!\n");\r
+        }\r
+    }\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP ConnectFilters(void)\r
+{\r
+    HRESULT hr;\r
+\r
+    hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP SetDefaultValues(void)\r
+{\r
+    HRESULT hr;\r
+    IAMStreamConfig *pSConfig;\r
+    int iCount = 0, iSize = 0;\r
+\r
+    hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0, g_pSrcFilter, &IID_IAMStreamConfig, (void**)&pSConfig);\r
+    if (FAILED(hr)) {\r
+        ERR("failed to FindInterface method\n");\r
+        return hr;\r
+    }\r
+\r
+    hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);\r
+    if (FAILED(hr))\r
+    {\r
+        ERR("failed to GetNumberOfCapabilities method\n");\r
+        pSConfig->lpVtbl->Release(pSConfig);\r
+        return hr;\r
+    }\r
+\r
+    if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))\r
+    {\r
+        int iFormat = 0;\r
+        for (iFormat = 0; iFormat < iCount; iFormat++)\r
+        {\r
+            VIDEO_STREAM_CONFIG_CAPS scc;\r
+            AM_MEDIA_TYPE *pmtConfig;\r
+\r
+            hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig, (BYTE*)&scc);\r
+            if (hr == S_OK)\r
+            {\r
+                if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo))\r
+                {\r
+                    VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pmtConfig->pbFormat;\r
+                    if ((pvi->bmiHeader.biWidth == g_dwWidth) &&\r
+                        (pvi->bmiHeader.biHeight == g_dwHeight) &&\r
+                        (pvi->bmiHeader.biCompression == g_dwFourcc))\r
+                    {\r
+                        pvi->AvgTimePerFrame = g_dwAvgInterval;\r
+                        hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);\r
+                        DeleteMediaType(pmtConfig);\r
+                        INFO("Setting default values.\n");\r
+                        break;\r
+                    }\r
+                }\r
+                DeleteMediaType(pmtConfig);\r
+            }\r
+        }\r
+    }\r
+    pSConfig->lpVtbl->Release(pSConfig);\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP SetResolution(LONG width, LONG height)\r
+{\r
+    HRESULT hr;\r
+    IAMStreamConfig* vsc = NULL;\r
+    AM_MEDIA_TYPE* pmt = NULL;\r
+\r
+    hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, g_pSrcFilter, &IID_IAMStreamConfig, (void**)&vsc);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = vsc->lpVtbl->GetFormat(vsc, &pmt);\r
+    if (FAILED(hr))\r
+    {\r
+        vsc->lpVtbl->Release(vsc);\r
+        return hr;\r
+    }\r
+\r
+    if (pmt != NULL)\r
+    {\r
+        if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))\r
+        {\r
+            VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pmt->pbFormat;\r
+            pvi->bmiHeader.biWidth = width;\r
+            pvi->bmiHeader.biHeight = height;\r
+            pvi->AvgTimePerFrame = g_dwAvgInterval;\r
+            pvi->bmiHeader.biSizeImage = ((width * pvi->bmiHeader.biBitCount) >> 3 ) * height;\r
+            hr = vsc->lpVtbl->SetFormat(vsc, pmt);\r
+        }\r
+        DeleteMediaType(pmt);\r
+    }\r
+    vsc->lpVtbl->Release(vsc);\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax, long *pStep, long *pDefault)\r
+{\r
+    HRESULT hr;\r
+    long Flags;\r
+    IAMVideoProcAmp *pProcAmp = NULL;\r
+\r
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);\r
+    if (FAILED(hr)) {\r
+        return hr;\r
+    }\r
+\r
+    hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax, pStep, pDefault, &Flags);\r
+\r
+    SAFE_RELEASE(pProcAmp);\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)\r
+{\r
+    HRESULT hr;\r
+    long Flags;\r
+    IAMVideoProcAmp *pProcAmp = NULL;\r
+\r
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to get property for video\n");\r
+    }\r
+\r
+    SAFE_RELEASE(pProcAmp);\r
+    return hr;\r
+}\r
+\r
+static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)\r
+{\r
+    HRESULT hr;\r
+\r
+    IAMVideoProcAmp *pProcAmp = NULL;\r
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);\r
+    if (FAILED(hr))\r
+        return hr;\r
+\r
+    hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value, VideoProcAmp_Flags_Manual);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to set property for video\n");\r
+    }\r
+    SAFE_RELEASE(pProcAmp);\r
+    return hr;\r
+}\r
+\r
+// MARUCAM_CMD_INIT\r
+void marucam_device_init(MaruCamState* state)\r
+{\r
+    g_state = state;\r
+}\r
+\r
+// MARUCAM_CMD_OPEN\r
+void marucam_device_open(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    MaruCamParam *param = state->param;\r
+    param->top = 0;\r
+\r
+    hr = GraphBuilder_Init();\r
+    if (FAILED(hr)) {\r
+        ERR("GraphBuilder_Init\n");\r
+        goto error_failed;\r
+    }\r
+\r
+    hr = BindSourceFilter();\r
+    if (FAILED(hr)) {\r
+        ERR("BindSourceFilter\n");\r
+        goto error_failed;\r
+    }\r
+\r
+    hr = BindTargetFilter();\r
+    if (FAILED(hr)) {\r
+        ERR("BindTargetFilter\n");\r
+        goto error_failed;\r
+    }\r
+\r
+    hr = ConnectFilters();\r
+    if (FAILED(hr)) {\r
+        ERR("ConnectFilters\n");\r
+        goto error_failed;\r
+    }\r
+\r
+    g_dwAvgInterval = 666666;\r
+    g_dwFourcc = MAKEFOURCC('Y','U','Y','2');\r
+    g_dwHeight = 480;\r
+    g_dwWidth = 640;\r
+    hr = SetDefaultValues();\r
+    if (hr != S_OK) {\r
+        ERR("SetDefaultValues\n");\r
+        goto error_failed;\r
+    }\r
+\r
+    INFO("Open successfully!!!\n");\r
+    return;\r
+\r
+error_failed:\r
+    CloseInterfaces();\r
+    param->errCode = EINVAL;\r
+    ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
+}\r
+\r
+// MARUCAM_CMD_CLOSE\r
+void marucam_device_close(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+    param->top = 0;\r
+\r
+    CloseInterfaces();\r
+    INFO("Close successfully!!!\n");\r
+}\r
+\r
+// MARUCAM_CMD_START_PREVIEW\r
+void marucam_device_start_preview(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    uint32_t width, height;\r
+    MaruCamParam *param = state->param;\r
+    param->top = 0;\r
+\r
+    assert(g_pCallback != NULL);\r
+    hr = ((HWCInPin*)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, g_pCallback);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to set IGrabCallback interface.\n");\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to run media control.\n");\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->streamon = 1;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+\r
+    width = supported_dst_frames[cur_frame_idx].width;\r
+    height = supported_dst_frames[cur_frame_idx].height;\r
+    state->buf_size = height * ((width * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3);\r
+\r
+    INFO("Start preview!!!\n");\r
+}\r
+\r
+// MARUCAM_CMD_STOP_PREVIEW\r
+void marucam_device_stop_preview(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    MaruCamParam *param = state->param;\r
+    param->top = 0;\r
+\r
+    hr = ((HWCInPin*)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to set IGrabCallback interface.\n");\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);\r
+    if (FAILED(hr)) {\r
+        ERR("Failed to stop media control.\n");\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->streamon = 0;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+    state->buf_size = 0;\r
+\r
+    INFO("Stop preview!!!\n");\r
+}\r
+\r
+// MARUCAM_CMD_S_PARAM\r
+void marucam_device_s_param(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+}\r
+\r
+// MARUCAM_CMD_G_PARAM\r
+void marucam_device_g_param(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+\r
+    param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME\r
+    param->stack[1] = 1; // numerator;\r
+    param->stack[2] = 30; // denominator;\r
+}\r
+\r
+// MARUCAM_CMD_S_FMT\r
+void marucam_device_s_fmt(MaruCamState* state)\r
+{\r
+    uint32_t width, height, pixfmt, pidx, fidx;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    width = param->stack[0];        // width\r
+    height = param->stack[1];       // height\r
+    pixfmt = param->stack[2];       // pixelformat\r
+\r
+    for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {\r
+        if ((supported_dst_frames[fidx].width == width) &&\r
+                (supported_dst_frames[fidx].height == height)) {\r
+            break;\r
+        }\r
+    }\r
+    if (fidx == ARRAY_SIZE(supported_dst_frames)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {\r
+        if (supported_dst_pixfmts[pidx].fmt == pixfmt) {\r
+            break;\r
+        }\r
+    }\r
+    if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    if ((supported_dst_frames[cur_frame_idx].width != width) &&\r
+            (supported_dst_frames[cur_frame_idx].height != height)) {\r
+        HRESULT hr = SetResolution((LONG)width, (LONG)height);\r
+        if (FAILED(hr)) {\r
+            param->errCode = EINVAL;\r
+            return;\r
+        }\r
+        g_dwWidth = (LONG)width;\r
+        g_dwHeight = (LONG)height;\r
+    }\r
+\r
+    param->stack[0] = width;\r
+    param->stack[1] = height;\r
+    param->stack[2] = 1; // V4L2_FIELD_NONE\r
+    param->stack[3] = pixfmt;\r
+    // bytes per line = (width * bpp) / 8\r
+    param->stack[4] = (width * supported_dst_pixfmts[pidx].bpp) >> 3;\r
+    param->stack[5] = param->stack[4] * height; // height * bytesperline\r
+    param->stack[6] = 0;\r
+    param->stack[7] = 0;\r
+\r
+    cur_frame_idx = fidx;\r
+    cur_fmt_idx = pidx;\r
+\r
+    TRACE("Set format...\n");\r
+}\r
+\r
+// MARUCAM_CMD_G_FMT\r
+void marucam_device_g_fmt(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+\r
+    param->stack[0] = supported_dst_frames[cur_frame_idx].width;    // width\r
+    param->stack[1] = supported_dst_frames[cur_frame_idx].height;   // height\r
+    param->stack[2] = 1; // V4L2_FIELD_NONE\r
+    param->stack[3] = supported_dst_pixfmts[cur_fmt_idx].fmt;   // pixelformat\r
+    // bytes per line = (width * bpp) / 8\r
+    param->stack[4] = (param->stack[0] * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3;\r
+    param->stack[5] = param->stack[1] * param->stack[4];    // height * bytesperline\r
+    param->stack[6] = 0;\r
+    param->stack[7] = 0;\r
+\r
+    TRACE("Get format...\n");\r
+}\r
+\r
+void marucam_device_try_fmt(MaruCamState* state)\r
+{\r
+    uint32_t width, height, pixfmt, i;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    width = param->stack[0];        // width\r
+    height = param->stack[1];       // height\r
+    pixfmt = param->stack[2];       // pixelformat\r
+\r
+    for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {\r
+        if ((supported_dst_frames[i].width == width) &&\r
+                (supported_dst_frames[i].height == height)) {\r
+            break;\r
+        }\r
+    }\r
+    if (i == ARRAY_SIZE(supported_dst_frames)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
+        if (supported_dst_pixfmts[i].fmt == pixfmt) {\r
+            break;\r
+        }\r
+    }\r
+    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    param->stack[0] = width;\r
+    param->stack[1] = height;\r
+    param->stack[2] = 1; // V4L2_FIELD_NONE\r
+    param->stack[3] = pixfmt;\r
+    // bytes per line = (width * bpp) / 8\r
+    param->stack[4] = (width * supported_dst_pixfmts[i].bpp) >> 3;\r
+    param->stack[5] = param->stack[4] * height; // height * bytesperline\r
+    param->stack[6] = 0;\r
+    param->stack[7] = 0;\r
+}\r
+\r
+void marucam_device_enum_fmt(MaruCamState* state)\r
+{\r
+    uint32_t index;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    index = param->stack[0];\r
+\r
+    if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    param->stack[1] = 0;                            // flags = NONE;\r
+    param->stack[2] = supported_dst_pixfmts[index].fmt; // pixelformat;\r
+    /* set description */\r
+    switch (supported_dst_pixfmts[index].fmt) {\r
+    case V4L2_PIX_FMT_YUYV:\r
+        memcpy(&param->stack[3], "YUY2", 32);\r
+        break;\r
+    case V4L2_PIX_FMT_YUV420:\r
+        memcpy(&param->stack[3], "YU12", 32);\r
+        break;\r
+    case V4L2_PIX_FMT_YVU420:\r
+        memcpy(&param->stack[3], "YV12", 32);\r
+        break;\r
+    }\r
+}\r
+\r
+void marucam_device_qctrl(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    uint32_t id, i;\r
+    long property, min, max, step, def_val, set_val;\r
+    char name[32] = {0,};\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    id = param->stack[0];\r
+\r
+    switch (id) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        TRACE("V4L2_CID_BRIGHTNESS\n");\r
+        property = VideoProcAmp_Brightness;\r
+        memcpy((void*)name, (void*)"brightness", 32);\r
+        i = 0;\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        TRACE("V4L2_CID_CONTRAST\n");\r
+        property = VideoProcAmp_Contrast;\r
+        memcpy((void*)name, (void*)"contrast", 32);\r
+        i = 1;\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        TRACE("V4L2_CID_SATURATION\n");\r
+        property = VideoProcAmp_Saturation;\r
+        memcpy((void*)name, (void*)"saturation", 32);\r
+        i = 2;\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        TRACE("V4L2_CID_SHARPNESS\n");\r
+        property = VideoProcAmp_Sharpness;\r
+        memcpy((void*)name, (void*)"sharpness", 32);\r
+        i = 3;\r
+        break;\r
+    default:\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);\r
+    if (FAILED(hr)) {\r
+        param->errCode = EINVAL;\r
+        ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);\r
+        return;\r
+    } else {\r
+        qctrl_tbl[i].hit = 1;\r
+        qctrl_tbl[i].min = min;\r
+        qctrl_tbl[i].max = max;\r
+        qctrl_tbl[i].step = step;\r
+        qctrl_tbl[i].init_val = def_val;\r
+\r
+        if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {\r
+            set_val = 0;\r
+        } else {\r
+            set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;\r
+        }\r
+        hr = SetVideoProcAmp(property, set_val);\r
+        if (FAILED(hr)) {\r
+            param->errCode = EINVAL;\r
+            ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);\r
+            return;\r
+        }\r
+    }\r
+\r
+    param->stack[0] = id;\r
+    param->stack[1] = MARUCAM_CTRL_VALUE_MIN;   // minimum\r
+    param->stack[2] = MARUCAM_CTRL_VALUE_MAX;   // maximum\r
+    param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step\r
+    param->stack[4] = MARUCAM_CTRL_VALUE_MID;   // default_value\r
+    param->stack[5] = V4L2_CTRL_FLAG_SLIDER;\r
+    /* name field setting */\r
+    memcpy(&param->stack[6], (void*)name, sizeof(name)/sizeof(name[0]));\r
+}\r
+\r
+void marucam_device_s_ctrl(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    uint32_t i;\r
+    long property, set_val;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+\r
+    switch (param->stack[0]) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        i = 0;\r
+        property = VideoProcAmp_Brightness;\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        i = 1;\r
+        property = VideoProcAmp_Contrast;\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        i = 2;\r
+        property = VideoProcAmp_Saturation;\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        i = 3;\r
+        property = VideoProcAmp_Sharpness;\r
+        break;\r
+    default:\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    set_val = value_convert_from_guest(qctrl_tbl[i].min,\r
+            qctrl_tbl[i].max, (long)param->stack[1]);\r
+    hr = SetVideoProcAmp(property, set_val);\r
+    if (FAILED(hr)) {\r
+        param->errCode = EINVAL;\r
+        ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);\r
+        return;\r
+    }\r
+}\r
+\r
+void marucam_device_g_ctrl(MaruCamState* state)\r
+{\r
+    HRESULT hr;\r
+    uint32_t i;\r
+    long property, get_val;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    switch (param->stack[0]) {\r
+    case V4L2_CID_BRIGHTNESS:\r
+        i = 0;\r
+        property = VideoProcAmp_Brightness;\r
+        break;\r
+    case V4L2_CID_CONTRAST:\r
+        i = 1;\r
+        property = VideoProcAmp_Contrast;\r
+        break;\r
+    case V4L2_CID_SATURATION:\r
+        i = 2;\r
+        property = VideoProcAmp_Saturation;\r
+        break;\r
+    case V4L2_CID_SHARPNESS:\r
+        i = 3;\r
+        property = VideoProcAmp_Sharpness;\r
+        break;\r
+    default:\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    hr = GetVideoProcAmp(property, &get_val);\r
+    if (FAILED(hr)) {\r
+        param->errCode = EINVAL;\r
+        ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);\r
+        return;\r
+    }\r
+    param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,\r
+                qctrl_tbl[i].max, get_val);\r
+}\r
+\r
+void marucam_device_enum_fsizes(MaruCamState* state)\r
+{\r
+    uint32_t index, pixfmt, i;\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+    index = param->stack[0];\r
+    pixfmt = param->stack[1];\r
+\r
+    if (index >= ARRAY_SIZE(supported_dst_frames)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
+        if (supported_dst_pixfmts[i].fmt == pixfmt)\r
+            break;\r
+    }\r
+\r
+    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+\r
+    param->stack[0] = supported_dst_frames[index].width;\r
+    param->stack[1] = supported_dst_frames[index].height;\r
+}\r
+\r
+void marucam_device_enum_fintv(MaruCamState* state)\r
+{\r
+    MaruCamParam *param = state->param;\r
+\r
+    param->top = 0;\r
+\r
+    // switch by index(param->stack[0])\r
+    switch (param->stack[0]) {\r
+    case 0:\r
+        param->stack[1] = 30;   // denominator\r
+        break;\r
+    default:\r
+        param->errCode = EINVAL;\r
+        return;\r
+    }\r
+    param->stack[0] = 1;    // numerator\r
+}\r
+\r
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,\r
+        uint32_t width, uint32_t height, uint32_t yvu)\r
+{\r
+    uint32_t i, j;\r
+    const unsigned char *src1;\r
+    unsigned char *udest, *vdest;\r
+\r
+    /* copy the Y values */\r
+    src1 = src;\r
+    for (i = 0; i < height; i++) {\r
+        for (j = 0; j < width; j += 2) {\r
+            *dest++ = src1[0];\r
+            *dest++ = src1[2];\r
+            src1 += 4;\r
+        }\r
+    }\r
+\r
+    /* copy the U and V values */\r
+    src++;              /* point to V */\r
+    src1 = src + width * 2;     /* next line */\r
+    if (yvu) {\r
+        vdest = dest;\r
+        udest = dest + width * height / 4;\r
+    } else {\r
+        udest = dest;\r
+        vdest = dest + width * height / 4;\r
+    }\r
+    for (i = 0; i < height; i += 2) {\r
+        for (j = 0; j < width; j += 2) {\r
+            *udest++ = ((int) src[0] + src1[0]) / 2;    /* U */\r
+            *vdest++ = ((int) src[2] + src1[2]) / 2;    /* V */\r
+            src += 4;\r
+            src1 += 4;\r
+        }\r
+        src = src1;\r
+        src1 += width * 2;\r
+    }\r
+}\r
index b15815f3f23b1d254d5e30168b47aa5aaab3e470..0ded96d7d34d36a3b4471170d7ee7ed8bdc322d6 100644 (file)
  */
 
 #include "maru_codec.h"
+#include <pthread.h>
 
-#define QEMU_DEV_NAME           "codec"
-#define SVCODEC_MEM_SIZE        (8 * 1024 * 1024)
-#define SVCODEC_REG_SIZE        (256)
+#define QEMU_DEV_NAME   "codec"
+
+/*  Needs 16M to support 1920x1080 video resolution.
+ *  Output size for encoding has to be greater than (width * height * 6)
+ */
+#define MARU_CODEC_MMAP_MEM_SIZE    (16 * 1024 * 1024)
+#define MARU_CODEC_MMAP_COUNT       (4)
+#define MARU_CODEC_MEM_SIZE     (MARU_CODEC_MMAP_COUNT * MARU_CODEC_MMAP_MEM_SIZE)
+#define MARU_CODEC_REG_SIZE     (256)
+
+#define MARU_ROUND_UP_16(num)   (((num) + 15) & ~15)
 
 /* define debug channel */
-MULTI_DEBUG_CHANNEL(qemu, svcodec);
+MULTI_DEBUG_CHANNEL(qemu, marucodec);
 
-static AVCodecContext *gAVCtx = NULL;
-static AVFrame *gFrame = NULL;
-static AVCodecParserContext *gAVParserCtx = NULL;
-static uint8_t* gParserOutBuf = NULL;
-static bool bParser; 
 static int paramCount = 0;
+static int ctxArrIndex = 0;
 
-void qemu_parser_init (void)
+static void qemu_parser_init (SVCodecState *s, int ctxIndex)
 {
-    gParserOutBuf = NULL;
-    bParser = false;
+    TRACE("[%s] Enter\n", __func__);
+
+    s->ctxArr[ctxIndex].pParserBuffer = NULL;
+    s->ctxArr[ctxIndex].bParser = false;
+
+    TRACE("[%s] Leave\n", __func__);
+}
+
+static void qemu_codec_close (SVCodecState *s, uint32_t value)
+{
+    int i;
+    int ctxIndex = 0;
+
+    TRACE("[%s] Enter\n", __func__);
+
+    pthread_mutex_lock(&s->codec_mutex);
+
+    for (i = 0; i < CODEC_MAX_CONTEXT; i++) {
+        if (s->ctxArr[i].nFileValue == value) {
+            ctxIndex = i;
+            break;
+        }
+    }
+
+    TRACE("[%s] Close %d context\n", __func__, ctxIndex);
+
+    s->ctxArr[ctxIndex].bUsed = false;
+       qemu_parser_init(s, ctxIndex);
+
+    pthread_mutex_unlock(&s->codec_mutex);
+
+    TRACE("[%s] Leave\n", __func__);
 }
 
-void qemu_restore_context (AVCodecContext *dst, AVCodecContext *src) {
+static void qemu_restore_context (AVCodecContext *dst, AVCodecContext *src) {
+    TRACE("[%s] Enter\n", __func__);
+
     dst->av_class = src->av_class;
     dst->extradata = src->extradata;
     dst->codec = src->codec;
@@ -71,16 +108,19 @@ void qemu_restore_context (AVCodecContext *dst, AVCodecContext *src) {
     dst->execute = src->execute;
     dst->thread_opaque = src->thread_opaque;
     dst->execute2 = src->execute2;
+
+    TRACE("[%s] Leave\n", __func__);
 }
 
 /* void av_register_all() */
-void qemu_av_register_all (void)
+static void qemu_av_register_all (void)
 {
     av_register_all();
+    TRACE("av_register_all\n");
 }
 
 /* int avcodec_default_get_buffer (AVCodecContext *s, AVFrame *pic) */
-int qemu_avcodec_get_buffer (AVCodecContext *context, AVFrame *picture)
+static int qemu_avcodec_get_buffer (AVCodecContext *context, AVFrame *picture)
 {
     int ret;
     TRACE("avcodec_default_get_buffer\n");
@@ -94,26 +134,26 @@ int qemu_avcodec_get_buffer (AVCodecContext *context, AVFrame *picture)
 }
 
 /* void avcodec_default_release_buffer (AVCodecContext *ctx, AVFrame *frame) */
-void qemu_avcodec_release_buffer (AVCodecContext *context, AVFrame *picture)
+static void qemu_avcodec_release_buffer (AVCodecContext *context, AVFrame *picture)
 {
     TRACE("avcodec_default_release_buffer\n");
     avcodec_default_release_buffer(context, picture);
 }
 
 /* int avcodec_open (AVCodecContext *avctx, AVCodec *codec) */
 #ifdef CODEC_HOST
-int qemu_avcodec_open (SVCodecState *s)
+static int qemu_avcodec_open (SVCodecState *s, int ctxIndex)
 {
     AVCodecContext *avctx;
     AVCodecContext tmpCtx;
     AVCodec *codec;
     AVCodec tmpCodec;
     enum CodecID codec_id;
-    int ret, size;
+    int ret;
 
-    if (!gAVCtx) {
-        ERR("AVCodecContext is NULL!!\n");
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!avctx) {
+        ERR("[%s][%d] AVCodecContext is NULL!!\n", __func__, __LINE__);
         return -1;
     }
     avctx = gAVCtx;
@@ -140,7 +180,7 @@ int qemu_avcodec_open (SVCodecState *s)
         avctx->extradata = NULL;
     }
 
-    TRACE("[%s][%d] CODEC ID : %d\n", __func__, __LINE__, codec_id);    
+    TRACE("[%s][%d] CODEC ID : %x\n", __func__, __LINE__, codec_id);
     if (tmpCodec.encode) {
         codec = avcodec_find_encoder(codec_id);
     } else {
@@ -162,72 +202,161 @@ int qemu_avcodec_open (SVCodecState *s)
     return ret;
 }
 #else
-int qemu_avcodec_open (SVCodecState *s)
+static int qemu_avcodec_open (SVCodecState *s, int ctxIndex)
 {
     AVCodecContext *avctx;
     AVCodecContext tempCtx;
     AVCodec *codec;
     AVCodec tmpCodec;
     enum CodecID codec_id;
+    off_t offset;
     int ret;
-    int size;
+    int size = 0;
+
+    pthread_mutex_lock(&s->codec_mutex);
 
-    if (!gAVCtx) {
-        ERR("AVCodecContext is NULL!!\n");
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!avctx) {
+        ERR("[%s][%d] AVCodecContext is NULL!!\n", __func__, __LINE__);
         return -1;
     }
 
-    avctx = gAVCtx;
-    size = sizeof(AVCodecContext);
-    memcpy(&tempCtx, avctx, size);
+    offset = s->codecParam.mmapOffset;
 
-    memcpy(avctx, s->vaddr, size);
-    memcpy(&tmpCodec, (uint8_t*)s->vaddr + size, sizeof(AVCodec));
+    TRACE("[%s] Context Index:%d, offset:%d\n", __func__, ctxIndex, offset);
 
-    /* restore AVCodecContext's pointer variables */
+#ifndef CODEC_DUMMY
+    size = sizeof(AVCodecContext);
+    memcpy(&tempCtx, avctx, size);
+    memcpy(avctx, (uint8_t*)s->vaddr + offset, size);
+    memcpy(&tmpCodec, (uint8_t*)s->vaddr + offset + size, sizeof(AVCodec));
+    size += sizeof(AVCodec);
     qemu_restore_context(avctx, &tempCtx);
+#else
+    memcpy(&avctx->bit_rate, (uint8_t*)s->vaddr, sizeof(int));
+    size = sizeof(int);
+    memcpy(&avctx->bit_rate_tolerance, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->flags, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->time_base, (uint8_t*)s->vaddr + size, sizeof(AVRational));
+    size += sizeof(AVRational);
+    memcpy(&avctx->width, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->height, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->gop_size, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->pix_fmt, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->sample_rate, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->channels, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->codec_tag, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->rc_strategy, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->strict_std_compliance, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->rc_qsquish, (uint8_t*)s->vaddr + size, sizeof(float));
+    size += sizeof(float);
+    memcpy(&avctx->sample_aspect_ratio, (uint8_t*)s->vaddr + size, sizeof(AVRational));
+    size += sizeof(AVRational);
+    memcpy(&avctx->mb_qmin, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->mb_qmax, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->pre_me, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->trellis, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&avctx->extradata_size, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&tmpCodec.id, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+    memcpy(&tmpCodec.encode, (uint8_t*)s->vaddr + size, sizeof(int));
+    size += sizeof(int);
+#endif
 
     codec_id = tmpCodec.id;
-    size += sizeof(AVCodec);
-
+    TRACE("[%s] codec type:%d codec id : %x\n", __func__, tmpCodec.type, codec_id);
     if (avctx->extradata_size > 0) {
         avctx->extradata = (uint8_t*)av_malloc(avctx->extradata_size);
-        memcpy(avctx->extradata, (uint8_t*)s->vaddr + size, avctx->extradata_size);
+        memcpy(avctx->extradata, (uint8_t*)s->vaddr + offset + size, avctx->extradata_size);
     } else {
-        avctx->extradata = NULL;
+        TRACE("[%s] allocate dummy extradata\n", __func__);
+        avctx->extradata = av_mallocz (MARU_ROUND_UP_16(FF_INPUT_BUFFER_PADDING_SIZE));
     }
 
     if (tmpCodec.encode) {
+           TRACE("[%s] find encoder, codec_id:%x\n", __func__, codec_id);
         codec = avcodec_find_encoder(codec_id);
     } else {
+           TRACE("[%s] find decoder, codec_id:%x\n", __func__, codec_id);
         codec = avcodec_find_decoder(codec_id);
     }
-
     avctx->get_buffer = qemu_avcodec_get_buffer;
     avctx->release_buffer = qemu_avcodec_release_buffer;
-    
+
     ret = avcodec_open(avctx, codec);
     if (ret != 0) {
-        ERR("Failed to open codec, %d\n", ret);
+        ERR("[%s] Failure avcodec_open, %d\n", __func__, ret);
     }
 
-    memcpy(s->vaddr, avctx, sizeof(AVCodecContext));
-    memcpy((uint8_t*)s->vaddr + sizeof(AVCodecContext), &ret, sizeof(int));
+    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+        TRACE("[%s] sample_rate:%d, channels:%d\n", __func__,
+                         avctx->sample_rate, avctx->channels);
+    }
 
+#ifndef CODEC_DUMMY
+    memcpy((uint8_t*)s->vaddr + offset, avctx, sizeof(AVCodecContext));
+    memcpy((uint8_t*)s->vaddr + offset + sizeof(AVCodecContext), &ret, sizeof(int));
+#else
+    memcpy((uint8_t*)s->vaddr, &avctx->pix_fmt, sizeof(int));
+    size = sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->time_base, sizeof(AVRational));
+    size += sizeof(AVRational);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->sample_fmt, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->codec_type, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->codec_id, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->coded_width, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->coded_height, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->ticks_per_frame, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->chroma_sample_location, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, avctx->priv_data, codec->priv_data_size);
+    size += codec->priv_data_size;
+    memcpy((uint8_t*)s->vaddr + size, &ret, sizeof(int));
+#endif
+
+    pthread_mutex_unlock(&s->codec_mutex);
     return ret;
 }
 #endif
 
 /* int avcodec_close (AVCodecContext *avctx) */
-int qemu_avcodec_close (SVCodecState* s)
+static int qemu_avcodec_close (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext *avctx;
+    off_t offset;
     int ret = -1;
-    
-    avctx = gAVCtx;
+
+    TRACE("Enter\n");
+    pthread_mutex_lock(&s->codec_mutex);
+
+    offset = s->codecParam.mmapOffset;
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
     if (!avctx) {
         ERR("[%s][%d] AVCodecContext is NULL\n", __func__, __LINE__);
-        memcpy(s->vaddr, &ret, sizeof(int));
+        memcpy((uint8_t*)s->vaddr + offset, &ret, sizeof(int));
         return ret;
     }
 
@@ -235,76 +364,145 @@ int qemu_avcodec_close (SVCodecState* s)
     TRACE("after avcodec_close. ret:%d\n", ret);
 
 #ifndef CODEC_HOST
-    memcpy(s->vaddr, &ret, sizeof(int));
+    memcpy((uint8_t*)s->vaddr + offset, &ret, sizeof(int));
 #endif
 
-//  qemu_parser_init();
-
+    pthread_mutex_unlock(&s->codec_mutex);
+    TRACE("[%s] Leave\n", __func__);
     return ret;
 }
 
 /* AVCodecContext* avcodec_alloc_context (void) */
-void qemu_avcodec_alloc_context (void)
+static void qemu_avcodec_alloc_context (SVCodecState* s)
 {
-    gAVCtx = avcodec_alloc_context();
-    qemu_parser_init();
+    off_t offset;
+    int index;
+
+    TRACE("[%s] Enter\n", __func__);
+    pthread_mutex_lock(&s->codec_mutex);
+
+    offset = s->codecParam.mmapOffset;
+
+    for (index = 0; index < CODEC_MAX_CONTEXT; index++) {
+        if (s->ctxArr[index].bUsed == false) {
+            TRACE("[%s] Succeeded to get context[%d].\n", __func__, index);
+            ctxArrIndex = index;
+            break;
+        }
+        TRACE("[%s] Failed to get context[%d].\n", __func__, index);
+    }
+
+    if (index == CODEC_MAX_CONTEXT) {
+        ERR("[%s] Failed to get available codec context from now\n", __func__);
+        ERR("[%s] Try to run codec again\n", __func__);
+        return;
+    }
+
+    TRACE("[%s] context index :%d.\n", __func__, ctxArrIndex);
+
+    s->ctxArr[ctxArrIndex].pAVCtx = avcodec_alloc_context();
+    s->ctxArr[ctxArrIndex].nFileValue = s->codecParam.fileIndex;
+    s->ctxArr[ctxArrIndex].bUsed = true;
+    memcpy((uint8_t*)s->vaddr + offset, &ctxArrIndex, sizeof(int));
+    qemu_parser_init(s, ctxArrIndex);
+
+    pthread_mutex_unlock(&s->codec_mutex);
+
+    TRACE("[%s] Leave\n", __func__);
 }
 
 /* AVFrame *avcodec_alloc_frame (void) */
-void qemu_avcodec_alloc_frame (void)
+static void qemu_avcodec_alloc_frame (SVCodecState* s)
 {
-    gFrame = avcodec_alloc_frame();
+    TRACE("[%s] Enter\n", __func__);
+    pthread_mutex_lock(&s->codec_mutex);
+
+    s->ctxArr[ctxArrIndex].pFrame = avcodec_alloc_frame();
+    pthread_mutex_unlock(&s->codec_mutex);
+    TRACE("[%s] Leave\n", __func__);
 }
 
 /* void av_free (void *ptr) */
-void qemu_av_free_context (void)
+static void qemu_av_free_context (SVCodecState* s, int ctxIndex)
 {
-    av_free(gAVCtx);
-    gAVCtx = NULL;
+    AVCodecContext *avctx;
+
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (avctx) {
+        av_free(avctx);
+        s->ctxArr[ctxIndex].pAVCtx = NULL;
+    }
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("free AVCodecContext\n");
 }
 
-void qemu_av_free_picture (void)
+static void qemu_av_free_picture (SVCodecState* s, int ctxIndex)
 {
-    if (gFrame) {
-        av_free(gFrame);
-        gFrame = NULL;
+    AVFrame *avframe;
+
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avframe = s->ctxArr[ctxIndex].pFrame ;
+    if (avframe) {
+        av_free(avframe);
+        s->ctxArr[ctxIndex].pFrame = NULL;
     }
+
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("free AVFrame\n");
 }
 
-void qemu_av_free_palctrl (void)
+static void qemu_av_free_palctrl (SVCodecState* s, int ctxIndex)
 {
-    if (gAVCtx->palctrl) {
-        av_free(gAVCtx->palctrl);
-        gAVCtx->palctrl = NULL;
+    AVCodecContext *avctx;
+
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+
+    if (avctx->palctrl) {
+        av_free(avctx->palctrl);
+        avctx->palctrl = NULL;
     }
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("free AVCodecContext palctrl\n");
 }
 
-void qemu_av_free_extradata (void)
+static void qemu_av_free_extradata (SVCodecState* s, int ctxIndex)
 {
-    if (gAVCtx && gAVCtx->extradata && gAVCtx->extradata_size > 0) {
-        av_free(gAVCtx->extradata);
-        gAVCtx->extradata = NULL;
+    AVCodecContext *avctx;
+
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (avctx && avctx->extradata && avctx->extradata_size > 0) {
+        av_free(avctx->extradata);
+        avctx->extradata = NULL;
     }
+
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("free AVCodecContext extradata\n");
 }
 
 /* void avcodec_flush_buffers (AVCodecContext *avctx) */
-void qemu_avcodec_flush_buffers (void)
+static void qemu_avcodec_flush_buffers (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext *avctx;
 
     TRACE("Enter\n");
+    pthread_mutex_lock(&s->codec_mutex);
 
-    avctx = gAVCtx;
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
     if (avctx) {
         avcodec_flush_buffers(avctx);
     } else {
-        ERR("AVCodecContext is NULL\n");
+        ERR("[%s][%d] AVCodecContext is NULL\n", __func__, __LINE__);
     }
-    TRACE("Leave\n");
+
+    pthread_mutex_unlock(&s->codec_mutex);
+    TRACE("[%s] Leave\n", __func__);
 }
 
 /* int avcodec_decode_video (AVCodecContext *avctx, AVFrame *picture,
@@ -312,48 +510,57 @@ void qemu_avcodec_flush_buffers (void)
  *                          int buf_size)
  */
 #ifdef CODEC_HOST
-int qemu_avcodec_decode_video (SVCodecState* s)
+static int qemu_avcodec_decode_video (SVCodecState* s, int ctxIndex)
 {
-    AVCodecContext *avctx = NULL;
-    AVFrame *picture = NULL;
-    int got_picture_ptr = 0;
-    const uint8_t *buf = NULL;
-    int buf_size = 0;
+    AVCodecContext *avctx;
+    AVFrame *picture;
+    int got_picture_ptr;
+    const uint8_t *buf;
+    uint8_t *pParserBuffer;
+    bool bParser;
+    int buf_size;
     int ret;
 
-    avctx = gAVCtx;
-    picture = gFrame;
-    if (avctx == NULL || picture == NULL) {
-        ERR("AVCodecContext or AVFrame is NULL");
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    picture = s->ctxArr[ctxIndex].pFrame;
+    if (!avctx || !picture) {
+        ERR("AVCodecContext or AVFrame is NULL!\n")
+        ERR("avctx:0x%x, picture:0x%x\n", avctx, picture);
         return -1;
     }
-    
+
+    pParserBuffer = s->ctxArr[ctxIndex].pParserBuffer;
+    bParser = s->ctxArr[ctxIndex].bParser;
+    TRACE("Parser Buffer : 0x%x, Parser:%d\n", pParserBuffer, bParser);
+
     cpu_synchronize_state(cpu_single_env);
     cpu_memory_rw_debug(cpu_single_env, s->codecParam.in_args[4],
                         (uint8_t*)&buf_size, sizeof(int), 0);
 
-    TRACE("Paser Buffer : 0x%x, Parser:%d\n", gParserOutBuf, bParser);
-    if (gParserOutBuf && bParser) {
-        buf = gParserOutBuf;
+    if (pParserBuffer && bParser) {
+        buf = pParserBuffer;
     } else if (buf_size > 0) {
+        TRACE("not use parser, codec_id:%d\n", avctx->codec_id);
         buf = (uint8_t*)av_malloc(buf_size * sizeof(uint8_t));
         cpu_memory_rw_debug(cpu_single_env, s->codecParam.in_args[3],
-                            (uint8_t*)buf, buf_size, 0);
+                (uint8_t*)buf, buf_size, 0);
     } else {
         TRACE("There is no input buffer\n");
     }
 
-    TRACE("before avcodec_decode_video\n");
+    avpkt.data = buf;
+    avpkt.size = buf_size;
 
-    ret = avcodec_decode_video(avctx, picture, &got_picture_ptr, buf, buf_size);
+    TRACE("before avcodec_decode_video\n");
+    ret = avcodec_decode_video2(avctx, picture, &got_picture_ptr, &avpkt);
 
     TRACE("after avcodec_decode_video, ret:%d\n", ret);
     if (got_picture_ptr == 0) {
         TRACE("There is no frame\n");
     }
 
-    if (!gParserOutBuf && !bParser) {
-        TRACE("not use parser, codec_id:%d\n", avctx->codec_id);
+    if (!pParserBuffer && !bParser) {
+        TRACE("Free input buffer after decoding video\n");
         av_free(buf);
     }
 
@@ -367,54 +574,102 @@ int qemu_avcodec_decode_video (SVCodecState* s)
     return ret;
 }
 #else
-int qemu_avcodec_decode_video (SVCodecState *s)
+static int qemu_avcodec_decode_video (SVCodecState* s, int ctxIndex)
 {
-    AVCodecContext *avctx; 
+    AVCodecContext *avctx;
     AVFrame *picture;
+    AVPacket avpkt;
     int got_picture_ptr;
     uint8_t *buf;
+    uint8_t *pParserBuffer;
+    bool bParser;
     int buf_size;
     int size;
     int ret;
+    off_t offset;
 
-    avctx = gAVCtx;
-    picture = gFrame;
-    if (avctx == NULL || picture == NULL) {
-        ERR("AVCodecContext or AVFrame is NULL!! avctx:0x%x, picture:0x%x\n", avctx, picture);
+    pthread_mutex_lock(&s->codec_mutex);
+
+    TRACE("[%s] Video Context Index : %d\n", __func__, ctxIndex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    picture = s->ctxArr[ctxIndex].pFrame;
+    if (!avctx || !picture) {
+        ERR("[%s] AVCodecContext or AVFrame is NULL!\n", __func__);
         return -1;
     }
 
-    memcpy(&buf_size, (uint8_t*)s->vaddr, sizeof(int));
+    offset = s->codecParam.mmapOffset;
+
+    pParserBuffer = s->ctxArr[ctxIndex].pParserBuffer;
+    bParser = s->ctxArr[ctxIndex].bParser;
+    TRACE("[%s] Parser Buffer : 0x%x, Parser:%d\n", __func__, pParserBuffer, bParser);
+
+    memcpy(&buf_size, (uint8_t*)s->vaddr + offset, sizeof(int));
     size = sizeof(int);
 
-    TRACE("Paser Buffer : 0x%x, Parser:%d\n", gParserOutBuf, bParser);
-    if (gParserOutBuf && bParser) {
-        buf = gParserOutBuf;
+    if (pParserBuffer && bParser) {
+        buf = pParserBuffer;
     } else if (buf_size > 0) {
-        buf = (uint8_t*)s->vaddr + size;
+        TRACE("[%s] not use parser, codec_id:%d\n", __func__, avctx->codec_id);
+        buf = (uint8_t*)s->vaddr + offset + size;
     } else {
         TRACE("There is no input buffer\n");
+        buf = NULL;
     }
+
+    av_init_packet(&avpkt);
+    avpkt.data = buf;
+    avpkt.size = buf_size;
     
-    TRACE("before avcodec_decode_video\n");
-    ret = avcodec_decode_video(avctx, picture, &got_picture_ptr, buf, buf_size);
-    TRACE("after avcodec_decode_video, ret:%d\n", ret);
+    TRACE("[%s] before avcodec_decode_video\n", __func__);
+    ret = avcodec_decode_video2(avctx, picture, &got_picture_ptr, &avpkt);
+    TRACE("[%s] after avcodec_decode_video, ret:%d\n", __func__, ret);
     if (got_picture_ptr == 0) {
-        TRACE("There is no frame\n");
+        TRACE("[%s] There is no frame\n", __func__);
     }
 
+#ifndef CODEC_DUMMY
     size = sizeof(AVCodecContext);
-    memcpy(s->vaddr, avctx, size);
-    memcpy((uint8_t*)s->vaddr + size, picture, sizeof(AVFrame));
+    memcpy((uint8_t*)s->vaddr + offset, avctx, size);
+#else
+    memcpy((uint8_t*)s->vaddr, &avctx->pix_fmt, sizeof(int));
+    size = sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->time_base, sizeof(AVRational));
+    size += sizeof(AVRational);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->width, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->height, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->has_b_frames, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->frame_number, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->sample_aspect_ratio, sizeof(AVRational));
+    size += sizeof(AVRational);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->internal_buffer_count, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->profile, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + size, &avctx->level, sizeof(int));
+    size += sizeof(int);
+#endif
+    memcpy((uint8_t*)s->vaddr + offset + size, picture, sizeof(AVFrame));
     size += sizeof(AVFrame);
-    memcpy((uint8_t*)s->vaddr + size, &got_picture_ptr, sizeof(int));
+    memcpy((uint8_t*)s->vaddr + offset + size, &got_picture_ptr, sizeof(int));
     size += sizeof(int);
-    memcpy((uint8_t*)s->vaddr + size, &ret, sizeof(int));
-
-    if (!gParserOutBuf && !bParser) {
-        TRACE("not use parser, codec_id:%d\n", avctx->codec_id);
+    memcpy((uint8_t*)s->vaddr + offset + size, &ret, sizeof(int));
+
+#if 0
+    if (pParserBuffer && bParser) {
+        TRACE("[%s] Free input buffer after decoding video\n", __func__);
+        TRACE("[%s] input buffer : %p, %p\n", __func__, avpkt.data, pParserBuffer);
+        av_free(avpkt.data);
+        s->ctxArr[ctxIndex].pParserBuffer = NULL;
     }
+#endif
 
+    pthread_mutex_unlock(&s->codec_mutex);
     return ret;
 }
 #endif
@@ -423,7 +678,7 @@ int qemu_avcodec_decode_video (SVCodecState *s)
  *                          int buf_size, const AVFrame *pict)
  */
 #ifdef CODEC_HOST
-int qemu_avcodec_encode_video (SVCodecState *s)
+static int qemu_avcodec_encode_video (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext *avctx;
     uint8_t *outBuf, *inBuf;
@@ -431,11 +686,10 @@ int qemu_avcodec_encode_video (SVCodecState *s)
     AVFrame *pict;
     int ret;
 
-    if (gAVCtx) {
-        avctx = gAVCtx;
-        pict = gFrame;
-    } else {
-        ERR("AVCodecContext is NULL\n");
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    pict = s->ctxArr[ctxIndex].pFrame;
+    if (!avctx || !pict) {
+        ERR("AVCodecContext or AVFrame is NULL\n");
         return -1;
     }
 
@@ -479,7 +733,7 @@ int qemu_avcodec_encode_video (SVCodecState *s)
     return ret;
 }
 #else
-int qemu_avcodec_encode_video (SVCodecState *s)
+static int qemu_avcodec_encode_video (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext *avctx = NULL;
     AVFrame *pict = NULL;
@@ -489,30 +743,33 @@ int qemu_avcodec_encode_video (SVCodecState *s)
     int bPict = -1;
     int size = 0;
     int ret = -1;
+    off_t offset;
 
-    if (gAVCtx) {
-        avctx = gAVCtx;
-        pict = gFrame;
-    } else {
-        ERR("AVCodecContext is NULL\n");
+    pthread_mutex_lock(&s->codec_mutex);
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    pict = s->ctxArr[ctxIndex].pFrame;
+    if (!avctx || !pict) {
+        ERR("AVCodecContext or AVFrame is NULL\n");
         return -1;
     }
 
+    offset = s->codecParam.mmapOffset;
+
     size = sizeof(int);
-    memcpy(&bPict, s->vaddr, size);
+    memcpy(&bPict, (uint8_t*)s->vaddr + offset, size);
     TRACE("avframe is :%d\n", bPict);
 
     if (bPict == 0) {
-        memcpy(&outputBufSize, (uint8_t*)s->vaddr + size, size);
+        memcpy(&outputBufSize, (uint8_t*)s->vaddr + offset + size, size);
         size += sizeof(int);
 
-        memcpy(pict, (uint8_t*)s->vaddr + size, sizeof(AVFrame));
+        memcpy(pict, (uint8_t*)s->vaddr + offset + size, sizeof(AVFrame));
         size += sizeof(AVFrame);
 
         numBytes = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
         TRACE("input buffer size :%d\n", numBytes);
 
-        inputBuf = (uint8_t*)s->vaddr + size;
+        inputBuf = (uint8_t*)s->vaddr + offset + size;
         if (!inputBuf) {
             ERR("failed to allocate decoded frame inputBuf\n");
             return -1;
@@ -532,23 +789,124 @@ int qemu_avcodec_encode_video (SVCodecState *s)
     }
 
     TRACE("before encoding video\n");
-    ret = avcodec_encode_video (avctx, s->vaddr, outputBufSize, pict);
+    ret = avcodec_encode_video (avctx, (uint8_t*)s->vaddr + offset, outputBufSize, pict);
 
     TRACE("after encoding video, ret:%d\n");
     if (ret < 0) {
         ERR("Failed to encode video\n");
     }
-    memcpy((uint8_t*)s->vaddr + outputBufSize, &ret, sizeof(int));
+    memcpy((uint8_t*)s->vaddr + offset + outputBufSize, &ret, sizeof(int));
 
+    pthread_mutex_unlock(&s->codec_mutex);
     return ret;
 }
 #endif
 
+/* 
+ *  int avcodec_decode_audio2 (AVCodecContext *avctx, int16_t *samples,
+ *                             int *frame_size_ptr, uint8_t *buf, int buf_size)
+ */
+static int qemu_avcodec_decode_audio (SVCodecState *s, int ctxIndex)
+{
+    AVCodecContext *avctx;
+    AVPacket avpkt;
+    int16_t *samples;
+    int frame_size_ptr;
+    uint8_t *buf;
+    uint8_t *pParserBuffer;
+    bool bParser;
+    int buf_size, outbuf_size;
+    int size;
+    int ret;
+    off_t offset;
+
+    TRACE("Audio Context Index : %d\n", ctxIndex);
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!avctx) {
+        ERR("[%s][%d] AVCodecContext is NULL!\n", __func__, __LINE__);
+        return -1;
+    }
+
+    offset = s->codecParam.mmapOffset;
+
+    pParserBuffer = s->ctxArr[ctxIndex].pParserBuffer;
+    bParser = s->ctxArr[ctxIndex].bParser;
+    TRACE("Parser Buffer : 0x%x, Parser:%d\n", pParserBuffer, bParser);
+
+    memcpy(&buf_size, (uint8_t*)s->vaddr + offset, sizeof(int));
+    size = sizeof(int);
+    TRACE("input buffer size : %d\n", buf_size);
+
+    if (pParserBuffer && bParser) {
+        TRACE("use parser, buf:%p codec_id:%x\n", pParserBuffer, avctx->codec_id);
+        buf = pParserBuffer;
+    } else if (buf_size > 0) {
+        TRACE("not use parser, codec_id:%x\n", avctx->codec_id);
+        buf = (uint8_t*)s->vaddr + offset + size;
+    } else {
+        TRACE("There is no input buffer\n");
+        buf = NULL;
+    }
+
+    av_init_packet(&avpkt);
+    avpkt.data = buf;
+    avpkt.size = buf_size;
+
+    frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    outbuf_size = frame_size_ptr;
+    samples = av_malloc(frame_size_ptr);
+
+    ret = avcodec_decode_audio3(avctx, samples, &frame_size_ptr, &avpkt);
+    TRACE("After decoding audio!, ret:%d\n", ret);
+
+#ifndef CODEC_DUMMY
+    size = sizeof(AVCodecContext);
+    memcpy((uint8_t*)s->vaddr + offset, avctx, size);
+#else
+    memcpy((uint8_t*)s->vaddr + offset, &avctx->bit_rate, sizeof(int));
+    size = sizeof(int);
+    memcpy((uint8_t*)s->vaddr + offset + size, &avctx->sub_id, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + offset + size, &avctx->frame_size, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + offset + size, &avctx->frame_number, sizeof(int));
+    size += sizeof(int);
+#endif
+    memcpy((uint8_t*)s->vaddr + offset + size, samples, outbuf_size);
+    size += outbuf_size;
+    memcpy((uint8_t*)s->vaddr + offset + size, &frame_size_ptr, sizeof(int));
+    size += sizeof(int);
+    memcpy((uint8_t*)s->vaddr + offset + size, &ret, sizeof(int));
+
+    TRACE("before free input buffer and output buffer!\n");
+    av_free(samples);
+
+    if (pParserBuffer && bParser) {
+        TRACE("[%s] free parser buf\n", __func__);
+        av_free(avpkt.data);
+        s->ctxArr[ctxIndex].pParserBuffer = NULL;
+    }
+
+    pthread_mutex_unlock(&s->codec_mutex);
+
+    TRACE("[%s] Leave\n", __func__);
+
+    return ret;
+}
+
+static int qemu_avcodec_encode_audio (SVCodecState *s, int ctxIndex)
+{
+    WARN("[%s] Does not support audio encoder using FFmpeg\n", __func__);
+    return 0;
+}
+
 /* void av_picture_copy (AVPicture *dst, const AVPicture *src,
  *                      enum PixelFormat pix_fmt, int width, int height)
  */
 #ifdef CODEC_HOST
-void qemu_av_picture_copy (SVCodecState *s)
+static void qemu_av_picture_copy (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext* avctx;
     AVPicture dst;
@@ -557,11 +915,9 @@ void qemu_av_picture_copy (SVCodecState *s)
     uint8_t *buffer = NULL;
     int ret;
 
-    TRACE("Enter :%s\n", __func__);
-    if (gAVCtx && gFrame) { 
-        avctx = gAVCtx;
-        src = (AVPicture*)gFrame;
-    } else {
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    src = (AVPicture*)s->ctxArr[ctxIndex].pFrame;
+    if (!avctx && !src) { 
         ERR("AVCodecContext or AVFrame is NULL\n");
         return;
     }
@@ -583,58 +939,66 @@ void qemu_av_picture_copy (SVCodecState *s)
     TRACE("Leave :%s\n", __func__);
 }
 #else
-void qemu_av_picture_copy (SVCodecState *s)
+static void qemu_av_picture_copy (SVCodecState* s, int ctxIndex)
 {
     AVCodecContext* avctx;
     AVPicture dst;
     AVPicture *src;
     int numBytes;
     uint8_t *buffer = NULL;
+    off_t offset;
 
     TRACE("Enter :%s\n", __func__);
-    if (gAVCtx && gFrame) { 
-        avctx = gAVCtx;
-        src = (AVPicture*)gFrame;
-    } else {
+    pthread_mutex_lock(&s->codec_mutex);
+
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    src = (AVPicture*)s->ctxArr[ctxIndex].pFrame;
+    if (!avctx && !src) { 
         ERR("AVCodecContext or AVFrame is NULL\n");
         return;
     }
 
+    offset = s->codecParam.mmapOffset;
+
     numBytes = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
     buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
     avpicture_fill(&dst, buffer, avctx->pix_fmt, avctx->width, avctx->height);
     av_picture_copy(&dst, src, avctx->pix_fmt, avctx->width, avctx->height);
 
-    memcpy(s->vaddr, dst.data[0], numBytes);
+    memcpy((uint8_t*)s->vaddr + offset, dst.data[0], numBytes);
     TRACE("After copy image buffer from host to guest\n");
-    
+
     av_free(buffer);
+
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("Leave :%s\n", __func__);
 }
 #endif
 
 /* AVCodecParserContext *av_parser_init (int codec_id) */
-void qemu_av_parser_init (SVCodecState *s)
+static void qemu_av_parser_init (SVCodecState* s, int ctxIndex)
 {
     AVCodecParserContext *parserctx = NULL;
     AVCodecContext *avctx;
 
     TRACE("Enter :%s\n", __func__);
+    pthread_mutex_lock(&s->codec_mutex);
 
-    avctx = gAVCtx;
-    if (avctx == NULL) {
-        ERR("AVCodecContext is NULL!!\n");
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!avctx) {
+        ERR("[%s][%d] AVCodecContext is NULL!!\n", __func__, __LINE__);
         return;
     }
 
-    TRACE("before av_parser_init, codec_id:%d\n", avctx->codec_id);
+    INFO("before av_parser_init, codec_type:%d codec_id:%x\n", avctx->codec_type, avctx->codec_id);
     parserctx = av_parser_init(avctx->codec_id);
     if (!parserctx) {
         ERR("Failed to initialize AVCodecParserContext\n");
     }
-    gAVParserCtx = parserctx;
-    bParser = true;
+    s->ctxArr[ctxIndex].pParserCtx = parserctx;
+    s->ctxArr[ctxIndex].bParser = true;
 
+    pthread_mutex_unlock(&s->codec_mutex);
     TRACE("Leave :%s\n", __func__);
 }
 
@@ -644,7 +1008,7 @@ void qemu_av_parser_init (SVCodecState *s)
  *                      int64_t pts, int64_t dts)
  */
 #ifdef CODEC_HOST
-int qemu_av_parser_parse (SVCodecState *s)
+static int qemu_av_parser_parse (SVCodecState* s, int ctxIndex)
 {
     AVCodecParserContext *parserctx = NULL;
     AVCodecContext *avctx = NULL;
@@ -657,11 +1021,10 @@ int qemu_av_parser_parse (SVCodecState *s)
     int64_t dts;
     int ret;
 
-    if (gAVParserCtx && gAVCtx) {
-        parserctx = gAVParserCtx;
-        avctx = gAVCtx;
-    } else {
-        ERR("AVCodecParserContext or AVCodecContext is NULL\n");
+    parserctx = s->ctxArr[ctxIndex].pParserCtx;
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!parserctx && !avctx) {
+        ERR("[%s][%d] AVCodecParserContext or AVCodecContext is NULL\n", __func__, __LINE__);
     }
 
     memcpy(&tmp_ctx, avctx, sizeof(AVCodecContext));
@@ -683,9 +1046,9 @@ int qemu_av_parser_parse (SVCodecState *s)
     cpu_memory_rw_debug(cpu_single_env, s->codecParam.in_args[7],
                         (uint8_t*)&dts, sizeof(int64_t), 0);
     
-    ret = av_parser_parse(parserctx, avctx, &poutbuf, &poutbuf_size,
-                          inbuf, inbuf_size, pts, dts);
-    gParserOutBuf = poutbuf;
+    ret = av_parser_parse2(parserctx, avctx, &poutbuf, &poutbuf_size,
+                          inbuf, inbuf_size, pts, dts, AV_NOPTS_VALUE);
+    s->ctxArr[ctxIndex].pParserBuffer = poutbuf;
     if (inbuf_size > 0 && inbuf) {
         av_free(inbuf);
         inbuf = NULL;
@@ -706,12 +1069,10 @@ int qemu_av_parser_parse (SVCodecState *s)
     return ret;
 }
 #else
-int qemu_av_parser_parse (SVCodecState *s)
+static int qemu_av_parser_parse (SVCodecState *s, int ctxIndex)
 {
     AVCodecParserContext *parserctx = NULL;
     AVCodecContext *avctx = NULL;
-    AVCodecContext tmp_ctx;
-
     uint8_t *poutbuf;
     int poutbuf_size;
     uint8_t *inbuf = NULL;
@@ -719,122 +1080,142 @@ int qemu_av_parser_parse (SVCodecState *s)
     int64_t pts;
     int64_t dts;
     int size, ret;
+    off_t offset;
 
-    if (gAVParserCtx && gAVCtx) {
-        parserctx = gAVParserCtx;
-        avctx = gAVCtx;
-    } else {
-        ERR("AVCodecParserContext or AVCodecContext is NULL\n");
+    TRACE("Enter %s\n", __func__);
+    pthread_mutex_lock(&s->codec_mutex);
+
+    parserctx = s->ctxArr[ctxIndex].pParserCtx;
+    avctx = s->ctxArr[ctxIndex].pAVCtx;
+    if (!parserctx && !avctx) {
+        ERR("[%s][%d] AVCodecParserContext or AVCodecContext is NULL\n", __func__, __LINE__);
     }
 
-    TRACE("Enter %s\n", __func__);
-    memcpy(&tmp_ctx, avctx, sizeof(AVCodecContext));
+    offset = s->codecParam.mmapOffset;
 
-    size = sizeof(AVCodecContext);
-    memcpy(avctx, s->vaddr, sizeof(AVCodecContext));
-    qemu_restore_context(avctx, &tmp_ctx);
-    memcpy(&pts, (uint8_t*)s->vaddr + size, sizeof(int64_t));
-    size += sizeof(int64_t);
-    memcpy(&dts, (uint8_t*)s->vaddr + size, sizeof(int64_t));
+    memcpy(&pts, (uint8_t*)s->vaddr + offset, sizeof(int64_t));
+    size = sizeof(int64_t);
+    memcpy(&dts, (uint8_t*)s->vaddr + offset + size, sizeof(int64_t));
     size += sizeof(int64_t);
-    memcpy(&inbuf_size, (uint8_t*)s->vaddr + size, sizeof(int));
+    memcpy(&inbuf_size, (uint8_t*)s->vaddr + offset + size, sizeof(int));
+
+    TRACE("[%s] input buffer size :%d\n", __func__, inbuf_size);
     if (inbuf_size > 0) {
         size += sizeof(int);
-        inbuf = (uint8_t*)s->vaddr + size;
-        size += inbuf_size;
+        inbuf = av_mallocz(inbuf_size);
+        memcpy(inbuf, (uint8_t*)s->vaddr + offset + size, inbuf_size);
     } else {
         inbuf = NULL;
     }
-    
-    ret = av_parser_parse(parserctx, avctx, &poutbuf, &poutbuf_size,
-                          inbuf, inbuf_size, pts, dts);
 
-    gParserOutBuf = poutbuf;
+    ret = av_parser_parse2(parserctx, avctx, &poutbuf, &poutbuf_size,
+                           inbuf, inbuf_size, pts, dts, AV_NOPTS_VALUE);
 
-    size = sizeof(AVCodecContext);
-    memcpy(s->vaddr, avctx, sizeof(AVCodecContext));
+    TRACE("[%s] after parsing, output buffer size :%d, ret:%d\n", __func__, poutbuf_size, ret);
+    TRACE("[%s] inbuf:%p, outbuf:%p\n", __func__, inbuf, poutbuf);
 
-    memcpy((uint8_t*)s->vaddr + size, &poutbuf_size, sizeof(int));
-    size += sizeof(int);
+    s->ctxArr[ctxIndex].pParserBuffer = poutbuf;
+
+    memcpy((uint8_t*)s->vaddr + offset, &poutbuf_size, sizeof(int));
+    size = sizeof(int);
     if (poutbuf_size != 0) {
-        memcpy((uint8_t*)s->vaddr + size, poutbuf, poutbuf_size);
+        memcpy((uint8_t*)s->vaddr + offset + size, poutbuf, poutbuf_size);
         size += poutbuf_size;
     }
-    memcpy((uint8_t*)s->vaddr + size, &ret, sizeof(int));
+    memcpy((uint8_t*)s->vaddr + offset + size, &ret, sizeof(int));
 
-    TRACE("Leave %s\n", __func__);
+#if 1
+    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+        TRACE("[%s] free parser inbuf\n", __func__);
+        av_free(inbuf);
+    }
+#endif
+
+    pthread_mutex_unlock(&s->codec_mutex);
+    TRACE("[%s]Leave\n", __func__);
     return ret;
 }
 #endif
 
 /* void av_parser_close (AVCodecParserContext *s) */
-void qemu_av_parser_close (void)
+static void qemu_av_parser_close (SVCodecState *s, int ctxIndex)
 {
     AVCodecParserContext *parserctx;
 
     TRACE("av_parser_close\n");
-    if (gAVParserCtx) {
-        parserctx = gAVParserCtx;
-    } else {
+    pthread_mutex_lock(&s->codec_mutex);
+
+    parserctx = s->ctxArr[ctxIndex].pParserCtx;
+    if (!parserctx) {
         ERR("AVCodecParserContext is NULL\n");
         return ;
     }
     av_parser_close(parserctx);
+    pthread_mutex_unlock(&s->codec_mutex);
+
 }
 
-static int codec_operate (uint32_t apiIndex, SVCodecState *state)
+static int codec_operate (uint32_t apiIndex, uint32_t ctxIndex, SVCodecState *state)
 {
     int ret = -1;
 
+    TRACE("[%s] context : %d\n", __func__, ctxIndex);
+
     switch (apiIndex) {
         /* FFMPEG API */
         case EMUL_AV_REGISTER_ALL:
             qemu_av_register_all();
             break;
         case EMUL_AVCODEC_OPEN:
-            ret = qemu_avcodec_open(state);
+            ret = qemu_avcodec_open(state, ctxIndex);
             break;
         case EMUL_AVCODEC_CLOSE:
-            ret = qemu_avcodec_close(state);
+            ret = qemu_avcodec_close(state, ctxIndex);
             break;
         case EMUL_AVCODEC_ALLOC_CONTEXT:
-            qemu_avcodec_alloc_context();
+            qemu_avcodec_alloc_context(state);
             break;
         case EMUL_AVCODEC_ALLOC_FRAME:
-            qemu_avcodec_alloc_frame();
+            qemu_avcodec_alloc_frame(state);
             break;
         case EMUL_AV_FREE_CONTEXT:
-            qemu_av_free_context();
+            qemu_av_free_context(state, ctxIndex);
             break;
         case EMUL_AV_FREE_FRAME:
-            qemu_av_free_picture();
+            qemu_av_free_picture(state, ctxIndex);
             break;
         case EMUL_AV_FREE_PALCTRL:
-            qemu_av_free_palctrl();
+            qemu_av_free_palctrl(state, ctxIndex);
             break;
         case EMUL_AV_FREE_EXTRADATA:
-            qemu_av_free_extradata();
+            qemu_av_free_extradata(state, ctxIndex);
             break;
         case EMUL_AVCODEC_FLUSH_BUFFERS:
-            qemu_avcodec_flush_buffers();
+            qemu_avcodec_flush_buffers(state, ctxIndex);
             break;
         case EMUL_AVCODEC_DECODE_VIDEO:
-            ret = qemu_avcodec_decode_video(state);
+            ret = qemu_avcodec_decode_video(state, ctxIndex);
             break;
         case EMUL_AVCODEC_ENCODE_VIDEO:
-            ret = qemu_avcodec_encode_video(state);
+            ret = qemu_avcodec_encode_video(state, ctxIndex);
+            break;
+        case EMUL_AVCODEC_DECODE_AUDIO:
+            ret = qemu_avcodec_decode_audio(state, ctxIndex);
+            break;
+        case EMUL_AVCODEC_ENCODE_AUDIO:
+            ret = qemu_avcodec_encode_audio(state, ctxIndex);
             break;
         case EMUL_AV_PICTURE_COPY:
-            qemu_av_picture_copy(state);
+            qemu_av_picture_copy(state, ctxIndex);
             break;
         case EMUL_AV_PARSER_INIT:
-            qemu_av_parser_init(state);
+            qemu_av_parser_init(state, ctxIndex);
             break;
         case EMUL_AV_PARSER_PARSE:
-            ret = qemu_av_parser_parse(state);
+            ret = qemu_av_parser_parse(state, ctxIndex);
             break;
         case EMUL_AV_PARSER_CLOSE:
-            qemu_av_parser_close();
+            qemu_av_parser_close(state, ctxIndex);
             break;
         default:
             WARN("The api index does not exsit!. api index:%d\n", apiIndex);
@@ -845,27 +1226,23 @@ static int codec_operate (uint32_t apiIndex, SVCodecState *state)
 /*
  *  Codec Device APIs
  */
-static uint32_t codec_read (void *opaque, target_phys_addr_t addr)
+uint64_t codec_read (void *opaque, target_phys_addr_t addr, unsigned size)
 {
-    int ret = -1;
-
     switch (addr) {
         default:
-            ERR("There is no avaiable command for svcodece\n");
+            ERR("There is no avaiable command for %s\n", QEMU_DEV_NAME);
     }
-    return ret;
+    return 0;
 }
 
-static void codec_write (void *opaque, target_phys_addr_t addr, uint32_t value)
+void codec_write (void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size)
 {
-    uint32_t offset;
     int ret = -1;
     SVCodecState *state = (SVCodecState*)opaque;
 
-    offset = addr;
-    switch (offset) {
-        case FUNC_NUM:
-            ret = codec_operate(value, state);
+    switch (addr) {
+        case CODEC_API_INDEX:
+            ret = codec_operate(value, state->codecParam.ctxIndex, state);
 #ifdef CODEC_HOST
             if (ret >= 0) {
                 cpu_synchronize_state(cpu_single_env);
@@ -875,83 +1252,86 @@ static void codec_write (void *opaque, target_phys_addr_t addr, uint32_t value)
 #endif
             paramCount = 0;
             break;
-        case IN_ARGS:
+        case CODEC_IN_PARAM:
             state->codecParam.in_args[paramCount++] = value;
             break;
-        case RET_STR:
+        case CODEC_RETURN_VALUE:
             state->codecParam.ret_args = value;
             break;
+        case CODEC_CONTEXT_INDEX:
+            state->codecParam.ctxIndex = value;
+            TRACE("Context Index : %d\n", state->codecParam.ctxIndex);
+            break;
+        case CODEC_MMAP_OFFSET:
+            state->codecParam.mmapOffset = value * MARU_CODEC_MMAP_MEM_SIZE;
+            TRACE("MMAP Offset :%d\n", state->codecParam.mmapOffset);
+            break;
+        case CODEC_FILE_INDEX:
+            state->codecParam.fileIndex = value;
+            break;
+        case CODEC_CLOSED:
+            qemu_codec_close(state, value);
+            break;
         default:
-            ERR("There is no avaiable command for svcodece\n");
+            ERR("There is no avaiable command for %s\n", QEMU_DEV_NAME);
     }
 }
 
-static CPUReadMemoryFunc * const svcodec_io_readfn[3] = {
-    codec_read,
-    codec_read,
-    codec_read,
-};
-
-static CPUWriteMemoryFunc * const svcodec_io_writefn[3] = {
-    codec_write,
-    codec_write,
-    codec_write,
+static const MemoryRegionOps codec_mmio_ops = {
+    .read = codec_read,
+    .write = codec_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void codec_mem_map (PCIDevice *dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
-    cpu_register_physical_memory(addr, size, s->vram_offset);
-    s->mem_addr = addr;
-}
-
-static void codec_mmio_map (PCIDevice *dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
-    cpu_register_physical_memory(addr, size, s->mmioIndex);
-    s->mmio_addr = addr;
-}
-
 static int codec_initfn (PCIDevice *dev)
 {
     SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
 
+    INFO("[%s] device init\n", __func__);
+
     memset(&s->codecParam, 0x00, sizeof(SVCodecParam));
-    
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_TIZEN);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIRTUAL_CODEC);
-    pci_config_set_class(pci_conf, PCI_CLASS_MULTIMEDIA_OTHER);
+    pthread_mutex_init(&s->codec_mutex, NULL);
     pci_config_set_interrupt_pin(pci_conf, 2);
 
-    s->vram_offset = qemu_ram_alloc(NULL, "codec.ram", SVCODEC_MEM_SIZE);
-    s->vaddr = qemu_get_ram_ptr(s->vram_offset);
+    memory_region_init_ram(&s->vram, NULL, "codec.ram", MARU_CODEC_MEM_SIZE);
+    s->vaddr = memory_region_get_ram_ptr(&s->vram);
+
+    memory_region_init_io (&s->mmio, &codec_mmio_ops, s, "codec-mmio", MARU_CODEC_REG_SIZE);
+
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
 
-    s->mmioIndex = cpu_register_io_memory(svcodec_io_readfn, svcodec_io_writefn,
-                                          s, DEVICE_LITTLE_ENDIAN);
+    return 0;
+}
 
-    pci_register_bar(&s->dev, 0, SVCODEC_MEM_SIZE,
-                    PCI_BASE_ADDRESS_MEM_PREFETCH, codec_mem_map);
-    pci_register_bar(&s->dev, 1, SVCODEC_REG_SIZE,
-                    PCI_BASE_ADDRESS_SPACE_MEMORY, codec_mmio_map);
+static int codec_exitfn (PCIDevice *dev)
+{
+    SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
+    INFO("[%s] device exit\n", __func__);
 
+    memory_region_destroy (&s->vram);
+    memory_region_destroy (&s->mmio);
     return 0;
 }
 
-int pci_codec_init (PCIBus *bus)
+int codec_init (PCIBus *bus)
 {
-    printf("[%s] device init\n", __func__);
+    INFO("[%s] device create\n", __func__);
     pci_create_simple (bus, -1, QEMU_DEV_NAME);
     return 0;
 }
 
 static PCIDeviceInfo codec_info = {
     .qdev.name      = QEMU_DEV_NAME,
-    .qdev.desc      = "Virtual codec device for Tizen emulator",
-    .qdev.size      = sizeof (SVCodecState),    
+    .qdev.desc      = "Virtual Codec device for Tizen emulator",
+    .qdev.size      = sizeof (SVCodecState),
     .init           = codec_initfn,
+    .exit           = codec_exitfn,
+    .vendor_id      = PCI_VENDOR_ID_TIZEN,
+    .device_id      = PCI_DEVICE_ID_VIRTUAL_CODEC,
+    .class_id       = PCI_CLASS_MULTIMEDIA_AUDIO,
 };
 
 static void codec_register (void)
index 1cc00fe8bac451a1057d56cefc54749fe39ff2c4..fb74bda0233658ce39f7b7dd0245f92b86d76799 100644 (file)
 #include "pci.h"
 #include "pci_ids.h"
 #include "tizen/src/debug_ch.h"
+#include "maru_pci_ids.h"
 
 #include <libavformat/avformat.h>
-#include <libswscale/swscale.h>
 
-// #define CODEC_HOST
+#define CODEC_MAX_CONTEXT   10
 
 /*
  *  Codec Device Structures
  */
 
 typedef struct _SVCodecParam {
-    uint32_t        func_num;
+    uint32_t        apiIndex;
+    uint32_t        ctxIndex;
     uint32_t        in_args[20];
     uint32_t        ret_args;
+    uint32_t        mmapOffset;
+       uint32_t                fileIndex;
 } SVCodecParam;
 
+typedef struct _SVCodecContext {
+    AVCodecContext          *pAVCtx;
+    AVFrame                 *pFrame;
+    AVCodecParserContext    *pParserCtx;
+    uint8_t                 *pParserBuffer;
+    bool                    bParser;
+    bool                    bUsed;
+       uint32_t                                nFileValue;
+} SVCodecContext;
 
 typedef struct _SVCodecState {
     PCIDevice           dev;
+    SVCodecContext      ctxArr[CODEC_MAX_CONTEXT];
     SVCodecParam        codecParam;
+    pthread_mutex_t     codec_mutex;
 
     int                 mmioIndex;
-
-    uint8_t*            vaddr;
-    ram_addr_t          vram_offset;
-
     uint32_t            mem_addr;
     uint32_t            mmio_addr;
 
-    int                 index;
+    uint8_t*            vaddr;
+    MemoryRegion        vram;
+    MemoryRegion        mmio;
 } SVCodecState;
 
 enum {
-    FUNC_NUM            = 0x00,
-    IN_ARGS             = 0x04,
-    RET_STR             = 0x08,
+    CODEC_API_INDEX         = 0x00,
+    CODEC_IN_PARAM          = 0x04,
+    CODEC_RETURN_VALUE      = 0x08,
+    CODEC_CONTEXT_INDEX     = 0x0c,
+    CODEC_MMAP_OFFSET       = 0x10,
+    CODEC_FILE_INDEX        = 0x14,
+    CODEC_CLOSED            = 0x18,
 };
 
 enum {
     EMUL_AV_REGISTER_ALL = 1,
-    EMUL_AVCODEC_OPEN,
-    EMUL_AVCODEC_CLOSE,
     EMUL_AVCODEC_ALLOC_CONTEXT,
     EMUL_AVCODEC_ALLOC_FRAME,
+    EMUL_AVCODEC_OPEN,
+    EMUL_AVCODEC_CLOSE,
     EMUL_AV_FREE_CONTEXT,
     EMUL_AV_FREE_FRAME,
     EMUL_AV_FREE_PALCTRL,
@@ -87,6 +103,8 @@ enum {
     EMUL_AVCODEC_FLUSH_BUFFERS,
     EMUL_AVCODEC_DECODE_VIDEO,
     EMUL_AVCODEC_ENCODE_VIDEO,
+    EMUL_AVCODEC_DECODE_AUDIO,
+    EMUL_AVCODEC_ENCODE_AUDIO,
     EMUL_AV_PICTURE_COPY,
     EMUL_AV_PARSER_INIT,
     EMUL_AV_PARSER_PARSE,
@@ -97,50 +115,61 @@ enum {
 /*
  *  Codec Device APIs
  */
-int pci_codec_init (PCIBus *bus);
-static int codec_operate(uint32_t value, SVCodecState *opaque);
+int codec_init (PCIBus *bus);
+
+uint64_t codec_read (void *opaque, target_phys_addr_t addr, unsigned size);
+
+void codec_write (void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size);
+
+static int codec_operate(uint32_t apiIndex, uint32_t ctxIndex, SVCodecState *state);
 
 /*
- *  FFMPEG APIs
+ *  Codec Helper APIs
  */
+static void qemu_parser_init (SVCodecState *s, int ctxIndex);
 
-void qemu_parser_init (void);
+static void qemu_restore_context (AVCodecContext *dst, AVCodecContext *src);
+
+/*
+ *  FFMPEG APIs
+ */
 
-void qemu_restore_context (AVCodecContext *dst, AVCodecContext *src);
+static void qemu_av_register_all (void);
 
-void qemu_av_register_all (void);
+static int qemu_avcodec_open (SVCodecState *s, int ctxIndex);
 
-int qemu_avcodec_open (SVCodecState *s);
+static int qemu_avcodec_close (SVCodecState *s, int ctxIndex);
 
-int qemu_avcodec_close (SVCodecState *s);
+static void qemu_avcodec_alloc_context (SVCodecState *s);
 
-void qemu_avcodec_alloc_context (void);
+static void qemu_avcodec_alloc_frame (SVCodecState *s);
 
-void qemu_avcodec_alloc_frame (void);
+static void qemu_av_free_context (SVCodecState* s, int ctxIndex);
 
-void qemu_av_free_context (void);
+static void qemu_av_free_picture (SVCodecState* s, int ctxIndex);
 
-void qemu_av_free_picture (void);
+static void qemu_av_free_palctrl (SVCodecState* s, int ctxIndex);
 
-void qemu_av_free_palctrl (void);
+static void qemu_av_free_extradata (SVCodecState* s, int ctxIndex);
 
-void qemu_av_free_extradata (void);
+static void qemu_avcodec_flush_buffers (SVCodecState *s, int ctxIndex);
 
-void qemu_avcodec_flush_buffers (void);
+static int qemu_avcodec_decode_video (SVCodecState *s, int ctxIndex);
 
-int qemu_avcodec_decode_video (SVCodecState *s);
+static int qemu_avcodec_encode_video (SVCodecState *s, int ctxIndex);
 
-int qemu_avcodec_encode_video (SVCodecState *s);
+static int qemu_avcodec_decode_audio (SVCodecState *s, int ctxIndex);
 
-void qemu_av_picture_copy (SVCodecState *s);
+static int qemu_avcodec_encode_audio (SVCodecState *s, int ctxIndex);
 
-void qemu_av_parser_init (SVCodecState *s);
+static void qemu_av_picture_copy (SVCodecState *s, int ctxIndex);
 
-int qemu_av_parser_parse (SVCodecState *s);
+static void qemu_av_parser_init (SVCodecState *s, int ctxIndex);
 
-void qemu_av_parser_close (void);
+static int qemu_av_parser_parse (SVCodecState *s, int ctxIndex);
 
-int qemu_avcodec_get_buffer (AVCodecContext *context, AVFrame *picture);
+static void qemu_av_parser_close (SVCodecState *s, int ctxIndex);
 
-void qemu_avcodec_release_buffer (AVCodecContext *context, AVFrame *picture);
+static int qemu_avcodec_get_buffer (AVCodecContext *context, AVFrame *picture);
 
+static void qemu_avcodec_release_buffer (AVCodecContext *context, AVFrame *picture);
diff --git a/tizen/src/hw/maru_overlay.c b/tizen/src/hw/maru_overlay.c
new file mode 100644 (file)
index 0000000..ecac547
--- /dev/null
@@ -0,0 +1,197 @@
+/* 
+ * Maru overlay device for VGA
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun <dk77.yun@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+#include "pc.h"
+#include "pci.h"
+#include "maru_pci_ids.h"
+#include "maru_overlay.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, maru_overlay);
+
+#define QEMU_DEV_NAME           "MARU_OVERLAY"
+
+#define OVERLAY_MEM_SIZE       (8192 * 1024)   // 4MB(overlay0) + 4MB(overlay1)
+#define OVERLAY_REG_SIZE       256
+#define OVERLAY1_REG_OFFSET    (OVERLAY_REG_SIZE / 2)
+
+
+enum {
+       OVERLAY_POWER    = 0x00,
+       OVERLAY_POSITION = 0x04,        // left top position
+       OVERLAY_SIZE     = 0x08,        // width and height
+};
+
+uint8_t* overlay_ptr;
+
+uint8_t overlay0_power;
+uint16_t overlay0_left;
+uint16_t overlay0_top;
+uint16_t overlay0_width;
+uint16_t overlay0_height;
+
+uint8_t overlay1_power;
+uint16_t overlay1_left;
+uint16_t overlay1_top;
+uint16_t overlay1_width;
+uint16_t overlay1_height;
+
+typedef struct OverlayState {
+    PCIDevice       dev;
+
+    MemoryRegion    mem_addr;
+    MemoryRegion    mmio_addr;
+
+} OverlayState;
+
+
+static uint64_t overlay_reg_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    switch (addr) {
+    case OVERLAY_POWER:
+        return overlay0_power;
+        break;
+    case OVERLAY_SIZE:
+        return overlay0_left | overlay0_top << 16;
+        break;
+    case OVERLAY_POSITION:
+        return overlay0_width | overlay0_height << 16;
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_POWER:
+        return overlay1_power;
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_SIZE:
+        return overlay1_left | overlay1_top << 16;
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_POSITION:
+        return overlay1_width | overlay1_height << 16;
+        break;
+    default:
+        ERR("wrong overlay register read - addr : %d\n", (int)addr);
+        break;
+    }
+
+    return 0;
+}
+
+static void overlay_reg_write(void *opaque, target_phys_addr_t addr, uint64_t val, unsigned size)
+{
+    switch (addr) {
+    case OVERLAY_POWER:
+        overlay0_power = val;
+        if( !overlay0_power ) {
+               // clear the last overlay area.
+               memset( overlay_ptr, 0x00, ( OVERLAY_MEM_SIZE / 2 ) );
+        }
+        break;
+    case OVERLAY_POSITION:
+        overlay0_left = val & 0xFFFF;
+        overlay0_top = val >> 16;
+        break;
+    case OVERLAY_SIZE:
+        overlay0_width = val & 0xFFFF;
+        overlay0_height = val >> 16;
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_POWER:
+        overlay1_power = val;
+        if( !overlay1_power ) {
+               // clear the last overlay area.
+               memset( overlay_ptr + OVERLAY1_REG_OFFSET , 0x00, ( OVERLAY_MEM_SIZE / 2 ) );
+        }
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_POSITION:
+        overlay1_left = val & 0xFFFF;
+        overlay1_top = val >> 16;
+        break;
+    case OVERLAY1_REG_OFFSET + OVERLAY_SIZE:
+        overlay1_width = val & 0xFFFF;
+        overlay1_height = val >> 16;
+        break;
+    default:
+        ERR("wrong overlay register write - addr : %d\n", (int)addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps overlay_mmio_ops = {
+    .read = overlay_reg_read,
+    .write = overlay_reg_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int overlay_initfn(PCIDevice *dev)
+{
+    OverlayState *s = DO_UPCAST(OverlayState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_TIZEN);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIRTUAL_OVERLAY);
+    pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_OTHER);
+
+    memory_region_init_ram(&s->mem_addr, NULL, "maru_overlay.ram", OVERLAY_MEM_SIZE);
+    overlay_ptr = memory_region_get_ram_ptr(&s->mem_addr);
+
+    memory_region_init_io (&s->mmio_addr, &overlay_mmio_ops, s, "maru_overlay_mmio", OVERLAY_REG_SIZE);
+
+    /* setup memory space */
+    /* memory #0 device memory (overlay surface) */
+    /* memory #1 memory-mapped I/O */
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mem_addr);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_addr);
+
+    return 0;
+}
+
+int pci_maru_overlay_init(PCIBus *bus)
+{
+    pci_create_simple(bus, -1, QEMU_DEV_NAME);
+    return 0;
+}
+
+static PCIDeviceInfo overlay_info = {
+    .qdev.name    = QEMU_DEV_NAME,
+    .qdev.size    = sizeof(OverlayState),
+    .no_hotplug   = 1,
+    .init         = overlay_initfn,
+};
+
+static void overlay_register(void)
+{
+    pci_qdev_register(&overlay_info);
+}
+
+device_init(overlay_register);
diff --git a/tizen/src/hw/maru_overlay.h b/tizen/src/hw/maru_overlay.h
new file mode 100644 (file)
index 0000000..8d75bc3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Maru overlay device for VGA
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_OVERLAY_H_
+#define MARU_OVERLAY_H_
+
+#include "qemu-common.h"
+
+extern uint8_t* overlay_ptr;
+extern uint8_t overlay0_power;
+extern uint16_t overlay0_left;
+extern uint16_t overlay0_top;
+extern uint16_t overlay0_width;
+extern uint16_t overlay0_height;
+
+extern uint8_t overlay1_power;
+extern uint16_t overlay1_left;
+extern uint16_t overlay1_top;
+extern uint16_t overlay1_width;
+extern uint16_t overlay1_height;
+
+int pci_maru_overlay_init( PCIBus *bus );
+
+#endif /* MARU_OVERLAY_H_ */
diff --git a/tizen/src/hw/maru_pci_ids.h b/tizen/src/hw/maru_pci_ids.h
new file mode 100644 (file)
index 0000000..af9264e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Maru PCI device id
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun <dk77.yun@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_PCI_IDS_H_
+#define MARU_PCI_IDS_H_
+
+#define PCI_VENDOR_ID_TIZEN              0xC9B5
+#define PCI_DEVICE_ID_VIRTUAL_OVERLAY    0x1010
+#define PCI_DEVICE_ID_VIRTUAL_BRIGHTNESS 0x1014
+#define PCI_DEVICE_ID_VIRTUAL_CAMERA     0x1018
+#define PCI_DEVICE_ID_VIRTUAL_CODEC      0x101C
+
+#endif /* MARU_PCI_IDS_H_ */
index 3727c191accf0cf068f542427572b74d469b367b..18a8bafed73d36798c014374d30496e131802902 100644 (file)
@@ -2,7 +2,7 @@
  * Maru power management emulator
  * Based on qemu/hw/acpi_piix4.c
  *
- * Copyright (C) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
  * Hyunjun Son <hj79.son@samsung.com>
@@ -37,7 +37,8 @@
 #include "acpi.h"
 #include "sysemu.h"
 #include "range.h"
-#include "tizen/src/debug_ch.h"
+#include "ioport.h"
+#include "debug_ch.h"
 
 //#define DEBUG
 
 # define PIIX4_DPRINTF(format, ...)     do { } while (0)
 #endif
 
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, maru_pm);
+
 #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
 
-/* define debug channel */
-MULTI_DEBUG_CHANNEL(qemu, tizen_acpi_piix4);
-
-struct gpe_regs {
-    uint16_t sts; /* status */
-    uint16_t en;  /* enabled */
-};
-
 struct pci_status {
     uint32_t up;
     uint32_t down;
@@ -72,25 +69,23 @@ 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;
+    Notifier machine_ready;
 
     /* for pci hotplug */
-    struct gpe_regs gpe;
+    ACPIGPE gpe;
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
 } PIIX4PMState;
@@ -103,55 +98,62 @@ 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(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(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) &
+    acpi_state = s;
+
+    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);
 }
 
+static void maru_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:
+#if 0 // changed suspend operation for emulator
+            /* 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);
+#else
+            INFO( "suspend is requested.\n" );
+            is_suspended = 1;
+            break;
+#endif// end : changed suspend operation for emulator
+        default:
+            break;
+        }
+    }
+}
+
 static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
                             uint64_t val)
 {
@@ -164,60 +166,25 @@ 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(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:
-#if 0 // changed suspend operation for emulator
-                    /* 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);
-                    }
+#if 0
+        acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
 #else
-                    INFO( "suspend is requested.\n" );
-                    is_suspended = 1;
-                    break;
+        maru_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
 #endif
-                default:
-                    break;
-                }
-            }
-        }
         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,
@@ -228,22 +195,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;
 }
 
@@ -257,11 +224,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) {
@@ -306,14 +269,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()
     }
 };
@@ -338,13 +312,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()
@@ -359,7 +333,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
 
     s->pci0_hotplug_enable = ~0;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
         PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
         int slot = PCI_SLOT(pdev->devfn);
@@ -390,13 +364,23 @@ 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;
+
+    acpi_pm1_evt_power_down(pm1a, tmr);
+}
+
+static void piix4_pm_machine_ready(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+    pci_conf[0x63] = 0x60;
+    pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
+    (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
 
-    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);
-    }
 }
 
 static int piix4_pm_initfn(PCIDevice *dev)
@@ -405,13 +389,9 @@ static int piix4_pm_initfn(PCIDevice *dev)
     uint8_t *pci_conf;
 
     pci_conf = s->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_3);
     pci_conf[0x06] = 0x80;
     pci_conf[0x07] = 0x02;
-    pci_conf[0x08] = 0x03; // revision number
     pci_conf[0x09] = 0x00;
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
     pci_conf[0x3d] = 0x01; // interrupt pin 1
 
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
@@ -429,22 +409,20 @@ static int piix4_pm_initfn(PCIDevice *dev)
 
     /* XXX: which specification is used ? The i82731AB has different
        mappings */
-    pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
-    pci_conf[0x63] = 0x60;
-    pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
-    (serial_hds[1] != NULL ? 0x90 : 0);
-
     pci_conf[0x90] = s->smb_io_base | 1;
     pci_conf[0x91] = s->smb_io_base >> 8;
     pci_conf[0xd2] = 0x09;
     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(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);
 
     pm_smbus_init(&s->dev.qdev, &s->smb);
+    s->machine_ready.notify = piix4_pm_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
     qemu_register_reset(piix4_reset, s);
     piix4_acpi_system_hot_add_init(dev->bus, s);
 
@@ -458,31 +436,33 @@ i2c_bus *maru_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
     PCIDevice *dev;
     PIIX4PMState *s;
 
-    dev = pci_create(bus, devfn, "TIZEN-PIIX4_PM");
+    dev = pci_create(bus, devfn, "MARU_PM");
     qdev_prop_set_uint32(&dev->qdev, "smb_io_base", 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;
 
-    acpi_state = s;
-
     qdev_init_nofail(&dev->qdev);
 
     return s->smb.smbus;
 }
 
 static PCIDeviceInfo piix4_pm_info = {
-    .qdev.name          = "TIZEN-PIIX4_PM",
-    .qdev.desc          = "TIZEN PM",
+    .qdev.name          = "MARU_PM",
+    .qdev.desc          = "PM",
     .qdev.size          = sizeof(PIIX4PMState),
     .qdev.vmsd          = &vmstate_acpi,
     .qdev.no_user       = 1,
     .no_hotplug         = 1,
     .init               = piix4_pm_initfn,
     .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_INTEL,
+    .device_id          = PCI_DEVICE_ID_INTEL_82371AB_3,
+    .revision           = 0x03,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
     .qdev.props         = (Property[]) {
         DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
         DEFINE_PROP_END_OF_LIST(),
@@ -496,74 +476,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);
@@ -614,11 +540,13 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
     BusState *bus = opaque;
     DeviceState *qdev, *next;
     PCIDevice *dev;
+    PCIDeviceInfo *info;
     int slot = ffs(val) - 1;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         dev = DO_UPCAST(PCIDevice, qdev, qdev);
-        if (PCI_SLOT(dev->devfn) == slot) {
+        info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
             qdev_free(qdev);
         }
     }
@@ -646,8 +574,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);
@@ -663,13 +592,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);
 }
 
@@ -706,16 +635,16 @@ void resume( void ) {
 
     if ( acpi_state ) {
 
-        if ( acpi_state->cmos_s3 ) {
-            acpi_state->pmsts |= ( ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS );
-            INFO( "raise irq for ACPI wake." );
-            qemu_irq_raise( acpi_state->cmos_s3 );
+        if ( acpi_state->pm1_cnt.cmos_s3 ) {
+            acpi_state->pm1a.sts |= ( ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS );
+            INFO( "raise irq for ACPI wake.\n" );
+            qemu_irq_raise( acpi_state->pm1_cnt.cmos_s3 );
         }else {
-            ERR( "acpi cmos_s3 is NULL." );
+            ERR( "acpi cmos_s3 is NULL.\n" );
         }
 
     }else {
-        ERR( "acpi state is NULL." );
+        ERR( "acpi state is NULL.\n" );
     }
 
 }
index c60002be43d68036191c6ff484acb8ade4c4fb4f..5552e9e831eddcaad840cc2b6d25baf4ee88ff7d 100644 (file)
@@ -2,7 +2,7 @@
  * Maru power management emulator
  * Based on qemu/hw/acpi_piix4.h
  *
- * Copyright (C) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
  * Hyunjun Son <hj79.son@samsung.com>
index 56253012be92444a237267da30242e650d35f8ca..d94fe50ee977ae90e9ae7a01a1f16248cf11411d 100644 (file)
@@ -6,8 +6,7 @@
  *
  * Contact:
  *  GiWoong Kim <giwoong.kim@samsung.com>
- *  Hyunjun Son <hj79.son@samsung.com>
- *  DongKyun Yun <dk77.yun@samsung.com>
+ *  HyunJun Son <hj79.son@samsung.com>
  *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  *
  */
 
-#include "hw.h"
-#include "console.h"
-#include "usb.h"
-#include "usb-desc.h"
 
+#include "maru_touchscreen.h"
+#include "debug_ch.h"
 
-typedef struct USBTouchscreenState {
-    USBDevice dev;
-    QEMUPutMouseEntry *eh_entry;
+MULTI_DEBUG_CHANNEL(qemu, touchscreen);
 
-    int32_t dx, dy, dz, buttons_state;
-    int8_t mouse_grabbed;
-    int8_t changed;
-} USBTouchscreenState;
 
-/* This structure must match the kernel definitions */
-typedef struct USBEmulTouchscreenPacket {
-    uint16_t x, y, z;
-    uint8_t state;
-} USBEmulTouchscreenPacket;
+#define MAX_TOUCH_EVENT_CNT  128
 
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-#define EMUL_TOUCHSCREEN_PACKET_LEN 7
-#define TOUCHSCREEN_RESOLUTION_X 5040
-#define TOUCHSCREEN_RESOLUTION_Y 3780
+static QTAILQ_HEAD(, TouchEventEntry) events_queue =
+    QTAILQ_HEAD_INITIALIZER(events_queue);
 
-enum {
-    STR_MANUFACTURER = 1,
-    STR_PRODUCT,
-    STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
-    [STR_PRODUCT]          = "Maru Virtual Touchscreen",
-    [STR_SERIALNUMBER]     = "1",
-};
-
-static const USBDescIface desc_iface_touchscreen = {
-    .bInterfaceNumber              = 0,
-    .bNumEndpoints                 = 1,
-    .bInterfaceClass               = USB_CLASS_HID,
-    .bInterfaceSubClass            = 0x01, /* boot */
-    .bInterfaceProtocol            = 0x02,
-    .ndesc                         = 1,
-    .descs = (USBDescOther[]) {
-        {
-            /* HID descriptor */
-            .data = (uint8_t[]) {
-                0x09,          /*  u8  bLength */
-                0x21,          /*  u8  bDescriptorType */
-                0x01, 0x10,    /*  u16 HID_class */
-                0x00,          /*  u8  country_code */
-                0x01,          /*  u8  num_descriptors */
-                0x22,          /*  u8  type: Report */
-                0x6e, 0,       /*  u16 len */
-            },
-        },
-    },
-    .eps = (USBDescEndpoint[]) {
-        {
-            .bEndpointAddress      = USB_DIR_IN | 0x01,
-            .bmAttributes          = USB_ENDPOINT_XFER_INT,
-            .wMaxPacketSize        = 8,
-            .bInterval             = 0x0a,
-        },
-    },
-};
-
-static const USBDescDevice desc_device_touchscreen = {
-    .bcdUSB                        = 0x0110,
-    .bMaxPacketSize0               = EMUL_TOUCHSCREEN_PACKET_LEN + 1,
-    .bNumConfigurations            = 1,
-    .confs = (USBDescConfig[]) {
-        {
-            .bNumInterfaces        = 1,
-            .bConfigurationValue   = 1,
-            .bmAttributes          = 0x80,
-            .bMaxPower             = 40,
-            .ifs = &desc_iface_touchscreen,
-        },
-    },
-};
-
-static const USBDesc desc_touchscreen = {
-    .id = {
-        .idVendor          = 0x056a,
-        .idProduct         = 0x0000,
-        .bcdDevice         = 0x0010,
-        .iManufacturer     = STR_MANUFACTURER,
-        .iProduct          = STR_PRODUCT,
-        .iSerialNumber     = STR_SERIALNUMBER,
-    },
-    .full = &desc_device_touchscreen,
-    .str = desc_strings,
-};
+static unsigned int event_cnt = 0;
+static unsigned int _processed_buf_cnt = 0;
+static TouchEventEntry _event_buf[MAX_TOUCH_EVENT_CNT];
 
 static void usb_touchscreen_event(void *opaque, int x, int y, int z, int buttons_state)
 {
+    TouchEventEntry *te;
     USBTouchscreenState *s = opaque;
 
-    /* scale to resolution */
-    s->dx = (x * TOUCHSCREEN_RESOLUTION_X / 0x7FFF);
-    s->dy = (y * TOUCHSCREEN_RESOLUTION_Y / 0x7FFF);
-    s->dz = z;
-    s->buttons_state = buttons_state;
+    pthread_mutex_lock(&event_mutex);
+    if (event_cnt >= MAX_TOUCH_EVENT_CNT) {
+        pthread_mutex_unlock(&event_mutex);
+        INFO("full touch event queue, lose event\n", event_cnt);
+        return;
+    }
+
+    //using prepared memory
+    te = &(_event_buf[_processed_buf_cnt % MAX_TOUCH_EVENT_CNT]);
+    _processed_buf_cnt++;
+
+    /* mouse event is copied into the packet */
+    te->index = ++event_cnt;
+    te->queue_packet.x = x; //(x * TOUCHSCREEN_RESOLUTION_X / 0x7FFF);
+    te->queue_packet.y = y; //(y * TOUCHSCREEN_RESOLUTION_Y / 0x7FFF);
+    te->queue_packet.z = z;
+    te->queue_packet.state = buttons_state;
+
+    QTAILQ_INSERT_TAIL(&events_queue, te, node);
     s->changed = 1;
+    pthread_mutex_unlock(&event_mutex);
+
+    TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n", te->index, x, y, z, buttons_state);
 }
 
 static int usb_touchscreen_poll(USBTouchscreenState *s, uint8_t *buf, int len)
@@ -177,32 +115,68 @@ static void usb_touchscreen_handle_reset(USBDevice *dev)
 {
     USBTouchscreenState *s = (USBTouchscreenState *) dev;
 
+    pthread_mutex_lock(&event_mutex);
+
     s->dx = 0;
     s->dy = 0;
     s->dz = 0;
     s->buttons_state = 0;
+
+    event_cnt = 0;
+    _processed_buf_cnt = 0;
+
+    pthread_mutex_unlock(&event_mutex);
 }
 
-static int usb_touchscreen_handle_control(USBDevice *dev,
+static int usb_touchscreen_handle_control(USBDevice *dev, USBPacket *p,
     int request, int value, int index, int length, uint8_t *data)
 {
-    return usb_desc_handle_control(dev, request, value, index, length, data);
+    return usb_desc_handle_control(dev, p, request, value, index, length, data);
 }
 
 static int usb_touchscreen_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBTouchscreenState *s = (USBTouchscreenState *) dev;
+    uint8_t buf[p->iov.size];
     int ret = 0;
 
     switch (p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
+            pthread_mutex_lock(&event_mutex);
+
             if (s->changed == 0) {
+                pthread_mutex_unlock(&event_mutex);
                 return USB_RET_NAK;
             }
 
-            s->changed = 0;
-            ret = usb_touchscreen_poll(s, p->data, p->len);
+            if (event_cnt != 0) {
+                if (!QTAILQ_EMPTY(&events_queue)) {
+                    TouchEventEntry *te = QTAILQ_FIRST(&events_queue);
+
+                    s->dx = te->queue_packet.x;
+                    s->dy = te->queue_packet.y;
+                    s->dz = te->queue_packet.z;
+                    s->buttons_state = te->queue_packet.state;
+
+                    QTAILQ_REMOVE(&events_queue, te, node);
+                    event_cnt--;
+                    TRACE("processed touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
+                        te->index, s->dx, s->dy, s->dz, s->buttons_state);
+
+                    if (QTAILQ_EMPTY(&events_queue)) {
+                        s->changed = 0;
+                        TRACE("processed all touch events (%d)\n", event_cnt);
+                    }
+                }
+            } else {
+                s->changed = 0;
+            }
+
+            pthread_mutex_unlock(&event_mutex);
+
+            ret = usb_touchscreen_poll(s, buf, p->iov.size);
+            usb_packet_copy(p, buf, ret);
             break;
         }
         /* Fall through */
@@ -228,7 +202,11 @@ static int usb_touchscreen_initfn(USBDevice *dev)
 {
     USBTouchscreenState *s = DO_UPCAST(USBTouchscreenState, dev, dev);
     usb_desc_init(dev);
+
+    pthread_mutex_lock(&event_mutex);
     s->changed = 1;
+    pthread_mutex_unlock(&event_mutex);
+
     return 0;
 }
 
@@ -248,7 +226,10 @@ static int touchscreen_post_load(void *opaque, int version_id)
 {
     USBTouchscreenState *s = (USBTouchscreenState *)opaque;
 
+    pthread_mutex_lock(&event_mutex);
     s->changed = 1;
+    pthread_mutex_unlock(&event_mutex);
+
     if (s->mouse_grabbed == 1) {
         s->eh_entry = qemu_add_mouse_event_handler(usb_touchscreen_event, s, 1, "QEMU Virtual touchscreen");
         qemu_activate_mouse_event_handler(s->eh_entry);
diff --git a/tizen/src/hw/maru_touchscreen.h b/tizen/src/hw/maru_touchscreen.h
new file mode 100644 (file)
index 0000000..f1fcade
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Maru Virtual USB Touchscreen emulation.
+ * Based on hw/usb-wacom.c:
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  GiWoong Kim <giwoong.kim@samsung.com>
+ *  HyunJun Son <hj79.son@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_TOUCH_H_
+#define MARU_TOUCH_H_
+
+#include <pthread.h>
+#include "hw.h"
+#include "console.h"
+#include "usb.h"
+#include "usb-desc.h"
+
+
+typedef struct USBTouchscreenState {
+    USBDevice dev;
+    QEMUPutMouseEntry *eh_entry;
+
+    int32_t dx, dy, dz, buttons_state;
+    int8_t mouse_grabbed;
+    int8_t changed;
+} USBTouchscreenState;
+
+/* This structure must match the kernel definitions */
+typedef struct USBEmulTouchscreenPacket {
+    uint16_t x, y, z;
+    uint8_t state;
+} USBEmulTouchscreenPacket;
+
+
+#define EMUL_TOUCHSCREEN_PACKET_LEN 7
+#define TOUCHSCREEN_RESOLUTION_X 5040
+#define TOUCHSCREEN_RESOLUTION_Y 3780
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]          = "Maru Virtual Touchscreen",
+    [STR_SERIALNUMBER]     = "1",
+};
+
+static const USBDescIface desc_iface_touchscreen = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HID,
+    .bInterfaceSubClass            = 0x01, /* boot */
+    .bInterfaceProtocol            = 0x02,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* HID descriptor */
+            .data = (uint8_t[]) {
+                0x09,          /*  u8  bLength */
+                0x21,          /*  u8  bDescriptorType */
+                0x01, 0x10,    /*  u16 HID_class */
+                0x00,          /*  u8  country_code */
+                0x01,          /*  u8  num_descriptors */
+                0x22,          /*  u8  type: Report */
+                0x6e, 0,       /*  u16 len */
+            },
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_touchscreen = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = EMUL_TOUCHSCREEN_PACKET_LEN + 1,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0x80,
+            .bMaxPower             = 40,
+            .nif = 1,
+            .ifs = &desc_iface_touchscreen,
+        },
+    },
+};
+
+static const USBDesc desc_touchscreen = {
+    .id = {
+        .idVendor          = 0x056a,
+        .idProduct         = 0x0000,
+        .bcdDevice         = 0x0010,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_touchscreen,
+    .str = desc_strings,
+};
+
+typedef struct TouchEventEntry {
+    USBEmulTouchscreenPacket queue_packet;
+    int index;
+
+    /* used internally by qemu for handling mice */
+    QTAILQ_ENTRY(TouchEventEntry) node;
+} TouchEventEntry;
+
+#endif /* MARU_TOUCH_H_ */
diff --git a/tizen/src/hw/maru_vga.c b/tizen/src/hw/maru_vga.c
new file mode 100644 (file)
index 0000000..d8451c5
--- /dev/null
@@ -0,0 +1,1599 @@
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga.c
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "pc.h"
+#include "pci.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+#include "qemu-timer.h"
+#include "maru_vga_int.h"
+#include "maru_brightness.h"
+#include "maru_overlay.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, maru_vga);
+
+//#define DEBUG_VGA
+//#define DEBUG_VGA_MEM
+//#define DEBUG_VGA_REG
+
+//#define DEBUG_BOCHS_VBE
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+        (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+        (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+        (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+        (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) (x)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define BIG 1
+#else
+#define BIG 0
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
+#else
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+#endif
+
+#define MARU_VGA
+
+static const uint32_t mask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+static uint32_t expand4[256];
+static uint16_t expand2[256];
+static uint8_t expand4to8[16];
+
+static void vga_screen_dump(void *opaque, const char *filename);
+static const char *screen_dump_filename;
+static DisplayChangeListener *screen_dump_dcl;
+
+static void vga_dumb_update_retrace_info(VGACommonState *s)
+{
+    (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+    int htotal_chars;
+    int hretr_start_char;
+    int hretr_skew_chars;
+    int hretr_end_char;
+
+    int vtotal_lines;
+    int vretr_start_line;
+    int vretr_end_line;
+
+    int dots;
+#if 0
+    int div2, sldiv2;
+#endif
+    int clocking_mode;
+    int clock_sel;
+    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+    int64_t chars_per_sec;
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+    htotal_chars = s->cr[0x00] + 5;
+    hretr_start_char = s->cr[0x04];
+    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
+    hretr_end_char = s->cr[0x05] & 0x1f;
+
+    vtotal_lines = (s->cr[0x06]
+                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
+        ;
+    vretr_start_line = s->cr[0x10]
+        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
+        ;
+    vretr_end_line = s->cr[0x11] & 0xf;
+
+
+
+    clocking_mode = (s->sr[0x01] >> 3) & 1;
+    clock_sel = (s->msr >> 2) & 3;
+    dots = (s->msr & 1) ? 8 : 9;
+
+    chars_per_sec = clk_hz[clock_sel] / dots;
+
+    htotal_chars <<= clocking_mode;
+
+    r->total_chars = vtotal_lines * htotal_chars;
+    if (r->freq) {
+        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+    } else {
+        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+    }
+
+    r->vstart = vretr_start_line;
+    r->vend = r->vstart + vretr_end_line + 1;
+
+    r->hstart = hretr_start_char + hretr_skew_chars;
+    r->hend = r->hstart + hretr_end_char + 1;
+    r->htotal = htotal_chars;
+
+#if 0
+    div2 = (s->cr[0x17] >> 2) & 1;
+    sldiv2 = (s->cr[0x17] >> 3) & 1;
+    printf (
+        "hz=%f\n"
+        "htotal = %d\n"
+        "hretr_start = %d\n"
+        "hretr_skew = %d\n"
+        "hretr_end = %d\n"
+        "vtotal = %d\n"
+        "vretr_start = %d\n"
+        "vretr_end = %d\n"
+        "div2 = %d sldiv2 = %d\n"
+        "clocking_mode = %d\n"
+        "clock_sel = %d %d\n"
+        "dots = %d\n"
+        "ticks/char = %" PRId64 "\n"
+        "\n",
+        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+        htotal_chars,
+        hretr_start_char,
+        hretr_skew_chars,
+        hretr_end_char,
+        vtotal_lines,
+        vretr_start_line,
+        vretr_end_line,
+        div2, sldiv2,
+        clocking_mode,
+        clock_sel,
+        clk_hz[clock_sel],
+        dots,
+        r->ticks_per_char
+        );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGACommonState *s)
+{
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+    if (r->total_chars) {
+        int cur_line, cur_line_char, cur_char;
+        int64_t cur_tick;
+
+        cur_tick = qemu_get_clock_ns(vm_clock);
+
+        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+        cur_line = cur_char / r->htotal;
+
+        if (cur_line >= r->vstart && cur_line <= r->vend) {
+            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+        } else {
+            cur_line_char = cur_char % r->htotal;
+            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+                val |= ST01_DISP_ENABLE;
+            }
+        }
+
+        return val;
+    } else {
+        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+    }
+}
+
+static uint8_t vga_dumb_retrace(VGACommonState *s)
+{
+    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
+typedef void maru_vga_draw_glyph8_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void maru_vga_draw_glyph9_func(uint8_t *d, int linesize,
+                                  const uint8_t *font_ptr, int h,
+                                  uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void maru_vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+                                const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "maru_vga_template.h"
+
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel8(r, g, b);
+    col |= col << 8;
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32(r, g, b);
+    return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32bgr(r, g, b);
+    return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    for(i = 0; i < 16; i++) {
+        v = s->ar[i];
+        if (s->ar[0x10] & 0x80)
+            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
+        else
+            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
+        v = v * 3;
+        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                              c6_to_8(s->palette[v + 1]),
+                              c6_to_8(s->palette[v + 2]));
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+    }
+    return full_update;
+}
+
+/* return true if the palette was modified */
+static int update_palette256(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    v = 0;
+    for(i = 0; i < 256; i++) {
+        if (s->dac_8bit) {
+          col = s->rgb_to_pixel(s->palette[v],
+                                s->palette[v + 1],
+                                s->palette[v + 2]);
+        } else {
+          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                                c6_to_8(s->palette[v + 1]),
+                                c6_to_8(s->palette[v + 2]));
+        }
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+        v += 3;
+    }
+    return full_update;
+}
+
+static void vga_get_offsets(VGACommonState *s,
+                            uint32_t *pline_offset,
+                            uint32_t *pstart_addr,
+                            uint32_t *pline_compare)
+{
+    uint32_t start_addr, line_offset, line_compare;
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        line_offset = s->vbe_line_offset;
+        start_addr = s->vbe_start_addr;
+        line_compare = 65535;
+    } else
+#endif
+    {
+        /* compute line_offset in bytes */
+        line_offset = s->cr[0x13];
+        line_offset <<= 3;
+
+        /* starting address */
+        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
+
+        /* line compare */
+        line_compare = s->cr[0x18] |
+            ((s->cr[0x07] & 0x10) << 4) |
+            ((s->cr[0x09] & 0x40) << 3);
+    }
+    *pline_offset = line_offset;
+    *pstart_addr = start_addr;
+    *pline_compare = line_compare;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGACommonState *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
+
+    full_update = 0;
+
+    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+    if (line_offset != s->line_offset ||
+        start_addr != s->start_addr ||
+        line_compare != s->line_compare) {
+        s->line_offset = line_offset;
+        s->start_addr = start_addr;
+        s->line_compare = line_compare;
+        full_update = 1;
+    }
+    return full_update;
+}
+
+#define NB_DEPTHS 7
+
+static inline int get_depth_index(DisplayState *s)
+{
+    switch(ds_get_bits_per_pixel(s)) {
+    default:
+    case 8:
+        return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(s->surface))
+            return 4;
+        else
+            return 3;
+    }
+}
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph8_table[NB_DEPTHS] = {
+    maru_vga_draw_glyph8_8,
+    maru_vga_draw_glyph8_16,
+    maru_vga_draw_glyph8_16,
+    maru_vga_draw_glyph8_32,
+    maru_vga_draw_glyph8_32,
+    maru_vga_draw_glyph8_16,
+    maru_vga_draw_glyph8_16,
+};
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph16_table[NB_DEPTHS] = {
+    maru_vga_draw_glyph16_8,
+    maru_vga_draw_glyph16_16,
+    maru_vga_draw_glyph16_16,
+    maru_vga_draw_glyph16_32,
+    maru_vga_draw_glyph16_32,
+    maru_vga_draw_glyph16_16,
+    maru_vga_draw_glyph16_16,
+};
+
+static maru_vga_draw_glyph9_func * const maru_vga_draw_glyph9_table[NB_DEPTHS] = {
+    maru_vga_draw_glyph9_8,
+    maru_vga_draw_glyph9_16,
+    maru_vga_draw_glyph9_16,
+    maru_vga_draw_glyph9_32,
+    maru_vga_draw_glyph9_32,
+    maru_vga_draw_glyph9_16,
+    maru_vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+                                    int *pcwidth, int *pcheight)
+{
+    int width, cwidth, height, cheight;
+
+    /* total width & height */
+    cheight = (s->cr[9] & 0x1f) + 1;
+    cwidth = 8;
+    if (!(s->sr[1] & 0x01))
+        cwidth = 9;
+    if (s->sr[1] & 0x08)
+        cwidth = 16; /* NOTE: no 18 pixel wide */
+    width = (s->cr[0x01] + 1);
+    if (s->cr[0x06] == 100) {
+        /* ugly hack for CGA 160x100x16 - explain me the logic */
+        height = 100;
+    } else {
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
+            ((s->cr[0x07] & 0x40) << 3);
+        height = (height + 1) / cheight;
+    }
+
+    *pwidth = width;
+    *pheight = height;
+    *pcwidth = cwidth;
+    *pcheight = cheight;
+}
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
+    rgb_to_pixel8_dup,
+    rgb_to_pixel15_dup,
+    rgb_to_pixel16_dup,
+    rgb_to_pixel32_dup,
+    rgb_to_pixel32bgr_dup,
+    rgb_to_pixel15bgr_dup,
+    rgb_to_pixel16bgr_dup,
+};
+
+/*
+ * Text mode update
+ * Missing:
+ * - double scan
+ * - double width
+ * - underline
+ * - flashing
+ */
+static void vga_draw_text(VGACommonState *s, int full_update)
+{
+    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+    int cx_min, cx_max, linesize, x_incr, line, line1;
+    uint32_t offset, fgcol, bgcol, v, cursor_offset;
+    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
+    const uint8_t *font_ptr, *font_base[2];
+    int dup9, line_offset, depth_index;
+    uint32_t *palette;
+    uint32_t *ch_attr_ptr;
+    maru_vga_draw_glyph8_func *maru_vga_draw_glyph8;
+    maru_vga_draw_glyph9_func *maru_vga_draw_glyph9;
+
+    /* compute font data address (in plane 2) */
+    v = s->sr[3];
+    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+    if (offset != s->font_offsets[0]) {
+        s->font_offsets[0] = offset;
+        full_update = 1;
+    }
+    font_base[0] = s->vram_ptr + offset;
+
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    font_base[1] = s->vram_ptr + offset;
+    if (offset != s->font_offsets[1]) {
+        s->font_offsets[1] = offset;
+        full_update = 1;
+    }
+    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
+        /* if the plane 2 was modified since the last display, it
+           indicates the font may have been modified */
+        s->plane_updated = 0;
+        full_update = 1;
+    }
+    full_update |= update_basic_params(s);
+
+    line_offset = s->line_offset;
+
+    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
+    if (width != s->last_width || height != s->last_height ||
+        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+        s->last_scr_width = width * cw;
+        s->last_scr_height = height * cheight;
+        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
+        s->last_depth = 0;
+        s->last_width = width;
+        s->last_height = height;
+        s->last_ch = cheight;
+        s->last_cw = cw;
+        full_update = 1;
+    }
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+    full_update |= update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+
+    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+    if (cursor_offset != s->cursor_offset ||
+        s->cr[0xa] != s->cursor_start ||
+        s->cr[0xb] != s->cursor_end) {
+      /* if the cursor position changed, we update the old and new
+         chars */
+        if (s->cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[s->cursor_offset] = -1;
+        if (cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[cursor_offset] = -1;
+        s->cursor_offset = cursor_offset;
+        s->cursor_start = s->cr[0xa];
+        s->cursor_end = s->cr[0xb];
+    }
+    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
+
+    depth_index = get_depth_index(s->ds);
+    if (cw == 16)
+        maru_vga_draw_glyph8 = maru_vga_draw_glyph16_table[depth_index];
+    else
+        maru_vga_draw_glyph8 = maru_vga_draw_glyph8_table[depth_index];
+    maru_vga_draw_glyph9 = maru_vga_draw_glyph9_table[depth_index];
+
+    dest = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
+    ch_attr_ptr = s->last_ch_attr;
+    line = 0;
+    offset = s->start_addr * 4;
+    for(cy = 0; cy < height; cy++) {
+        d1 = dest;
+        src = s->vram_ptr + offset;
+        cx_min = width;
+        cx_max = -1;
+        for(cx = 0; cx < width; cx++) {
+            ch_attr = *(uint16_t *)src;
+            if (full_update || ch_attr != *ch_attr_ptr) {
+                if (cx < cx_min)
+                    cx_min = cx;
+                if (cx > cx_max)
+                    cx_max = cx;
+                *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+                ch = ch_attr >> 8;
+                cattr = ch_attr & 0xff;
+#else
+                ch = ch_attr & 0xff;
+                cattr = ch_attr >> 8;
+#endif
+                font_ptr = font_base[(cattr >> 3) & 1];
+                font_ptr += 32 * 4 * ch;
+                bgcol = palette[cattr >> 4];
+                fgcol = palette[cattr & 0x0f];
+                if (cw != 9) {
+                    maru_vga_draw_glyph8(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol);
+                } else {
+                    dup9 = 0;
+                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+                        dup9 = 1;
+                    maru_vga_draw_glyph9(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol, dup9);
+                }
+                if (src == cursor_ptr &&
+                    !(s->cr[0x0a] & 0x20)) {
+                    int line_start, line_last, h;
+                    /* draw the cursor */
+                    line_start = s->cr[0x0a] & 0x1f;
+                    line_last = s->cr[0x0b] & 0x1f;
+                    /* XXX: check that */
+                    if (line_last > cheight - 1)
+                        line_last = cheight - 1;
+                    if (line_last >= line_start && line_start < cheight) {
+                        h = line_last - line_start + 1;
+                        d = d1 + linesize * line_start;
+                        if (cw != 9) {
+                            maru_vga_draw_glyph8(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol);
+                        } else {
+                            maru_vga_draw_glyph9(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol, 1);
+                        }
+                    }
+                }
+            }
+            d1 += x_incr;
+            src += 4;
+            ch_attr_ptr++;
+        }
+        if (cx_max != -1) {
+            dpy_update(s->ds, cx_min * cw, cy * cheight,
+                       (cx_max - cx_min + 1) * cw, cheight);
+        }
+        dest += linesize * cheight;
+        line1 = line + cheight;
+        offset += line_offset;
+        if (line < s->line_compare && line1 >= s->line_compare) {
+            offset = 0;
+        }
+        line = line1;
+    }
+}
+
+enum {
+    maru_vga_draw_line2,
+    maru_vga_draw_line2D2,
+    maru_vga_draw_line4,
+    maru_vga_draw_line4D2,
+    maru_vga_draw_line8D2,
+    maru_vga_draw_line8,
+    maru_vga_draw_line15,
+    maru_vga_draw_line16,
+    maru_vga_draw_line24,
+    maru_vga_draw_line32,
+    maru_vga_draw_line_NB,
+};
+
+static maru_vga_draw_line_func * const maru_vga_draw_line_table[NB_DEPTHS * maru_vga_draw_line_NB] = {
+    maru_vga_draw_line2_8,
+    maru_vga_draw_line2_16,
+    maru_vga_draw_line2_16,
+    maru_vga_draw_line2_32,
+    maru_vga_draw_line2_32,
+    maru_vga_draw_line2_16,
+    maru_vga_draw_line2_16,
+
+    maru_vga_draw_line2d2_8,
+    maru_vga_draw_line2d2_16,
+    maru_vga_draw_line2d2_16,
+    maru_vga_draw_line2d2_32,
+    maru_vga_draw_line2d2_32,
+    maru_vga_draw_line2d2_16,
+    maru_vga_draw_line2d2_16,
+
+    maru_vga_draw_line4_8,
+    maru_vga_draw_line4_16,
+    maru_vga_draw_line4_16,
+    maru_vga_draw_line4_32,
+    maru_vga_draw_line4_32,
+    maru_vga_draw_line4_16,
+    maru_vga_draw_line4_16,
+
+    maru_vga_draw_line4d2_8,
+    maru_vga_draw_line4d2_16,
+    maru_vga_draw_line4d2_16,
+    maru_vga_draw_line4d2_32,
+    maru_vga_draw_line4d2_32,
+    maru_vga_draw_line4d2_16,
+    maru_vga_draw_line4d2_16,
+
+    maru_vga_draw_line8d2_8,
+    maru_vga_draw_line8d2_16,
+    maru_vga_draw_line8d2_16,
+    maru_vga_draw_line8d2_32,
+    maru_vga_draw_line8d2_32,
+    maru_vga_draw_line8d2_16,
+    maru_vga_draw_line8d2_16,
+
+    maru_vga_draw_line8_8,
+    maru_vga_draw_line8_16,
+    maru_vga_draw_line8_16,
+    maru_vga_draw_line8_32,
+    maru_vga_draw_line8_32,
+    maru_vga_draw_line8_16,
+    maru_vga_draw_line8_16,
+
+    maru_vga_draw_line15_8,
+    maru_vga_draw_line15_15,
+    maru_vga_draw_line15_16,
+    maru_vga_draw_line15_32,
+    maru_vga_draw_line15_32bgr,
+    maru_vga_draw_line15_15bgr,
+    maru_vga_draw_line15_16bgr,
+
+    maru_vga_draw_line16_8,
+    maru_vga_draw_line16_15,
+    maru_vga_draw_line16_16,
+    maru_vga_draw_line16_32,
+    maru_vga_draw_line16_32bgr,
+    maru_vga_draw_line16_15bgr,
+    maru_vga_draw_line16_16bgr,
+
+    maru_vga_draw_line24_8,
+    maru_vga_draw_line24_15,
+    maru_vga_draw_line24_16,
+    maru_vga_draw_line24_32,
+    maru_vga_draw_line24_32bgr,
+    maru_vga_draw_line24_15bgr,
+    maru_vga_draw_line24_16bgr,
+
+    maru_vga_draw_line32_8,
+    maru_vga_draw_line32_15,
+    maru_vga_draw_line32_16,
+    maru_vga_draw_line32_32,
+    maru_vga_draw_line32_32bgr,
+    maru_vga_draw_line32_15bgr,
+    maru_vga_draw_line32_16bgr,
+};
+
+static int vga_get_bpp(VGACommonState *s)
+{
+    int ret;
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+    } else
+#endif
+    {
+        ret = 0;
+    }
+    return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+    } else
+#endif
+    {
+        width = (s->cr[0x01] + 1) * 8;
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
+            ((s->cr[0x07] & 0x40) << 3);
+        height = (height + 1);
+    }
+    *pwidth = width;
+    *pheight = height;
+}
+
+static void vga_sync_dirty_bitmap(VGACommonState *s)
+{
+    memory_region_sync_dirty_bitmap(&s->vram);
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+    int y1, y, update, linesize, y_start, double_scan, mask, depth;
+    int width, height, shift_control, line_offset, bwidth, bits;
+    ram_addr_t page0, page1, page_min, page_max;
+    int disp_width, multi_scan, multi_run;
+    uint8_t *d;
+    uint32_t v, addr1, addr;
+    maru_vga_draw_line_func *maru_vga_draw_line;
+
+    full_update |= update_basic_params(s);
+
+    if (!full_update)
+        vga_sync_dirty_bitmap(s);
+
+    s->get_resolution(s, &width, &height);
+
+    disp_width = width;
+
+    shift_control = (s->gr[0x05] >> 5) & 3;
+    double_scan = (s->cr[0x09] >> 7);
+    if (shift_control != 1) {
+        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+    } else {
+        /* in CGA modes, multi_scan is ignored */
+        /* XXX: is it correct ? */
+        multi_scan = double_scan;
+    }
+    multi_run = multi_scan;
+    if (shift_control != s->shift_control ||
+        double_scan != s->double_scan) {
+        full_update = 1;
+        s->shift_control = shift_control;
+        s->double_scan = double_scan;
+    }
+
+    if (shift_control == 0) {
+        if (s->sr[0x01] & 8) {
+            disp_width <<= 1;
+        }
+    } else if (shift_control == 1) {
+        if (s->sr[0x01] & 8) {
+            disp_width <<= 1;
+        }
+    }
+
+    depth = s->get_bpp(s);
+    if (s->line_offset != s->last_line_offset ||
+        disp_width != s->last_width ||
+        height != s->last_height ||
+        s->last_depth != depth) {
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+        if (depth == 16 || depth == 32) {
+#else
+        if (depth == 32) {
+#endif
+            qemu_free_displaysurface(s->ds);
+
+#ifdef MARU_VGA // create new sufrace by malloc in MARU VGA
+            s->ds->surface = qemu_create_displaysurface( s->ds, disp_width, height );
+#else
+            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
+                    s->line_offset,
+                    s->vram_ptr + (s->start_addr * 4));
+#endif
+
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
+#endif
+            dpy_resize(s->ds);
+        } else {
+            qemu_console_resize(s->ds, disp_width, height);
+        }
+        s->last_scr_width = disp_width;
+        s->last_scr_height = height;
+        s->last_width = disp_width;
+        s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
+        full_update = 1;
+    } else if (is_buffer_shared(s->ds->surface) &&
+               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
+        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
+        dpy_setdata(s->ds);
+    }
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+
+    if (shift_control == 0) {
+        full_update |= update_palette16(s);
+        if (s->sr[0x01] & 8) {
+            v = maru_vga_draw_line4D2;
+        } else {
+            v = maru_vga_draw_line4;
+        }
+        bits = 4;
+    } else if (shift_control == 1) {
+        full_update |= update_palette16(s);
+        if (s->sr[0x01] & 8) {
+            v = maru_vga_draw_line2D2;
+        } else {
+            v = maru_vga_draw_line2;
+        }
+        bits = 4;
+    } else {
+        switch(s->get_bpp(s)) {
+        default:
+        case 0:
+            full_update |= update_palette256(s);
+            v = maru_vga_draw_line8D2;
+            bits = 4;
+            break;
+        case 8:
+            full_update |= update_palette256(s);
+            v = maru_vga_draw_line8;
+            bits = 8;
+            break;
+        case 15:
+            v = maru_vga_draw_line15;
+            bits = 16;
+            break;
+        case 16:
+            v = maru_vga_draw_line16;
+            bits = 16;
+            break;
+        case 24:
+            v = maru_vga_draw_line24;
+            bits = 24;
+            break;
+        case 32:
+            v = maru_vga_draw_line32;
+            bits = 32;
+            break;
+        }
+    }
+    maru_vga_draw_line = maru_vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
+
+    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
+        s->cursor_invalidate(s);
+
+    line_offset = s->line_offset;
+#if 0
+    printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
+           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
+#endif
+    addr1 = (s->start_addr * 4);
+    bwidth = (width * bits + 7) / 8;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
+    y1 = 0;
+    for(y = 0; y < height; y++) {
+        addr = addr1;
+        if (!(s->cr[0x17] & 1)) {
+            int shift;
+            /* CGA compatibility handling */
+            shift = 14 + ((s->cr[0x17] >> 6) & 1);
+            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+        }
+        if (!(s->cr[0x17] & 2)) {
+            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
+        }
+        page0 = addr & TARGET_PAGE_MASK;
+        page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
+        update = full_update |
+            memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
+            memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
+        if ((page1 - page0) > TARGET_PAGE_SIZE) {
+            /* if wide line, can use another page */
+            update |= memory_region_get_dirty(&s->vram,
+                                              page0 + TARGET_PAGE_SIZE,
+                                              DIRTY_MEMORY_VGA);
+        }
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+
+#ifdef MARU_VGA // needs full update
+        update |= 1;
+#endif
+
+        if (update) {
+            if (y_start < 0)
+                y_start = y;
+            if (page0 < page_min)
+                page_min = page0;
+            if (page1 > page_max)
+                page_max = page1;
+            if (!(is_buffer_shared(s->ds->surface))) {
+                maru_vga_draw_line(s, d, s->vram_ptr + addr, width);
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
+            }
+
+#ifdef MARU_VGA
+
+            int i;
+            uint8_t *fb_sub;
+            uint8_t *over_sub;
+            uint8_t *dst_sub;
+            uint8_t alpha, c_alpha;
+            uint32_t *dst;
+            uint16_t overlay_bottom;
+
+            if ( overlay0_power ) {
+
+                overlay_bottom = overlay0_top + overlay0_height;
+
+                if ( overlay0_top <= y && y < overlay_bottom ) {
+
+                    fb_sub = s->vram_ptr + addr + overlay0_left * 4;
+                    over_sub = overlay_ptr + ( y - overlay0_top ) * overlay0_width * 4;
+                    dst = (uint32_t*) ( s->ds->surface->data + addr + overlay0_left * 4 );
+
+                    for ( i = 0; i < overlay0_width; i++, fb_sub += 4, over_sub += 4, dst++ ) {
+
+                        alpha = fb_sub[3];
+                        c_alpha = 0xff - alpha;
+
+                        *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 )
+                            | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 )
+                            | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 );
+                    }
+
+                }
+
+            }
+
+            if ( overlay1_power ) {
+
+                overlay_bottom = overlay1_top + overlay1_height;
+
+                if ( overlay1_top <= y && y < overlay_bottom ) {
+
+                    fb_sub = s->vram_ptr + addr + overlay1_left * 4;
+                    over_sub = overlay_ptr + ( y - overlay1_top ) * overlay1_width * 4 + 0x00400000;
+                    dst = (uint32_t*) ( s->ds->surface->data + addr + overlay1_left * 4 );
+
+                    for ( i = 0; i < overlay1_width; i++, fb_sub += 4, over_sub += 4, dst++ ) {
+
+                        alpha = fb_sub[3];
+                        c_alpha = 0xff - alpha;
+
+                        *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 )
+                            | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 )
+                            | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 );
+                    }
+
+                }
+
+            }
+
+            if ( brightness_off ) {
+
+                dst_sub = s->ds->surface->data + addr;
+                dst = (uint32_t*) ( s->ds->surface->data + addr );
+
+                for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) {
+                    *dst = 0xFF000000; // black
+                }
+
+            } else  {
+
+                if ( brightness_level < BRIGHTNESS_MAX ) {
+
+                    alpha = brightness_tbl[brightness_level];
+
+                    dst_sub = s->ds->surface->data + addr;
+                    dst = (uint32_t*) ( s->ds->surface->data + addr );
+
+                    for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) {
+                        *dst = ( ( alpha * dst_sub[0] ) >> 8 )
+                                | ( ( alpha * dst_sub[1] ) & 0xFF00 )
+                                | ( ( ( alpha * dst_sub[2] ) & 0xFF00 ) << 8 );
+                    }
+                }
+
+            }
+
+#endif /* MARU_VGA */
+
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(s->ds, 0, y_start,
+                           disp_width, y - y_start);
+                y_start = -1;
+            }
+        }
+        if (!multi_run) {
+            mask = (s->cr[0x17] & 3) ^ 3;
+            if ((y1 & mask) == mask)
+                addr1 += line_offset;
+            y1++;
+            multi_run = multi_scan;
+        } else {
+            multi_run--;
+        }
+        /* line compare acts on the displayed lines */
+        if (y == s->line_compare)
+            addr1 = 0;
+        d += linesize;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(s->ds, 0, y_start,
+                   disp_width, y - y_start);
+    }
+
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        memory_region_reset_dirty(&s->vram,
+                                  page_min,
+                                  page_max + TARGET_PAGE_SIZE - page_min,
+                                  DIRTY_MEMORY_VGA);
+    }
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGACommonState *s, int full_update)
+{
+    int i, w, val;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+    if (ds_get_bits_per_pixel(s->ds) == 8)
+        val = s->rgb_to_pixel(0, 0, 0);
+    else
+        val = 0;
+    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+    d = ds_get_data(s->ds);
+    for(i = 0; i < s->last_scr_height; i++) {
+        memset(d, val, w);
+        d += ds_get_linesize(s->ds);
+    }
+    dpy_update(s->ds, 0, 0,
+               s->last_scr_width, s->last_scr_height);
+}
+
+#define GMODE_TEXT     0
+#define GMODE_GRAPH    1
+#define GMODE_BLANK 2
+
+static void vga_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    int full_update, graphic_mode;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (ds_get_bits_per_pixel(s->ds) == 0) {
+        /* nothing to do */
+    } else {
+        full_update = 0;
+        if (!(s->ar_index & 0x20)) {
+            graphic_mode = GMODE_BLANK;
+        } else {
+            graphic_mode = s->gr[6] & 1;
+        }
+        if (graphic_mode != s->graphic_mode) {
+            s->graphic_mode = graphic_mode;
+            full_update = 1;
+        }
+        switch(graphic_mode) {
+        case GMODE_TEXT:
+            vga_draw_text(s, full_update);
+            break;
+        case GMODE_GRAPH:
+            vga_draw_graphic(s, full_update);
+            break;
+        case GMODE_BLANK:
+        default:
+            vga_draw_blank(s, full_update);
+            break;
+        }
+    }
+}
+
+/* force a full display refresh */
+static void vga_invalidate_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+
+    s->last_width = -1;
+    s->last_height = -1;
+}
+
+
+#define TEXTMODE_X(x)   ((x) % width)
+#define TEXTMODE_Y(x)   ((x) / width)
+#define VMEM2CHTYPE(v)  ((v & 0xff0007ff) | \
+        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+    VGACommonState *s =  opaque;
+    int graphic_mode, i, cursor_offset, cursor_visible;
+    int cw, cheight, width, height, size, c_min, c_max;
+    uint32_t *src;
+    console_ch_t *dst, val;
+    char msg_buffer[80];
+    int full_update = 0;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (!(s->ar_index & 0x20)) {
+        graphic_mode = GMODE_BLANK;
+    } else {
+        graphic_mode = s->gr[6] & 1;
+    }
+    if (graphic_mode != s->graphic_mode) {
+        s->graphic_mode = graphic_mode;
+        full_update = 1;
+    }
+    if (s->last_width == -1) {
+        s->last_width = 0;
+        full_update = 1;
+    }
+
+    switch (graphic_mode) {
+    case GMODE_TEXT:
+        /* TODO: update palette */
+        full_update |= update_basic_params(s);
+
+        /* total width & height */
+        cheight = (s->cr[9] & 0x1f) + 1;
+        cw = 8;
+        if (!(s->sr[1] & 0x01))
+            cw = 9;
+        if (s->sr[1] & 0x08)
+            cw = 16; /* NOTE: no 18 pixel wide */
+        width = (s->cr[0x01] + 1);
+        if (s->cr[0x06] == 100) {
+            /* ugly hack for CGA 160x100x16 - explain me the logic */
+            height = 100;
+        } else {
+            height = s->cr[0x12] | 
+                ((s->cr[0x07] & 0x02) << 7) | 
+                ((s->cr[0x07] & 0x40) << 3);
+            height = (height + 1) / cheight;
+        }
+
+        size = (height * width);
+        if (size > CH_ATTR_SIZE) {
+            if (!full_update)
+                return;
+
+            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
+                     width, height);
+            break;
+        }
+
+        if (width != s->last_width || height != s->last_height ||
+            cw != s->last_cw || cheight != s->last_ch) {
+            s->last_scr_width = width * cw;
+            s->last_scr_height = height * cheight;
+            s->ds->surface->width = width;
+            s->ds->surface->height = height;
+            dpy_resize(s->ds);
+            s->last_width = width;
+            s->last_height = height;
+            s->last_ch = cheight;
+            s->last_cw = cw;
+            full_update = 1;
+        }
+
+        /* Update "hardware" cursor */
+        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+        if (cursor_offset != s->cursor_offset ||
+            s->cr[0xa] != s->cursor_start ||
+            s->cr[0xb] != s->cursor_end || full_update) {
+            cursor_visible = !(s->cr[0xa] & 0x20);
+            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
+                dpy_cursor(s->ds,
+                           TEXTMODE_X(cursor_offset),
+                           TEXTMODE_Y(cursor_offset));
+            else
+                dpy_cursor(s->ds, -1, -1);
+            s->cursor_offset = cursor_offset;
+            s->cursor_start = s->cr[0xa];
+            s->cursor_end = s->cr[0xb];
+        }
+
+        src = (uint32_t *) s->vram_ptr + s->start_addr;
+        dst = chardata;
+
+        if (full_update) {
+            for (i = 0; i < size; src ++, dst ++, i ++)
+                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+
+            dpy_update(s->ds, 0, 0, width, height);
+        } else {
+            c_max = 0;
+
+            for (i = 0; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                    break;
+                }
+            }
+            c_min = i;
+            for (; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                }
+            }
+
+            if (c_min <= c_max) {
+                i = TEXTMODE_Y(c_min);
+                dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+            }
+        }
+
+        return;
+    case GMODE_GRAPH:
+        if (!full_update)
+            return;
+
+        s->get_resolution(s, &width, &height);
+        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
+                 width, height);
+        break;
+    case GMODE_BLANK:
+    default:
+        if (!full_update)
+            return;
+
+        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
+        break;
+    }
+
+    /* Display a message */
+    s->last_width = 60;
+    s->last_height = height = 3;
+    dpy_cursor(s->ds, -1, -1);
+    s->ds->surface->width = s->last_width;
+    s->ds->surface->height = height;
+    dpy_resize(s->ds);
+
+    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
+        console_write_ch(dst ++, ' ');
+
+    size = strlen(msg_buffer);
+    width = (s->last_width - size) / 2;
+    dst = chardata + s->last_width + width;
+    for (i = 0; i < size; i ++)
+        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+
+    dpy_update(s->ds, 0, 0, s->last_width, height);
+}
+
+void maru_vga_common_init(VGACommonState *s, int vga_ram_size)
+{
+    int i, j, v, b;
+
+    for(i = 0;i < 256; i++) {
+        v = 0;
+        for(j = 0; j < 8; j++) {
+            v |= ((i >> j) & 1) << (j * 4);
+        }
+        expand4[i] = v;
+
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            v |= ((i >> (2 * j)) & 3) << (j * 4);
+        }
+        expand2[i] = v;
+    }
+    for(i = 0; i < 16; i++) {
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            b = ((i >> j) & 1);
+            v |= b << (2 * j);
+            v |= b << (2 * j + 1);
+        }
+        expand4to8[i] = v;
+    }
+
+#ifdef CONFIG_BOCHS_VBE
+    s->is_vbe_vmstate = 1;
+#else
+    s->is_vbe_vmstate = 0;
+#endif
+    memory_region_init_ram(&s->vram, NULL, "maru_vga.vram", vga_ram_size);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    s->vram_size = vga_ram_size;
+    s->get_bpp = vga_get_bpp;
+    s->get_offsets = vga_get_offsets;
+    s->get_resolution = vga_get_resolution;
+    s->update = vga_update_display;
+    s->invalidate = vga_invalidate_display;
+    s->screen_dump = vga_screen_dump;
+    s->text_update = vga_update_text;
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        s->retrace = vga_dumb_retrace;
+        s->update_retrace_info = vga_dumb_update_retrace_info;
+        break;
+
+    case VGA_RETRACE_PRECISE:
+        s->retrace = vga_precise_retrace;
+        s->update_retrace_info = vga_precise_update_retrace_info;
+        break;
+    }
+    vga_dirty_log_start(s);
+}
+
+/********************************************************/
+/* vga screen dump */
+
+static int maru_ppm_save(const char *filename, struct DisplaySurface *ds)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    uint32_t v;
+    int y, x;
+    uint8_t r, g, b;
+    int ret;
+    char *linebuf, *pbuf;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return -1;
+    fprintf(f, "P6\n%d %d\n%d\n",
+            ds->width, ds->height, 255);
+    linebuf = g_malloc(ds->width * 3);
+    d1 = ds->data;
+    for(y = 0; y < ds->height; y++) {
+        d = d1;
+        pbuf = linebuf;
+        for(x = 0; x < ds->width; x++) {
+            if (ds->pf.bits_per_pixel == 32)
+                v = *(uint32_t *)d;
+            else
+                v = (uint32_t) (*(uint16_t *)d);
+            r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
+                (ds->pf.rmax + 1);
+            g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
+                (ds->pf.gmax + 1);
+            b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
+                (ds->pf.bmax + 1);
+            *pbuf++ = r;
+            *pbuf++ = g;
+            *pbuf++ = b;
+            d += ds->pf.bytes_per_pixel;
+        }
+        d1 += ds->linesize;
+        ret = fwrite(linebuf, 1, pbuf - linebuf, f);
+        (void)ret;
+    }
+    g_free(linebuf);
+    fclose(f);
+    return 0;
+}
+
+static void vga_save_dpy_update(DisplayState *ds,
+                                int x, int y, int w, int h)
+{
+    if (screen_dump_filename) {
+        maru_ppm_save(screen_dump_filename, ds->surface);
+    }
+}
+
+static void vga_save_dpy_resize(DisplayState *s)
+{
+}
+
+static void vga_save_dpy_refresh(DisplayState *s)
+{
+}
+
+static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
+{
+    DisplayChangeListener *dcl;
+
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
+    dcl->dpy_update = vga_save_dpy_update;
+    dcl->dpy_resize = vga_save_dpy_resize;
+    dcl->dpy_refresh = vga_save_dpy_refresh;
+    register_displaychangelistener(ds, dcl);
+    return dcl;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vga_screen_dump(void *opaque, const char *filename)
+{
+    VGACommonState *s = opaque;
+
+    if (!screen_dump_dcl)
+        screen_dump_dcl = vga_screen_dump_init(s->ds);
+
+    screen_dump_filename = filename;
+    vga_invalidate_display(s);
+    vga_hw_update();
+    screen_dump_filename = NULL;
+}
diff --git a/tizen/src/hw/maru_vga_int.h b/tizen/src/hw/maru_vga_int.h
new file mode 100644 (file)
index 0000000..2beeb53
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga_int.h
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VGA_INT_H_
+#define MARU_VGA_INT_H_
+
+void maru_vga_common_init(VGACommonState *s, int vga_ram_size);
+
+void maru_vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
+                            int poffset, int w,
+                            unsigned int color0, unsigned int color1,
+                            unsigned int color_xor);
+void maru_vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
+                             unsigned int color0, unsigned int color1,
+                             unsigned int color_xor);
+void maru_vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
+                             unsigned int color0, unsigned int color1,
+                             unsigned int color_xor);
+
+#endif /* MARU_VGA_INT_H_ */
diff --git a/tizen/src/hw/maru_vga_template.h b/tizen/src/hw/maru_vga_template.h
new file mode 100644 (file)
index 0000000..bcb1b96
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ *  vga device
+ * Based on qemu/hw/vga_template.h
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(maru_vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+                                                     uint32_t font_data,
+                                                     uint32_t xorcol,
+                                                     uint32_t bgcol)
+{
+#if BPP == 1
+        ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+        ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(maru_vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(maru_vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(maru_vga_draw_glyph_line_, DEPTH)(d,
+                                          expand4to8[font_data >> 4],
+                                          xorcol, bgcol);
+        glue(maru_vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+                                          expand4to8[font_data & 0x0f],
+                                          xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+    uint32_t font_data, xorcol, v;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+#if BPP == 1
+        cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+        v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+1, v);
+        if (dup9)
+            ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+        else
+            ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
+        cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+        v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+3, v);
+        if (dup9)
+            ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+        else
+            ((uint16_t *)d)[8] = bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = v;
+        if (dup9)
+            ((uint32_t *)d)[8] = v;
+        else
+            ((uint32_t *)d)[8] = bgcol;
+#endif
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(maru_vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        PUT_PIXEL2(d, 0, palette[v >> 12]);
+        PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        PUT_PIXEL2(d, 4, palette[v >> 12]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(maru_vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+        ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        PUT_PIXEL2(d, 0, palette[v >> 28]);
+        PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+        PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        PUT_PIXEL2(d, 0, palette[s[0]]);
+        PUT_PIXEL2(d, 1, palette[s[1]]);
+        PUT_PIXEL2(d, 2, palette[s[2]]);
+        PUT_PIXEL2(d, 3, palette[s[3]]);
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+        ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+        ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+        ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+        ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+        ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+        ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+        ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+        d += BPP * 8;
+        s += 8;
+    }
+}
+
+void glue(maru_vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+                                        const uint8_t *src1,
+                                        int poffset, int w,
+                                        unsigned int color0,
+                                        unsigned int color1,
+                                        unsigned int color_xor)
+{
+    const uint8_t *plane0, *plane1;
+    int x, b0, b1;
+    uint8_t *d;
+
+    d = d1;
+    plane0 = src1;
+    plane1 = src1 + poffset;
+    for(x = 0; x < w; x++) {
+        b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+        b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            d[0] ^= color_xor;
+            break;
+        case 2:
+            d[0] = color0;
+            break;
+        case 3:
+            d[0] = color1;
+            break;
+        }
+#elif DEPTH == 16
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint16_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint16_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint16_t *)d)[0] = color1;
+            break;
+        }
+#elif DEPTH == 32
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint32_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint32_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint32_t *)d)[0] = color1;
+            break;
+        }
+#else
+#error unsupported depth
+#endif
+        d += BPP;
+    }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(maru_vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 7) & 0xf8;
+        g = (v >> 2) & 0xf8;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(maru_vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(maru_vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[0];
+        g = s[1];
+        b = s[2];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 3;
+        d += BPP;
+    } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(maru_vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
+    memcpy(d, s, width * 4);
+#else
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 4;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/tizen/src/hw/mesa_gl.h b/tizen/src/hw/mesa_gl.h
new file mode 100755 (executable)
index 0000000..b62c9a8
--- /dev/null
@@ -0,0 +1,2251 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5.1
+ *
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ *
+ * 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
+ * BRIAN PAUL 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 __gl_h_
+#define __gl_h_
+
+#if defined(USE_MGL_NAMESPACE)
+#include "gl_mangle.h"
+#endif
+
+
+/**********************************************************************
+ * Begin system-specific stuff. Do not do any of this when building
+ * for SciTech SNAP, as this is all done before this header file is
+ * included. 
+ */
+#if !defined(__SCITECH_SNAP__)
+
+#if defined(__BEOS__)
+#include <stdlib.h>     /* to get some BeOS-isms */
+#endif
+
+#if !defined(OPENSTEP) && (defined(NeXT) || defined(NeXT_PDO))
+#define OPENSTEP
+#endif
+
+#if defined(_WIN32) && !defined(__WIN32__) && !defined(__CYGWIN__)
+#define __WIN32__
+#endif
+
+#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__))
+#  if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */
+#    define GLAPI __declspec(dllexport)
+#  elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL) /* tag specifying we're building for DLL runtime support */
+#    define GLAPI __declspec(dllimport)
+#  else /* for use with static link lib build of Win32 edition only */
+#    define GLAPI extern
+#  endif /* _STATIC_MESA support */
+#  define GLAPIENTRY __stdcall
+#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */
+#  define GLAPI extern
+#  define GLAPIENTRY __stdcall
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
+#  define GLAPI __attribute__((visibility("default")))
+#  define GLAPIENTRY
+#endif /* WIN32 && !CYGWIN */
+
+#if (defined(__BEOS__) && defined(__POWERPC__)) || defined(__QUICKDRAW__)
+#  define PRAGMA_EXPORT_SUPPORTED              1
+#endif
+
+/*
+ * WINDOWS: Include windows.h here to define APIENTRY.
+ * It is also useful when applications include this file by
+ * including only glut.h, since glut.h depends on windows.h.
+ * Applications needing to include windows.h with parms other
+ * than "WIN32_LEAN_AND_MEAN" may include windows.h before
+ * glut.h or gl.h.
+ */
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#if defined(_WIN32) && !defined(_WINGDI_) && !defined(_GNU_H_WINDOWS32_DEFINES) && !defined(OPENSTEP) && !defined(__CYGWIN__)
+#include <GL/mesa_wgl.h>
+#endif
+
+#if defined(macintosh) && PRAGMA_IMPORT_SUPPORTED
+#pragma import on
+#endif
+
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY GLAPIENTRY
+#endif
+
+/* "P" suffix to be used for a pointer to a function */
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifndef GLAPIENTRYP
+#define GLAPIENTRYP GLAPIENTRY *
+#endif
+
+#ifdef CENTERLINE_CLPP
+#define signed
+#endif
+
+#if defined(PRAGMA_EXPORT_SUPPORTED)
+#pragma export on
+#endif
+
+#endif /* !__SCITECH_SNAP__ */
+/*
+ * End system-specific stuff.
+ **********************************************************************/
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define GL_VERSION_1_1   1
+#define GL_VERSION_1_2   1
+#define GL_VERSION_1_3   1
+#define GL_ARB_imaging   1
+
+
+/*
+ * Datatypes
+ */
+typedef unsigned int   GLenum;
+typedef unsigned char  GLboolean;
+typedef unsigned int   GLbitfield;
+typedef void           GLvoid;
+typedef signed char    GLbyte;         /* 1-byte signed */
+typedef short          GLshort;        /* 2-byte signed */
+typedef int            GLint;          /* 4-byte signed */
+typedef unsigned char  GLubyte;        /* 1-byte unsigned */
+typedef unsigned short GLushort;       /* 2-byte unsigned */
+typedef unsigned int   GLuint;         /* 4-byte unsigned */
+typedef int            GLsizei;        /* 4-byte signed */
+typedef float          GLfloat;        /* single precision float */
+typedef float          GLclampf;       /* single precision float in [0,1] */
+typedef double         GLdouble;       /* double precision float */
+typedef double         GLclampd;       /* double precision float in [0,1] */
+
+
+
+/*
+ * Constants
+ */
+
+/* Boolean values */
+#define GL_FALSE                               0x0
+#define GL_TRUE                                        0x1
+
+/* Data types */
+#define GL_BYTE                                        0x1400
+#define GL_UNSIGNED_BYTE                       0x1401
+#define GL_SHORT                               0x1402
+#define GL_UNSIGNED_SHORT                      0x1403
+#define GL_INT                                 0x1404
+#define GL_UNSIGNED_INT                                0x1405
+#define GL_FLOAT                               0x1406
+#define GL_2_BYTES                             0x1407
+#define GL_3_BYTES                             0x1408
+#define GL_4_BYTES                             0x1409
+#define GL_DOUBLE                              0x140A
+
+/* Primitives */
+#define GL_POINTS                              0x0000
+#define GL_LINES                               0x0001
+#define GL_LINE_LOOP                           0x0002
+#define GL_LINE_STRIP                          0x0003
+#define GL_TRIANGLES                           0x0004
+#define GL_TRIANGLE_STRIP                      0x0005
+#define GL_TRIANGLE_FAN                                0x0006
+#define GL_QUADS                               0x0007
+#define GL_QUAD_STRIP                          0x0008
+#define GL_POLYGON                             0x0009
+
+/* Vertex Arrays */
+#define GL_VERTEX_ARRAY                                0x8074
+#define GL_NORMAL_ARRAY                                0x8075
+#define GL_COLOR_ARRAY                         0x8076
+#define GL_INDEX_ARRAY                         0x8077
+#define GL_TEXTURE_COORD_ARRAY                 0x8078
+#define GL_EDGE_FLAG_ARRAY                     0x8079
+#define GL_VERTEX_ARRAY_SIZE                   0x807A
+#define GL_VERTEX_ARRAY_TYPE                   0x807B
+#define GL_VERTEX_ARRAY_STRIDE                 0x807C
+#define GL_NORMAL_ARRAY_TYPE                   0x807E
+#define GL_NORMAL_ARRAY_STRIDE                 0x807F
+#define GL_COLOR_ARRAY_SIZE                    0x8081
+#define GL_COLOR_ARRAY_TYPE                    0x8082
+#define GL_COLOR_ARRAY_STRIDE                  0x8083
+#define GL_INDEX_ARRAY_TYPE                    0x8085
+#define GL_INDEX_ARRAY_STRIDE                  0x8086
+#define GL_TEXTURE_COORD_ARRAY_SIZE            0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE            0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE          0x808A
+#define GL_EDGE_FLAG_ARRAY_STRIDE              0x808C
+#define GL_VERTEX_ARRAY_POINTER                        0x808E
+#define GL_NORMAL_ARRAY_POINTER                        0x808F
+#define GL_COLOR_ARRAY_POINTER                 0x8090
+#define GL_INDEX_ARRAY_POINTER                 0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER         0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER             0x8093
+#define GL_V2F                                 0x2A20
+#define GL_V3F                                 0x2A21
+#define GL_C4UB_V2F                            0x2A22
+#define GL_C4UB_V3F                            0x2A23
+#define GL_C3F_V3F                             0x2A24
+#define GL_N3F_V3F                             0x2A25
+#define GL_C4F_N3F_V3F                         0x2A26
+#define GL_T2F_V3F                             0x2A27
+#define GL_T4F_V4F                             0x2A28
+#define GL_T2F_C4UB_V3F                                0x2A29
+#define GL_T2F_C3F_V3F                         0x2A2A
+#define GL_T2F_N3F_V3F                         0x2A2B
+#define GL_T2F_C4F_N3F_V3F                     0x2A2C
+#define GL_T4F_C4F_N3F_V4F                     0x2A2D
+
+/* Matrix Mode */
+#define GL_MATRIX_MODE                         0x0BA0
+#define GL_MODELVIEW                           0x1700
+#define GL_PROJECTION                          0x1701
+#define GL_TEXTURE                             0x1702
+
+/* Points */
+#define GL_POINT_SMOOTH                                0x0B10
+#define GL_POINT_SIZE                          0x0B11
+#define GL_POINT_SIZE_GRANULARITY              0x0B13
+#define GL_POINT_SIZE_RANGE                    0x0B12
+
+/* Lines */
+#define GL_LINE_SMOOTH                         0x0B20
+#define GL_LINE_STIPPLE                                0x0B24
+#define GL_LINE_STIPPLE_PATTERN                        0x0B25
+#define GL_LINE_STIPPLE_REPEAT                 0x0B26
+#define GL_LINE_WIDTH                          0x0B21
+#define GL_LINE_WIDTH_GRANULARITY              0x0B23
+#define GL_LINE_WIDTH_RANGE                    0x0B22
+
+/* Polygons */
+#define GL_POINT                               0x1B00
+#define GL_LINE                                        0x1B01
+#define GL_FILL                                        0x1B02
+#define GL_CW                                  0x0900
+#define GL_CCW                                 0x0901
+#define GL_FRONT                               0x0404
+#define GL_BACK                                        0x0405
+#define GL_POLYGON_MODE                                0x0B40
+#define GL_POLYGON_SMOOTH                      0x0B41
+#define GL_POLYGON_STIPPLE                     0x0B42
+#define GL_EDGE_FLAG                           0x0B43
+#define GL_CULL_FACE                           0x0B44
+#define GL_CULL_FACE_MODE                      0x0B45
+#define GL_FRONT_FACE                          0x0B46
+#define GL_POLYGON_OFFSET_FACTOR               0x8038
+#define GL_POLYGON_OFFSET_UNITS                        0x2A00
+#define GL_POLYGON_OFFSET_POINT                        0x2A01
+#define GL_POLYGON_OFFSET_LINE                 0x2A02
+#define GL_POLYGON_OFFSET_FILL                 0x8037
+
+/* Display Lists */
+#define GL_COMPILE                             0x1300
+#define GL_COMPILE_AND_EXECUTE                 0x1301
+#define GL_LIST_BASE                           0x0B32
+#define GL_LIST_INDEX                          0x0B33
+#define GL_LIST_MODE                           0x0B30
+
+/* Depth buffer */
+#define GL_NEVER                               0x0200
+#define GL_LESS                                        0x0201
+#define GL_EQUAL                               0x0202
+#define GL_LEQUAL                              0x0203
+#define GL_GREATER                             0x0204
+#define GL_NOTEQUAL                            0x0205
+#define GL_GEQUAL                              0x0206
+#define GL_ALWAYS                              0x0207
+#define GL_DEPTH_TEST                          0x0B71
+#define GL_DEPTH_BITS                          0x0D56
+#define GL_DEPTH_CLEAR_VALUE                   0x0B73
+#define GL_DEPTH_FUNC                          0x0B74
+#define GL_DEPTH_RANGE                         0x0B70
+#define GL_DEPTH_WRITEMASK                     0x0B72
+#define GL_DEPTH_COMPONENT                     0x1902
+
+/* Lighting */
+#define GL_LIGHTING                            0x0B50
+#define GL_LIGHT0                              0x4000
+#define GL_LIGHT1                              0x4001
+#define GL_LIGHT2                              0x4002
+#define GL_LIGHT3                              0x4003
+#define GL_LIGHT4                              0x4004
+#define GL_LIGHT5                              0x4005
+#define GL_LIGHT6                              0x4006
+#define GL_LIGHT7                              0x4007
+#define GL_SPOT_EXPONENT                       0x1205
+#define GL_SPOT_CUTOFF                         0x1206
+#define GL_CONSTANT_ATTENUATION                        0x1207
+#define GL_LINEAR_ATTENUATION                  0x1208
+#define GL_QUADRATIC_ATTENUATION               0x1209
+#define GL_AMBIENT                             0x1200
+#define GL_DIFFUSE                             0x1201
+#define GL_SPECULAR                            0x1202
+#define GL_SHININESS                           0x1601
+#define GL_EMISSION                            0x1600
+#define GL_POSITION                            0x1203
+#define GL_SPOT_DIRECTION                      0x1204
+#define GL_AMBIENT_AND_DIFFUSE                 0x1602
+#define GL_COLOR_INDEXES                       0x1603
+#define GL_LIGHT_MODEL_TWO_SIDE                        0x0B52
+#define GL_LIGHT_MODEL_LOCAL_VIEWER            0x0B51
+#define GL_LIGHT_MODEL_AMBIENT                 0x0B53
+#define GL_FRONT_AND_BACK                      0x0408
+#define GL_SHADE_MODEL                         0x0B54
+#define GL_FLAT                                        0x1D00
+#define GL_SMOOTH                              0x1D01
+#define GL_COLOR_MATERIAL                      0x0B57
+#define GL_COLOR_MATERIAL_FACE                 0x0B55
+#define GL_COLOR_MATERIAL_PARAMETER            0x0B56
+#define GL_NORMALIZE                           0x0BA1
+
+/* User clipping planes */
+#define GL_CLIP_PLANE0                         0x3000
+#define GL_CLIP_PLANE1                         0x3001
+#define GL_CLIP_PLANE2                         0x3002
+#define GL_CLIP_PLANE3                         0x3003
+#define GL_CLIP_PLANE4                         0x3004
+#define GL_CLIP_PLANE5                         0x3005
+
+/* Accumulation buffer */
+#define GL_ACCUM_RED_BITS                      0x0D58
+#define GL_ACCUM_GREEN_BITS                    0x0D59
+#define GL_ACCUM_BLUE_BITS                     0x0D5A
+#define GL_ACCUM_ALPHA_BITS                    0x0D5B
+#define GL_ACCUM_CLEAR_VALUE                   0x0B80
+#define GL_ACCUM                               0x0100
+#define GL_ADD                                 0x0104
+#define GL_LOAD                                        0x0101
+#define GL_MULT                                        0x0103
+#define GL_RETURN                              0x0102
+
+/* Alpha testing */
+#define GL_ALPHA_TEST                          0x0BC0
+#define GL_ALPHA_TEST_REF                      0x0BC2
+#define GL_ALPHA_TEST_FUNC                     0x0BC1
+
+/* Blending */
+#define GL_BLEND                               0x0BE2
+#define GL_BLEND_SRC                           0x0BE1
+#define GL_BLEND_DST                           0x0BE0
+#define GL_ZERO                                        0x0
+#define GL_ONE                                 0x1
+#define GL_SRC_COLOR                           0x0300
+#define GL_ONE_MINUS_SRC_COLOR                 0x0301
+#define GL_SRC_ALPHA                           0x0302
+#define GL_ONE_MINUS_SRC_ALPHA                 0x0303
+#define GL_DST_ALPHA                           0x0304
+#define GL_ONE_MINUS_DST_ALPHA                 0x0305
+#define GL_DST_COLOR                           0x0306
+#define GL_ONE_MINUS_DST_COLOR                 0x0307
+#define GL_SRC_ALPHA_SATURATE                  0x0308
+
+/* Render Mode */
+#define GL_FEEDBACK                            0x1C01
+#define GL_RENDER                              0x1C00
+#define GL_SELECT                              0x1C02
+
+/* Feedback */
+#define GL_2D                                  0x0600
+#define GL_3D                                  0x0601
+#define GL_3D_COLOR                            0x0602
+#define GL_3D_COLOR_TEXTURE                    0x0603
+#define GL_4D_COLOR_TEXTURE                    0x0604
+#define GL_POINT_TOKEN                         0x0701
+#define GL_LINE_TOKEN                          0x0702
+#define GL_LINE_RESET_TOKEN                    0x0707
+#define GL_POLYGON_TOKEN                       0x0703
+#define GL_BITMAP_TOKEN                                0x0704
+#define GL_DRAW_PIXEL_TOKEN                    0x0705
+#define GL_COPY_PIXEL_TOKEN                    0x0706
+#define GL_PASS_THROUGH_TOKEN                  0x0700
+#define GL_FEEDBACK_BUFFER_POINTER             0x0DF0
+#define GL_FEEDBACK_BUFFER_SIZE                        0x0DF1
+#define GL_FEEDBACK_BUFFER_TYPE                        0x0DF2
+
+/* Selection */
+#define GL_SELECTION_BUFFER_POINTER            0x0DF3
+#define GL_SELECTION_BUFFER_SIZE               0x0DF4
+
+/* Fog */
+#define GL_FOG                                 0x0B60
+#define GL_FOG_MODE                            0x0B65
+#define GL_FOG_DENSITY                         0x0B62
+#define GL_FOG_COLOR                           0x0B66
+#define GL_FOG_INDEX                           0x0B61
+#define GL_FOG_START                           0x0B63
+#define GL_FOG_END                             0x0B64
+#define GL_LINEAR                              0x2601
+#define GL_EXP                                 0x0800
+#define GL_EXP2                                        0x0801
+
+/* Logic Ops */
+#define GL_LOGIC_OP                            0x0BF1
+#define GL_INDEX_LOGIC_OP                      0x0BF1
+#define GL_COLOR_LOGIC_OP                      0x0BF2
+#define GL_LOGIC_OP_MODE                       0x0BF0
+#define GL_CLEAR                               0x1500
+#define GL_SET                                 0x150F
+#define GL_COPY                                        0x1503
+#define GL_COPY_INVERTED                       0x150C
+#define GL_NOOP                                        0x1505
+#define GL_INVERT                              0x150A
+#define GL_AND                                 0x1501
+#define GL_NAND                                        0x150E
+#define GL_OR                                  0x1507
+#define GL_NOR                                 0x1508
+#define GL_XOR                                 0x1506
+#define GL_EQUIV                               0x1509
+#define GL_AND_REVERSE                         0x1502
+#define GL_AND_INVERTED                                0x1504
+#define GL_OR_REVERSE                          0x150B
+#define GL_OR_INVERTED                         0x150D
+
+/* Stencil */
+#define GL_STENCIL_BITS                                0x0D57
+#define GL_STENCIL_TEST                                0x0B90
+#define GL_STENCIL_CLEAR_VALUE                 0x0B91
+#define GL_STENCIL_FUNC                                0x0B92
+#define GL_STENCIL_VALUE_MASK                  0x0B93
+#define GL_STENCIL_FAIL                                0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL             0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS             0x0B96
+#define GL_STENCIL_REF                         0x0B97
+#define GL_STENCIL_WRITEMASK                   0x0B98
+#define GL_STENCIL_INDEX                       0x1901
+#define GL_KEEP                                        0x1E00
+#define GL_REPLACE                             0x1E01
+#define GL_INCR                                        0x1E02
+#define GL_DECR                                        0x1E03
+
+/* Buffers, Pixel Drawing/Reading */
+#define GL_NONE                                        0x0
+#define GL_LEFT                                        0x0406
+#define GL_RIGHT                               0x0407
+/*GL_FRONT                                     0x0404 */
+/*GL_BACK                                      0x0405 */
+/*GL_FRONT_AND_BACK                            0x0408 */
+#define GL_FRONT_LEFT                          0x0400
+#define GL_FRONT_RIGHT                         0x0401
+#define GL_BACK_LEFT                           0x0402
+#define GL_BACK_RIGHT                          0x0403
+#define GL_AUX0                                        0x0409
+#define GL_AUX1                                        0x040A
+#define GL_AUX2                                        0x040B
+#define GL_AUX3                                        0x040C
+#define GL_COLOR_INDEX                         0x1900
+#define GL_RED                                 0x1903
+#define GL_GREEN                               0x1904
+#define GL_BLUE                                        0x1905
+#define GL_ALPHA                               0x1906
+#define GL_LUMINANCE                           0x1909
+#define GL_LUMINANCE_ALPHA                     0x190A
+#define GL_ALPHA_BITS                          0x0D55
+#define GL_RED_BITS                            0x0D52
+#define GL_GREEN_BITS                          0x0D53
+#define GL_BLUE_BITS                           0x0D54
+#define GL_INDEX_BITS                          0x0D51
+#define GL_SUBPIXEL_BITS                       0x0D50
+#define GL_AUX_BUFFERS                         0x0C00
+#define GL_READ_BUFFER                         0x0C02
+#define GL_DRAW_BUFFER                         0x0C01
+#define GL_DOUBLEBUFFER                                0x0C32
+#define GL_STEREO                              0x0C33
+#define GL_BITMAP                              0x1A00
+#define GL_COLOR                               0x1800
+#define GL_DEPTH                               0x1801
+#define GL_STENCIL                             0x1802
+#define GL_DITHER                              0x0BD0
+#define GL_RGB                                 0x1907
+#define GL_RGBA                                        0x1908
+
+/* Implementation limits */
+#define GL_MAX_LIST_NESTING                    0x0B31
+#define GL_MAX_EVAL_ORDER                      0x0D30
+#define GL_MAX_LIGHTS                          0x0D31
+#define GL_MAX_CLIP_PLANES                     0x0D32
+#define GL_MAX_TEXTURE_SIZE                    0x0D33
+#define GL_MAX_PIXEL_MAP_TABLE                 0x0D34
+#define GL_MAX_ATTRIB_STACK_DEPTH              0x0D35
+#define GL_MAX_MODELVIEW_STACK_DEPTH           0x0D36
+#define GL_MAX_NAME_STACK_DEPTH                        0x0D37
+#define GL_MAX_PROJECTION_STACK_DEPTH          0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH             0x0D39
+#define GL_MAX_VIEWPORT_DIMS                   0x0D3A
+#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH       0x0D3B
+
+/* Gets */
+#define GL_ATTRIB_STACK_DEPTH                  0x0BB0
+#define GL_CLIENT_ATTRIB_STACK_DEPTH           0x0BB1
+#define GL_COLOR_CLEAR_VALUE                   0x0C22
+#define GL_COLOR_WRITEMASK                     0x0C23
+#define GL_CURRENT_INDEX                       0x0B01
+#define GL_CURRENT_COLOR                       0x0B00
+#define GL_CURRENT_NORMAL                      0x0B02
+#define GL_CURRENT_RASTER_COLOR                        0x0B04
+#define GL_CURRENT_RASTER_DISTANCE             0x0B09
+#define GL_CURRENT_RASTER_INDEX                        0x0B05
+#define GL_CURRENT_RASTER_POSITION             0x0B07
+#define GL_CURRENT_RASTER_TEXTURE_COORDS       0x0B06
+#define GL_CURRENT_RASTER_POSITION_VALID       0x0B08
+#define GL_CURRENT_TEXTURE_COORDS              0x0B03
+#define GL_INDEX_CLEAR_VALUE                   0x0C20
+#define GL_INDEX_MODE                          0x0C30
+#define GL_INDEX_WRITEMASK                     0x0C21
+#define GL_MODELVIEW_MATRIX                    0x0BA6
+#define GL_MODELVIEW_STACK_DEPTH               0x0BA3
+#define GL_NAME_STACK_DEPTH                    0x0D70
+#define GL_PROJECTION_MATRIX                   0x0BA7
+#define GL_PROJECTION_STACK_DEPTH              0x0BA4
+#define GL_RENDER_MODE                         0x0C40
+#define GL_RGBA_MODE                           0x0C31
+#define GL_TEXTURE_MATRIX                      0x0BA8
+#define GL_TEXTURE_STACK_DEPTH                 0x0BA5
+#define GL_VIEWPORT                            0x0BA2
+
+/* Evaluators */
+#define GL_AUTO_NORMAL                         0x0D80
+#define GL_MAP1_COLOR_4                                0x0D90
+#define GL_MAP1_INDEX                          0x0D91
+#define GL_MAP1_NORMAL                         0x0D92
+#define GL_MAP1_TEXTURE_COORD_1                        0x0D93
+#define GL_MAP1_TEXTURE_COORD_2                        0x0D94
+#define GL_MAP1_TEXTURE_COORD_3                        0x0D95
+#define GL_MAP1_TEXTURE_COORD_4                        0x0D96
+#define GL_MAP1_VERTEX_3                       0x0D97
+#define GL_MAP1_VERTEX_4                       0x0D98
+#define GL_MAP2_COLOR_4                                0x0DB0
+#define GL_MAP2_INDEX                          0x0DB1
+#define GL_MAP2_NORMAL                         0x0DB2
+#define GL_MAP2_TEXTURE_COORD_1                        0x0DB3
+#define GL_MAP2_TEXTURE_COORD_2                        0x0DB4
+#define GL_MAP2_TEXTURE_COORD_3                        0x0DB5
+#define GL_MAP2_TEXTURE_COORD_4                        0x0DB6
+#define GL_MAP2_VERTEX_3                       0x0DB7
+#define GL_MAP2_VERTEX_4                       0x0DB8
+#define GL_MAP1_GRID_DOMAIN                    0x0DD0
+#define GL_MAP1_GRID_SEGMENTS                  0x0DD1
+#define GL_MAP2_GRID_DOMAIN                    0x0DD2
+#define GL_MAP2_GRID_SEGMENTS                  0x0DD3
+#define GL_COEFF                               0x0A00
+#define GL_ORDER                               0x0A01
+#define GL_DOMAIN                              0x0A02
+
+/* Hints */
+#define GL_PERSPECTIVE_CORRECTION_HINT         0x0C50
+#define GL_POINT_SMOOTH_HINT                   0x0C51
+#define GL_LINE_SMOOTH_HINT                    0x0C52
+#define GL_POLYGON_SMOOTH_HINT                 0x0C53
+#define GL_FOG_HINT                            0x0C54
+#define GL_DONT_CARE                           0x1100
+#define GL_FASTEST                             0x1101
+#define GL_NICEST                              0x1102
+
+/* Scissor box */
+#define GL_SCISSOR_BOX                         0x0C10
+#define GL_SCISSOR_TEST                                0x0C11
+
+/* Pixel Mode / Transfer */
+#define GL_MAP_COLOR                           0x0D10
+#define GL_MAP_STENCIL                         0x0D11
+#define GL_INDEX_SHIFT                         0x0D12
+#define GL_INDEX_OFFSET                                0x0D13
+#define GL_RED_SCALE                           0x0D14
+#define GL_RED_BIAS                            0x0D15
+#define GL_GREEN_SCALE                         0x0D18
+#define GL_GREEN_BIAS                          0x0D19
+#define GL_BLUE_SCALE                          0x0D1A
+#define GL_BLUE_BIAS                           0x0D1B
+#define GL_ALPHA_SCALE                         0x0D1C
+#define GL_ALPHA_BIAS                          0x0D1D
+#define GL_DEPTH_SCALE                         0x0D1E
+#define GL_DEPTH_BIAS                          0x0D1F
+#define GL_PIXEL_MAP_S_TO_S_SIZE               0x0CB1
+#define GL_PIXEL_MAP_I_TO_I_SIZE               0x0CB0
+#define GL_PIXEL_MAP_I_TO_R_SIZE               0x0CB2
+#define GL_PIXEL_MAP_I_TO_G_SIZE               0x0CB3
+#define GL_PIXEL_MAP_I_TO_B_SIZE               0x0CB4
+#define GL_PIXEL_MAP_I_TO_A_SIZE               0x0CB5
+#define GL_PIXEL_MAP_R_TO_R_SIZE               0x0CB6
+#define GL_PIXEL_MAP_G_TO_G_SIZE               0x0CB7
+#define GL_PIXEL_MAP_B_TO_B_SIZE               0x0CB8
+#define GL_PIXEL_MAP_A_TO_A_SIZE               0x0CB9
+#define GL_PIXEL_MAP_S_TO_S                    0x0C71
+#define GL_PIXEL_MAP_I_TO_I                    0x0C70
+#define GL_PIXEL_MAP_I_TO_R                    0x0C72
+#define GL_PIXEL_MAP_I_TO_G                    0x0C73
+#define GL_PIXEL_MAP_I_TO_B                    0x0C74
+#define GL_PIXEL_MAP_I_TO_A                    0x0C75
+#define GL_PIXEL_MAP_R_TO_R                    0x0C76
+#define GL_PIXEL_MAP_G_TO_G                    0x0C77
+#define GL_PIXEL_MAP_B_TO_B                    0x0C78
+#define GL_PIXEL_MAP_A_TO_A                    0x0C79
+#define GL_PACK_ALIGNMENT                      0x0D05
+#define GL_PACK_LSB_FIRST                      0x0D01
+#define GL_PACK_ROW_LENGTH                     0x0D02
+#define GL_PACK_SKIP_PIXELS                    0x0D04
+#define GL_PACK_SKIP_ROWS                      0x0D03
+#define GL_PACK_SWAP_BYTES                     0x0D00
+#define GL_UNPACK_ALIGNMENT                    0x0CF5
+#define GL_UNPACK_LSB_FIRST                    0x0CF1
+#define GL_UNPACK_ROW_LENGTH                   0x0CF2
+#define GL_UNPACK_SKIP_PIXELS                  0x0CF4
+#define GL_UNPACK_SKIP_ROWS                    0x0CF3
+#define GL_UNPACK_SWAP_BYTES                   0x0CF0
+#define GL_ZOOM_X                              0x0D16
+#define GL_ZOOM_Y                              0x0D17
+
+/* Texture mapping */
+#define GL_TEXTURE_ENV                         0x2300
+#define GL_TEXTURE_ENV_MODE                    0x2200
+#define GL_TEXTURE_1D                          0x0DE0
+#define GL_TEXTURE_2D                          0x0DE1
+#define GL_TEXTURE_WRAP_S                      0x2802
+#define GL_TEXTURE_WRAP_T                      0x2803
+#define GL_TEXTURE_MAG_FILTER                  0x2800
+#define GL_TEXTURE_MIN_FILTER                  0x2801
+#define GL_TEXTURE_ENV_COLOR                   0x2201
+#define GL_TEXTURE_GEN_S                       0x0C60
+#define GL_TEXTURE_GEN_T                       0x0C61
+#define GL_TEXTURE_GEN_MODE                    0x2500
+#define GL_TEXTURE_BORDER_COLOR                        0x1004
+#define GL_TEXTURE_WIDTH                       0x1000
+#define GL_TEXTURE_HEIGHT                      0x1001
+#define GL_TEXTURE_BORDER                      0x1005
+#define GL_TEXTURE_COMPONENTS                  0x1003
+#define GL_TEXTURE_RED_SIZE                    0x805C
+#define GL_TEXTURE_GREEN_SIZE                  0x805D
+#define GL_TEXTURE_BLUE_SIZE                   0x805E
+#define GL_TEXTURE_ALPHA_SIZE                  0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE              0x8060
+#define GL_TEXTURE_INTENSITY_SIZE              0x8061
+#define GL_NEAREST_MIPMAP_NEAREST              0x2700
+#define GL_NEAREST_MIPMAP_LINEAR               0x2702
+#define GL_LINEAR_MIPMAP_NEAREST               0x2701
+#define GL_LINEAR_MIPMAP_LINEAR                        0x2703
+#define GL_OBJECT_LINEAR                       0x2401
+#define GL_OBJECT_PLANE                                0x2501
+#define GL_EYE_LINEAR                          0x2400
+#define GL_EYE_PLANE                           0x2502
+#define GL_SPHERE_MAP                          0x2402
+#define GL_DECAL                               0x2101
+#define GL_MODULATE                            0x2100
+#define GL_NEAREST                             0x2600
+#define GL_REPEAT                              0x2901
+#define GL_CLAMP                               0x2900
+#define GL_S                                   0x2000
+#define GL_T                                   0x2001
+#define GL_R                                   0x2002
+#define GL_Q                                   0x2003
+#define GL_TEXTURE_GEN_R                       0x0C62
+#define GL_TEXTURE_GEN_Q                       0x0C63
+
+/* Utility */
+#define GL_VENDOR                              0x1F00
+#define GL_RENDERER                            0x1F01
+#define GL_VERSION                             0x1F02
+#define GL_EXTENSIONS                          0x1F03
+
+/* Errors */
+#define GL_NO_ERROR                            0x0
+#define GL_INVALID_ENUM                                0x0500
+#define GL_INVALID_VALUE                       0x0501
+#define GL_INVALID_OPERATION                   0x0502
+#define GL_STACK_OVERFLOW                      0x0503
+#define GL_STACK_UNDERFLOW                     0x0504
+#define GL_OUT_OF_MEMORY                       0x0505
+
+/* glPush/PopAttrib bits */
+#define GL_CURRENT_BIT                         0x00000001
+#define GL_POINT_BIT                           0x00000002
+#define GL_LINE_BIT                            0x00000004
+#define GL_POLYGON_BIT                         0x00000008
+#define GL_POLYGON_STIPPLE_BIT                 0x00000010
+#define GL_PIXEL_MODE_BIT                      0x00000020
+#define GL_LIGHTING_BIT                                0x00000040
+#define GL_FOG_BIT                             0x00000080
+#define GL_DEPTH_BUFFER_BIT                    0x00000100
+#define GL_ACCUM_BUFFER_BIT                    0x00000200
+#define GL_STENCIL_BUFFER_BIT                  0x00000400
+#define GL_VIEWPORT_BIT                                0x00000800
+#define GL_TRANSFORM_BIT                       0x00001000
+#define GL_ENABLE_BIT                          0x00002000
+#define GL_COLOR_BUFFER_BIT                    0x00004000
+#define GL_HINT_BIT                            0x00008000
+#define GL_EVAL_BIT                            0x00010000
+#define GL_LIST_BIT                            0x00020000
+#define GL_TEXTURE_BIT                         0x00040000
+#define GL_SCISSOR_BIT                         0x00080000
+#define GL_ALL_ATTRIB_BITS                     0x000FFFFF
+
+
+/* OpenGL 1.1 */
+#define GL_PROXY_TEXTURE_1D                    0x8063
+#define GL_PROXY_TEXTURE_2D                    0x8064
+#define GL_TEXTURE_PRIORITY                    0x8066
+#define GL_TEXTURE_RESIDENT                    0x8067
+#define GL_TEXTURE_BINDING_1D                  0x8068
+#define GL_TEXTURE_BINDING_2D                  0x8069
+#define GL_TEXTURE_INTERNAL_FORMAT             0x1003
+#define GL_ALPHA4                              0x803B
+#define GL_ALPHA8                              0x803C
+#define GL_ALPHA12                             0x803D
+#define GL_ALPHA16                             0x803E
+#define GL_LUMINANCE4                          0x803F
+#define GL_LUMINANCE8                          0x8040
+#define GL_LUMINANCE12                         0x8041
+#define GL_LUMINANCE16                         0x8042
+#define GL_LUMINANCE4_ALPHA4                   0x8043
+#define GL_LUMINANCE6_ALPHA2                   0x8044
+#define GL_LUMINANCE8_ALPHA8                   0x8045
+#define GL_LUMINANCE12_ALPHA4                  0x8046
+#define GL_LUMINANCE12_ALPHA12                 0x8047
+#define GL_LUMINANCE16_ALPHA16                 0x8048
+#define GL_INTENSITY                           0x8049
+#define GL_INTENSITY4                          0x804A
+#define GL_INTENSITY8                          0x804B
+#define GL_INTENSITY12                         0x804C
+#define GL_INTENSITY16                         0x804D
+#define GL_R3_G3_B2                            0x2A10
+#define GL_RGB4                                        0x804F
+#define GL_RGB5                                        0x8050
+#define GL_RGB8                                        0x8051
+#define GL_RGB10                               0x8052
+#define GL_RGB12                               0x8053
+#define GL_RGB16                               0x8054
+#define GL_RGBA2                               0x8055
+#define GL_RGBA4                               0x8056
+#define GL_RGB5_A1                             0x8057
+#define GL_RGBA8                               0x8058
+#define GL_RGB10_A2                            0x8059
+#define GL_RGBA12                              0x805A
+#define GL_RGBA16                              0x805B
+#define GL_CLIENT_PIXEL_STORE_BIT              0x00000001
+#define GL_CLIENT_VERTEX_ARRAY_BIT             0x00000002
+#define GL_ALL_CLIENT_ATTRIB_BITS              0xFFFFFFFF
+#define GL_CLIENT_ALL_ATTRIB_BITS              0xFFFFFFFF
+
+
+
+/*
+ * Miscellaneous
+ */
+
+GLAPI void GLAPIENTRY glClearIndex( GLfloat c );
+
+GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
+
+GLAPI void GLAPIENTRY glClear( GLbitfield mask );
+
+GLAPI void GLAPIENTRY glIndexMask( GLuint mask );
+
+GLAPI void GLAPIENTRY glColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
+
+GLAPI void GLAPIENTRY glAlphaFunc( GLenum func, GLclampf ref );
+
+GLAPI void GLAPIENTRY glBlendFunc( GLenum sfactor, GLenum dfactor );
+
+GLAPI void GLAPIENTRY glLogicOp( GLenum opcode );
+
+GLAPI void GLAPIENTRY glCullFace( GLenum mode );
+
+GLAPI void GLAPIENTRY glFrontFace( GLenum mode );
+
+GLAPI void GLAPIENTRY glPointSize( GLfloat size );
+
+GLAPI void GLAPIENTRY glLineWidth( GLfloat width );
+
+GLAPI void GLAPIENTRY glLineStipple( GLint factor, GLushort pattern );
+
+GLAPI void GLAPIENTRY glPolygonMode( GLenum face, GLenum mode );
+
+GLAPI void GLAPIENTRY glPolygonOffset( GLfloat factor, GLfloat units );
+
+GLAPI void GLAPIENTRY glPolygonStipple( const GLubyte *mask );
+
+GLAPI void GLAPIENTRY glGetPolygonStipple( GLubyte *mask );
+
+GLAPI void GLAPIENTRY glEdgeFlag( GLboolean flag );
+
+GLAPI void GLAPIENTRY glEdgeFlagv( const GLboolean *flag );
+
+GLAPI void GLAPIENTRY glScissor( GLint x, GLint y, GLsizei width, GLsizei height);
+
+GLAPI void GLAPIENTRY glClipPlane( GLenum plane, const GLdouble *equation );
+
+GLAPI void GLAPIENTRY glGetClipPlane( GLenum plane, GLdouble *equation );
+
+GLAPI void GLAPIENTRY glDrawBuffer( GLenum mode );
+
+GLAPI void GLAPIENTRY glReadBuffer( GLenum mode );
+
+GLAPI void GLAPIENTRY glEnable( GLenum cap );
+
+GLAPI void GLAPIENTRY glDisable( GLenum cap );
+
+GLAPI GLboolean GLAPIENTRY glIsEnabled( GLenum cap );
+
+
+GLAPI void GLAPIENTRY glEnableClientState( GLenum cap );  /* 1.1 */
+
+GLAPI void GLAPIENTRY glDisableClientState( GLenum cap );  /* 1.1 */
+
+
+GLAPI void GLAPIENTRY glGetBooleanv( GLenum pname, GLboolean *params );
+
+GLAPI void GLAPIENTRY glGetDoublev( GLenum pname, GLdouble *params );
+
+GLAPI void GLAPIENTRY glGetFloatv( GLenum pname, GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetIntegerv( GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glPushAttrib( GLbitfield mask );
+
+GLAPI void GLAPIENTRY glPopAttrib( void );
+
+
+GLAPI void GLAPIENTRY glPushClientAttrib( GLbitfield mask );  /* 1.1 */
+
+GLAPI void GLAPIENTRY glPopClientAttrib( void );  /* 1.1 */
+
+
+GLAPI GLint GLAPIENTRY glRenderMode( GLenum mode );
+
+GLAPI GLenum GLAPIENTRY glGetError( void );
+
+GLAPI const GLubyte * GLAPIENTRY glGetString( GLenum name );
+
+GLAPI void GLAPIENTRY glFinish( void );
+
+GLAPI void GLAPIENTRY glFlush( void );
+
+GLAPI void GLAPIENTRY glHint( GLenum target, GLenum mode );
+
+
+/*
+ * Depth Buffer
+ */
+
+GLAPI void GLAPIENTRY glClearDepth( GLclampd depth );
+
+GLAPI void GLAPIENTRY glDepthFunc( GLenum func );
+
+GLAPI void GLAPIENTRY glDepthMask( GLboolean flag );
+
+GLAPI void GLAPIENTRY glDepthRange( GLclampd near_val, GLclampd far_val );
+
+
+/*
+ * Accumulation Buffer
+ */
+
+GLAPI void GLAPIENTRY glClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
+
+GLAPI void GLAPIENTRY glAccum( GLenum op, GLfloat value );
+
+
+/*
+ * Transformation
+ */
+
+GLAPI void GLAPIENTRY glMatrixMode( GLenum mode );
+
+GLAPI void GLAPIENTRY glOrtho( GLdouble left, GLdouble right,
+                                 GLdouble bottom, GLdouble top,
+                                 GLdouble near_val, GLdouble far_val );
+
+GLAPI void GLAPIENTRY glFrustum( GLdouble left, GLdouble right,
+                                   GLdouble bottom, GLdouble top,
+                                   GLdouble near_val, GLdouble far_val );
+
+GLAPI void GLAPIENTRY glViewport( GLint x, GLint y,
+                                    GLsizei width, GLsizei height );
+
+GLAPI void GLAPIENTRY glPushMatrix( void );
+
+GLAPI void GLAPIENTRY glPopMatrix( void );
+
+GLAPI void GLAPIENTRY glLoadIdentity( void );
+
+GLAPI void GLAPIENTRY glLoadMatrixd( const GLdouble *m );
+GLAPI void GLAPIENTRY glLoadMatrixf( const GLfloat *m );
+
+GLAPI void GLAPIENTRY glMultMatrixd( const GLdouble *m );
+GLAPI void GLAPIENTRY glMultMatrixf( const GLfloat *m );
+
+GLAPI void GLAPIENTRY glRotated( GLdouble angle,
+                                   GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glRotatef( GLfloat angle,
+                                   GLfloat x, GLfloat y, GLfloat z );
+
+GLAPI void GLAPIENTRY glScaled( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glScalef( GLfloat x, GLfloat y, GLfloat z );
+
+GLAPI void GLAPIENTRY glTranslated( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glTranslatef( GLfloat x, GLfloat y, GLfloat z );
+
+
+/*
+ * Display Lists
+ */
+
+GLAPI GLboolean GLAPIENTRY glIsList( GLuint list );
+
+GLAPI void GLAPIENTRY glDeleteLists( GLuint list, GLsizei range );
+
+GLAPI GLuint GLAPIENTRY glGenLists( GLsizei range );
+
+GLAPI void GLAPIENTRY glNewList( GLuint list, GLenum mode );
+
+GLAPI void GLAPIENTRY glEndList( void );
+
+GLAPI void GLAPIENTRY glCallList( GLuint list );
+
+GLAPI void GLAPIENTRY glCallLists( GLsizei n, GLenum type,
+                                     const GLvoid *lists );
+
+GLAPI void GLAPIENTRY glListBase( GLuint base );
+
+
+/*
+ * Drawing Functions
+ */
+
+GLAPI void GLAPIENTRY glBegin( GLenum mode );
+
+GLAPI void GLAPIENTRY glEnd( void );
+
+
+GLAPI void GLAPIENTRY glVertex2d( GLdouble x, GLdouble y );
+GLAPI void GLAPIENTRY glVertex2f( GLfloat x, GLfloat y );
+GLAPI void GLAPIENTRY glVertex2i( GLint x, GLint y );
+GLAPI void GLAPIENTRY glVertex2s( GLshort x, GLshort y );
+
+GLAPI void GLAPIENTRY glVertex3d( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glVertex3f( GLfloat x, GLfloat y, GLfloat z );
+GLAPI void GLAPIENTRY glVertex3i( GLint x, GLint y, GLint z );
+GLAPI void GLAPIENTRY glVertex3s( GLshort x, GLshort y, GLshort z );
+
+GLAPI void GLAPIENTRY glVertex4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+GLAPI void GLAPIENTRY glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+GLAPI void GLAPIENTRY glVertex4i( GLint x, GLint y, GLint z, GLint w );
+GLAPI void GLAPIENTRY glVertex4s( GLshort x, GLshort y, GLshort z, GLshort w );
+
+GLAPI void GLAPIENTRY glVertex2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex2iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glVertex3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex3iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glVertex4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glVertex4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glVertex4iv( const GLint *v );
+GLAPI void GLAPIENTRY glVertex4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glNormal3b( GLbyte nx, GLbyte ny, GLbyte nz );
+GLAPI void GLAPIENTRY glNormal3d( GLdouble nx, GLdouble ny, GLdouble nz );
+GLAPI void GLAPIENTRY glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz );
+GLAPI void GLAPIENTRY glNormal3i( GLint nx, GLint ny, GLint nz );
+GLAPI void GLAPIENTRY glNormal3s( GLshort nx, GLshort ny, GLshort nz );
+
+GLAPI void GLAPIENTRY glNormal3bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glNormal3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glNormal3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glNormal3iv( const GLint *v );
+GLAPI void GLAPIENTRY glNormal3sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glIndexd( GLdouble c );
+GLAPI void GLAPIENTRY glIndexf( GLfloat c );
+GLAPI void GLAPIENTRY glIndexi( GLint c );
+GLAPI void GLAPIENTRY glIndexs( GLshort c );
+GLAPI void GLAPIENTRY glIndexub( GLubyte c );  /* 1.1 */
+
+GLAPI void GLAPIENTRY glIndexdv( const GLdouble *c );
+GLAPI void GLAPIENTRY glIndexfv( const GLfloat *c );
+GLAPI void GLAPIENTRY glIndexiv( const GLint *c );
+GLAPI void GLAPIENTRY glIndexsv( const GLshort *c );
+GLAPI void GLAPIENTRY glIndexubv( const GLubyte *c );  /* 1.1 */
+
+GLAPI void GLAPIENTRY glColor3b( GLbyte red, GLbyte green, GLbyte blue );
+GLAPI void GLAPIENTRY glColor3d( GLdouble red, GLdouble green, GLdouble blue );
+GLAPI void GLAPIENTRY glColor3f( GLfloat red, GLfloat green, GLfloat blue );
+GLAPI void GLAPIENTRY glColor3i( GLint red, GLint green, GLint blue );
+GLAPI void GLAPIENTRY glColor3s( GLshort red, GLshort green, GLshort blue );
+GLAPI void GLAPIENTRY glColor3ub( GLubyte red, GLubyte green, GLubyte blue );
+GLAPI void GLAPIENTRY glColor3ui( GLuint red, GLuint green, GLuint blue );
+GLAPI void GLAPIENTRY glColor3us( GLushort red, GLushort green, GLushort blue );
+
+GLAPI void GLAPIENTRY glColor4b( GLbyte red, GLbyte green,
+                                   GLbyte blue, GLbyte alpha );
+GLAPI void GLAPIENTRY glColor4d( GLdouble red, GLdouble green,
+                                   GLdouble blue, GLdouble alpha );
+GLAPI void GLAPIENTRY glColor4f( GLfloat red, GLfloat green,
+                                   GLfloat blue, GLfloat alpha );
+GLAPI void GLAPIENTRY glColor4i( GLint red, GLint green,
+                                   GLint blue, GLint alpha );
+GLAPI void GLAPIENTRY glColor4s( GLshort red, GLshort green,
+                                   GLshort blue, GLshort alpha );
+GLAPI void GLAPIENTRY glColor4ub( GLubyte red, GLubyte green,
+                                    GLubyte blue, GLubyte alpha );
+GLAPI void GLAPIENTRY glColor4ui( GLuint red, GLuint green,
+                                    GLuint blue, GLuint alpha );
+GLAPI void GLAPIENTRY glColor4us( GLushort red, GLushort green,
+                                    GLushort blue, GLushort alpha );
+
+
+GLAPI void GLAPIENTRY glColor3bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glColor3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glColor3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glColor3iv( const GLint *v );
+GLAPI void GLAPIENTRY glColor3sv( const GLshort *v );
+GLAPI void GLAPIENTRY glColor3ubv( const GLubyte *v );
+GLAPI void GLAPIENTRY glColor3uiv( const GLuint *v );
+GLAPI void GLAPIENTRY glColor3usv( const GLushort *v );
+
+GLAPI void GLAPIENTRY glColor4bv( const GLbyte *v );
+GLAPI void GLAPIENTRY glColor4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glColor4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glColor4iv( const GLint *v );
+GLAPI void GLAPIENTRY glColor4sv( const GLshort *v );
+GLAPI void GLAPIENTRY glColor4ubv( const GLubyte *v );
+GLAPI void GLAPIENTRY glColor4uiv( const GLuint *v );
+GLAPI void GLAPIENTRY glColor4usv( const GLushort *v );
+
+
+GLAPI void GLAPIENTRY glTexCoord1d( GLdouble s );
+GLAPI void GLAPIENTRY glTexCoord1f( GLfloat s );
+GLAPI void GLAPIENTRY glTexCoord1i( GLint s );
+GLAPI void GLAPIENTRY glTexCoord1s( GLshort s );
+
+GLAPI void GLAPIENTRY glTexCoord2d( GLdouble s, GLdouble t );
+GLAPI void GLAPIENTRY glTexCoord2f( GLfloat s, GLfloat t );
+GLAPI void GLAPIENTRY glTexCoord2i( GLint s, GLint t );
+GLAPI void GLAPIENTRY glTexCoord2s( GLshort s, GLshort t );
+
+GLAPI void GLAPIENTRY glTexCoord3d( GLdouble s, GLdouble t, GLdouble r );
+GLAPI void GLAPIENTRY glTexCoord3f( GLfloat s, GLfloat t, GLfloat r );
+GLAPI void GLAPIENTRY glTexCoord3i( GLint s, GLint t, GLint r );
+GLAPI void GLAPIENTRY glTexCoord3s( GLshort s, GLshort t, GLshort r );
+
+GLAPI void GLAPIENTRY glTexCoord4d( GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+GLAPI void GLAPIENTRY glTexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+GLAPI void GLAPIENTRY glTexCoord4i( GLint s, GLint t, GLint r, GLint q );
+GLAPI void GLAPIENTRY glTexCoord4s( GLshort s, GLshort t, GLshort r, GLshort q );
+
+GLAPI void GLAPIENTRY glTexCoord1dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord1fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord1iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord1sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord2iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord3iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glTexCoord4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glTexCoord4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glTexCoord4iv( const GLint *v );
+GLAPI void GLAPIENTRY glTexCoord4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glRasterPos2d( GLdouble x, GLdouble y );
+GLAPI void GLAPIENTRY glRasterPos2f( GLfloat x, GLfloat y );
+GLAPI void GLAPIENTRY glRasterPos2i( GLint x, GLint y );
+GLAPI void GLAPIENTRY glRasterPos2s( GLshort x, GLshort y );
+
+GLAPI void GLAPIENTRY glRasterPos3d( GLdouble x, GLdouble y, GLdouble z );
+GLAPI void GLAPIENTRY glRasterPos3f( GLfloat x, GLfloat y, GLfloat z );
+GLAPI void GLAPIENTRY glRasterPos3i( GLint x, GLint y, GLint z );
+GLAPI void GLAPIENTRY glRasterPos3s( GLshort x, GLshort y, GLshort z );
+
+GLAPI void GLAPIENTRY glRasterPos4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+GLAPI void GLAPIENTRY glRasterPos4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+GLAPI void GLAPIENTRY glRasterPos4i( GLint x, GLint y, GLint z, GLint w );
+GLAPI void GLAPIENTRY glRasterPos4s( GLshort x, GLshort y, GLshort z, GLshort w );
+
+GLAPI void GLAPIENTRY glRasterPos2dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos2fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos2iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos2sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glRasterPos3dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos3fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos3iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos3sv( const GLshort *v );
+
+GLAPI void GLAPIENTRY glRasterPos4dv( const GLdouble *v );
+GLAPI void GLAPIENTRY glRasterPos4fv( const GLfloat *v );
+GLAPI void GLAPIENTRY glRasterPos4iv( const GLint *v );
+GLAPI void GLAPIENTRY glRasterPos4sv( const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glRectd( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );
+GLAPI void GLAPIENTRY glRectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );
+GLAPI void GLAPIENTRY glRecti( GLint x1, GLint y1, GLint x2, GLint y2 );
+GLAPI void GLAPIENTRY glRects( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );
+
+
+GLAPI void GLAPIENTRY glRectdv( const GLdouble *v1, const GLdouble *v2 );
+GLAPI void GLAPIENTRY glRectfv( const GLfloat *v1, const GLfloat *v2 );
+GLAPI void GLAPIENTRY glRectiv( const GLint *v1, const GLint *v2 );
+GLAPI void GLAPIENTRY glRectsv( const GLshort *v1, const GLshort *v2 );
+
+
+/*
+ * Vertex Arrays  (1.1)
+ */
+
+GLAPI void GLAPIENTRY glVertexPointer( GLint size, GLenum type,
+                                       GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glNormalPointer( GLenum type, GLsizei stride,
+                                       const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glColorPointer( GLint size, GLenum type,
+                                      GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glIndexPointer( GLenum type, GLsizei stride,
+                                      const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glTexCoordPointer( GLint size, GLenum type,
+                                         GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glEdgeFlagPointer( GLsizei stride, const GLvoid *ptr );
+
+GLAPI void GLAPIENTRY glGetPointerv( GLenum pname, GLvoid **params );
+
+GLAPI void GLAPIENTRY glArrayElement( GLint i );
+
+GLAPI void GLAPIENTRY glDrawArrays( GLenum mode, GLint first, GLsizei count );
+
+GLAPI void GLAPIENTRY glDrawElements( GLenum mode, GLsizei count,
+                                      GLenum type, const GLvoid *indices );
+
+GLAPI void GLAPIENTRY glInterleavedArrays( GLenum format, GLsizei stride,
+                                           const GLvoid *pointer );
+
+/*
+ * Lighting
+ */
+
+GLAPI void GLAPIENTRY glShadeModel( GLenum mode );
+
+GLAPI void GLAPIENTRY glLightf( GLenum light, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glLighti( GLenum light, GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glLightfv( GLenum light, GLenum pname,
+                                 const GLfloat *params );
+GLAPI void GLAPIENTRY glLightiv( GLenum light, GLenum pname,
+                                 const GLint *params );
+
+GLAPI void GLAPIENTRY glGetLightfv( GLenum light, GLenum pname,
+                                    GLfloat *params );
+GLAPI void GLAPIENTRY glGetLightiv( GLenum light, GLenum pname,
+                                    GLint *params );
+
+GLAPI void GLAPIENTRY glLightModelf( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glLightModeli( GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glLightModelfv( GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glLightModeliv( GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glMaterialf( GLenum face, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glMateriali( GLenum face, GLenum pname, GLint param );
+GLAPI void GLAPIENTRY glMaterialfv( GLenum face, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glMaterialiv( GLenum face, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetMaterialfv( GLenum face, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetMaterialiv( GLenum face, GLenum pname, GLint *params );
+
+GLAPI void GLAPIENTRY glColorMaterial( GLenum face, GLenum mode );
+
+
+/*
+ * Raster functions
+ */
+
+GLAPI void GLAPIENTRY glPixelZoom( GLfloat xfactor, GLfloat yfactor );
+
+GLAPI void GLAPIENTRY glPixelStoref( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glPixelStorei( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glPixelTransferf( GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glPixelTransferi( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glPixelMapfv( GLenum map, GLsizei mapsize,
+                                    const GLfloat *values );
+GLAPI void GLAPIENTRY glPixelMapuiv( GLenum map, GLsizei mapsize,
+                                     const GLuint *values );
+GLAPI void GLAPIENTRY glPixelMapusv( GLenum map, GLsizei mapsize,
+                                     const GLushort *values );
+
+GLAPI void GLAPIENTRY glGetPixelMapfv( GLenum map, GLfloat *values );
+GLAPI void GLAPIENTRY glGetPixelMapuiv( GLenum map, GLuint *values );
+GLAPI void GLAPIENTRY glGetPixelMapusv( GLenum map, GLushort *values );
+
+GLAPI void GLAPIENTRY glBitmap( GLsizei width, GLsizei height,
+                                GLfloat xorig, GLfloat yorig,
+                                GLfloat xmove, GLfloat ymove,
+                                const GLubyte *bitmap );
+
+GLAPI void GLAPIENTRY glReadPixels( GLint x, GLint y,
+                                    GLsizei width, GLsizei height,
+                                    GLenum format, GLenum type,
+                                    GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glDrawPixels( GLsizei width, GLsizei height,
+                                    GLenum format, GLenum type,
+                                    const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glCopyPixels( GLint x, GLint y,
+                                    GLsizei width, GLsizei height,
+                                    GLenum type );
+
+/*
+ * Stenciling
+ */
+
+GLAPI void GLAPIENTRY glStencilFunc( GLenum func, GLint ref, GLuint mask );
+
+GLAPI void GLAPIENTRY glStencilMask( GLuint mask );
+
+GLAPI void GLAPIENTRY glStencilOp( GLenum fail, GLenum zfail, GLenum zpass );
+
+GLAPI void GLAPIENTRY glClearStencil( GLint s );
+
+
+
+/*
+ * Texture mapping
+ */
+
+GLAPI void GLAPIENTRY glTexGend( GLenum coord, GLenum pname, GLdouble param );
+GLAPI void GLAPIENTRY glTexGenf( GLenum coord, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexGeni( GLenum coord, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexGendv( GLenum coord, GLenum pname, const GLdouble *params );
+GLAPI void GLAPIENTRY glTexGenfv( GLenum coord, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glTexGeniv( GLenum coord, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexGendv( GLenum coord, GLenum pname, GLdouble *params );
+GLAPI void GLAPIENTRY glGetTexGenfv( GLenum coord, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexGeniv( GLenum coord, GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexEnvf( GLenum target, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexEnvi( GLenum target, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexEnvfv( GLenum target, GLenum pname, const GLfloat *params );
+GLAPI void GLAPIENTRY glTexEnviv( GLenum target, GLenum pname, const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexEnvfv( GLenum target, GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexEnviv( GLenum target, GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexParameterf( GLenum target, GLenum pname, GLfloat param );
+GLAPI void GLAPIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glTexParameterfv( GLenum target, GLenum pname,
+                                          const GLfloat *params );
+GLAPI void GLAPIENTRY glTexParameteriv( GLenum target, GLenum pname,
+                                          const GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexParameterfv( GLenum target,
+                                           GLenum pname, GLfloat *params);
+GLAPI void GLAPIENTRY glGetTexParameteriv( GLenum target,
+                                           GLenum pname, GLint *params );
+
+GLAPI void GLAPIENTRY glGetTexLevelParameterfv( GLenum target, GLint level,
+                                                GLenum pname, GLfloat *params );
+GLAPI void GLAPIENTRY glGetTexLevelParameteriv( GLenum target, GLint level,
+                                                GLenum pname, GLint *params );
+
+
+GLAPI void GLAPIENTRY glTexImage1D( GLenum target, GLint level,
+                                    GLint internalFormat,
+                                    GLsizei width, GLint border,
+                                    GLenum format, GLenum type,
+                                    const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glTexImage2D( GLenum target, GLint level,
+                                    GLint internalFormat,
+                                    GLsizei width, GLsizei height,
+                                    GLint border, GLenum format, GLenum type,
+                                    const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glGetTexImage( GLenum target, GLint level,
+                                     GLenum format, GLenum type,
+                                     GLvoid *pixels );
+
+
+/* 1.1 functions */
+
+GLAPI void GLAPIENTRY glGenTextures( GLsizei n, GLuint *textures );
+
+GLAPI void GLAPIENTRY glDeleteTextures( GLsizei n, const GLuint *textures);
+
+GLAPI void GLAPIENTRY glBindTexture( GLenum target, GLuint texture );
+
+GLAPI void GLAPIENTRY glPrioritizeTextures( GLsizei n,
+                                            const GLuint *textures,
+                                            const GLclampf *priorities );
+
+GLAPI GLboolean GLAPIENTRY glAreTexturesResident( GLsizei n,
+                                                  const GLuint *textures,
+                                                  GLboolean *residences );
+
+GLAPI GLboolean GLAPIENTRY glIsTexture( GLuint texture );
+
+
+GLAPI void GLAPIENTRY glTexSubImage1D( GLenum target, GLint level,
+                                       GLint xoffset,
+                                       GLsizei width, GLenum format,
+                                       GLenum type, const GLvoid *pixels );
+
+
+GLAPI void GLAPIENTRY glTexSubImage2D( GLenum target, GLint level,
+                                       GLint xoffset, GLint yoffset,
+                                       GLsizei width, GLsizei height,
+                                       GLenum format, GLenum type,
+                                       const GLvoid *pixels );
+
+
+GLAPI void GLAPIENTRY glCopyTexImage1D( GLenum target, GLint level,
+                                        GLenum internalformat,
+                                        GLint x, GLint y,
+                                        GLsizei width, GLint border );
+
+
+GLAPI void GLAPIENTRY glCopyTexImage2D( GLenum target, GLint level,
+                                        GLenum internalformat,
+                                        GLint x, GLint y,
+                                        GLsizei width, GLsizei height,
+                                        GLint border );
+
+
+GLAPI void GLAPIENTRY glCopyTexSubImage1D( GLenum target, GLint level,
+                                           GLint xoffset, GLint x, GLint y,
+                                           GLsizei width );
+
+
+GLAPI void GLAPIENTRY glCopyTexSubImage2D( GLenum target, GLint level,
+                                           GLint xoffset, GLint yoffset,
+                                           GLint x, GLint y,
+                                           GLsizei width, GLsizei height );
+
+
+/*
+ * Evaluators
+ */
+
+GLAPI void GLAPIENTRY glMap1d( GLenum target, GLdouble u1, GLdouble u2,
+                               GLint stride,
+                               GLint order, const GLdouble *points );
+GLAPI void GLAPIENTRY glMap1f( GLenum target, GLfloat u1, GLfloat u2,
+                               GLint stride,
+                               GLint order, const GLfloat *points );
+
+GLAPI void GLAPIENTRY glMap2d( GLenum target,
+                    GLdouble u1, GLdouble u2, GLint ustride, GLint uorder,
+                    GLdouble v1, GLdouble v2, GLint vstride, GLint vorder,
+                    const GLdouble *points );
+GLAPI void GLAPIENTRY glMap2f( GLenum target,
+                    GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
+                    GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
+                    const GLfloat *points );
+
+GLAPI void GLAPIENTRY glGetMapdv( GLenum target, GLenum query, GLdouble *v );
+GLAPI void GLAPIENTRY glGetMapfv( GLenum target, GLenum query, GLfloat *v );
+GLAPI void GLAPIENTRY glGetMapiv( GLenum target, GLenum query, GLint *v );
+
+GLAPI void GLAPIENTRY glEvalCoord1d( GLdouble u );
+GLAPI void GLAPIENTRY glEvalCoord1f( GLfloat u );
+
+GLAPI void GLAPIENTRY glEvalCoord1dv( const GLdouble *u );
+GLAPI void GLAPIENTRY glEvalCoord1fv( const GLfloat *u );
+
+GLAPI void GLAPIENTRY glEvalCoord2d( GLdouble u, GLdouble v );
+GLAPI void GLAPIENTRY glEvalCoord2f( GLfloat u, GLfloat v );
+
+GLAPI void GLAPIENTRY glEvalCoord2dv( const GLdouble *u );
+GLAPI void GLAPIENTRY glEvalCoord2fv( const GLfloat *u );
+
+GLAPI void GLAPIENTRY glMapGrid1d( GLint un, GLdouble u1, GLdouble u2 );
+GLAPI void GLAPIENTRY glMapGrid1f( GLint un, GLfloat u1, GLfloat u2 );
+
+GLAPI void GLAPIENTRY glMapGrid2d( GLint un, GLdouble u1, GLdouble u2,
+                                   GLint vn, GLdouble v1, GLdouble v2 );
+GLAPI void GLAPIENTRY glMapGrid2f( GLint un, GLfloat u1, GLfloat u2,
+                                   GLint vn, GLfloat v1, GLfloat v2 );
+
+GLAPI void GLAPIENTRY glEvalPoint1( GLint i );
+
+GLAPI void GLAPIENTRY glEvalPoint2( GLint i, GLint j );
+
+GLAPI void GLAPIENTRY glEvalMesh1( GLenum mode, GLint i1, GLint i2 );
+
+GLAPI void GLAPIENTRY glEvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
+
+
+/*
+ * Fog
+ */
+
+GLAPI void GLAPIENTRY glFogf( GLenum pname, GLfloat param );
+
+GLAPI void GLAPIENTRY glFogi( GLenum pname, GLint param );
+
+GLAPI void GLAPIENTRY glFogfv( GLenum pname, const GLfloat *params );
+
+GLAPI void GLAPIENTRY glFogiv( GLenum pname, const GLint *params );
+
+
+/*
+ * Selection and Feedback
+ */
+
+GLAPI void GLAPIENTRY glFeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer );
+
+GLAPI void GLAPIENTRY glPassThrough( GLfloat token );
+
+GLAPI void GLAPIENTRY glSelectBuffer( GLsizei size, GLuint *buffer );
+
+GLAPI void GLAPIENTRY glInitNames( void );
+
+GLAPI void GLAPIENTRY glLoadName( GLuint name );
+
+GLAPI void GLAPIENTRY glPushName( GLuint name );
+
+GLAPI void GLAPIENTRY glPopName( void );
+
+
+
+/*
+ * OpenGL 1.2
+ */
+
+#define GL_RESCALE_NORMAL                      0x803A
+#define GL_CLAMP_TO_EDGE                       0x812F
+#define GL_MAX_ELEMENTS_VERTICES               0x80E8
+#define GL_MAX_ELEMENTS_INDICES                        0x80E9
+#define GL_BGR                                 0x80E0
+#define GL_BGRA                                        0x80E1
+#define GL_UNSIGNED_BYTE_3_3_2                 0x8032
+#define GL_UNSIGNED_BYTE_2_3_3_REV             0x8362
+#define GL_UNSIGNED_SHORT_5_6_5                        0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV            0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4              0x8033
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV          0x8365
+#define GL_UNSIGNED_SHORT_5_5_5_1              0x8034
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV          0x8366
+#define GL_UNSIGNED_INT_8_8_8_8                        0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV            0x8367
+#define GL_UNSIGNED_INT_10_10_10_2             0x8036
+#define GL_UNSIGNED_INT_2_10_10_10_REV         0x8368
+#define GL_LIGHT_MODEL_COLOR_CONTROL           0x81F8
+#define GL_SINGLE_COLOR                                0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR             0x81FA
+#define GL_TEXTURE_MIN_LOD                     0x813A
+#define GL_TEXTURE_MAX_LOD                     0x813B
+#define GL_TEXTURE_BASE_LEVEL                  0x813C
+#define GL_TEXTURE_MAX_LEVEL                   0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE             0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY       0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE             0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY       0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE            0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE            0x846E
+#define GL_PACK_SKIP_IMAGES                    0x806B
+#define GL_PACK_IMAGE_HEIGHT                   0x806C
+#define GL_UNPACK_SKIP_IMAGES                  0x806D
+#define GL_UNPACK_IMAGE_HEIGHT                 0x806E
+#define GL_TEXTURE_3D                          0x806F
+#define GL_PROXY_TEXTURE_3D                    0x8070
+#define GL_TEXTURE_DEPTH                       0x8071
+#define GL_TEXTURE_WRAP_R                      0x8072
+#define GL_MAX_3D_TEXTURE_SIZE                 0x8073
+#define GL_TEXTURE_BINDING_3D                  0x806A
+
+GLAPI void GLAPIENTRY glDrawRangeElements( GLenum mode, GLuint start,
+       GLuint end, GLsizei count, GLenum type, const GLvoid *indices );
+
+GLAPI void GLAPIENTRY glTexImage3D( GLenum target, GLint level,
+                                      GLint internalFormat,
+                                      GLsizei width, GLsizei height,
+                                      GLsizei depth, GLint border,
+                                      GLenum format, GLenum type,
+                                      const GLvoid *pixels );
+
+GLAPI void GLAPIENTRY glTexSubImage3D( GLenum target, GLint level,
+                                         GLint xoffset, GLint yoffset,
+                                         GLint zoffset, GLsizei width,
+                                         GLsizei height, GLsizei depth,
+                                         GLenum format,
+                                         GLenum type, const GLvoid *pixels);
+
+GLAPI void GLAPIENTRY glCopyTexSubImage3D( GLenum target, GLint level,
+                                             GLint xoffset, GLint yoffset,
+                                             GLint zoffset, GLint x,
+                                             GLint y, GLsizei width,
+                                             GLsizei height );
+
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+
+
+/*
+ * GL_ARB_imaging
+ */
+
+#define GL_CONSTANT_COLOR                      0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR            0x8002
+#define GL_CONSTANT_ALPHA                      0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA            0x8004
+#define GL_COLOR_TABLE                         0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE                0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE       0x80D2
+#define GL_PROXY_COLOR_TABLE                   0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE  0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE                   0x80D6
+#define GL_COLOR_TABLE_BIAS                    0x80D7
+#define GL_COLOR_TABLE_FORMAT                  0x80D8
+#define GL_COLOR_TABLE_WIDTH                   0x80D9
+#define GL_COLOR_TABLE_RED_SIZE                        0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE              0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE               0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE              0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE          0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE          0x80DF
+#define GL_CONVOLUTION_1D                      0x8010
+#define GL_CONVOLUTION_2D                      0x8011
+#define GL_SEPARABLE_2D                                0x8012
+#define GL_CONVOLUTION_BORDER_MODE             0x8013
+#define GL_CONVOLUTION_FILTER_SCALE            0x8014
+#define GL_CONVOLUTION_FILTER_BIAS             0x8015
+#define GL_REDUCE                              0x8016
+#define GL_CONVOLUTION_FORMAT                  0x8017
+#define GL_CONVOLUTION_WIDTH                   0x8018
+#define GL_CONVOLUTION_HEIGHT                  0x8019
+#define GL_MAX_CONVOLUTION_WIDTH               0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT              0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE          0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE                0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE         0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE                0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS           0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS         0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS          0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS         0x8023
+#define GL_CONSTANT_BORDER                     0x8151
+#define GL_REPLICATE_BORDER                    0x8153
+#define GL_CONVOLUTION_BORDER_COLOR            0x8154
+#define GL_COLOR_MATRIX                                0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH            0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH                0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE         0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE       0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE                0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE       0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS          0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS                0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS         0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS                0x80BB
+#define GL_HISTOGRAM                           0x8024
+#define GL_PROXY_HISTOGRAM                     0x8025
+#define GL_HISTOGRAM_WIDTH                     0x8026
+#define GL_HISTOGRAM_FORMAT                    0x8027
+#define GL_HISTOGRAM_RED_SIZE                  0x8028
+#define GL_HISTOGRAM_GREEN_SIZE                        0x8029
+#define GL_HISTOGRAM_BLUE_SIZE                 0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE                        0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE            0x802C
+#define GL_HISTOGRAM_SINK                      0x802D
+#define GL_MINMAX                              0x802E
+#define GL_MINMAX_FORMAT                       0x802F
+#define GL_MINMAX_SINK                         0x8030
+#define GL_TABLE_TOO_LARGE                     0x8031
+#define GL_BLEND_EQUATION                      0x8009
+#define GL_MIN                                 0x8007
+#define GL_MAX                                 0x8008
+#define GL_FUNC_ADD                            0x8006
+#define GL_FUNC_SUBTRACT                       0x800A
+#define GL_FUNC_REVERSE_SUBTRACT               0x800B
+#define GL_BLEND_COLOR                         0x8005
+
+
+GLAPI void GLAPIENTRY glColorTable( GLenum target, GLenum internalformat,
+                                    GLsizei width, GLenum format,
+                                    GLenum type, const GLvoid *table );
+
+GLAPI void GLAPIENTRY glColorSubTable( GLenum target,
+                                       GLsizei start, GLsizei count,
+                                       GLenum format, GLenum type,
+                                       const GLvoid *data );
+
+GLAPI void GLAPIENTRY glColorTableParameteriv(GLenum target, GLenum pname,
+                                              const GLint *params);
+
+GLAPI void GLAPIENTRY glColorTableParameterfv(GLenum target, GLenum pname,
+                                              const GLfloat *params);
+
+GLAPI void GLAPIENTRY glCopyColorSubTable( GLenum target, GLsizei start,
+                                           GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glCopyColorTable( GLenum target, GLenum internalformat,
+                                        GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glGetColorTable( GLenum target, GLenum format,
+                                       GLenum type, GLvoid *table );
+
+GLAPI void GLAPIENTRY glGetColorTableParameterfv( GLenum target, GLenum pname,
+                                                  GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetColorTableParameteriv( GLenum target, GLenum pname,
+                                                  GLint *params );
+
+GLAPI void GLAPIENTRY glBlendEquation( GLenum mode );
+
+GLAPI void GLAPIENTRY glBlendColor( GLclampf red, GLclampf green,
+                                    GLclampf blue, GLclampf alpha );
+
+GLAPI void GLAPIENTRY glHistogram( GLenum target, GLsizei width,
+                                  GLenum internalformat, GLboolean sink );
+
+GLAPI void GLAPIENTRY glResetHistogram( GLenum target );
+
+GLAPI void GLAPIENTRY glGetHistogram( GLenum target, GLboolean reset,
+                                     GLenum format, GLenum type,
+                                     GLvoid *values );
+
+GLAPI void GLAPIENTRY glGetHistogramParameterfv( GLenum target, GLenum pname,
+                                                GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetHistogramParameteriv( GLenum target, GLenum pname,
+                                                GLint *params );
+
+GLAPI void GLAPIENTRY glMinmax( GLenum target, GLenum internalformat,
+                               GLboolean sink );
+
+GLAPI void GLAPIENTRY glResetMinmax( GLenum target );
+
+GLAPI void GLAPIENTRY glGetMinmax( GLenum target, GLboolean reset,
+                                   GLenum format, GLenum types,
+                                   GLvoid *values );
+
+GLAPI void GLAPIENTRY glGetMinmaxParameterfv( GLenum target, GLenum pname,
+                                             GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetMinmaxParameteriv( GLenum target, GLenum pname,
+                                             GLint *params );
+
+GLAPI void GLAPIENTRY glConvolutionFilter1D( GLenum target,
+       GLenum internalformat, GLsizei width, GLenum format, GLenum type,
+       const GLvoid *image );
+
+GLAPI void GLAPIENTRY glConvolutionFilter2D( GLenum target,
+       GLenum internalformat, GLsizei width, GLsizei height, GLenum format,
+       GLenum type, const GLvoid *image );
+
+GLAPI void GLAPIENTRY glConvolutionParameterf( GLenum target, GLenum pname,
+       GLfloat params );
+
+GLAPI void GLAPIENTRY glConvolutionParameterfv( GLenum target, GLenum pname,
+       const GLfloat *params );
+
+GLAPI void GLAPIENTRY glConvolutionParameteri( GLenum target, GLenum pname,
+       GLint params );
+
+GLAPI void GLAPIENTRY glConvolutionParameteriv( GLenum target, GLenum pname,
+       const GLint *params );
+
+GLAPI void GLAPIENTRY glCopyConvolutionFilter1D( GLenum target,
+       GLenum internalformat, GLint x, GLint y, GLsizei width );
+
+GLAPI void GLAPIENTRY glCopyConvolutionFilter2D( GLenum target,
+       GLenum internalformat, GLint x, GLint y, GLsizei width,
+       GLsizei height);
+
+GLAPI void GLAPIENTRY glGetConvolutionFilter( GLenum target, GLenum format,
+       GLenum type, GLvoid *image );
+
+GLAPI void GLAPIENTRY glGetConvolutionParameterfv( GLenum target, GLenum pname,
+       GLfloat *params );
+
+GLAPI void GLAPIENTRY glGetConvolutionParameteriv( GLenum target, GLenum pname,
+       GLint *params );
+
+GLAPI void GLAPIENTRY glSeparableFilter2D( GLenum target,
+       GLenum internalformat, GLsizei width, GLsizei height, GLenum format,
+       GLenum type, const GLvoid *row, const GLvoid *column );
+
+GLAPI void GLAPIENTRY glGetSeparableFilter( GLenum target, GLenum format,
+       GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );
+
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+
+
+
+/*
+ * OpenGL 1.3
+ */
+
+/* multitexture */
+#define GL_TEXTURE0                            0x84C0
+#define GL_TEXTURE1                            0x84C1
+#define GL_TEXTURE2                            0x84C2
+#define GL_TEXTURE3                            0x84C3
+#define GL_TEXTURE4                            0x84C4
+#define GL_TEXTURE5                            0x84C5
+#define GL_TEXTURE6                            0x84C6
+#define GL_TEXTURE7                            0x84C7
+#define GL_TEXTURE8                            0x84C8
+#define GL_TEXTURE9                            0x84C9
+#define GL_TEXTURE10                           0x84CA
+#define GL_TEXTURE11                           0x84CB
+#define GL_TEXTURE12                           0x84CC
+#define GL_TEXTURE13                           0x84CD
+#define GL_TEXTURE14                           0x84CE
+#define GL_TEXTURE15                           0x84CF
+#define GL_TEXTURE16                           0x84D0
+#define GL_TEXTURE17                           0x84D1
+#define GL_TEXTURE18                           0x84D2
+#define GL_TEXTURE19                           0x84D3
+#define GL_TEXTURE20                           0x84D4
+#define GL_TEXTURE21                           0x84D5
+#define GL_TEXTURE22                           0x84D6
+#define GL_TEXTURE23                           0x84D7
+#define GL_TEXTURE24                           0x84D8
+#define GL_TEXTURE25                           0x84D9
+#define GL_TEXTURE26                           0x84DA
+#define GL_TEXTURE27                           0x84DB
+#define GL_TEXTURE28                           0x84DC
+#define GL_TEXTURE29                           0x84DD
+#define GL_TEXTURE30                           0x84DE
+#define GL_TEXTURE31                           0x84DF
+#define GL_ACTIVE_TEXTURE                      0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE               0x84E1
+#define GL_MAX_TEXTURE_UNITS                   0x84E2
+/* texture_cube_map */
+#define GL_NORMAL_MAP                          0x8511
+#define GL_REFLECTION_MAP                      0x8512
+#define GL_TEXTURE_CUBE_MAP                    0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP            0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X         0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X         0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y         0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y         0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z         0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z         0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP              0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE           0x851C
+/* texture_compression */
+#define GL_COMPRESSED_ALPHA                    0x84E9
+#define GL_COMPRESSED_LUMINANCE                        0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA          0x84EB
+#define GL_COMPRESSED_INTENSITY                        0x84EC
+#define GL_COMPRESSED_RGB                      0x84ED
+#define GL_COMPRESSED_RGBA                     0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT            0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE       0x86A0
+#define GL_TEXTURE_COMPRESSED                  0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS      0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS          0x86A3
+/* multisample */
+#define GL_MULTISAMPLE                         0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE            0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE                 0x809F
+#define GL_SAMPLE_COVERAGE                     0x80A0
+#define GL_SAMPLE_BUFFERS                      0x80A8
+#define GL_SAMPLES                             0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE               0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT              0x80AB
+#define GL_MULTISAMPLE_BIT                     0x20000000
+/* transpose_matrix */
+#define GL_TRANSPOSE_MODELVIEW_MATRIX          0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX         0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX            0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX              0x84E6
+/* texture_env_combine */
+#define GL_COMBINE                             0x8570
+#define GL_COMBINE_RGB                         0x8571
+#define GL_COMBINE_ALPHA                       0x8572
+#define GL_SOURCE0_RGB                         0x8580
+#define GL_SOURCE1_RGB                         0x8581
+#define GL_SOURCE2_RGB                         0x8582
+#define GL_SOURCE0_ALPHA                       0x8588
+#define GL_SOURCE1_ALPHA                       0x8589
+#define GL_SOURCE2_ALPHA                       0x858A
+#define GL_OPERAND0_RGB                                0x8590
+#define GL_OPERAND1_RGB                                0x8591
+#define GL_OPERAND2_RGB                                0x8592
+#define GL_OPERAND0_ALPHA                      0x8598
+#define GL_OPERAND1_ALPHA                      0x8599
+#define GL_OPERAND2_ALPHA                      0x859A
+#define GL_RGB_SCALE                           0x8573
+#define GL_ADD_SIGNED                          0x8574
+#define GL_INTERPOLATE                         0x8575
+#define GL_SUBTRACT                            0x84E7
+#define GL_CONSTANT                            0x8576
+#define GL_PRIMARY_COLOR                       0x8577
+#define GL_PREVIOUS                            0x8578
+/* texture_env_dot3 */
+#define GL_DOT3_RGB                            0x86AE
+#define GL_DOT3_RGBA                           0x86AF
+/* texture_border_clamp */
+#define GL_CLAMP_TO_BORDER                     0x812D
+
+GLAPI void GLAPIENTRY glActiveTexture( GLenum texture );
+
+GLAPI void GLAPIENTRY glClientActiveTexture( GLenum texture );
+
+GLAPI void GLAPIENTRY glCompressedTexImage1D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glCompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data );
+
+GLAPI void GLAPIENTRY glGetCompressedTexImage( GLenum target, GLint lod, GLvoid *img );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1d( GLenum target, GLdouble s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1f( GLenum target, GLfloat s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1i( GLenum target, GLint s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1s( GLenum target, GLshort s );
+
+GLAPI void GLAPIENTRY glMultiTexCoord1sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2d( GLenum target, GLdouble s, GLdouble t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2f( GLenum target, GLfloat s, GLfloat t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2i( GLenum target, GLint s, GLint t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2s( GLenum target, GLshort s, GLshort t );
+
+GLAPI void GLAPIENTRY glMultiTexCoord2sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3d( GLenum target, GLdouble s, GLdouble t, GLdouble r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3f( GLenum target, GLfloat s, GLfloat t, GLfloat r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3i( GLenum target, GLint s, GLint t, GLint r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3s( GLenum target, GLshort s, GLshort t, GLshort r );
+
+GLAPI void GLAPIENTRY glMultiTexCoord3sv( GLenum target, const GLshort *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4d( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4dv( GLenum target, const GLdouble *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4f( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4fv( GLenum target, const GLfloat *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4i( GLenum target, GLint s, GLint t, GLint r, GLint q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4iv( GLenum target, const GLint *v );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4s( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
+
+GLAPI void GLAPIENTRY glMultiTexCoord4sv( GLenum target, const GLshort *v );
+
+
+GLAPI void GLAPIENTRY glLoadTransposeMatrixd( const GLdouble m[16] );
+
+GLAPI void GLAPIENTRY glLoadTransposeMatrixf( const GLfloat m[16] );
+
+GLAPI void GLAPIENTRY glMultTransposeMatrixd( const GLdouble m[16] );
+
+GLAPI void GLAPIENTRY glMultTransposeMatrixf( const GLfloat m[16] );
+
+GLAPI void GLAPIENTRY glSampleCoverage( GLclampf value, GLboolean invert );
+
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
+
+
+/*
+ * GL_ARB_multitexture (ARB extension 1 and OpenGL 1.2.1)
+ */
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+
+#define GL_TEXTURE0_ARB                                0x84C0
+#define GL_TEXTURE1_ARB                                0x84C1
+#define GL_TEXTURE2_ARB                                0x84C2
+#define GL_TEXTURE3_ARB                                0x84C3
+#define GL_TEXTURE4_ARB                                0x84C4
+#define GL_TEXTURE5_ARB                                0x84C5
+#define GL_TEXTURE6_ARB                                0x84C6
+#define GL_TEXTURE7_ARB                                0x84C7
+#define GL_TEXTURE8_ARB                                0x84C8
+#define GL_TEXTURE9_ARB                                0x84C9
+#define GL_TEXTURE10_ARB                       0x84CA
+#define GL_TEXTURE11_ARB                       0x84CB
+#define GL_TEXTURE12_ARB                       0x84CC
+#define GL_TEXTURE13_ARB                       0x84CD
+#define GL_TEXTURE14_ARB                       0x84CE
+#define GL_TEXTURE15_ARB                       0x84CF
+#define GL_TEXTURE16_ARB                       0x84D0
+#define GL_TEXTURE17_ARB                       0x84D1
+#define GL_TEXTURE18_ARB                       0x84D2
+#define GL_TEXTURE19_ARB                       0x84D3
+#define GL_TEXTURE20_ARB                       0x84D4
+#define GL_TEXTURE21_ARB                       0x84D5
+#define GL_TEXTURE22_ARB                       0x84D6
+#define GL_TEXTURE23_ARB                       0x84D7
+#define GL_TEXTURE24_ARB                       0x84D8
+#define GL_TEXTURE25_ARB                       0x84D9
+#define GL_TEXTURE26_ARB                       0x84DA
+#define GL_TEXTURE27_ARB                       0x84DB
+#define GL_TEXTURE28_ARB                       0x84DC
+#define GL_TEXTURE29_ARB                       0x84DD
+#define GL_TEXTURE30_ARB                       0x84DE
+#define GL_TEXTURE31_ARB                       0x84DF
+#define GL_ACTIVE_TEXTURE_ARB                  0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB           0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB               0x84E2
+
+GLAPI void GLAPIENTRY glActiveTextureARB(GLenum texture);
+GLAPI void GLAPIENTRY glClientActiveTextureARB(GLenum texture);
+GLAPI void GLAPIENTRY glMultiTexCoord1dARB(GLenum target, GLdouble s);
+GLAPI void GLAPIENTRY glMultiTexCoord1dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1fARB(GLenum target, GLfloat s);
+GLAPI void GLAPIENTRY glMultiTexCoord1fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1iARB(GLenum target, GLint s);
+GLAPI void GLAPIENTRY glMultiTexCoord1ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord1sARB(GLenum target, GLshort s);
+GLAPI void GLAPIENTRY glMultiTexCoord1svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2dARB(GLenum target, GLdouble s, GLdouble t);
+GLAPI void GLAPIENTRY glMultiTexCoord2dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t);
+GLAPI void GLAPIENTRY glMultiTexCoord2fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2iARB(GLenum target, GLint s, GLint t);
+GLAPI void GLAPIENTRY glMultiTexCoord2ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord2sARB(GLenum target, GLshort s, GLshort t);
+GLAPI void GLAPIENTRY glMultiTexCoord2svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void GLAPIENTRY glMultiTexCoord3dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void GLAPIENTRY glMultiTexCoord3fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3iARB(GLenum target, GLint s, GLint t, GLint r);
+GLAPI void GLAPIENTRY glMultiTexCoord3ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord3sARB(GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void GLAPIENTRY glMultiTexCoord3svARB(GLenum target, const GLshort *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void GLAPIENTRY glMultiTexCoord4dvARB(GLenum target, const GLdouble *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void GLAPIENTRY glMultiTexCoord4fvARB(GLenum target, const GLfloat *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4iARB(GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void GLAPIENTRY glMultiTexCoord4ivARB(GLenum target, const GLint *v);
+GLAPI void GLAPIENTRY glMultiTexCoord4sARB(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void GLAPIENTRY glMultiTexCoord4svARB(GLenum target, const GLshort *v);
+
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+
+#endif /* GL_ARB_multitexture */
+
+
+
+/*
+ * Define this token if you want "old-style" header file behaviour (extensions
+ * defined in gl.h).  Otherwise, extensions will be included from glext.h.
+ */
+#if defined(GL_GLEXT_LEGACY)
+
+/* All extensions that used to be here are now found in glext.h */
+
+#else  /* GL_GLEXT_LEGACY */
+
+#include <mesa_glext.h>
+
+#endif  /* GL_GLEXT_LEGACY */
+
+
+
+#if GL_ARB_shader_objects
+
+#ifndef GL_MESA_shader_debug
+#define GL_MESA_shader_debug 1
+
+#define GL_DEBUG_OBJECT_MESA              0x8759
+#define GL_DEBUG_PRINT_MESA               0x875A
+#define GL_DEBUG_ASSERT_MESA              0x875B
+
+GLAPI GLhandleARB APIENTRY glCreateDebugObjectMESA (void);
+GLAPI void APIENTRY glClearDebugLogMESA (GLhandleARB obj, GLenum logType, GLenum shaderType);
+GLAPI void APIENTRY glGetDebugLogMESA (GLhandleARB obj, GLenum logType, GLenum shaderType, GLsizei maxLength,
+                                         GLsizei *length, GLcharARB *debugLog);
+GLAPI GLsizei APIENTRY glGetDebugLogLengthMESA (GLhandleARB obj, GLenum logType, GLenum shaderType);
+
+#endif /* GL_MESA_shader_debug */
+
+#endif /* GL_ARB_shader_objects */
+
+
+/*
+ * ???. GL_MESA_packed_depth_stencil
+ * XXX obsolete
+ */
+#ifndef GL_MESA_packed_depth_stencil
+#define GL_MESA_packed_depth_stencil 1
+
+#define GL_DEPTH_STENCIL_MESA                  0x8750
+#define GL_UNSIGNED_INT_24_8_MESA              0x8751
+#define GL_UNSIGNED_INT_8_24_REV_MESA          0x8752
+#define GL_UNSIGNED_SHORT_15_1_MESA            0x8753
+#define GL_UNSIGNED_SHORT_1_15_REV_MESA                0x8754
+
+#endif /* GL_MESA_packed_depth_stencil */
+
+
+#ifndef GL_MESA_program_debug
+#define GL_MESA_program_debug 1
+
+#define GL_FRAGMENT_PROGRAM_POSITION_MESA       0x8bb0
+#define GL_FRAGMENT_PROGRAM_CALLBACK_MESA       0x8bb1
+#define GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA  0x8bb2
+#define GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA  0x8bb3
+#define GL_VERTEX_PROGRAM_POSITION_MESA         0x8bb4
+#define GL_VERTEX_PROGRAM_CALLBACK_MESA         0x8bb5
+#define GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA    0x8bb6
+#define GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA    0x8bb7
+
+typedef void (*GLprogramcallbackMESA)(GLenum target, GLvoid *data);
+
+GLAPI void GLAPIENTRY glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback, GLvoid *data);
+
+GLAPI void GLAPIENTRY glGetProgramRegisterfvMESA(GLenum target, GLsizei len, const GLubyte *name, GLfloat *v);
+
+#endif /* GL_MESA_program_debug */
+
+
+#ifndef GL_ATI_blend_equation_separate
+#define GL_ATI_blend_equation_separate 1
+
+#define GL_ALPHA_BLEND_EQUATION_ATI            0x883D
+
+GLAPI void GLAPIENTRY glBlendEquationSeparateATI( GLenum modeRGB, GLenum modeA );
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEATIPROC) (GLenum modeRGB, GLenum modeA);
+
+#endif /* GL_ATI_blend_equation_separate */
+
+
+
+/**
+ ** NOTE!!!!!  If you add new functions to this file, or update
+ ** glext.h be sure to regenerate the gl_mangle.h file.  See comments
+ ** in that file for details.
+ **/
+
+
+
+/**********************************************************************
+ * Begin system-specific stuff
+ */
+#if defined(PRAGMA_EXPORT_SUPPORTED)
+#pragma export off
+#endif
+
+#if defined(macintosh) && PRAGMA_IMPORT_SUPPORTED
+#pragma import off
+#endif
+/*
+ * End system-specific stuff
+ **********************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
diff --git a/tizen/src/hw/mesa_glext.h b/tizen/src/hw/mesa_glext.h
new file mode 100755 (executable)
index 0000000..1b3a170
--- /dev/null
@@ -0,0 +1,7279 @@
+#ifndef __glext_h_
+#define __glext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007 The Khronos Group Inc.
+** 
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+** 
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+/*************************************************************/
+
+/* Header file version number, required by OpenGL ABI for Linux */
+/* glext.h last updated 2007/02/12 */
+/* Current version at http://www.opengl.org/registry/ */
+#define GL_GLEXT_VERSION 39
+
+#ifndef GL_VERSION_1_2
+#define GL_UNSIGNED_BYTE_3_3_2            0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_INT_8_8_8_8           0x8035
+#define GL_UNSIGNED_INT_10_10_10_2        0x8036
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_TEXTURE_BINDING_3D             0x806A
+#define GL_PACK_SKIP_IMAGES               0x806B
+#define GL_PACK_IMAGE_HEIGHT              0x806C
+#define GL_UNPACK_SKIP_IMAGES             0x806D
+#define GL_UNPACK_IMAGE_HEIGHT            0x806E
+#define GL_TEXTURE_3D                     0x806F
+#define GL_PROXY_TEXTURE_3D               0x8070
+#define GL_TEXTURE_DEPTH                  0x8071
+#define GL_TEXTURE_WRAP_R                 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE            0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV        0x8362
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV       0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV     0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV     0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#define GL_BGR                            0x80E0
+#define GL_BGRA                           0x80E1
+#define GL_MAX_ELEMENTS_VERTICES          0x80E8
+#define GL_MAX_ELEMENTS_INDICES           0x80E9
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_TEXTURE_MIN_LOD                0x813A
+#define GL_TEXTURE_MAX_LOD                0x813B
+#define GL_TEXTURE_BASE_LEVEL             0x813C
+#define GL_TEXTURE_MAX_LEVEL              0x813D
+#define GL_LIGHT_MODEL_COLOR_CONTROL      0x81F8
+#define GL_SINGLE_COLOR                   0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR        0x81FA
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY  0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY  0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#endif
+
+#ifndef GL_ARB_imaging
+#define GL_CONSTANT_COLOR                 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002
+#define GL_CONSTANT_ALPHA                 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004
+#define GL_BLEND_COLOR                    0x8005
+#define GL_FUNC_ADD                       0x8006
+#define GL_MIN                            0x8007
+#define GL_MAX                            0x8008
+#define GL_BLEND_EQUATION                 0x8009
+#define GL_FUNC_SUBTRACT                  0x800A
+#define GL_FUNC_REVERSE_SUBTRACT          0x800B
+#define GL_CONVOLUTION_1D                 0x8010
+#define GL_CONVOLUTION_2D                 0x8011
+#define GL_SEPARABLE_2D                   0x8012
+#define GL_CONVOLUTION_BORDER_MODE        0x8013
+#define GL_CONVOLUTION_FILTER_SCALE       0x8014
+#define GL_CONVOLUTION_FILTER_BIAS        0x8015
+#define GL_REDUCE                         0x8016
+#define GL_CONVOLUTION_FORMAT             0x8017
+#define GL_CONVOLUTION_WIDTH              0x8018
+#define GL_CONVOLUTION_HEIGHT             0x8019
+#define GL_MAX_CONVOLUTION_WIDTH          0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT         0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE     0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS      0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023
+#define GL_HISTOGRAM                      0x8024
+#define GL_PROXY_HISTOGRAM                0x8025
+#define GL_HISTOGRAM_WIDTH                0x8026
+#define GL_HISTOGRAM_FORMAT               0x8027
+#define GL_HISTOGRAM_RED_SIZE             0x8028
+#define GL_HISTOGRAM_GREEN_SIZE           0x8029
+#define GL_HISTOGRAM_BLUE_SIZE            0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE           0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C
+#define GL_HISTOGRAM_SINK                 0x802D
+#define GL_MINMAX                         0x802E
+#define GL_MINMAX_FORMAT                  0x802F
+#define GL_MINMAX_SINK                    0x8030
+#define GL_TABLE_TOO_LARGE                0x8031
+#define GL_COLOR_MATRIX                   0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB
+#define GL_COLOR_TABLE                    0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2
+#define GL_PROXY_COLOR_TABLE              0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE              0x80D6
+#define GL_COLOR_TABLE_BIAS               0x80D7
+#define GL_COLOR_TABLE_FORMAT             0x80D8
+#define GL_COLOR_TABLE_WIDTH              0x80D9
+#define GL_COLOR_TABLE_RED_SIZE           0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF
+#define GL_CONSTANT_BORDER                0x8151
+#define GL_REPLICATE_BORDER               0x8153
+#define GL_CONVOLUTION_BORDER_COLOR       0x8154
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+#define GL_MULTISAMPLE_BIT                0x20000000
+#define GL_NORMAL_MAP                     0x8511
+#define GL_REFLECTION_MAP                 0x8512
+#define GL_TEXTURE_CUBE_MAP               0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+#define GL_COMPRESSED_ALPHA               0x84E9
+#define GL_COMPRESSED_LUMINANCE           0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB
+#define GL_COMPRESSED_INTENSITY           0x84EC
+#define GL_COMPRESSED_RGB                 0x84ED
+#define GL_COMPRESSED_RGBA                0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT       0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0
+#define GL_TEXTURE_COMPRESSED             0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+#define GL_CLAMP_TO_BORDER                0x812D
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_SOURCE0_RGB                    0x8580
+#define GL_SOURCE1_RGB                    0x8581
+#define GL_SOURCE2_RGB                    0x8582
+#define GL_SOURCE0_ALPHA                  0x8588
+#define GL_SOURCE1_ALPHA                  0x8589
+#define GL_SOURCE2_ALPHA                  0x858A
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_SUBTRACT                       0x84E7
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_BLEND_DST_RGB                  0x80C8
+#define GL_BLEND_SRC_RGB                  0x80C9
+#define GL_BLEND_DST_ALPHA                0x80CA
+#define GL_BLEND_SRC_ALPHA                0x80CB
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_GENERATE_MIPMAP                0x8191
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+#define GL_DEPTH_COMPONENT16              0x81A5
+#define GL_DEPTH_COMPONENT24              0x81A6
+#define GL_DEPTH_COMPONENT32              0x81A7
+#define GL_MIRRORED_REPEAT                0x8370
+#define GL_FOG_COORDINATE_SOURCE          0x8450
+#define GL_FOG_COORDINATE                 0x8451
+#define GL_FRAGMENT_DEPTH                 0x8452
+#define GL_CURRENT_FOG_COORDINATE         0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE      0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE    0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER   0x8456
+#define GL_FOG_COORDINATE_ARRAY           0x8457
+#define GL_COLOR_SUM                      0x8458
+#define GL_CURRENT_SECONDARY_COLOR        0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE     0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE     0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE   0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER  0x845D
+#define GL_SECONDARY_COLOR_ARRAY          0x845E
+#define GL_MAX_TEXTURE_LOD_BIAS           0x84FD
+#define GL_TEXTURE_FILTER_CONTROL         0x8500
+#define GL_TEXTURE_LOD_BIAS               0x8501
+#define GL_INCR_WRAP                      0x8507
+#define GL_DECR_WRAP                      0x8508
+#define GL_TEXTURE_DEPTH_SIZE             0x884A
+#define GL_DEPTH_TEXTURE_MODE             0x884B
+#define GL_TEXTURE_COMPARE_MODE           0x884C
+#define GL_TEXTURE_COMPARE_FUNC           0x884D
+#define GL_COMPARE_R_TO_TEXTURE           0x884E
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+#define GL_QUERY_COUNTER_BITS             0x8864
+#define GL_CURRENT_QUERY                  0x8865
+#define GL_QUERY_RESULT                   0x8866
+#define GL_QUERY_RESULT_AVAILABLE         0x8867
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+#define GL_ARRAY_BUFFER_BINDING           0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING    0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING    0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING     0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING     0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING    0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY                      0x88B8
+#define GL_WRITE_ONLY                     0x88B9
+#define GL_READ_WRITE                     0x88BA
+#define GL_BUFFER_ACCESS                  0x88BB
+#define GL_BUFFER_MAPPED                  0x88BC
+#define GL_BUFFER_MAP_POINTER             0x88BD
+#define GL_STREAM_DRAW                    0x88E0
+#define GL_STREAM_READ                    0x88E1
+#define GL_STREAM_COPY                    0x88E2
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_STATIC_READ                    0x88E5
+#define GL_STATIC_COPY                    0x88E6
+#define GL_DYNAMIC_DRAW                   0x88E8
+#define GL_DYNAMIC_READ                   0x88E9
+#define GL_DYNAMIC_COPY                   0x88EA
+#define GL_SAMPLES_PASSED                 0x8914
+#define GL_FOG_COORD_SRC                  GL_FOG_COORDINATE_SOURCE
+#define GL_FOG_COORD                      GL_FOG_COORDINATE
+#define GL_CURRENT_FOG_COORD              GL_CURRENT_FOG_COORDINATE
+#define GL_FOG_COORD_ARRAY_TYPE           GL_FOG_COORDINATE_ARRAY_TYPE
+#define GL_FOG_COORD_ARRAY_STRIDE         GL_FOG_COORDINATE_ARRAY_STRIDE
+#define GL_FOG_COORD_ARRAY_POINTER        GL_FOG_COORDINATE_ARRAY_POINTER
+#define GL_FOG_COORD_ARRAY                GL_FOG_COORDINATE_ARRAY
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
+#define GL_SRC0_RGB                       GL_SOURCE0_RGB
+#define GL_SRC1_RGB                       GL_SOURCE1_RGB
+#define GL_SRC2_RGB                       GL_SOURCE2_RGB
+#define GL_SRC0_ALPHA                     GL_SOURCE0_ALPHA
+#define GL_SRC1_ALPHA                     GL_SOURCE1_ALPHA
+#define GL_SRC2_ALPHA                     GL_SOURCE2_ALPHA
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_BLEND_EQUATION_RGB             GL_BLEND_EQUATION
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625
+#define GL_CURRENT_VERTEX_ATTRIB          0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE      0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE        0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645
+#define GL_STENCIL_BACK_FUNC              0x8800
+#define GL_STENCIL_BACK_FAIL              0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803
+#define GL_MAX_DRAW_BUFFERS               0x8824
+#define GL_DRAW_BUFFER0                   0x8825
+#define GL_DRAW_BUFFER1                   0x8826
+#define GL_DRAW_BUFFER2                   0x8827
+#define GL_DRAW_BUFFER3                   0x8828
+#define GL_DRAW_BUFFER4                   0x8829
+#define GL_DRAW_BUFFER5                   0x882A
+#define GL_DRAW_BUFFER6                   0x882B
+#define GL_DRAW_BUFFER7                   0x882C
+#define GL_DRAW_BUFFER8                   0x882D
+#define GL_DRAW_BUFFER9                   0x882E
+#define GL_DRAW_BUFFER10                  0x882F
+#define GL_DRAW_BUFFER11                  0x8830
+#define GL_DRAW_BUFFER12                  0x8831
+#define GL_DRAW_BUFFER13                  0x8832
+#define GL_DRAW_BUFFER14                  0x8833
+#define GL_DRAW_BUFFER15                  0x8834
+#define GL_BLEND_EQUATION_ALPHA           0x883D
+#define GL_POINT_SPRITE                   0x8861
+#define GL_COORD_REPLACE                  0x8862
+#define GL_MAX_VERTEX_ATTRIBS             0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_COORDS             0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS        0x8872
+#define GL_FRAGMENT_SHADER                0x8B30
+#define GL_VERTEX_SHADER                  0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS  0x8B4A
+#define GL_MAX_VARYING_FLOATS             0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE                    0x8B4F
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_SAMPLER_1D                     0x8B5D
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_3D                     0x8B5F
+#define GL_SAMPLER_CUBE                   0x8B60
+#define GL_SAMPLER_1D_SHADOW              0x8B61
+#define GL_SAMPLER_2D_SHADOW              0x8B62
+#define GL_DELETE_STATUS                  0x8B80
+#define GL_COMPILE_STATUS                 0x8B81
+#define GL_LINK_STATUS                    0x8B82
+#define GL_VALIDATE_STATUS                0x8B83
+#define GL_INFO_LOG_LENGTH                0x8B84
+#define GL_ATTACHED_SHADERS               0x8B85
+#define GL_ACTIVE_UNIFORMS                0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH      0x8B87
+#define GL_SHADER_SOURCE_LENGTH           0x8B88
+#define GL_ACTIVE_ATTRIBUTES              0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH    0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION       0x8B8C
+#define GL_CURRENT_PROGRAM                0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN      0x8CA0
+#define GL_LOWER_LEFT                     0x8CA1
+#define GL_UPPER_LEFT                     0x8CA2
+#define GL_STENCIL_BACK_REF               0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK         0x8CA5
+#endif
+
+#ifndef GL_VERSION_2_1
+#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F
+#define GL_PIXEL_PACK_BUFFER              0x88EB
+#define GL_PIXEL_UNPACK_BUFFER            0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING      0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING    0x88EF
+#define GL_FLOAT_MAT2x3                   0x8B65
+#define GL_FLOAT_MAT2x4                   0x8B66
+#define GL_FLOAT_MAT3x2                   0x8B67
+#define GL_FLOAT_MAT3x4                   0x8B68
+#define GL_FLOAT_MAT4x2                   0x8B69
+#define GL_FLOAT_MAT4x3                   0x8B6A
+#define GL_SRGB                           0x8C40
+#define GL_SRGB8                          0x8C41
+#define GL_SRGB_ALPHA                     0x8C42
+#define GL_SRGB8_ALPHA8                   0x8C43
+#define GL_SLUMINANCE_ALPHA               0x8C44
+#define GL_SLUMINANCE8_ALPHA8             0x8C45
+#define GL_SLUMINANCE                     0x8C46
+#define GL_SLUMINANCE8                    0x8C47
+#define GL_COMPRESSED_SRGB                0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA          0x8C49
+#define GL_COMPRESSED_SLUMINANCE          0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA    0x8C4B
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_TEXTURE0_ARB                   0x84C0
+#define GL_TEXTURE1_ARB                   0x84C1
+#define GL_TEXTURE2_ARB                   0x84C2
+#define GL_TEXTURE3_ARB                   0x84C3
+#define GL_TEXTURE4_ARB                   0x84C4
+#define GL_TEXTURE5_ARB                   0x84C5
+#define GL_TEXTURE6_ARB                   0x84C6
+#define GL_TEXTURE7_ARB                   0x84C7
+#define GL_TEXTURE8_ARB                   0x84C8
+#define GL_TEXTURE9_ARB                   0x84C9
+#define GL_TEXTURE10_ARB                  0x84CA
+#define GL_TEXTURE11_ARB                  0x84CB
+#define GL_TEXTURE12_ARB                  0x84CC
+#define GL_TEXTURE13_ARB                  0x84CD
+#define GL_TEXTURE14_ARB                  0x84CE
+#define GL_TEXTURE15_ARB                  0x84CF
+#define GL_TEXTURE16_ARB                  0x84D0
+#define GL_TEXTURE17_ARB                  0x84D1
+#define GL_TEXTURE18_ARB                  0x84D2
+#define GL_TEXTURE19_ARB                  0x84D3
+#define GL_TEXTURE20_ARB                  0x84D4
+#define GL_TEXTURE21_ARB                  0x84D5
+#define GL_TEXTURE22_ARB                  0x84D6
+#define GL_TEXTURE23_ARB                  0x84D7
+#define GL_TEXTURE24_ARB                  0x84D8
+#define GL_TEXTURE25_ARB                  0x84D9
+#define GL_TEXTURE26_ARB                  0x84DA
+#define GL_TEXTURE27_ARB                  0x84DB
+#define GL_TEXTURE28_ARB                  0x84DC
+#define GL_TEXTURE29_ARB                  0x84DD
+#define GL_TEXTURE30_ARB                  0x84DE
+#define GL_TEXTURE31_ARB                  0x84DF
+#define GL_ACTIVE_TEXTURE_ARB             0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_MULTISAMPLE_ARB                0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F
+#define GL_SAMPLE_COVERAGE_ARB            0x80A0
+#define GL_SAMPLE_BUFFERS_ARB             0x80A8
+#define GL_SAMPLES_ARB                    0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB
+#define GL_MULTISAMPLE_BIT_ARB            0x20000000
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_NORMAL_MAP_ARB                 0x8511
+#define GL_REFLECTION_MAP_ARB             0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_COMPRESSED_ALPHA_ARB           0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB       0x84EC
+#define GL_COMPRESSED_RGB_ARB             0x84ED
+#define GL_COMPRESSED_RGBA_ARB            0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB         0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_ARB            0x812D
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_POINT_SIZE_MIN_ARB             0x8126
+#define GL_POINT_SIZE_MAX_ARB             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_MAX_VERTEX_UNITS_ARB           0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6
+#define GL_VERTEX_BLEND_ARB               0x86A7
+#define GL_CURRENT_WEIGHT_ARB             0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC
+#define GL_WEIGHT_ARRAY_ARB               0x86AD
+#define GL_MODELVIEW0_ARB                 0x1700
+#define GL_MODELVIEW1_ARB                 0x850A
+#define GL_MODELVIEW2_ARB                 0x8722
+#define GL_MODELVIEW3_ARB                 0x8723
+#define GL_MODELVIEW4_ARB                 0x8724
+#define GL_MODELVIEW5_ARB                 0x8725
+#define GL_MODELVIEW6_ARB                 0x8726
+#define GL_MODELVIEW7_ARB                 0x8727
+#define GL_MODELVIEW8_ARB                 0x8728
+#define GL_MODELVIEW9_ARB                 0x8729
+#define GL_MODELVIEW10_ARB                0x872A
+#define GL_MODELVIEW11_ARB                0x872B
+#define GL_MODELVIEW12_ARB                0x872C
+#define GL_MODELVIEW13_ARB                0x872D
+#define GL_MODELVIEW14_ARB                0x872E
+#define GL_MODELVIEW15_ARB                0x872F
+#define GL_MODELVIEW16_ARB                0x8730
+#define GL_MODELVIEW17_ARB                0x8731
+#define GL_MODELVIEW18_ARB                0x8732
+#define GL_MODELVIEW19_ARB                0x8733
+#define GL_MODELVIEW20_ARB                0x8734
+#define GL_MODELVIEW21_ARB                0x8735
+#define GL_MODELVIEW22_ARB                0x8736
+#define GL_MODELVIEW23_ARB                0x8737
+#define GL_MODELVIEW24_ARB                0x8738
+#define GL_MODELVIEW25_ARB                0x8739
+#define GL_MODELVIEW26_ARB                0x873A
+#define GL_MODELVIEW27_ARB                0x873B
+#define GL_MODELVIEW28_ARB                0x873C
+#define GL_MODELVIEW29_ARB                0x873D
+#define GL_MODELVIEW30_ARB                0x873E
+#define GL_MODELVIEW31_ARB                0x873F
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_MATRIX_PALETTE_ARB             0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB       0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_COMBINE_ARB                    0x8570
+#define GL_COMBINE_RGB_ARB                0x8571
+#define GL_COMBINE_ALPHA_ARB              0x8572
+#define GL_SOURCE0_RGB_ARB                0x8580
+#define GL_SOURCE1_RGB_ARB                0x8581
+#define GL_SOURCE2_RGB_ARB                0x8582
+#define GL_SOURCE0_ALPHA_ARB              0x8588
+#define GL_SOURCE1_ALPHA_ARB              0x8589
+#define GL_SOURCE2_ALPHA_ARB              0x858A
+#define GL_OPERAND0_RGB_ARB               0x8590
+#define GL_OPERAND1_RGB_ARB               0x8591
+#define GL_OPERAND2_RGB_ARB               0x8592
+#define GL_OPERAND0_ALPHA_ARB             0x8598
+#define GL_OPERAND1_ALPHA_ARB             0x8599
+#define GL_OPERAND2_ALPHA_ARB             0x859A
+#define GL_RGB_SCALE_ARB                  0x8573
+#define GL_ADD_SIGNED_ARB                 0x8574
+#define GL_INTERPOLATE_ARB                0x8575
+#define GL_SUBTRACT_ARB                   0x84E7
+#define GL_CONSTANT_ARB                   0x8576
+#define GL_PRIMARY_COLOR_ARB              0x8577
+#define GL_PREVIOUS_ARB                   0x8578
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_DOT3_RGB_ARB                   0x86AE
+#define GL_DOT3_RGBA_ARB                  0x86AF
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_ARB            0x8370
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_DEPTH_COMPONENT16_ARB          0x81A5
+#define GL_DEPTH_COMPONENT24_ARB          0x81A6
+#define GL_DEPTH_COMPONENT32_ARB          0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif
+
+#ifndef GL_ARB_window_pos
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_COLOR_SUM_ARB                  0x8458
+#define GL_VERTEX_PROGRAM_ARB             0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626
+#define GL_PROGRAM_LENGTH_ARB             0x8627
+#define GL_PROGRAM_STRING_ARB             0x8628
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_CURRENT_MATRIX_ARB             0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B
+#define GL_PROGRAM_BINDING_ARB            0x8677
+#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ERROR_STRING_ARB       0x8874
+#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
+#define GL_PROGRAM_FORMAT_ARB             0x8876
+#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB         0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB            0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7
+#define GL_MATRIX0_ARB                    0x88C0
+#define GL_MATRIX1_ARB                    0x88C1
+#define GL_MATRIX2_ARB                    0x88C2
+#define GL_MATRIX3_ARB                    0x88C3
+#define GL_MATRIX4_ARB                    0x88C4
+#define GL_MATRIX5_ARB                    0x88C5
+#define GL_MATRIX6_ARB                    0x88C6
+#define GL_MATRIX7_ARB                    0x88C7
+#define GL_MATRIX8_ARB                    0x88C8
+#define GL_MATRIX9_ARB                    0x88C9
+#define GL_MATRIX10_ARB                   0x88CA
+#define GL_MATRIX11_ARB                   0x88CB
+#define GL_MATRIX12_ARB                   0x88CC
+#define GL_MATRIX13_ARB                   0x88CD
+#define GL_MATRIX14_ARB                   0x88CE
+#define GL_MATRIX15_ARB                   0x88CF
+#define GL_MATRIX16_ARB                   0x88D0
+#define GL_MATRIX17_ARB                   0x88D1
+#define GL_MATRIX18_ARB                   0x88D2
+#define GL_MATRIX19_ARB                   0x88D3
+#define GL_MATRIX20_ARB                   0x88D4
+#define GL_MATRIX21_ARB                   0x88D5
+#define GL_MATRIX22_ARB                   0x88D6
+#define GL_MATRIX23_ARB                   0x88D7
+#define GL_MATRIX24_ARB                   0x88D8
+#define GL_MATRIX25_ARB                   0x88D9
+#define GL_MATRIX26_ARB                   0x88DA
+#define GL_MATRIX27_ARB                   0x88DB
+#define GL_MATRIX28_ARB                   0x88DC
+#define GL_MATRIX29_ARB                   0x88DD
+#define GL_MATRIX30_ARB                   0x88DE
+#define GL_MATRIX31_ARB                   0x88DF
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_FRAGMENT_PROGRAM_ARB           0x8804
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_MAX_TEXTURE_COORDS_ARB         0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_BUFFER_SIZE_ARB                0x8764
+#define GL_BUFFER_USAGE_ARB               0x8765
+#define GL_ARRAY_BUFFER_ARB               0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB                  0x88B8
+#define GL_WRITE_ONLY_ARB                 0x88B9
+#define GL_READ_WRITE_ARB                 0x88BA
+#define GL_BUFFER_ACCESS_ARB              0x88BB
+#define GL_BUFFER_MAPPED_ARB              0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#define GL_STREAM_DRAW_ARB                0x88E0
+#define GL_STREAM_READ_ARB                0x88E1
+#define GL_STREAM_COPY_ARB                0x88E2
+#define GL_STATIC_DRAW_ARB                0x88E4
+#define GL_STATIC_READ_ARB                0x88E5
+#define GL_STATIC_COPY_ARB                0x88E6
+#define GL_DYNAMIC_DRAW_ARB               0x88E8
+#define GL_DYNAMIC_READ_ARB               0x88E9
+#define GL_DYNAMIC_COPY_ARB               0x88EA
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_QUERY_COUNTER_BITS_ARB         0x8864
+#define GL_CURRENT_QUERY_ARB              0x8865
+#define GL_QUERY_RESULT_ARB               0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867
+#define GL_SAMPLES_PASSED_ARB             0x8914
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_PROGRAM_OBJECT_ARB             0x8B40
+#define GL_SHADER_OBJECT_ARB              0x8B48
+#define GL_OBJECT_TYPE_ARB                0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB             0x8B4F
+#define GL_FLOAT_VEC2_ARB                 0x8B50
+#define GL_FLOAT_VEC3_ARB                 0x8B51
+#define GL_FLOAT_VEC4_ARB                 0x8B52
+#define GL_INT_VEC2_ARB                   0x8B53
+#define GL_INT_VEC3_ARB                   0x8B54
+#define GL_INT_VEC4_ARB                   0x8B55
+#define GL_BOOL_ARB                       0x8B56
+#define GL_BOOL_VEC2_ARB                  0x8B57
+#define GL_BOOL_VEC3_ARB                  0x8B58
+#define GL_BOOL_VEC4_ARB                  0x8B59
+#define GL_FLOAT_MAT2_ARB                 0x8B5A
+#define GL_FLOAT_MAT3_ARB                 0x8B5B
+#define GL_FLOAT_MAT4_ARB                 0x8B5C
+#define GL_SAMPLER_1D_ARB                 0x8B5D
+#define GL_SAMPLER_2D_ARB                 0x8B5E
+#define GL_SAMPLER_3D_ARB                 0x8B5F
+#define GL_SAMPLER_CUBE_ARB               0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62
+#define GL_SAMPLER_2D_RECT_ARB            0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB         0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB              0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB            0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_POINT_SPRITE_ARB               0x8861
+#define GL_COORD_REPLACE_ARB              0x8862
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ARB           0x8824
+#define GL_DRAW_BUFFER0_ARB               0x8825
+#define GL_DRAW_BUFFER1_ARB               0x8826
+#define GL_DRAW_BUFFER2_ARB               0x8827
+#define GL_DRAW_BUFFER3_ARB               0x8828
+#define GL_DRAW_BUFFER4_ARB               0x8829
+#define GL_DRAW_BUFFER5_ARB               0x882A
+#define GL_DRAW_BUFFER6_ARB               0x882B
+#define GL_DRAW_BUFFER7_ARB               0x882C
+#define GL_DRAW_BUFFER8_ARB               0x882D
+#define GL_DRAW_BUFFER9_ARB               0x882E
+#define GL_DRAW_BUFFER10_ARB              0x882F
+#define GL_DRAW_BUFFER11_ARB              0x8830
+#define GL_DRAW_BUFFER12_ARB              0x8831
+#define GL_DRAW_BUFFER13_ARB              0x8832
+#define GL_DRAW_BUFFER14_ARB              0x8833
+#define GL_DRAW_BUFFER15_ARB              0x8834
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_ARB          0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_RGBA_FLOAT_MODE_ARB            0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B
+#define GL_CLAMP_READ_COLOR_ARB           0x891C
+#define GL_FIXED_ONLY_ARB                 0x891D
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_HALF_FLOAT_ARB                 0x140B
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_TEXTURE_RED_TYPE_ARB           0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17
+#define GL_RGBA32F_ARB                    0x8814
+#define GL_RGB32F_ARB                     0x8815
+#define GL_ALPHA32F_ARB                   0x8816
+#define GL_INTENSITY32F_ARB               0x8817
+#define GL_LUMINANCE32F_ARB               0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB         0x8819
+#define GL_RGBA16F_ARB                    0x881A
+#define GL_RGB16F_ARB                     0x881B
+#define GL_ALPHA16F_ARB                   0x881C
+#define GL_INTENSITY16F_ARB               0x881D
+#define GL_LUMINANCE16F_ARB               0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB         0x881F
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_ABGR_EXT                       0x8000
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_CONSTANT_COLOR_EXT             0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002
+#define GL_CONSTANT_ALPHA_EXT             0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004
+#define GL_BLEND_COLOR_EXT                0x8005
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_POLYGON_OFFSET_EXT             0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_ALPHA4_EXT                     0x803B
+#define GL_ALPHA8_EXT                     0x803C
+#define GL_ALPHA12_EXT                    0x803D
+#define GL_ALPHA16_EXT                    0x803E
+#define GL_LUMINANCE4_EXT                 0x803F
+#define GL_LUMINANCE8_EXT                 0x8040
+#define GL_LUMINANCE12_EXT                0x8041
+#define GL_LUMINANCE16_EXT                0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT          0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT          0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT          0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT         0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT        0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT        0x8048
+#define GL_INTENSITY_EXT                  0x8049
+#define GL_INTENSITY4_EXT                 0x804A
+#define GL_INTENSITY8_EXT                 0x804B
+#define GL_INTENSITY12_EXT                0x804C
+#define GL_INTENSITY16_EXT                0x804D
+#define GL_RGB2_EXT                       0x804E
+#define GL_RGB4_EXT                       0x804F
+#define GL_RGB5_EXT                       0x8050
+#define GL_RGB8_EXT                       0x8051
+#define GL_RGB10_EXT                      0x8052
+#define GL_RGB12_EXT                      0x8053
+#define GL_RGB16_EXT                      0x8054
+#define GL_RGBA2_EXT                      0x8055
+#define GL_RGBA4_EXT                      0x8056
+#define GL_RGB5_A1_EXT                    0x8057
+#define GL_RGBA8_EXT                      0x8058
+#define GL_RGB10_A2_EXT                   0x8059
+#define GL_RGBA12_EXT                     0x805A
+#define GL_RGBA16_EXT                     0x805B
+#define GL_TEXTURE_RED_SIZE_EXT           0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061
+#define GL_REPLACE_EXT                    0x8062
+#define GL_PROXY_TEXTURE_1D_EXT           0x8063
+#define GL_PROXY_TEXTURE_2D_EXT           0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT          0x8065
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_PACK_SKIP_IMAGES_EXT           0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E
+#define GL_TEXTURE_3D_EXT                 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT           0x8070
+#define GL_TEXTURE_DEPTH_EXT              0x8071
+#define GL_TEXTURE_WRAP_R_EXT             0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_FILTER4_SGIS                   0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147
+#endif
+
+#ifndef GL_EXT_subtexture
+#endif
+
+#ifndef GL_EXT_copy_texture
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_HISTOGRAM_EXT                  0x8024
+#define GL_PROXY_HISTOGRAM_EXT            0x8025
+#define GL_HISTOGRAM_WIDTH_EXT            0x8026
+#define GL_HISTOGRAM_FORMAT_EXT           0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C
+#define GL_HISTOGRAM_SINK_EXT             0x802D
+#define GL_MINMAX_EXT                     0x802E
+#define GL_MINMAX_FORMAT_EXT              0x802F
+#define GL_MINMAX_SINK_EXT                0x8030
+#define GL_TABLE_TOO_LARGE_EXT            0x8031
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_CONVOLUTION_1D_EXT             0x8010
+#define GL_CONVOLUTION_2D_EXT             0x8011
+#define GL_SEPARABLE_2D_EXT               0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015
+#define GL_REDUCE_EXT                     0x8016
+#define GL_CONVOLUTION_FORMAT_EXT         0x8017
+#define GL_CONVOLUTION_WIDTH_EXT          0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT         0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+#endif
+
+#ifndef GL_SGI_color_matrix
+#define GL_COLOR_MATRIX_SGI               0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_COLOR_TABLE_SGI                0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI          0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI          0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI           0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_PIXEL_TEXTURE_SGIS             0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_PIXEL_TEX_GEN_SGIX             0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133
+#define GL_TEXTURE_4D_SGIS                0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS          0x8135
+#define GL_TEXTURE_4DSIZE_SGIS            0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS            0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS        0x814F
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_CMYK_EXT                       0x800C
+#define GL_CMYKA_EXT                      0x800D
+#define GL_PACK_CMYK_HINT_EXT             0x800E
+#define GL_UNPACK_CMYK_HINT_EXT           0x800F
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_TEXTURE_PRIORITY_EXT           0x8066
+#define GL_TEXTURE_RESIDENT_EXT           0x8067
+#define GL_TEXTURE_1D_BINDING_EXT         0x8068
+#define GL_TEXTURE_2D_BINDING_EXT         0x8069
+#define GL_TEXTURE_3D_BINDING_EXT         0x806A
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS             0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_LINEAR_SHARPEN_SGIS            0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_TEXTURE_MIN_LOD_SGIS           0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS           0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_MULTISAMPLE_SGIS               0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F
+#define GL_SAMPLE_MASK_SGIS               0x80A0
+#define GL_1PASS_SGIS                     0x80A1
+#define GL_2PASS_0_SGIS                   0x80A2
+#define GL_2PASS_1_SGIS                   0x80A3
+#define GL_4PASS_0_SGIS                   0x80A4
+#define GL_4PASS_1_SGIS                   0x80A5
+#define GL_4PASS_2_SGIS                   0x80A6
+#define GL_4PASS_3_SGIS                   0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS            0x80A8
+#define GL_SAMPLES_SGIS                   0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB
+#define GL_SAMPLE_PATTERN_SGIS            0x80AC
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_RESCALE_NORMAL_EXT             0x803A
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_VERTEX_ARRAY_EXT               0x8074
+#define GL_NORMAL_ARRAY_EXT               0x8075
+#define GL_COLOR_ARRAY_EXT                0x8076
+#define GL_INDEX_ARRAY_EXT                0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT            0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT           0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT           0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT          0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT           0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT          0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT        0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT        0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_GENERATE_MIPMAP_SGIS           0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_TEXTURE_COMPARE_SGIX           0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_CLAMP_TO_EDGE_SGIS             0x812F
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_SGIS           0x812D
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_FUNC_ADD_EXT                   0x8006
+#define GL_MIN_EXT                        0x8007
+#define GL_MAX_EXT                        0x8008
+#define GL_BLEND_EQUATION_EXT             0x8009
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_FUNC_SUBTRACT_EXT              0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_INTERLACE_SGIX                 0x8094
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145
+#endif
+
+#ifndef GL_SGIS_texture_select
+#define GL_DUAL_ALPHA4_SGIS               0x8110
+#define GL_DUAL_ALPHA8_SGIS               0x8111
+#define GL_DUAL_ALPHA12_SGIS              0x8112
+#define GL_DUAL_ALPHA16_SGIS              0x8113
+#define GL_DUAL_LUMINANCE4_SGIS           0x8114
+#define GL_DUAL_LUMINANCE8_SGIS           0x8115
+#define GL_DUAL_LUMINANCE12_SGIS          0x8116
+#define GL_DUAL_LUMINANCE16_SGIS          0x8117
+#define GL_DUAL_INTENSITY4_SGIS           0x8118
+#define GL_DUAL_INTENSITY8_SGIS           0x8119
+#define GL_DUAL_INTENSITY12_SGIS          0x811A
+#define GL_DUAL_INTENSITY16_SGIS          0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D
+#define GL_QUAD_ALPHA4_SGIS               0x811E
+#define GL_QUAD_ALPHA8_SGIS               0x811F
+#define GL_QUAD_LUMINANCE4_SGIS           0x8120
+#define GL_QUAD_LUMINANCE8_SGIS           0x8121
+#define GL_QUAD_INTENSITY4_SGIS           0x8122
+#define GL_QUAD_INTENSITY8_SGIS           0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SPRITE_SGIX                    0x8148
+#define GL_SPRITE_MODE_SGIX               0x8149
+#define GL_SPRITE_AXIS_SGIX               0x814A
+#define GL_SPRITE_TRANSLATION_SGIX        0x814B
+#define GL_SPRITE_AXIAL_SGIX              0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_POINT_SIZE_MIN_EXT             0x8126
+#define GL_POINT_SIZE_MAX_EXT             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128
+#define GL_DISTANCE_ATTENUATION_EXT       0x8129
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_POINT_SIZE_MIN_SGIS            0x8126
+#define GL_POINT_SIZE_MAX_SGIS            0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS      0x8129
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_FRAMEZOOM_SGIX                 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#endif
+
+#ifndef GL_FfdMaskSGIX
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX       0x8195
+#define GL_DEFORMATIONS_MASK_SGIX         0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_REFERENCE_PLANE_SGIX           0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_DEPTH_COMPONENT16_SGIX         0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX         0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX         0x81A7
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_FOG_FUNC_SGIS                  0x812A
+#define GL_FOG_FUNC_POINTS_SGIS           0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_FOG_OFFSET_SGIX                0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX          0x8199
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_IMAGE_SCALE_X_HP               0x8155
+#define GL_IMAGE_SCALE_Y_HP               0x8156
+#define GL_IMAGE_TRANSLATE_X_HP           0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP           0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B
+#define GL_IMAGE_MAG_FILTER_HP            0x815C
+#define GL_IMAGE_MIN_FILTER_HP            0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E
+#define GL_CUBIC_HP                       0x815F
+#define GL_AVERAGE_HP                     0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP          0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_IGNORE_BORDER_HP               0x8150
+#define GL_CONSTANT_BORDER_HP             0x8151
+#define GL_REPLICATE_BORDER_HP            0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154
+#endif
+
+#ifndef GL_INGR_palette_buffer
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE
+#endif
+
+#ifndef GL_EXT_color_subtable
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_VERTEX_DATA_HINT_PGI           0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI            0x1A22D
+#define GL_COLOR3_BIT_PGI                 0x00010000
+#define GL_COLOR4_BIT_PGI                 0x00020000
+#define GL_EDGEFLAG_BIT_PGI               0x00040000
+#define GL_INDEX_BIT_PGI                  0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI            0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000
+#define GL_MAT_EMISSION_BIT_PGI           0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000
+#define GL_MAT_SHININESS_BIT_PGI          0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI           0x04000000
+#define GL_NORMAL_BIT_PGI                 0x08000000
+#define GL_TEXCOORD1_BIT_PGI              0x10000000
+#define GL_TEXCOORD2_BIT_PGI              0x20000000
+#define GL_TEXCOORD3_BIT_PGI              0x40000000
+#define GL_TEXCOORD4_BIT_PGI              0x80000000
+#define GL_VERTEX23_BIT_PGI               0x00000004
+#define GL_VERTEX4_BIT_PGI                0x00000008
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI          0x1A219
+#define GL_CLIP_NEAR_HINT_PGI             0x1A220
+#define GL_CLIP_FAR_HINT_PGI              0x1A221
+#define GL_WIDE_LINE_HINT_PGI             0x1A222
+#define GL_BACK_NORMALS_HINT_PGI          0x1A223
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_COLOR_INDEX1_EXT               0x80E2
+#define GL_COLOR_INDEX2_EXT               0x80E3
+#define GL_COLOR_INDEX4_EXT               0x80E4
+#define GL_COLOR_INDEX8_EXT               0x80E5
+#define GL_COLOR_INDEX12_EXT              0x80E6
+#define GL_COLOR_INDEX16_EXT              0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_LIST_PRIORITY_SGIX             0x8182
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_IR_INSTRUMENT1_SGIX            0x817F
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SHADOW_AMBIENT_SGIX            0x80BF
+#endif
+
+#ifndef GL_EXT_index_texture
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_INDEX_MATERIAL_EXT             0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_INDEX_TEST_EXT                 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT            0x81B6
+#define GL_INDEX_TEST_REF_EXT             0x81B7
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_IUI_V2F_EXT                    0x81AD
+#define GL_IUI_V3F_EXT                    0x81AE
+#define GL_IUI_N3F_V2F_EXT                0x81AF
+#define GL_IUI_N3F_V3F_EXT                0x81B0
+#define GL_T2F_IUI_V2F_EXT                0x81B1
+#define GL_T2F_IUI_V3F_EXT                0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_CULL_VERTEX_EXT                0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_YCRCB_422_SGIX                 0x81BB
+#define GL_YCRCB_444_SGIX                 0x81BC
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_FRAGMENT_LIGHTING_SGIX         0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406
+#define GL_LIGHT_ENV_MODE_SGIX            0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX           0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX           0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX           0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX           0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX           0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX           0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX           0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX           0x8413
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP       0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_PHONG_WIN                      0x80EA
+#define GL_PHONG_HINT_WIN                 0x80EB
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_FRAGMENT_MATERIAL_EXT          0x8349
+#define GL_FRAGMENT_NORMAL_EXT            0x834A
+#define GL_FRAGMENT_COLOR_EXT             0x834C
+#define GL_ATTENUATION_EXT                0x834D
+#define GL_SHADOW_ATTENUATION_EXT         0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F
+#define GL_TEXTURE_LIGHT_EXT              0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+/* reuse GL_FRAGMENT_DEPTH_EXT */
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_ALPHA_MIN_SGIX                 0x8320
+#define GL_ALPHA_MAX_SGIX                 0x8321
+#endif
+
+#ifndef GL_SGIX_impact_pixel_texture
+#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX   0x8184
+#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX     0x8185
+#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX     0x8186
+#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187
+#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188
+#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX    0x8189
+#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX    0x818A
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_BGR_EXT                        0x80E0
+#define GL_BGRA_EXT                       0x80E1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_ASYNC_MARKER_SGIX              0x8329
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX         0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_ASYNC_HISTOGRAM_SGIX           0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D
+#endif
+
+#ifndef GL_INTEL_texture_scissor
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_PARALLEL_ARRAYS_INTEL          0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_OCCLUSION_TEST_HP              0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP       0x8166
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330
+#define GL_PIXEL_MAG_FILTER_EXT           0x8331
+#define GL_PIXEL_MIN_FILTER_EXT           0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333
+#define GL_CUBIC_EXT                      0x8334
+#define GL_AVERAGE_EXT                    0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8
+#define GL_SINGLE_COLOR_EXT               0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_COLOR_SUM_EXT                  0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_PERTURB_EXT                    0x85AE
+#define GL_TEXTURE_NORMAL_EXT             0x85AF
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450
+#define GL_FOG_COORDINATE_EXT             0x8451
+#define GL_FRAGMENT_DEPTH_EXT             0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_SCREEN_COORDINATES_REND        0x8490
+#define GL_INVERTED_SCREEN_W_REND         0x8491
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_TANGENT_ARRAY_EXT              0x8439
+#define GL_BINORMAL_ARRAY_EXT             0x843A
+#define GL_CURRENT_TANGENT_EXT            0x843B
+#define GL_CURRENT_BINORMAL_EXT           0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443
+#define GL_MAP1_TANGENT_EXT               0x8444
+#define GL_MAP2_TANGENT_EXT               0x8445
+#define GL_MAP1_BINORMAL_EXT              0x8446
+#define GL_MAP2_BINORMAL_EXT              0x8447
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_COMBINE_EXT                    0x8570
+#define GL_COMBINE_RGB_EXT                0x8571
+#define GL_COMBINE_ALPHA_EXT              0x8572
+#define GL_RGB_SCALE_EXT                  0x8573
+#define GL_ADD_SIGNED_EXT                 0x8574
+#define GL_INTERPOLATE_EXT                0x8575
+#define GL_CONSTANT_EXT                   0x8576
+#define GL_PRIMARY_COLOR_EXT              0x8577
+#define GL_PREVIOUS_EXT                   0x8578
+#define GL_SOURCE0_RGB_EXT                0x8580
+#define GL_SOURCE1_RGB_EXT                0x8581
+#define GL_SOURCE2_RGB_EXT                0x8582
+#define GL_SOURCE0_ALPHA_EXT              0x8588
+#define GL_SOURCE1_ALPHA_EXT              0x8589
+#define GL_SOURCE2_ALPHA_EXT              0x858A
+#define GL_OPERAND0_RGB_EXT               0x8590
+#define GL_OPERAND1_RGB_EXT               0x8591
+#define GL_OPERAND2_RGB_EXT               0x8592
+#define GL_OPERAND0_ALPHA_EXT             0x8598
+#define GL_OPERAND1_ALPHA_EXT             0x8599
+#define GL_OPERAND2_ALPHA_EXT             0x859A
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_TRANSFORM_HINT_APPLE           0x85B1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_FOG_SCALE_SGIX                 0x81FC
+#define GL_FOG_SCALE_VALUE_SGIX           0x81FD
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_GLOBAL_ALPHA_SUN               0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_RESTART_SUN                    0x0001
+#define GL_REPLACE_MIDDLE_SUN             0x0002
+#define GL_REPLACE_OLDEST_SUN             0x0003
+#define GL_TRIANGLE_LIST_SUN              0x81D7
+#define GL_REPLACEMENT_CODE_SUN           0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN                   0x85C4
+#define GL_R1UI_C4UB_V3F_SUN              0x85C5
+#define GL_R1UI_C3F_V3F_SUN               0x85C6
+#define GL_R1UI_N3F_V3F_SUN               0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8
+#define GL_R1UI_T2F_V3F_SUN               0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB
+#endif
+
+#ifndef GL_SUN_vertex
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_BLEND_DST_RGB_EXT              0x80C8
+#define GL_BLEND_SRC_RGB_EXT              0x80C9
+#define GL_BLEND_DST_ALPHA_EXT            0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT            0x80CB
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_RED_MIN_CLAMP_INGR             0x8560
+#define GL_GREEN_MIN_CLAMP_INGR           0x8561
+#define GL_BLUE_MIN_CLAMP_INGR            0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR           0x8563
+#define GL_RED_MAX_CLAMP_INGR             0x8564
+#define GL_GREEN_MAX_CLAMP_INGR           0x8565
+#define GL_BLUE_MAX_CLAMP_INGR            0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR           0x8567
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INTERLACE_READ_INGR            0x8568
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_INCR_WRAP_EXT                  0x8507
+#define GL_DECR_WRAP_EXT                  0x8508
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_422_EXT                        0x80CC
+#define GL_422_REV_EXT                    0x80CD
+#define GL_422_AVERAGE_EXT                0x80CE
+#define GL_422_REV_AVERAGE_EXT            0x80CF
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NORMAL_MAP_NV                  0x8511
+#define GL_REFLECTION_MAP_NV              0x8512
+#endif
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_NORMAL_MAP_EXT                 0x8511
+#define GL_REFLECTION_MAP_EXT             0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_WRAP_BORDER_SUN                0x81D4
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT           0x8501
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_MODELVIEW0_STACK_DEPTH_EXT     GL_MODELVIEW_STACK_DEPTH
+#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502
+#define GL_MODELVIEW0_MATRIX_EXT          GL_MODELVIEW_MATRIX
+#define GL_MODELVIEW1_MATRIX_EXT          0x8506
+#define GL_VERTEX_WEIGHTING_EXT           0x8509
+#define GL_MODELVIEW0_EXT                 GL_MODELVIEW
+#define GL_MODELVIEW1_EXT                 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_MAX_SHININESS_NV               0x8504
+#define GL_MAX_SPOT_EXPONENT_NV           0x8505
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_NV          0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_REGISTER_COMBINERS_NV          0x8522
+#define GL_VARIABLE_A_NV                  0x8523
+#define GL_VARIABLE_B_NV                  0x8524
+#define GL_VARIABLE_C_NV                  0x8525
+#define GL_VARIABLE_D_NV                  0x8526
+#define GL_VARIABLE_E_NV                  0x8527
+#define GL_VARIABLE_F_NV                  0x8528
+#define GL_VARIABLE_G_NV                  0x8529
+#define GL_CONSTANT_COLOR0_NV             0x852A
+#define GL_CONSTANT_COLOR1_NV             0x852B
+#define GL_PRIMARY_COLOR_NV               0x852C
+#define GL_SECONDARY_COLOR_NV             0x852D
+#define GL_SPARE0_NV                      0x852E
+#define GL_SPARE1_NV                      0x852F
+#define GL_DISCARD_NV                     0x8530
+#define GL_E_TIMES_F_NV                   0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV           0x8536
+#define GL_UNSIGNED_INVERT_NV             0x8537
+#define GL_EXPAND_NORMAL_NV               0x8538
+#define GL_EXPAND_NEGATE_NV               0x8539
+#define GL_HALF_BIAS_NORMAL_NV            0x853A
+#define GL_HALF_BIAS_NEGATE_NV            0x853B
+#define GL_SIGNED_IDENTITY_NV             0x853C
+#define GL_SIGNED_NEGATE_NV               0x853D
+#define GL_SCALE_BY_TWO_NV                0x853E
+#define GL_SCALE_BY_FOUR_NV               0x853F
+#define GL_SCALE_BY_ONE_HALF_NV           0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541
+#define GL_COMBINER_INPUT_NV              0x8542
+#define GL_COMBINER_MAPPING_NV            0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546
+#define GL_COMBINER_MUX_SUM_NV            0x8547
+#define GL_COMBINER_SCALE_NV              0x8548
+#define GL_COMBINER_BIAS_NV               0x8549
+#define GL_COMBINER_AB_OUTPUT_NV          0x854A
+#define GL_COMBINER_CD_OUTPUT_NV          0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV         0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV       0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV       0x854E
+#define GL_COLOR_SUM_CLAMP_NV             0x854F
+#define GL_COMBINER0_NV                   0x8550
+#define GL_COMBINER1_NV                   0x8551
+#define GL_COMBINER2_NV                   0x8552
+#define GL_COMBINER3_NV                   0x8553
+#define GL_COMBINER4_NV                   0x8554
+#define GL_COMBINER5_NV                   0x8555
+#define GL_COMBINER6_NV                   0x8556
+#define GL_COMBINER7_NV                   0x8557
+/* reuse GL_TEXTURE0_ARB */
+/* reuse GL_TEXTURE1_ARB */
+/* reuse GL_ZERO */
+/* reuse GL_NONE */
+/* reuse GL_FOG */
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_FOG_DISTANCE_MODE_NV           0x855A
+#define GL_EYE_RADIAL_NV                  0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C
+/* reuse GL_EYE_PLANE */
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_EMBOSS_LIGHT_NV                0x855D
+#define GL_EMBOSS_CONSTANT_NV             0x855E
+#define GL_EMBOSS_MAP_NV                  0x855F
+#endif
+
+#ifndef GL_NV_blend_square
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_COMBINE4_NV                    0x8503
+#define GL_SOURCE3_RGB_NV                 0x8583
+#define GL_SOURCE3_ALPHA_NV               0x858B
+#define GL_OPERAND3_RGB_NV                0x8593
+#define GL_OPERAND3_ALPHA_NV              0x859B
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#endif
+
+#ifndef GL_MESA_window_pos
+#endif
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_CULL_VERTEX_IBM                103050
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_VERTEX_ARRAY_LIST_IBM          103070
+#define GL_NORMAL_ARRAY_LIST_IBM          103071
+#define GL_COLOR_ARRAY_LIST_IBM           103072
+#define GL_INDEX_ARRAY_LIST_IBM           103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_YCRCB_SGIX                     0x8318
+#define GL_YCRCBA_SGIX                    0x8319
+#endif
+
+#ifndef GL_SGI_depth_pass_instrument
+#define GL_DEPTH_PASS_INSTRUMENT_SGIX     0x8310
+#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311
+#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_MULTISAMPLE_3DFX               0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX            0x86B3
+#define GL_SAMPLES_3DFX                   0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX           0x20000000
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_MULTISAMPLE_EXT                0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F
+#define GL_SAMPLE_MASK_EXT                0x80A0
+#define GL_1PASS_EXT                      0x80A1
+#define GL_2PASS_0_EXT                    0x80A2
+#define GL_2PASS_1_EXT                    0x80A3
+#define GL_4PASS_0_EXT                    0x80A4
+#define GL_4PASS_1_EXT                    0x80A5
+#define GL_4PASS_2_EXT                    0x80A6
+#define GL_4PASS_3_EXT                    0x80A7
+#define GL_SAMPLE_BUFFERS_EXT             0x80A8
+#define GL_SAMPLES_EXT                    0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB
+#define GL_SAMPLE_PATTERN_EXT             0x80AC
+#define GL_MULTISAMPLE_BIT_EXT            0x20000000
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_VERTEX_PRECLIP_SGIX            0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_CONVOLUTION_HINT_SGIX          0x8316
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_PACK_RESAMPLE_SGIX             0x842C
+#define GL_UNPACK_RESAMPLE_SGIX           0x842D
+#define GL_RESAMPLE_REPLICATE_SGIX        0x842E
+#define GL_RESAMPLE_ZERO_FILL_SGIX        0x842F
+#define GL_RESAMPLE_DECIMATE_SGIX         0x8430
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3
+#define GL_EYE_POINT_SGIS                 0x81F4
+#define GL_OBJECT_POINT_SGIS              0x81F5
+#define GL_EYE_LINE_SGIS                  0x81F6
+#define GL_OBJECT_LINE_SGIS               0x81F7
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_DOT3_RGB_EXT                   0x8740
+#define GL_DOT3_RGBA_EXT                  0x8741
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_MIRROR_CLAMP_ATI               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743
+#endif
+
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV               0x84F2
+#define GL_FENCE_STATUS_NV                0x84F3
+#define GL_FENCE_CONDITION_NV             0x84F4
+#endif
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_IBM            0x8370
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_EVAL_2D_NV                     0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1
+#define GL_MAP_TESSELLATION_NV            0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV        0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_DEPTH_STENCIL_NV               0x84F9
+#define GL_UNSIGNED_INT_24_8_NV           0x84FA
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_PER_STAGE_CONSTANTS_NV         0x8535
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_NV           0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV          0x86DC
+#define GL_SHADER_CONSISTENT_NV           0x86DD
+#define GL_TEXTURE_SHADER_NV              0x86DE
+#define GL_SHADER_OPERATION_NV            0x86DF
+#define GL_CULL_MODES_NV                  0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    GL_OFFSET_TEXTURE_MATRIX_NV
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV     GL_OFFSET_TEXTURE_SCALE_NV
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV      GL_OFFSET_TEXTURE_BIAS_NV
+#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4
+#define GL_CONST_EYE_NV                   0x86E5
+#define GL_PASS_THROUGH_NV                0x86E6
+#define GL_CULL_FRAGMENT_NV               0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV           0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA
+#define GL_DOT_PRODUCT_NV                 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV                        0x86F4
+#define GL_DSDT_NV                        0x86F5
+#define GL_DSDT_MAG_NV                    0x86F6
+#define GL_DSDT_MAG_VIB_NV                0x86F7
+#define GL_HILO16_NV                      0x86F8
+#define GL_SIGNED_HILO_NV                 0x86F9
+#define GL_SIGNED_HILO16_NV               0x86FA
+#define GL_SIGNED_RGBA_NV                 0x86FB
+#define GL_SIGNED_RGBA8_NV                0x86FC
+#define GL_SIGNED_RGB_NV                  0x86FE
+#define GL_SIGNED_RGB8_NV                 0x86FF
+#define GL_SIGNED_LUMINANCE_NV            0x8701
+#define GL_SIGNED_LUMINANCE8_NV           0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704
+#define GL_SIGNED_ALPHA_NV                0x8705
+#define GL_SIGNED_ALPHA8_NV               0x8706
+#define GL_SIGNED_INTENSITY_NV            0x8707
+#define GL_SIGNED_INTENSITY8_NV           0x8708
+#define GL_DSDT8_NV                       0x8709
+#define GL_DSDT8_MAG8_NV                  0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV                    0x870E
+#define GL_LO_SCALE_NV                    0x870F
+#define GL_DS_SCALE_NV                    0x8710
+#define GL_DT_SCALE_NV                    0x8711
+#define GL_MAGNITUDE_SCALE_NV             0x8712
+#define GL_VIBRANCE_SCALE_NV              0x8713
+#define GL_HI_BIAS_NV                     0x8714
+#define GL_LO_BIAS_NV                     0x8715
+#define GL_DS_BIAS_NV                     0x8716
+#define GL_DT_BIAS_NV                     0x8717
+#define GL_MAGNITUDE_BIAS_NV              0x8718
+#define GL_VIBRANCE_BIAS_NV               0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV       0x871A
+#define GL_TEXTURE_HI_SIZE_NV             0x871B
+#define GL_TEXTURE_LO_SIZE_NV             0x871C
+#define GL_TEXTURE_DS_SIZE_NV             0x871D
+#define GL_TEXTURE_DT_SIZE_NV             0x871E
+#define GL_TEXTURE_MAG_SIZE_NV            0x871F
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_VERTEX_PROGRAM_NV              0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV        0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625
+#define GL_CURRENT_ATTRIB_NV              0x8626
+#define GL_PROGRAM_LENGTH_NV              0x8627
+#define GL_PROGRAM_STRING_NV              0x8628
+#define GL_MODELVIEW_PROJECTION_NV        0x8629
+#define GL_IDENTITY_NV                    0x862A
+#define GL_INVERSE_NV                     0x862B
+#define GL_TRANSPOSE_NV                   0x862C
+#define GL_INVERSE_TRANSPOSE_NV           0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV          0x862F
+#define GL_MATRIX0_NV                     0x8630
+#define GL_MATRIX1_NV                     0x8631
+#define GL_MATRIX2_NV                     0x8632
+#define GL_MATRIX3_NV                     0x8633
+#define GL_MATRIX4_NV                     0x8634
+#define GL_MATRIX5_NV                     0x8635
+#define GL_MATRIX6_NV                     0x8636
+#define GL_MATRIX7_NV                     0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640
+#define GL_CURRENT_MATRIX_NV              0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643
+#define GL_PROGRAM_PARAMETER_NV           0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645
+#define GL_PROGRAM_TARGET_NV              0x8646
+#define GL_PROGRAM_RESIDENT_NV            0x8647
+#define GL_TRACK_MATRIX_NV                0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV      0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SCALEBIAS_HINT_SGIX            0x8322
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_INTERLACE_OML                  0x8980
+#define GL_INTERLACE_READ_OML             0x8981
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983
+#endif
+
+#ifndef GL_OML_resample
+#define GL_PACK_RESAMPLE_OML              0x8984
+#define GL_UNPACK_RESAMPLE_OML            0x8985
+#define GL_RESAMPLE_REPLICATE_OML         0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML         0x8987
+#define GL_RESAMPLE_AVERAGE_OML           0x8988
+#define GL_RESAMPLE_DECIMATE_OML          0x8989
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_BUMP_ROT_MATRIX_ATI            0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777
+#define GL_BUMP_TEX_UNITS_ATI             0x8778
+#define GL_DUDV_ATI                       0x8779
+#define GL_DU8DV8_ATI                     0x877A
+#define GL_BUMP_ENVMAP_ATI                0x877B
+#define GL_BUMP_TARGET_ATI                0x877C
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_FRAGMENT_SHADER_ATI            0x8920
+#define GL_REG_0_ATI                      0x8921
+#define GL_REG_1_ATI                      0x8922
+#define GL_REG_2_ATI                      0x8923
+#define GL_REG_3_ATI                      0x8924
+#define GL_REG_4_ATI                      0x8925
+#define GL_REG_5_ATI                      0x8926
+#define GL_REG_6_ATI                      0x8927
+#define GL_REG_7_ATI                      0x8928
+#define GL_REG_8_ATI                      0x8929
+#define GL_REG_9_ATI                      0x892A
+#define GL_REG_10_ATI                     0x892B
+#define GL_REG_11_ATI                     0x892C
+#define GL_REG_12_ATI                     0x892D
+#define GL_REG_13_ATI                     0x892E
+#define GL_REG_14_ATI                     0x892F
+#define GL_REG_15_ATI                     0x8930
+#define GL_REG_16_ATI                     0x8931
+#define GL_REG_17_ATI                     0x8932
+#define GL_REG_18_ATI                     0x8933
+#define GL_REG_19_ATI                     0x8934
+#define GL_REG_20_ATI                     0x8935
+#define GL_REG_21_ATI                     0x8936
+#define GL_REG_22_ATI                     0x8937
+#define GL_REG_23_ATI                     0x8938
+#define GL_REG_24_ATI                     0x8939
+#define GL_REG_25_ATI                     0x893A
+#define GL_REG_26_ATI                     0x893B
+#define GL_REG_27_ATI                     0x893C
+#define GL_REG_28_ATI                     0x893D
+#define GL_REG_29_ATI                     0x893E
+#define GL_REG_30_ATI                     0x893F
+#define GL_REG_31_ATI                     0x8940
+#define GL_CON_0_ATI                      0x8941
+#define GL_CON_1_ATI                      0x8942
+#define GL_CON_2_ATI                      0x8943
+#define GL_CON_3_ATI                      0x8944
+#define GL_CON_4_ATI                      0x8945
+#define GL_CON_5_ATI                      0x8946
+#define GL_CON_6_ATI                      0x8947
+#define GL_CON_7_ATI                      0x8948
+#define GL_CON_8_ATI                      0x8949
+#define GL_CON_9_ATI                      0x894A
+#define GL_CON_10_ATI                     0x894B
+#define GL_CON_11_ATI                     0x894C
+#define GL_CON_12_ATI                     0x894D
+#define GL_CON_13_ATI                     0x894E
+#define GL_CON_14_ATI                     0x894F
+#define GL_CON_15_ATI                     0x8950
+#define GL_CON_16_ATI                     0x8951
+#define GL_CON_17_ATI                     0x8952
+#define GL_CON_18_ATI                     0x8953
+#define GL_CON_19_ATI                     0x8954
+#define GL_CON_20_ATI                     0x8955
+#define GL_CON_21_ATI                     0x8956
+#define GL_CON_22_ATI                     0x8957
+#define GL_CON_23_ATI                     0x8958
+#define GL_CON_24_ATI                     0x8959
+#define GL_CON_25_ATI                     0x895A
+#define GL_CON_26_ATI                     0x895B
+#define GL_CON_27_ATI                     0x895C
+#define GL_CON_28_ATI                     0x895D
+#define GL_CON_29_ATI                     0x895E
+#define GL_CON_30_ATI                     0x895F
+#define GL_CON_31_ATI                     0x8960
+#define GL_MOV_ATI                        0x8961
+#define GL_ADD_ATI                        0x8963
+#define GL_MUL_ATI                        0x8964
+#define GL_SUB_ATI                        0x8965
+#define GL_DOT3_ATI                       0x8966
+#define GL_DOT4_ATI                       0x8967
+#define GL_MAD_ATI                        0x8968
+#define GL_LERP_ATI                       0x8969
+#define GL_CND_ATI                        0x896A
+#define GL_CND0_ATI                       0x896B
+#define GL_DOT2_ADD_ATI                   0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F
+#define GL_NUM_PASSES_ATI                 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975
+#define GL_SWIZZLE_STR_ATI                0x8976
+#define GL_SWIZZLE_STQ_ATI                0x8977
+#define GL_SWIZZLE_STR_DR_ATI             0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI             0x8979
+#define GL_SWIZZLE_STRQ_ATI               0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B
+#define GL_RED_BIT_ATI                    0x00000001
+#define GL_GREEN_BIT_ATI                  0x00000002
+#define GL_BLUE_BIT_ATI                   0x00000004
+#define GL_2X_BIT_ATI                     0x00000001
+#define GL_4X_BIT_ATI                     0x00000002
+#define GL_8X_BIT_ATI                     0x00000004
+#define GL_HALF_BIT_ATI                   0x00000008
+#define GL_QUARTER_BIT_ATI                0x00000010
+#define GL_EIGHTH_BIT_ATI                 0x00000020
+#define GL_SATURATE_BIT_ATI               0x00000040
+#define GL_COMP_BIT_ATI                   0x00000002
+#define GL_NEGATE_BIT_ATI                 0x00000004
+#define GL_BIAS_BIT_ATI                   0x00000008
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_PN_TRIANGLES_ATI               0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_STATIC_ATI                     0x8760
+#define GL_DYNAMIC_ATI                    0x8761
+#define GL_PRESERVE_ATI                   0x8762
+#define GL_DISCARD_ATI                    0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_VERTEX_SHADER_EXT              0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT      0x8781
+#define GL_OP_INDEX_EXT                   0x8782
+#define GL_OP_NEGATE_EXT                  0x8783
+#define GL_OP_DOT3_EXT                    0x8784
+#define GL_OP_DOT4_EXT                    0x8785
+#define GL_OP_MUL_EXT                     0x8786
+#define GL_OP_ADD_EXT                     0x8787
+#define GL_OP_MADD_EXT                    0x8788
+#define GL_OP_FRAC_EXT                    0x8789
+#define GL_OP_MAX_EXT                     0x878A
+#define GL_OP_MIN_EXT                     0x878B
+#define GL_OP_SET_GE_EXT                  0x878C
+#define GL_OP_SET_LT_EXT                  0x878D
+#define GL_OP_CLAMP_EXT                   0x878E
+#define GL_OP_FLOOR_EXT                   0x878F
+#define GL_OP_ROUND_EXT                   0x8790
+#define GL_OP_EXP_BASE_2_EXT              0x8791
+#define GL_OP_LOG_BASE_2_EXT              0x8792
+#define GL_OP_POWER_EXT                   0x8793
+#define GL_OP_RECIP_EXT                   0x8794
+#define GL_OP_RECIP_SQRT_EXT              0x8795
+#define GL_OP_SUB_EXT                     0x8796
+#define GL_OP_CROSS_PRODUCT_EXT           0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798
+#define GL_OP_MOV_EXT                     0x8799
+#define GL_OUTPUT_VERTEX_EXT              0x879A
+#define GL_OUTPUT_COLOR0_EXT              0x879B
+#define GL_OUTPUT_COLOR1_EXT              0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC
+#define GL_OUTPUT_FOG_EXT                 0x87BD
+#define GL_SCALAR_EXT                     0x87BE
+#define GL_VECTOR_EXT                     0x87BF
+#define GL_MATRIX_EXT                     0x87C0
+#define GL_VARIANT_EXT                    0x87C1
+#define GL_INVARIANT_EXT                  0x87C2
+#define GL_LOCAL_CONSTANT_EXT             0x87C3
+#define GL_LOCAL_EXT                      0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4
+#define GL_X_EXT                          0x87D5
+#define GL_Y_EXT                          0x87D6
+#define GL_Z_EXT                          0x87D7
+#define GL_W_EXT                          0x87D8
+#define GL_NEGATIVE_X_EXT                 0x87D9
+#define GL_NEGATIVE_Y_EXT                 0x87DA
+#define GL_NEGATIVE_Z_EXT                 0x87DB
+#define GL_NEGATIVE_W_EXT                 0x87DC
+#define GL_ZERO_EXT                       0x87DD
+#define GL_ONE_EXT                        0x87DE
+#define GL_NEGATIVE_ONE_EXT               0x87DF
+#define GL_NORMALIZED_RANGE_EXT           0x87E0
+#define GL_FULL_RANGE_EXT                 0x87E1
+#define GL_CURRENT_VERTEX_EXT             0x87E2
+#define GL_MVP_MATRIX_EXT                 0x87E3
+#define GL_VARIANT_VALUE_EXT              0x87E4
+#define GL_VARIANT_DATATYPE_EXT           0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7
+#define GL_VARIANT_ARRAY_EXT              0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9
+#define GL_INVARIANT_VALUE_EXT            0x87EA
+#define GL_INVARIANT_DATATYPE_EXT         0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_MAX_VERTEX_STREAMS_ATI         0x876B
+#define GL_VERTEX_STREAM0_ATI             0x876C
+#define GL_VERTEX_STREAM1_ATI             0x876D
+#define GL_VERTEX_STREAM2_ATI             0x876E
+#define GL_VERTEX_STREAM3_ATI             0x876F
+#define GL_VERTEX_STREAM4_ATI             0x8770
+#define GL_VERTEX_STREAM5_ATI             0x8771
+#define GL_VERTEX_STREAM6_ATI             0x8772
+#define GL_VERTEX_STREAM7_ATI             0x8773
+#define GL_VERTEX_SOURCE_ATI              0x8774
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ELEMENT_ARRAY_ATI              0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_QUAD_MESH_SUN                  0x8614
+#define GL_TRIANGLE_MESH_SUN              0x8615
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SLICE_ACCUM_SUN                0x85CC
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_DEPTH_CLAMP_NV                 0x864F
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_PIXEL_COUNTER_BITS_NV          0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865
+#define GL_PIXEL_COUNT_NV                 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_POINT_SPRITE_NV                0x8861
+#define GL_COORD_REPLACE_NV               0x8862
+#define GL_POINT_SPRITE_R_MODE_NV         0x8863
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV                       0x885E
+#define GL_SIGNED_HILO8_NV                0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV           0x8860
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_ELEMENT_ARRAY_APPLE            0x8768
+#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8769
+#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x876A
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_DRAW_PIXELS_APPLE              0x8A0A
+#define GL_FENCE_APPLE                    0x8A0B
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CACHED_APPLE           0x85BE
+#define GL_STORAGE_SHARED_APPLE           0x85BF
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_YCBCR_422_APPLE                0x85B9
+#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_RGB_S3TC                       0x83A0
+#define GL_RGB4_S3TC                      0x83A1
+#define GL_RGBA_S3TC                      0x83A2
+#define GL_RGBA4_S3TC                     0x83A3
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ATI           0x8824
+#define GL_DRAW_BUFFER0_ATI               0x8825
+#define GL_DRAW_BUFFER1_ATI               0x8826
+#define GL_DRAW_BUFFER2_ATI               0x8827
+#define GL_DRAW_BUFFER3_ATI               0x8828
+#define GL_DRAW_BUFFER4_ATI               0x8829
+#define GL_DRAW_BUFFER5_ATI               0x882A
+#define GL_DRAW_BUFFER6_ATI               0x882B
+#define GL_DRAW_BUFFER7_ATI               0x882C
+#define GL_DRAW_BUFFER8_ATI               0x882D
+#define GL_DRAW_BUFFER9_ATI               0x882E
+#define GL_DRAW_BUFFER10_ATI              0x882F
+#define GL_DRAW_BUFFER11_ATI              0x8830
+#define GL_DRAW_BUFFER12_ATI              0x8831
+#define GL_DRAW_BUFFER13_ATI              0x8832
+#define GL_DRAW_BUFFER14_ATI              0x8833
+#define GL_DRAW_BUFFER15_ATI              0x8834
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_TYPE_RGBA_FLOAT_ATI            0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_MODULATE_ADD_ATI               0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI        0x8745
+#define GL_MODULATE_SUBTRACT_ATI          0x8746
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_RGBA_FLOAT32_ATI               0x8814
+#define GL_RGB_FLOAT32_ATI                0x8815
+#define GL_ALPHA_FLOAT32_ATI              0x8816
+#define GL_INTENSITY_FLOAT32_ATI          0x8817
+#define GL_LUMINANCE_FLOAT32_ATI          0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819
+#define GL_RGBA_FLOAT16_ATI               0x881A
+#define GL_RGB_FLOAT16_ATI                0x881B
+#define GL_ALPHA_FLOAT16_ATI              0x881C
+#define GL_INTENSITY_FLOAT16_ATI          0x881D
+#define GL_LUMINANCE_FLOAT16_ATI          0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_FLOAT_R_NV                     0x8880
+#define GL_FLOAT_RG_NV                    0x8881
+#define GL_FLOAT_RGB_NV                   0x8882
+#define GL_FLOAT_RGBA_NV                  0x8883
+#define GL_FLOAT_R16_NV                   0x8884
+#define GL_FLOAT_R32_NV                   0x8885
+#define GL_FLOAT_RG16_NV                  0x8886
+#define GL_FLOAT_RG32_NV                  0x8887
+#define GL_FLOAT_RGB16_NV                 0x8888
+#define GL_FLOAT_RGB32_NV                 0x8889
+#define GL_FLOAT_RGBA16_NV                0x888A
+#define GL_FLOAT_RGBA32_NV                0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D
+#define GL_FLOAT_RGBA_MODE_NV             0x888E
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV            0x8870
+#define GL_MAX_TEXTURE_COORDS_NV          0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873
+#define GL_PROGRAM_ERROR_STRING_NV        0x8874
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_HALF_FLOAT_NV                  0x140B
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_PRIMITIVE_RESTART_NV           0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif
+
+#ifndef GL_NV_vertex_program2
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_STENCIL_BACK_FUNC_ATI          0x8800
+#define GL_STENCIL_BACK_FAIL_ATI          0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890
+#define GL_DEPTH_BOUNDS_EXT               0x8891
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_MIRROR_CLAMP_EXT               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_BLEND_EQUATION_RGB_EXT         GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_PACK_INVERT_MESA               0x8758
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB
+#define GL_YCBCR_MESA                     0x8757
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */
+/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */
+#endif
+
+#ifndef GL_NV_vertex_program3
+/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT         0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT           0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT         0x8D20
+#define GL_FRAMEBUFFER_EXT                0x8D40
+#define GL_RENDERBUFFER_EXT               0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT             0x8D46
+#define GL_STENCIL_INDEX4_EXT             0x8D47
+#define GL_STENCIL_INDEX8_EXT             0x8D48
+#define GL_STENCIL_INDEX16_EXT            0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#endif
+
+#ifndef GL_EXT_packed_depth_stencil
+#define GL_DEPTH_STENCIL_EXT              0x84F9
+#define GL_UNSIGNED_INT_24_8_EXT          0x84FA
+#define GL_DEPTH24_STENCIL8_EXT           0x88F0
+#define GL_TEXTURE_STENCIL_SIZE_EXT       0x88F1
+#endif
+
+#ifndef GL_EXT_stencil_clear_tag
+#define GL_STENCIL_TAG_BITS_EXT           0x88F2
+#define GL_STENCIL_CLEAR_TAG_VALUE_EXT    0x88F3
+#endif
+
+#ifndef GL_EXT_texture_sRGB
+#define GL_SRGB_EXT                       0x8C40
+#define GL_SRGB8_EXT                      0x8C41
+#define GL_SRGB_ALPHA_EXT                 0x8C42
+#define GL_SRGB8_ALPHA8_EXT               0x8C43
+#define GL_SLUMINANCE_ALPHA_EXT           0x8C44
+#define GL_SLUMINANCE8_ALPHA8_EXT         0x8C45
+#define GL_SLUMINANCE_EXT                 0x8C46
+#define GL_SLUMINANCE8_EXT                0x8C47
+#define GL_COMPRESSED_SRGB_EXT            0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA_EXT      0x8C49
+#define GL_COMPRESSED_SLUMINANCE_EXT      0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#endif
+
+#ifndef GL_EXT_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_EXT           0x8CA8
+#define GL_DRAW_FRAMEBUFFER_EXT           0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING_EXT   GL_FRAMEBUFFER_BINDING_EXT
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT   0x8CAA
+#endif
+
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_EXT       0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT                0x8D57
+#endif
+
+#ifndef GL_MESAX_texture_stack
+#define GL_TEXTURE_1D_STACK_MESAX         0x8759
+#define GL_TEXTURE_2D_STACK_MESAX         0x875A
+#define GL_PROXY_TEXTURE_1D_STACK_MESAX   0x875B
+#define GL_PROXY_TEXTURE_2D_STACK_MESAX   0x875C
+#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D
+#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E
+#endif
+
+#ifndef GL_EXT_timer_query
+#define GL_TIME_ELAPSED_EXT               0x88BF
+#endif
+
+#ifndef GL_EXT_gpu_program_parameters
+#endif
+
+#ifndef GL_APPLE_flush_buffer_range
+#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12
+#define GL_BUFFER_FLUSHING_UNMAP_APPLE    0x8A13
+#endif
+
+#ifndef GL_NV_gpu_program4
+#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV    0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV    0x8905
+#define GL_PROGRAM_ATTRIB_COMPONENTS_NV   0x8906
+#define GL_PROGRAM_RESULT_COMPONENTS_NV   0x8907
+#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908
+#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909
+#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5
+#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6
+#endif
+
+#ifndef GL_NV_geometry_program4
+#define GL_LINES_ADJACENCY_EXT            0x000A
+#define GL_LINE_STRIP_ADJACENCY_EXT       0x000B
+#define GL_TRIANGLES_ADJACENCY_EXT        0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_EXT   0x000D
+#define GL_GEOMETRY_PROGRAM_NV            0x8C26
+#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27
+#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28
+#define GL_GEOMETRY_VERTICES_OUT_EXT      0x8DDA
+#define GL_GEOMETRY_INPUT_TYPE_EXT        0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_EXT       0x8DDC
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4
+#define GL_PROGRAM_POINT_SIZE_EXT         0x8642
+#endif
+
+#ifndef GL_EXT_geometry_shader4
+#define GL_GEOMETRY_SHADER_EXT            0x8DD9
+/* reuse GL_GEOMETRY_VERTICES_OUT_EXT */
+/* reuse GL_GEOMETRY_INPUT_TYPE_EXT */
+/* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */
+/* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE
+#define GL_MAX_VARYING_COMPONENTS_EXT     0x8B4B
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1
+/* reuse GL_LINES_ADJACENCY_EXT */
+/* reuse GL_LINE_STRIP_ADJACENCY_EXT */
+/* reuse GL_TRIANGLES_ADJACENCY_EXT */
+/* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */
+/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */
+/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */
+/* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */
+/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */
+/* reuse GL_PROGRAM_POINT_SIZE_EXT */
+#endif
+
+#ifndef GL_NV_vertex_program4
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD
+#endif
+
+#ifndef GL_EXT_gpu_shader4
+#define GL_SAMPLER_1D_ARRAY_EXT           0x8DC0
+#define GL_SAMPLER_2D_ARRAY_EXT           0x8DC1
+#define GL_SAMPLER_BUFFER_EXT             0x8DC2
+#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT    0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT    0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW_EXT        0x8DC5
+#define GL_UNSIGNED_INT_VEC2_EXT          0x8DC6
+#define GL_UNSIGNED_INT_VEC3_EXT          0x8DC7
+#define GL_UNSIGNED_INT_VEC4_EXT          0x8DC8
+#define GL_INT_SAMPLER_1D_EXT             0x8DC9
+#define GL_INT_SAMPLER_2D_EXT             0x8DCA
+#define GL_INT_SAMPLER_3D_EXT             0x8DCB
+#define GL_INT_SAMPLER_CUBE_EXT           0x8DCC
+#define GL_INT_SAMPLER_2D_RECT_EXT        0x8DCD
+#define GL_INT_SAMPLER_1D_ARRAY_EXT       0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY_EXT       0x8DCF
+#define GL_INT_SAMPLER_BUFFER_EXT         0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_1D_EXT    0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D_EXT    0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D_EXT    0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT  0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8
+#endif
+
+#ifndef GL_EXT_draw_instanced
+#endif
+
+#ifndef GL_EXT_packed_float
+#define GL_R11F_G11F_B10F_EXT             0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B
+#define GL_RGBA_SIGNED_COMPONENTS_EXT     0x8C3C
+#endif
+
+#ifndef GL_EXT_texture_array
+#define GL_TEXTURE_1D_ARRAY_EXT           0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY_EXT     0x8C19
+#define GL_TEXTURE_2D_ARRAY_EXT           0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY_EXT     0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY_EXT   0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY_EXT   0x8C1D
+#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT   0x88FF
+#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E
+/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */
+#endif
+
+#ifndef GL_EXT_texture_buffer_object
+#define GL_TEXTURE_BUFFER_EXT             0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT    0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER_EXT     0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D
+#define GL_TEXTURE_BUFFER_FORMAT_EXT      0x8C2E
+#endif
+
+#ifndef GL_EXT_texture_compression_latc
+#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
+#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
+#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
+#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
+#endif
+
+#ifndef GL_EXT_texture_compression_rgtc
+#define GL_COMPRESSED_RED_RGTC1_EXT       0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
+#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
+#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
+#endif
+
+#ifndef GL_EXT_texture_shared_exponent
+#define GL_RGB9_E5_EXT                    0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT   0x8C3E
+#define GL_TEXTURE_SHARED_SIZE_EXT        0x8C3F
+#endif
+
+#ifndef GL_NV_depth_buffer_float
+#define GL_DEPTH_COMPONENT32F_NV          0x8DAB
+#define GL_DEPTH32F_STENCIL8_NV           0x8DAC
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD
+#define GL_DEPTH_BUFFER_FLOAT_MODE_NV     0x8DAF
+#endif
+
+#ifndef GL_NV_fragment_program4
+#endif
+
+#ifndef GL_NV_framebuffer_multisample_coverage
+#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB
+#define GL_RENDERBUFFER_COLOR_SAMPLES_NV  0x8E10
+#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11
+#define GL_MULTISAMPLE_COVERAGE_MODES_NV  0x8E12
+#endif
+
+#ifndef GL_EXT_framebuffer_sRGB
+#define GL_FRAMEBUFFER_SRGB_EXT           0x8DB9
+#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT   0x8DBA
+#endif
+
+#ifndef GL_NV_geometry_shader4
+#endif
+
+#ifndef GL_NV_parameter_buffer_object
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1
+#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2
+#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3
+#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4
+#endif
+
+#ifndef GL_EXT_draw_buffers2
+#endif
+
+#ifndef GL_NV_transform_feedback
+#define GL_BACK_PRIMARY_COLOR_NV          0x8C77
+#define GL_BACK_SECONDARY_COLOR_NV        0x8C78
+#define GL_TEXTURE_COORD_NV               0x8C79
+#define GL_CLIP_DISTANCE_NV               0x8C7A
+#define GL_VERTEX_ID_NV                   0x8C7B
+#define GL_PRIMITIVE_ID_NV                0x8C7C
+#define GL_GENERIC_ATTRIB_NV              0x8C7D
+#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV  0x8C7E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80
+#define GL_ACTIVE_VARYINGS_NV             0x8C81
+#define GL_ACTIVE_VARYING_MAX_LENGTH_NV   0x8C82
+#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85
+#define GL_TRANSFORM_FEEDBACK_RECORD_NV   0x8C86
+#define GL_PRIMITIVES_GENERATED_NV        0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88
+#define GL_RASTERIZER_DISCARD_NV          0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS_NV         0x8C8C
+#define GL_SEPARATE_ATTRIBS_NV            0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER_NV   0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F
+#endif
+
+#ifndef GL_EXT_bindable_uniform
+#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2
+#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3
+#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4
+#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT  0x8DED
+#define GL_UNIFORM_BUFFER_EXT             0x8DEE
+#define GL_UNIFORM_BUFFER_BINDING_EXT     0x8DEF
+#endif
+
+#ifndef GL_EXT_texture_integer
+#define GL_RGBA32UI_EXT                   0x8D70
+#define GL_RGB32UI_EXT                    0x8D71
+#define GL_ALPHA32UI_EXT                  0x8D72
+#define GL_INTENSITY32UI_EXT              0x8D73
+#define GL_LUMINANCE32UI_EXT              0x8D74
+#define GL_LUMINANCE_ALPHA32UI_EXT        0x8D75
+#define GL_RGBA16UI_EXT                   0x8D76
+#define GL_RGB16UI_EXT                    0x8D77
+#define GL_ALPHA16UI_EXT                  0x8D78
+#define GL_INTENSITY16UI_EXT              0x8D79
+#define GL_LUMINANCE16UI_EXT              0x8D7A
+#define GL_LUMINANCE_ALPHA16UI_EXT        0x8D7B
+#define GL_RGBA8UI_EXT                    0x8D7C
+#define GL_RGB8UI_EXT                     0x8D7D
+#define GL_ALPHA8UI_EXT                   0x8D7E
+#define GL_INTENSITY8UI_EXT               0x8D7F
+#define GL_LUMINANCE8UI_EXT               0x8D80
+#define GL_LUMINANCE_ALPHA8UI_EXT         0x8D81
+#define GL_RGBA32I_EXT                    0x8D82
+#define GL_RGB32I_EXT                     0x8D83
+#define GL_ALPHA32I_EXT                   0x8D84
+#define GL_INTENSITY32I_EXT               0x8D85
+#define GL_LUMINANCE32I_EXT               0x8D86
+#define GL_LUMINANCE_ALPHA32I_EXT         0x8D87
+#define GL_RGBA16I_EXT                    0x8D88
+#define GL_RGB16I_EXT                     0x8D89
+#define GL_ALPHA16I_EXT                   0x8D8A
+#define GL_INTENSITY16I_EXT               0x8D8B
+#define GL_LUMINANCE16I_EXT               0x8D8C
+#define GL_LUMINANCE_ALPHA16I_EXT         0x8D8D
+#define GL_RGBA8I_EXT                     0x8D8E
+#define GL_RGB8I_EXT                      0x8D8F
+#define GL_ALPHA8I_EXT                    0x8D90
+#define GL_INTENSITY8I_EXT                0x8D91
+#define GL_LUMINANCE8I_EXT                0x8D92
+#define GL_LUMINANCE_ALPHA8I_EXT          0x8D93
+#define GL_RED_INTEGER_EXT                0x8D94
+#define GL_GREEN_INTEGER_EXT              0x8D95
+#define GL_BLUE_INTEGER_EXT               0x8D96
+#define GL_ALPHA_INTEGER_EXT              0x8D97
+#define GL_RGB_INTEGER_EXT                0x8D98
+#define GL_RGBA_INTEGER_EXT               0x8D99
+#define GL_BGR_INTEGER_EXT                0x8D9A
+#define GL_BGRA_INTEGER_EXT               0x8D9B
+#define GL_LUMINANCE_INTEGER_EXT          0x8D9C
+#define GL_LUMINANCE_ALPHA_INTEGER_EXT    0x8D9D
+#define GL_RGBA_INTEGER_MODE_EXT          0x8D9E
+#endif
+
+
+/*************************************************************/
+
+#include <stddef.h>
+#ifndef GL_VERSION_2_0
+/* GL type for program/shader text */
+typedef char GLchar;                   /* native character */
+#endif
+
+#ifndef GL_VERSION_1_5
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+#endif
+
+#ifndef GL_ARB_shader_objects
+/* GL types for handling shader object handles and program/shader text */
+typedef char GLcharARB;                /* native character */
+typedef unsigned int GLhandleARB;      /* shader object handle */
+#endif
+
+/* GL types for "half" precision (s10e5) float data in host memory */
+#ifndef GL_ARB_half_float_pixel
+typedef unsigned short GLhalfARB;
+#endif
+
+#ifndef GL_NV_half_float
+typedef unsigned short GLhalfNV;
+#endif
+
+#ifndef GLEXT_64_TYPES_DEFINED
+/* This code block is duplicated in glext.h, so must be protected */
+#define GLEXT_64_TYPES_DEFINED
+/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
+/* (as used in the GL_EXT_timer_query extension). */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif /* __arch64__ */
+#endif /* __STDC__ */
+#elif defined( __VMS )
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <inttypes.h>     /* Fallback option */
+#endif
+#endif
+
+#ifndef GL_EXT_timer_query
+typedef int64_t GLint64EXT;
+typedef uint64_t GLuint64EXT;
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf);
+GLAPI void APIENTRY glBlendEquation (GLenum);
+GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogram (GLenum);
+GLAPI void APIENTRY glResetMinmax (GLenum);
+GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum);
+GLAPI void APIENTRY glClientActiveTexture (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glFogCoordf (GLfloat);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *);
+GLAPI void APIENTRY glFogCoordd (GLdouble);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glPointParameteri (GLenum, GLint);
+GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2i (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *);
+GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *);
+GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *);
+GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint);
+GLAPI void APIENTRY glBeginQuery (GLenum, GLuint);
+GLAPI void APIENTRY glEndQuery (GLenum);
+GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *);
+GLAPI void APIENTRY glBindBuffer (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint);
+GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum);
+GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint);
+GLAPI void APIENTRY glAttachShader (GLuint, GLuint);
+GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *);
+GLAPI void APIENTRY glCompileShader (GLuint);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum);
+GLAPI void APIENTRY glDeleteProgram (GLuint);
+GLAPI void APIENTRY glDeleteShader (GLuint);
+GLAPI void APIENTRY glDetachShader (GLuint, GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint);
+GLAPI GLboolean APIENTRY glIsShader (GLuint);
+GLAPI void APIENTRY glLinkProgram (GLuint);
+GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *);
+GLAPI void APIENTRY glUseProgram (GLuint);
+GLAPI void APIENTRY glUniform1f (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1i (GLint, GLint);
+GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glValidateProgram (GLuint);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_VERSION_2_1
+#define GL_VERSION_2_1 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformMatrix2x3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3x2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix2x4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4x2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3x4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4x3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *);
+GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *);
+GLAPI void APIENTRY glWeightivARB (GLint, const GLint *);
+GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *);
+GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *);
+GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexBlendARB (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#endif
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint);
+GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint);
+GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint);
+GLAPI void APIENTRY glEndQueryARB (GLenum);
+GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1iARB (GLint, GLint);
+GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+#endif
+
+#ifndef GL_SGI_color_matrix
+#define GL_SGI_color_matrix 1
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint);
+GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *);
+GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#endif
+
+#ifndef GL_SGIX_texture_select
+#define GL_SGIX_texture_select 1
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *);
+/* ERO Begin */
+GLAPI void APIENTRY glPointParameteriEXT (GLenum, GLint);
+GLAPI void APIENTRY glPointParameterivEXT (GLenum, const GLint *);
+/* ERO end */
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#endif
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#endif
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum);
+GLAPI void APIENTRY glTextureLightEXT (GLenum);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *);
+GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *);
+/* ERO Begin */
+GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum, GLenum, GLfloat *);
+/* ERO End */
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+/* ERO Begin */
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+/* ERO End */
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *);
+GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_SGIX_fog_scale 1
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#endif
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#endif
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride);
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params);
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#endif
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint);
+GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFinishFenceNV (GLuint);
+GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *);
+GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint);
+GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#endif
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint);
+/* ERO Begin */
+GLAPI void APIENTRY glDeleteObjectBufferATI (GLuint);
+/* ERO End */
+GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *);
+GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *);
+GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+/* This is really a WGL extension, but defines some associated GL enums.
+ * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string.
+ */
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#endif
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture2D (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);
+#endif
+
+#ifndef GL_EXT_packed_depth_stencil
+#define GL_EXT_packed_depth_stencil 1
+#endif
+
+#ifndef GL_EXT_stencil_clear_tag
+#define GL_EXT_stencil_clear_tag 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilClearTagEXT (GLsizei, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag);
+#endif
+
+#ifndef GL_EXT_texture_sRGB
+#define GL_EXT_texture_sRGB 1
+#endif
+
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlitFramebufferEXT (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_MESAX_texture_stack
+#define GL_MESAX_texture_stack 1
+#endif
+
+#ifndef GL_EXT_timer_query
+#define GL_EXT_timer_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint, GLenum, GLint64EXT *);
+GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint, GLenum, GLuint64EXT *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params);
+#endif
+
+#ifndef GL_EXT_gpu_program_parameters
+#define GL_EXT_gpu_program_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+#endif
+
+#ifndef GL_APPLE_flush_buffer_range
+#define GL_APPLE_flush_buffer_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum, GLintptr, GLsizeiptr);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size);
+#endif
+
+#ifndef GL_NV_gpu_program4
+#define GL_NV_gpu_program4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum, GLuint, const GLint *);
+GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *);
+GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum, GLuint, const GLuint *);
+GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *);
+GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum, GLuint, const GLint *);
+GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *);
+GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum, GLuint, const GLuint *);
+GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *);
+GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum, GLuint, GLint *);
+GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum, GLuint, GLuint *);
+GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum, GLuint, GLint *);
+GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum, GLuint, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+#endif
+
+#ifndef GL_NV_geometry_program4
+#define GL_NV_geometry_program4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramVertexLimitNV (GLenum, GLint);
+GLAPI void APIENTRY glFramebufferTextureEXT (GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum, GLenum, GLuint, GLint, GLint);
+GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum, GLenum, GLuint, GLint, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#endif
+
+#ifndef GL_EXT_geometry_shader4
+#define GL_EXT_geometry_shader4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramParameteriEXT (GLuint, GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+#endif
+
+#ifndef GL_NV_vertex_program4
+#define GL_NV_vertex_program4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint, GLint);
+GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint, GLint, GLint);
+GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint, GLuint);
+GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint, GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_EXT_gpu_shader4
+#define GL_EXT_gpu_shader4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetUniformuivEXT (GLuint, GLint, GLuint *);
+GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint, GLuint, const GLchar *);
+GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint, const GLchar *);
+GLAPI void APIENTRY glUniform1uiEXT (GLint, GLuint);
+GLAPI void APIENTRY glUniform2uiEXT (GLint, GLuint, GLuint);
+GLAPI void APIENTRY glUniform3uiEXT (GLint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glUniform4uiEXT (GLint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glUniform1uivEXT (GLint, GLsizei, const GLuint *);
+GLAPI void APIENTRY glUniform2uivEXT (GLint, GLsizei, const GLuint *);
+GLAPI void APIENTRY glUniform3uivEXT (GLint, GLsizei, const GLuint *);
+GLAPI void APIENTRY glUniform4uivEXT (GLint, GLsizei, const GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+#endif
+
+#ifndef GL_EXT_draw_instanced
+#define GL_EXT_draw_instanced 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+
+#ifndef GL_EXT_packed_float
+#define GL_EXT_packed_float 1
+#endif
+
+#ifndef GL_EXT_texture_array
+#define GL_EXT_texture_array 1
+#endif
+
+#ifndef GL_EXT_texture_buffer_object
+#define GL_EXT_texture_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBufferEXT (GLenum, GLenum, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+#endif
+
+#ifndef GL_EXT_texture_compression_latc
+#define GL_EXT_texture_compression_latc 1
+#endif
+
+#ifndef GL_EXT_texture_compression_rgtc
+#define GL_EXT_texture_compression_rgtc 1
+#endif
+
+#ifndef GL_EXT_texture_shared_exponent
+#define GL_EXT_texture_shared_exponent 1
+#endif
+
+#ifndef GL_NV_depth_buffer_float
+#define GL_NV_depth_buffer_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthRangedNV (GLdouble, GLdouble);
+GLAPI void APIENTRY glClearDepthdNV (GLdouble);
+GLAPI void APIENTRY glDepthBoundsdNV (GLdouble, GLdouble);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth);
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax);
+#endif
+
+#ifndef GL_NV_fragment_program4
+#define GL_NV_fragment_program4 1
+#endif
+
+#ifndef GL_NV_framebuffer_multisample_coverage
+#define GL_NV_framebuffer_multisample_coverage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_EXT_framebuffer_sRGB
+#define GL_EXT_framebuffer_sRGB 1
+#endif
+
+#ifndef GL_NV_geometry_shader4
+#define GL_NV_geometry_shader4 1
+#endif
+
+#ifndef GL_NV_parameter_buffer_object
+#define GL_NV_parameter_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum, GLuint, GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum, GLuint, GLuint, GLsizei, const GLint *);
+GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum, GLuint, GLuint, GLsizei, const GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params);
+#endif
+
+#ifndef GL_EXT_draw_buffers2
+#define GL_EXT_draw_buffers2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint, GLboolean, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum, GLuint, GLboolean *);
+GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum, GLuint, GLint *);
+GLAPI void APIENTRY glEnableIndexedEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDisableIndexedEXT (GLenum, GLuint);
+GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index);
+#endif
+
+#ifndef GL_NV_transform_feedback
+#define GL_NV_transform_feedback 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum);
+GLAPI void APIENTRY glEndTransformFeedbackNV (void);
+GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint, const GLint *, GLenum);
+GLAPI void APIENTRY glBindBufferRangeNV (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr);
+GLAPI void APIENTRY glBindBufferOffsetNV (GLenum, GLuint, GLuint, GLintptr);
+GLAPI void APIENTRY glBindBufferBaseNV (GLenum, GLuint, GLuint);
+GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint, GLsizei, const GLint *, GLenum);
+GLAPI void APIENTRY glActiveVaryingNV (GLuint, const GLchar *);
+GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetActiveVaryingNV (GLuint, GLuint, GLsizei, GLsizei *, GLsizei *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint, GLuint, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location);
+#endif
+
+#ifndef GL_EXT_bindable_uniform
+#define GL_EXT_bindable_uniform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformBufferEXT (GLuint, GLint, GLuint);
+GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint, GLint);
+GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location);
+typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location);
+#endif
+
+#ifndef GL_EXT_texture_integer
+#define GL_EXT_texture_integer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexParameterIivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glTexParameterIuivEXT (GLenum, GLenum, const GLuint *);
+GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum, GLenum, GLuint *);
+GLAPI void APIENTRY glClearColorIiEXT (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glClearColorIuiEXT (GLuint, GLuint, GLuint, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha);
+typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+#endif
+
+/* ERO */
+GLAPI void GLAPIENTRY fake_gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/tizen/src/hw/mesa_glu.h b/tizen/src/hw/mesa_glu.h
new file mode 100755 (executable)
index 0000000..eae5fa6
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: This software was created using the
+** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has
+** not been independently verified as being compliant with the OpenGL(R)
+** version 1.2.1 Specification.
+*/
+
+#ifndef __glu_h__
+#define __glu_h__
+
+#if defined(USE_MGL_NAMESPACE)
+#include "glu_mangle.h"
+#endif
+
+//#include <GL/gl.h>
+#include "mesa_gl.h"
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY
+#endif
+
+#ifndef GLAPIENTRYP
+#define GLAPIENTRYP GLAPIENTRY *
+#endif
+
+#ifdef GLAPI
+#undef GLAPI
+#endif
+
+#  if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
+#    define GLAPI __declspec(dllexport)
+#  elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL) /* tag specifying we're building for DLL runtime support */
+#    define GLAPI __declspec(dllimport)
+#  else /* for use with static link lib build of Win32 edition only */
+#    define GLAPI extern
+#  endif /* _STATIC_MESA support */
+
+
+#ifndef GLAPI
+#define GLAPI
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+/* Extensions */
+#define GLU_EXT_object_space_tess          1
+#define GLU_EXT_nurbs_tessellator          1
+
+/* Boolean */
+#define GLU_FALSE                          0
+#define GLU_TRUE                           1
+
+/* Version */
+#define GLU_VERSION_1_1                    1
+#define GLU_VERSION_1_2                    1
+#define GLU_VERSION_1_3                    1
+
+/* StringName */
+#define GLU_VERSION                        100800
+#define GLU_EXTENSIONS                     100801
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM                   100900
+#define GLU_INVALID_VALUE                  100901
+#define GLU_OUT_OF_MEMORY                  100902
+#define GLU_INCOMPATIBLE_GL_VERSION        100903
+#define GLU_INVALID_OPERATION              100904
+
+/* NurbsDisplay */
+/*      GLU_FILL */
+#define GLU_OUTLINE_POLYGON                100240
+#define GLU_OUTLINE_PATCH                  100241
+
+/* NurbsCallback */
+#define GLU_NURBS_ERROR                    100103
+#define GLU_ERROR                          100103
+#define GLU_NURBS_BEGIN                    100164
+#define GLU_NURBS_BEGIN_EXT                100164
+#define GLU_NURBS_VERTEX                   100165
+#define GLU_NURBS_VERTEX_EXT               100165
+#define GLU_NURBS_NORMAL                   100166
+#define GLU_NURBS_NORMAL_EXT               100166
+#define GLU_NURBS_COLOR                    100167
+#define GLU_NURBS_COLOR_EXT                100167
+#define GLU_NURBS_TEXTURE_COORD            100168
+#define GLU_NURBS_TEX_COORD_EXT            100168
+#define GLU_NURBS_END                      100169
+#define GLU_NURBS_END_EXT                  100169
+#define GLU_NURBS_BEGIN_DATA               100170
+#define GLU_NURBS_BEGIN_DATA_EXT           100170
+#define GLU_NURBS_VERTEX_DATA              100171
+#define GLU_NURBS_VERTEX_DATA_EXT          100171
+#define GLU_NURBS_NORMAL_DATA              100172
+#define GLU_NURBS_NORMAL_DATA_EXT          100172
+#define GLU_NURBS_COLOR_DATA               100173
+#define GLU_NURBS_COLOR_DATA_EXT           100173
+#define GLU_NURBS_TEXTURE_COORD_DATA       100174
+#define GLU_NURBS_TEX_COORD_DATA_EXT       100174
+#define GLU_NURBS_END_DATA                 100175
+#define GLU_NURBS_END_DATA_EXT             100175
+
+/* NurbsError */
+#define GLU_NURBS_ERROR1                   100251
+#define GLU_NURBS_ERROR2                   100252
+#define GLU_NURBS_ERROR3                   100253
+#define GLU_NURBS_ERROR4                   100254
+#define GLU_NURBS_ERROR5                   100255
+#define GLU_NURBS_ERROR6                   100256
+#define GLU_NURBS_ERROR7                   100257
+#define GLU_NURBS_ERROR8                   100258
+#define GLU_NURBS_ERROR9                   100259
+#define GLU_NURBS_ERROR10                  100260
+#define GLU_NURBS_ERROR11                  100261
+#define GLU_NURBS_ERROR12                  100262
+#define GLU_NURBS_ERROR13                  100263
+#define GLU_NURBS_ERROR14                  100264
+#define GLU_NURBS_ERROR15                  100265
+#define GLU_NURBS_ERROR16                  100266
+#define GLU_NURBS_ERROR17                  100267
+#define GLU_NURBS_ERROR18                  100268
+#define GLU_NURBS_ERROR19                  100269
+#define GLU_NURBS_ERROR20                  100270
+#define GLU_NURBS_ERROR21                  100271
+#define GLU_NURBS_ERROR22                  100272
+#define GLU_NURBS_ERROR23                  100273
+#define GLU_NURBS_ERROR24                  100274
+#define GLU_NURBS_ERROR25                  100275
+#define GLU_NURBS_ERROR26                  100276
+#define GLU_NURBS_ERROR27                  100277
+#define GLU_NURBS_ERROR28                  100278
+#define GLU_NURBS_ERROR29                  100279
+#define GLU_NURBS_ERROR30                  100280
+#define GLU_NURBS_ERROR31                  100281
+#define GLU_NURBS_ERROR32                  100282
+#define GLU_NURBS_ERROR33                  100283
+#define GLU_NURBS_ERROR34                  100284
+#define GLU_NURBS_ERROR35                  100285
+#define GLU_NURBS_ERROR36                  100286
+#define GLU_NURBS_ERROR37                  100287
+
+/* NurbsProperty */
+#define GLU_AUTO_LOAD_MATRIX               100200
+#define GLU_CULLING                        100201
+#define GLU_SAMPLING_TOLERANCE             100203
+#define GLU_DISPLAY_MODE                   100204
+#define GLU_PARAMETRIC_TOLERANCE           100202
+#define GLU_SAMPLING_METHOD                100205
+#define GLU_U_STEP                         100206
+#define GLU_V_STEP                         100207
+#define GLU_NURBS_MODE                     100160
+#define GLU_NURBS_MODE_EXT                 100160
+#define GLU_NURBS_TESSELLATOR              100161
+#define GLU_NURBS_TESSELLATOR_EXT          100161
+#define GLU_NURBS_RENDERER                 100162
+#define GLU_NURBS_RENDERER_EXT             100162
+
+/* NurbsSampling */
+#define GLU_OBJECT_PARAMETRIC_ERROR        100208
+#define GLU_OBJECT_PARAMETRIC_ERROR_EXT    100208
+#define GLU_OBJECT_PATH_LENGTH             100209
+#define GLU_OBJECT_PATH_LENGTH_EXT         100209
+#define GLU_PATH_LENGTH                    100215
+#define GLU_PARAMETRIC_ERROR               100216
+#define GLU_DOMAIN_DISTANCE                100217
+
+/* NurbsTrim */
+#define GLU_MAP1_TRIM_2                    100210
+#define GLU_MAP1_TRIM_3                    100211
+
+/* QuadricDrawStyle */
+#define GLU_POINT                          100010
+#define GLU_LINE                           100011
+#define GLU_FILL                           100012
+#define GLU_SILHOUETTE                     100013
+
+/* QuadricCallback */
+/*      GLU_ERROR */
+
+/* QuadricNormal */
+#define GLU_SMOOTH                         100000
+#define GLU_FLAT                           100001
+#define GLU_NONE                           100002
+
+/* QuadricOrientation */
+#define GLU_OUTSIDE                        100020
+#define GLU_INSIDE                         100021
+
+/* TessCallback */
+#define GLU_TESS_BEGIN                     100100
+#define GLU_BEGIN                          100100
+#define GLU_TESS_VERTEX                    100101
+#define GLU_VERTEX                         100101
+#define GLU_TESS_END                       100102
+#define GLU_END                            100102
+#define GLU_TESS_ERROR                     100103
+#define GLU_TESS_EDGE_FLAG                 100104
+#define GLU_EDGE_FLAG                      100104
+#define GLU_TESS_COMBINE                   100105
+#define GLU_TESS_BEGIN_DATA                100106
+#define GLU_TESS_VERTEX_DATA               100107
+#define GLU_TESS_END_DATA                  100108
+#define GLU_TESS_ERROR_DATA                100109
+#define GLU_TESS_EDGE_FLAG_DATA            100110
+#define GLU_TESS_COMBINE_DATA              100111
+
+/* TessContour */
+#define GLU_CW                             100120
+#define GLU_CCW                            100121
+#define GLU_INTERIOR                       100122
+#define GLU_EXTERIOR                       100123
+#define GLU_UNKNOWN                        100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE              100140
+#define GLU_TESS_BOUNDARY_ONLY             100141
+#define GLU_TESS_TOLERANCE                 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1                    100151
+#define GLU_TESS_ERROR2                    100152
+#define GLU_TESS_ERROR3                    100153
+#define GLU_TESS_ERROR4                    100154
+#define GLU_TESS_ERROR5                    100155
+#define GLU_TESS_ERROR6                    100156
+#define GLU_TESS_ERROR7                    100157
+#define GLU_TESS_ERROR8                    100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON     100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR     100152
+#define GLU_TESS_MISSING_END_POLYGON       100153
+#define GLU_TESS_MISSING_END_CONTOUR       100154
+#define GLU_TESS_COORD_TOO_LARGE           100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK     100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD               100130
+#define GLU_TESS_WINDING_NONZERO           100131
+#define GLU_TESS_WINDING_POSITIVE          100132
+#define GLU_TESS_WINDING_NEGATIVE          100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO       100134
+
+/*************************************************************/
+
+
+#ifdef __cplusplus
+class GLUnurbs;
+class GLUquadric;
+class GLUtesselator;
+#else
+typedef struct GLUnurbs GLUnurbs;
+typedef struct GLUquadric GLUquadric;
+typedef struct GLUtesselator GLUtesselator;
+#endif
+
+typedef GLUnurbs GLUnurbsObj;
+typedef GLUquadric GLUquadricObj;
+typedef GLUtesselator GLUtesselatorObj;
+typedef GLUtesselator GLUtriangulatorObj;
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+/* Internal convenience typedefs */
+typedef void (GLAPIENTRYP _GLUfuncptr)();
+
+GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
+GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
+GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
+GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
+GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
+GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
+GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
+GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
+GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
+GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
+GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
+GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
+GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
+GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
+GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
+GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
+GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
+GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
+GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
+GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
+GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
+GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
+GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
+GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
+GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
+GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
+GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
+GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
+GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
+GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
+GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
+GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glu_h__ */
diff --git a/tizen/src/hw/mesa_mipmap.c b/tizen/src/hw/mesa_mipmap.c
new file mode 100755 (executable)
index 0000000..1263cd5
--- /dev/null
@@ -0,0 +1,825 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.4
+ * Copyright (C) 1995-2000  Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mesa_glu.h"
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+//#include "gluP.h"
+#endif
+
+
+/*
+ * Compute ceiling of integer quotient of A divided by B:
+ */
+#define CEILING( A, B )  ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
+
+
+
+#ifdef EPSILON
+#undef EPSILON
+#endif
+#define EPSILON 0.001
+
+
+/* To work around optimizer bug in MSVC4.1 */
+#if defined(__WIN32__) && !defined(OPENSTEP)
+void
+dummy(GLuint j, GLuint k)
+{
+}
+#else
+#define dummy(J, K)
+#endif
+
+
+static GLint GLAPIENTRY
+mesa_gluScaleImage(GLenum format,
+             GLsizei widthin, GLsizei heightin,
+             GLenum typein, const void *datain,
+             GLsizei widthout, GLsizei heightout,
+             GLenum typeout, void *dataout)
+{
+   GLint components, i, j, k;
+   GLfloat *tempin, *tempout;
+   GLfloat sx, sy;
+   GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+   GLint packrowlength, packalignment, packskiprows, packskippixels;
+   GLint sizein, sizeout;
+   GLint rowstride, rowlen;
+
+
+   /* Determine number of components per pixel */
+   switch (format) {
+   case GL_COLOR_INDEX:
+   case GL_STENCIL_INDEX:
+   case GL_DEPTH_COMPONENT:
+   case GL_RED:
+   case GL_GREEN:
+   case GL_BLUE:
+   case GL_ALPHA:
+   case GL_LUMINANCE:
+      components = 1;
+      break;
+   case GL_LUMINANCE_ALPHA:
+      components = 2;
+      break;
+   case GL_RGB:
+   case GL_BGR:
+      components = 3;
+      break;
+   case GL_RGBA:
+   case GL_BGRA:
+#ifdef GL_EXT_abgr
+   case GL_ABGR_EXT:
+#endif
+      components = 4;
+      break;
+   default:
+      return GLU_INVALID_ENUM;
+   }
+
+   /* Determine bytes per input datum */
+   switch (typein) {
+   case GL_UNSIGNED_BYTE:
+      sizein = sizeof(GLubyte);
+      break;
+   case GL_BYTE:
+      sizein = sizeof(GLbyte);
+      break;
+   case GL_UNSIGNED_SHORT:
+      sizein = sizeof(GLushort);
+      break;
+   case GL_SHORT:
+      sizein = sizeof(GLshort);
+      break;
+   case GL_UNSIGNED_INT:
+      sizein = sizeof(GLuint);
+      break;
+   case GL_INT:
+      sizein = sizeof(GLint);
+      break;
+   case GL_FLOAT:
+      sizein = sizeof(GLfloat);
+      break;
+   case GL_BITMAP:
+      /* not implemented yet */
+   default:
+      return GL_INVALID_ENUM;
+   }
+
+   /* Determine bytes per output datum */
+   switch (typeout) {
+   case GL_UNSIGNED_BYTE:
+      sizeout = sizeof(GLubyte);
+      break;
+   case GL_BYTE:
+      sizeout = sizeof(GLbyte);
+      break;
+   case GL_UNSIGNED_SHORT:
+      sizeout = sizeof(GLushort);
+      break;
+   case GL_SHORT:
+      sizeout = sizeof(GLshort);
+      break;
+   case GL_UNSIGNED_INT:
+      sizeout = sizeof(GLuint);
+      break;
+   case GL_INT:
+      sizeout = sizeof(GLint);
+      break;
+   case GL_FLOAT:
+      sizeout = sizeof(GLfloat);
+      break;
+   case GL_BITMAP:
+      /* not implemented yet */
+   default:
+      return GL_INVALID_ENUM;
+   }
+
+   /* Get glPixelStore state */
+   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
+   glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
+   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
+   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
+   glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
+   glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
+   glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
+   glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
+
+   /* Allocate storage for intermediate images */
+   tempin = (GLfloat *) malloc(widthin * heightin
+                              * components * sizeof(GLfloat));
+   if (!tempin) {
+      return GLU_OUT_OF_MEMORY;
+   }
+   tempout = (GLfloat *) malloc(widthout * heightout
+                               * components * sizeof(GLfloat));
+   if (!tempout) {
+      free(tempin);
+      return GLU_OUT_OF_MEMORY;
+   }
+
+
+   /*
+    * Unpack the pixel data and convert to floating point
+    */
+
+   if (unpackrowlength > 0) {
+      rowlen = unpackrowlength;
+   }
+   else {
+      rowlen = widthin;
+   }
+   if (sizein >= unpackalignment) {
+      rowstride = components * rowlen;
+   }
+   else {
+      rowstride = unpackalignment / sizein
+        * CEILING(components * rowlen * sizein, unpackalignment);
+   }
+
+   switch (typein) {
+   case GL_UNSIGNED_BYTE:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLubyte *ubptr = (GLubyte *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * ubptr++;
+        }
+      }
+      break;
+   case GL_BYTE:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLbyte *bptr = (GLbyte *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * bptr++;
+        }
+      }
+      break;
+   case GL_UNSIGNED_SHORT:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLushort *usptr = (GLushort *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * usptr++;
+        }
+      }
+      break;
+   case GL_SHORT:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLshort *sptr = (GLshort *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * sptr++;
+        }
+      }
+      break;
+   case GL_UNSIGNED_INT:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLuint *uiptr = (GLuint *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * uiptr++;
+        }
+      }
+      break;
+   case GL_INT:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLint *iptr = (GLint *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = (GLfloat) * iptr++;
+        }
+      }
+      break;
+   case GL_FLOAT:
+      k = 0;
+      for (i = 0; i < heightin; i++) {
+        GLfloat *fptr = (GLfloat *) datain
+           + i * rowstride
+           + unpackskiprows * rowstride + unpackskippixels * components;
+        for (j = 0; j < widthin * components; j++) {
+           dummy(j, k);
+           tempin[k++] = *fptr++;
+        }
+      }
+      break;
+   default:
+      return GLU_INVALID_ENUM;
+   }
+
+
+   /*
+    * Scale the image!
+    */
+
+   if (widthout > 1)
+      sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1);
+   else
+      sx = (GLfloat) (widthin - 1);
+   if (heightout > 1)
+      sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1);
+   else
+      sy = (GLfloat) (heightin - 1);
+
+/*#define POINT_SAMPLE*/
+#ifdef POINT_SAMPLE
+   for (i = 0; i < heightout; i++) {
+      GLint ii = i * sy;
+      for (j = 0; j < widthout; j++) {
+        GLint jj = j * sx;
+
+        GLfloat *src = tempin + (ii * widthin + jj) * components;
+        GLfloat *dst = tempout + (i * widthout + j) * components;
+
+        for (k = 0; k < components; k++) {
+           *dst++ = *src++;
+        }
+      }
+   }
+#else
+   if (sx < 1.0 && sy < 1.0) {
+      /* magnify both width and height:  use weighted sample of 4 pixels */
+      GLint i0, i1, j0, j1;
+      GLfloat alpha, beta;
+      GLfloat *src00, *src01, *src10, *src11;
+      GLfloat s1, s2;
+      GLfloat *dst;
+
+      for (i = 0; i < heightout; i++) {
+        i0 = i * sy;
+        i1 = i0 + 1;
+        if (i1 >= heightin)
+           i1 = heightin - 1;
+/*      i1 = (i+1) * sy - EPSILON;*/
+        alpha = i * sy - i0;
+        for (j = 0; j < widthout; j++) {
+           j0 = j * sx;
+           j1 = j0 + 1;
+           if (j1 >= widthin)
+              j1 = widthin - 1;
+/*         j1 = (j+1) * sx - EPSILON; */
+           beta = j * sx - j0;
+
+           /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
+           src00 = tempin + (i0 * widthin + j0) * components;
+           src01 = tempin + (i0 * widthin + j1) * components;
+           src10 = tempin + (i1 * widthin + j0) * components;
+           src11 = tempin + (i1 * widthin + j1) * components;
+
+           dst = tempout + (i * widthout + j) * components;
+
+           for (k = 0; k < components; k++) {
+              s1 = *src00++ * (1.0 - beta) + *src01++ * beta;
+              s2 = *src10++ * (1.0 - beta) + *src11++ * beta;
+              *dst++ = s1 * (1.0 - alpha) + s2 * alpha;
+           }
+        }
+      }
+   }
+   else {
+      /* shrink width and/or height:  use an unweighted box filter */
+      GLint i0, i1;
+      GLint j0, j1;
+      GLint ii, jj;
+      GLfloat sum, *dst;
+
+      for (i = 0; i < heightout; i++) {
+        i0 = i * sy;
+        i1 = i0 + 1;
+        if (i1 >= heightin)
+           i1 = heightin - 1;
+/*      i1 = (i+1) * sy - EPSILON; */
+        for (j = 0; j < widthout; j++) {
+           j0 = j * sx;
+           j1 = j0 + 1;
+           if (j1 >= widthin)
+              j1 = widthin - 1;
+/*         j1 = (j+1) * sx - EPSILON; */
+
+           dst = tempout + (i * widthout + j) * components;
+
+           /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
+           for (k = 0; k < components; k++) {
+              sum = 0.0;
+              for (ii = i0; ii <= i1; ii++) {
+                 for (jj = j0; jj <= j1; jj++) {
+                    sum += *(tempin + (ii * widthin + jj) * components + k);
+                 }
+              }
+              sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
+              *dst++ = sum;
+           }
+        }
+      }
+   }
+#endif
+
+
+   /*
+    * Return output image
+    */
+
+   if (packrowlength > 0) {
+      rowlen = packrowlength;
+   }
+   else {
+      rowlen = widthout;
+   }
+   if (sizeout >= packalignment) {
+      rowstride = components * rowlen;
+   }
+   else {
+      rowstride = packalignment / sizeout
+        * CEILING(components * rowlen * sizeout, packalignment);
+   }
+
+   switch (typeout) {
+   case GL_UNSIGNED_BYTE:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLubyte *ubptr = (GLubyte *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *ubptr++ = (GLubyte) tempout[k++];
+        }
+      }
+      break;
+   case GL_BYTE:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLbyte *bptr = (GLbyte *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *bptr++ = (GLbyte) tempout[k++];
+        }
+      }
+      break;
+   case GL_UNSIGNED_SHORT:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLushort *usptr = (GLushort *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *usptr++ = (GLushort) tempout[k++];
+        }
+      }
+      break;
+   case GL_SHORT:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLshort *sptr = (GLshort *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *sptr++ = (GLshort) tempout[k++];
+        }
+      }
+      break;
+   case GL_UNSIGNED_INT:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLuint *uiptr = (GLuint *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *uiptr++ = (GLuint) tempout[k++];
+        }
+      }
+      break;
+   case GL_INT:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLint *iptr = (GLint *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *iptr++ = (GLint) tempout[k++];
+        }
+      }
+      break;
+   case GL_FLOAT:
+      k = 0;
+      for (i = 0; i < heightout; i++) {
+        GLfloat *fptr = (GLfloat *) dataout
+           + i * rowstride
+           + packskiprows * rowstride + packskippixels * components;
+        for (j = 0; j < widthout * components; j++) {
+           dummy(j, k + i);
+           *fptr++ = tempout[k++];
+        }
+      }
+      break;
+   default:
+      return GLU_INVALID_ENUM;
+   }
+
+
+   /* free temporary image storage */
+   free(tempin);
+   free(tempout);
+
+   return 0;
+}
+
+
+
+/*
+ * Return the largest k such that 2^k <= n.
+ */
+static GLint
+ilog2(GLint n)
+{
+   GLint k;
+
+   if (n <= 0)
+      return 0;
+   for (k = 0; n >>= 1; k++);
+   return k;
+}
+
+
+
+/*
+ * Find the value nearest to n which is also a power of two.
+ */
+static GLint
+round2(GLint n)
+{
+   GLint m;
+
+   for (m = 1; m < n; m *= 2);
+
+   /* m>=n */
+   if (m - n <= n - m / 2) {
+      return m;
+   }
+   else {
+      return m / 2;
+   }
+}
+
+
+/*
+ * Given an pixel format and datatype, return the number of bytes to
+ * store one pixel.
+ */
+static GLint
+bytes_per_pixel(GLenum format, GLenum type)
+{
+   GLint n, m;
+
+   switch (format) {
+   case GL_COLOR_INDEX:
+   case GL_STENCIL_INDEX:
+   case GL_DEPTH_COMPONENT:
+   case GL_RED:
+   case GL_GREEN:
+   case GL_BLUE:
+   case GL_ALPHA:
+   case GL_LUMINANCE:
+      n = 1;
+      break;
+   case GL_LUMINANCE_ALPHA:
+      n = 2;
+      break;
+   case GL_RGB:
+   case GL_BGR:
+      n = 3;
+      break;
+   case GL_RGBA:
+   case GL_BGRA:
+#ifdef GL_EXT_abgr
+   case GL_ABGR_EXT:
+#endif
+      n = 4;
+      break;
+   default:
+      n = 0;
+   }
+
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      m = sizeof(GLubyte);
+      break;
+   case GL_BYTE:
+      m = sizeof(GLbyte);
+      break;
+   case GL_BITMAP:
+      m = 1;
+      break;
+   case GL_UNSIGNED_SHORT:
+      m = sizeof(GLushort);
+      break;
+   case GL_SHORT:
+      m = sizeof(GLshort);
+      break;
+   case GL_UNSIGNED_INT:
+      m = sizeof(GLuint);
+      break;
+   case GL_INT:
+      m = sizeof(GLint);
+      break;
+   case GL_FLOAT:
+      m = sizeof(GLfloat);
+      break;
+   default:
+      m = 0;
+   }
+
+   return n * m;
+}
+
+
+
+/*
+ * WARNING: This function isn't finished and has never been tested!!!!
+ */
+GLint GLAPIENTRY
+mesa_gluBuild1DMipmaps(GLenum target, GLint components,
+                 GLsizei width, GLenum format, GLenum type, const void *data)
+{
+   GLubyte *texture;
+   GLint levels, max_levels;
+   GLint new_width, max_width;
+   GLint i, j, k, l;
+
+   if (width < 1)
+      return GLU_INVALID_VALUE;
+
+   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_width);
+   max_levels = ilog2(max_width) + 1;
+
+   /* Compute how many mipmap images to make */
+   levels = ilog2(width) + 1;
+   if (levels > max_levels) {
+      levels = max_levels;
+   }
+
+   new_width = 1 << (levels - 1);
+
+   texture = (GLubyte *) malloc(new_width * components);
+   if (!texture) {
+      return GLU_OUT_OF_MEMORY;
+   }
+
+   if (width != new_width) {
+      /* initial rescaling */
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+        {
+           GLubyte *ub_data = (GLubyte *) data;
+           for (i = 0; i < new_width; i++) {
+              j = i * width / new_width;
+              for (k = 0; k < components; k++) {
+                 texture[i * components + k] = ub_data[j * components + k];
+              }
+           }
+        }
+        break;
+      default:
+        /* Not implemented */
+        return GLU_ERROR;
+      }
+   }
+
+   /* generate and load mipmap images */
+   for (l = 0; l < levels; l++) {
+      glTexImage1D(GL_TEXTURE_1D, l, components, new_width, 0,
+                  format, GL_UNSIGNED_BYTE, texture);
+
+      /* Scale image down to 1/2 size */
+      new_width = new_width / 2;
+      for (i = 0; i < new_width; i++) {
+        for (k = 0; k < components; k++) {
+           GLint sample1, sample2;
+           sample1 = (GLint) texture[i * 2 * components + k];
+           sample2 = (GLint) texture[(i * 2 + 1) * components + k];
+           texture[i * components + k] = (GLubyte) ((sample1 + sample2) / 2);
+        }
+      }
+   }
+
+   free(texture);
+
+   return 0;
+}
+
+
+
+GLint GLAPIENTRY
+mesa_gluBuild2DMipmaps(GLenum target, GLint components,
+                 GLsizei width, GLsizei height, GLenum format,
+                 GLenum type, const void *data)
+{
+   GLint w, h, maxsize;
+   void *image, *newimage;
+   GLint neww, newh, level, bpp;
+   int error;
+   GLboolean done;
+   GLint retval = 0;
+   GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+   GLint packrowlength, packalignment, packskiprows, packskippixels;
+
+   if (width < 1 || height < 1)
+      return GLU_INVALID_VALUE;
+
+   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+
+   w = round2(width);
+   if (w > maxsize) {
+      w = maxsize;
+   }
+   h = round2(height);
+   if (h > maxsize) {
+      h = maxsize;
+   }
+
+   bpp = bytes_per_pixel(format, type);
+   if (bpp == 0) {
+      /* probably a bad format or type enum */
+      return GLU_INVALID_ENUM;
+   }
+
+   /* Get current glPixelStore values */
+   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
+   glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
+   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
+   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
+   glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
+   glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
+   glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
+   glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
+
+   /* set pixel packing */
+   glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+   glPixelStorei(GL_PACK_ALIGNMENT, 1);
+   glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+   glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+   done = GL_FALSE;
+
+   if (w != width || h != height) {
+      /* must rescale image to get "top" mipmap texture image */
+      image = malloc((w + 4) * h * bpp);
+      if (!image) {
+        return GLU_OUT_OF_MEMORY;
+      }
+      error = mesa_gluScaleImage(format, width, height, type, data,
+                           w, h, type, image);
+      if (error) {
+        retval = error;
+        done = GL_TRUE;
+      }
+   }
+   else {
+      image = (void *) data;
+   }
+
+   level = 0;
+   while (!done) {
+      if (image != data) {
+        /* set pixel unpacking */
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+      }
+
+      glTexImage2D(target, level, components, w, h, 0, format, type, image);
+
+      if (w == 1 && h == 1)
+        break;
+
+      neww = (w < 2) ? 1 : w / 2;
+      newh = (h < 2) ? 1 : h / 2;
+      newimage = malloc((neww + 4) * newh * bpp);
+      if (!newimage) {
+        return GLU_OUT_OF_MEMORY;
+      }
+
+      error = mesa_gluScaleImage(format, w, h, type, image,
+                           neww, newh, type, newimage);
+      if (error) {
+        retval = error;
+        done = GL_TRUE;
+      }
+
+      if (image != data) {
+        free(image);
+      }
+      image = newimage;
+
+      w = neww;
+      h = newh;
+      level++;
+   }
+
+   if (image != data) {
+      free(image);
+   }
+
+   /* Restore original glPixelStore state */
+   glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
+   glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
+   glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
+   glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
+   glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
+   glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
+   glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
+   glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
+
+   return retval;
+}
diff --git a/tizen/src/hw/mesa_mipmap.h b/tizen/src/hw/mesa_mipmap.h
new file mode 100755 (executable)
index 0000000..047596f
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.4
+ * Copyright (C) 1995-2000  Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+extern GLint GLAPIENTRY
+mesa_gluBuild2DMipmaps(GLenum target, GLint components,
+                  GLsizei width, GLsizei height, GLenum format,
+                  GLenum type, const void *data);
diff --git a/tizen/src/hw/op_helper.c b/tizen/src/hw/op_helper.c
new file mode 100755 (executable)
index 0000000..c89e4a4
--- /dev/null
@@ -0,0 +1,5881 @@
+/*
+ *  i386 helpers
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <math.h>
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "host-utils.h"
+#include "ioport.h"
+#include "qemu-common.h"
+#include "qemu-log.h"
+#include "cpu-defs.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+#  define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
+#  define LOG_PCALL_STATE(env) \
+          log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
+#else
+#  define LOG_PCALL(...) do { } while (0)
+#  define LOG_PCALL_STATE(env) do { } while (0)
+#endif
+
+/* n must be a constant to be efficient */
+static inline target_long lshift(target_long x, int n)
+{
+    if (n >= 0) {
+        return x << n;
+    } else {
+        return x >> (-n);
+    }
+}
+
+#define RC_MASK         0xc00
+#define RC_NEAR         0x000
+#define RC_DOWN         0x400
+#define RC_UP           0x800
+#define RC_CHOP         0xc00
+
+#define MAXTAN 9223372036854775808.0
+
+/* the following deal with x86 long double-precision numbers */
+#define MAXEXPD 0x7fff
+#define EXPBIAS 16383
+#define EXPD(fp)        (fp.l.upper & 0x7fff)
+#define SIGND(fp)       ((fp.l.upper) & 0x8000)
+#define MANTD(fp)       (fp.l.lower)
+#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
+
+static inline void fpush(void)
+{
+    env->fpstt = (env->fpstt - 1) & 7;
+    env->fptags[env->fpstt] = 0; /* validate stack entry */
+}
+
+static inline void fpop(void)
+{
+    env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
+    env->fpstt = (env->fpstt + 1) & 7;
+}
+
+static inline floatx80 helper_fldt(target_ulong ptr)
+{
+    CPU_LDoubleU temp;
+
+    temp.l.lower = ldq(ptr);
+    temp.l.upper = lduw(ptr + 8);
+    return temp.d;
+}
+
+static inline void helper_fstt(floatx80 f, target_ulong ptr)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = f;
+    stq(ptr, temp.l.lower);
+    stw(ptr + 8, temp.l.upper);
+}
+
+#define FPUS_IE (1 << 0)
+#define FPUS_DE (1 << 1)
+#define FPUS_ZE (1 << 2)
+#define FPUS_OE (1 << 3)
+#define FPUS_UE (1 << 4)
+#define FPUS_PE (1 << 5)
+#define FPUS_SF (1 << 6)
+#define FPUS_SE (1 << 7)
+#define FPUS_B  (1 << 15)
+
+#define FPUC_EM 0x3f
+
+static inline uint32_t compute_eflags(void)
+{
+    return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+}
+
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
+static inline void load_eflags(int eflags, int update_mask)
+{
+    CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+    DF = 1 - (2 * ((eflags >> 10) & 1));
+    env->eflags = (env->eflags & ~update_mask) |
+        (eflags & update_mask) | 0x2;
+}
+
+/* load efer and update the corresponding hflags. XXX: do consistency
+   checks with cpuid bits ? */
+static inline void cpu_load_efer(CPUState *env, uint64_t val)
+{
+    env->efer = val;
+    env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
+    if (env->efer & MSR_EFER_LMA) {
+        env->hflags |= HF_LMA_MASK;
+    }
+    if (env->efer & MSR_EFER_SVME) {
+        env->hflags |= HF_SVME_MASK;
+    }
+}
+
+#if 0
+#define raise_exception_err(a, b)\
+do {\
+    qemu_log("raise_exception line=%d\n", __LINE__);\
+    (raise_exception_err)(a, b);\
+} while (0)
+#endif
+
+static void QEMU_NORETURN raise_exception_err(int exception_index,
+                                              int error_code);
+
+static const uint8_t parity_table[256] = {
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+};
+
+/* modulo 17 table */
+static const uint8_t rclw_table[32] = {
+    0, 1, 2, 3, 4, 5, 6, 7,
+    8, 9,10,11,12,13,14,15,
+   16, 0, 1, 2, 3, 4, 5, 6,
+    7, 8, 9,10,11,12,13,14,
+};
+
+/* modulo 9 table */
+static const uint8_t rclb_table[32] = {
+    0, 1, 2, 3, 4, 5, 6, 7,
+    8, 0, 1, 2, 3, 4, 5, 6,
+    7, 8, 0, 1, 2, 3, 4, 5,
+    6, 7, 8, 0, 1, 2, 3, 4,
+};
+
+#define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
+#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
+#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
+
+/* broken thread support */
+
+static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void helper_lock(void)
+{
+    spin_lock(&global_cpu_lock);
+}
+
+void helper_unlock(void)
+{
+    spin_unlock(&global_cpu_lock);
+}
+
+void helper_write_eflags(target_ulong t0, uint32_t update_mask)
+{
+    load_eflags(t0, update_mask);
+}
+
+target_ulong helper_read_eflags(void)
+{
+    uint32_t eflags;
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags |= (DF & DF_MASK);
+    eflags |= env->eflags & ~(VM_MASK | RF_MASK);
+    return eflags;
+}
+
+/* return non zero if error */
+static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
+                               int selector)
+{
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    if (selector & 0x4)
+        dt = &env->ldt;
+    else
+        dt = &env->gdt;
+    index = selector & ~7;
+    if ((index + 7) > dt->limit)
+        return -1;
+    ptr = dt->base + index;
+    *e1_ptr = ldl_kernel(ptr);
+    *e2_ptr = ldl_kernel(ptr + 4);
+    return 0;
+}
+
+static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
+{
+    unsigned int limit;
+    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+    if (e2 & DESC_G_MASK)
+        limit = (limit << 12) | 0xfff;
+    return limit;
+}
+
+static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
+{
+    return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+}
+
+static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
+{
+    sc->base = get_seg_base(e1, e2);
+    sc->limit = get_seg_limit(e1, e2);
+    sc->flags = e2;
+}
+
+/* init the segment cache in vm86 mode. */
+static inline void load_seg_vm(int seg, int selector)
+{
+    selector &= 0xffff;
+    cpu_x86_load_seg_cache(env, seg, selector,
+                           (selector << 4), 0xffff, 0);
+}
+
+static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
+                                       uint32_t *esp_ptr, int dpl)
+{
+    int type, index, shift;
+
+#if 0
+    {
+        int i;
+        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
+        for(i=0;i<env->tr.limit;i++) {
+            printf("%02x ", env->tr.base[i]);
+            if ((i & 7) == 7) printf("\n");
+        }
+        printf("\n");
+    }
+#endif
+
+    if (!(env->tr.flags & DESC_P_MASK))
+        cpu_abort(env, "invalid tss");
+    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+    if ((type & 7) != 1)
+        cpu_abort(env, "invalid tss type");
+    shift = type >> 3;
+    index = (dpl * 4 + 2) << shift;
+    if (index + (4 << shift) - 1 > env->tr.limit)
+        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
+    if (shift == 0) {
+        *esp_ptr = lduw_kernel(env->tr.base + index);
+        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
+    } else {
+        *esp_ptr = ldl_kernel(env->tr.base + index);
+        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
+    }
+}
+
+/* XXX: merge with load_seg() */
+static void tss_load_seg(int seg_reg, int selector)
+{
+    uint32_t e1, e2;
+    int rpl, dpl, cpl;
+
+    if ((selector & 0xfffc) != 0) {
+        if (load_segment(&e1, &e2, selector) != 0)
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        if (!(e2 & DESC_S_MASK))
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        rpl = selector & 3;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        cpl = env->hflags & HF_CPL_MASK;
+        if (seg_reg == R_CS) {
+            if (!(e2 & DESC_CS_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            /* XXX: is it correct ? */
+            if (dpl != rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            if ((e2 & DESC_C_MASK) && dpl > rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        } else if (seg_reg == R_SS) {
+            /* SS must be writable data */
+            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            if (dpl != cpl || dpl != rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        } else {
+            /* not readable code */
+            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            /* if data or non conforming code, checks the rights */
+            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
+                if (dpl < cpl || dpl < rpl)
+                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            }
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+    } else {
+        if (seg_reg == R_SS || seg_reg == R_CS)
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+    }
+}
+
+#define SWITCH_TSS_JMP  0
+#define SWITCH_TSS_IRET 1
+#define SWITCH_TSS_CALL 2
+
+/* XXX: restore CPU state in registers (PowerPC case) */
+static void switch_tss(int tss_selector,
+                       uint32_t e1, uint32_t e2, int source,
+                       uint32_t next_eip)
+{
+    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
+    target_ulong tss_base;
+    uint32_t new_regs[8], new_segs[6];
+    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
+    uint32_t old_eflags, eflags_mask;
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+    LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
+
+    /* if task gate, we read the TSS segment and we load it */
+    if (type == 5) {
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
+        tss_selector = e1 >> 16;
+        if (tss_selector & 4)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        if (load_segment(&e1, &e2, tss_selector) != 0)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+        if (e2 & DESC_S_MASK)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        if ((type & 7) != 1)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+    }
+
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
+
+    if (type & 8)
+        tss_limit_max = 103;
+    else
+        tss_limit_max = 43;
+    tss_limit = get_seg_limit(e1, e2);
+    tss_base = get_seg_base(e1, e2);
+    if ((tss_selector & 4) != 0 ||
+        tss_limit < tss_limit_max)
+        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+    if (old_type & 8)
+        old_tss_limit_max = 103;
+    else
+        old_tss_limit_max = 43;
+
+    /* read all the registers from the new TSS */
+    if (type & 8) {
+        /* 32 bit */
+        new_cr3 = ldl_kernel(tss_base + 0x1c);
+        new_eip = ldl_kernel(tss_base + 0x20);
+        new_eflags = ldl_kernel(tss_base + 0x24);
+        for(i = 0; i < 8; i++)
+            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
+        for(i = 0; i < 6; i++)
+            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
+        new_ldt = lduw_kernel(tss_base + 0x60);
+        new_trap = ldl_kernel(tss_base + 0x64);
+    } else {
+        /* 16 bit */
+        new_cr3 = 0;
+        new_eip = lduw_kernel(tss_base + 0x0e);
+        new_eflags = lduw_kernel(tss_base + 0x10);
+        for(i = 0; i < 8; i++)
+            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
+        for(i = 0; i < 4; i++)
+            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
+        new_ldt = lduw_kernel(tss_base + 0x2a);
+        new_segs[R_FS] = 0;
+        new_segs[R_GS] = 0;
+        new_trap = 0;
+    }
+    /* XXX: avoid a compiler warning, see
+     http://support.amd.com/us/Processor_TechDocs/24593.pdf
+     chapters 12.2.5 and 13.2.4 on how to implement TSS Trap bit */
+    (void)new_trap;
+
+    /* NOTE: we must avoid memory exceptions during the task switch,
+       so we make dummy accesses before */
+    /* XXX: it can still fail in some cases, so a bigger hack is
+       necessary to valid the TLB after having done the accesses */
+
+    v1 = ldub_kernel(env->tr.base);
+    v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
+    stb_kernel(env->tr.base, v1);
+    stb_kernel(env->tr.base + old_tss_limit_max, v2);
+
+    /* clear busy bit (it is restartable) */
+    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
+        target_ulong ptr;
+        uint32_t e2;
+        ptr = env->gdt.base + (env->tr.selector & ~7);
+        e2 = ldl_kernel(ptr + 4);
+        e2 &= ~DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+    old_eflags = compute_eflags();
+    if (source == SWITCH_TSS_IRET)
+        old_eflags &= ~NT_MASK;
+
+    /* save the current state in the old TSS */
+    if (type & 8) {
+        /* 32 bit */
+        stl_kernel(env->tr.base + 0x20, next_eip);
+        stl_kernel(env->tr.base + 0x24, old_eflags);
+        stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
+        stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
+        stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
+        stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
+        stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
+        stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
+        stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
+        stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
+        for(i = 0; i < 6; i++)
+            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
+    } else {
+        /* 16 bit */
+        stw_kernel(env->tr.base + 0x0e, next_eip);
+        stw_kernel(env->tr.base + 0x10, old_eflags);
+        stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
+        stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
+        stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
+        stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
+        stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
+        stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
+        stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
+        stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
+        for(i = 0; i < 4; i++)
+            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
+    }
+
+    /* now if an exception occurs, it will occurs in the next task
+       context */
+
+    if (source == SWITCH_TSS_CALL) {
+        stw_kernel(tss_base, env->tr.selector);
+        new_eflags |= NT_MASK;
+    }
+
+    /* set busy bit */
+    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
+        target_ulong ptr;
+        uint32_t e2;
+        ptr = env->gdt.base + (tss_selector & ~7);
+        e2 = ldl_kernel(ptr + 4);
+        e2 |= DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+
+    /* set the new CPU state */
+    /* from this point, any exception which occurs can give problems */
+    env->cr[0] |= CR0_TS_MASK;
+    env->hflags |= HF_TS_MASK;
+    env->tr.selector = tss_selector;
+    env->tr.base = tss_base;
+    env->tr.limit = tss_limit;
+    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
+
+    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
+        cpu_x86_update_cr3(env, new_cr3);
+    }
+
+    /* load all registers without an exception, then reload them with
+       possible exception */
+    env->eip = new_eip;
+    eflags_mask = TF_MASK | AC_MASK | ID_MASK |
+        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
+    if (!(type & 8))
+        eflags_mask &= 0xffff;
+    load_eflags(new_eflags, eflags_mask);
+    /* XXX: what to do in 16 bit case ? */
+    EAX = new_regs[0];
+    ECX = new_regs[1];
+    EDX = new_regs[2];
+    EBX = new_regs[3];
+    ESP = new_regs[4];
+    EBP = new_regs[5];
+    ESI = new_regs[6];
+    EDI = new_regs[7];
+    if (new_eflags & VM_MASK) {
+        for(i = 0; i < 6; i++)
+            load_seg_vm(i, new_segs[i]);
+        /* in vm86, CPL is always 3 */
+        cpu_x86_set_cpl(env, 3);
+    } else {
+        /* CPL is set the RPL of CS */
+        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
+        /* first just selectors as the rest may trigger exceptions */
+        for(i = 0; i < 6; i++)
+            cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
+    }
+
+    env->ldt.selector = new_ldt & ~4;
+    env->ldt.base = 0;
+    env->ldt.limit = 0;
+    env->ldt.flags = 0;
+
+    /* load the LDT */
+    if (new_ldt & 4)
+        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+
+    if ((new_ldt & 0xfffc) != 0) {
+        dt = &env->gdt;
+        index = new_ldt & ~7;
+        if ((index + 7) > dt->limit)
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        load_seg_cache_raw_dt(&env->ldt, e1, e2);
+    }
+
+    /* load the segments */
+    if (!(new_eflags & VM_MASK)) {
+        tss_load_seg(R_CS, new_segs[R_CS]);
+        tss_load_seg(R_SS, new_segs[R_SS]);
+        tss_load_seg(R_ES, new_segs[R_ES]);
+        tss_load_seg(R_DS, new_segs[R_DS]);
+        tss_load_seg(R_FS, new_segs[R_FS]);
+        tss_load_seg(R_GS, new_segs[R_GS]);
+    }
+
+    /* check that EIP is in the CS segment limits */
+    if (new_eip > env->segs[R_CS].limit) {
+        /* XXX: different exception if CALL ? */
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+
+#ifndef CONFIG_USER_ONLY
+    /* reset local breakpoints */
+    if (env->dr[7] & 0x55) {
+        for (i = 0; i < 4; i++) {
+            if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
+                hw_breakpoint_remove(env, i);
+        }
+        env->dr[7] &= ~0x55;
+    }
+#endif
+}
+
+/* check if Port I/O is allowed in TSS */
+static inline void check_io(int addr, int size)
+{
+    int io_offset, val, mask;
+
+    /* TSS must be a valid 32 bit one */
+    if (!(env->tr.flags & DESC_P_MASK) ||
+        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+        env->tr.limit < 103)
+        goto fail;
+    io_offset = lduw_kernel(env->tr.base + 0x66);
+    io_offset += (addr >> 3);
+    /* Note: the check needs two bytes */
+    if ((io_offset + 1) > env->tr.limit)
+        goto fail;
+    val = lduw_kernel(env->tr.base + io_offset);
+    val >>= (addr & 7);
+    mask = (1 << size) - 1;
+    /* all bits must be zero to allow the I/O */
+    if ((val & mask) != 0) {
+    fail:
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+}
+
+void helper_check_iob(uint32_t t0)
+{
+    check_io(t0, 1);
+}
+
+void helper_check_iow(uint32_t t0)
+{
+    check_io(t0, 2);
+}
+
+void helper_check_iol(uint32_t t0)
+{
+    check_io(t0, 4);
+}
+
+void helper_outb(uint32_t port, uint32_t data)
+{
+    cpu_outb(port, data & 0xff);
+}
+
+target_ulong helper_inb(uint32_t port)
+{
+    return cpu_inb(port);
+}
+
+void helper_outw(uint32_t port, uint32_t data)
+{
+    cpu_outw(port, data & 0xffff);
+}
+
+target_ulong helper_inw(uint32_t port)
+{
+    return cpu_inw(port);
+}
+
+void helper_outl(uint32_t port, uint32_t data)
+{
+    cpu_outl(port, data);
+}
+
+target_ulong helper_inl(uint32_t port)
+{
+    return cpu_inl(port);
+}
+
+static inline unsigned int get_sp_mask(unsigned int e2)
+{
+    if (e2 & DESC_B_MASK)
+        return 0xffffffff;
+    else
+        return 0xffff;
+}
+
+static int exeption_has_error_code(int intno)
+{
+        switch(intno) {
+        case 8:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 17:
+            return 1;
+        }
+       return 0;
+}
+
+#ifdef TARGET_X86_64
+#define SET_ESP(val, sp_mask)\
+do {\
+    if ((sp_mask) == 0xffff)\
+        ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
+    else if ((sp_mask) == 0xffffffffLL)\
+        ESP = (uint32_t)(val);\
+    else\
+        ESP = (val);\
+} while (0)
+#else
+#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
+#endif
+
+/* in 64-bit machines, this can overflow. So this segment addition macro
+ * can be used to trim the value to 32-bit whenever needed */
+#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
+
+/* XXX: add a is_user flag to have proper security support */
+#define PUSHW(ssp, sp, sp_mask, val)\
+{\
+    sp -= 2;\
+    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
+}
+
+#define PUSHL(ssp, sp, sp_mask, val)\
+{\
+    sp -= 4;\
+    stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
+}
+
+#define POPW(ssp, sp, sp_mask, val)\
+{\
+    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
+    sp += 2;\
+}
+
+#define POPL(ssp, sp, sp_mask, val)\
+{\
+    val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
+    sp += 4;\
+}
+
+/* protected mode interrupt */
+static void do_interrupt_protected(int intno, int is_int, int error_code,
+                                   unsigned int next_eip, int is_hw)
+{
+    SegmentCache *dt;
+    target_ulong ptr, ssp;
+    int type, dpl, selector, ss_dpl, cpl;
+    int has_error_code, new_stack, shift;
+    uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
+    uint32_t old_eip, sp_mask;
+
+    has_error_code = 0;
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+
+    dt = &env->idt;
+    if (intno * 8 + 7 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    ptr = dt->base + intno * 8;
+    e1 = ldl_kernel(ptr);
+    e2 = ldl_kernel(ptr + 4);
+    /* check gate type */
+    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+    switch(type) {
+    case 5: /* task gate */
+        /* must do that check here to return the correct error code */
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
+        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
+        if (has_error_code) {
+            int type;
+            uint32_t mask;
+            /* push the error code */
+            type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+            shift = type >> 3;
+            if (env->segs[R_SS].flags & DESC_B_MASK)
+                mask = 0xffffffff;
+            else
+                mask = 0xffff;
+            esp = (ESP - (2 << shift)) & mask;
+            ssp = env->segs[R_SS].base + esp;
+            if (shift)
+                stl_kernel(ssp, error_code);
+            else
+                stw_kernel(ssp, error_code);
+            SET_ESP(esp, mask);
+        }
+        return;
+    case 6: /* 286 interrupt gate */
+    case 7: /* 286 trap gate */
+    case 14: /* 386 interrupt gate */
+    case 15: /* 386 trap gate */
+        break;
+    default:
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+        break;
+    }
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    /* check valid bit */
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
+    selector = e1 >> 16;
+    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+    if ((selector & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+
+    if (load_segment(&e1, &e2, selector) != 0)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (dpl > cpl)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+        /* to inner privilege */
+        get_ss_esp_from_tss(&ss, &esp, dpl);
+        if ((ss & 0xfffc) == 0)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if ((ss & 3) != dpl)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+        if (ss_dpl != dpl)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (!(ss_e2 & DESC_S_MASK) ||
+            (ss_e2 & DESC_CS_MASK) ||
+            !(ss_e2 & DESC_W_MASK))
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (!(ss_e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        new_stack = 1;
+        sp_mask = get_sp_mask(ss_e2);
+        ssp = get_seg_base(ss_e1, ss_e2);
+    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
+        /* to same privilege */
+        if (env->eflags & VM_MASK)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0;
+        sp_mask = get_sp_mask(env->segs[R_SS].flags);
+        ssp = env->segs[R_SS].base;
+        esp = ESP;
+        dpl = cpl;
+    } else {
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0; /* avoid warning */
+        sp_mask = 0; /* avoid warning */
+        ssp = 0; /* avoid warning */
+        esp = 0; /* avoid warning */
+    }
+
+    shift = type >> 3;
+
+#if 0
+    /* XXX: check that enough room is available */
+    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
+    if (env->eflags & VM_MASK)
+        push_size += 8;
+    push_size <<= shift;
+#endif
+    if (shift == 1) {
+        if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
+            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
+            PUSHL(ssp, esp, sp_mask, ESP);
+        }
+        PUSHL(ssp, esp, sp_mask, compute_eflags());
+        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
+        PUSHL(ssp, esp, sp_mask, old_eip);
+        if (has_error_code) {
+            PUSHL(ssp, esp, sp_mask, error_code);
+        }
+    } else {
+        if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
+            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
+            PUSHW(ssp, esp, sp_mask, ESP);
+        }
+        PUSHW(ssp, esp, sp_mask, compute_eflags());
+        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
+        PUSHW(ssp, esp, sp_mask, old_eip);
+        if (has_error_code) {
+            PUSHW(ssp, esp, sp_mask, error_code);
+        }
+    }
+
+    if (new_stack) {
+        if (env->eflags & VM_MASK) {
+            cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
+        }
+        ss = (ss & ~3) | dpl;
+        cpu_x86_load_seg_cache(env, R_SS, ss,
+                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
+    }
+    SET_ESP(esp, sp_mask);
+
+    selector = (selector & ~3) | dpl;
+    cpu_x86_load_seg_cache(env, R_CS, selector,
+                   get_seg_base(e1, e2),
+                   get_seg_limit(e1, e2),
+                   e2);
+    cpu_x86_set_cpl(env, dpl);
+    env->eip = offset;
+
+    /* interrupt gate clear IF mask */
+    if ((type & 1) == 0) {
+        env->eflags &= ~IF_MASK;
+    }
+    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+}
+
+#ifdef TARGET_X86_64
+
+#define PUSHQ(sp, val)\
+{\
+    sp -= 8;\
+    stq_kernel(sp, (val));\
+}
+
+#define POPQ(sp, val)\
+{\
+    val = ldq_kernel(sp);\
+    sp += 8;\
+}
+
+static inline target_ulong get_rsp_from_tss(int level)
+{
+    int index;
+
+#if 0
+    printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
+           env->tr.base, env->tr.limit);
+#endif
+
+    if (!(env->tr.flags & DESC_P_MASK))
+        cpu_abort(env, "invalid tss");
+    index = 8 * level + 4;
+    if ((index + 7) > env->tr.limit)
+        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
+    return ldq_kernel(env->tr.base + index);
+}
+
+/* 64 bit interrupt */
+static void do_interrupt64(int intno, int is_int, int error_code,
+                           target_ulong next_eip, int is_hw)
+{
+    SegmentCache *dt;
+    target_ulong ptr;
+    int type, dpl, selector, cpl, ist;
+    int has_error_code, new_stack;
+    uint32_t e1, e2, e3, ss;
+    target_ulong old_eip, esp, offset;
+
+    has_error_code = 0;
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+
+    dt = &env->idt;
+    if (intno * 16 + 15 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+    ptr = dt->base + intno * 16;
+    e1 = ldl_kernel(ptr);
+    e2 = ldl_kernel(ptr + 4);
+    e3 = ldl_kernel(ptr + 8);
+    /* check gate type */
+    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+    switch(type) {
+    case 14: /* 386 interrupt gate */
+    case 15: /* 386 trap gate */
+        break;
+    default:
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+        break;
+    }
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+    /* check valid bit */
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
+    selector = e1 >> 16;
+    offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+    ist = e2 & 7;
+    if ((selector & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+
+    if (load_segment(&e1, &e2, selector) != 0)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (dpl > cpl)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+    if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
+        /* to inner privilege */
+        if (ist != 0)
+            esp = get_rsp_from_tss(ist + 3);
+        else
+            esp = get_rsp_from_tss(dpl);
+        esp &= ~0xfLL; /* align stack */
+        ss = 0;
+        new_stack = 1;
+    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
+        /* to same privilege */
+        if (env->eflags & VM_MASK)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0;
+        if (ist != 0)
+            esp = get_rsp_from_tss(ist + 3);
+        else
+            esp = ESP;
+        esp &= ~0xfLL; /* align stack */
+        dpl = cpl;
+    } else {
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0; /* avoid warning */
+        esp = 0; /* avoid warning */
+    }
+
+    PUSHQ(esp, env->segs[R_SS].selector);
+    PUSHQ(esp, ESP);
+    PUSHQ(esp, compute_eflags());
+    PUSHQ(esp, env->segs[R_CS].selector);
+    PUSHQ(esp, old_eip);
+    if (has_error_code) {
+        PUSHQ(esp, error_code);
+    }
+
+    if (new_stack) {
+        ss = 0 | dpl;
+        cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
+    }
+    ESP = esp;
+
+    selector = (selector & ~3) | dpl;
+    cpu_x86_load_seg_cache(env, R_CS, selector,
+                   get_seg_base(e1, e2),
+                   get_seg_limit(e1, e2),
+                   e2);
+    cpu_x86_set_cpl(env, dpl);
+    env->eip = offset;
+
+    /* interrupt gate clear IF mask */
+    if ((type & 1) == 0) {
+        env->eflags &= ~IF_MASK;
+    }
+    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+}
+#endif
+
+#ifdef TARGET_X86_64
+#if defined(CONFIG_USER_ONLY)
+void helper_syscall(int next_eip_addend)
+{
+    env->exception_index = EXCP_SYSCALL;
+    env->exception_next_eip = env->eip + next_eip_addend;
+    cpu_loop_exit(env);
+}
+#else
+void helper_syscall(int next_eip_addend)
+{
+    int selector;
+
+    if (!(env->efer & MSR_EFER_SCE)) {
+        raise_exception_err(EXCP06_ILLOP, 0);
+    }
+    selector = (env->star >> 32) & 0xffff;
+    if (env->hflags & HF_LMA_MASK) {
+        int code64;
+
+        ECX = env->eip + next_eip_addend;
+        env->regs[11] = compute_eflags();
+
+        code64 = env->hflags & HF_CS64_MASK;
+
+        cpu_x86_set_cpl(env, 0);
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
+                               DESC_G_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags &= ~env->fmask;
+        load_eflags(env->eflags, 0);
+        if (code64)
+            env->eip = env->lstar;
+        else
+            env->eip = env->cstar;
+    } else {
+        ECX = (uint32_t)(env->eip + next_eip_addend);
+
+        cpu_x86_set_cpl(env, 0);
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
+        env->eip = (uint32_t)env->star;
+    }
+}
+#endif
+#endif
+
+#ifdef TARGET_X86_64
+void helper_sysret(int dflag)
+{
+    int cpl, selector;
+
+    if (!(env->efer & MSR_EFER_SCE)) {
+        raise_exception_err(EXCP06_ILLOP, 0);
+    }
+    cpl = env->hflags & HF_CPL_MASK;
+    if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    selector = (env->star >> 48) & 0xffff;
+    if (env->hflags & HF_LMA_MASK) {
+        if (dflag == 2) {
+            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
+                                   0, 0xffffffff,
+                                   DESC_G_MASK | DESC_P_MASK |
+                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
+                                   DESC_L_MASK);
+            env->eip = ECX;
+        } else {
+            cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                                   0, 0xffffffff,
+                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+            env->eip = (uint32_t)ECX;
+        }
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
+                    IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
+        cpu_x86_set_cpl(env, 3);
+    } else {
+        cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        env->eip = (uint32_t)ECX;
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags |= IF_MASK;
+        cpu_x86_set_cpl(env, 3);
+    }
+}
+#endif
+
+/* real mode interrupt */
+static void do_interrupt_real(int intno, int is_int, int error_code,
+                              unsigned int next_eip)
+{
+    SegmentCache *dt;
+    target_ulong ptr, ssp;
+    int selector;
+    uint32_t offset, esp;
+    uint32_t old_cs, old_eip;
+
+    /* real mode (simpler !) */
+    dt = &env->idt;
+    if (intno * 4 + 3 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    ptr = dt->base + intno * 4;
+    offset = lduw_kernel(ptr);
+    selector = lduw_kernel(ptr + 2);
+    esp = ESP;
+    ssp = env->segs[R_SS].base;
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+    old_cs = env->segs[R_CS].selector;
+    /* XXX: use SS segment size ? */
+    PUSHW(ssp, esp, 0xffff, compute_eflags());
+    PUSHW(ssp, esp, 0xffff, old_cs);
+    PUSHW(ssp, esp, 0xffff, old_eip);
+
+    /* update processor state */
+    ESP = (ESP & ~0xffff) | (esp & 0xffff);
+    env->eip = offset;
+    env->segs[R_CS].selector = selector;
+    env->segs[R_CS].base = (selector << 4);
+    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
+}
+
+#if defined(CONFIG_USER_ONLY)
+/* fake user mode interrupt */
+static void do_interrupt_user(int intno, int is_int, int error_code,
+                              target_ulong next_eip)
+{
+    SegmentCache *dt;
+    target_ulong ptr;
+    int dpl, cpl, shift;
+    uint32_t e2;
+
+    dt = &env->idt;
+    if (env->hflags & HF_LMA_MASK) {
+        shift = 4;
+    } else {
+        shift = 3;
+    }
+    ptr = dt->base + (intno << shift);
+    e2 = ldl_kernel(ptr + 4);
+
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
+
+    /* Since we emulate only user space, we cannot do more than
+       exiting the emulation with the suitable exception and error
+       code */
+    if (is_int)
+        EIP = next_eip;
+}
+
+#else
+
+static void handle_even_inj(int intno, int is_int, int error_code,
+               int is_hw, int rm)
+{
+    uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (!(event_inj & SVM_EVTINJ_VALID)) {
+           int type;
+           if (is_int)
+                   type = SVM_EVTINJ_TYPE_SOFT;
+           else
+                   type = SVM_EVTINJ_TYPE_EXEPT;
+           event_inj = intno | type | SVM_EVTINJ_VALID;
+           if (!rm && exeption_has_error_code(intno)) {
+                   event_inj |= SVM_EVTINJ_VALID_ERR;
+                   stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
+           }
+           stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
+    }
+}
+#endif
+
+/*
+ * Begin execution of an interruption. is_int is TRUE if coming from
+ * the int instruction. next_eip is the EIP value AFTER the interrupt
+ * instruction. It is only relevant if is_int is TRUE.
+ */
+static void do_interrupt_all(int intno, int is_int, int error_code,
+                             target_ulong next_eip, int is_hw)
+{
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        if ((env->cr[0] & CR0_PE_MASK)) {
+            static int count;
+            qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
+                    count, intno, error_code, is_int,
+                    env->hflags & HF_CPL_MASK,
+                    env->segs[R_CS].selector, EIP,
+                    (int)env->segs[R_CS].base + EIP,
+                    env->segs[R_SS].selector, ESP);
+            if (intno == 0x0e) {
+                qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
+            } else {
+                qemu_log(" EAX=" TARGET_FMT_lx, EAX);
+            }
+            qemu_log("\n");
+            log_cpu_state(env, X86_DUMP_CCOP);
+#if 0
+            {
+                int i;
+                target_ulong ptr;
+                qemu_log("       code=");
+                ptr = env->segs[R_CS].base + env->eip;
+                for(i = 0; i < 16; i++) {
+                    qemu_log(" %02x", ldub(ptr + i));
+                }
+                qemu_log("\n");
+            }
+#endif
+            count++;
+        }
+    }
+    if (env->cr[0] & CR0_PE_MASK) {
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 0);
+#endif
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
+        } else
+#endif
+        {
+            do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
+        }
+    } else {
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 1);
+#endif
+        do_interrupt_real(intno, is_int, error_code, next_eip);
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    if (env->hflags & HF_SVMI_MASK) {
+           uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+           stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
+    }
+#endif
+}
+
+void do_interrupt(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+#if defined(CONFIG_USER_ONLY)
+    /* if user mode only, we simulate a fake exception
+       which will be handled outside the cpu execution
+       loop */
+    do_interrupt_user(env->exception_index,
+                      env->exception_is_int,
+                      env->error_code,
+                      env->exception_next_eip);
+    /* successfully delivered */
+    env->old_exception = -1;
+#else
+    /* simulate a real cpu exception. On i386, it can
+       trigger new exceptions, but we do not handle
+       double or triple faults yet. */
+    do_interrupt_all(env->exception_index,
+                     env->exception_is_int,
+                     env->error_code,
+                     env->exception_next_eip, 0);
+    /* successfully delivered */
+    env->old_exception = -1;
+#endif
+    env = saved_env;
+}
+
+void do_interrupt_x86_hardirq(CPUState *env1, int intno, int is_hw)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(intno, 0, 0, 0, is_hw);
+    env = saved_env;
+}
+
+/* This should come from sysemu.h - if we could include it here... */
+void qemu_system_reset_request(void);
+
+/*
+ * Check nested exceptions and change to double or triple fault if
+ * needed. It should only be called, if this is not an interrupt.
+ * Returns the new exception number.
+ */
+static int check_exception(int intno, int *error_code)
+{
+    int first_contributory = env->old_exception == 0 ||
+                              (env->old_exception >= 10 &&
+                               env->old_exception <= 13);
+    int second_contributory = intno == 0 ||
+                               (intno >= 10 && intno <= 13);
+
+    qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
+                env->old_exception, intno);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (env->old_exception == EXCP08_DBLE) {
+        if (env->hflags & HF_SVMI_MASK)
+            helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
+
+        qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
+
+        qemu_system_reset_request();
+        return EXCP_HLT;
+    }
+#endif
+
+    if ((first_contributory && second_contributory)
+        || (env->old_exception == EXCP0E_PAGE &&
+            (second_contributory || (intno == EXCP0E_PAGE)))) {
+        intno = EXCP08_DBLE;
+        *error_code = 0;
+    }
+
+    if (second_contributory || (intno == EXCP0E_PAGE) ||
+        (intno == EXCP08_DBLE))
+        env->old_exception = intno;
+
+    return intno;
+}
+
+/*
+ * Signal an interruption. It is executed in the main CPU loop.
+ * is_int is TRUE if coming from the int instruction. next_eip is the
+ * EIP value AFTER the interrupt instruction. It is only relevant if
+ * is_int is TRUE.
+ */
+static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
+                                          int next_eip_addend)
+{
+    if (!is_int) {
+        helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
+        intno = check_exception(intno, &error_code);
+    } else {
+        helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
+    }
+
+    env->exception_index = intno;
+    env->error_code = error_code;
+    env->exception_is_int = is_int;
+    env->exception_next_eip = env->eip + next_eip_addend;
+    cpu_loop_exit(env);
+}
+
+/* shortcuts to generate exceptions */
+
+static void QEMU_NORETURN raise_exception_err(int exception_index,
+                                              int error_code)
+{
+    raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+void raise_exception_err_env(CPUState *nenv, int exception_index,
+                             int error_code)
+{
+    env = nenv;
+    raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+static void QEMU_NORETURN raise_exception(int exception_index)
+{
+    raise_interrupt(exception_index, 0, 0, 0);
+}
+
+void raise_exception_env(int exception_index, CPUState *nenv)
+{
+    env = nenv;
+    raise_exception(exception_index);
+}
+/* SMM support */
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_smm_enter(CPUState *env1)
+{
+}
+
+void helper_rsm(void)
+{
+}
+
+#else
+
+#ifdef TARGET_X86_64
+#define SMM_REVISION_ID 0x00020064
+#else
+#define SMM_REVISION_ID 0x00020000
+#endif
+
+void do_smm_enter(CPUState *env1)
+{
+    target_ulong sm_state;
+    SegmentCache *dt;
+    int i, offset;
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+
+    qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
+
+    env->hflags |= HF_SMM_MASK;
+    cpu_smm_update(env);
+
+    sm_state = env->smbase + 0x8000;
+
+#ifdef TARGET_X86_64
+    for(i = 0; i < 6; i++) {
+        dt = &env->segs[i];
+        offset = 0x7e00 + i * 16;
+        stw_phys(sm_state + offset, dt->selector);
+        stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
+        stl_phys(sm_state + offset + 4, dt->limit);
+        stq_phys(sm_state + offset + 8, dt->base);
+    }
+
+    stq_phys(sm_state + 0x7e68, env->gdt.base);
+    stl_phys(sm_state + 0x7e64, env->gdt.limit);
+
+    stw_phys(sm_state + 0x7e70, env->ldt.selector);
+    stq_phys(sm_state + 0x7e78, env->ldt.base);
+    stl_phys(sm_state + 0x7e74, env->ldt.limit);
+    stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
+
+    stq_phys(sm_state + 0x7e88, env->idt.base);
+    stl_phys(sm_state + 0x7e84, env->idt.limit);
+
+    stw_phys(sm_state + 0x7e90, env->tr.selector);
+    stq_phys(sm_state + 0x7e98, env->tr.base);
+    stl_phys(sm_state + 0x7e94, env->tr.limit);
+    stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
+
+    stq_phys(sm_state + 0x7ed0, env->efer);
+
+    stq_phys(sm_state + 0x7ff8, EAX);
+    stq_phys(sm_state + 0x7ff0, ECX);
+    stq_phys(sm_state + 0x7fe8, EDX);
+    stq_phys(sm_state + 0x7fe0, EBX);
+    stq_phys(sm_state + 0x7fd8, ESP);
+    stq_phys(sm_state + 0x7fd0, EBP);
+    stq_phys(sm_state + 0x7fc8, ESI);
+    stq_phys(sm_state + 0x7fc0, EDI);
+    for(i = 8; i < 16; i++)
+        stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
+    stq_phys(sm_state + 0x7f78, env->eip);
+    stl_phys(sm_state + 0x7f70, compute_eflags());
+    stl_phys(sm_state + 0x7f68, env->dr[6]);
+    stl_phys(sm_state + 0x7f60, env->dr[7]);
+
+    stl_phys(sm_state + 0x7f48, env->cr[4]);
+    stl_phys(sm_state + 0x7f50, env->cr[3]);
+    stl_phys(sm_state + 0x7f58, env->cr[0]);
+
+    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
+    stl_phys(sm_state + 0x7f00, env->smbase);
+#else
+    stl_phys(sm_state + 0x7ffc, env->cr[0]);
+    stl_phys(sm_state + 0x7ff8, env->cr[3]);
+    stl_phys(sm_state + 0x7ff4, compute_eflags());
+    stl_phys(sm_state + 0x7ff0, env->eip);
+    stl_phys(sm_state + 0x7fec, EDI);
+    stl_phys(sm_state + 0x7fe8, ESI);
+    stl_phys(sm_state + 0x7fe4, EBP);
+    stl_phys(sm_state + 0x7fe0, ESP);
+    stl_phys(sm_state + 0x7fdc, EBX);
+    stl_phys(sm_state + 0x7fd8, EDX);
+    stl_phys(sm_state + 0x7fd4, ECX);
+    stl_phys(sm_state + 0x7fd0, EAX);
+    stl_phys(sm_state + 0x7fcc, env->dr[6]);
+    stl_phys(sm_state + 0x7fc8, env->dr[7]);
+
+    stl_phys(sm_state + 0x7fc4, env->tr.selector);
+    stl_phys(sm_state + 0x7f64, env->tr.base);
+    stl_phys(sm_state + 0x7f60, env->tr.limit);
+    stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
+
+    stl_phys(sm_state + 0x7fc0, env->ldt.selector);
+    stl_phys(sm_state + 0x7f80, env->ldt.base);
+    stl_phys(sm_state + 0x7f7c, env->ldt.limit);
+    stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
+
+    stl_phys(sm_state + 0x7f74, env->gdt.base);
+    stl_phys(sm_state + 0x7f70, env->gdt.limit);
+
+    stl_phys(sm_state + 0x7f58, env->idt.base);
+    stl_phys(sm_state + 0x7f54, env->idt.limit);
+
+    for(i = 0; i < 6; i++) {
+        dt = &env->segs[i];
+        if (i < 3)
+            offset = 0x7f84 + i * 12;
+        else
+            offset = 0x7f2c + (i - 3) * 12;
+        stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
+        stl_phys(sm_state + offset + 8, dt->base);
+        stl_phys(sm_state + offset + 4, dt->limit);
+        stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
+    }
+    stl_phys(sm_state + 0x7f14, env->cr[4]);
+
+    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
+    stl_phys(sm_state + 0x7ef8, env->smbase);
+#endif
+    /* init SMM cpu state */
+
+#ifdef TARGET_X86_64
+    cpu_load_efer(env, 0);
+#endif
+    load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->eip = 0x00008000;
+    cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
+                           0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
+
+    cpu_x86_update_cr0(env,
+                       env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
+    cpu_x86_update_cr4(env, 0);
+    env->dr[7] = 0x00000400;
+    CC_OP = CC_OP_EFLAGS;
+    env = saved_env;
+}
+
+void helper_rsm(void)
+{
+    target_ulong sm_state;
+    int i, offset;
+    uint32_t val;
+
+    sm_state = env->smbase + 0x8000;
+#ifdef TARGET_X86_64
+    cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
+
+    for(i = 0; i < 6; i++) {
+        offset = 0x7e00 + i * 16;
+        cpu_x86_load_seg_cache(env, i,
+                               lduw_phys(sm_state + offset),
+                               ldq_phys(sm_state + offset + 8),
+                               ldl_phys(sm_state + offset + 4),
+                               (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
+    }
+
+    env->gdt.base = ldq_phys(sm_state + 0x7e68);
+    env->gdt.limit = ldl_phys(sm_state + 0x7e64);
+
+    env->ldt.selector = lduw_phys(sm_state + 0x7e70);
+    env->ldt.base = ldq_phys(sm_state + 0x7e78);
+    env->ldt.limit = ldl_phys(sm_state + 0x7e74);
+    env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
+
+    env->idt.base = ldq_phys(sm_state + 0x7e88);
+    env->idt.limit = ldl_phys(sm_state + 0x7e84);
+
+    env->tr.selector = lduw_phys(sm_state + 0x7e90);
+    env->tr.base = ldq_phys(sm_state + 0x7e98);
+    env->tr.limit = ldl_phys(sm_state + 0x7e94);
+    env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
+
+    EAX = ldq_phys(sm_state + 0x7ff8);
+    ECX = ldq_phys(sm_state + 0x7ff0);
+    EDX = ldq_phys(sm_state + 0x7fe8);
+    EBX = ldq_phys(sm_state + 0x7fe0);
+    ESP = ldq_phys(sm_state + 0x7fd8);
+    EBP = ldq_phys(sm_state + 0x7fd0);
+    ESI = ldq_phys(sm_state + 0x7fc8);
+    EDI = ldq_phys(sm_state + 0x7fc0);
+    for(i = 8; i < 16; i++)
+        env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
+    env->eip = ldq_phys(sm_state + 0x7f78);
+    load_eflags(ldl_phys(sm_state + 0x7f70),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->dr[6] = ldl_phys(sm_state + 0x7f68);
+    env->dr[7] = ldl_phys(sm_state + 0x7f60);
+
+    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
+    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
+    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
+
+    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
+    if (val & 0x20000) {
+        env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
+    }
+#else
+    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
+    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
+    load_eflags(ldl_phys(sm_state + 0x7ff4),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->eip = ldl_phys(sm_state + 0x7ff0);
+    EDI = ldl_phys(sm_state + 0x7fec);
+    ESI = ldl_phys(sm_state + 0x7fe8);
+    EBP = ldl_phys(sm_state + 0x7fe4);
+    ESP = ldl_phys(sm_state + 0x7fe0);
+    EBX = ldl_phys(sm_state + 0x7fdc);
+    EDX = ldl_phys(sm_state + 0x7fd8);
+    ECX = ldl_phys(sm_state + 0x7fd4);
+    EAX = ldl_phys(sm_state + 0x7fd0);
+    env->dr[6] = ldl_phys(sm_state + 0x7fcc);
+    env->dr[7] = ldl_phys(sm_state + 0x7fc8);
+
+    env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
+    env->tr.base = ldl_phys(sm_state + 0x7f64);
+    env->tr.limit = ldl_phys(sm_state + 0x7f60);
+    env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
+
+    env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
+    env->ldt.base = ldl_phys(sm_state + 0x7f80);
+    env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
+    env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
+
+    env->gdt.base = ldl_phys(sm_state + 0x7f74);
+    env->gdt.limit = ldl_phys(sm_state + 0x7f70);
+
+    env->idt.base = ldl_phys(sm_state + 0x7f58);
+    env->idt.limit = ldl_phys(sm_state + 0x7f54);
+
+    for(i = 0; i < 6; i++) {
+        if (i < 3)
+            offset = 0x7f84 + i * 12;
+        else
+            offset = 0x7f2c + (i - 3) * 12;
+        cpu_x86_load_seg_cache(env, i,
+                               ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
+                               ldl_phys(sm_state + offset + 8),
+                               ldl_phys(sm_state + offset + 4),
+                               (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
+    }
+    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
+
+    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
+    if (val & 0x20000) {
+        env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
+    }
+#endif
+    CC_OP = CC_OP_EFLAGS;
+    env->hflags &= ~HF_SMM_MASK;
+    cpu_smm_update(env);
+
+    qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+
+/* division, flags are undefined */
+
+void helper_divb_AL(target_ulong t0)
+{
+    unsigned int num, den, q, r;
+
+    num = (EAX & 0xffff);
+    den = (t0 & 0xff);
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q > 0xff)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xff;
+    r = (num % den) & 0xff;
+    EAX = (EAX & ~0xffff) | (r << 8) | q;
+}
+
+void helper_idivb_AL(target_ulong t0)
+{
+    int num, den, q, r;
+
+    num = (int16_t)EAX;
+    den = (int8_t)t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q != (int8_t)q)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xff;
+    r = (num % den) & 0xff;
+    EAX = (EAX & ~0xffff) | (r << 8) | q;
+}
+
+void helper_divw_AX(target_ulong t0)
+{
+    unsigned int num, den, q, r;
+
+    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+    den = (t0 & 0xffff);
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q > 0xffff)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xffff;
+    r = (num % den) & 0xffff;
+    EAX = (EAX & ~0xffff) | q;
+    EDX = (EDX & ~0xffff) | r;
+}
+
+void helper_idivw_AX(target_ulong t0)
+{
+    int num, den, q, r;
+
+    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+    den = (int16_t)t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q != (int16_t)q)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xffff;
+    r = (num % den) & 0xffff;
+    EAX = (EAX & ~0xffff) | q;
+    EDX = (EDX & ~0xffff) | r;
+}
+
+void helper_divl_EAX(target_ulong t0)
+{
+    unsigned int den, r;
+    uint64_t num, q;
+
+    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+    den = t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    r = (num % den);
+    if (q > 0xffffffff)
+        raise_exception(EXCP00_DIVZ);
+    EAX = (uint32_t)q;
+    EDX = (uint32_t)r;
+}
+
+void helper_idivl_EAX(target_ulong t0)
+{
+    int den, r;
+    int64_t num, q;
+
+    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+    den = t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    r = (num % den);
+    if (q != (int32_t)q)
+        raise_exception(EXCP00_DIVZ);
+    EAX = (uint32_t)q;
+    EDX = (uint32_t)r;
+}
+
+/* bcd */
+
+/* XXX: exception */
+void helper_aam(int base)
+{
+    int al, ah;
+    al = EAX & 0xff;
+    ah = al / base;
+    al = al % base;
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_DST = al;
+}
+
+void helper_aad(int base)
+{
+    int al, ah;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+    al = ((ah * base) + al) & 0xff;
+    EAX = (EAX & ~0xffff) | al;
+    CC_DST = al;
+}
+
+void helper_aaa(void)
+{
+    int icarry;
+    int al, ah, af;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+
+    icarry = (al > 0xf9);
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al + 6) & 0x0f;
+        ah = (ah + 1 + icarry) & 0xff;
+        eflags |= CC_C | CC_A;
+    } else {
+        eflags &= ~(CC_C | CC_A);
+        al &= 0x0f;
+    }
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_SRC = eflags;
+}
+
+void helper_aas(void)
+{
+    int icarry;
+    int al, ah, af;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+
+    icarry = (al < 6);
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al - 6) & 0x0f;
+        ah = (ah - 1 - icarry) & 0xff;
+        eflags |= CC_C | CC_A;
+    } else {
+        eflags &= ~(CC_C | CC_A);
+        al &= 0x0f;
+    }
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_SRC = eflags;
+}
+
+void helper_daa(void)
+{
+    int old_al, al, af, cf;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    cf = eflags & CC_C;
+    af = eflags & CC_A;
+    old_al = al = EAX & 0xff;
+
+    eflags = 0;
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al + 6) & 0xff;
+        eflags |= CC_A;
+    }
+    if ((old_al > 0x99) || cf) {
+        al = (al + 0x60) & 0xff;
+        eflags |= CC_C;
+    }
+    EAX = (EAX & ~0xff) | al;
+    /* well, speed is not an issue here, so we compute the flags by hand */
+    eflags |= (al == 0) << 6; /* zf */
+    eflags |= parity_table[al]; /* pf */
+    eflags |= (al & 0x80); /* sf */
+    CC_SRC = eflags;
+}
+
+void helper_das(void)
+{
+    int al, al1, af, cf;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    cf = eflags & CC_C;
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+
+    eflags = 0;
+    al1 = al;
+    if (((al & 0x0f) > 9 ) || af) {
+        eflags |= CC_A;
+        if (al < 6 || cf)
+            eflags |= CC_C;
+        al = (al - 6) & 0xff;
+    }
+    if ((al1 > 0x99) || cf) {
+        al = (al - 0x60) & 0xff;
+        eflags |= CC_C;
+    }
+    EAX = (EAX & ~0xff) | al;
+    /* well, speed is not an issue here, so we compute the flags by hand */
+    eflags |= (al == 0) << 6; /* zf */
+    eflags |= parity_table[al]; /* pf */
+    eflags |= (al & 0x80); /* sf */
+    CC_SRC = eflags;
+}
+
+void helper_into(int next_eip_addend)
+{
+    int eflags;
+    eflags = helper_cc_compute_all(CC_OP);
+    if (eflags & CC_O) {
+        raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
+    }
+}
+
+void helper_cmpxchg8b(target_ulong a0)
+{
+    uint64_t d;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    d = ldq(a0);
+    if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
+        stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
+        eflags |= CC_Z;
+    } else {
+        /* always do the store */
+        stq(a0, d); 
+        EDX = (uint32_t)(d >> 32);
+        EAX = (uint32_t)d;
+        eflags &= ~CC_Z;
+    }
+    CC_SRC = eflags;
+}
+
+#ifdef TARGET_X86_64
+void helper_cmpxchg16b(target_ulong a0)
+{
+    uint64_t d0, d1;
+    int eflags;
+
+    if ((a0 & 0xf) != 0)
+        raise_exception(EXCP0D_GPF);
+    eflags = helper_cc_compute_all(CC_OP);
+    d0 = ldq(a0);
+    d1 = ldq(a0 + 8);
+    if (d0 == EAX && d1 == EDX) {
+        stq(a0, EBX);
+        stq(a0 + 8, ECX);
+        eflags |= CC_Z;
+    } else {
+        /* always do the store */
+        stq(a0, d0); 
+        stq(a0 + 8, d1); 
+        EDX = d1;
+        EAX = d0;
+        eflags &= ~CC_Z;
+    }
+    CC_SRC = eflags;
+}
+#endif
+
+void helper_single_step(void)
+{
+#ifndef CONFIG_USER_ONLY
+    check_hw_breakpoints(env, 1);
+    env->dr[6] |= DR6_BS;
+#endif
+    raise_exception(EXCP01_DB);
+}
+
+void helper_cpuid(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+
+    helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
+
+    cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
+    EAX = eax;
+    EBX = ebx;
+    ECX = ecx;
+    EDX = edx;
+}
+
+void helper_enter_level(int level, int data32, target_ulong t1)
+{
+    target_ulong ssp;
+    uint32_t esp_mask, esp, ebp;
+
+    esp_mask = get_sp_mask(env->segs[R_SS].flags);
+    ssp = env->segs[R_SS].base;
+    ebp = EBP;
+    esp = ESP;
+    if (data32) {
+        /* 32 bit */
+        esp -= 4;
+        while (--level) {
+            esp -= 4;
+            ebp -= 4;
+            stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
+        }
+        esp -= 4;
+        stl(ssp + (esp & esp_mask), t1);
+    } else {
+        /* 16 bit */
+        esp -= 2;
+        while (--level) {
+            esp -= 2;
+            ebp -= 2;
+            stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
+        }
+        esp -= 2;
+        stw(ssp + (esp & esp_mask), t1);
+    }
+}
+
+#ifdef TARGET_X86_64
+void helper_enter64_level(int level, int data64, target_ulong t1)
+{
+    target_ulong esp, ebp;
+    ebp = EBP;
+    esp = ESP;
+
+    if (data64) {
+        /* 64 bit */
+        esp -= 8;
+        while (--level) {
+            esp -= 8;
+            ebp -= 8;
+            stq(esp, ldq(ebp));
+        }
+        esp -= 8;
+        stq(esp, t1);
+    } else {
+        /* 16 bit */
+        esp -= 2;
+        while (--level) {
+            esp -= 2;
+            ebp -= 2;
+            stw(esp, lduw(ebp));
+        }
+        esp -= 2;
+        stw(esp, t1);
+    }
+}
+#endif
+
+void helper_lldt(int selector)
+{
+    SegmentCache *dt;
+    uint32_t e1, e2;
+    int index, entry_limit;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    if ((selector & 0xfffc) == 0) {
+        /* XXX: NULL selector case: invalid LDT */
+        env->ldt.base = 0;
+        env->ldt.limit = 0;
+    } else {
+        if (selector & 0x4)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dt = &env->gdt;
+        index = selector & ~7;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            entry_limit = 15;
+        else
+#endif
+            entry_limit = 7;
+        if ((index + entry_limit) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint32_t e3;
+            e3 = ldl_kernel(ptr + 8);
+            load_seg_cache_raw_dt(&env->ldt, e1, e2);
+            env->ldt.base |= (target_ulong)e3 << 32;
+        } else
+#endif
+        {
+            load_seg_cache_raw_dt(&env->ldt, e1, e2);
+        }
+    }
+    env->ldt.selector = selector;
+}
+
+void helper_ltr(int selector)
+{
+    SegmentCache *dt;
+    uint32_t e1, e2;
+    int index, type, entry_limit;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    if ((selector & 0xfffc) == 0) {
+        /* NULL selector case: invalid TR */
+        env->tr.base = 0;
+        env->tr.limit = 0;
+        env->tr.flags = 0;
+    } else {
+        if (selector & 0x4)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dt = &env->gdt;
+        index = selector & ~7;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            entry_limit = 15;
+        else
+#endif
+            entry_limit = 7;
+        if ((index + entry_limit) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        if ((e2 & DESC_S_MASK) ||
+            (type != 1 && type != 9))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint32_t e3, e4;
+            e3 = ldl_kernel(ptr + 8);
+            e4 = ldl_kernel(ptr + 12);
+            if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            load_seg_cache_raw_dt(&env->tr, e1, e2);
+            env->tr.base |= (target_ulong)e3 << 32;
+        } else
+#endif
+        {
+            load_seg_cache_raw_dt(&env->tr, e1, e2);
+        }
+        e2 |= DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+    env->tr.selector = selector;
+}
+
+/* only works if protected mode and not VM86. seg_reg must be != R_CS */
+void helper_load_seg(int seg_reg, int selector)
+{
+    uint32_t e1, e2;
+    int cpl, dpl, rpl;
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    cpl = env->hflags & HF_CPL_MASK;
+    if ((selector & 0xfffc) == 0) {
+        /* null selector case */
+        if (seg_reg == R_SS
+#ifdef TARGET_X86_64
+            && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
+#endif
+            )
+            raise_exception_err(EXCP0D_GPF, 0);
+        cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
+    } else {
+
+        if (selector & 0x4)
+            dt = &env->ldt;
+        else
+            dt = &env->gdt;
+        index = selector & ~7;
+        if ((index + 7) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+
+        if (!(e2 & DESC_S_MASK))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        rpl = selector & 3;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (seg_reg == R_SS) {
+            /* must be writable segment */
+            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            if (rpl != cpl || dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        } else {
+            /* must be readable segment */
+            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+
+            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+                /* if not conforming code, test rights */
+                if (dpl < cpl || dpl < rpl)
+                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            }
+        }
+
+        if (!(e2 & DESC_P_MASK)) {
+            if (seg_reg == R_SS)
+                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
+            else
+                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+        }
+
+        /* set the access bit if not already set */
+        if (!(e2 & DESC_A_MASK)) {
+            e2 |= DESC_A_MASK;
+            stl_kernel(ptr + 4, e2);
+        }
+
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+#if 0
+        qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
+                selector, (unsigned long)sc->base, sc->limit, sc->flags);
+#endif
+    }
+}
+
+/* protected mode jump */
+void helper_ljmp_protected(int new_cs, target_ulong new_eip,
+                           int next_eip_addend)
+{
+    int gate_cs, type;
+    uint32_t e1, e2, cpl, dpl, rpl, limit;
+    target_ulong next_eip;
+
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if (!(e2 & DESC_CS_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (e2 & DESC_C_MASK) {
+            /* conforming code segment */
+            if (dpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        } else {
+            /* non conforming code segment */
+            rpl = new_cs & 3;
+            if (rpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+        limit = get_seg_limit(e1, e2);
+        if (new_eip > limit &&
+            !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                       get_seg_base(e1, e2), limit, e2);
+        EIP = new_eip;
+    } else {
+        /* jump to call or task gate */
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        rpl = new_cs & 3;
+        cpl = env->hflags & HF_CPL_MASK;
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1: /* 286 TSS */
+        case 9: /* 386 TSS */
+        case 5: /* task gate */
+            if (dpl < cpl || dpl < rpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            next_eip = env->eip + next_eip_addend;
+            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
+            CC_OP = CC_OP_EFLAGS;
+            break;
+        case 4: /* 286 call gate */
+        case 12: /* 386 call gate */
+            if ((dpl < cpl) || (dpl < rpl))
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (!(e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+            gate_cs = e1 >> 16;
+            new_eip = (e1 & 0xffff);
+            if (type == 12)
+                new_eip |= (e2 & 0xffff0000);
+            if (load_segment(&e1, &e2, gate_cs) != 0)
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+            /* must be code segment */
+            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
+                 (DESC_S_MASK | DESC_CS_MASK)))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
+                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            if (!(e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            limit = get_seg_limit(e1, e2);
+            if (new_eip > limit)
+                raise_exception_err(EXCP0D_GPF, 0);
+            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2), limit, e2);
+            EIP = new_eip;
+            break;
+        default:
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            break;
+        }
+    }
+}
+
+/* real mode call */
+void helper_lcall_real(int new_cs, target_ulong new_eip1,
+                       int shift, int next_eip)
+{
+    int new_eip;
+    uint32_t esp, esp_mask;
+    target_ulong ssp;
+
+    new_eip = new_eip1;
+    esp = ESP;
+    esp_mask = get_sp_mask(env->segs[R_SS].flags);
+    ssp = env->segs[R_SS].base;
+    if (shift) {
+        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
+        PUSHL(ssp, esp, esp_mask, next_eip);
+    } else {
+        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
+        PUSHW(ssp, esp, esp_mask, next_eip);
+    }
+
+    SET_ESP(esp, esp_mask);
+    env->eip = new_eip;
+    env->segs[R_CS].selector = new_cs;
+    env->segs[R_CS].base = (new_cs << 4);
+}
+
+/* protected mode call */
+void helper_lcall_protected(int new_cs, target_ulong new_eip, 
+                            int shift, int next_eip_addend)
+{
+    int new_stack, i;
+    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
+    uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
+    uint32_t val, limit, old_sp_mask;
+    target_ulong ssp, old_ssp, next_eip;
+
+    next_eip = env->eip + next_eip_addend;
+    LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
+    LOG_PCALL_STATE(env);
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    LOG_PCALL("desc=%08x:%08x\n", e1, e2);
+    if (e2 & DESC_S_MASK) {
+        if (!(e2 & DESC_CS_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (e2 & DESC_C_MASK) {
+            /* conforming code segment */
+            if (dpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        } else {
+            /* non conforming code segment */
+            rpl = new_cs & 3;
+            if (rpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+#ifdef TARGET_X86_64
+        /* XXX: check 16/32 bit cases in long mode */
+        if (shift == 2) {
+            target_ulong rsp;
+            /* 64 bit case */
+            rsp = ESP;
+            PUSHQ(rsp, env->segs[R_CS].selector);
+            PUSHQ(rsp, next_eip);
+            /* from this point, not restartable */
+            ESP = rsp;
+            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2),
+                                   get_seg_limit(e1, e2), e2);
+            EIP = new_eip;
+        } else
+#endif
+        {
+            sp = ESP;
+            sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            ssp = env->segs[R_SS].base;
+            if (shift) {
+                PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
+                PUSHL(ssp, sp, sp_mask, next_eip);
+            } else {
+                PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
+                PUSHW(ssp, sp, sp_mask, next_eip);
+            }
+
+            limit = get_seg_limit(e1, e2);
+            if (new_eip > limit)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            /* from this point, not restartable */
+            SET_ESP(sp, sp_mask);
+            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2), limit, e2);
+            EIP = new_eip;
+        }
+    } else {
+        /* check gate type */
+        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        rpl = new_cs & 3;
+        switch(type) {
+        case 1: /* available 286 TSS */
+        case 9: /* available 386 TSS */
+        case 5: /* task gate */
+            if (dpl < cpl || dpl < rpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
+            CC_OP = CC_OP_EFLAGS;
+            return;
+        case 4: /* 286 call gate */
+        case 12: /* 386 call gate */
+            break;
+        default:
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            break;
+        }
+        shift = type >> 3;
+
+        if (dpl < cpl || dpl < rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        /* check valid bit */
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
+        selector = e1 >> 16;
+        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+        param_count = e2 & 0x1f;
+        if ((selector & 0xfffc) == 0)
+            raise_exception_err(EXCP0D_GPF, 0);
+
+        if (load_segment(&e1, &e2, selector) != 0)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (dpl > cpl)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+
+        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+            /* to inner privilege */
+            get_ss_esp_from_tss(&ss, &sp, dpl);
+            LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
+                        ss, sp, param_count, ESP);
+            if ((ss & 0xfffc) == 0)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if ((ss & 3) != dpl)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+            if (ss_dpl != dpl)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (!(ss_e2 & DESC_S_MASK) ||
+                (ss_e2 & DESC_CS_MASK) ||
+                !(ss_e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (!(ss_e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+
+            //            push_size = ((param_count * 2) + 8) << shift;
+
+            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            old_ssp = env->segs[R_SS].base;
+
+            sp_mask = get_sp_mask(ss_e2);
+            ssp = get_seg_base(ss_e1, ss_e2);
+            if (shift) {
+                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
+                PUSHL(ssp, sp, sp_mask, ESP);
+                for(i = param_count - 1; i >= 0; i--) {
+                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
+                    PUSHL(ssp, sp, sp_mask, val);
+                }
+            } else {
+                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
+                PUSHW(ssp, sp, sp_mask, ESP);
+                for(i = param_count - 1; i >= 0; i--) {
+                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
+                    PUSHW(ssp, sp, sp_mask, val);
+                }
+            }
+            new_stack = 1;
+        } else {
+            /* to same privilege */
+            sp = ESP;
+            sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            ssp = env->segs[R_SS].base;
+            //            push_size = (4 << shift);
+            new_stack = 0;
+        }
+
+        if (shift) {
+            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
+            PUSHL(ssp, sp, sp_mask, next_eip);
+        } else {
+            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
+            PUSHW(ssp, sp, sp_mask, next_eip);
+        }
+
+        /* from this point, not restartable */
+
+        if (new_stack) {
+            ss = (ss & ~3) | dpl;
+            cpu_x86_load_seg_cache(env, R_SS, ss,
+                                   ssp,
+                                   get_seg_limit(ss_e1, ss_e2),
+                                   ss_e2);
+        }
+
+        selector = (selector & ~3) | dpl;
+        cpu_x86_load_seg_cache(env, R_CS, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+        cpu_x86_set_cpl(env, dpl);
+        SET_ESP(sp, sp_mask);
+        EIP = offset;
+    }
+}
+
+/* real and vm86 mode iret */
+void helper_iret_real(int shift)
+{
+    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
+    target_ulong ssp;
+    int eflags_mask;
+
+    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
+    sp = ESP;
+    ssp = env->segs[R_SS].base;
+    if (shift == 1) {
+        /* 32 bits */
+        POPL(ssp, sp, sp_mask, new_eip);
+        POPL(ssp, sp, sp_mask, new_cs);
+        new_cs &= 0xffff;
+        POPL(ssp, sp, sp_mask, new_eflags);
+    } else {
+        /* 16 bits */
+        POPW(ssp, sp, sp_mask, new_eip);
+        POPW(ssp, sp, sp_mask, new_cs);
+        POPW(ssp, sp, sp_mask, new_eflags);
+    }
+    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
+    env->segs[R_CS].selector = new_cs;
+    env->segs[R_CS].base = (new_cs << 4);
+    env->eip = new_eip;
+    if (env->eflags & VM_MASK)
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
+    else
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
+    if (shift == 0)
+        eflags_mask &= 0xffff;
+    load_eflags(new_eflags, eflags_mask);
+    env->hflags2 &= ~HF2_NMI_MASK;
+}
+
+static inline void validate_seg(int seg_reg, int cpl)
+{
+    int dpl;
+    uint32_t e2;
+
+    /* XXX: on x86_64, we do not want to nullify FS and GS because
+       they may still contain a valid base. I would be interested to
+       know how a real x86_64 CPU behaves */
+    if ((seg_reg == R_FS || seg_reg == R_GS) &&
+        (env->segs[seg_reg].selector & 0xfffc) == 0)
+        return;
+
+    e2 = env->segs[seg_reg].flags;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+        /* data or non conforming code segment */
+        if (dpl < cpl) {
+            cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
+        }
+    }
+}
+
+/* protected mode iret */
+static inline void helper_ret_protected(int shift, int is_iret, int addend)
+{
+    uint32_t new_cs, new_eflags, new_ss;
+    uint32_t new_es, new_ds, new_fs, new_gs;
+    uint32_t e1, e2, ss_e1, ss_e2;
+    int cpl, dpl, rpl, eflags_mask, iopl;
+    target_ulong ssp, sp, new_eip, new_esp, sp_mask;
+
+#ifdef TARGET_X86_64
+    if (shift == 2)
+        sp_mask = -1;
+    else
+#endif
+        sp_mask = get_sp_mask(env->segs[R_SS].flags);
+    sp = ESP;
+    ssp = env->segs[R_SS].base;
+    new_eflags = 0; /* avoid warning */
+#ifdef TARGET_X86_64
+    if (shift == 2) {
+        POPQ(sp, new_eip);
+        POPQ(sp, new_cs);
+        new_cs &= 0xffff;
+        if (is_iret) {
+            POPQ(sp, new_eflags);
+        }
+    } else
+#endif
+    if (shift == 1) {
+        /* 32 bits */
+        POPL(ssp, sp, sp_mask, new_eip);
+        POPL(ssp, sp, sp_mask, new_cs);
+        new_cs &= 0xffff;
+        if (is_iret) {
+            POPL(ssp, sp, sp_mask, new_eflags);
+            if (new_eflags & VM_MASK)
+                goto return_to_vm86;
+        }
+    } else {
+        /* 16 bits */
+        POPW(ssp, sp, sp_mask, new_eip);
+        POPW(ssp, sp, sp_mask, new_cs);
+        if (is_iret)
+            POPW(ssp, sp, sp_mask, new_eflags);
+    }
+    LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
+              new_cs, new_eip, shift, addend);
+    LOG_PCALL_STATE(env);
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    if (!(e2 & DESC_S_MASK) ||
+        !(e2 & DESC_CS_MASK))
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    rpl = new_cs & 3;
+    if (rpl < cpl)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (e2 & DESC_C_MASK) {
+        if (dpl > rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    } else {
+        if (dpl != rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    }
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+    sp += addend;
+    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
+                       ((env->hflags & HF_CS64_MASK) && !is_iret))) {
+        /* return to same privilege level */
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+    } else {
+        /* return to different privilege level */
+#ifdef TARGET_X86_64
+        if (shift == 2) {
+            POPQ(sp, new_esp);
+            POPQ(sp, new_ss);
+            new_ss &= 0xffff;
+        } else
+#endif
+        if (shift == 1) {
+            /* 32 bits */
+            POPL(ssp, sp, sp_mask, new_esp);
+            POPL(ssp, sp, sp_mask, new_ss);
+            new_ss &= 0xffff;
+        } else {
+            /* 16 bits */
+            POPW(ssp, sp, sp_mask, new_esp);
+            POPW(ssp, sp, sp_mask, new_ss);
+        }
+        LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
+                    new_ss, new_esp);
+        if ((new_ss & 0xfffc) == 0) {
+#ifdef TARGET_X86_64
+            /* NULL ss is allowed in long mode if cpl != 3*/
+            /* XXX: test CS64 ? */
+            if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
+                cpu_x86_load_seg_cache(env, R_SS, new_ss,
+                                       0, 0xffffffff,
+                                       DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                                       DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
+                                       DESC_W_MASK | DESC_A_MASK);
+                ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
+            } else
+#endif
+            {
+                raise_exception_err(EXCP0D_GPF, 0);
+            }
+        } else {
+            if ((new_ss & 3) != rpl)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (!(ss_e2 & DESC_S_MASK) ||
+                (ss_e2 & DESC_CS_MASK) ||
+                !(ss_e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+            if (dpl != rpl)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (!(ss_e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
+            cpu_x86_load_seg_cache(env, R_SS, new_ss,
+                                   get_seg_base(ss_e1, ss_e2),
+                                   get_seg_limit(ss_e1, ss_e2),
+                                   ss_e2);
+        }
+
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+        cpu_x86_set_cpl(env, rpl);
+        sp = new_esp;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_CS64_MASK)
+            sp_mask = -1;
+        else
+#endif
+            sp_mask = get_sp_mask(ss_e2);
+
+        /* validate data segments */
+        validate_seg(R_ES, rpl);
+        validate_seg(R_DS, rpl);
+        validate_seg(R_FS, rpl);
+        validate_seg(R_GS, rpl);
+
+        sp += addend;
+    }
+    SET_ESP(sp, sp_mask);
+    env->eip = new_eip;
+    if (is_iret) {
+        /* NOTE: 'cpl' is the _old_ CPL */
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
+        if (cpl == 0)
+            eflags_mask |= IOPL_MASK;
+        iopl = (env->eflags >> IOPL_SHIFT) & 3;
+        if (cpl <= iopl)
+            eflags_mask |= IF_MASK;
+        if (shift == 0)
+            eflags_mask &= 0xffff;
+        load_eflags(new_eflags, eflags_mask);
+    }
+    return;
+
+ return_to_vm86:
+    POPL(ssp, sp, sp_mask, new_esp);
+    POPL(ssp, sp, sp_mask, new_ss);
+    POPL(ssp, sp, sp_mask, new_es);
+    POPL(ssp, sp, sp_mask, new_ds);
+    POPL(ssp, sp, sp_mask, new_fs);
+    POPL(ssp, sp, sp_mask, new_gs);
+
+    /* modify processor state */
+    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
+                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
+    load_seg_vm(R_CS, new_cs & 0xffff);
+    cpu_x86_set_cpl(env, 3);
+    load_seg_vm(R_SS, new_ss & 0xffff);
+    load_seg_vm(R_ES, new_es & 0xffff);
+    load_seg_vm(R_DS, new_ds & 0xffff);
+    load_seg_vm(R_FS, new_fs & 0xffff);
+    load_seg_vm(R_GS, new_gs & 0xffff);
+
+    env->eip = new_eip & 0xffff;
+    ESP = new_esp;
+}
+
+void helper_iret_protected(int shift, int next_eip)
+{
+    int tss_selector, type;
+    uint32_t e1, e2;
+
+    /* specific case for TSS */
+    if (env->eflags & NT_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            raise_exception_err(EXCP0D_GPF, 0);
+#endif
+        tss_selector = lduw_kernel(env->tr.base + 0);
+        if (tss_selector & 4)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        if (load_segment(&e1, &e2, tss_selector) != 0)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
+        /* NOTE: we check both segment and busy TSS */
+        if (type != 3)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
+    } else {
+        helper_ret_protected(shift, 1, 0);
+    }
+    env->hflags2 &= ~HF2_NMI_MASK;
+}
+
+void helper_lret_protected(int shift, int addend)
+{
+    helper_ret_protected(shift, 0, addend);
+}
+
+void helper_sysenter(void)
+{
+    if (env->sysenter_cs == 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
+    cpu_x86_set_cpl(env, 0);
+
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_LMA_MASK) {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+    }
+    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
+                           0, 0xffffffff,
+                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                           DESC_S_MASK |
+                           DESC_W_MASK | DESC_A_MASK);
+    ESP = env->sysenter_esp;
+    EIP = env->sysenter_eip;
+}
+
+void helper_sysexit(int dflag)
+{
+    int cpl;
+
+    cpl = env->hflags & HF_CPL_MASK;
+    if (env->sysenter_cs == 0 || cpl != 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    cpu_x86_set_cpl(env, 3);
+#ifdef TARGET_X86_64
+    if (dflag == 2) {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    }
+    ESP = ECX;
+    EIP = EDX;
+}
+
+#if defined(CONFIG_USER_ONLY)
+target_ulong helper_read_crN(int reg)
+{
+    return 0;
+}
+
+void helper_write_crN(int reg, target_ulong t0)
+{
+}
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+}
+#else
+target_ulong helper_read_crN(int reg)
+{
+    target_ulong val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
+    switch(reg) {
+    default:
+        val = env->cr[reg];
+        break;
+    case 8:
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            val = cpu_get_apic_tpr(env->apic_state);
+        } else {
+            val = env->v_tpr;
+        }
+        break;
+    }
+    return val;
+}
+
+void helper_write_crN(int reg, target_ulong t0)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
+    switch(reg) {
+    case 0:
+        cpu_x86_update_cr0(env, t0);
+        break;
+    case 3:
+        cpu_x86_update_cr3(env, t0);
+        break;
+    case 4:
+        cpu_x86_update_cr4(env, t0);
+        break;
+    case 8:
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            cpu_set_apic_tpr(env->apic_state, t0);
+        }
+        env->v_tpr = t0 & 0x0f;
+        break;
+    default:
+        env->cr[reg] = t0;
+        break;
+    }
+}
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+    int i;
+
+    if (reg < 4) {
+        hw_breakpoint_remove(env, reg);
+        env->dr[reg] = t0;
+        hw_breakpoint_insert(env, reg);
+    } else if (reg == 7) {
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_remove(env, i);
+        env->dr[7] = t0;
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_insert(env, i);
+    } else
+        env->dr[reg] = t0;
+}
+#endif
+
+void helper_lmsw(target_ulong t0)
+{
+    /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
+       if already set to one. */
+    t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
+    helper_write_crN(0, t0);
+}
+
+void helper_clts(void)
+{
+    env->cr[0] &= ~CR0_TS_MASK;
+    env->hflags &= ~HF_TS_MASK;
+}
+
+void helper_invlpg(target_ulong addr)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
+    tlb_flush_page(env, addr);
+}
+
+void helper_rdtsc(void)
+{
+    uint64_t val;
+
+    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
+        raise_exception(EXCP0D_GPF);
+    }
+    helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
+
+    val = cpu_get_tsc(env) + env->tsc_offset;
+    EAX = (uint32_t)(val);
+    EDX = (uint32_t)(val >> 32);
+}
+
+void helper_rdtscp(void)
+{
+    helper_rdtsc();
+    ECX = (uint32_t)(env->tsc_aux);
+}
+
+void helper_rdpmc(void)
+{
+    if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
+        raise_exception(EXCP0D_GPF);
+    }
+    helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
+    
+    /* currently unimplemented */
+    raise_exception_err(EXCP06_ILLOP, 0);
+}
+
+#if defined(CONFIG_USER_ONLY)
+void helper_wrmsr(void)
+{
+}
+
+void helper_rdmsr(void)
+{
+}
+#else
+void helper_wrmsr(void)
+{
+    uint64_t val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
+
+    val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+
+    switch((uint32_t)ECX) {
+    case MSR_IA32_SYSENTER_CS:
+        env->sysenter_cs = val & 0xffff;
+        break;
+    case MSR_IA32_SYSENTER_ESP:
+        env->sysenter_esp = val;
+        break;
+    case MSR_IA32_SYSENTER_EIP:
+        env->sysenter_eip = val;
+        break;
+    case MSR_IA32_APICBASE:
+        cpu_set_apic_base(env->apic_state, val);
+        break;
+    case MSR_EFER:
+        {
+            uint64_t update_mask;
+            update_mask = 0;
+            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
+                update_mask |= MSR_EFER_SCE;
+            if (env->cpuid_ext2_features & CPUID_EXT2_LM)
+                update_mask |= MSR_EFER_LME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
+            if (env->cpuid_ext2_features & CPUID_EXT2_NX)
+                update_mask |= MSR_EFER_NXE;
+            if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
+                update_mask |= MSR_EFER_SVME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
+            cpu_load_efer(env, (env->efer & ~update_mask) |
+                          (val & update_mask));
+        }
+        break;
+    case MSR_STAR:
+        env->star = val;
+        break;
+    case MSR_PAT:
+        env->pat = val;
+        break;
+    case MSR_VM_HSAVE_PA:
+        env->vm_hsave = val;
+        break;
+#ifdef TARGET_X86_64
+    case MSR_LSTAR:
+        env->lstar = val;
+        break;
+    case MSR_CSTAR:
+        env->cstar = val;
+        break;
+    case MSR_FMASK:
+        env->fmask = val;
+        break;
+    case MSR_FSBASE:
+        env->segs[R_FS].base = val;
+        break;
+    case MSR_GSBASE:
+        env->segs[R_GS].base = val;
+        break;
+    case MSR_KERNELGSBASE:
+        env->kernelgsbase = val;
+        break;
+#endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
+        break;
+    case MSR_MTRRfix64K_00000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
+        break;
+    case MSR_MTRRdefType:
+        env->mtrr_deftype = val;
+        break;
+    case MSR_MCG_STATUS:
+        env->mcg_status = val;
+        break;
+    case MSR_MCG_CTL:
+        if ((env->mcg_cap & MCG_CTL_P)
+            && (val == 0 || val == ~(uint64_t)0))
+            env->mcg_ctl = val;
+        break;
+    case MSR_TSC_AUX:
+        env->tsc_aux = val;
+        break;
+    case MSR_IA32_MISC_ENABLE:
+        env->msr_ia32_misc_enable = val;
+        break;
+    default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            if ((offset & 0x3) != 0
+                || (val == 0 || val == ~(uint64_t)0))
+                env->mce_banks[offset] = val;
+            break;
+        }
+        /* XXX: exception ? */
+        break;
+    }
+}
+
+void helper_rdmsr(void)
+{
+    uint64_t val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
+
+    switch((uint32_t)ECX) {
+    case MSR_IA32_SYSENTER_CS:
+        val = env->sysenter_cs;
+        break;
+    case MSR_IA32_SYSENTER_ESP:
+        val = env->sysenter_esp;
+        break;
+    case MSR_IA32_SYSENTER_EIP:
+        val = env->sysenter_eip;
+        break;
+    case MSR_IA32_APICBASE:
+        val = cpu_get_apic_base(env->apic_state);
+        break;
+    case MSR_EFER:
+        val = env->efer;
+        break;
+    case MSR_STAR:
+        val = env->star;
+        break;
+    case MSR_PAT:
+        val = env->pat;
+        break;
+    case MSR_VM_HSAVE_PA:
+        val = env->vm_hsave;
+        break;
+    case MSR_IA32_PERF_STATUS:
+        /* tsc_increment_by_tick */
+        val = 1000ULL;
+        /* CPU multiplier */
+        val |= (((uint64_t)4ULL) << 40);
+        break;
+#ifdef TARGET_X86_64
+    case MSR_LSTAR:
+        val = env->lstar;
+        break;
+    case MSR_CSTAR:
+        val = env->cstar;
+        break;
+    case MSR_FMASK:
+        val = env->fmask;
+        break;
+    case MSR_FSBASE:
+        val = env->segs[R_FS].base;
+        break;
+    case MSR_GSBASE:
+        val = env->segs[R_GS].base;
+        break;
+    case MSR_KERNELGSBASE:
+        val = env->kernelgsbase;
+        break;
+    case MSR_TSC_AUX:
+        val = env->tsc_aux;
+        break;
+#endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
+        break;
+    case MSR_MTRRfix64K_00000:
+        val = env->mtrr_fixed[0];
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
+        break;
+    case MSR_MTRRdefType:
+        val = env->mtrr_deftype;
+        break;
+    case MSR_MTRRcap:
+        if (env->cpuid_features & CPUID_MTRR)
+            val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
+        else
+            /* XXX: exception ? */
+            val = 0;
+        break;
+    case MSR_MCG_CAP:
+        val = env->mcg_cap;
+        break;
+    case MSR_MCG_CTL:
+        if (env->mcg_cap & MCG_CTL_P)
+            val = env->mcg_ctl;
+        else
+            val = 0;
+        break;
+    case MSR_MCG_STATUS:
+        val = env->mcg_status;
+        break;
+    case MSR_IA32_MISC_ENABLE:
+        val = env->msr_ia32_misc_enable;
+        break;
+    default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            val = env->mce_banks[offset];
+            break;
+        }
+        /* XXX: exception ? */
+        val = 0;
+        break;
+    }
+    EAX = (uint32_t)(val);
+    EDX = (uint32_t)(val >> 32);
+}
+#endif
+
+target_ulong helper_lsl(target_ulong selector1)
+{
+    unsigned int limit;
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl, type;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
+            /* conforming */
+        } else {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1:
+        case 2:
+        case 3:
+        case 9:
+        case 11:
+            break;
+        default:
+            goto fail;
+        }
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return 0;
+        }
+    }
+    limit = get_seg_limit(e1, e2);
+    CC_SRC = eflags | CC_Z;
+    return limit;
+}
+
+target_ulong helper_lar(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl, type;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
+            /* conforming */
+        } else {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1:
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+        case 11:
+        case 12:
+            break;
+        default:
+            goto fail;
+        }
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return 0;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+    return e2 & 0x00f0ff00;
+}
+
+void helper_verr(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    if (!(e2 & DESC_S_MASK))
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_CS_MASK) {
+        if (!(e2 & DESC_R_MASK))
+            goto fail;
+        if (!(e2 & DESC_C_MASK)) {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+}
+
+void helper_verw(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    if (!(e2 & DESC_S_MASK))
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_CS_MASK) {
+        goto fail;
+    } else {
+        if (dpl < cpl || dpl < rpl)
+            goto fail;
+        if (!(e2 & DESC_W_MASK)) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+}
+
+/* x87 FPU helpers */
+
+static inline double floatx80_to_double(floatx80 a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.f64 = floatx80_to_float64(a, &env->fp_status);
+    return u.d;
+}
+
+static inline floatx80 double_to_floatx80(double a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.d = a;
+    return float64_to_floatx80(u.f64, &env->fp_status);
+}
+
+static void fpu_set_exception(int mask)
+{
+    env->fpus |= mask;
+    if (env->fpus & (~env->fpuc & FPUC_EM))
+        env->fpus |= FPUS_SE | FPUS_B;
+}
+
+static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
+{
+    if (floatx80_is_zero(b)) {
+        fpu_set_exception(FPUS_ZE);
+    }
+    return floatx80_div(a, b, &env->fp_status);
+}
+
+static void fpu_raise_exception(void)
+{
+    if (env->cr[0] & CR0_NE_MASK) {
+        raise_exception(EXCP10_COPR);
+    }
+#if !defined(CONFIG_USER_ONLY)
+    else {
+        cpu_set_ferr(env);
+    }
+#endif
+}
+
+void helper_flds_FT0(uint32_t val)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = val;
+    FT0 = float32_to_floatx80(u.f, &env->fp_status);
+}
+
+void helper_fldl_FT0(uint64_t val)
+{
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    u.i = val;
+    FT0 = float64_to_floatx80(u.f, &env->fp_status);
+}
+
+void helper_fildl_FT0(int32_t val)
+{
+    FT0 = int32_to_floatx80(val, &env->fp_status);
+}
+
+void helper_flds_ST0(uint32_t val)
+{
+    int new_fpstt;
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    new_fpstt = (env->fpstt - 1) & 7;
+    u.i = val;
+    env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fldl_ST0(uint64_t val)
+{
+    int new_fpstt;
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    new_fpstt = (env->fpstt - 1) & 7;
+    u.i = val;
+    env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildl_ST0(int32_t val)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildll_ST0(int64_t val)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+uint32_t helper_fsts_ST0(void)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = floatx80_to_float32(ST0, &env->fp_status);
+    return u.i;
+}
+
+uint64_t helper_fstl_ST0(void)
+{
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    u.f = floatx80_to_float64(ST0, &env->fp_status);
+    return u.i;
+}
+
+int32_t helper_fist_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32(ST0, &env->fp_status);
+    if (val != (int16_t)val)
+        val = -32768;
+    return val;
+}
+
+int32_t helper_fistl_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32(ST0, &env->fp_status);
+    return val;
+}
+
+int64_t helper_fistll_ST0(void)
+{
+    int64_t val;
+    val = floatx80_to_int64(ST0, &env->fp_status);
+    return val;
+}
+
+int32_t helper_fistt_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
+    if (val != (int16_t)val)
+        val = -32768;
+    return val;
+}
+
+int32_t helper_fisttl_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
+    return val;
+}
+
+int64_t helper_fisttll_ST0(void)
+{
+    int64_t val;
+    val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
+    return val;
+}
+
+void helper_fldt_ST0(target_ulong ptr)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = helper_fldt(ptr);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fstt_ST0(target_ulong ptr)
+{
+    helper_fstt(ST0, ptr);
+}
+
+void helper_fpush(void)
+{
+    fpush();
+}
+
+void helper_fpop(void)
+{
+    fpop();
+}
+
+void helper_fdecstp(void)
+{
+    env->fpstt = (env->fpstt - 1) & 7;
+    env->fpus &= (~0x4700);
+}
+
+void helper_fincstp(void)
+{
+    env->fpstt = (env->fpstt + 1) & 7;
+    env->fpus &= (~0x4700);
+}
+
+/* FPU move */
+
+void helper_ffree_STN(int st_index)
+{
+    env->fptags[(env->fpstt + st_index) & 7] = 1;
+}
+
+void helper_fmov_ST0_FT0(void)
+{
+    ST0 = FT0;
+}
+
+void helper_fmov_FT0_STN(int st_index)
+{
+    FT0 = ST(st_index);
+}
+
+void helper_fmov_ST0_STN(int st_index)
+{
+    ST0 = ST(st_index);
+}
+
+void helper_fmov_STN_ST0(int st_index)
+{
+    ST(st_index) = ST0;
+}
+
+void helper_fxchg_ST0_STN(int st_index)
+{
+    floatx80 tmp;
+    tmp = ST(st_index);
+    ST(st_index) = ST0;
+    ST0 = tmp;
+}
+
+/* FPU operations */
+
+static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
+
+void helper_fcom_ST0_FT0(void)
+{
+    int ret;
+
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
+    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+}
+
+void helper_fucom_ST0_FT0(void)
+{
+    int ret;
+
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
+}
+
+static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
+
+void helper_fcomi_ST0_FT0(void)
+{
+    int eflags;
+    int ret;
+
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
+    CC_SRC = eflags;
+}
+
+void helper_fucomi_ST0_FT0(void)
+{
+    int eflags;
+    int ret;
+
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
+    CC_SRC = eflags;
+}
+
+void helper_fadd_ST0_FT0(void)
+{
+    ST0 = floatx80_add(ST0, FT0, &env->fp_status);
+}
+
+void helper_fmul_ST0_FT0(void)
+{
+    ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
+}
+
+void helper_fsub_ST0_FT0(void)
+{
+    ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
+}
+
+void helper_fsubr_ST0_FT0(void)
+{
+    ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
+}
+
+void helper_fdiv_ST0_FT0(void)
+{
+    ST0 = helper_fdiv(ST0, FT0);
+}
+
+void helper_fdivr_ST0_FT0(void)
+{
+    ST0 = helper_fdiv(FT0, ST0);
+}
+
+/* fp operations between STN and ST0 */
+
+void helper_fadd_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fmul_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fsub_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fsubr_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
+}
+
+void helper_fdiv_STN_ST0(int st_index)
+{
+    floatx80 *p;
+    p = &ST(st_index);
+    *p = helper_fdiv(*p, ST0);
+}
+
+void helper_fdivr_STN_ST0(int st_index)
+{
+    floatx80 *p;
+    p = &ST(st_index);
+    *p = helper_fdiv(ST0, *p);
+}
+
+/* misc FPU operations */
+void helper_fchs_ST0(void)
+{
+    ST0 = floatx80_chs(ST0);
+}
+
+void helper_fabs_ST0(void)
+{
+    ST0 = floatx80_abs(ST0);
+}
+
+void helper_fld1_ST0(void)
+{
+    ST0 = floatx80_one;
+}
+
+void helper_fldl2t_ST0(void)
+{
+    ST0 = floatx80_l2t;
+}
+
+void helper_fldl2e_ST0(void)
+{
+    ST0 = floatx80_l2e;
+}
+
+void helper_fldpi_ST0(void)
+{
+    ST0 = floatx80_pi;
+}
+
+void helper_fldlg2_ST0(void)
+{
+    ST0 = floatx80_lg2;
+}
+
+void helper_fldln2_ST0(void)
+{
+    ST0 = floatx80_ln2;
+}
+
+void helper_fldz_ST0(void)
+{
+    ST0 = floatx80_zero;
+}
+
+void helper_fldz_FT0(void)
+{
+    FT0 = floatx80_zero;
+}
+
+uint32_t helper_fnstsw(void)
+{
+    return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+}
+
+uint32_t helper_fnstcw(void)
+{
+    return env->fpuc;
+}
+
+static void update_fp_status(void)
+{
+    int rnd_type;
+
+    /* set rounding mode */
+    switch(env->fpuc & RC_MASK) {
+    default:
+    case RC_NEAR:
+        rnd_type = float_round_nearest_even;
+        break;
+    case RC_DOWN:
+        rnd_type = float_round_down;
+        break;
+    case RC_UP:
+        rnd_type = float_round_up;
+        break;
+    case RC_CHOP:
+        rnd_type = float_round_to_zero;
+        break;
+    }
+    set_float_rounding_mode(rnd_type, &env->fp_status);
+    switch((env->fpuc >> 8) & 3) {
+    case 0:
+        rnd_type = 32;
+        break;
+    case 2:
+        rnd_type = 64;
+        break;
+    case 3:
+    default:
+        rnd_type = 80;
+        break;
+    }
+    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
+}
+
+void helper_fldcw(uint32_t val)
+{
+    env->fpuc = val;
+    update_fp_status();
+}
+
+void helper_fclex(void)
+{
+    env->fpus &= 0x7f00;
+}
+
+void helper_fwait(void)
+{
+    if (env->fpus & FPUS_SE)
+        fpu_raise_exception();
+}
+
+void helper_fninit(void)
+{
+    env->fpus = 0;
+    env->fpstt = 0;
+    env->fpuc = 0x37f;
+    env->fptags[0] = 1;
+    env->fptags[1] = 1;
+    env->fptags[2] = 1;
+    env->fptags[3] = 1;
+    env->fptags[4] = 1;
+    env->fptags[5] = 1;
+    env->fptags[6] = 1;
+    env->fptags[7] = 1;
+}
+
+/* BCD ops */
+
+void helper_fbld_ST0(target_ulong ptr)
+{
+    floatx80 tmp;
+    uint64_t val;
+    unsigned int v;
+    int i;
+
+    val = 0;
+    for(i = 8; i >= 0; i--) {
+        v = ldub(ptr + i);
+        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
+    }
+    tmp = int64_to_floatx80(val, &env->fp_status);
+    if (ldub(ptr + 9) & 0x80) {
+        floatx80_chs(tmp);
+    }
+    fpush();
+    ST0 = tmp;
+}
+
+void helper_fbst_ST0(target_ulong ptr)
+{
+    int v;
+    target_ulong mem_ref, mem_end;
+    int64_t val;
+
+    val = floatx80_to_int64(ST0, &env->fp_status);
+    mem_ref = ptr;
+    mem_end = mem_ref + 9;
+    if (val < 0) {
+        stb(mem_end, 0x80);
+        val = -val;
+    } else {
+        stb(mem_end, 0x00);
+    }
+    while (mem_ref < mem_end) {
+        if (val == 0)
+            break;
+        v = val % 100;
+        val = val / 100;
+        v = ((v / 10) << 4) | (v % 10);
+        stb(mem_ref++, v);
+    }
+    while (mem_ref < mem_end) {
+        stb(mem_ref++, 0);
+    }
+}
+
+void helper_f2xm1(void)
+{
+    double val = floatx80_to_double(ST0);
+    val = pow(2.0, val) - 1.0;
+    ST0 = double_to_floatx80(val);
+}
+
+void helper_fyl2x(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if (fptemp>0.0){
+        fptemp = log(fptemp)/log(2.0);    /* log2(ST) */
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
+        fpop();
+    } else {
+        env->fpus &= (~0x4700);
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fptan(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        fptemp = tan(fptemp);
+        ST0 = double_to_floatx80(fptemp);
+        fpush();
+        ST0 = floatx80_one;
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**52 only */
+    }
+}
+
+void helper_fpatan(void)
+{
+    double fptemp, fpsrcop;
+
+    fpsrcop = floatx80_to_double(ST1);
+    fptemp = floatx80_to_double(ST0);
+    ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
+    fpop();
+}
+
+void helper_fxtract(void)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = ST0;
+
+    if (floatx80_is_zero(ST0)) {
+        /* Easy way to generate -inf and raising division by 0 exception */
+        ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status);
+        fpush();
+        ST0 = temp.d;
+    } else {
+        int expdif;
+
+        expdif = EXPD(temp) - EXPBIAS;
+        /*DP exponent bias*/
+        ST0 = int32_to_floatx80(expdif, &env->fp_status);
+        fpush();
+        BIASEXPONENT(temp);
+        ST0 = temp.d;
+    }
+}
+
+void helper_fprem1(void)
+{
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
+    int expdif;
+    signed long long int q;
+
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+        ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        return;
+    }
+
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
+    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        /* ST0 is unchanged */
+        return;
+    }
+
+    if (expdif < 53) {
+        dblq = fpsrcop / fptemp;
+        /* round dblq towards nearest integer */
+        dblq = rint(dblq);
+        st0 = fpsrcop - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
+    } else {
+        env->fpus |= 0x400;  /* C2 <-- 1 */
+        fptemp = pow(2.0, expdif - 50);
+        fpsrcop = (st0 / st1) / fptemp;
+        /* fpsrcop = integer obtained by chopping */
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
+        st0 -= (st1 * fpsrcop * fptemp);
+    }
+    ST0 = double_to_floatx80(st0);
+}
+
+void helper_fprem(void)
+{
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
+    int expdif;
+    signed long long int q;
+
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+       ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+       env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+       return;
+    }
+
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
+    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        /* ST0 is unchanged */
+        return;
+    }
+
+    if ( expdif < 53 ) {
+        dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
+        /* round dblq towards zero */
+        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
+        st0 = fpsrcop/*ST0*/ - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
+    } else {
+        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 = integer obtained by chopping */
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
+        st0 -= (st1 * fpsrcop * fptemp);
+    }
+    ST0 = double_to_floatx80(st0);
+}
+
+void helper_fyl2xp1(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp+1.0)>0.0) {
+        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
+        fpop();
+    } else {
+        env->fpus &= (~0x4700);
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fsqrt(void)
+{
+    if (floatx80_is_neg(ST0)) {
+        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
+        env->fpus |= 0x400;
+    }
+    ST0 = floatx80_sqrt(ST0, &env->fp_status);
+}
+
+void helper_fsincos(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(sin(fptemp));
+        fpush();
+        ST0 = double_to_floatx80(cos(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**63 only */
+    }
+}
+
+void helper_frndint(void)
+{
+    ST0 = floatx80_round_to_int(ST0, &env->fp_status);
+}
+
+void helper_fscale(void)
+{
+    if (floatx80_is_any_nan(ST1)) {
+        ST0 = ST1;
+    } else {
+        int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
+        ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
+    }
+}
+
+void helper_fsin(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(sin(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**53 only */
+    }
+}
+
+void helper_fcos(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(cos(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg5 < 2**63 only */
+    }
+}
+
+void helper_fxam_ST0(void)
+{
+    CPU_LDoubleU temp;
+    int expdif;
+
+    temp.d = ST0;
+
+    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
+    if (SIGND(temp))
+        env->fpus |= 0x200; /* C1 <-- 1 */
+
+    /* XXX: test fptags too */
+    expdif = EXPD(temp);
+    if (expdif == MAXEXPD) {
+        if (MANTD(temp) == 0x8000000000000000ULL)
+            env->fpus |=  0x500 /*Infinity*/;
+        else
+            env->fpus |=  0x100 /*NaN*/;
+    } else if (expdif == 0) {
+        if (MANTD(temp) == 0)
+            env->fpus |=  0x4000 /*Zero*/;
+        else
+            env->fpus |= 0x4400 /*Denormal*/;
+    } else {
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fstenv(target_ulong ptr, int data32)
+{
+    int fpus, fptag, exp, i;
+    uint64_t mant;
+    CPU_LDoubleU tmp;
+
+    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    fptag = 0;
+    for (i=7; i>=0; i--) {
+       fptag <<= 2;
+       if (env->fptags[i]) {
+            fptag |= 3;
+       } else {
+            tmp.d = env->fpregs[i].d;
+            exp = EXPD(tmp);
+            mant = MANTD(tmp);
+            if (exp == 0 && mant == 0) {
+                /* zero */
+               fptag |= 1;
+           } else if (exp == 0 || exp == MAXEXPD
+                       || (mant & (1LL << 63)) == 0
+                       ) {
+                /* NaNs, infinity, denormal */
+                fptag |= 2;
+            }
+        }
+    }
+    if (data32) {
+        /* 32 bit */
+        stl(ptr, env->fpuc);
+        stl(ptr + 4, fpus);
+        stl(ptr + 8, fptag);
+        stl(ptr + 12, 0); /* fpip */
+        stl(ptr + 16, 0); /* fpcs */
+        stl(ptr + 20, 0); /* fpoo */
+        stl(ptr + 24, 0); /* fpos */
+    } else {
+        /* 16 bit */
+        stw(ptr, env->fpuc);
+        stw(ptr + 2, fpus);
+        stw(ptr + 4, fptag);
+        stw(ptr + 6, 0);
+        stw(ptr + 8, 0);
+        stw(ptr + 10, 0);
+        stw(ptr + 12, 0);
+    }
+}
+
+void helper_fldenv(target_ulong ptr, int data32)
+{
+    int i, fpus, fptag;
+
+    if (data32) {
+       env->fpuc = lduw(ptr);
+        fpus = lduw(ptr + 4);
+        fptag = lduw(ptr + 8);
+    }
+    else {
+       env->fpuc = lduw(ptr);
+        fpus = lduw(ptr + 2);
+        fptag = lduw(ptr + 4);
+    }
+    env->fpstt = (fpus >> 11) & 7;
+    env->fpus = fpus & ~0x3800;
+    for(i = 0;i < 8; i++) {
+        env->fptags[i] = ((fptag & 3) == 3);
+        fptag >>= 2;
+    }
+}
+
+void helper_fsave(target_ulong ptr, int data32)
+{
+    floatx80 tmp;
+    int i;
+
+    helper_fstenv(ptr, data32);
+
+    ptr += (14 << data32);
+    for(i = 0;i < 8; i++) {
+        tmp = ST(i);
+        helper_fstt(tmp, ptr);
+        ptr += 10;
+    }
+
+    /* fninit */
+    env->fpus = 0;
+    env->fpstt = 0;
+    env->fpuc = 0x37f;
+    env->fptags[0] = 1;
+    env->fptags[1] = 1;
+    env->fptags[2] = 1;
+    env->fptags[3] = 1;
+    env->fptags[4] = 1;
+    env->fptags[5] = 1;
+    env->fptags[6] = 1;
+    env->fptags[7] = 1;
+}
+
+void helper_frstor(target_ulong ptr, int data32)
+{
+    floatx80 tmp;
+    int i;
+
+    helper_fldenv(ptr, data32);
+    ptr += (14 << data32);
+
+    for(i = 0;i < 8; i++) {
+        tmp = helper_fldt(ptr);
+        ST(i) = tmp;
+        ptr += 10;
+    }
+}
+
+
+#if defined(CONFIG_USER_ONLY)
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+        selector &= 0xffff;
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                               (selector << 4), 0xffff, 0);
+    } else {
+        helper_load_seg(seg_reg, selector);
+    }
+    env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+
+    helper_fsave(ptr, data32);
+
+    env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+
+    helper_frstor(ptr, data32);
+
+    env = saved_env;
+}
+#endif
+
+void helper_fxsave(target_ulong ptr, int data64)
+{
+    int fpus, fptag, i, nb_xmm_regs;
+    floatx80 tmp;
+    target_ulong addr;
+
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
+    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    fptag = 0;
+    for(i = 0; i < 8; i++) {
+        fptag |= (env->fptags[i] << i);
+    }
+    stw(ptr, env->fpuc);
+    stw(ptr + 2, fpus);
+    stw(ptr + 4, fptag ^ 0xff);
+#ifdef TARGET_X86_64
+    if (data64) {
+        stq(ptr + 0x08, 0); /* rip */
+        stq(ptr + 0x10, 0); /* rdp */
+    } else 
+#endif
+    {
+        stl(ptr + 0x08, 0); /* eip */
+        stl(ptr + 0x0c, 0); /* sel  */
+        stl(ptr + 0x10, 0); /* dp */
+        stl(ptr + 0x14, 0); /* sel  */
+    }
+
+    addr = ptr + 0x20;
+    for(i = 0;i < 8; i++) {
+        tmp = ST(i);
+        helper_fstt(tmp, addr);
+        addr += 16;
+    }
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        /* XXX: finish it */
+        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
+        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
+        if (env->hflags & HF_CS64_MASK)
+            nb_xmm_regs = 16;
+        else
+            nb_xmm_regs = 8;
+        addr = ptr + 0xa0;
+        /* Fast FXSAVE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                stq(addr, env->xmm_regs[i].XMM_Q(0));
+                stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
+                addr += 16;
+            }
+        }
+    }
+}
+
+void helper_fxrstor(target_ulong ptr, int data64)
+{
+    int i, fpus, fptag, nb_xmm_regs;
+    floatx80 tmp;
+    target_ulong addr;
+
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
+    env->fpuc = lduw(ptr);
+    fpus = lduw(ptr + 2);
+    fptag = lduw(ptr + 4);
+    env->fpstt = (fpus >> 11) & 7;
+    env->fpus = fpus & ~0x3800;
+    fptag ^= 0xff;
+    for(i = 0;i < 8; i++) {
+        env->fptags[i] = ((fptag >> i) & 1);
+    }
+
+    addr = ptr + 0x20;
+    for(i = 0;i < 8; i++) {
+        tmp = helper_fldt(addr);
+        ST(i) = tmp;
+        addr += 16;
+    }
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        /* XXX: finish it */
+        env->mxcsr = ldl(ptr + 0x18);
+        //ldl(ptr + 0x1c);
+        if (env->hflags & HF_CS64_MASK)
+            nb_xmm_regs = 16;
+        else
+            nb_xmm_regs = 8;
+        addr = ptr + 0xa0;
+        /* Fast FXRESTORE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                env->xmm_regs[i].XMM_Q(0) = ldq(addr);
+                env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+                addr += 16;
+            }
+        }
+    }
+}
+
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = f;
+    *pmant = temp.l.lower;
+    *pexp = temp.l.upper;
+}
+
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
+{
+    CPU_LDoubleU temp;
+
+    temp.l.upper = upper;
+    temp.l.lower = mant;
+    return temp.d;
+}
+
+#ifdef TARGET_X86_64
+
+//#define DEBUG_MULDIV
+
+static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    *plow += a;
+    /* carry test */
+    if (*plow < a)
+        (*phigh)++;
+    *phigh += b;
+}
+
+static void neg128(uint64_t *plow, uint64_t *phigh)
+{
+    *plow = ~ *plow;
+    *phigh = ~ *phigh;
+    add128(plow, phigh, 1, 0);
+}
+
+/* return TRUE if overflow */
+static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
+{
+    uint64_t q, r, a1, a0;
+    int i, qb, ab;
+
+    a0 = *plow;
+    a1 = *phigh;
+    if (a1 == 0) {
+        q = a0 / b;
+        r = a0 % b;
+        *plow = q;
+        *phigh = r;
+    } else {
+        if (a1 >= b)
+            return 1;
+        /* XXX: use a better algorithm */
+        for(i = 0; i < 64; i++) {
+            ab = a1 >> 63;
+            a1 = (a1 << 1) | (a0 >> 63);
+            if (ab || a1 >= b) {
+                a1 -= b;
+                qb = 1;
+            } else {
+                qb = 0;
+            }
+            a0 = (a0 << 1) | qb;
+        }
+#if defined(DEBUG_MULDIV)
+        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
+               *phigh, *plow, b, a0, a1);
+#endif
+        *plow = a0;
+        *phigh = a1;
+    }
+    return 0;
+}
+
+/* return TRUE if overflow */
+static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
+{
+    int sa, sb;
+    sa = ((int64_t)*phigh < 0);
+    if (sa)
+        neg128(plow, phigh);
+    sb = (b < 0);
+    if (sb)
+        b = -b;
+    if (div64(plow, phigh, b) != 0)
+        return 1;
+    if (sa ^ sb) {
+        if (*plow > (1ULL << 63))
+            return 1;
+        *plow = - *plow;
+    } else {
+        if (*plow >= (1ULL << 63))
+            return 1;
+    }
+    if (sa)
+        *phigh = - *phigh;
+    return 0;
+}
+
+void helper_mulq_EAX_T0(target_ulong t0)
+{
+    uint64_t r0, r1;
+
+    mulu64(&r0, &r1, EAX, t0);
+    EAX = r0;
+    EDX = r1;
+    CC_DST = r0;
+    CC_SRC = r1;
+}
+
+void helper_imulq_EAX_T0(target_ulong t0)
+{
+    uint64_t r0, r1;
+
+    muls64(&r0, &r1, EAX, t0);
+    EAX = r0;
+    EDX = r1;
+    CC_DST = r0;
+    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
+}
+
+target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
+{
+    uint64_t r0, r1;
+
+    muls64(&r0, &r1, t0, t1);
+    CC_DST = r0;
+    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
+    return r0;
+}
+
+void helper_divq_EAX(target_ulong t0)
+{
+    uint64_t r0, r1;
+    if (t0 == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    r0 = EAX;
+    r1 = EDX;
+    if (div64(&r0, &r1, t0))
+        raise_exception(EXCP00_DIVZ);
+    EAX = r0;
+    EDX = r1;
+}
+
+void helper_idivq_EAX(target_ulong t0)
+{
+    uint64_t r0, r1;
+    if (t0 == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    r0 = EAX;
+    r1 = EDX;
+    if (idiv64(&r0, &r1, t0))
+        raise_exception(EXCP00_DIVZ);
+    EAX = r0;
+    EDX = r1;
+}
+#endif
+
+static void do_hlt(void)
+{
+    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit(env);
+}
+
+void helper_hlt(int next_eip_addend)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
+    EIP += next_eip_addend;
+    
+    do_hlt();
+}
+
+void helper_monitor(target_ulong ptr)
+{
+    if ((uint32_t)ECX != 0)
+        raise_exception(EXCP0D_GPF);
+    /* XXX: store address ? */
+    helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
+}
+
+void helper_mwait(int next_eip_addend)
+{
+    if ((uint32_t)ECX != 0)
+        raise_exception(EXCP0D_GPF);
+    helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
+    EIP += next_eip_addend;
+
+    /* XXX: not complete but not completely erroneous */
+    if (env->cpu_index != 0 || env->next_cpu != NULL) {
+        /* more than one CPU: do not sleep because another CPU may
+           wake this one */
+    } else {
+        do_hlt();
+    }
+}
+
+void helper_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
+
+void helper_reset_rf(void)
+{
+    env->eflags &= ~RF_MASK;
+}
+
+void helper_raise_interrupt(int intno, int next_eip_addend)
+{
+    raise_interrupt(intno, 1, 0, next_eip_addend);
+}
+
+void helper_raise_exception(int exception_index)
+{
+    raise_exception(exception_index);
+}
+
+void helper_cli(void)
+{
+    env->eflags &= ~IF_MASK;
+}
+
+void helper_sti(void)
+{
+    env->eflags |= IF_MASK;
+}
+
+#if 0
+/* vm86plus instructions */
+void helper_cli_vm(void)
+{
+    env->eflags &= ~VIF_MASK;
+}
+
+void helper_sti_vm(void)
+{
+    env->eflags |= VIF_MASK;
+    if (env->eflags & VIP_MASK) {
+        raise_exception(EXCP0D_GPF);
+    }
+}
+#endif
+
+void helper_set_inhibit_irq(void)
+{
+    env->hflags |= HF_INHIBIT_IRQ_MASK;
+}
+
+void helper_reset_inhibit_irq(void)
+{
+    env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+}
+
+void helper_boundw(target_ulong a0, int v)
+{
+    int low, high;
+    low = ldsw(a0);
+    high = ldsw(a0 + 2);
+    v = (int16_t)v;
+    if (v < low || v > high) {
+        raise_exception(EXCP05_BOUND);
+    }
+}
+
+void helper_boundl(target_ulong a0, int v)
+{
+    int low, high;
+    low = ldl(a0);
+    high = ldl(a0 + 4);
+    if (v < low || v > high) {
+        raise_exception(EXCP05_BOUND);
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
+{
+    TranslationBlock *tb;
+    int ret;
+    unsigned long pc;
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = env1;
+
+    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (ret) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        raise_exception_err(env->exception_index, env->error_code);
+    }
+    env = saved_env;
+}
+#endif
+
+/* Secure Virtual Machine helpers */
+
+#if defined(CONFIG_USER_ONLY)
+
+void helper_vmrun(int aflag, int next_eip_addend)
+{ 
+}
+void helper_vmmcall(void) 
+{ 
+}
+void helper_vmload(int aflag)
+{ 
+}
+void helper_vmsave(int aflag)
+{ 
+}
+void helper_stgi(void)
+{
+}
+void helper_clgi(void)
+{
+}
+void helper_skinit(void) 
+{ 
+}
+void helper_invlpga(int aflag)
+{ 
+}
+void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 
+{ 
+}
+void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+}
+
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+}
+
+void helper_svm_check_io(uint32_t port, uint32_t param, 
+                         uint32_t next_eip_addend)
+{
+}
+#else
+
+static inline void svm_save_seg(target_phys_addr_t addr,
+                                const SegmentCache *sc)
+{
+    stw_phys(addr + offsetof(struct vmcb_seg, selector), 
+             sc->selector);
+    stq_phys(addr + offsetof(struct vmcb_seg, base), 
+             sc->base);
+    stl_phys(addr + offsetof(struct vmcb_seg, limit), 
+             sc->limit);
+    stw_phys(addr + offsetof(struct vmcb_seg, attrib), 
+             ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
+}
+                                
+static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
+{
+    unsigned int flags;
+
+    sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
+    sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
+    sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
+    flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
+    sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
+}
+
+static inline void svm_load_seg_cache(target_phys_addr_t addr, 
+                                      CPUState *env, int seg_reg)
+{
+    SegmentCache sc1, *sc = &sc1;
+    svm_load_seg(addr, sc);
+    cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
+                           sc->base, sc->limit, sc->flags);
+}
+
+void helper_vmrun(int aflag, int next_eip_addend)
+{
+    target_ulong addr;
+    uint32_t event_inj;
+    uint32_t int_ctl;
+
+    helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
+
+    env->vm_vmcb = addr;
+
+    /* save the current CPU state in the hsave page */
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
+
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), 
+                  &env->segs[R_ES]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), 
+                 &env->segs[R_CS]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), 
+                 &env->segs[R_SS]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), 
+                 &env->segs[R_DS]);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
+             EIP + next_eip_addend);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
+
+    /* load the interception bitmaps so we do not need to access the
+       vmcb in svm mode */
+    env->intercept            = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
+    env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
+    env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
+    env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
+    env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
+    env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
+
+    /* enable intercepts */
+    env->hflags |= HF_SVMI_MASK;
+
+    env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
+
+    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
+
+    /* clear exit_info_2 so we behave like the real hardware */
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
+    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
+    if (int_ctl & V_INTR_MASKING_MASK) {
+        env->v_tpr = int_ctl & V_TPR_MASK;
+        env->hflags2 |= HF2_VINTR_MASK;
+        if (env->eflags & IF_MASK)
+            env->hflags2 |= HF2_HIF_MASK;
+    }
+
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
+                       env, R_ES);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
+                       env, R_CS);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
+                       env, R_SS);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
+                       env, R_DS);
+
+    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
+    env->eip = EIP;
+    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
+    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
+    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
+    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
+
+    /* FIXME: guest state consistency checks */
+
+    switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
+        case TLB_CONTROL_DO_NOTHING:
+            break;
+        case TLB_CONTROL_FLUSH_ALL_ASID:
+            /* FIXME: this is not 100% correct but should work for now */
+            tlb_flush(env, 1);
+        break;
+    }
+
+    env->hflags2 |= HF2_GIF_MASK;
+
+    if (int_ctl & V_IRQ_MASK) {
+        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
+    }
+
+    /* maybe we need to inject an event */
+    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (event_inj & SVM_EVTINJ_VALID) {
+        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
+        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
+        uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
+
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
+        /* FIXME: need to implement valid_err */
+        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
+        case SVM_EVTINJ_TYPE_INTR:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = -1;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
+                /* XXX: is it always correct ? */
+                do_interrupt_all(vector, 0, 0, 0, 1);
+                break;
+        case SVM_EVTINJ_TYPE_NMI:
+                env->exception_index = EXCP02_NMI;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = EIP;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
+                cpu_loop_exit(env);
+                break;
+        case SVM_EVTINJ_TYPE_EXEPT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = -1;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
+                cpu_loop_exit(env);
+                break;
+        case SVM_EVTINJ_TYPE_SOFT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 1;
+                env->exception_next_eip = EIP;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
+                cpu_loop_exit(env);
+                break;
+        }
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
+    }
+}
+
+void helper_vmmcall(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
+    raise_exception(EXCP06_ILLOP);
+}
+
+void helper_vmload(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
+                       env, R_FS);
+    svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
+                       env, R_GS);
+    svm_load_seg(addr + offsetof(struct vmcb, save.tr),
+                 &env->tr);
+    svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
+                 &env->ldt);
+
+#ifdef TARGET_X86_64
+    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
+    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
+    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
+    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
+#endif
+    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
+    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
+    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
+    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
+}
+
+void helper_vmsave(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    svm_save_seg(addr + offsetof(struct vmcb, save.fs), 
+                 &env->segs[R_FS]);
+    svm_save_seg(addr + offsetof(struct vmcb, save.gs), 
+                 &env->segs[R_GS]);
+    svm_save_seg(addr + offsetof(struct vmcb, save.tr), 
+                 &env->tr);
+    svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), 
+                 &env->ldt);
+
+#ifdef TARGET_X86_64
+    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
+    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
+    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
+    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
+#endif
+    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
+}
+
+void helper_stgi(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
+    env->hflags2 |= HF2_GIF_MASK;
+}
+
+void helper_clgi(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
+    env->hflags2 &= ~HF2_GIF_MASK;
+}
+
+void helper_skinit(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
+    /* XXX: not implemented */
+    raise_exception(EXCP06_ILLOP);
+}
+
+void helper_invlpga(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
+    
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    /* XXX: could use the ASID to see if it is needed to do the
+       flush */
+    tlb_flush_page(env, addr);
+}
+
+void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+    if (likely(!(env->hflags & HF_SVMI_MASK)))
+        return;
+    switch(type) {
+    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
+        if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
+        if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
+        if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
+        if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
+        if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_MSR:
+        if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
+            /* FIXME: this should be read in at vmrun (faster this way?) */
+            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
+            uint32_t t0, t1;
+            switch((uint32_t)ECX) {
+            case 0 ... 0x1fff:
+                t0 = (ECX * 2) % 8;
+                t1 = (ECX * 2) / 8;
+                break;
+            case 0xc0000000 ... 0xc0001fff:
+                t0 = (8192 + ECX - 0xc0000000) * 2;
+                t1 = (t0 / 8);
+                t0 %= 8;
+                break;
+            case 0xc0010000 ... 0xc0011fff:
+                t0 = (16384 + ECX - 0xc0010000) * 2;
+                t1 = (t0 / 8);
+                t0 %= 8;
+                break;
+            default:
+                helper_vmexit(type, param);
+                t0 = 0;
+                t1 = 0;
+                break;
+            }
+            if (ldub_phys(addr + t1) & ((1 << param) << t0))
+                helper_vmexit(type, param);
+        }
+        break;
+    default:
+        if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    }
+}
+
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    helper_svm_check_intercept_param(type, 0);
+    env = saved_env;
+}
+
+void helper_svm_check_io(uint32_t port, uint32_t param, 
+                         uint32_t next_eip_addend)
+{
+    if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
+        /* FIXME: this should be read in at vmrun (faster this way?) */
+        uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
+        uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
+        if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
+            /* next EIP */
+            stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 
+                     env->eip + next_eip_addend);
+            helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
+        }
+    }
+}
+
+/* Note: currently only 32 bits of exit_code are used */
+void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
+{
+    uint32_t int_ctl;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
+                exit_code, exit_info_1,
+                ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
+                EIP);
+
+    if(env->hflags & HF_INHIBIT_IRQ_MASK) {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
+        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+    } else {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
+    }
+
+    /* Save the VM state in the vmcb */
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), 
+                 &env->segs[R_ES]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), 
+                 &env->segs[R_CS]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), 
+                 &env->segs[R_SS]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), 
+                 &env->segs[R_DS]);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
+
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
+    int_ctl |= env->v_tpr & V_TPR_MASK;
+    if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
+        int_ctl |= V_IRQ_MASK;
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
+
+    /* Reload the host state from vm_hsave */
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
+    env->hflags &= ~HF_SVMI_MASK;
+    env->intercept = 0;
+    env->intercept_exceptions = 0;
+    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+    env->tsc_offset = 0;
+
+    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
+    /* we need to set the efer after the crs so the hidden flags get
+       set properly */
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
+                       env, R_ES);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
+                       env, R_CS);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
+                       env, R_SS);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
+                       env, R_DS);
+
+    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
+    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
+
+    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
+    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
+
+    /* other setups */
+    cpu_x86_set_cpl(env, 0);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
+
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
+
+    env->hflags2 &= ~HF2_GIF_MASK;
+    /* FIXME: Resets the current ASID register to zero (host ASID). */
+
+    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
+
+    /* Clears the TSC_OFFSET inside the processor. */
+
+    /* If the host is in PAE mode, the processor reloads the host's PDPEs
+       from the page table indicated the host's CR3. If the PDPEs contain
+       illegal state, the processor causes a shutdown. */
+
+    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
+    env->cr[0] |= CR0_PE_MASK;
+    env->eflags &= ~VM_MASK;
+
+    /* Disables all breakpoints in the host DR7 register. */
+
+    /* Checks the reloaded host state for consistency. */
+
+    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
+       host's code segment or non-canonical (in the case of long mode), a
+       #GP fault is delivered inside the host.) */
+
+    /* remove any pending exception */
+    env->exception_index = -1;
+    env->error_code = 0;
+    env->old_exception = -1;
+
+    cpu_loop_exit(env);
+}
+
+#endif
+
+/* MMX/SSE */
+/* XXX: optimize by storing fptt and fptags in the static cpu state */
+void helper_enter_mmx(void)
+{
+    env->fpstt = 0;
+    *(uint32_t *)(env->fptags) = 0;
+    *(uint32_t *)(env->fptags + 4) = 0;
+}
+
+void helper_emms(void)
+{
+    /* set to empty state */
+    *(uint32_t *)(env->fptags) = 0x01010101;
+    *(uint32_t *)(env->fptags + 4) = 0x01010101;
+}
+
+/* XXX: suppress */
+void helper_movq(void *d, void *s)
+{
+    *(uint64_t *)d = *(uint64_t *)s;
+}
+
+#define SHIFT 0
+#include "ops_sse.h"
+
+#define SHIFT 1
+#include "ops_sse.h"
+
+#define SHIFT 0
+#include "helper_template.h"
+#undef SHIFT
+
+#define SHIFT 1
+#include "helper_template.h"
+#undef SHIFT
+
+#define SHIFT 2
+#include "helper_template.h"
+#undef SHIFT
+
+#ifdef TARGET_X86_64
+
+#define SHIFT 3
+#include "helper_template.h"
+#undef SHIFT
+
+#endif
+
+/* bit operations */
+target_ulong helper_bsf(target_ulong t0)
+{
+    int count;
+    target_ulong res;
+
+    res = t0;
+    count = 0;
+    while ((res & 1) == 0) {
+        count++;
+        res >>= 1;
+    }
+    return count;
+}
+
+target_ulong helper_lzcnt(target_ulong t0, int wordsize)
+{
+    int count;
+    target_ulong res, mask;
+
+    if (wordsize > 0 && t0 == 0) {
+        return wordsize;
+    }
+    res = t0;
+    count = TARGET_LONG_BITS - 1;
+    mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
+    while ((res & mask) == 0) {
+        count--;
+        res <<= 1;
+    }
+    if (wordsize > 0) {
+        return wordsize - 1 - count;
+    }
+    return count;
+}
+
+target_ulong helper_bsr(target_ulong t0)
+{
+       return helper_lzcnt(t0, 0);
+}
+
+static int compute_all_eflags(void)
+{
+    return CC_SRC;
+}
+
+static int compute_c_eflags(void)
+{
+    return CC_SRC & CC_C;
+}
+
+uint32_t helper_cc_compute_all(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
+
+    case CC_OP_EFLAGS: return compute_all_eflags();
+
+    case CC_OP_MULB: return compute_all_mulb();
+    case CC_OP_MULW: return compute_all_mulw();
+    case CC_OP_MULL: return compute_all_mull();
+
+    case CC_OP_ADDB: return compute_all_addb();
+    case CC_OP_ADDW: return compute_all_addw();
+    case CC_OP_ADDL: return compute_all_addl();
+
+    case CC_OP_ADCB: return compute_all_adcb();
+    case CC_OP_ADCW: return compute_all_adcw();
+    case CC_OP_ADCL: return compute_all_adcl();
+
+    case CC_OP_SUBB: return compute_all_subb();
+    case CC_OP_SUBW: return compute_all_subw();
+    case CC_OP_SUBL: return compute_all_subl();
+
+    case CC_OP_SBBB: return compute_all_sbbb();
+    case CC_OP_SBBW: return compute_all_sbbw();
+    case CC_OP_SBBL: return compute_all_sbbl();
+
+    case CC_OP_LOGICB: return compute_all_logicb();
+    case CC_OP_LOGICW: return compute_all_logicw();
+    case CC_OP_LOGICL: return compute_all_logicl();
+
+    case CC_OP_INCB: return compute_all_incb();
+    case CC_OP_INCW: return compute_all_incw();
+    case CC_OP_INCL: return compute_all_incl();
+
+    case CC_OP_DECB: return compute_all_decb();
+    case CC_OP_DECW: return compute_all_decw();
+    case CC_OP_DECL: return compute_all_decl();
+
+    case CC_OP_SHLB: return compute_all_shlb();
+    case CC_OP_SHLW: return compute_all_shlw();
+    case CC_OP_SHLL: return compute_all_shll();
+
+    case CC_OP_SARB: return compute_all_sarb();
+    case CC_OP_SARW: return compute_all_sarw();
+    case CC_OP_SARL: return compute_all_sarl();
+
+#ifdef TARGET_X86_64
+    case CC_OP_MULQ: return compute_all_mulq();
+
+    case CC_OP_ADDQ: return compute_all_addq();
+
+    case CC_OP_ADCQ: return compute_all_adcq();
+
+    case CC_OP_SUBQ: return compute_all_subq();
+
+    case CC_OP_SBBQ: return compute_all_sbbq();
+
+    case CC_OP_LOGICQ: return compute_all_logicq();
+
+    case CC_OP_INCQ: return compute_all_incq();
+
+    case CC_OP_DECQ: return compute_all_decq();
+
+    case CC_OP_SHLQ: return compute_all_shlq();
+
+    case CC_OP_SARQ: return compute_all_sarq();
+#endif
+    }
+}
+
+uint32_t cpu_cc_compute_all(CPUState *env1, int op)
+{
+    CPUState *saved_env;
+    uint32_t ret;
+
+    saved_env = env;
+    env = env1;
+    ret = helper_cc_compute_all(op);
+    env = saved_env;
+    return ret;
+}
+
+uint32_t helper_cc_compute_c(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
+
+    case CC_OP_EFLAGS: return compute_c_eflags();
+
+    case CC_OP_MULB: return compute_c_mull();
+    case CC_OP_MULW: return compute_c_mull();
+    case CC_OP_MULL: return compute_c_mull();
+
+    case CC_OP_ADDB: return compute_c_addb();
+    case CC_OP_ADDW: return compute_c_addw();
+    case CC_OP_ADDL: return compute_c_addl();
+
+    case CC_OP_ADCB: return compute_c_adcb();
+    case CC_OP_ADCW: return compute_c_adcw();
+    case CC_OP_ADCL: return compute_c_adcl();
+
+    case CC_OP_SUBB: return compute_c_subb();
+    case CC_OP_SUBW: return compute_c_subw();
+    case CC_OP_SUBL: return compute_c_subl();
+
+    case CC_OP_SBBB: return compute_c_sbbb();
+    case CC_OP_SBBW: return compute_c_sbbw();
+    case CC_OP_SBBL: return compute_c_sbbl();
+
+    case CC_OP_LOGICB: return compute_c_logicb();
+    case CC_OP_LOGICW: return compute_c_logicw();
+    case CC_OP_LOGICL: return compute_c_logicl();
+
+    case CC_OP_INCB: return compute_c_incl();
+    case CC_OP_INCW: return compute_c_incl();
+    case CC_OP_INCL: return compute_c_incl();
+
+    case CC_OP_DECB: return compute_c_incl();
+    case CC_OP_DECW: return compute_c_incl();
+    case CC_OP_DECL: return compute_c_incl();
+
+    case CC_OP_SHLB: return compute_c_shlb();
+    case CC_OP_SHLW: return compute_c_shlw();
+    case CC_OP_SHLL: return compute_c_shll();
+
+    case CC_OP_SARB: return compute_c_sarl();
+    case CC_OP_SARW: return compute_c_sarl();
+    case CC_OP_SARL: return compute_c_sarl();
+
+#ifdef TARGET_X86_64
+    case CC_OP_MULQ: return compute_c_mull();
+
+    case CC_OP_ADDQ: return compute_c_addq();
+
+    case CC_OP_ADCQ: return compute_c_adcq();
+
+    case CC_OP_SUBQ: return compute_c_subq();
+
+    case CC_OP_SBBQ: return compute_c_sbbq();
+
+    case CC_OP_LOGICQ: return compute_c_logicq();
+
+    case CC_OP_INCQ: return compute_c_incl();
+
+    case CC_OP_DECQ: return compute_c_incl();
+
+    case CC_OP_SHLQ: return compute_c_shlq();
+
+    case CC_OP_SARQ: return compute_c_sarl();
+#endif
+    }
+}
diff --git a/tizen/src/hw/opengl_exec.c b/tizen/src/hw/opengl_exec.c
new file mode 100755 (executable)
index 0000000..4721199
--- /dev/null
@@ -0,0 +1,3353 @@
+/*
+ *  Host-side implementation of GL/GLX API
+ *
+ *  Copyright (c) 2006,2007 Even Rouault
+ *
+ *  modified by:
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h> // for pid_t
+
+#include "qemu-common.h"
+
+/* GW: dyngen-exec.h defines its own version of stuff that is in stdio.h - 
+   only it misses things and is mildly different to stdio \o/. Hence
+   don't include stdio and make our own defines. */
+
+/*
+#ifdef DEBUG_GL
+#ifdef _WIN32
+#define DEBUGF(...) printf(__VA_ARGS__)
+#else
+#define DEBUGF(...) fprintf(stderr, __VA_ARGS__)
+#endif
+#else
+#define DEBUGF(...) while(0) {printf(__VA_ARGS__); }
+#endif
+*/
+#include "tizen/src/debug_ch.h"
+MULTI_DEBUG_CHANNEL(qemu, opengl);
+#define DEBUGF         TRACE
+
+#define GL_GLEXT_PROTOTYPES
+#define GLX_GLXEXT_PROTOTYPES
+#include <mesa_gl.h>
+
+#include "qemu-queue.h"
+#include "opengl_func.h"
+#include "mesa_mipmap.h"
+#include "opengl_process.h"
+#include "range_alloc.h"
+#include "gloffscreen.h"
+
+
+/** Misc X11/GLX defines - we don't want to include the whole files for these
+ * as we need them on Windows too */
+typedef int Bool;
+const Bool True = 1;
+const Bool False = 0;
+typedef struct __GLXFBConfigRec GLXFBConfig;
+struct __GLXFBConfigRec {
+  int formatFlags;
+};
+
+// #defines from glx.h
+#define GLX_VENDOR              1
+#define GLX_VERSION             2
+#define GLX_EXTENSIONS          3
+
+/* We'll say the XVisual Id is actually just an index into here */
+const GLXFBConfig FBCONFIGS[] = {
+    {GLO_FF_ALPHA|GLO_FF_BITS_32},
+    {GLO_FF_ALPHA|GLO_FF_BITS_32|GLO_FF_DEPTH_24},
+    {GLO_FF_ALPHA|GLO_FF_BITS_32|GLO_FF_DEPTH_24|GLO_FF_STENCIL_8},
+/*
+    {GLO_FF_BITS_32},
+    {GLO_FF_BITS_32|GLO_FF_DEPTH_24},
+    {GLO_FF_BITS_32|GLO_FF_DEPTH_24|GLO_FF_STENCIL_8},
+
+    {GLO_FF_BITS_24},
+    {GLO_FF_BITS_24|GLO_FF_DEPTH_24},
+    {GLO_FF_BITS_24|GLO_FF_DEPTH_24|GLO_FF_STENCIL_8},
+*/
+/*
+    {GLO_FF_BITS_16},
+    {GLO_FF_BITS_16|GLO_FF_DEPTH_24},
+    {GLO_FF_BITS_16|GLO_FF_DEPTH_24|GLO_FF_STENCIL_8},*/
+};
+
+#define FAKE_GL_VENDOR     "Qemu"
+#define FAKE_GL_RENDERER   "VMGL Passthrough"
+#define FAKE_GL_VERSION    "1.4"
+#define FAKE_GL_MAJOR      1
+
+
+#define FAKE_GLX_VENDOR     "Qemu"
+#define FAKE_GLX_VERSION_STRING "1.2"
+#define FAKE_GLX_VERSION_MAJOR 1
+#define FAKE_GLX_VERSION_MINOR 2
+
+void *g_malloc(size_t size);
+void *g_realloc(void *ptr, size_t size);
+void g_free(void *ptr);
+
+#define glGetError() 0
+
+#define GET_EXT_PTR(type, funcname, args_decl) \
+    static int detect_##funcname = 0; \
+    static type(*ptr_func_##funcname)args_decl = NULL; \
+    if (detect_##funcname == 0) \
+    { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type(*)args_decl)glo_getprocaddress((const char*)#funcname); \
+        assert (ptr_func_##funcname); \
+    }
+
+#define GET_EXT_PTR_NO_FAIL(type, funcname, args_decl) \
+    static int detect_##funcname = 0; \
+    static type(*ptr_func_##funcname)args_decl = NULL; \
+    if (detect_##funcname == 0) \
+    { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type(*)args_decl)glo_getprocaddress((const char*)#funcname); \
+    }
+
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+
+static void *get_glu_ptr(const char *name)
+{
+    static void *handle = (void *) -1;
+
+    if (handle == (void *) -1) {
+#ifndef WIN32
+        handle = dlopen("libGLU.so", RTLD_LAZY);
+        if (!handle)
+            DEBUGF("can't load libGLU.so : %s\n", dlerror());
+#else
+        handle = (void *) LoadLibrary("glu32.dll");
+        if (!handle)
+            DEBUGF("can't load glu32.dll\n");
+#endif
+    }
+    if (handle) {
+#ifndef WIN32
+        return dlsym(handle, name);
+#else
+        return GetProcAddress(handle, name);
+#endif
+    }
+    return NULL;
+}
+
+#define GET_GLU_PTR(type, funcname, args_decl) \
+    static int detect_##funcname = 0; \
+    static type(*ptr_func_##funcname)args_decl = NULL; \
+    if (detect_##funcname == 0) \
+    { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type(*)args_decl)get_glu_ptr(#funcname); \
+    }
+
+int display_function_call = 0;
+extern int kill_process;
+
+typedef struct {
+    void *key;
+    void *value;
+} Assoc;
+
+#define MAX_HANDLED_PROCESS 100
+#define MAX_ASSOC_SIZE 100
+
+#define MAX_FBCONFIG 10
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define DIM(X) (sizeof(X) / sizeof(X[0]))
+
+typedef struct {
+    GLbitfield mask;
+    int activeTextureIndex;
+} ClientState;
+
+#define MAX_CLIENT_STATE_STACK_SIZE 16
+
+typedef void *ClientGLXDrawable;
+
+typedef struct GLState GLState;
+
+typedef struct QGloSurface {
+    GLState *glstate;
+    GloSurface *surface;
+    ClientGLXDrawable *client_drawable;
+    int ready;
+    int ref;
+    QTAILQ_ENTRY(QGloSurface) next;
+} QGloSurface;
+
+struct GLState {
+    int ref;
+    int fake_ctxt;
+    int fake_shareList;
+
+    GloContext *context; // context (owned by this)
+    QGloSurface *current_qsurface; // current rendering surface/drawable
+    QTAILQ_HEAD(, QGloSurface) qsurfaces; // list of surfaces/drawables for
+                                          // this context
+
+    void *vertexPointer;
+    void *normalPointer;
+    void *colorPointer;
+    void *secondaryColorPointer;
+    void *indexPointer;
+    void *texCoordPointer[NB_MAX_TEXTURES];
+    void *edgeFlagPointer;
+    void *vertexAttribPointer[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+    void *vertexAttribPointerNV[MY_GL_MAX_VERTEX_ATTRIBS_NV];
+    void *weightPointer;
+    void *matrixIndexPointer;
+    void *fogCoordPointer;
+    void *variantPointerEXT[MY_GL_MAX_VARIANT_POINTER_EXT];
+    void *interleavedArrays;
+    void *elementPointerATI;
+
+    int vertexPointerSize;
+    int normalPointerSize;
+    int colorPointerSize;
+    int secondaryColorPointerSize;
+    int indexPointerSize;
+    int texCoordPointerSize[NB_MAX_TEXTURES];
+    int edgeFlagPointerSize;
+    int vertexAttribPointerSize[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+    int vertexAttribPointerNVSize[MY_GL_MAX_VERTEX_ATTRIBS_NV];
+    int weightPointerSize;
+    int matrixIndexPointerSize;
+    int fogCoordPointerSize;
+    int variantPointerEXTSize[MY_GL_MAX_VARIANT_POINTER_EXT];
+    int interleavedArraysSize;
+    int elementPointerATISize;
+
+    int selectBufferSize;
+    void *selectBufferPtr;
+    int feedbackBufferSize;
+    void *feedbackBufferPtr;
+
+    ClientState clientStateStack[MAX_CLIENT_STATE_STACK_SIZE];
+    int clientStateSp;
+    int activeTextureIndex;
+
+    unsigned int ownTabTextures[32768];
+    unsigned int *tabTextures;
+    RangeAllocator ownTextureAllocator;
+    RangeAllocator *textureAllocator;
+
+    unsigned int ownTabBuffers[32768];
+    unsigned int *tabBuffers;
+    RangeAllocator ownBufferAllocator;
+    RangeAllocator *bufferAllocator;
+
+    unsigned int ownTabLists[32768];
+    unsigned int *tabLists;
+    RangeAllocator ownListAllocator;
+    RangeAllocator *listAllocator;
+
+};
+
+typedef struct {
+    ProcessStruct p;
+
+    int next_available_context_number;
+
+    int nb_states;
+    GLState default_state;
+    GLState **glstates;
+    GLState *current_state;
+
+    int nfbconfig;
+    const GLXFBConfig *fbconfigs[MAX_FBCONFIG];
+    int fbconfigs_max[MAX_FBCONFIG];
+    int nfbconfig_total;
+
+    int primitive;
+    int bufsize;
+    int bufstart;
+    arg_t *cmdbuf;
+} ProcessState;
+
+static ProcessState processes[MAX_HANDLED_PROCESS];
+
+static char *strip_extensions(const char *avail, const char *ext[]) {
+    char *pos, *supported, *srcp;
+
+    supported = (char *)g_malloc(strlen(avail) + 2);
+
+    pos = supported;
+    while(*ext) {
+        srcp = (char*)avail;
+        while((srcp = strstr(srcp, *ext))) {
+            int len = strlen(*ext);
+            if(*(srcp+len) == ' ' || *(srcp+len) == '\0') {
+                strcpy(pos, *ext);
+                pos += len;
+                if(*(srcp+len) == ' ') {
+                    *pos = ' ';
+                    pos++;
+                }
+                break;
+            }
+            srcp += len;
+        }
+        ext++;
+    }
+    *pos = ' ';
+    *pos = '\0';
+
+  return supported;
+}
+
+static const char *glx_ext_supported[] = {
+    "GLX_ARB_multisample",
+    0
+};
+
+static char *supported_glx_extensions() {
+    static char *supported;
+
+    if(!supported)
+      supported = strip_extensions(glo_glXQueryExtensionsString(),
+                                   glx_ext_supported);
+
+    return supported;
+}
+
+static const char *gl_ext_supported[] = {
+// Mandatory OpenGL 1.4 Extensions
+    "GL_ARB_depth_texture",
+    "GL_ARB_multisample",
+    "GL_ARB_multitexture",
+    "GL_ARB_point_parameters",
+    "GL_ARB_shadow",
+    "GL_ARB_texture_border_clamp",
+    "GL_ARB_texture_compression",
+    "GL_ARB_texture_cube_map",
+    "GL_ARB_texture_env_add",
+    "GL_ARB_texture_env_combine",
+    "GL_ARB_texture_env_crossbar",
+    "GL_ARB_texture_env_dot3",
+    "GL_ARB_texture_mirrored_repeat",
+    "GL_ARB_transpose_matrix",
+    "GL_ARB_window_pos",
+    "GL_EXT_bgra",
+    "GL_EXT_blend_color",
+    "GL_EXT_blend_func_separate",
+    "GL_EXT_blend_logic_op",
+    "GL_EXT_blend_minmax",
+    "GL_EXT_blend_subtract",
+    "GL_EXT_copy_texture",
+    "GL_EXT_draw_range_elements",
+    "GL_EXT_fog_coord",
+    "GL_EXT_multi_draw_arrays",
+    "GL_EXT_packed_pixels",
+    "GL_EXT_point_parameters",
+    "GL_EXT_polygon_offset",
+    "GL_EXT_rescale_normal",
+    "GL_EXT_secondary_color",
+    "GL_EXT_separate_specular_color",
+    "GL_EXT_stencil_wrap",
+    "GL_EXT_subtexture",
+    "GL_EXT_texture",
+    "GL_EXT_texture3D",
+    "GL_EXT_texture_edge_clamp",
+    "GL_EXT_texture_env_add",
+    "GL_EXT_texture_env_combine",
+    "GL_EXT_texture_lod",
+    "GL_EXT_texture_lod_bias",
+    "GL_EXT_texture_object",
+    "GL_APPLE_packed_pixels",
+    "GL_NV_blend_square",
+    "GL_SGIS_generate_mipmap",
+    "GL_SGIS_texture_border_clamp",
+    "GL_SGIS_texture_edge_clamp",
+    "GL_SGIS_texture_lod",
+// Optional extensions. If you get problems try disabling the below.
+    "GL_EXT_compiled_vertex_array",
+    "GL_ARB_copy_buffer",
+    "GL_ARB_depth_clamp",
+    "GL_ARB_draw_buffers ",
+    "GL_ARB_draw_elements_base_vertex",
+    "GL_ARB_fragment_program",
+    "GL_ARB_fragment_program_shadow",
+    "GL_ARB_fragment_shader",
+    "GL_ARB_framebuffer_object",
+    "GL_ARB_half_float_pixel",
+    "GL_ARB_map_buffer_range",                                           
+    "GL_ARB_occlusion_query",
+    "GL_ARB_pixel_buffer_object",
+    "GL_ARB_point_sprite",
+    "GL_ARB_provoking_vertex",
+    "GL_ARB_seamless_cube_map",
+    "GL_ARB_shader_objects",
+    "GL_ARB_shading_language_100",
+    "GL_ARB_shading_language_120",
+    "GL_ARB_sync",                                                           
+    "GL_ARB_texture_non_power_of_two",
+    "GL_ARB_texture_rectangle",
+    "GL_ARB_vertex_array_bgra",                           
+    "GL_ARB_vertex_array_object",
+    "GL_ARB_vertex_buffer_object",
+    "GL_ARB_vertex_program",
+    "GL_ARB_vertex_shader,"
+    "GL_EXT_abgr",
+    "GL_EXT_blend_equation_separate",
+    "GL_EXT_cull_vertex",
+    "GL_EXT_framebuffer_blit",
+    "GL_EXT_framebuffer_object",
+    "GL_EXT_gpu_program_parameters",                            
+    "GL_EXT_packed_depth_stencil",                        
+    "GL_EXT_pixel_buffer_object",
+    "GL_EXT_provoking_vertex",
+    "GL_EXT_shadow_funcs",
+    "GL_EXT_stencil_two_side",
+    "GL_EXT_texture_cube_map",   
+    "GL_EXT_texture_env_dot3",                              
+    "GL_EXT_texture_filter_anisotropic",
+    "GL_EXT_texture_rectangle",
+    "GL_EXT_texture_sRGB",
+    "GL_EXT_texture_swizzle",
+    "GL_EXT_vertex_array",
+    "GL_EXT_vertex_array_bgra",
+    "GL_3DFX_texture_compression_FXT1",
+    "GL_APPLE_client_storage",
+    "GL_APPLE_vertex_array_object",                          
+    "GL_ATI_blend_equation_separate",
+    "GL_ATI_envmap_bumpmap",
+    "GL_ATI_texture_env_combine3",
+    "GL_ATI_separate_stencil",
+    "GL_IBM_multimode_draw_arrays",
+    "GL_IBM_rasterpos_clip",
+    "GL_IBM_texture_mirrored_repeat",
+    "GL_INGR_blend_func_separate", 
+    "GL_MESA_pack_invert",
+    "GL_MESA_texture_signed_rgba",
+    "GL_MESA_ycbcr_texture",
+    "GL_MESA_window_pos",
+    "GL_NV_depth_clamp",
+    "GL_NV_light_max_exponent",
+    "GL_NV_packed_depth_stencil",
+    "GL_NV_texture_env_combine4",
+    "GL_NV_texture_rectangle",
+    "GL_NV_texgen_reflection",
+    "GL_NV_vertex_program",
+    "GL_NV_vertex_program1_1",
+    "GL_OES_read_format",
+    "GL_SUN_multi_draw_arrays",
+    0
+};
+
+static char *compute_gl_extensions() {
+    static char *supported;
+
+    if(!supported)
+        supported = strip_extensions((const char *)glGetString(GL_EXTENSIONS),
+                                     gl_ext_supported);
+
+    return supported;
+}
+
+static inline QGloSurface *get_qsurface_from_client_drawable(GLState *state, ClientGLXDrawable client_drawable) {
+    QGloSurface *qsurface;
+
+    if(state->current_qsurface->client_drawable == client_drawable)
+        return state->current_qsurface;
+
+    QTAILQ_FOREACH(qsurface, &state->qsurfaces, next) {
+        if (qsurface->client_drawable == client_drawable)
+            return qsurface;
+    }
+
+    return NULL;
+}
+
+// This must always be called only on surfaces belonging to the current context
+static inline void render_surface(QGloSurface *qsurface, int bpp, int stride, char *buffer)
+{
+    int w, h;
+    if(!qsurface->ready)
+       return;
+
+    glo_surface_get_size(qsurface->surface, &w, &h);
+
+    glo_surface_getcontents(qsurface->surface, stride, bpp, buffer);
+}
+
+// This must always be called only on surfaces belonging to the current context
+static inline void resize_surface(ProcessState *process, QGloSurface *qsurface,
+                                  int w, int h) {
+    GLState *glstate = qsurface->glstate;
+    GloSurface *old_surface = qsurface->surface;
+    GloSurface *surface;
+
+    DEBUGF("resize_start\n");
+
+    glo_surface_destroy(old_surface);
+
+    surface = glo_surface_create(w, h, glstate->context);
+    qsurface->surface = surface;
+
+    // Client doesnt know surface is new - need to MakeCurrent
+    if(process->current_state == qsurface->glstate) {
+        glo_surface_makecurrent(qsurface->surface);
+        // set the viewport while the window size is changed. It is needed
+        // especially for the case that glViewport is not explicitly called
+        // in program. In this case, the viewport is set to incorrectly
+        // in the first MakeCurrent when the window size is not known.
+        // It will not impact normal GL programs with glViewport set as 
+        // programmers want.
+        glViewport (0, 0, w, h);
+    }
+    else {
+        DEBUGF("Error: Surface is not current! %p %p\n",
+               process->current_state,
+               process->current_state->current_qsurface);
+        exit(1);
+    }
+
+    glstate->current_qsurface->ready = 1;
+    DEBUGF( "resize_done\n");
+}
+
+
+void init_process_tab()
+{
+    memset(processes, 0, sizeof(processes));
+}
+
+#define ARG_TO_CHAR(x)                (char)(x)
+#define ARG_TO_UNSIGNED_CHAR(x)       (unsigned char)(x)
+#define ARG_TO_SHORT(x)               (short)(x)
+#define ARG_TO_UNSIGNED_SHORT(x)      (unsigned short)(x)
+#define ARG_TO_INT(x)                 (int)(x)
+#define ARG_TO_UNSIGNED_INT(x)        (unsigned int)(x)
+#define ARG_TO_FLOAT(x)               (*(float*)&(x))
+#define ARG_TO_DOUBLE(x)              (*(double*)(x))
+
+#include "server_stub.c"
+
+//typedef void *ClientGLXDrawable;
+static inline ClientGLXDrawable to_drawable(arg_t arg)
+{
+#ifdef TARGET_X86_64
+    if (arg > (unsigned long) -1) {
+        DEBUGF( "GLXDrawable too big for this implementation\n");
+        exit(-1);
+    }
+#endif
+    return (void *) (unsigned long) arg;
+}
+
+/* ---- */
+
+/* Bind a qsurface to a context (GLState) */
+static void bind_qsurface(GLState *state,
+                          QGloSurface *qsurface)
+{
+    qsurface->glstate = state;
+
+    QTAILQ_INSERT_HEAD(&state->qsurfaces, qsurface, next);
+
+    state->current_qsurface = qsurface;
+}
+
+/* Make the appropriate qsurface current for a given client_drawable */
+static int set_current_qsurface(GLState *state,
+                                ClientGLXDrawable client_drawable)
+{
+    QGloSurface *qsurface;
+
+    if(state->current_qsurface && state->current_qsurface->client_drawable == client_drawable)
+        return 1;
+
+    QTAILQ_FOREACH(qsurface, &state->qsurfaces, next) {
+        if(qsurface->client_drawable == client_drawable) {
+            state->current_qsurface = qsurface;
+            return 1;
+        }
+    }
+
+    state->current_qsurface = NULL;
+
+    return 0;
+}
+
+static int get_server_texture(ProcessState *process,
+                              unsigned int client_texture)
+{
+    unsigned int server_texture = 0;
+
+    if (client_texture < 32768) {
+        server_texture = process->current_state->tabTextures[client_texture];
+    } else {
+        DEBUGF( "invalid texture name %d\n", client_texture);
+    }
+    return server_texture;
+}
+
+static int get_server_buffer(ProcessState *process,
+                             unsigned int client_buffer)
+{
+    unsigned int server_buffer = 0;
+
+    if (client_buffer < 32768) {
+        server_buffer = process->current_state->tabBuffers[client_buffer];
+    } else {
+        DEBUGF( "invalid buffer name %d\n", client_buffer);
+    }
+    return server_buffer;
+}
+
+
+static int get_server_list(ProcessState *process, unsigned int client_list)
+{
+    unsigned int server_list = 0;
+
+    if (client_list < 32768) {
+        server_list = process->current_state->tabLists[client_list];
+    } else {
+        DEBUGF( "invalid list name %d\n", client_list);
+    }
+    return server_list;
+}
+
+const GLXFBConfig *get_fbconfig(ProcessState *process, int client_fbconfig)
+{
+    int i;
+    int nbtotal = 0;
+
+    for (i = 0; i < process->nfbconfig; i++) {
+        assert(client_fbconfig >= 1 + nbtotal);
+        if (client_fbconfig <= nbtotal + process->fbconfigs_max[i]) {
+            return &process->fbconfigs[i][client_fbconfig - 1 - nbtotal];
+        }
+        nbtotal += process->fbconfigs_max[i];
+    }
+    return 0;
+}
+
+static int glXChooseVisualFunc(const int *attrib_list)
+{
+    if (attrib_list == NULL)
+        return 0;
+
+    int formatFlags = glo_flags_get_from_glx(attrib_list, True);
+    int i;
+    int bestConfig = 0;
+    int bestScore = -1;
+
+    for (i=0;i<DIM(FBCONFIGS);i++) {
+        int score = glo_flags_score(formatFlags, FBCONFIGS[i].formatFlags);
+        if (bestScore < 0 || score<=bestScore) {
+            bestScore = score;
+            bestConfig = i;
+        }
+    }
+
+    if (bestScore > 0)
+        DEBUGF( "Got format flags %d but we couldn't find an exactly matching config, chose %d\n", formatFlags, bestConfig);
+
+    return bestConfig;
+}
+
+static int glXGetConfigFunc(int visualid, int attrib, int *value) {
+    const GLXFBConfig *config = &FBCONFIGS[0]; // default
+    int v;
+
+    if (visualid>=0 && visualid<DIM(FBCONFIGS))
+        config = &FBCONFIGS[visualid];
+    else
+        DEBUGF( "Unknown visual ID %d\n", visualid);
+
+    v = glo_get_glx_from_flags(config->formatFlags, attrib);
+    if (value)
+       *value = v;
+    return 0;
+}
+
+static const GLXFBConfig * glXGetFBConfigsFunc(int screen, int *nelements) {
+    *nelements = DIM(FBCONFIGS);
+    return &FBCONFIGS[0];
+}
+
+static int glXGetFBConfigAttribFunc(const GLXFBConfig *fbconfig, int attrib, int *value) {
+    // TODO other enums - see http://www.opengl.org/sdk/docs/man/xhtml/glXGetFBConfigAttrib.xml
+
+    int v = glo_get_glx_from_flags(fbconfig->formatFlags, attrib);
+    if (value) *value = v;
+    return 0;
+}
+
+static const GLXFBConfig *glXChooseFBConfigFunc(int screen, const int *attrib_list, int *nelements) {
+    if (attrib_list != NULL) {
+        int formatFlags = glo_flags_get_from_glx(attrib_list, False);
+        int i;
+        int bestConfig = 0;
+        int bestScore = -1;
+
+        for (i=0;i<DIM(FBCONFIGS);i++) {
+            int score = glo_flags_score(formatFlags, FBCONFIGS[i].formatFlags);
+            if (bestScore < 0 || score<=bestScore) {
+                bestScore = score;
+                bestConfig = i;
+            }
+        }
+
+        if (bestScore > 0) {
+            DEBUGF( "Got format flags %d but we couldn't find an exactly matching config, chose %d\n", formatFlags, bestConfig);
+        }
+
+        if (nelements)
+            *nelements=1;
+
+        return &FBCONFIGS[bestConfig];
+    }
+
+    if (nelements)
+        *nelements=0;
+
+    return 0;
+}
+
+static void do_glClientActiveTextureARB(int texture)
+{
+    GET_EXT_PTR_NO_FAIL(void, glClientActiveTextureARB, (int));
+
+    if (ptr_func_glClientActiveTextureARB) {
+        ptr_func_glClientActiveTextureARB(texture);
+    }
+}
+
+static void destroy_gl_state(GLState *state)
+{
+    int i;
+    QGloSurface *qsurface, *tmp;
+
+    QTAILQ_FOREACH_SAFE(qsurface, &state->qsurfaces, next, tmp) {
+        glo_surface_destroy(qsurface->surface);
+        QTAILQ_REMOVE(&state->qsurfaces, qsurface, next);
+        g_free(qsurface);
+    }
+        
+    if (state->context)
+      glo_context_destroy(state->context);
+
+    if (state->vertexPointer)
+        g_free(state->vertexPointer);
+    if (state->normalPointer)
+        g_free(state->normalPointer);
+    if (state->indexPointer)
+        g_free(state->indexPointer);
+    if (state->colorPointer)
+        g_free(state->colorPointer);
+    if (state->secondaryColorPointer)
+        g_free(state->secondaryColorPointer);
+    for (i = 0; i < NB_MAX_TEXTURES; i++) {
+        if (state->texCoordPointer[i])
+            g_free(state->texCoordPointer[i]);
+    }
+    for (i = 0; i < MY_GL_MAX_VERTEX_ATTRIBS_ARB; i++) {
+        if (state->vertexAttribPointer[i])
+            g_free(state->vertexAttribPointer[i]);
+    }
+    for (i = 0; i < MY_GL_MAX_VERTEX_ATTRIBS_NV; i++) {
+        if (state->vertexAttribPointerNV[i])
+            g_free(state->vertexAttribPointerNV[i]);
+    }
+    if (state->weightPointer)
+        g_free(state->weightPointer);
+    if (state->matrixIndexPointer)
+        g_free(state->matrixIndexPointer);
+    if (state->fogCoordPointer)
+        g_free(state->fogCoordPointer);
+    for (i = 0; i < MY_GL_MAX_VARIANT_POINTER_EXT; i++) {
+        if (state->variantPointerEXT[i])
+            g_free(state->variantPointerEXT[i]);
+    }
+    if (state->interleavedArrays)
+        g_free(state->interleavedArrays);
+    if (state->elementPointerATI)
+        g_free(state->elementPointerATI);
+}
+
+static void init_gl_state(GLState *state)
+{
+    state->textureAllocator = &state->ownTextureAllocator;
+    state->tabTextures = state->ownTabTextures;
+    state->bufferAllocator = &state->ownBufferAllocator;
+    state->tabBuffers = state->ownTabBuffers;
+    state->listAllocator = &state->ownListAllocator;
+    state->tabLists = state->ownTabLists;
+}
+
+/*
+ * Translate the nth element of list from type to GLuint.
+ */
+static GLuint translate_id(GLsizei n, GLenum type, const GLvoid *list)
+{
+    GLbyte *bptr;
+    GLubyte *ubptr;
+    GLshort *sptr;
+    GLushort *usptr;
+    GLint *iptr;
+    GLuint *uiptr;
+    GLfloat *fptr;
+
+    switch (type) {
+    case GL_BYTE:
+        bptr = (GLbyte *) list;
+        return (GLuint) *(bptr + n);
+    case GL_UNSIGNED_BYTE:
+        ubptr = (GLubyte *) list;
+        return (GLuint) *(ubptr + n);
+    case GL_SHORT:
+        sptr = (GLshort *) list;
+        return (GLuint) *(sptr + n);
+    case GL_UNSIGNED_SHORT:
+        usptr = (GLushort *) list;
+        return (GLuint) *(usptr + n);
+    case GL_INT:
+        iptr = (GLint *) list;
+        return (GLuint) *(iptr + n);
+    case GL_UNSIGNED_INT:
+        uiptr = (GLuint *) list;
+        return (GLuint) *(uiptr + n);
+    case GL_FLOAT:
+        fptr = (GLfloat *) list;
+        return (GLuint) *(fptr + n);
+    case GL_2_BYTES:
+        ubptr = ((GLubyte *) list) + 2 * n;
+        return (GLuint) (*ubptr << 8) + (GLuint) *(ubptr + 1);
+    case GL_3_BYTES:
+        ubptr = ((GLubyte *) list) + 3 * n;
+        return (GLuint) (*ubptr << 16) + (GLuint) (*(ubptr + 1) << 8) +
+            (GLuint) *(ubptr + 2);
+    case GL_4_BYTES:
+        ubptr = ((GLubyte *) list) + 4 * n;
+        return (GLuint) (*ubptr << 24) + (GLuint) (*(ubptr + 1) << 16) +
+            (GLuint) (*(ubptr + 2) << 8) + (GLuint) *(ubptr + 3);
+    default:
+        return 0;
+    }
+}
+
+GLState *_create_context(ProcessState *process, int fake_ctxt, int fake_shareList)
+{
+    // FIXMEIM - realloc? really?
+    process->glstates = g_realloc(process->glstates,
+                                  (process->nb_states + 1) * sizeof(GLState *));
+
+    process->glstates[process->nb_states] = g_malloc(sizeof(GLState));
+    memset(process->glstates[process->nb_states], 0, sizeof(GLState));
+
+    process->glstates[process->nb_states]->ref = 1;
+    process->glstates[process->nb_states]->fake_ctxt = fake_ctxt;
+    process->glstates[process->nb_states]->fake_shareList = fake_shareList;
+
+    init_gl_state(process->glstates[process->nb_states]);
+
+    if (fake_shareList) {
+        int i;
+
+        for (i = 0; i < process->nb_states; i++) {
+            if (process->glstates[i]->fake_ctxt == fake_shareList) {
+                process->glstates[i]->ref++;
+                process->glstates[process->nb_states]->textureAllocator =
+                    process->glstates[i]->textureAllocator;
+                process->glstates[process->nb_states]->tabTextures =
+                    process->glstates[i]->tabTextures;
+                process->glstates[process->nb_states]->bufferAllocator =
+                    process->glstates[i]->bufferAllocator;
+                process->glstates[process->nb_states]->tabBuffers =
+                    process->glstates[i]->tabBuffers;
+                process->glstates[process->nb_states]->listAllocator =
+                    process->glstates[i]->listAllocator;
+                process->glstates[process->nb_states]->tabLists =
+                    process->glstates[i]->tabLists;
+                break;
+            }
+        }
+    }
+    process->nb_states++;
+
+    return process->glstates[process->nb_states-1];
+}
+
+GLState *get_glstate_for_fake_ctxt(ProcessState *process, int fake_ctxt)
+{
+    int i;
+    for (i = 0; i < process->nb_states; i++)
+        if (process->glstates[i]->fake_ctxt == fake_ctxt)
+            return process->glstates[i];
+    return 0;
+}
+
+void gl_disconnect(ProcessState *process)
+{
+    int i;
+    for (i = 0; i < process->nb_states; i++) {
+        destroy_gl_state(process->glstates[i]);
+        g_free(process->glstates[i]);
+    }
+    destroy_gl_state(&process->default_state);
+    g_free(process->glstates);
+
+    if (process->cmdbuf)
+        g_free(process->cmdbuf);
+
+    for (i = 0; &processes[i] != process; i ++);
+        memmove(&processes[i], &processes[i + 1],
+                (MAX_HANDLED_PROCESS - 1 - i) * sizeof(ProcessState));
+}
+
+static const int beginend_allowed[GL_N_CALLS] = {
+#undef MAGIC_MACRO
+#define MAGIC_MACRO(name) [name ## _func] = 1,
+#include "gl_beginend.h"
+};
+
+ProcessStruct *vmgl_get_process(pid_t pid)
+{
+    ProcessState *process = NULL;
+    static int first;
+    int i;
+
+    if(!first) {
+        first = 1;
+        init_process_tab();
+    }
+
+    /* Lookup a process stuct. If there isnt one associated with this pid
+     * then we create one.
+     * process->current_state contains info on which of the guests contexts is
+     * current.
+     */
+    for (i = 0; i < MAX_HANDLED_PROCESS; i ++)
+        if (processes[i].p.process_id == pid) {
+            process = &processes[i];
+            break;
+        } else if (processes[i].p.process_id == 0) {
+            process = &processes[i];
+            memset(process, 0, sizeof(ProcessState));
+            process->p.process_id = pid;
+            init_gl_state(&process->default_state);
+            process->current_state = &process->default_state;
+            break;
+        }
+
+    if (process == NULL) {
+        DEBUGF( "Too many processes !\n");
+        exit(-1);
+    }
+
+    return (ProcessStruct *)process; // Cast is ok due to struct defn.
+}
+
+void vmgl_context_switch(ProcessStruct *p, int switch_gl_context)
+{
+    ProcessState *process = (ProcessState *)p;
+    if(switch_gl_context) {
+        if(process->current_state->current_qsurface)
+            glo_surface_makecurrent(process->current_state->current_qsurface->surface);
+        else
+            glo_surface_makecurrent(0); // should never happen
+    }
+}
+
+static const char *opengl_strtok(const char *s, int *n, char **saveptr, char *prevbuf)
+{
+       char *start;
+       char *ret;
+       char *p;
+       int retlen;
+    static const char *delim = " \t\n\r/";
+
+       if (prevbuf)
+               free(prevbuf);
+
+    if (s) {
+        *saveptr = s;
+    } else {
+        if (!(*saveptr) || !(*n))
+            return NULL;
+        s = *saveptr;
+    }
+
+    for (; *n && strchr(delim, *s); s++, (*n)--) {
+        if (*s == '/' && *n > 1) {
+            if (s[1] == '/') {
+                do {
+                    s++, (*n)--;
+                } while (*n > 1 && s[1] != '\n' && s[1] != '\r');
+            } else if (s[1] == '*') {
+                do {
+                    s++, (*n)--;
+                } while (*n > 2 && (s[1] != '*' || s[2] != '/'));
+                s++, (*n)--;
+                               s++, (*n)--;
+                               if (*n == 0) {
+                                       break;
+                               }
+                       } else {
+                               break;
+            }
+        }
+    }
+
+       start = s;
+    for (; *n && *s && !strchr(delim, *s); s++, (*n)--);
+       if (*n > 0) 
+               s++, (*n)--;
+
+       *saveptr = s;
+
+       retlen = s - start;
+       ret = malloc(retlen + 1);
+       p = ret;
+
+       if (retlen == 0) {
+               *p = 0;
+               return;
+       }
+
+       while (retlen > 0) {
+        if (*start == '/' && retlen > 1) {
+            if (start[1] == '/') {
+                do {
+                    start++, retlen--;
+                } while (retlen > 1 && start[1] != '\n' && start[1] != '\r');
+                               start++, retlen--;
+                               continue;
+            } else if (start[1] == '*') {
+                do {
+                    start++, retlen--;
+                } while (retlen > 2 && (start[1] != '*' || start[2] != '/'));
+                start += 3, retlen -= 3;
+                               continue;
+            }
+        }
+               *(p++) = *(start++), retlen--;
+       }
+       
+       *p = 0;
+       return ret;
+}
+
+static char *do_eglShaderPatch(const char *source, int length, int *patched_len)
+{
+       char *saveptr = NULL;
+       char *sp;
+       char *p = NULL;
+
+    if (!length) 
+        length = strlen(source);
+    
+    *patched_len = 0;
+    int patched_size = length;
+    char *patched = malloc(patched_size + 1);
+
+    if (!patched) 
+        return NULL;
+
+    p = opengl_strtok(source, &length, &saveptr, NULL);
+    for (; p; p = opengl_strtok(0, &length, &saveptr, p)) {
+        if (!strncmp(p, "lowp", 4) || !strncmp(p, "mediump", 7) || !strncmp(p, "highp", 5)) {
+            continue;
+        } else if (!strncmp(p, "precision", 9)) {
+            while ((p = opengl_strtok(0, &length, &saveptr, p)) && !strchr(p, ';'));
+        } else {
+            if (!strncmp(p, "gl_MaxVertexUniformVectors", 26)) {
+                p = "(gl_MaxVertexUniformComponents / 4)";
+            } else if (!strncmp(p, "gl_MaxFragmentUniformVectors", 28)) {
+                p = "(gl_MaxFragmentUniformComponents / 4)";
+            } else if (!strncmp(p, "gl_MaxVaryingVectors", 20)) {
+                p = "(gl_MaxVaryingFloats / 4)";
+            }
+
+            int new_len = strlen(p);
+            if (*patched_len + new_len > patched_size) {
+                patched_size *= 2;
+                patched = realloc(patched, patched_size + 1);
+
+                if (!patched) 
+                    return NULL;
+            }
+
+            memcpy(patched + *patched_len, p, new_len);
+            *patched_len += new_len;
+        }     
+    }
+
+    patched[*patched_len] = 0;
+    /* check that we don't leave dummy preprocessor lines */
+    for (sp = patched; *sp;) {
+        for (; *sp == ' ' || *sp == '\t'; sp++);
+        if (!strncmp(sp, "#define", 7)) {
+            for (p = sp + 7; *p == ' ' || *p == '\t'; p++);
+            if (*p == '\n' || *p == '\r' || *p == '/') {
+                memset(sp, 0x20, 7);
+            }
+        }
+        for (; *sp && *sp != '\n' && *sp != '\r'; sp++);
+        for (; *sp == '\n' || *sp == '\r'; sp++);
+    }
+    return patched;
+}
+
+static int 
+shadersrc_gles_to_gl(GLsizei count, const char** string, char **s, const GLint* length, GLint *l)
+{
+       int i;
+
+       for(i = 0; i < count; ++i) {
+               GLint len;
+               if(length) {
+                       len = length[i];
+                       if (len < 0) 
+                               len = string[i] ? strlen(string[i]) : 0;
+               } else
+                       len = string[i] ? strlen(string[i]) : 0;
+
+               if(string[i]) {
+                       s[i] = do_eglShaderPatch(string[i], len, &l[i]);
+                       if(!s[i]) {
+                               while(i)
+                                       free(s[--i]);
+
+                               free(l);
+                               free(s);
+                               return -1;
+                       }
+               } else {
+                       s[i] = NULL;
+                       l[i] = 0;
+               }
+       }
+       
+       return 0;
+}
+
+
+int do_function_call(ProcessState *process, int func_number, unsigned long *args, char *ret_string)
+{
+    union gl_ret_type ret;
+
+    Signature *signature = (Signature *) tab_opengl_calls[func_number];
+    int ret_type = signature->ret_type;
+
+    ret.s = NULL;
+
+    if (display_function_call) {
+        DEBUGF( "[%d]> %s\n", process->p.process_id,
+                tab_opengl_calls_name[func_number]);
+    }
+       TRACE( "[%d]> %s\n", process->p.process_id,
+                       tab_opengl_calls_name[func_number]);
+
+    switch (func_number) {
+    case -1:
+        break;
+
+    case _resize_surface_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[0]);
+            QGloSurface *qsurface = get_qsurface_from_client_drawable(
+                                        process->current_state, client_drawable);
+
+            // We have to assume the current context here
+            // since we assume that a drawable must belong to a specific context
+            resize_surface(process, qsurface, (int)args[1], (int)args[2]);
+            break;
+
+        }
+
+    case _render_surface_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[0]);
+            QGloSurface *qsurface = get_qsurface_from_client_drawable(
+                                        process->current_state, client_drawable);
+            int bpp    = (int)args[1];
+            int stride = (int)args[2];
+            char *render_buffer = (char*)args[3];
+
+//            DEBUGF( "win: %08x stride: %d buf: %08x cl_dr: %08x qsurf: %08x\n", args[0], args[1], args[2], client_drawable, qsurface);
+
+            // We have to assume the current context here
+            // since we assume that a drawable must belong to a specific context
+            render_surface(qsurface, bpp, stride, render_buffer);
+            break;
+
+        }
+
+    case glXWaitGL_func:
+        {
+            glFinish(); //glXWaitGL();
+            ret.i = 0;
+            break;
+        }
+
+    case glXWaitX_func:
+        {
+            // FIXME GW Maybe we should just do this on the server?
+            //glXWaitX();
+            ret.i = 0;
+            break;
+        }
+
+    case glXChooseVisual_func:
+        {
+            ret.i = glXChooseVisualFunc((int *) &args[2]);
+            break;
+        }
+
+    case glXQueryExtensionsString_func:
+        {
+            ret.s = supported_glx_extensions();//glXQueryExtensionsString(dpy, 0);
+            break;
+        }
+
+    case glXQueryServerString_func:
+        {
+            switch (args[2]) {
+            case GLX_VENDOR : ret.s = FAKE_GLX_VENDOR; break;
+            case GLX_VERSION : ret.s = FAKE_GLX_VERSION_STRING; break;
+            case GLX_EXTENSIONS : ret.s = supported_glx_extensions(); break;
+            default: ret.s = 0;
+            }
+            break;
+        }
+
+    case glXGetClientString_func:
+        {
+            switch (args[1]) {
+            case GLX_VENDOR : ret.s = FAKE_GLX_VENDOR; break;
+            case GLX_VERSION : ret.s = FAKE_GLX_VERSION_STRING; break;
+            case GLX_EXTENSIONS : ret.s = "GLX_ARB_get_proc_address "; break;
+            default: ret.s = 0;
+            }
+            break;
+        }
+
+    case glXGetScreenDriver_func:
+        {
+            // FIXME GW What is this? not documented anywhere!!
+            //GET_EXT_PTR(const char *, glXGetScreenDriver, (Display *, int));
+            //ret.s = ptr_func_glXGetScreenDriver(dpy, 0);
+            ret.s = "";
+            break;
+        }
+
+    case glXGetDriverConfig_func:
+        {
+            // FIXME GW What is this? not documented anywhere!!
+            //GET_EXT_PTR(const char *, glXGetDriverConfig, (const char *));
+            //ret.s = ptr_func_glXGetDriverConfig((const char *) args[0]);
+            ret.s = "";
+            break;
+        }
+
+    case glXCreateContext_func:
+        {
+            int visualid = (int) args[1];
+            int fake_shareList = (int) args[2];
+
+            if (display_function_call)
+                DEBUGF( "visualid=%d, fake_shareList=%d\n", visualid,
+                        fake_shareList);
+
+            GLState *shareListState = get_glstate_for_fake_ctxt(process, fake_shareList);
+            int fake_ctxt = ++process->next_available_context_number;
+
+            ret.i = fake_ctxt;
+
+            // Work out format flags from visual id
+            int formatFlags = GLO_FF_DEFAULT;
+            if (visualid>=0 && visualid<DIM(FBCONFIGS))
+              formatFlags = FBCONFIGS[visualid].formatFlags;
+
+            GLState *state = _create_context(process, fake_ctxt, fake_shareList);
+            state->context = glo_context_create(formatFlags,
+                                                (GloContext*)shareListState?shareListState->context:0);
+
+            DEBUGF( " created context %p for %08x\n", state, fake_ctxt);
+            break;
+        }
+
+
+    case glXCreateNewContext_func:
+        {
+            int client_fbconfig = args[1];
+
+            ret.i = 0;
+            const GLXFBConfig *fbconfig = get_fbconfig(process, client_fbconfig);
+
+            if (fbconfig) {
+                int fake_shareList = args[3];
+                GLState *shareListState = get_glstate_for_fake_ctxt(process, fake_shareList);
+
+                process->next_available_context_number++;
+                int fake_ctxt = process->next_available_context_number;
+                ret.i = fake_ctxt;
+
+                GLState *state = _create_context(process, fake_ctxt, fake_shareList);
+                state->context = glo_context_create(fbconfig->formatFlags,
+                                                    shareListState?shareListState->context:0); // FIXME GW get from fbconfig
+            }
+            break;
+        }
+
+    case glXCopyContext_func:
+        {
+          DEBUGF( " glXCopyContext not supported (does anything use it?)\n");
+            break;
+        }
+
+    case glXDestroyContext_func:
+        {
+            int fake_ctxt = (int) args[1];
+
+            if (display_function_call)
+                DEBUGF( "fake_ctxt=%d\n", fake_ctxt);
+
+            int i;
+            for (i = 0; i < process->nb_states; i ++) {
+                if (process->glstates[i]->fake_ctxt == fake_ctxt) {
+                    // this was our GLState...
+                    process->current_state = &process->default_state;
+
+                    int fake_shareList =
+                        process->glstates[i]->fake_shareList;
+                    process->glstates[i]->ref--;
+                    if (process->glstates[i]->ref == 0) {
+                        DEBUGF(
+                                "destroy_gl_state fake_ctxt = %d\n",
+                                process->glstates[i]->fake_ctxt);
+                        destroy_gl_state(process->glstates[i]);
+                        g_free(process->glstates[i]);
+                        memmove(&process->glstates[i],
+                                &process->glstates[i + 1],
+                                (process->nb_states - i - 1) *
+                                sizeof(GLState *));
+                        process->nb_states --;
+                    }
+
+                    if (fake_shareList) {
+                        for (i = 0; i < process->nb_states; i++) {
+                            if (process->glstates[i]->fake_ctxt ==
+                                fake_shareList) {
+                                process->glstates[i]->ref--;
+                                if (process->glstates[i]->ref == 0) {
+                                    DEBUGF(
+                                            "destroy_gl_state fake_ctxt = %d\n",
+                                            process->glstates[i]->
+                                            fake_ctxt);
+                                    destroy_gl_state(process->
+                                                     glstates[i]);
+                                    g_free(process->glstates[i]);
+                                    memmove(&process->glstates[i],
+                                            &process->glstates[i + 1],
+                                            (process->nb_states - i - 1) *
+                                            sizeof(GLState *));
+                                    process->nb_states --;
+                                }
+                                break;
+                            }
+                        }
+                    }
+
+                    break;
+                }
+            }
+            break;
+        }
+
+    case glXQueryVersion_func:
+        {
+            int *major = (int *) args[1];
+            int *minor = (int *) args[2];
+            //ret.i = glXQueryVersion(dpy, (int *) args[1], (int *) args[2]);
+            if (major) *major=FAKE_GLX_VERSION_MAJOR;
+            if (minor) *minor=FAKE_GLX_VERSION_MINOR;
+            ret.i = True;
+            break;
+        }
+
+    case glGetString_func:
+        {
+            switch (args[0]) {
+              case GL_VENDOR:
+                ret.s = FAKE_GL_VENDOR;
+              break;
+              case GL_RENDERER:
+                ret.s = FAKE_GL_RENDERER;
+              break;
+              case GL_VERSION:
+                ret.s = FAKE_GL_VERSION;
+              break;
+              case GL_EXTENSIONS:
+                ret.s = compute_gl_extensions();
+              break;
+              case GL_SHADING_LANGUAGE_VERSION:
+               if(FAKE_GL_MAJOR < 2) {
+                  ret.s = "";
+                  break;
+                }
+              // Fall through.
+              default:
+                ret.s = (char *) glGetString(args[0]);
+              break;
+            }
+            break;
+        }
+
+    case glXMakeCurrent_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[1]);
+            int fake_ctxt = (int) args[2];
+            GLState *glstate = NULL;
+
+//            DEBUGF( "Makecurrent: fake_ctx=%d client_drawable=%08x\n", fake_ctxt, client_drawable);
+
+            if (client_drawable == 0 && fake_ctxt == 0) {
+                /* Release context */
+                if(process->current_state->current_qsurface)
+                    process->current_state->current_qsurface->ref--;
+                process->current_state = &process->default_state;
+
+//                DEBUGF( " --release\n");
+                glo_surface_makecurrent(0);
+            } else { /* Lookup GLState struct for this context */
+                glstate = get_glstate_for_fake_ctxt(process, fake_ctxt);
+                if (!glstate) {
+                    DEBUGF( " --invalid fake_ctxt (%d)!\n", fake_ctxt);
+                } else {
+                    if(!set_current_qsurface(glstate, client_drawable)) {
+                       // If there is no surface, create one.
+                       QGloSurface *qsurface = calloc(1, sizeof(QGloSurface));
+                       qsurface->surface = glo_surface_create(4, 4,
+                                                              glstate->context);
+                       qsurface->client_drawable = client_drawable;
+                       qsurface->ref = 1;
+
+                       bind_qsurface(glstate, qsurface);
+//                       DEBUGF( " --Client drawable not found, create new surface: %16x %16lx\n", (unsigned int)qsurface, (unsigned long int)client_drawable);
+
+                    }
+                    else {
+//                       DEBUGF( " --Client drawable found, using surface: %16x %16lx\n", (unsigned int)glstate->current_qsurface, (unsigned long int)client_drawable);
+                    }
+
+                    process->current_state = glstate;
+
+                    ret.i = glo_surface_makecurrent(glstate->current_qsurface->surface);
+                }
+            }
+            break;
+        }
+
+    case glXSwapBuffers_func:
+        {
+            // Does nothing - window data is copied via render_surface()
+            break;
+        }
+    case glXIsDirect_func:
+        {
+            // int fake_ctxt = (int) args[1];
+
+            // Does this go direct and skip the X server? We'll just say
+            // yes for now.
+            ret.c = True;
+
+            break;
+        }
+
+    case glXGetConfig_func:
+        {
+            int visualid = args[1];
+            ret.i = glXGetConfigFunc(visualid, args[2], (int *) args[3]);
+            break;
+        }
+
+    case glXGetConfig_extended_func:
+        {
+            int visualid = args[1];
+            int n = args[2];
+            int i;
+            int *attribs = (int *) args[3];
+            int *values = (int *) args[4];
+            int *res = (int *) args[5];
+
+            for (i = 0; i < n; i++) {
+                res[i] = glXGetConfigFunc(visualid, attribs[i], &values[i]);
+            }
+            break;
+        }
+
+    case glXUseXFont_func:
+        {
+            /* implementation is client-side only :-) */
+            break;
+        }
+
+    case glXQueryExtension_func:
+        {
+            int *errorBase = (int *) args[1];
+            int *eventBase = (int *) args[2];
+            if (errorBase) *errorBase = 0; /* FIXME GW */
+            if (eventBase) *eventBase = 0; /* FIXME GW */
+            ret.i = True;
+            break;
+        }
+
+    case glXChooseFBConfig_func:
+        {
+            if (process->nfbconfig == MAX_FBCONFIG) {
+                *(int *) args[3] = 0;
+                ret.i = 0;
+            } else {
+                const GLXFBConfig *fbconfigs =
+                    glXChooseFBConfigFunc(args[1], (int *) args[2], (int *) args[3]);
+                if (fbconfigs) {
+                    process->fbconfigs[process->nfbconfig] = fbconfigs;
+                    process->fbconfigs_max[process->nfbconfig] =
+                        *(int *) args[3];
+                    process->nfbconfig++;
+                    ret.i = 1 + process->nfbconfig_total;
+                    process->nfbconfig_total +=
+                        process->fbconfigs_max[process->nfbconfig];
+                } else {
+                    ret.i = 0;
+                }
+            }
+            break;
+        }
+    case glXGetFBConfigs_func:
+        {
+            if (process->nfbconfig == MAX_FBCONFIG) {
+                *(int *) args[2] = 0;
+                ret.i = 0;
+            } else {
+                const GLXFBConfig *fbconfigs =
+                    glXGetFBConfigsFunc(args[1], (int *) args[2]);
+                if (fbconfigs) {
+                    process->fbconfigs[process->nfbconfig] = fbconfigs;
+                    process->fbconfigs_max[process->nfbconfig] =
+                        *(int *) args[2];
+                    process->nfbconfig++;
+                    ret.i = 1 + process->nfbconfig_total;
+                    process->nfbconfig_total +=
+                        process->fbconfigs_max[process->nfbconfig];
+                } else {
+                    ret.i = 0;
+                }
+            }
+            break;
+        }
+    case glXGetFBConfigAttrib_func:
+        {
+            int client_fbconfig = args[1];
+
+            ret.i = 0;
+            const GLXFBConfig *fbconfig = get_fbconfig(process, client_fbconfig);
+
+            if (fbconfig)
+                ret.i =
+                    glXGetFBConfigAttribFunc(fbconfig, args[2], (int *) args[3]);
+            break;
+        }
+
+    case glXGetFBConfigAttrib_extended_func:
+        {
+            int client_fbconfig = args[1];
+            int n = args[2];
+            int i;
+            int *attribs = (int *) args[3];
+            int *values = (int *) args[4];
+            int *res = (int *) args[5];
+            const GLXFBConfig *fbconfig = get_fbconfig(process, client_fbconfig);
+
+            for (i = 0; i < n; i++) {
+                if (fbconfig) {
+                    res[i] =
+                        glXGetFBConfigAttribFunc(fbconfig, attribs[i], &values[i]);
+                } else {
+                    res[i] = 0;
+                }
+            }
+            break;
+        }
+    case glXQueryContext_func:
+        {
+            DEBUGF( "glXQueryContext not implemented\n");
+            ret.i = 0;
+#if 0 //GW
+            GET_EXT_PTR(int, glXQueryContext,
+                        (Display *, GLXContext, int, int *));
+            int fake_ctxt = (int) args[1];
+
+            if (display_function_call)
+                DEBUGF( "fake_ctx=%i\n", fake_ctxt);
+            GLXContext ctxt =
+                get_association_fakecontext_glxcontext(process, fake_ctxt);
+            if (ctxt == NULL) {
+                DEBUGF( "invalid fake_ctxt (%i) !\n", fake_ctxt);
+                ret.i = 0;
+            } else {
+                ret.i =
+                    ptr_func_glXQueryContext(dpy, ctxt, args[2],
+                                             (int *) args[3]);
+            }
+#endif
+            break;
+        }
+
+    case glXQueryDrawable_func:
+        {
+            // TODO GW one of:
+            // GLX_WIDTH, GLX_HEIGHT, GLX_PRESERVED_CONTENTS, GLX_LARGEST_PBUFFER, GLX_FBCONFIG_ID
+            DEBUGF( "FIXME: glXQueryDrawable not implemented\n");
+            ret.i = 0;
+#if 0 //GW
+            GET_EXT_PTR(void, glXQueryDrawable,
+                        (Display *, GLXDrawable, int, int *));
+            ClientGLXDrawable client_drawable = to_drawable(args[1]);
+            GLXDrawable drawable =
+                    get_association_clientdrawable_serverdrawable(
+                                    glstate, client_drawable);
+
+            if (display_function_call)
+                DEBUGF( "client_drawable=%p\n",
+                                client_drawable);
+
+            if (!drawable)
+                DEBUGF( "invalid client_drawable (%p) !\n",
+                                client_drawable);
+            else
+                ptr_func_glXQueryDrawable(dpy, drawable,
+                                args[2], (int *) args[3]);
+#endif
+            break;
+        }
+    case glXGetVisualFromFBConfig_func:
+        {
+            int client_fbconfig = args[1];
+
+            ret.i = 0;
+            const GLXFBConfig *fbconfig = get_fbconfig(process, client_fbconfig);
+
+            if (fbconfig) {
+                // we tread visualid as the index into the fbconfigs array
+                ret.i = &FBCONFIGS[0] - fbconfig;
+                if (display_function_call)
+                    DEBUGF( "visualid = %d\n", ret.i);
+            }
+            break;
+        }
+    case glXSwapIntervalSGI_func:
+        {
+            /*GET_EXT_PTR(int, glXSwapIntervalSGI, (int));
+            ret.i = ptr_func_glXSwapIntervalSGI(args[0]);*/
+            ret.i = 0;
+            break;
+        }
+
+    case glXGetProcAddress_fake_func:
+        {
+//            if (display_function_call)
+            //DEBUGF( "glXGetProcAddress %s  ", (char *) args[0]);
+            ret.i = glo_getprocaddress((const char *) args[0]) != NULL;
+            //   DEBUGF( " == %08x\n", ret.i);
+            ret.i = 0;
+            break;
+        }
+
+    case glXGetProcAddress_global_fake_func:
+        {
+            int nbElts = args[0];
+            char *huge_buffer = (char *) args[1];
+            char *result = (char *) args[2];
+            int i;
+
+            for (i = 0; i < nbElts; i++) {
+                int len = strlen(huge_buffer);
+                //DEBUGF( "glXGetProcAddress_global %s  ", (char *)huge_buffer);
+                result[i] =
+                    glo_getprocaddress((const char *) huge_buffer) !=
+                    NULL;
+                huge_buffer += len + 1;
+            }
+            break;
+        }
+/* Begin of texture stuff */
+    case glBindTexture_func:
+    case glBindTextureEXT_func:
+        {
+            int target = args[0];
+            unsigned int client_texture = args[1];
+            unsigned int server_texture;
+
+            if (client_texture == 0) {
+                glBindTexture(target, 0);
+            } else {
+                alloc_value(process->current_state->textureAllocator,
+                            client_texture);
+                server_texture =
+                    process->current_state->tabTextures[client_texture];
+                if (server_texture == 0) {
+                    glGenTextures(1, &server_texture);
+                    process->current_state->tabTextures[client_texture] =
+                        server_texture;
+                }
+                glBindTexture(target, server_texture);
+            }
+            break;
+        }
+
+    case glGenTextures_fake_func:
+        {
+            GET_EXT_PTR(void, glGenTextures, (GLsizei n, GLuint *textures));
+            int i;
+            int n = args[0];
+            unsigned int *clientTabTextures = g_malloc(n * sizeof(int));
+            unsigned int *serverTabTextures = g_malloc(n * sizeof(int));
+
+            alloc_range(process->current_state->textureAllocator, n,
+                        clientTabTextures);
+
+            ptr_func_glGenTextures(n, serverTabTextures);
+            for (i = 0; i < n; i++) {
+                process->current_state->tabTextures[clientTabTextures[i]] =
+                    serverTabTextures[i];
+            }
+
+            g_free(clientTabTextures);
+            g_free(serverTabTextures);
+            break;
+        }
+
+
+    case glDeleteTextures_func:
+        {
+            GET_EXT_PTR(void, glDeleteTextures,
+                        (GLsizei n, const GLuint *textures));
+            int i;
+            int n = args[0];
+            unsigned int *clientTabTextures = (unsigned int *) args[1];
+
+            delete_range(process->current_state->textureAllocator, n,
+                         clientTabTextures);
+
+            unsigned int *serverTabTextures = g_malloc(n * sizeof(int));
+
+            for (i = 0; i < n; i++) {
+                serverTabTextures[i] =
+                    get_server_texture(process, clientTabTextures[i]);
+            }
+            ptr_func_glDeleteTextures(n, serverTabTextures);
+            for (i = 0; i < n; i++) {
+                process->current_state->tabTextures[clientTabTextures[i]] = 0;
+            }
+            g_free(serverTabTextures);
+            break;
+        }
+
+    case glPrioritizeTextures_func:
+        {
+            GET_EXT_PTR(void, glPrioritizeTextures,
+                        (GLsizei n, const GLuint *textures,
+                         const GLclampf *priorities));
+
+            int i;
+            int n = args[0];
+            unsigned int *textures = (unsigned int *) args[1];
+
+            for (i = 0; i < n; i++) {
+                textures[i] = get_server_texture(process, textures[i]);
+            }
+            ptr_func_glPrioritizeTextures(n, textures,
+                                          (const GLclampf *) args[2]);
+            break;
+        }
+
+    case glAreTexturesResident_func:
+        {
+            GET_EXT_PTR(void, glAreTexturesResident,
+                        (GLsizei n, const GLuint *textures,
+                         GLboolean *residences));
+            int i;
+            int n = args[0];
+            unsigned int *textures = (unsigned int *) args[1];
+
+            for (i = 0; i < n; i++) {
+                textures[i] = get_server_texture(process, textures[i]);
+            }
+            ptr_func_glAreTexturesResident(n, textures,
+                                           (GLboolean *) args[2]);
+            break;
+        }
+
+    case glIsTexture_func:
+    case glIsTextureEXT_func:
+        {
+            GET_EXT_PTR(GLboolean, glIsTexture, (GLuint texture));
+            unsigned int client_texture = args[0];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture)
+                ret.c = ptr_func_glIsTexture(server_texture);
+            else
+                ret.c = 0;
+            break;
+        }
+
+    case glFramebufferTexture1DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture1DEXT,
+                        (int, int, int, int, int));
+            unsigned int client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture)
+                ptr_func_glFramebufferTexture1DEXT(args[0], args[1], args[2],
+                                                   server_texture, args[4]);
+            break;
+        }
+
+    case glFramebufferTexture2D_func:
+        //DEBUGF( "wooooot!\n");
+    case glFramebufferTexture2DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture2DEXT,
+                        (int, int, int, int, int));
+            unsigned int client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture)
+                ptr_func_glFramebufferTexture2DEXT(args[0], args[1], args[2],
+                                                   server_texture, args[4]);
+            break;
+        }
+
+    case glFramebufferTexture3DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture3DEXT,
+                        (int, int, int, int, int, int));
+            unsigned int client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture)
+                ptr_func_glFramebufferTexture3DEXT(args[0], args[1], args[2],
+                                                   server_texture, args[4],
+                                                   args[5]);
+            break;
+        }
+/* End of texture stuff */
+
+/* Begin of list stuff */
+    case glIsList_func:
+        {
+            unsigned int client_list = args[0];
+            unsigned int server_list = get_server_list(process, client_list);
+
+            if (server_list)
+                ret.c = glIsList(server_list);
+            else
+                ret.c = 0;
+            break;
+        }
+
+    case glDeleteLists_func:
+        {
+            int i;
+            unsigned int first_client = args[0];
+            int n = args[1];
+
+            unsigned int first_server =
+                get_server_list(process, first_client);
+            for (i = 0; i < n; i++) {
+                if (get_server_list(process, first_client + i) !=
+                    first_server + i)
+                    break;
+            }
+            if (i == n) {
+                glDeleteLists(first_server, n);
+            } else {
+                for (i = 0; i < n; i++) {
+                    glDeleteLists(get_server_list(process, first_client + i),
+                                  1);
+                }
+            }
+
+            for (i = 0; i < n; i++) {
+                process->current_state->tabLists[first_client + i] = 0;
+            }
+            delete_consecutive_values(process->current_state->listAllocator,
+                                      first_client, n);
+            break;
+        }
+
+    case glGenLists_fake_func:
+        {
+            int i;
+            int n = args[0];
+            unsigned int server_first = glGenLists(n);
+
+            if (server_first) {
+                unsigned int client_first =
+                    alloc_range(process->current_state->listAllocator, n,
+                                NULL);
+                for (i = 0; i < n; i++) {
+                    process->current_state->tabLists[client_first + i] =
+                        server_first + i;
+                }
+            }
+            break;
+        }
+
+    case glNewList_func:
+        {
+            unsigned int client_list = args[0];
+            int mode = args[1];
+
+            alloc_value(process->current_state->listAllocator, client_list);
+            unsigned int server_list = get_server_list(process, client_list);
+
+            if (server_list == 0) {
+                server_list = glGenLists(1);
+                process->current_state->tabLists[client_list] = server_list;
+            }
+            glNewList(server_list, mode);
+            break;
+        }
+
+    case glCallList_func:
+        {
+            unsigned int client_list = args[0];
+            unsigned int server_list = get_server_list(process, client_list);
+
+            glCallList(server_list);
+            break;
+        }
+
+    case glCallLists_func:
+        {
+            int i;
+            int n = args[0];
+            int type = args[1];
+            const GLvoid *lists = (const GLvoid *) args[2];
+            int *new_lists = g_malloc(sizeof(int) * n);
+
+            for (i = 0; i < n; i++) {
+                new_lists[i] =
+                    get_server_list(process, translate_id(i, type, lists));
+            }
+            glCallLists(n, GL_UNSIGNED_INT, new_lists);
+            g_free(new_lists);
+            break;
+        }
+
+
+/* End of list stuff */
+
+/* Begin of buffer stuff */
+    case glBindBufferARB_func:
+        {
+            GET_EXT_PTR(void, glBindBufferARB, (int, int));
+            int target = args[0];
+            unsigned int client_buffer = args[1];
+            unsigned int server_buffer;
+
+            if (client_buffer == 0) {
+                ptr_func_glBindBufferARB(target, 0);
+            } else {
+                server_buffer = get_server_buffer(process, client_buffer);
+                ptr_func_glBindBufferARB(target, server_buffer);
+            }
+            break;
+        }
+
+    case glGenBuffersARB_fake_func:
+        {
+            GET_EXT_PTR(void, glGenBuffersARB, (int, unsigned int *));
+            int i;
+            int n = args[0];
+            unsigned int *clientTabBuffers = g_malloc(n * sizeof(int));
+            unsigned int *serverTabBuffers = g_malloc(n * sizeof(int));
+
+            alloc_range(process->current_state->bufferAllocator, n,
+                        clientTabBuffers);
+
+            ptr_func_glGenBuffersARB(n, serverTabBuffers);
+            for (i = 0; i < n; i++) {
+                process->current_state->tabBuffers[clientTabBuffers[i]] =
+                    serverTabBuffers[i];
+            }
+
+            g_free(clientTabBuffers);
+            g_free(serverTabBuffers);
+            break;
+        }
+
+
+    case glDeleteBuffersARB_func:
+        {
+            GET_EXT_PTR(void, glDeleteBuffersARB, (int, int *));
+            int i;
+            int n = args[0];
+            unsigned int *clientTabBuffers = (unsigned int *) args[1];
+
+            delete_range(process->current_state->bufferAllocator, n,
+                         clientTabBuffers);
+
+            int *serverTabBuffers = g_malloc(n * sizeof(int));
+
+            for (i = 0; i < n; i++) {
+                serverTabBuffers[i] =
+                    get_server_buffer(process, clientTabBuffers[i]);
+            }
+            ptr_func_glDeleteBuffersARB(n, serverTabBuffers);
+            for (i = 0; i < n; i++) {
+                process->current_state->tabBuffers[clientTabBuffers[i]] = 0;
+            }
+            g_free(serverTabBuffers);
+            break;
+        }
+
+    case glIsBufferARB_func:
+        {
+            GET_EXT_PTR(int, glIsBufferARB, (int));
+            unsigned int client_buffer = args[0];
+            unsigned int server_buffer =
+                get_server_buffer(process, client_buffer);
+            if (server_buffer)
+                ret.i = ptr_func_glIsBufferARB(server_buffer);
+            else
+                ret.i = 0;
+            break;
+        }
+
+/* End of buffer stuff */
+
+    case glShaderSourceARB_fake_func:
+        {
+            GET_EXT_PTR(void, glShaderSourceARB, (int, int, char **, void *));
+            int size = args[1];
+            int i;
+            int acc_length = 0;
+            GLcharARB **tab_prog = g_malloc(size * sizeof(GLcharARB *));
+            int *tab_length = (int *) args[3];
+
+            for (i = 0; i < size; i++) {
+                tab_prog[i] = ((GLcharARB *) args[2]) + acc_length;
+                acc_length += tab_length[i];
+            }
+            ptr_func_glShaderSourceARB(args[0], args[1], tab_prog,
+                                       tab_length);
+            g_free(tab_prog);
+            break;
+        }
+
+    case glShaderSource_fake_func:
+               {
+                       GET_EXT_PTR(void, glShaderSource, (int, int, char **, void *));
+                       int size = args[1];
+                       int i;
+                       int acc_length = 0;
+                       GLcharARB **tab_prog = g_malloc(size * sizeof(GLcharARB *));
+                       int *tab_length = (int *) args[3];
+
+                       char **tab_prog_new;
+                       GLint *tab_length_new;
+
+                       tab_prog_new = malloc(args[1]* sizeof(char*));
+                       tab_length_new = malloc(args[1]* sizeof(GLint));
+
+                       memset(tab_prog_new, 0, args[1] * sizeof(char*));
+                       memset(tab_length_new, 0, args[1] * sizeof(GLint));
+
+
+                       for (i = 0; i < size; i++) {
+                               tab_prog[i] = ((GLcharARB *) args[2]) + acc_length;
+                               acc_length += tab_length[i];
+                       }
+
+                       shadersrc_gles_to_gl(args[1], tab_prog, tab_prog_new, tab_length, tab_length_new);
+
+                       if (!tab_prog_new || !tab_length_new)
+                               break;
+
+                       ptr_func_glShaderSource(args[0], args[1], tab_prog_new, tab_length_new);
+
+                       for (i = 0; i < args[1]; i++)
+                               free(tab_prog_new[i]);
+                       free(tab_prog_new);
+                       free(tab_length_new);
+
+                       free(tab_prog);
+
+                       break;
+               }
+
+    case glVertexPointer_fake_func:
+        {
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset,
+                   (void *) args[5], bytes_size);
+            /* DEBUGF( "glVertexPointer_fake_func size=%d, type=%d,
+             * stride=%d, byte_size=%d\n", size, type, stride, bytes_size); */
+            glVertexPointer(size, type, stride,
+                            process->current_state->vertexPointer);
+            break;
+        }
+
+    case glNormalPointer_fake_func:
+        {
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->normalPointerSize =
+                MAX(process->current_state->normalPointerSize,
+                    offset + bytes_size);
+            process->current_state->normalPointer =
+                g_realloc(process->current_state->normalPointer,
+                        process->current_state->normalPointerSize);
+            memcpy(process->current_state->normalPointer + offset,
+                   (void *) args[4], bytes_size);
+            // DEBUGF( "glNormalPointer_fake_func type=%d, stride=%d, 
+            // byte_size=%d\n", type, stride, bytes_size);
+            glNormalPointer(type, stride,
+                            process->current_state->normalPointer);
+            break;
+        }
+
+    case glIndexPointer_fake_func:
+        {
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->indexPointerSize =
+                MAX(process->current_state->indexPointerSize,
+                    offset + bytes_size);
+            process->current_state->indexPointer =
+                g_realloc(process->current_state->indexPointer,
+                        process->current_state->indexPointerSize);
+            memcpy(process->current_state->indexPointer + offset,
+                   (void *) args[4], bytes_size);
+            // DEBUGF( "glIndexPointer_fake_func type=%d, stride=%d,
+            // byte_size=%d\n", type, stride, bytes_size);
+            glIndexPointer(type, stride,
+                           process->current_state->indexPointer);
+            break;
+        }
+
+    case glEdgeFlagPointer_fake_func:
+        {
+            int offset = args[0];
+            int stride = args[1];
+            int bytes_size = args[2];
+
+            process->current_state->edgeFlagPointerSize =
+                MAX(process->current_state->edgeFlagPointerSize,
+                    offset + bytes_size);
+            process->current_state->edgeFlagPointer =
+                g_realloc(process->current_state->edgeFlagPointer,
+                        process->current_state->edgeFlagPointerSize);
+            memcpy(process->current_state->edgeFlagPointer + offset,
+                   (void *) args[3], bytes_size);
+            // DEBUGF( "glEdgeFlagPointer_fake_func stride = %d,
+            // bytes_size=%d\n", stride, bytes_size);
+            glEdgeFlagPointer(stride,
+                              process->current_state->edgeFlagPointer);
+            break;
+        }
+
+    case glVertexAttribPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerARB,
+                        (int, int, int, int, int, void *));
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int normalized = args[4];
+            int stride = args[5];
+            int bytes_size = args[6];
+
+            process->current_state->vertexAttribPointerSize[index] =
+                MAX(process->current_state->vertexAttribPointerSize[index],
+                    offset + bytes_size);
+            process->current_state->vertexAttribPointer[index] =
+                g_realloc(process->current_state->vertexAttribPointer[index],
+                        process->current_state->
+                        vertexAttribPointerSize[index]);
+            memcpy(process->current_state->vertexAttribPointer[index] +
+                   offset, (void *) args[7], bytes_size);
+            ptr_func_glVertexAttribPointerARB(index, size, type, normalized,
+                                              stride,
+                                              process->current_state->
+                                              vertexAttribPointer[index]);
+            break;
+        }
+
+    case glVertexAttribPointerNV_fake_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerNV,
+                        (int, int, int, int, void *));
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int stride = args[4];
+            int bytes_size = args[5];
+
+            process->current_state->vertexAttribPointerNVSize[index] =
+                MAX(process->current_state->vertexAttribPointerNVSize[index],
+                    offset + bytes_size);
+            process->current_state->vertexAttribPointerNV[index] =
+                g_realloc(process->current_state->vertexAttribPointerNV[index],
+                        process->current_state->
+                        vertexAttribPointerNVSize[index]);
+            memcpy(process->current_state->vertexAttribPointerNV[index] +
+                   offset, (void *) args[6], bytes_size);
+            ptr_func_glVertexAttribPointerNV(index, size, type, stride,
+                                             process->current_state->
+                                             vertexAttribPointerNV[index]);
+            break;
+        }
+
+    case glColorPointer_fake_func:
+        {
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->colorPointerSize =
+                MAX(process->current_state->colorPointerSize,
+                    offset + bytes_size);
+            process->current_state->colorPointer =
+                g_realloc(process->current_state->colorPointer,
+                        process->current_state->colorPointerSize);
+            memcpy(process->current_state->colorPointer + offset,
+                   (void *) args[5], bytes_size);
+            // DEBUGF( "glColorPointer_fake_func bytes_size = %d\n",
+            // bytes_size);
+            glColorPointer(size, type, stride,
+                           process->current_state->colorPointer);
+
+            break;
+        }
+
+    case glSecondaryColorPointer_fake_func:
+        {
+            GET_EXT_PTR(void, glSecondaryColorPointer,
+                        (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->secondaryColorPointerSize =
+                MAX(process->current_state->secondaryColorPointerSize,
+                    offset + bytes_size);
+            process->current_state->secondaryColorPointer =
+                g_realloc(process->current_state->secondaryColorPointer,
+                        process->current_state->secondaryColorPointerSize);
+            memcpy(process->current_state->secondaryColorPointer + offset,
+                   (void *) args[5], bytes_size);
+            // DEBUGF( "glSecondaryColorPointer_fake_func bytes_size
+            // = %d\n", bytes_size);
+            ptr_func_glSecondaryColorPointer(size, type, stride,
+                                             process->current_state->
+                                             secondaryColorPointer);
+
+            break;
+        }
+
+    case glPushClientAttrib_func:
+        {
+            int mask = args[0];
+
+            if (process->current_state->clientStateSp <
+                MAX_CLIENT_STATE_STACK_SIZE) {
+                process->current_state->clientStateStack[process->
+                                                         current_state->
+                                                         clientStateSp].mask =
+                    mask;
+                if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
+                    process->current_state->clientStateStack[process->
+                                                             current_state->
+                                                             clientStateSp].
+                        activeTextureIndex =
+                        process->current_state->activeTextureIndex;
+                }
+                process->current_state->clientStateSp++;
+            }
+            glPushClientAttrib(mask);
+            break;
+        }
+
+    case glPopClientAttrib_func:
+        {
+            if (process->current_state->clientStateSp > 0) {
+                process->current_state->clientStateSp--;
+                if (process->current_state->
+                    clientStateStack[process->current_state->clientStateSp].
+                    mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
+                    process->current_state->activeTextureIndex =
+                        process->current_state->clientStateStack[process->
+                                                                 current_state->
+                                                                 clientStateSp].
+                        activeTextureIndex;
+                }
+            }
+            glPopClientAttrib();
+            break;
+        }
+
+    case glClientActiveTexture_func:
+    case glClientActiveTextureARB_func:
+        {
+            int activeTexture = args[0];
+
+            process->current_state->activeTextureIndex =
+                activeTexture - GL_TEXTURE0_ARB;
+            do_glClientActiveTextureARB(activeTexture);
+            break;
+        }
+
+    case glTexCoordPointer_fake_func:
+        {
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int stride = args[4];
+            int bytes_size = args[5];
+
+            process->current_state->texCoordPointerSize[index] =
+                MAX(process->current_state->texCoordPointerSize[index],
+                    offset + bytes_size);
+            process->current_state->texCoordPointer[index] =
+                g_realloc(process->current_state->texCoordPointer[index],
+                        process->current_state->texCoordPointerSize[index]);
+            memcpy(process->current_state->texCoordPointer[index] + offset,
+                   (void *) args[6], bytes_size);
+            /* DEBUGF( "glTexCoordPointer_fake_func size=%d, type=%d, 
+             * stride=%d, byte_size=%d\n", size, type, stride, bytes_size); */
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + index);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[index]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glWeightPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glWeightPointerARB, (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->weightPointerSize =
+                MAX(process->current_state->weightPointerSize,
+                    offset + bytes_size);
+            process->current_state->weightPointer =
+                g_realloc(process->current_state->weightPointer,
+                        process->current_state->weightPointerSize);
+            memcpy(process->current_state->weightPointer + offset,
+                   (void *) args[5], bytes_size);
+            /* DEBUGF( "glWeightPointerARB_fake_func size=%d,
+             * type=%d, stride=%d, byte_size=%d\n", size, type, stride,
+             * bytes_size); */
+            ptr_func_glWeightPointerARB(size, type, stride,
+                                        process->current_state->
+                                        weightPointer);
+            break;
+        }
+
+    case glMatrixIndexPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glMatrixIndexPointerARB,
+                        (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->matrixIndexPointerSize =
+                MAX(process->current_state->matrixIndexPointerSize,
+                    offset + bytes_size);
+            process->current_state->matrixIndexPointer =
+                g_realloc(process->current_state->matrixIndexPointer,
+                        process->current_state->matrixIndexPointerSize);
+            memcpy(process->current_state->matrixIndexPointer + offset,
+                   (void *) args[5], bytes_size);
+            /* DEBUGF( "glMatrixIndexPointerARB_fake_func size=%d,
+             * type=%d, stride=%d, byte_size=%d\n", size, type, stride,
+             * bytes_size); */
+            ptr_func_glMatrixIndexPointerARB(size, type, stride,
+                                             process->current_state->
+                                             matrixIndexPointer);
+            break;
+        }
+
+    case glFogCoordPointer_fake_func:
+        {
+            GET_EXT_PTR(void, glFogCoordPointer, (int, int, void *));
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->fogCoordPointerSize =
+                MAX(process->current_state->fogCoordPointerSize,
+                    offset + bytes_size);
+            process->current_state->fogCoordPointer =
+                g_realloc(process->current_state->fogCoordPointer,
+                        process->current_state->fogCoordPointerSize);
+            memcpy(process->current_state->fogCoordPointer + offset,
+                   (void *) args[4], bytes_size);
+            // DEBUGF( "glFogCoordPointer_fake_func type=%d,
+            // stride=%d, byte_size=%d\n", type, stride, bytes_size);
+            ptr_func_glFogCoordPointer(type, stride,
+                                       process->current_state->
+                                       fogCoordPointer);
+            break;
+        }
+
+    case glVariantPointerEXT_fake_func:
+        {
+            GET_EXT_PTR(void, glVariantPointerEXT, (int, int, int, void *));
+            int offset = args[0];
+            int id = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->variantPointerEXTSize[id] =
+                MAX(process->current_state->variantPointerEXTSize[id],
+                    offset + bytes_size);
+            process->current_state->variantPointerEXT[id] =
+                g_realloc(process->current_state->variantPointerEXT[id],
+                        process->current_state->variantPointerEXTSize[id]);
+            memcpy(process->current_state->variantPointerEXT[id] + offset,
+                   (void *) args[5], bytes_size);
+            // DEBUGF( "glVariantPointerEXT_fake_func[%d] type=%d,
+            // stride=%d, byte_size=%d\n", id, type, stride, bytes_size);
+            ptr_func_glVariantPointerEXT(id, type, stride,
+                                         process->current_state->
+                                         variantPointerEXT[id]);
+            break;
+        }
+
+    case glInterleavedArrays_fake_func:
+        {
+            GET_EXT_PTR(void, glInterleavedArrays, (int, int, void *));
+            int offset = args[0];
+            int format = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->interleavedArraysSize =
+                MAX(process->current_state->interleavedArraysSize,
+                    offset + bytes_size);
+            process->current_state->interleavedArrays =
+                g_realloc(process->current_state->interleavedArrays,
+                        process->current_state->interleavedArraysSize);
+            memcpy(process->current_state->interleavedArrays + offset,
+                   (void *) args[4], bytes_size);
+            // DEBUGF( "glInterleavedArrays_fake_func format=%d,
+            // stride=%d, byte_size=%d\n", format, stride, bytes_size);
+            ptr_func_glInterleavedArrays(format, stride,
+                                         process->current_state->
+                                         interleavedArrays);
+            break;
+        }
+
+    case glElementPointerATI_fake_func:
+        {
+            GET_EXT_PTR(void, glElementPointerATI, (int, void *));
+            int type = args[0];
+            int bytes_size = args[1];
+
+            process->current_state->elementPointerATISize = bytes_size;
+            process->current_state->elementPointerATI =
+                g_realloc(process->current_state->elementPointerATI,
+                        process->current_state->elementPointerATISize);
+            memcpy(process->current_state->elementPointerATI,
+                   (void *) args[2], bytes_size);
+            // DEBUGF( "glElementPointerATI_fake_func type=%d,
+            // byte_size=%d\n", type, bytes_size);
+            ptr_func_glElementPointerATI(type,
+                                         process->current_state->
+                                         elementPointerATI);
+            break;
+        }
+
+    case glTexCoordPointer01_fake_func:
+        {
+            int size = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->texCoordPointerSize[0] = bytes_size;
+            process->current_state->texCoordPointer[0] =
+                g_realloc(process->current_state->texCoordPointer[0],
+                        bytes_size);
+            memcpy(process->current_state->texCoordPointer[0],
+                   (void *) args[4], bytes_size);
+            /* DEBUGF( "glTexCoordPointer01_fake_func size=%d,
+             * type=%d, stride=%d, byte_size=%d\n", size, type, stride,
+             * bytes_size); */
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glTexCoordPointer012_fake_func:
+        {
+            int size = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->texCoordPointerSize[0] = bytes_size;
+            process->current_state->texCoordPointer[0] =
+                g_realloc(process->current_state->texCoordPointer[0],
+                        bytes_size);
+            memcpy(process->current_state->texCoordPointer[0],
+                   (void *) args[4], bytes_size);
+            /* DEBUGF( "glTexCoordPointer012_fake_func size=%d,
+             * type=%d, stride=%d, byte_size=%d\n", size, type, stride,
+             * bytes_size); */
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(size, type, stride,
+                              process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexAndNormalPointer_fake_func:
+        {
+            int vertexPointerSize = args[0];
+            int vertexPointerType = args[1];
+            int vertexPointerStride = args[2];
+            int normalPointerType = args[3];
+            int normalPointerStride = args[4];
+            int bytes_size = args[5];
+            void *ptr = (void *) args[6];
+
+            process->current_state->vertexPointerSize = bytes_size;
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer, bytes_size);
+            memcpy(process->current_state->vertexPointer, ptr, bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType,
+                            vertexPointerStride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, normalPointerStride,
+                            process->current_state->vertexPointer);
+            break;
+        }
+
+    case glVertexNormalPointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            break;
+        }
+
+    case glTuxRacerDrawElements_fake_func:
+        {
+            int mode = args[0];
+            int count = args[1];
+            int isColorEnabled = args[2];
+            void *ptr = (void *) args[3];
+            int stride =
+                6 * sizeof(float) +
+                ((isColorEnabled) ? 4 * sizeof(unsigned char) : 0);
+            glVertexPointer(3, GL_FLOAT, stride, ptr);
+            glNormalPointer(GL_FLOAT, stride, ptr + 3 * sizeof(float));
+            if (isColorEnabled)
+                glColorPointer(4, GL_UNSIGNED_BYTE, stride,
+                               ptr + 6 * sizeof(float));
+            glDrawArrays(mode, 0, count);
+            break;
+        }
+
+    case glVertexNormalColorPointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int colorPointerOffset = args[i++];
+            int colorPointerSize = args[i++];
+            int colorPointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            glColorPointer(colorPointerSize, colorPointerType, stride,
+                           process->current_state->vertexPointer +
+                           colorPointerOffset);
+            break;
+        }
+
+    case glVertexColorTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int colorPointerOffset = args[i++];
+            int colorPointerSize = args[i++];
+            int colorPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glColorPointer(colorPointerSize, colorPointerType, stride,
+                           process->current_state->vertexPointer +
+                           colorPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalTexCoord01PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int texCoord1PointerOffset = args[i++];
+            int texCoord1PointerSize = args[i++];
+            int texCoord1PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1PointerSize, texCoord1PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord1PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalTexCoord012PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int texCoord1PointerOffset = args[i++];
+            int texCoord1PointerSize = args[i++];
+            int texCoord1PointerType = args[i++];
+            int texCoord2PointerOffset = args[i++];
+            int texCoord2PointerSize = args[i++];
+            int texCoord2PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1PointerSize, texCoord1PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord1PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(texCoord2PointerSize, texCoord2PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord2PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int colorPointerOffset = args[i++];
+            int colorPointerSize = args[i++];
+            int colorPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            glColorPointer(colorPointerSize, colorPointerType, stride,
+                           process->current_state->vertexPointer +
+                           colorPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord01PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int colorPointerOffset = args[i++];
+            int colorPointerSize = args[i++];
+            int colorPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int texCoord1PointerOffset = args[i++];
+            int texCoord1PointerSize = args[i++];
+            int texCoord1PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            glColorPointer(colorPointerSize, colorPointerType, stride,
+                           process->current_state->vertexPointer +
+                           colorPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1PointerSize, texCoord1PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord1PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord012PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointerSize = args[i++];
+            int vertexPointerType = args[i++];
+            int stride = args[i++];
+            int normalPointerOffset = args[i++];
+            int normalPointerType = args[i++];
+            int colorPointerOffset = args[i++];
+            int colorPointerSize = args[i++];
+            int colorPointerType = args[i++];
+            int texCoord0PointerOffset = args[i++];
+            int texCoord0PointerSize = args[i++];
+            int texCoord0PointerType = args[i++];
+            int texCoord1PointerOffset = args[i++];
+            int texCoord1PointerSize = args[i++];
+            int texCoord1PointerType = args[i++];
+            int texCoord2PointerOffset = args[i++];
+            int texCoord2PointerSize = args[i++];
+            int texCoord2PointerType = args[i++];
+            int bytes_size = args[i++];
+            void *ptr = (void *) args[i++];
+
+            process->current_state->vertexPointerSize =
+                MAX(process->current_state->vertexPointerSize,
+                    offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                        process->current_state->vertexPointerSize);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                   bytes_size);
+            glVertexPointer(vertexPointerSize, vertexPointerType, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointerType, stride,
+                            process->current_state->vertexPointer +
+                            normalPointerOffset);
+            glColorPointer(colorPointerSize, colorPointerType, stride,
+                           process->current_state->vertexPointer +
+                           colorPointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0PointerSize, texCoord0PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord0PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1PointerSize, texCoord1PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord1PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(texCoord2PointerSize, texCoord2PointerType,
+                              stride,
+                              process->current_state->vertexPointer +
+                              texCoord2PointerOffset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                                        process->current_state->
+                                        activeTextureIndex);
+            break;
+        }
+
+    case _glVertexPointer_buffer_func:
+        {
+            glVertexPointer(args[0], args[1], args[2], (void *) args[3]);
+            break;
+        }
+
+    case _glNormalPointer_buffer_func:
+        {
+            glNormalPointer(args[0], args[1], (void *) args[2]);
+            break;
+        }
+
+    case _glColorPointer_buffer_func:
+        {
+            glColorPointer(args[0], args[1], args[2], (void *) args[3]);
+            break;
+        }
+
+    case _glSecondaryColorPointer_buffer_func:
+        {
+            GET_EXT_PTR(void, glSecondaryColorPointer,
+                        (int, int, int, void *));
+            ptr_func_glSecondaryColorPointer(args[0], args[1], args[2],
+                                             (void *) args[3]);
+            break;
+        }
+
+    case _glIndexPointer_buffer_func:
+        {
+            glIndexPointer(args[0], args[1], (void *) args[2]);
+            break;
+        }
+
+    case _glTexCoordPointer_buffer_func:
+        {
+            glTexCoordPointer(args[0], args[1], args[2], (void *) args[3]);
+            break;
+        }
+
+    case _glEdgeFlagPointer_buffer_func:
+        {
+            glEdgeFlagPointer(args[0], (void *) args[1]);
+            break;
+        }
+
+    case _glVertexAttribPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerARB,
+                        (int, int, int, int, int, void *));
+            ptr_func_glVertexAttribPointerARB(args[0], args[1], args[2],
+                                              args[3], args[4],
+                                              (void *) args[5]);
+            break;
+        }
+
+    case _glWeightPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glWeightPointerARB, (int, int, int, void *));
+
+            ptr_func_glWeightPointerARB(args[0], args[1], args[2],
+                                        (void *) args[3]);
+            break;
+        }
+
+    case _glMatrixIndexPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glMatrixIndexPointerARB,
+                        (int, int, int, void *));
+            ptr_func_glMatrixIndexPointerARB(args[0], args[1], args[2],
+                                             (void *) args[3]);
+            break;
+        }
+
+    case _glFogCoordPointer_buffer_func:
+        {
+            GET_EXT_PTR(void, glFogCoordPointer, (int, int, void *));
+
+            ptr_func_glFogCoordPointer(args[0], args[1], (void *) args[2]);
+            break;
+        }
+
+    case _glVariantPointerEXT_buffer_func:
+        {
+            GET_EXT_PTR(void, glVariantPointerEXT, (int, int, int, void *));
+
+            ptr_func_glVariantPointerEXT(args[0], args[1], args[2],
+                                         (void *) args[3]);
+            break;
+        }
+
+    case _glDrawElements_buffer_func:
+        {
+            glDrawElements(args[0], args[1], args[2], (void *) args[3]);
+            break;
+        }
+#ifndef _WIN32
+    case _glDrawRangeElements_buffer_func:
+        {
+            glDrawRangeElements(args[0], args[1], args[2], args[3], args[4],
+                                (void *) args[5]);
+            break;
+        }
+#endif
+    case _glMultiDrawElements_buffer_func:
+        {
+            GET_EXT_PTR(void, glMultiDrawElements,
+                        (int, int *, int, void **, int));
+            ptr_func_glMultiDrawElements(args[0], (int *) args[1], args[2],
+                                         (void **) args[3], args[4]);
+            break;
+        }
+
+    case _glGetError_fake_func:
+        {
+            break;
+        }
+
+    case glGetIntegerv_func:
+        {
+            glGetIntegerv(args[0], (int *) args[1]);
+            break;
+        }
+
+    case _glReadPixels_pbo_func:
+        {
+            glReadPixels(ARG_TO_INT(args[0]), ARG_TO_INT(args[1]),
+                         ARG_TO_INT(args[2]), ARG_TO_INT(args[3]),
+                         ARG_TO_UNSIGNED_INT(args[4]),
+                         ARG_TO_UNSIGNED_INT(args[5]), (void *) (args[6]));
+            break;
+        }
+
+    case _glDrawPixels_pbo_func:
+        {
+            glDrawPixels(ARG_TO_INT(args[0]), ARG_TO_INT(args[1]),
+                         ARG_TO_UNSIGNED_INT(args[2]),
+                         ARG_TO_UNSIGNED_INT(args[3]),
+                         (const void *) (args[4]));
+            break;
+        }
+
+    case _glMapBufferARB_fake_func:
+        {
+            GET_EXT_PTR(GLvoid *, glMapBufferARB, (GLenum, GLenum));
+            GET_EXT_PTR(GLboolean, glUnmapBufferARB, (GLenum));
+            int target = args[0];
+            int size = args[1];
+            void *dst_ptr = (void *) args[2];
+            void *src_ptr = ptr_func_glMapBufferARB(target, GL_READ_ONLY);
+
+            if (src_ptr) {
+                memcpy(dst_ptr, src_ptr, size);
+                ret.i = ptr_func_glUnmapBufferARB(target);
+            } else {
+                ret.i = 0;
+            }
+            break;
+        }
+
+    case fake_gluBuild2DMipmaps_func:
+        {
+            GET_GLU_PTR(GLint, gluBuild2DMipmaps,
+                        (GLenum arg_0, GLint arg_1, GLsizei arg_2,
+                         GLsizei arg_3, GLenum arg_4, GLenum arg_5,
+                         const GLvoid *arg_6));
+            if (ptr_func_gluBuild2DMipmaps == NULL)
+                ptr_func_gluBuild2DMipmaps = mesa_gluBuild2DMipmaps;
+            ptr_func_gluBuild2DMipmaps(ARG_TO_UNSIGNED_INT(args[0]),
+                                       ARG_TO_INT(args[1]),
+                                       ARG_TO_INT(args[2]),
+                                       ARG_TO_INT(args[3]),
+                                       ARG_TO_UNSIGNED_INT(args[4]),
+                                       ARG_TO_UNSIGNED_INT(args[5]),
+                                       (const void *) (args[6]));
+            break;
+        }
+
+    case _glSelectBuffer_fake_func:
+        {
+            process->current_state->selectBufferSize = args[0] * 4;
+            process->current_state->selectBufferPtr =
+                g_realloc(process->current_state->selectBufferPtr,
+                        process->current_state->selectBufferSize);
+            glSelectBuffer(args[0], process->current_state->selectBufferPtr);
+            break;
+        }
+
+    case _glGetSelectBuffer_fake_func:
+        {
+            void *ptr = (void *) args[0];
+
+            memcpy(ptr, process->current_state->selectBufferPtr,
+                   process->current_state->selectBufferSize);
+            break;
+        }
+
+    case _glFeedbackBuffer_fake_func:
+        {
+            process->current_state->feedbackBufferSize = args[0] * 4;
+            process->current_state->feedbackBufferPtr =
+                g_realloc(process->current_state->feedbackBufferPtr,
+                        process->current_state->feedbackBufferSize);
+            glFeedbackBuffer((GLsizei)args[0], (GLenum) args[1],
+                             process->current_state->feedbackBufferPtr);
+            break;
+        }
+
+    case _glGetFeedbackBuffer_fake_func:
+        {
+            void *ptr = (void *) args[0];
+
+            memcpy(ptr, process->current_state->feedbackBufferPtr,
+                   process->current_state->feedbackBufferSize);
+            break;
+        }
+
+        /* 
+         * case glEnableClientState_func: { if (display_function_call)
+         * DEBUGF( "cap : %s\n", nameArrays[args[0] -
+         * GL_VERTEX_ARRAY]); glEnableClientState(args[0]); break; }
+         * 
+         * case glDisableClientState_func: { if (display_function_call)
+         * DEBUGF( "cap : %s\n", nameArrays[args[0] -
+         * GL_VERTEX_ARRAY]); glDisableClientState(args[0]); break; }
+         * 
+         * case glClientActiveTexture_func: case
+         * glClientActiveTextureARB_func: { if (display_function_call)
+         * DEBUGF( "client activeTexture %d\n", args[0] -
+         * GL_TEXTURE0_ARB); glClientActiveTextureARB(args[0]); break; }
+         * 
+         * case glActiveTextureARB_func: { if (display_function_call)
+         * DEBUGF( "server activeTexture %d\n", args[0] -
+         * GL_TEXTURE0_ARB); glActiveTextureARB(args[0]); break; }
+         * 
+         * case glLockArraysEXT_func: break;
+         * 
+         * case glUnlockArraysEXT_func: break;
+         * 
+         * case glArrayElement_func: { glArrayElement(args[0]); break; }
+         * 
+         * case glDrawArrays_func: { glDrawArrays(args[0],args[1],args[2]);
+         * break; }
+         * 
+         * case glDrawElements_func: {
+         * glDrawElements(args[0],args[1],args[2],(void*)args[3]); break; }
+         * 
+         * case glDrawRangeElements_func: {
+         * glDrawRangeElements(args[0],args[1],args[2],args[3],args[4],(void*)args[5]);
+         * break; } */
+
+    case glGetError_func:
+        {
+            ret.i = glGetError();
+            break;
+        }
+
+    case glNewObjectBufferATI_func:
+        {
+            GET_EXT_PTR(int, glNewObjectBufferATI, (int, void *, int));
+
+            ret.i = ptr_func_glNewObjectBufferATI(args[0],
+                            (void *) args[1], args[2]);
+            break;
+        }
+
+    case glClear_func:
+        glClear((GLbitfield)args[0]);
+        break;
+#if 0
+        /* HACK workaround for an unexplainable issue */
+        if (args[0] & GL_COLOR_BUFFER_BIT)
+            glClear(GL_COLOR_BUFFER_BIT);
+        if (args[0] & GL_STENCIL_BUFFER_BIT)
+            glClear(GL_STENCIL_BUFFER_BIT);
+        if (args[0] & GL_DEPTH_BUFFER_BIT)
+            glClear(GL_DEPTH_BUFFER_BIT);
+        if (args[0] & GL_ACCUM_BUFFER_BIT)
+            glClear(GL_ACCUM_BUFFER_BIT);
+        break;
+#endif
+
+    default:
+        execute_func(func_number, (void**)args, &ret);
+        break;
+    }
+
+    switch (ret_type) {
+    case TYPE_NONE:
+    case TYPE_CHAR:
+    case TYPE_UNSIGNED_CHAR:
+    case TYPE_INT:
+    case TYPE_UNSIGNED_INT:
+        break;
+
+    case TYPE_CONST_CHAR:
+        {
+            strncpy(ret_string, (ret.s) ? ret.s : "", 32768);
+            break;
+        }
+
+    default:
+        DEBUGF( "unexpected ret type : %d\n", ret_type);
+        exit(-1);
+        break;
+    }
+
+    if (display_function_call)
+        DEBUGF( "[%d]< %s\n", process->p.process_id,
+                tab_opengl_calls_name[func_number]);
+
+    return ret.i;
+}
diff --git a/tizen/src/hw/opengl_exec.h b/tizen/src/hw/opengl_exec.h
new file mode 100755 (executable)
index 0000000..9bd828b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) 2006,2007 Even Rouault
+ *
+ *  Modified by:
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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 <sys/types.h>
+
+extern void gl_disconnect(ProcessStruct *process);
+extern ProcessStruct *vmgl_get_process(pid_t pid);
+extern void vmgl_context_switch(ProcessStruct *process, int switch_gl_context);
+extern int do_function_call(ProcessStruct *process, int func_number,
+                            unsigned long *args, char *ret_string);
diff --git a/tizen/src/hw/opengl_func.h b/tizen/src/hw/opengl_func.h
new file mode 100755 (executable)
index 0000000..b2c8a1c
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ *  Copyright (c) 2006,2007 Even Rouault
+ *
+ *  Parts written by: 
+ *    Gordon Williams <gordon.williams@collabora.co.uk>
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef INCLUDE_OPENGL_FUNC_H
+#define INCLUDE_OPENGL_FUNC_H
+
+#include "mesa_gl.h"
+#include "mesa_glext.h"
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#define TARGET_PHYS_ADDR_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#define TARGET_PHYS_ADDR_BITS 32
+#endif
+
+//#define NEED_CPU_H
+//#include "exec.h"  // For arg_t typedef
+//#undef NEED_CPU_H
+#include "targphys.h"
+
+/* Argument list are internally of a type that can hold a target pointer
+ * or a host pointer.  */
+typedef target_phys_addr_t arg_t;
+
+enum {
+    TYPE_NONE,
+    TYPE_CHAR,
+    TYPE_UNSIGNED_CHAR,
+    TYPE_SHORT,
+    TYPE_UNSIGNED_SHORT,
+    TYPE_INT,
+    TYPE_UNSIGNED_INT,
+    TYPE_FLOAT,
+    TYPE_DOUBLE,
+    TYPE_1CHAR,
+    TYPE_2CHAR,
+    TYPE_3CHAR,
+    TYPE_4CHAR,
+    TYPE_128UCHAR,
+    TYPE_1SHORT,
+    TYPE_2SHORT,
+    TYPE_3SHORT,
+    TYPE_4SHORT,
+    TYPE_1INT,
+    TYPE_2INT,
+    TYPE_3INT,
+    TYPE_4INT,
+    TYPE_1FLOAT,
+    TYPE_2FLOAT,
+    TYPE_3FLOAT,
+    TYPE_4FLOAT,
+    TYPE_16FLOAT,
+    TYPE_1DOUBLE,
+    TYPE_2DOUBLE,
+    TYPE_3DOUBLE,
+    TYPE_4DOUBLE,
+    TYPE_16DOUBLE,
+    TYPE_OUT_1INT,
+    TYPE_OUT_1FLOAT,
+    TYPE_OUT_4CHAR,
+    TYPE_OUT_4INT,
+    TYPE_OUT_4FLOAT,
+    TYPE_OUT_4DOUBLE,
+    TYPE_OUT_128UCHAR,
+    TYPE_CONST_CHAR,
+    TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_SHORT,
+    TYPE_ARRAY_INT,
+    TYPE_ARRAY_FLOAT,
+    TYPE_ARRAY_DOUBLE,
+    TYPE_IN_IGNORED_POINTER,
+    TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_SHORT,
+    TYPE_OUT_ARRAY_INT,
+    TYPE_OUT_ARRAY_FLOAT,
+    TYPE_OUT_ARRAY_DOUBLE,
+    TYPE_NULL_TERMINATED_STRING,
+
+    TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    /* .... */
+    TYPE_LAST,
+    /* .... */
+    TYPE_1UCHAR = TYPE_CHAR,
+    TYPE_1USHORT = TYPE_1SHORT,
+    TYPE_1UINT = TYPE_1INT,
+    TYPE_OUT_1UINT = TYPE_OUT_1INT,
+    TYPE_OUT_4UCHAR = TYPE_OUT_4CHAR,
+    TYPE_ARRAY_VOID = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_SIGNED_CHAR = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_UNSIGNED_CHAR = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_UNSIGNED_SHORT = TYPE_ARRAY_SHORT,
+    TYPE_ARRAY_UNSIGNED_INT = TYPE_ARRAY_INT,
+    TYPE_OUT_ARRAY_VOID = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_SIGNED_CHAR = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_UNSIGNED_CHAR = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_UNSIGNED_SHORT = TYPE_OUT_ARRAY_SHORT,
+    TYPE_OUT_ARRAY_UNSIGNED_INT = TYPE_OUT_ARRAY_INT,
+    TYPE_ARRAY_VOID_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_SIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_VOID_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_SIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+};
+
+#define CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS \
+  case TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_OUT_LENGTH_DEPENDING_ON_PREVIOUS_ARGS \
+  case TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_OUT_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+  case TYPE_OUT_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_IN_UNKNOWN_SIZE_POINTERS \
+  case TYPE_ARRAY_CHAR: \
+  case TYPE_ARRAY_SHORT: \
+  case TYPE_ARRAY_INT: \
+  case TYPE_ARRAY_FLOAT: \
+  case TYPE_ARRAY_DOUBLE
+
+#define CASE_IN_KNOWN_SIZE_POINTERS \
+  case TYPE_1CHAR:\
+  case TYPE_2CHAR:\
+  case TYPE_3CHAR:\
+  case TYPE_4CHAR:\
+  case TYPE_128UCHAR:\
+  case TYPE_1SHORT:\
+  case TYPE_2SHORT:\
+  case TYPE_3SHORT:\
+  case TYPE_4SHORT:\
+  case TYPE_1INT:\
+  case TYPE_2INT:\
+  case TYPE_3INT:\
+  case TYPE_4INT:\
+  case TYPE_1FLOAT:\
+  case TYPE_2FLOAT:\
+  case TYPE_3FLOAT:\
+  case TYPE_4FLOAT:\
+  case TYPE_16FLOAT:\
+  case TYPE_1DOUBLE:\
+  case TYPE_2DOUBLE:\
+  case TYPE_3DOUBLE:\
+  case TYPE_4DOUBLE:\
+  case TYPE_16DOUBLE
+
+#define CASE_OUT_UNKNOWN_SIZE_POINTERS \
+  case TYPE_OUT_ARRAY_CHAR: \
+  case TYPE_OUT_ARRAY_SHORT: \
+  case TYPE_OUT_ARRAY_INT: \
+  case TYPE_OUT_ARRAY_FLOAT: \
+  case TYPE_OUT_ARRAY_DOUBLE
+
+#define CASE_OUT_KNOWN_SIZE_POINTERS \
+  case TYPE_OUT_1INT: \
+  case TYPE_OUT_1FLOAT: \
+  case TYPE_OUT_4CHAR: \
+  case TYPE_OUT_4INT: \
+  case TYPE_OUT_4FLOAT: \
+  case TYPE_OUT_4DOUBLE: \
+  case TYPE_OUT_128UCHAR \
+
+#define CASE_IN_POINTERS CASE_IN_UNKNOWN_SIZE_POINTERS: CASE_IN_KNOWN_SIZE_POINTERS: CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+#define CASE_OUT_POINTERS CASE_OUT_UNKNOWN_SIZE_POINTERS: CASE_OUT_KNOWN_SIZE_POINTERS: CASE_OUT_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_POINTERS CASE_IN_POINTERS: CASE_OUT_POINTERS
+#define CASE_KNOWN_SIZE_POINTERS CASE_IN_KNOWN_SIZE_POINTERS: CASE_OUT_KNOWN_SIZE_POINTERS
+
+
+#define IS_ARRAY_CHAR(type)  (type == TYPE_ARRAY_CHAR || type == TYPE_1CHAR || type == TYPE_2CHAR || type == TYPE_3CHAR || type == TYPE_4CHAR || type == TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_SHORT(type)  (type == TYPE_ARRAY_SHORT || type == TYPE_1SHORT || type == TYPE_2SHORT || type == TYPE_3SHORT || type == TYPE_4SHORT || type == TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_INT(type)  (type == TYPE_ARRAY_INT || type == TYPE_1INT || type == TYPE_2INT || type == TYPE_3INT || type == TYPE_4INT || type == TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_FLOAT(type)  (type == TYPE_ARRAY_FLOAT || type == TYPE_1FLOAT || type == TYPE_2FLOAT || type == TYPE_3FLOAT || type == TYPE_4FLOAT || type == TYPE_16FLOAT || type == TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_DOUBLE(type)  (type == TYPE_ARRAY_DOUBLE || type == TYPE_1DOUBLE || type == TYPE_2DOUBLE || type == TYPE_3DOUBLE || type == TYPE_4DOUBLE || type == TYPE_16DOUBLE || type == TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+
+#define NB_MAX_TEXTURES 16
+#define MY_GL_MAX_VERTEX_ATTRIBS_ARB 16
+#define MY_GL_MAX_VERTEX_ATTRIBS_NV 16
+#define MY_GL_MAX_VARIANT_POINTER_EXT 16
+
+typedef struct {
+    int ret_type;
+    int has_out_parameters;
+    int nb_args;
+    int args_type[0];
+} Signature;
+
+static const int _init32_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+static const int _init64_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+
+static const int _resize_surface_signature[] =
+    {TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT};
+
+static const int _render_surface_signature[] =
+    {TYPE_NONE, 1, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_OUT_ARRAY_CHAR};
+
+/* XVisualInfo* glXChooseVisual( Display *dpy, int screen, int *attribList ) */
+static const int glXChooseVisual_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT };
+
+/*GLXContext glXCreateContext( Display *dpy, XVisualInfo *vis,
+                             GLXContext shareList, Bool direct )*/
+static const int glXCreateContext_signature[] =
+    { TYPE_INT, 0, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT };
+
+static const int glXCopyContext_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_INT };
+
+/* void glXDestroyContext( Display *dpy, GLXContext ctx ) */
+static const int glXDestroyContext_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* Bool glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx) */
+/* making it asynchronous */
+static const int glXMakeCurrent_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+/*int glXGetConfig( Display *dpy, XVisualInfo *visual,
+                  int attrib, int *value )*/
+static const int glXGetConfig_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+/* "glXGetConfig_extended"(dpy, visual_id, int n, int* attribs, int* values, int* rets) */
+static const int glXGetConfig_extended_signature[] =
+    { TYPE_NONE, 1, 6, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_INT, TYPE_OUT_ARRAY_INT, TYPE_OUT_ARRAY_INT };
+
+/* void glXSwapBuffers( Display *dpy, GLXDrawable drawable ); */
+static const int glXSwapBuffers_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* Bool glXQueryVersion( Display *dpy, int *maj, int *min ) */
+static const int glXQueryVersion_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_OUT_1INT, TYPE_OUT_1INT };
+
+/* Bool glXQueryExtension( Display *dpy, int *errorBase, int *eventBase ) */
+static const int glXQueryExtension_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_OUT_1INT, TYPE_OUT_1INT };
+
+static const int glXWaitGL_signature[] = { TYPE_INT, 0, 0 };
+static const int glXWaitX_signature[] = { TYPE_INT, 0, 0 };
+
+/* GLX 1.1 and later */
+
+/* const char *glXGetClientString( Display *dpy, int name ) */
+static const int glXGetClientString_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/*const char *glXQueryExtensionsString( Display *dpy, int screen ) */
+static const int glXQueryExtensionsString_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* const char *glXQueryServerString( Display *dpy, int screen, int name ) */
+static const int glXQueryServerString_signature[] =
+    { TYPE_CONST_CHAR, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+
+static const int glXGetProcAddress_fake_signature[] =
+    { TYPE_INT, 0, 1, TYPE_NULL_TERMINATED_STRING };
+
+static const int glXGetProcAddress_global_fake_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_OUT_ARRAY_CHAR };
+
+
+/* GLX 1.3 and later */
+
+/*
+GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen,
+                                       const int *attribList, int *nitems ); */
+static const int glXChooseFBConfig_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT,
+TYPE_OUT_1INT };
+
+static const int glXChooseFBConfigSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT,
+TYPE_OUT_1INT };
+
+static const int glXGetFBConfigs_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_OUT_1INT };
+
+/* "glXGetFBConfigAttrib_extended"(dpy, fbconfig, int n, int* attribs, int* values, int* rets) */
+static const int glXGetFBConfigAttrib_extended_signature[] =
+    { TYPE_NONE, 1, 6, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_INT, TYPE_OUT_ARRAY_INT, TYPE_OUT_ARRAY_INT };
+
+
+/* GLXPbuffer glXCreatePbuffer( Display *dpy, GLXFBConfig config,
+                             const int *attribList ) */
+static const int glXCreatePbuffer_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT };
+
+static const int glXCreateGLXPbufferSGIX_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_INT };
+
+static const int glXDestroyPbuffer_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXDestroyGLXPbufferSGIX_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* GLXContext glXCreateNewContext(Display * dpy
+                               GLXFBConfig  config
+                               int  renderType
+                               GLXContext  ShareList
+                               Bool  Direct) */
+static const int glXCreateNewContext_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT };
+
+static const int glXCreateContextWithConfigSGIX_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT };
+
+/*XVisualInfo *glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config ) */
+static const int glXGetVisualFromFBConfig_signature[] =
+    { TYPE_INT, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/*int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig  config, int attribute, int *value)*/
+static const int glXGetFBConfigAttrib_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+static const int glXGetFBConfigAttribSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+static const int glXQueryContext_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+static const int glXQueryGLXPbufferSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+static const int glXQueryDrawable_signature[] =
+    { TYPE_NONE, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+TYPE_OUT_1INT };
+
+/* void glXUseXFont( Font font, int first, int count, int list ) */
+static const int glXUseXFont_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+
+/* Bool glXIsDirect( Display *dpy, GLXContext ctx ) */
+static const int glXIsDirect_signature[] =
+    { TYPE_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXGetScreenDriver_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXGetDriverConfig_signature[] =
+    { TYPE_CONST_CHAR, 0, 1, TYPE_NULL_TERMINATED_STRING };
+
+
+static const int glXWaitVideoSyncSGI_signature[] =
+    { TYPE_INT, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+
+static const int glXGetVideoSyncSGI_signature[] =
+    { TYPE_INT, 1, 1, TYPE_OUT_1INT };
+
+static const int glXSwapIntervalSGI_signature[] =
+    { TYPE_INT, 0, 1, TYPE_INT };
+
+static const int glXBindTexImageATI_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXReleaseTexImageATI_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXBindTexImageARB_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXReleaseTexImageARB_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+/* const GLubyte * glGetString( GLenum name ) */
+static const int glGetString_signature[] =
+    { TYPE_CONST_CHAR, 0, 1, TYPE_INT };
+
+/* void glShaderSourceARB (GLhandleARB handle , GLsizei size, const GLcharARB* *p_tab_prog, const GLint * tab_length) */
+/* --> void glShaderSourceARB (GLhandleARB handle , GLsizei size, const GLcharARB* all_progs, const GLint * tab_length) */
+static const int glShaderSourceARB_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_ARRAY_INT };
+static const int glShaderSource_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_ARRAY_INT };
+
+static const int glVertexPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glNormalPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glColorPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glSecondaryColorPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glIndexPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glEdgeFlagPointer_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAttribPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 8, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAttribPointerNV_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glWeightPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glMatrixIndexPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glFogCoordPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glInterleavedArrays_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glElementPointerATI_fake_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVariantPointerEXT_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glTuxRacerDrawElements_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAndNormalPointer_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer01_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer012_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int glVertexNormalPointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 8, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalColorPointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 11, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexColorTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 12, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 11, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord01PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 14, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord012PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 17, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 14, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord01PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 17, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord012PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 20, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+
+static const int glGenTextures_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int glGenBuffersARB_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int glGenLists_fake_signature[] = { TYPE_NONE, 0, 1, TYPE_INT };
+
+static const int _glDrawElements_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glDrawRangeElements_buffer_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT };
+static const int _glMultiDrawElements_buffer_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_ARRAY_INT, TYPE_INT, TYPE_ARRAY_INT,
+TYPE_INT };
+
+static const int _glVertexPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glNormalPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glColorPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glSecondaryColorPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glIndexPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glTexCoordPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glEdgeFlagPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_INT, TYPE_INT };
+static const int _glVertexAttribPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT };
+static const int _glWeightPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glMatrixIndexPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glFogCoordPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glVariantPointerEXT_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+
+static const int _glReadPixels_pbo_signature[] =
+    { TYPE_INT, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+TYPE_INT, TYPE_INT };
+static const int _glDrawPixels_pbo_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int _glMapBufferARB_fake_signature[] =
+    { TYPE_INT, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_ARRAY_CHAR };
+
+static const int _glSelectBuffer_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int _glGetSelectBuffer_fake_signature[] =
+    { TYPE_NONE, 1, 1, TYPE_ARRAY_CHAR };
+static const int _glFeedbackBuffer_fake_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_INT, TYPE_INT };
+static const int _glGetFeedbackBuffer_fake_signature[] =
+    { TYPE_NONE, 1, 1, TYPE_ARRAY_CHAR };
+
+static const int _glGetError_fake_signature[] = { TYPE_NONE, 0, 0 };
+
+#include "gl_func.h"
+
+#define IS_NULL_POINTER_OK_FOR_FUNC(func_number) \
+                 (func_number == glBitmap_func || \
+                  func_number == glTexImage1D_func || \
+                  func_number == glTexImage2D_func || \
+                  func_number == glTexImage3D_func || \
+                  func_number == glBufferDataARB_func || \
+                  func_number == glNewObjectBufferATI_func)
+
+#endif // INCLUDE_OPENGL_FUNC_H
+
diff --git a/tizen/src/hw/opengl_process.h b/tizen/src/hw/opengl_process.h
new file mode 100755 (executable)
index 0000000..5a92387
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by:
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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.
+ */
+
+typedef struct {
+    int process_id;
+    int wordsize;
+    int rq_l, rrq_l;
+    int sum; // Debugging only
+    char *rq, *rq_p;
+    char *rrq, *rrq_p;
+} ProcessStruct;
+
diff --git a/tizen/src/hw/parse_gl_h.c b/tizen/src/hw/parse_gl_h.c
new file mode 100755 (executable)
index 0000000..e37cf71
--- /dev/null
@@ -0,0 +1,1506 @@
+/*
+ *  Parse gl.h et glx.h to auto-generate source code
+ * 
+ *  Copyright (c) 2006,2007 Even Rouault
+ *
+ * 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.
+ */
+
+/* gcc -g parse_gl_h.c -o parse_gl_h && ./parse_gl_h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define                GL_INCLUDE_PATH         "../tizen/src/hw/"
+
+
+int isExtByName(const char* name)
+{
+  return (strstr(name, "ARB") != NULL) ||
+         (strstr(name, "IBM") != NULL) ||
+         (strstr(name, "EXT") != NULL) ||
+         (strstr(name, "ATI") != NULL) ||
+         (strstr(name, "NV") != NULL) ||
+         (strstr(name, "MESA") != NULL) ||
+         (strstr(name, "APPLE") != NULL) ||
+         (strstr(name, "SUN") != NULL) ||
+         (strstr(name, "SGI") != NULL);
+}
+
+char* get_arg_type(char* s)
+{
+  while(*s == ' ' || *s == '\t') s++;
+  char* n = s;
+  char* c = strstr(n, "const");
+  if (c)
+    n += 6;
+    
+  char* t = strstr(n, " ");
+  if (t)
+  {
+    if (t[1] == '*')
+      t += 2;
+    t[0] = 0;
+    char* ori = t;
+    t = strstr(t+1, "[");
+    if (t)
+    {
+      memmove(ori, t, strlen(t));
+      strstr(ori, "]")[1] = 0;
+    }
+  }
+  return strdup(s);
+}
+
+typedef struct
+{
+  char* type;
+  char* name;
+  int nargs;
+  char** args;
+  int ok;
+  int just_for_server_side;
+  int has_out_parameters;
+  int isExt;
+} FuncDesc;
+
+int isExt(FuncDesc* func)
+{
+  return func->isExt;
+}
+
+char* get_type_string(char* type)
+{
+  if (strstr(type, "[16]"))
+  {
+    if (strstr(type, "float"))
+      return ("TYPE_16FLOAT");
+    else if (strstr(type, "double"))
+      return ("TYPE_16DOUBLE");
+    else
+    {
+      printf("inconnu %s\n", type);
+      exit(-1);
+    }
+  }
+  else if (strstr(type, "[128]") && strstr(type, "GLubyte"))
+    return strstr(type, "const") ? "TYPE_128UCHAR" : "TYPE_OUT_128UCHAR";
+  else if (strstr(type, "const GLvoid *"))
+    return "TYPE_ARRAY_VOID";
+  else if (strstr(type, "const GLchar *") ||
+           strstr(type, "const GLcharARB *"))
+    return "TYPE_NULL_TERMINATED_STRING";
+  else if (strstr(type, "const GLbyte *"))
+    return "TYPE_ARRAY_SIGNED_CHAR";
+  else if (strstr(type, "const GLubyte *"))
+    return "TYPE_ARRAY_UNSIGNED_CHAR";
+  else if (strstr(type, "const GLshort *"))
+    return "TYPE_ARRAY_SHORT";
+  else if (strstr(type, "const GLushort *") ||
+           strstr(type, "const GLhalfNV *"))
+    return "TYPE_ARRAY_UNSIGNED_SHORT";
+  else if (strstr(type, "const GLint *"))
+    return "TYPE_ARRAY_INT";
+  else if (strstr(type, "const GLuint *") ||
+           strstr(type, "const GLenum *"))
+    return "TYPE_ARRAY_UNSIGNED_INT";
+  else if (strstr(type, "const GLfloat *") ||
+           strstr(type, "const GLclampf *"))
+    return "TYPE_ARRAY_FLOAT";
+  else if (strstr(type, "const GLdouble *"))
+    return "TYPE_ARRAY_DOUBLE";
+  else if (strstr(type, "GLvoid *"))
+    return "TYPE_OUT_ARRAY_VOID";
+  else if (strstr(type, "GLboolean *") ||
+           strstr(type, "GLubyte *"))
+    return "TYPE_OUT_ARRAY_UNSIGNED_CHAR";
+  else if (strstr(type, "GLcharARB *") ||
+           strstr(type, "GLchar *"))
+    return "TYPE_OUT_ARRAY_CHAR";
+  else if (strstr(type, "GLshort *"))
+    return "TYPE_OUT_ARRAY_SHORT";
+  else if (strstr(type, "GLushort *"))
+    return "TYPE_OUT_ARRAY_UNSIGNED_SHORT";
+  else if (strstr(type, "GLint *")||
+           strstr(type, "GLsizei *"))
+    return "TYPE_OUT_ARRAY_INT";
+  else if (strstr(type, "GLuint *") ||
+           strstr(type, "GLenum *") ||
+           strstr(type, "GLhandleARB *"))
+    return "TYPE_OUT_ARRAY_UNSIGNED_INT";
+  else if (strstr(type, "GLfloat *"))
+    return "TYPE_OUT_ARRAY_FLOAT";
+  else if (strstr(type, "GLdouble *"))
+    return "TYPE_OUT_ARRAY_DOUBLE";
+  else if (strcmp(type, "void") == 0)
+    return("TYPE_NONE");
+  else if (strcmp(type, "GLbyte") == 0)
+    return("TYPE_CHAR");
+  else if (strcmp(type, "GLubyte") == 0 ||
+           strcmp(type, "GLboolean") == 0)
+    return("TYPE_UNSIGNED_CHAR");
+  else if (strcmp(type, "GLshort") == 0)
+    return("TYPE_SHORT");
+  else if (strcmp(type, "GLushort") == 0 ||
+           strcmp(type, "GLhalfNV") == 0)
+    return("TYPE_UNSIGNED_SHORT");
+  else if (strcmp(type, "GLint") == 0 ||
+           strcmp(type, "GLsizei") == 0 ||
+           strcmp(type, "GLintptr") == 0 ||
+           strcmp(type, "GLsizeiptr") == 0 ||
+           strcmp(type, "GLintptrARB") == 0 ||
+           strcmp(type, "GLsizeiptrARB") == 0)
+    return("TYPE_INT");
+  else if (strcmp(type, "GLenum") == 0 ||
+           strcmp(type, "GLuint") == 0 ||
+           strcmp(type, "GLhandleARB") == 0 ||
+           strcmp(type, "GLbitfield") == 0)
+    return("TYPE_UNSIGNED_INT");
+  else if (strcmp(type, "GLfloat") == 0 ||
+           strcmp(type, "GLclampf") == 0)
+    return("TYPE_FLOAT");
+  else if (strcmp(type, "GLdouble") == 0 ||
+           strcmp(type, "GLclampd") == 0)
+    return("TYPE_DOUBLE");
+  else
+  {
+    printf("inconnu %s\n", type);
+    exit(-1);
+  }
+}
+
+typedef struct
+{
+  char* letter;
+  char* signature_type_name;
+  char* gl_c_type_name;
+  char* c_type_name;
+} ForIsKnownArgVector;
+
+#define N_ELEMENTS(x)  (sizeof(x)/sizeof(x[0]))
+#define N_FIELDS_IN_ARG_VECTOR  4
+
+
+typedef struct
+{
+  char* func_name;
+  char* signature_type_name;
+} KnownLastArgFunc;
+
+static KnownLastArgFunc knownLastArgFuncs[] =
+{
+{"glFogCoordfv", "TYPE_1FLOAT"},
+{"glFogCoorddv", "TYPE_1DOUBLE"},
+{"glFogCoordfvEXT", "TYPE_1FLOAT"},
+{"glFogCoorddvEXT", "TYPE_1DOUBLE"},
+{"glFogCoordhvNV", "TYPE_1USHORT"},
+  
+{"glGetFenceivNV", "TYPE_OUT_1INT"},
+
+{"glGetTexLevelParameteriv", "TYPE_OUT_1INT" },
+{"glGetTexLevelParameterfv", "TYPE_OUT_1FLOAT" },
+
+{"glGetRenderbufferParameterivEXT", "TYPE_OUT_1INT"},
+{"glGetFramebufferAttachmentParameterivEXT", "TYPE_OUT_1INT"},
+{"glGetFinalCombinerInputParameterivNV", "TYPE_OUT_1INT"},
+{"glGetCombinerOutputParameterivNV", "TYPE_OUT_1INT"},
+{"glGetCombinerInputParameterivNV", "TYPE_OUT_1INT"},
+{"glGetOcclusionQueryivNV", "TYPE_OUT_1INT"},
+{"glGetOcclusionQueryuivNV", "TYPE_OUT_1UINT"},
+{"glGetObjectParameterivARB", "TYPE_OUT_1INT"},
+{"glGetQueryivARB", "TYPE_OUT_1INT"},
+{"glGetQueryiv", "TYPE_OUT_1INT"},
+{"glGetQueryObjectivARB", "TYPE_OUT_1INT"},
+{"glGetQueryObjectiv", "TYPE_OUT_1INT"},
+{"glGetQueryObjectuivARB", "TYPE_OUT_1UINT"},
+{"glGetQueryObjectuiv", "TYPE_OUT_1UINT"},
+{"glGetProgramivARB", "TYPE_OUT_1INT"},
+{"glGetProgramiv", "TYPE_OUT_1INT"},
+{"glGetProgramivNV", "TYPE_OUT_1INT"},
+{"glGetShaderiv", "TYPE_OUT_1INT"},
+
+{"glCombinerParameterfvNV", "TYPE_1FLOAT"},
+{"glCombinerParameterivNV", "TYPE_1INT"},
+
+{"glGetFinalCombinerInputParameterfvNV", "TYPE_OUT_1FLOAT"},
+{"glGetCombinerOutputParameterfvNV", "TYPE_OUT_1FLOAT"},
+{"glGetCombinerInputParameterfvNV", "TYPE_OUT_1FLOAT"},
+{"glGetObjectParameterfvARB", "TYPE_OUT_1FLOAT"},
+
+{"glCombinerStageParameterfvNV", "TYPE_4FLOAT"},
+{"glGetCombinerStageParameterfvNV", "TYPE_OUT_4FLOAT"},
+
+{"glTexBumpParameterivATI", "TYPE_1INT"},
+{"glTexBumpParameterfvATI", "TYPE_1FLOAT"},
+{"glGetTexBumpParameterivATI", "TYPE_OUT_1INT"},
+{"glGetTexBumpParameterfvATI", "TYPE_OUT_1FLOAT"},
+
+{"glGetProgramLocalParameterfvARB", "TYPE_OUT_4FLOAT"},
+{"glGetProgramLocalParameterdvARB", "TYPE_OUT_4DOUBLE"},
+{"glGetProgramEnvParameterfvARB", "TYPE_OUT_4FLOAT"},
+{"glGetProgramEnvParameterdvARB", "TYPE_OUT_4DOUBLE"},
+{"glGetProgramLocalParameterIivNV", "TYPE_OUT_1INT"},
+{"glGetProgramLocalParameterIuivNV", "TYPE_OUT_1UINT"},
+{"glGetProgramEnvParameterIivNV", "TYPE_OUT_1INT"},
+{"glGetProgramEnvParameterIuivNV", "TYPE_OUT_1UINT"},
+
+{"glGetProgramParameterfvNV", "TYPE_OUT_4FLOAT"},
+{"glGetProgramParameterdvNV", "TYPE_OUT_4DOUBLE"},
+{"glGetProgramNamedParameterfvNV", "TYPE_OUT_4FLOAT"},
+{"glGetProgramNamedParameterdvNV", "TYPE_OUT_4DOUBLE"},
+
+{"glCullParameterfvEXT", "TYPE_4FLOAT"},
+{"glCullParameterdvEXT", "TYPE_4DOUBLE"},
+
+{"glGetTrackMatrixivNV", "TYPE_OUT_1INT"},
+{"glExecuteProgramNV", "TYPE_4FLOAT"},
+
+{"glEdgeFlagv", "TYPE_1UCHAR"},
+
+{"glClipPlane", "TYPE_4DOUBLE"},
+{"glGetClipPlane", "TYPE_OUT_4DOUBLE"},
+
+{"glSetFragmentShaderConstantATI", "TYPE_4FLOAT"},
+
+{"glGetObjectBufferfvATI", "TYPE_OUT_1FLOAT"},
+{"glGetObjectBufferivATI", "TYPE_OUT_1INT"},
+{"glGetArrayObjectfvATI", "TYPE_OUT_1FLOAT"},
+{"glGetArrayObjectivATI", "TYPE_OUT_1INT"},
+{"glGetVariantArrayObjectfvATI", "TYPE_OUT_1FLOAT"},
+{"glGetVariantArrayObjectivATI", "TYPE_OUT_1INT"},
+{"glGetVertexAttribArrayObjectfvATI", "TYPE_OUT_1FLOAT"},
+{"glGetVertexAttribArrayObjectivATI", "TYPE_OUT_1INT"},
+
+{"glPixelTransformParameterivEXT", "TYPE_1INT"},
+{"glPixelTransformParameterfvEXT", "TYPE_1FLOAT"},
+{"glGetPixelTransformParameterivEXT", "TYPE_OUT_1INT"},
+{"glGetPixelTransformParameterfvEXT", "TYPE_OUT_1FLOAT"},
+
+{"glColorTableParameterfv", "TYPE_4FLOAT"},
+{"glColorTableParameteriv", "TYPE_4INT"},
+{"glGetColorTableParameterfv", "TYPE_OUT_4FLOAT"},
+{"glGetColorTableParameteriv", "TYPE_OUT_4INT"},
+{"glColorTableParameterfvEXT", "TYPE_4FLOAT"},
+{"glColorTableParameterivEXT", "TYPE_4INT"},
+{"glGetColorTableParameterfvEXT", "TYPE_OUT_4FLOAT"},
+{"glGetColorTableParameterivEXT", "TYPE_OUT_4INT"},
+
+{"glGetMinmaxParameterfv", "TYPE_OUT_1FLOAT"},
+{"glGetMinmaxParameteriv", "TYPE_OUT_1INT"},
+{"glGetHistogramParameterfv", "TYPE_OUT_1FLOAT"},
+{"glGetHistogramParameteriv", "TYPE_OUT_1INT"},
+{"glGetMinmaxParameterfvEXT", "TYPE_OUT_1FLOAT"},
+{"glGetMinmaxParameterivEXT", "TYPE_OUT_1INT"},
+{"glGetHistogramParameterfvEXT", "TYPE_OUT_1FLOAT"},
+{"glGetHistogramParameterivEXT", "TYPE_OUT_1INT"},
+
+/* Not sure at all for the 2 followingo ones ! */
+{"glGetBooleanIndexedvEXT", "TYPE_OUT_4UCHAR"},
+{"glGetIntegerIndexedvEXT", "TYPE_OUT_4INT"},
+
+{"glReferencePlaneSGIX", "TYPE_4DOUBLE"},
+
+{"glGetTransformFeedbackVaryingNV", "TYPE_OUT_1INT"},
+
+};
+
+int is_known_arg_vector(FuncDesc* desc, char** p_signature_type_name, char** p_c_type_name)
+{
+  static ForIsKnownArgVector my_tab[] =
+  {
+    { "b", "CHAR", "GLbyte", "signed char" },
+    { "Boolean", "CHAR", "GLboolean", "unsigned char" },
+    { "s", "SHORT", "GLshort", "short" },
+    { "i", "INT", "GLint", "int" },
+    { "Integer", "INT", "GLint", "int" },
+    { "ub", "CHAR", "GLubyte", "unsigned char" },
+    { "h", "SHORT", "GLhalf", "unsigned short" },
+    { "us", "SHORT", "GLushort", "unsigned short" },
+    { "ui", "INT", "GLuint", "unsigned int" },
+    { "Nb", "CHAR", "GLbyte", "signed char" },
+    { "Ns", "SHORT", "GLshort", "short" },
+    { "Ni", "INT", "GLint", "int" },
+    { "Nub", "CHAR", "GLubyte", "unsigned char" },
+    { "Nus", "SHORT", "GLushort", "unsigned short" },
+    { "Nui", "INT", "GLuint", "unsigned int" },
+    
+    { "f", "FLOAT", "GLfloat", "float" },
+    { "Float", "FLOAT", "GLfloat", "float" },
+    { "d", "DOUBLE", "GLdouble", "double" },
+  };
+      
+  if (desc->nargs == 0)
+    return 0;
+  
+  int i , j;
+  
+  if (strstr(desc->name, "glVertexAttribs") ||
+      strstr(desc->name, "glProgramParameters") ||
+      strstr(desc->name, "glProgramEnvParameters") ||
+      strstr(desc->name, "glProgramLocalParameters") ||
+      (strstr(desc->name, "glUniform") && (strstr(desc->name, "iv") || strstr(desc->name, "fv"))))
+    return 0;
+  
+  static char signatures[N_ELEMENTS(my_tab)][N_FIELDS_IN_ARG_VECTOR][20] = {0};
+  char signature[10];
+  
+  for(i=0;i<N_ELEMENTS(knownLastArgFuncs);i++)
+  {
+    if (strcmp(desc->name, knownLastArgFuncs[i].func_name) == 0)
+    {
+      if (p_signature_type_name)
+      {
+        *p_signature_type_name = knownLastArgFuncs[i].signature_type_name;
+      }
+      if (p_c_type_name)
+      {
+        if (strstr(knownLastArgFuncs[i].signature_type_name, "FLOAT"))
+          *p_c_type_name = "float";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "DOUBLE"))
+          *p_c_type_name = "double";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "UINT"))
+          *p_c_type_name = "unsigned int";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "INT"))
+          *p_c_type_name = "int";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "USHORT"))
+          *p_c_type_name = "unsigned short";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "SHORT"))
+          *p_c_type_name = "short";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "UCHAR"))
+          *p_c_type_name = "unsigned char";
+        else if (strstr(knownLastArgFuncs[i].signature_type_name, "CHAR"))
+          *p_c_type_name = "char";
+        else
+          assert(0);
+      }
+      return 1;
+    }
+  }
+  
+  for(i=0;i<N_ELEMENTS(my_tab);i++)
+  {
+    for(j=1;j<=N_FIELDS_IN_ARG_VECTOR;j++)
+    {
+      if (strstr(desc->name, "glIndex") && strstr(desc->name, "v"))
+        sprintf(signature, "%sv", my_tab[i].letter);
+      else
+        sprintf(signature, "%d%sv", j, my_tab[i].letter);
+      if (strstr(desc->name, signature) &&
+          strstr(desc->args[desc->nargs - 1], my_tab[i].gl_c_type_name) &&
+          strstr(desc->args[desc->nargs - 1], "*"))
+      {
+        if (p_signature_type_name)
+        {
+          if (signatures[i][j-1][0] == 0)
+            sprintf(signatures[i][j-1], "TYPE_%d%s", j, my_tab[i].signature_type_name);
+          *p_signature_type_name = signatures[i][j-1];
+        }
+        if (p_c_type_name) *p_c_type_name = my_tab[i].c_type_name;
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+static void print_server_side_argument(FILE* server_stub, int j, char* glType)
+{
+  const char* symbolic_type = get_type_string(glType);
+  if (strcmp(symbolic_type, "TYPE_CHAR") == 0)
+    fprintf(server_stub, "ARG_TO_CHAR(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_UNSIGNED_CHAR") == 0)
+    fprintf(server_stub, "ARG_TO_UNSIGNED_CHAR(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_SHORT") == 0)
+    fprintf(server_stub, "ARG_TO_SHORT(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_UNSIGNED_SHORT") == 0)
+    fprintf(server_stub, "ARG_TO_UNSIGNED_SHORT(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_INT") == 0)
+    fprintf(server_stub, "ARG_TO_INT(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_UNSIGNED_INT") == 0)
+    fprintf(server_stub, "ARG_TO_UNSIGNED_INT(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_FLOAT") == 0)
+    fprintf(server_stub, "ARG_TO_FLOAT(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_16FLOAT") == 0)
+    fprintf(server_stub, "(const float*)(args[%d])", j);
+  else if (strcmp(symbolic_type, "TYPE_DOUBLE") == 0)
+    fprintf(server_stub, "ARG_TO_DOUBLE(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_16DOUBLE") == 0)
+    fprintf(server_stub, "(const double*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_128UCHAR") == 0)
+    fprintf(server_stub, "(unsigned char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_128UCHAR") == 0)
+    fprintf(server_stub, "(const unsigned char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_NULL_TERMINATED_STRING") == 0)
+    fprintf(server_stub, "(const char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_SHORT") == 0)
+    fprintf(server_stub, "(const short*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_UNSIGNED_SHORT") == 0)
+    fprintf(server_stub, "(const unsigned short*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_INT") == 0)
+    fprintf(server_stub, "(const int*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_UNSIGNED_INT") == 0)
+    fprintf(server_stub, "(const unsigned int*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_FLOAT") == 0)
+    fprintf(server_stub, "(const float*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_DOUBLE") == 0)
+    fprintf(server_stub, "(const double*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_CHAR") == 0)
+    fprintf(server_stub, "(const char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_SIGNED_CHAR") == 0)
+    fprintf(server_stub, "(const signed char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_VOID") == 0)
+    fprintf(server_stub, "(const void*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_ARRAY_UNSIGNED_CHAR") == 0)
+    fprintf(server_stub, "(const unsigned char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_SHORT") == 0)
+    fprintf(server_stub, "(short*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_UNSIGNED_SHORT") == 0)
+    fprintf(server_stub, "(unsigned short*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_INT") == 0)
+    fprintf(server_stub, "(int*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_UNSIGNED_INT") == 0)
+    fprintf(server_stub, "(unsigned int*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_FLOAT") == 0)
+    fprintf(server_stub, "(float*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_DOUBLE") == 0)
+    fprintf(server_stub, "(double*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_VOID") == 0)
+    fprintf(server_stub, "(void*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_CHAR") == 0)
+    fprintf(server_stub, "(char*)(args[%d])", j);
+  else if ( strcmp(symbolic_type, "TYPE_OUT_ARRAY_UNSIGNED_CHAR") == 0)
+    fprintf(server_stub, "(unsigned char*)(args[%d])", j);
+
+  else
+  {
+    fprintf(stderr, "Unknown : %s\n", symbolic_type);
+    assert(0);
+  }
+}
+
+static const char* func_dealt_by_hand[500] = { NULL };
+
+
+static const char* ignore_func[] =
+{
+  "glGetPointerv",
+  "glRectdv",
+  "glRectfv",
+  "glRectiv",
+  "glRectsv",
+  "glMultiDrawArrays",
+  "glMultiDrawArraysEXT",
+  "glMultiDrawElements",
+  "glMultiDrawElementsEXT",
+  "glUnmapBuffer",
+  "glUnmapBufferARB",
+  "glLoadTransposeMatrixf",
+  "glLoadTransposeMatrixd",
+  "glMultTransposeMatrixf",
+  "glMultTransposeMatrixd",
+  "glLoadTransposeMatrixfARB",
+  "glLoadTransposeMatrixdARB",
+  "glMultTransposeMatrixfARB",
+  "glMultTransposeMatrixdARB",
+  
+  "glPixelDataRangeNV",
+  "glFlushPixelDataRangeNV",
+  "glVertexArrayRangeNV",
+  "glFlushVertexArrayRangeNV",
+  "glVertexWeightfEXT",
+  
+  "glGetBufferPointerv",
+  "glGetBufferPointervARB",
+  "glGetVertexAttribPointerv",
+  "glGetVertexAttribPointervARB",
+  "glVertexAttribPointer",
+  "glVertexAttribPointerARB",
+  "glGetVariantPointervEXT",
+  NULL,
+};
+
+void get_func_dealt_by_hand()
+{
+  FILE* f = fopen(GL_INCLUDE_PATH"gl_func_perso.h", "r");
+  char buffer[256];
+  int i = 0;
+  char* c;
+  while(fgets(buffer, 256, f))
+  {
+    if (strstr(buffer, "MAGIC_MACRO("))
+    {
+      func_dealt_by_hand[i] = strdup(strstr(buffer, "MAGIC_MACRO(") + strlen("MAGIC_MACRO("));
+      * strstr(func_dealt_by_hand[i], ")") = 0;
+      c = strstr(func_dealt_by_hand[i], "_");
+      if (c && c != func_dealt_by_hand[i]) *c = 0;
+      i ++;
+    }
+  }
+  fclose(f);
+  
+  int j = 0;
+  while(ignore_func[j])
+  {
+    func_dealt_by_hand[i] = ignore_func[j];
+    i++;
+    j++;
+  }
+}
+
+static const char* just_for_server_side_list[] =
+{
+  "glEnableClientState",
+  "glDisableClientState",
+  "glPushClientAttrib",
+  "glPopClientAttrib",
+  "glPixelStorei",
+  "glPixelStoref",
+  "glClientActiveTexture",
+  "glClientActiveTextureARB",
+  "glEnableVertexAttribArray",
+  "glEnableVertexAttribArrayARB",
+  "glDisableVertexAttribArray",
+  "glDisableVertexAttribArrayARB",
+  "glDrawElementArrayATI",
+  "glDrawRangeElementArrayATI",
+  "glGenSymbolsEXT",
+  "glFreeObjectBufferATI",
+  "glUnmapObjectBufferATI",
+  "glLockArraysEXT",
+  "glUnlockArraysEXT",
+  "glDepthFunc",
+  "glFogf",
+  "glFogi",
+  "glClipPlane",
+  "glGetClipPlane",
+  
+/* begin of openquartz optimization */
+#if 1
+  "glMatrixMode",
+  "glOrtho",
+  "glFrustum",
+  "glPushMatrix",
+  "glPopMatrix",
+  "glLoadIdentity",
+  "glLoadMatrixd",
+  "glLoadMatrixf",
+  "glMultMatrixd",
+  "glMultMatrixf",
+  "glRotated",
+  "glRotatef",
+  "glScaled",
+  "glScalef",
+  "glTranslated",
+  "glTranslatef",
+#endif
+/* end of openquartz optimization */
+  
+  "glGetError",
+  "glActiveTextureARB",
+  
+  "glViewport",
+  "glScissor",
+  
+  "glBindBufferARB",
+  "glDeleteBuffersARB",
+  "glGenBuffersARB",
+  "glBufferDataARB",
+  "glBufferSubDataARB",
+  "glGetBufferSubDataARB",
+  "glGetBufferParameterivARB",
+  "glBindBuffer",
+  "glDeleteBuffers",
+  "glGenBuffers",
+  "glBufferData",
+  "glBufferSubData",
+  "glGetBufferSubData",
+  "glGetBufferParameteriv",
+  
+  "glPushAttrib",
+  "glPopAttrib",
+  "glEnable",
+  "glDisable",
+  "glIsEnabled",
+  "glBindTexture",
+  "glBindTextureEXT",
+  "glFogfv",
+  "glFogiv",
+  "glBitmap",
+  "glGetTexImage",
+  "glReadPixels",
+  "glDrawPixels",
+  "glSelectBuffer",
+  "glFeedbackBuffer",
+  
+  "glTexImage1D",
+  "glTexImage2D",
+  "glTexImage3D",
+  "glTexSubImage1D",
+  "glTexSubImage2D",
+  "glTexSubImage3D",
+  
+  "glTexImage3DEXT",
+  "glTexSubImage1DEXT",
+  "glTexSubImage2DEXT",
+  "glTexSubImage3DEXT",
+  
+  "glGetCompressedTexImage",
+  "glCompressedTexImage1D",
+  "glCompressedTexImage2D",
+  "glCompressedTexImage3D",
+  "glCompressedTexSubImage1D",
+  "glCompressedTexSubImage2D",
+  "glCompressedTexSubImage3D",
+  
+  "glGetCompressedTexImageARB",
+  "glCompressedTexImage1DARB",
+  "glCompressedTexImage2DARB",
+  "glCompressedTexImage3DARB",
+  "glCompressedTexSubImage1DARB",
+  "glCompressedTexSubImage2DARB",
+  "glCompressedTexSubImage3DARB",
+  
+  "glCallLists",
+  "glNewList",
+  "glDeleteLists",
+  "glGenLists",
+  
+  "glGenTextures",
+  "glDeleteTextures",
+  "glDeleteTexturesEXT",
+  "glMap1f",
+  "glMap1d",
+  "glMap2f",
+  "glMap2d",
+  "glGetMapdv",
+  "glGetMapfv",
+  "glGetMapiv",
+  "glGetBooleanv",
+  "glGetIntegerv",
+  "glGetFloatv",
+  "glGetDoublev",
+  
+  "glGetPixelMapfv",
+  "glGetPixelMapuiv",
+  "glGetPixelMapusv",
+  "glGetProgramStringARB",
+  "glGetProgramStringNV",
+  "glArrayElement",
+  "glDrawArrays",
+  "glDrawElements",
+  "glDrawRangeElements",
+  "glDrawRangeElementsEXT",
+  "glGetProgramInfoLog",
+  "glGetTexLevelParameteriv",
+  "glGetInfoLogARB",
+  "glGetShaderInfoLog",
+  "glGetAttachedObjectsARB",
+  "glGetAttachedShaders",
+  "glGetActiveUniformARB",
+  "glGetActiveUniform",
+  "glGetUniformLocationARB",
+  "glGetUniformLocation",
+  "glGetUniformfvARB",
+  "glGetUniformfv",
+  "glGetUniformivARB",
+  "glGetUniformiv",
+  "glGetUniformuivEXT",
+  "glGetShaderSourceARB",
+  "glGetShaderSource",
+  "glGetActiveAttribARB",
+  "glGetActiveAttrib",
+  "glGetAttribLocationARB",
+  "glGetAttribLocation",
+  
+  "glNewObjectBufferATI",
+  "glUpdateObjectBufferATI",
+  
+  "glSetLocalConstantEXT",
+  "glSetInvariantEXT",
+  "glVariantbvEXT",
+  "glVariantsvEXT",
+  "glVariantivEXT",
+  "glVariantfvEXT",
+  "glVariantdvEXT",
+  "glVariantubvEXT",
+  "glVariantusvEXT",
+  "glVariantuivEXT",
+  "glGetVariantBooleanvEXT",
+  "glGetVariantIntegervEXT",
+  "glGetVariantFloatvEXT",
+  "glGetInvariantBooleanvEXT",
+  "glGetInvariantIntegervEXT",
+  "glGetInvariantFloatvEXT",
+  "glGetLocalConstantBooleanvEXT",
+  "glGetLocalConstantIntegervEXT",
+  "glGetLocalConstantFloatvEXT",
+  
+  "glMatrixIndexubvARB",
+  "glMatrixIndexusvARB",
+  "glMatrixIndexuivARB",
+  "glColorTable",
+  "glColorSubTable",
+  "glGetColorTable",
+  "glConvolutionFilter1D",
+  "glConvolutionFilter2D",
+  "glGetConvolutionFilter",
+  "glSeparableFilter2D",
+  "glGetSeparableFilter",
+  "glGetHistogram",
+  "glGetMinmax",
+  "glColorTableEXT",
+  "glColorSubTableEXT",
+  "glGetColorTableEXT",
+  "glConvolutionFilter1DEXT",
+  "glConvolutionFilter2DEXT",
+  "glGetConvolutionFilterEXT",
+  "glSeparableFilter2DEXT",
+  "glGetSeparableFilterEXT",
+  "glGetHistogramEXT",
+  "glGetMinmaxEXT",
+  
+  "glGetTexParameterfv",
+  
+  "glGetVertexAttribivARB",
+  "glGetVertexAttribfvARB",
+  "glGetVertexAttribdvARB",
+  "glGetVertexAttribiv",
+  "glGetVertexAttribfv",
+  "glGetVertexAttribdv",
+  
+  "glGetDetailTexFuncSGIS",
+  "glGetSharpenTexFuncSGIS",
+  
+  "fake_gluBuild2DMipmaps",
+  
+  "glRenderMode",
+  
+  "glEnableVariantClientStateEXT",
+  "glDisableVariantClientStateEXT",
+  
+  "glGetActiveVaryingNV",
+  
+  NULL,
+};
+
+static int just_for_server_side_func(char* funcname)
+{
+  int i;
+  for(i=0;just_for_server_side_list[i];i++)
+  {
+    if (strcmp(just_for_server_side_list[i], funcname) == 0)
+      return 1;
+  }
+  return 0;
+}
+
+int parse(FILE* f, FuncDesc* funcDesc, int funcDescCount, int ignoreEXT)
+{
+  char buffer[256];
+  while(fgets(buffer, 256, f))
+  {
+
+    if (strncmp(buffer, "GLAPI", 5) == 0 && strstr(buffer, "APIENTRY") && strstr(buffer, "("))
+    {
+      int i = 0;
+      int skip = 0;
+      if (func_dealt_by_hand[0] == 0)
+      {
+        get_func_dealt_by_hand();
+      }
+      while (func_dealt_by_hand[i])
+      {
+        if (strstr(buffer, func_dealt_by_hand[i]))
+        {
+          skip = 1;
+          break;
+        }
+        i++;
+      }
+      if (skip)
+        continue;
+      
+      char** args = malloc(15 * sizeof(char*));
+      int narg = 0;
+      char* type = buffer + 6;
+      char* n = strstr(type, "GLAPIENTRY") ? strstr(type, "GLAPIENTRY") : strstr(type, "APIENTRY");
+      int skip_length = strstr(type, "GLAPIENTRY") ? 11 : 9;
+      n[-1] = 0;
+      type = strdup(type);
+      n += skip_length;
+      char* fonc = n;
+      n = strstr(n, "(");
+      if (n[-1] == ' ') n[-1] = 0;
+      n[0] = 0;
+      fonc = strdup(fonc);
+      /*if (strstr(fonc, "glLockArraysEXT") || strstr(fonc, "glUnlockArraysEXT"))
+      {
+      }
+      else*/
+      
+      
+      if (ignoreEXT == 1 && isExtByName(fonc))
+      {
+        free(type);
+        free(fonc);
+        continue;
+      }
+      n++;
+      while(1)
+      {
+        char* virg = strstr(n, ",");
+        if (virg)
+        {
+          args[narg] = n;
+          virg[0] = 0;
+          args[narg] = get_arg_type(args[narg]);
+          narg++;
+          n = virg+1;
+        }
+        else
+          break;
+      }
+      while (strstr(n, ")") == 0)
+      {
+        fgets(buffer, 256, f);
+        n = buffer;
+        while(1)
+        {
+          char* virg = strstr(n, ",");
+          if (virg)
+          {
+            args[narg] = n;
+            virg[0] = 0;
+            args[narg] = get_arg_type(args[narg]);
+            narg++;
+            n = virg+1;
+          }
+          else
+            break;
+        }
+      }
+      char* par = strstr(n, ")");
+      args[narg] = n;
+      par[0] = 0;
+      args[narg] = get_arg_type(args[narg]);
+      narg++;
+      
+      
+      /*printf("%s %s (", type, fonc);
+      for(i=0;i<narg;i++)
+      {
+      printf("%s,", args[i]);
+    }
+      printf(")\n");*/
+      
+      for(i=0;i<funcDescCount;i++)
+      {
+        if (strcmp(funcDesc[i].name, fonc) == 0)
+        {
+          if (ignoreEXT == 0)
+            funcDesc[i].isExt = 1;
+          break;
+        }
+      }
+      if (i == funcDescCount)
+      {
+        funcDesc[funcDescCount].type = type;
+        funcDesc[funcDescCount].name = fonc;
+        funcDesc[funcDescCount].nargs = narg;
+        funcDesc[funcDescCount].args = args;
+        funcDesc[funcDescCount].isExt = ignoreEXT == 0;
+        funcDescCount++;
+      }
+      else
+      {
+        free(fonc);
+        free(args);
+        free(type);
+      }
+      /*
+      for(i=0;i<narg;i++)
+      {
+      free(args[i]);
+    }
+      free(fonc);
+      free(type);*/
+    }
+  }
+  return funcDescCount;
+}
+
+typedef struct
+{
+  char* str;
+  int i;
+} StringIntStruct;
+
+StringIntStruct argDependingOnPreviousArgTab[] =
+{
+  { "glLoadProgramNV", 3},
+  { "ProgramNamedParameter", 2},
+  { "glDeleteBuffers", 1},
+  { "glDrawBuffers", 1},
+  { "glGenPrograms", 1},
+  { "glDeletePrograms", 1},
+  { "glGenQueries", 1},
+  { "glDeleteQueries", 1},
+  { "glGenFencesNV", 1},
+  { "glDeleteFencesNV", 1},
+  { "glGenOcclusionQueriesNV", 1},
+  { "glDeleteOcclusionQueriesNV", 1},
+  { "glRequestResidentProgramsNV", 1},
+  { "glDeleteTextures", 1},
+  { "glGenFramebuffersEXT", 1},
+  { "glDeleteFramebuffersEXT", 1},
+  { "glGenRenderbuffersEXT", 1},
+  { "glDeleteRenderbuffersEXT", 1},
+  { "glUniform1fv", 2},
+  { "glUniform2fv", 2},
+  { "glUniform3fv", 2},
+  { "glUniform4fv", 2},
+  { "glUniform1iv", 2},
+  { "glUniform2iv", 2},
+  { "glUniform3iv", 2},
+  { "glUniform4iv", 2},
+  { "glUniform1uivEXT", 2},
+  { "glUniform2uivEXT", 2},
+  { "glUniform3uivEXT", 2},
+  { "glUniform4uivEXT", 2},
+  { "glProgramParameters4fvNV", 3},
+  { "glProgramParameters4dvNV", 3},
+  { "glProgramLocalParameters4fvEXT", 3},
+  { "glProgramLocalParametersI4ivNV", 3},
+  { "glProgramLocalParametersI4uivNV", 3},
+  { "glProgramEnvParameters4fvEXT", 3},
+  { "glProgramEnvParametersI4ivNV", 3},
+  { "glProgramEnvParametersI4uivNV", 3},
+  { "glAreProgramsResidentNV", 1} ,
+  { "glAreProgramsResidentNV", 2} ,
+  { "glAreTexturesResident", 1} ,
+  { "glAreTexturesResident", 2} ,
+  { "glPrioritizeTextures", 1} ,
+  { "glPrioritizeTextures", 2} ,
+  { "glProgramStringARB", 3} ,
+  
+  { "glVertexAttribs", 2},
+  
+  { "glUniformMatrix", 3 },
+  
+  { "glGetVertexAttribfv", 2},
+  { "glGetVertexAttribiv", 2},
+  { "glGetVertexAttribdv", 2},
+  { "glGetVertexAttribIivEXT", 2},
+  { "glGetVertexAttribIuivEXT", 2},
+  
+  { "glPointParameterfv", 1},
+  { "glPointParameteriv", 1},
+  
+  { "glWeightbvARB", 1},
+  { "glWeightsvARB", 1},
+  { "glWeightivARB", 1},
+  { "glWeightfvARB", 1},
+  { "glWeightdvARB", 1},
+  { "glWeightubvARB", 1},
+  { "glWeightusvARB", 1},
+  { "glWeightuivARB", 1},
+
+  { "glTexEnvfv", 2},
+  { "glTexEnviv", 2},
+  { "glGetTexEnvfv", 2},
+  { "glGetTexEnviv", 2},
+  { "glTexGendv", 2},
+  { "glTexGenfv", 2},
+  { "glTexGeniv", 2},
+  { "glGetTexGendv", 2},
+  { "glGetTexGenfv", 2},
+  { "glGetTexGeniv", 2},
+  
+  { "glLightfv", 2},
+  { "glLightiv", 2},
+  { "glGetLightfv", 2},
+  { "glGetLightiv", 2},
+  { "glFragmentLightfvSGIX", 2},
+  { "glFragmentLightivSGIX", 2},
+  { "glGetFragmentLightfvSGIX", 2},
+  { "glGetFragmentLightivSGIX", 2},
+  
+  
+  { "glLightModelfv", 1},
+  { "glLightModeliv", 1},
+  { "glFragmentLightModelfvSGIX", 1},
+  { "glFragmentLightModelivSGIX", 1},
+  
+  { "glMaterialfv", 2},
+  { "glMaterialiv", 2},
+  { "glGetMaterialfv", 2},
+  { "glGetMaterialiv", 2},
+  { "glFragmentMaterialfvSGIX", 2},
+  { "glFragmentMaterialivSGIX", 2},
+  { "glGetFragmentMaterialfvSGIX", 2},
+  { "glGetFragmentMaterialivSGIX", 2},
+
+  { "glFogiv", 1},
+  { "glFogfv", 1},
+
+  { "glTexParameterfv", 2},
+  { "glTexParameteriv", 2},
+  { "glGetTexParameterfv", 2},
+  { "glGetTexParameteriv", 2},
+  
+  { "glTexParameterIivEXT", 2},
+  { "glTexParameterIuivEXT", 2},
+  { "glGetTexParameterIivEXT", 2},
+  { "glGetTexParameterIuivEXT", 2},
+
+  { "glPixelMapfv", 2},
+  { "glPixelMapuiv", 2},
+  { "glPixelMapusv", 2},
+  
+  { "glDetailTexFuncSGIS", 2 },
+  { "glSharpenTexFuncSGIS", 2 },
+  
+  { "glSpriteParameterfvSGIX", 1 },
+  { "glSpriteParameterivSGIX", 1 },
+  
+  { "ConvolutionParameter", 2},
+  
+  { "glProgramBufferParametersfvNV", 4},
+  { "glProgramBufferParametersIivNV", 4},
+  { "glProgramBufferParametersIuivNV", 4},
+  
+  { "glTransformFeedbackAttribsNV", 1},
+  { "glTransformFeedbackVaryingsNV", 2},
+};
+
+int is_arg_of_length_depending_on_previous_args(FuncDesc* funcDesc, int j)
+{
+  int i;
+  if (strstr(funcDesc->args[j], "*") == NULL)
+    return 0;
+  for(i=0;i< N_ELEMENTS(argDependingOnPreviousArgTab); i++)
+  {
+    if (strstr(funcDesc->name, argDependingOnPreviousArgTab[i].str) && j == argDependingOnPreviousArgTab[i].i)
+      return 1;
+  }
+  return 0;
+}
+
+static void fprintf_prototype_args(FILE* f, FuncDesc* funcDesc)
+{
+  int j;
+  for(j=0;j<funcDesc->nargs;j++)
+  {
+    if (j != 0) fprintf(f,", ");
+    if (strstr(funcDesc->args[j], "[16]"))
+    {
+      if (strstr(funcDesc->args[j], "float"))
+      {
+        fprintf(f, "const GLfloat arg_%d[16]", j);
+      }
+      else if (strstr(funcDesc->args[j], "double"))
+      {
+        fprintf(f, "const GLdouble arg_%d[16]", j);
+      }
+      else
+      {
+        exit(-1);
+      }
+    }
+    else if (strstr(funcDesc->args[j], "[128]") && strstr(funcDesc->args[j], "GLubyte"))
+      fprintf(f, (strstr(funcDesc->args[j], "const")) ? "const GLubyte* arg_%d" : "GLubyte* arg_%d", j);
+    else
+      fprintf(f, "%s arg_%d", funcDesc->args[j], j);
+  }
+}
+
+int main(int argc, char* argv[])
+{
+  FuncDesc funcDesc[3000];
+  int funcDescCount = 0;
+  FILE* f;
+
+       printf("***** path : %s\n", GL_INCLUDE_PATH"mesa_gl.h");
+  f = fopen(GL_INCLUDE_PATH"mesa_gl.h", "r");
+  assert(f);
+  /*if (!f)
+    f = fopen("/usr/include/GL/gl.h", "r");*/
+  funcDescCount = parse(f, funcDesc, 0, 1);
+  fclose(f);
+  
+  f = fopen(GL_INCLUDE_PATH"mesa_glext.h", "r");
+  assert(f);
+  /*if (!f)
+    f = fopen("/usr/include/GL/glext.h", "r");*/
+  funcDescCount = parse(f, funcDesc, funcDescCount, 0);
+  fclose(f);
+  
+  FILE* header = fopen("gl_func.h", "w");
+  FILE* client_stub = fopen("client_stub.c", "w");
+  FILE* server_stub = fopen("server_stub.c", "w");
+
+  fprintf(header, "/* This is a generated file by parse_gl_h.c - DO NOT EDIT ! */\n\n");
+  fprintf(header, "union gl_ret_type {\n"
+    "const char *s;\n"
+    "int i;\n"
+    "char c;\n"
+    "};\n");
+
+  fprintf(header, "#define COMPOSE(x,y) x##y\n");
+  fprintf(header, "#define MAGIC_MACRO(x)  COMPOSE(x,_func)\n");
+  fprintf(header, "enum {\n"
+                  "#include \"gl_func_perso.h\"\n");
+
+  fprintf(client_stub, "/* This is a generated file by parse_gl_h.c - DO NOT EDIT ! */\n\n");
+
+  fprintf(server_stub, "/* This is a generated file by parse_gl_h.c - DO NOT EDIT ! */\n\n");
+
+  int i;
+  for(i=0;i<funcDescCount;i++)
+  {
+    funcDesc[i].ok = 0;
+    char* name = funcDesc[i].name;
+    char* type = funcDesc[i].type;
+    if ((strcmp(type, "void") == 0 || strcmp(type, "GLboolean") == 0 ||
+         strcmp(type, "GLuint") == 0 || strcmp(type, "GLint") == 0 ||
+         strcmp(type, "GLenum") == 0) || strcmp(type, "GLhandleARB") == 0 ||
+         strcmp(type, "GLhalf") == 0 || strcmp(type, "GLhalfNV") == 0)
+    {
+      int pointer_of_unknown_size = 0;
+      int j;
+      
+      if (funcDesc[i].nargs == 1 && strcmp(funcDesc[i].args[0], "void") == 0)
+      {
+        funcDesc[i].nargs = 0;
+      }
+      for(j=0;j<funcDesc[i].nargs-1;j++)
+      {
+        if (!is_arg_of_length_depending_on_previous_args(&funcDesc[i], j) &&
+            strstr(funcDesc[i].args[j], "const GLchar") == NULL &&
+            strstr(funcDesc[i].args[j], "[16]") == NULL)
+        {
+          pointer_of_unknown_size |= strstr(funcDesc[i].args[j], "*") != NULL;
+          pointer_of_unknown_size |= strstr(funcDesc[i].args[j], "[") != NULL;
+        }
+      }
+
+      if (pointer_of_unknown_size == 0)
+      {
+        char* signature_type_name;
+        if (is_known_arg_vector(&funcDesc[i], &signature_type_name, NULL))
+        {
+          if (strstr(signature_type_name, "TYPE_OUT"))
+            funcDesc[i].has_out_parameters = 1;
+        }
+        else
+        {
+          if (funcDesc[i].nargs-1 >= 0)
+          {
+            j = funcDesc[i].nargs-1;
+            if (!is_arg_of_length_depending_on_previous_args(&funcDesc[i], j) &&
+                strstr(funcDesc[i].args[j], "const GLchar") == NULL &&
+                strstr(funcDesc[i].args[j], "[16]") == NULL)
+            {
+              pointer_of_unknown_size |= strstr(funcDesc[i].args[j], "*") != NULL;
+              pointer_of_unknown_size |= strstr(funcDesc[i].args[j], "[") != NULL;
+            }
+          }
+        }
+      }
+      if (pointer_of_unknown_size && funcDesc[i].nargs == 1)
+      {
+        if (strstr(funcDesc[i].name, "Matrixf") || strstr(funcDesc[i].name, "Matrixd"))
+        {
+          free(funcDesc[i].args[0]);
+          if (strstr(funcDesc[i].name, "Matrixf"))
+            funcDesc[i].args[0] = strdup("GLfloat m[16]");
+          else
+            funcDesc[i].args[0] = strdup("GLdouble m[16]");
+          pointer_of_unknown_size = 0;
+        }
+        else if (strcmp(funcDesc[i].name, "glPolygonStipple") == 0)
+        {
+          free(funcDesc[i].args[0]);
+          funcDesc[i].args[0] = strdup("const GLubyte mask[128]");
+          pointer_of_unknown_size = 0;
+        }
+        else if (strcmp(funcDesc[i].name, "glGetPolygonStipple") == 0)
+        {
+          free(funcDesc[i].args[0]);
+          funcDesc[i].args[0] = strdup("GLubyte mask[128]");
+          funcDesc[i].has_out_parameters = 1;
+          pointer_of_unknown_size = 0;
+        }
+      }
+      if (just_for_server_side_func(name) || pointer_of_unknown_size == 0)
+      {
+        fprintf(header, "  %s_func,\n", funcDesc[i].name);
+        funcDesc[i].ok = 1;
+        if (just_for_server_side_func(name))
+          funcDesc[i].just_for_server_side = 1;
+        for(j=0;j<funcDesc[i].nargs;j++)
+        {
+          if (strstr(get_type_string(funcDesc[i].args[j]), "OUT"))
+            funcDesc[i].has_out_parameters = 1;
+        }
+      }
+      else
+      {
+        fprintf(stderr, "not handled either manually or automatically : %s\n", funcDesc[i].name);
+      }
+    }
+  }
+  
+  fprintf(header, "  GL_N_CALLS\n};\n");
+
+
+  fprintf(server_stub, "void execute_func(int func_number, void **args, union gl_ret_type *pret)\n");
+  fprintf(server_stub, "{\n");
+  fprintf(server_stub, "  switch(func_number)\n");
+  fprintf(server_stub, "  {\n");
+  
+  
+  for(i=0;i<funcDescCount;i++)
+  {
+    if (funcDesc[i].ok)
+    {
+      fprintf(header, "static const int %s_signature[] = { %s, %d, ",
+              funcDesc[i].name,
+              get_type_string(funcDesc[i].type),
+              funcDesc[i].has_out_parameters);
+      fprintf(header, "%d", funcDesc[i].nargs);
+      int j;
+      char* signature_type_name;
+      int n_args_to_check = is_known_arg_vector(&funcDesc[i], &signature_type_name, NULL) ? funcDesc[i].nargs - 1 : funcDesc[i].nargs;
+      
+      for(j=0;j<n_args_to_check;j++)
+      {
+        if (is_arg_of_length_depending_on_previous_args(&funcDesc[i], j))
+        {
+          fprintf(header, ", %s_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS", get_type_string(funcDesc[i].args[j]));
+        }
+        else
+          fprintf(header, ", %s", get_type_string(funcDesc[i].args[j]));
+      }
+      
+      if (is_known_arg_vector(&funcDesc[i], &signature_type_name, NULL))
+      {
+        fprintf(header, ", %s", signature_type_name);
+      }
+      fprintf(header, "};\n");
+      
+      
+      if (funcDesc[i].just_for_server_side == 0)
+      {
+        if (isExt(&funcDesc[i]))
+          fprintf(client_stub, "GLAPI %s APIENTRY EXT_FUNC(%s) (", funcDesc[i].type, funcDesc[i].name);
+        else
+          fprintf(client_stub, "GLAPI %s APIENTRY %s(", funcDesc[i].type, funcDesc[i].name);
+        fprintf_prototype_args(client_stub, &funcDesc[i]);
+        fprintf(client_stub, ")\n");
+        fprintf(client_stub, "{\n");
+        if (strcmp(funcDesc[i].type, "void") != 0)
+        {
+          fprintf(client_stub, "  %s ret;\n", funcDesc[i].type);
+          if (isExt(&funcDesc[i]))
+            fprintf(client_stub, "  CHECK_PROC_WITH_RET(%s);\n", funcDesc[i].name);
+        }
+        else
+        {
+          if (isExt(&funcDesc[i]))
+            fprintf(client_stub, "  CHECK_PROC(%s);\n", funcDesc[i].name);
+        }
+        
+        /*
+        fprintf(client_stub, "  do_opengl_call(%s_func, %s",
+                funcDesc[i].name, (strcmp(funcDesc[i].type, "void") == 0) ? "NULL" : "&ret");
+        for(j=0;j<funcDesc[i].nargs;j++)
+        {
+          fprintf(client_stub, ", arg_%d", j);
+        }
+        fprintf(client_stub, ");\n");
+        */
+        
+        if (funcDesc[i].nargs)
+        {
+          fprintf(client_stub, "  long args[] = { ");
+          for(j=0;j<funcDesc[i].nargs;j++)
+          {
+            if (j > 0) fprintf(client_stub, ", ");
+            if (strstr(funcDesc[i].args[j], "*"))
+            {
+              fprintf(client_stub, "POINTER_TO_ARG(arg_%d)", j);
+            }
+            else
+            {
+              const char* symbolic_type = get_type_string(funcDesc[i].args[j]);
+              if (strcmp(symbolic_type, "TYPE_CHAR") == 0)
+                fprintf(client_stub, "CHAR_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_UNSIGNED_CHAR") == 0)
+                fprintf(client_stub, "UNSIGNED_CHAR_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_SHORT") == 0)
+                fprintf(client_stub, "SHORT_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_UNSIGNED_SHORT") == 0)
+                fprintf(client_stub, "UNSIGNED_SHORT_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_INT") == 0)
+                fprintf(client_stub, "INT_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_UNSIGNED_INT") == 0)
+                fprintf(client_stub, "UNSIGNED_INT_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_FLOAT") == 0)
+                fprintf(client_stub, "FLOAT_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_16FLOAT") == 0)
+                fprintf(client_stub, "POINTER_TO_ARG");
+              else if (strcmp(symbolic_type, "TYPE_DOUBLE") == 0)
+                fprintf(client_stub, "DOUBLE_TO_ARG");
+              else if ( strcmp(symbolic_type, "TYPE_16DOUBLE") == 0)
+                fprintf(client_stub, "POINTER_TO_ARG");
+              else if ( strcmp(symbolic_type, "TYPE_128UCHAR") == 0 || strcmp(symbolic_type, "TYPE_OUT_128UCHAR") == 0)
+                fprintf(client_stub, "POINTER_TO_ARG");
+              else
+              {
+                fprintf(stderr, "Unknown : %s\n", symbolic_type);
+                assert(0);
+              }
+              fprintf(client_stub, "(arg_%d)", j);
+            }
+          }
+          fprintf(client_stub, "};\n");
+        }
+        
+        fprintf(client_stub, "  do_opengl_call(%s_func, %s, %s, NULL);\n",
+                funcDesc[i].name, (strcmp(funcDesc[i].type, "void") == 0) ? "NULL" : "&ret",
+                (funcDesc[i].nargs) ? "args" : "NULL");
+        
+        if (strcmp(funcDesc[i].type, "void") != 0)
+        {
+          fprintf(client_stub, "  return ret;\n");
+        }
+        fprintf(client_stub, "}\n\n");
+      }
+      
+      fprintf(server_stub, "    case %s_func:\n", funcDesc[i].name);
+      fprintf(server_stub, "    {\n");
+      
+      if (isExt(&funcDesc[i]))
+      {
+        fprintf(server_stub, "      GET_EXT_PTR(%s, %s, (", funcDesc[i].type, funcDesc[i].name);
+        fprintf_prototype_args(server_stub, &funcDesc[i]);
+        fprintf(server_stub, "));\n");
+      }
+      
+      fprintf(server_stub, "      ");
+      
+      if (strcmp(funcDesc[i].type, "void") == 0)
+        ;
+      else if (strcmp(get_type_string(funcDesc[i].type), "TYPE_INT") == 0 ||
+               strcmp(get_type_string(funcDesc[i].type), "TYPE_UNSIGNED_INT") == 0)
+        fprintf(server_stub, "pret->i = ");
+      else if (strcmp(get_type_string(funcDesc[i].type), "TYPE_CHAR") == 0 ||
+               strcmp(get_type_string(funcDesc[i].type), "TYPE_UNSIGNED_CHAR") == 0)
+        fprintf(server_stub, "pret->c = ");
+      else
+      {
+        fprintf(stderr, "unknown ret type = %s\n", get_type_string(funcDesc[i].type));
+        exit(-1);
+      }
+      /*if (strstr(funcDesc[i].name, "EXT"))
+      {
+        char* dup = strdup(funcDesc[i].name);
+        *strstr(dup, "EXT") = 0;
+        fprintf(server_stub, "%s(", dup);
+        free(dup);
+      }
+      else*/
+      { 
+        if (isExt(&funcDesc[i]))
+          fprintf(server_stub, "ptr_func_%s(", funcDesc[i].name);
+        else
+          fprintf(server_stub, "%s(", funcDesc[i].name);
+      }
+      char* c_type_name;
+      if (is_known_arg_vector(&funcDesc[i], NULL, &c_type_name))
+      {
+        for(j=0;j<funcDesc[i].nargs - 1;j++)
+        {
+          if (j != 0) fprintf(server_stub,", ");
+          print_server_side_argument(server_stub, j, funcDesc[i].args[j]);
+        }
+        if (j != 0) fprintf(server_stub,", ");
+        if (strstr(funcDesc[i].args[funcDesc[i].nargs - 1], "const"))
+          fprintf(server_stub, "(const %s*)args[%d]", c_type_name, j);
+        else
+          fprintf(server_stub, "(%s*)args[%d]", c_type_name, j);
+      }
+      else
+      {
+        for(j=0;j<funcDesc[i].nargs;j++)
+        {
+          if (j != 0) fprintf(server_stub,", ");
+          print_server_side_argument(server_stub, j, funcDesc[i].args[j]);
+        }
+      }
+      fprintf(server_stub, ");\n");
+      
+      fprintf(server_stub, "      break;\n");
+      fprintf(server_stub, "    }\n");
+    }
+  }
+  
+  fprintf(server_stub, "    default:\n");
+  fprintf(server_stub, "      DEBUGF(\"unknown=%%d\", func_number);\n");
+  fprintf(server_stub, "      break;\n");
+  fprintf(server_stub, "  }\n");
+  fprintf(server_stub, "}\n");
+
+  fprintf(header, "#undef MAGIC_MACRO\n");
+  fprintf(header, "#define MAGIC_MACRO(x)  COMPOSE(x,_signature)\n");
+  fprintf(header, "static const int* tab_opengl_calls[GL_N_CALLS] =\n");
+  fprintf(header, "{\n");
+  fprintf(header, "#include \"gl_func_perso.h\"\n");
+  for(i=0;i<funcDescCount;i++)
+  {
+    if (funcDesc[i].ok)
+    {
+      fprintf(header, "  %s_signature,\n", funcDesc[i].name);
+    }
+  }
+  fprintf(header, "};\n\n");
+
+  fprintf(header, "#undef MAGIC_MACRO\n");
+  fprintf(header, "#define MAGIC_MACRO(x)  #x\n");
+  fprintf(header, "static const char* tab_opengl_calls_name[GL_N_CALLS] =\n");
+  fprintf(header, "{\n");
+  fprintf(header, "#include \"gl_func_perso.h\"\n");
+  for(i=0;i<funcDescCount;i++)
+  {
+    if (funcDesc[i].ok)
+    {
+      fprintf(header, "  \"%s\",\n", funcDesc[i].name);
+    }
+  }
+  fprintf(header, "};\n\n");
+  
+  fclose(header);
+  fclose(server_stub);
+  fclose(client_stub);
+
+  return 0;
+}
diff --git a/tizen/src/hw/range_alloc.h b/tizen/src/hw/range_alloc.h
new file mode 100755 (executable)
index 0000000..c1a8d77
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *  Copyright (c) 2007 Even Rouault
+ *
+ *  Modified by Ian Molton 2010
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef _OPENGL_UTILS
+#define _OPENGL_UTILS
+
+void *g_malloc(size_t size);
+void *g_realloc(void *ptr, size_t size);
+void g_free(void *ptr);
+
+typedef struct {
+    unsigned int *values;
+    int nbValues;
+} RangeAllocator;
+
+/*
+static void print_range(RangeAllocator* range)
+{
+  int i;
+  printf("%s", "table : ");
+  for(i=0;i<range->nbValues;i++)
+  {
+    printf("%d ", range->values[i]);
+  }
+  printf("\n");
+}
+*/
+
+static inline void alloc_value(RangeAllocator *range, unsigned int value)
+{
+    if (value == 0)
+        return;
+    if (range->nbValues >= 1) {
+        int lower = 0;
+        int upper = range->nbValues - 1;
+
+        while (1) {
+            int mid = (lower + upper) / 2;
+
+            if (range->values[mid] > value)
+                upper = mid;
+            else if (range->values[mid] < value)
+                lower = mid;
+            else
+                break;
+            if (upper - lower <= 1) {
+                if (value < range->values[lower]) {
+                    range->values =
+                        realloc(range->values,
+                                (range->nbValues + 1) * sizeof(int));
+                    memmove(&range->values[lower + 1], &range->values[lower],
+                            (range->nbValues - lower) * sizeof(int));
+                    range->values[lower] = value;
+                    range->nbValues++;
+                } else if (value == range->values[lower]) {
+                } else if (value < range->values[upper]) {
+                    range->values =
+                        realloc(range->values,
+                                (range->nbValues + 1) * sizeof(int));
+                    memmove(&range->values[upper + 1], &range->values[upper],
+                            (range->nbValues - upper) * sizeof(int));
+                    range->values[upper] = value;
+                    range->nbValues++;
+                } else if (value == range->values[upper]) {
+                } else {
+                    upper++;
+
+                    range->values =
+                        realloc(range->values,
+                                (range->nbValues + 1) * sizeof(int));
+                    memmove(&range->values[upper + 1], &range->values[upper],
+                            (range->nbValues - upper) * sizeof(int));
+                    range->values[upper] = value;
+                    range->nbValues++;
+                }
+                break;
+            }
+        }
+    } else {
+        range->values = g_malloc(sizeof(int));
+        range->values[0] = value;
+        range->nbValues = 1;
+    }
+}
+
+/* return first value */
+static inline unsigned int alloc_range(RangeAllocator *range, int n,
+                unsigned int *values)
+{
+    int i, j;
+
+    if (range->nbValues == 0) {
+        range->nbValues = n;
+        range->values = g_malloc(n * sizeof(int));
+        for (i = 0; i < n; i++) {
+            range->values[i] = i + 1;
+            if (values)
+                values[i] = range->values[i];
+        }
+        return 1;
+    } else {
+        int lastValue = 1;
+
+        for (i = 0; i < range->nbValues; i++) {
+            if ((int) range->values[i] - (int) lastValue - 1 >= n) {
+                range->values =
+                    realloc(range->values,
+                            (range->nbValues + n) * sizeof(int));
+                memmove(&range->values[i + n], &range->values[i],
+                        (range->nbValues - i) * sizeof(int));
+                for (j = 0; j < n; j++) {
+                    range->values[i + j] = lastValue + 1 + j;
+                    if (values)
+                        values[j] = range->values[i + j];
+                }
+                range->nbValues += n;
+                break;
+            } else
+                lastValue = range->values[i];
+        }
+        if (i == range->nbValues) {
+            range->values =
+                realloc(range->values, (range->nbValues + n) * sizeof(int));
+            for (j = 0; j < n; j++) {
+                range->values[i + j] = lastValue + 1 + j;
+                if (values)
+                    values[j] = range->values[i + j];
+            }
+            range->nbValues += n;
+        }
+        return lastValue + 1;
+    }
+}
+
+static inline void delete_value(RangeAllocator *range, unsigned int value)
+{
+    if (value == 0)
+        return;
+    if (range->nbValues >= 1) {
+        int lower = 0;
+        int upper = range->nbValues - 1;
+
+        while (1) {
+            int mid = (lower + upper) / 2;
+
+            if (range->values[mid] > value)
+                upper = mid;
+            else if (range->values[mid] < value)
+                lower = mid;
+            else {
+                lower = upper = mid;
+            }
+            if (upper - lower <= 1) {
+                if (value == range->values[lower]) {
+                    memmove(&range->values[lower], &range->values[lower + 1],
+                            (range->nbValues - lower - 1) * sizeof(int));
+                    range->nbValues--;
+                } else if (value == range->values[upper]) {
+                    memmove(&range->values[upper], &range->values[upper + 1],
+                            (range->nbValues - upper - 1) * sizeof(int));
+                    range->nbValues--;
+                }
+                break;
+            }
+        }
+    }
+}
+
+static inline void delete_range(RangeAllocator *range, int n,
+                const unsigned int *values)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+        delete_value(range, values[i]);
+    }
+}
+
+static inline void delete_consecutive_values(RangeAllocator *range,
+                unsigned int first, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+        delete_value(range, first + i);
+    }
+}
+
+#endif
diff --git a/tizen/src/hw/virtio-gl.c b/tizen/src/hw/virtio-gl.c
new file mode 100755 (executable)
index 0000000..4ca1ed7
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *  Virtio GL Device
+ *
+ *  Copyright (c) 2010 Intel Corporation
+ *  Written by:
+ *    Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * 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 "virtio.h"
+
+typedef target_phys_addr_t arg_t;
+#include "opengl_process.h"
+#include "opengl_exec.h"
+#include <sys/time.h>
+
+#include "tizen/src/debug_ch.h"
+MULTI_DEBUG_CHANNEL(qemu, virtio-gl);
+
+int decode_call_int(ProcessStruct *p, char *in_args, int args_len, char *r_buffer);
+
+/* Uncomment to enable debugging - WARNING!!! changes ABI! */
+//#define DEBUG_GLIO
+
+typedef struct VirtIOGL
+{
+       VirtIODevice vdev;
+       VirtQueue *vq;
+} VirtIOGL;
+
+struct d_hdr
+{
+       int pid;
+       int rq_l;
+       int rrq_l;
+#ifdef DEBUG_GLIO
+       int sum;
+#endif
+};
+
+#define SIZE_OUT_HEADER sizeof(struct d_hdr)
+
+#ifdef DEBUG_GLIO
+#define SIZE_IN_HEADER (4*2)
+#else
+#define SIZE_IN_HEADER 4
+#endif
+
+static void virtio_gl_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+       VirtQueueElement elem;
+       int nkill = 1;
+
+       TRACE("virtio_gl_handle called. \n");
+
+       while(virtqueue_pop(vq, &elem)) {
+               struct d_hdr *hdr = (struct d_hdr*)elem.out_sg[0].iov_base;
+               ProcessStruct *process;
+               int i, remain;
+               int ret = 0;
+
+               if(!elem.out_num) {
+                       fprintf(stderr, "Bad packet\n");
+                       goto done;
+               }
+
+               process = vmgl_get_process(hdr->pid);
+
+               if(hdr->rq_l) {
+
+                       if(hdr->rrq_l) {
+                               if(process->rq) {  // Usually only the quit packet...
+                                       free(process->rq);
+                                       free(process->rrq);
+                               }
+                               //                process->rq  = process->rq_p  = qemu_malloc(hdr->rq_l);
+                               //                process->rrq = process->rrq_p = qemu_malloc(hdr->rrq_l);
+                               process->rq  = process->rq_p  = g_malloc(hdr->rq_l);
+                               process->rrq = process->rrq_p = g_malloc(hdr->rrq_l);
+                               process->rq_l  = hdr->rq_l - SIZE_OUT_HEADER;
+                               process->rrq_l = hdr->rrq_l;
+#ifdef DEBUG_GLIO
+                               process->sum = hdr->sum;
+#endif
+                       }
+
+                       i = 0;
+                       remain = process->rq_l - (process->rq_p - process->rq);
+                       while(remain && i < elem.out_num){
+                               char *src = (char *)elem.out_sg[i].iov_base;
+                               int ilen = elem.out_sg[i].iov_len;
+                               int len = remain;
+
+                               if(i == 0) {
+                                       src += SIZE_OUT_HEADER;
+                                       ilen -= SIZE_OUT_HEADER;
+                               }
+
+                               if(len > ilen)
+                                       len = ilen;
+
+                               memcpy(process->rq_p, src, len);
+                               process->rq_p += len;
+                               remain -= len;
+                               i++;
+                       }
+
+                       if(process->rq_p >= process->rq + process->rq_l) {
+
+#ifdef DEBUG_GLIO
+                               int sum = 0;
+                               for(i = 0; i < process->rq_l ; i++)
+                                       sum += process->rq[i];
+                               if(sum != process->sum)
+                                       fprintf(stderr, "Checksum fail\n");
+#endif
+
+                               *(int*)process->rrq = nkill = decode_call_int(process, 
+                                               process->rq,      /* command_buffer */
+                                               process->rq_l,    /* cmd buffer length */
+                                               process->rrq + SIZE_IN_HEADER);    /* return buffer */
+
+                               //qemu_free(process->rq);
+                               g_free(process->rq);
+                               process->rq = NULL;
+
+#ifdef DEBUG_GLIO
+                               sum = 0;
+                               for(i = SIZE_IN_BUFFER; i < process->rrq_l ; i++)
+                                       sum += process->rrq[i];
+                               *(int*)(process->rrq+sizeof(int)) = sum;
+#endif
+
+                       }
+               }
+
+               if(hdr->rrq_l && process->rq == NULL) {
+
+                       i = 0;
+                       remain = process->rrq_l - (process->rrq_p - process->rrq);
+                       while(remain && i < elem.in_num) {
+                               char *dst = elem.in_sg[i].iov_base;
+                               int len = remain;
+                               int ilen = elem.in_sg[i].iov_len;
+
+                               if(len > ilen)
+                                       len = ilen;
+
+                               memcpy(dst, process->rrq_p, len);
+                               process->rrq_p += len;
+                               remain -= len;
+                               ret += len;
+                               i++;
+                       }
+
+                       if(remain <= 0) {
+                               //qemu_free(process->rrq);
+                               g_free(process->rrq);
+                               if(!nkill)
+                                       gl_disconnect(process);
+                       }
+               }
+done:
+               virtqueue_push(vq, &elem, ret);
+
+               virtio_notify(vdev, vq);
+       }
+}
+
+static uint32_t virtio_gl_get_features(VirtIODevice *vdev, uint32_t f)
+{
+       return 0;
+}
+
+static void virtio_gl_save(QEMUFile *f, void *opaque)
+{
+       VirtIOGL *s = opaque;
+
+       virtio_save(&s->vdev, f);
+}
+
+static int virtio_gl_load(QEMUFile *f, void *opaque, int version_id)
+{
+       VirtIOGL *s = opaque;
+
+       if (version_id != 1)
+               return -EINVAL;
+
+       virtio_load(&s->vdev, f);
+       return 0;
+}
+
+VirtIODevice *virtio_gl_init(DeviceState *dev)
+{
+       VirtIOGL *s;
+
+       s = (VirtIOGL *)virtio_common_init("virtio-gl", VIRTIO_ID_GL,
+                       0, sizeof(VirtIOGL));
+       if (!s)
+               return NULL;
+
+       s->vdev.get_features = virtio_gl_get_features;
+       s->vq = virtio_add_queue(&s->vdev, 128, virtio_gl_handle);
+       register_savevm(dev, "virtio-gl", -1, 1, virtio_gl_save, virtio_gl_load, s);
+
+       return &s->vdev;
+}
+
diff --git a/tizen/src/maru_common.h b/tizen/src/maru_common.h
new file mode 100644 (file)
index 0000000..89d1905
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Emulator
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+/**
+ * @file emulator.h
+ * @brief - header of file these are config structures and defines in emulator
+ */
+
+#ifndef __MARU_COMMON_H__
+#define __MARU_COMMON_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#endif /* __MARU_COMMON_H__ */
diff --git a/tizen/src/maru_finger.c b/tizen/src/maru_finger.c
new file mode 100644 (file)
index 0000000..f90702f
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Multi-touch processing
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <math.h>
+#include <glib.h>
+#include <SDL.h>
+#include "maru_finger.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+#include "console.h"
+
+MULTI_DEBUG_CHANNEL(qemu, maru_finger);
+
+
+/* ===== Reference: http://content.gpwiki.org/index.php/SDL:Tutorials:Drawing_and_Filling_Circles ===== */
+/*
+ * This is a 32-bit pixel function created with help from this
+* website: http://www.libsdl.org/intro.en/usingvideo.html
+*
+* You will need to make changes if you want it to work with
+* 8-, 16- or 24-bit surfaces.  Consult the above website for
+* more information.
+*/
+static void sdl_set_pixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {
+   Uint8 *target_pixel = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
+   *(Uint32 *)target_pixel = pixel;
+}
+
+/*
+* This is an implementation of the Midpoint Circle Algorithm 
+* found on Wikipedia at the following link:
+*
+*   http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
+*
+* The algorithm elegantly draws a circle quickly, using a
+* set_pixel function for clarity.
+*/
+static void sdl_draw_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel) {
+   int error = -radius;
+   int x = radius;
+   int y = 0;
+
+   while (x >= y) {
+       sdl_set_pixel(surface, cx + x, cy + y, pixel);
+       sdl_set_pixel(surface, cx + y, cy + x, pixel);
+
+       if (x != 0) {
+           sdl_set_pixel(surface, cx - x, cy + y, pixel);
+           sdl_set_pixel(surface, cx + y, cy - x, pixel);
+       }
+
+       if (y != 0) {
+           sdl_set_pixel(surface, cx + x, cy - y, pixel);
+           sdl_set_pixel(surface, cx - y, cy + x, pixel);
+       }
+
+       if (x != 0 && y != 0) {
+           sdl_set_pixel(surface, cx - x, cy - y, pixel);
+           sdl_set_pixel(surface, cx - y, cy - x, pixel);
+       }
+
+       error += y;
+       ++y;
+       error += y;
+
+       if (error >= 0) {
+           --x;
+           error -= x;
+           error -= x;
+       }
+   }
+}
+
+/*
+ * SDL_Surface 32-bit circle-fill algorithm without using trig
+*
+* While I humbly call this "Celdecea's Method", odds are that the
+* procedure has already been documented somewhere long ago.  All of
+* the circle-fill examples I came across utilized trig functions or
+* scanning neighbor pixels.  This algorithm identifies the width of
+* a semi-circle at each pixel height and draws a scan-line covering
+* that width.
+*
+* The code is not optimized but very fast, owing to the fact that it
+* alters pixels in the provided surface directly rather than through
+* function calls.
+*
+* WARNING:  This function does not lock surfaces before altering, so
+* use SDL_LockSurface in any release situation.
+*/
+static void sdl_fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel)
+{
+   // Note that there is more to altering the bitrate of this
+   // method than just changing this value.  See how pixels are
+   // altered at the following web page for tips:
+   //   http://www.libsdl.org/intro.en/usingvideo.html
+   const int bpp = 4;
+   double dy;
+
+   double r = (double)radius;
+
+   for (dy = 1; dy <= r; dy += 1.0)
+   {
+       // This loop is unrolled a bit, only iterating through half of the
+       // height of the circle.  The result is used to draw a scan line and
+       // its mirror image below it.
+       // The following formula has been simplified from our original.  We
+       // are using half of the width of the circle because we are provided
+       // with a center and we need left/right coordinates.
+       double dx = floor(sqrt((2.0 * r * dy) - (dy * dy)));
+       int x = cx - dx;
+       // Grab a pointer to the left-most pixel for each half of the circle
+       Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * bpp;
+       Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * bpp;
+
+       for (; x <= cx + dx; x++)
+       {
+           *(Uint32 *)target_pixel_a = pixel;
+           *(Uint32 *)target_pixel_b = pixel;
+           target_pixel_a += bpp;
+           target_pixel_b += bpp;
+       }
+   }
+}
+/* ==================================================================================================== */
+
+void init_multi_touch_state(void)
+{
+    int i;
+    MultiTouchState* mts = get_emul_multi_touch_state();
+    FingerPoint *finger = NULL;
+    INFO("multi-touch state initialization\n");
+
+    mts->multitouch_enable = 0;
+
+    mts->finger_cnt_max = get_emul_max_touch_point();
+    if (mts->finger_cnt_max > MAX_FINGER_CNT) {
+        mts->finger_cnt_max = MAX_FINGER_CNT; //TODO:
+        set_emul_max_touch_point(mts->finger_cnt_max);
+    }
+    INFO("maxTouchPoint=%d\n", get_emul_max_touch_point());
+
+    mts->finger_cnt = 0;
+
+    if (mts->finger_slot != NULL) {
+        g_free(mts->finger_slot);
+        mts->finger_slot = NULL;
+    }
+    mts->finger_slot = (FingerPoint *)g_malloc0(sizeof(FingerPoint) * mts->finger_cnt_max);
+
+    for (i = 0; i < mts->finger_cnt_max; i++) {
+        finger = get_finger_point_from_slot(i);
+        //finger->id = 0;
+        finger->x = finger->y = -1;
+    }
+
+    mts->finger_point_size = DEFAULT_FINGER_POINT_SIZE; //temp
+    int finger_point_size_half = mts->finger_point_size / 2;
+    mts->finger_point_color = DEFAULT_FINGER_POINT_COLOR; //temp
+    mts->finger_point_outline_color = DEFAULT_FINGER_POINT_OUTLINE_COLOR; //temp
+
+    /* create finger point surface */
+    Uint32 rmask, gmask, bmask, amask;
+#ifdef HOST_WORDS_BIGENDIAN
+    rmask = 0xff000000;
+    gmask = 0x00ff0000;
+    bmask = 0x0000ff00;
+    amask = 0x000000ff;
+#else
+    rmask = 0x000000ff;
+    gmask = 0x0000ff00;
+    bmask = 0x00ff0000;
+    amask = 0xff000000;
+#endif
+
+    SDL_Surface *point = SDL_CreateRGBSurface(SDL_SRCALPHA | SDL_HWSURFACE,
+               mts->finger_point_size + 2, mts->finger_point_size + 2, get_emul_sdl_bpp(), rmask, gmask, bmask, amask);
+
+    sdl_fill_circle(point, finger_point_size_half, finger_point_size_half,
+        finger_point_size_half, mts->finger_point_color); //finger point circle
+    sdl_draw_circle(point, finger_point_size_half, finger_point_size_half, finger_point_size_half,
+        mts->finger_point_outline_color); // finger point circle outline
+
+    mts->finger_point_surface = (void *)point;
+}
+
+void set_multi_touch_enable(int enable)
+{
+    get_emul_multi_touch_state()->multitouch_enable = enable;
+}
+
+int get_multi_touch_enable(void)
+{
+    return get_emul_multi_touch_state()->multitouch_enable;
+}
+
+static int _add_finger_point(int x, int y)
+{
+    MultiTouchState *mts = get_emul_multi_touch_state();
+
+    if (mts->finger_cnt == mts->finger_cnt_max) {
+        INFO("support multi-touch up to %d fingers\n", mts->finger_cnt_max);
+        return -1;
+    }
+
+    mts->finger_cnt += 1;
+
+    mts->finger_slot[mts->finger_cnt - 1].id = mts->finger_cnt;
+    mts->finger_slot[mts->finger_cnt - 1].x = x;
+    mts->finger_slot[mts->finger_cnt - 1].y = y;
+    INFO("%d finger touching\n", mts->finger_cnt);
+
+    return mts->finger_cnt;
+}
+
+FingerPoint *get_finger_point_from_slot(int index)
+{
+    MultiTouchState *mts = get_emul_multi_touch_state();
+
+    if (index < 0 || index > mts->finger_cnt_max) {
+        return NULL;
+    }
+
+    return &(mts->finger_slot[index]);
+}
+
+FingerPoint *get_finger_point_search(int x, int y)
+{
+    int i;
+    MultiTouchState *mts = get_emul_multi_touch_state();
+    FingerPoint *finger = NULL;
+    int finger_point_size_half = (mts->finger_point_size / 2) + 2;
+
+    for (i = mts->finger_cnt - 1; i >= 0; i--) {
+        finger = get_finger_point_from_slot(i);
+        if (finger != NULL) {
+            if (x >= (finger->x - finger_point_size_half) &&
+                x < (finger->x + finger_point_size_half) &&
+                y >= (finger->y - finger_point_size_half) &&
+                y < (finger->y + finger_point_size_half)) {
+                    return finger;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static int _grab_finger_id = 0;
+#define QEMU_MOUSE_PRESSED 1
+#define QEMU_MOUSE_RELEASEED 0
+void maru_finger_processing(int x, int y, int touch_type)
+{
+    MultiTouchState *mts = get_emul_multi_touch_state();
+    FingerPoint *finger = NULL;
+
+    if (touch_type == MOUSE_DOWN || touch_type == MOUSE_DRAG) { /* pressed */
+        if (_grab_finger_id > 0) {
+            finger = get_finger_point_from_slot(_grab_finger_id - 1);
+            if (finger != NULL) {
+                finger->x = x;
+                finger->y = y;
+                if (finger->id != 0) {
+                    kbd_mouse_event(x, y, _grab_finger_id - 1, QEMU_MOUSE_PRESSED);
+                    TRACE("id %d finger multi-touch dragging = (%d, %d)\n", _grab_finger_id, x, y);
+                }
+            }
+            return;
+        }
+
+        if (mts->finger_cnt == 0)
+        { //first finger touch input
+            if (_add_finger_point(x, y) == -1) {
+                return;
+            }
+            kbd_mouse_event(x, y, 0, QEMU_MOUSE_PRESSED);
+        }
+        else if ((finger = get_finger_point_search(x, y)) != NULL) //check the position of previous touch event
+        {
+            //finger point is selected
+            _grab_finger_id = finger->id;
+            TRACE("id %d finger is grabbed\n", _grab_finger_id);
+        }
+        else if (mts->finger_cnt == mts->finger_cnt_max) //Let's assume that this event is last finger touch input
+        {
+            finger = get_finger_point_from_slot(mts->finger_cnt_max - 1);
+            if (finger != NULL) {
+#if 1 //send release event??
+                kbd_mouse_event(finger->x, finger->y, mts->finger_cnt_max - 1, 0);
+#endif
+
+                finger->x = x;
+                finger->y = y;
+                if (finger->id != 0) {
+                    kbd_mouse_event(x, y, mts->finger_cnt_max - 1, QEMU_MOUSE_PRESSED);
+                }
+            }
+        }
+        else //one more finger
+        {
+            _add_finger_point(x, y) ;
+            kbd_mouse_event(x, y, mts->finger_cnt - 1, QEMU_MOUSE_PRESSED);
+        }
+
+    } else if (touch_type == MOUSE_UP) { /* released */
+        _grab_finger_id = 0;
+    }
+
+}
+
+void clear_finger_slot(void)
+{
+    int i;
+    MultiTouchState *mts = get_emul_multi_touch_state();
+    FingerPoint *finger = NULL;
+
+    for (i = 0; i < mts->finger_cnt; i++) {
+        finger = get_finger_point_from_slot(i);
+        if (finger != NULL && finger->id != 0) {
+            kbd_mouse_event(finger->x, finger->y, finger->id - 1, QEMU_MOUSE_RELEASEED);
+        }
+
+        finger->id = 0;
+        finger->x = finger->y = -1;
+    }
+
+    _grab_finger_id = 0;
+
+    mts->finger_cnt = 0;
+    INFO("clear multi-touch\n");
+}
+
+void cleanup_multi_touch_state(void)
+{
+    MultiTouchState *mts = get_emul_multi_touch_state();
+    SDL_Surface *point = (SDL_Surface *)mts->finger_point_surface;
+
+    mts->multitouch_enable = 0;
+
+    clear_finger_slot();
+    g_free(mts->finger_slot);
+
+    mts->finger_point_surface = NULL;
+    SDL_FreeSurface(point);
+}
+
diff --git a/tizen/src/maru_finger.h b/tizen/src/maru_finger.h
new file mode 100644 (file)
index 0000000..a37edb5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Multi-touch processing
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef __MARU_FINGER_H__
+#define __MARU_FINGER_H__
+
+
+/* definitions relating to multi-touch */
+//TODO : from arg
+#define MAX_FINGER_CNT 2
+#define DEFAULT_FINGER_POINT_SIZE 32
+#define DEFAULT_FINGER_POINT_COLOR 0x7E0F0F0F
+#define DEFAULT_FINGER_POINT_OUTLINE_COLOR 0xDDDDDDDD
+
+typedef struct FingerPoint {
+    int id;
+    int x;
+    int y;
+} FingerPoint;
+
+typedef struct MultiTouchState {
+    int multitouch_enable;
+    int finger_cnt;
+    int finger_cnt_max;
+    FingerPoint *finger_slot;
+
+    int finger_point_size;
+    int finger_point_color;
+    int finger_point_outline_color;
+    void *finger_point_surface; //SDL_Surface
+} MultiTouchState;
+
+
+void init_multi_touch_state(void);
+void set_multi_touch_enable(int enable);
+int get_multi_touch_enable(void);
+FingerPoint *get_finger_point_from_slot(int index);
+FingerPoint *get_finger_point_search(int x, int y);
+void maru_finger_processing(int x, int y, int touch_type);
+void clear_finger_slot(void);
+void cleanup_multi_touch_state(void);
+
+
+#endif /* __MARU_FINGER_H__ */
diff --git a/tizen/src/maru_sdl.c b/tizen/src/maru_sdl.c
new file mode 100644 (file)
index 0000000..0957e14
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * MARU SDL display driver
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <pthread.h>
+#include "console.h"
+#include "maru_sdl.h"
+#include "emul_state.h"
+#include "sdl_rotate.h"
+#include "maru_finger.h"
+#include "hw/maru_pm.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru_sdl);
+
+
+// TODO : organize
+SDL_Surface *surface_screen;
+SDL_Surface *surface_qemu;
+
+static double scale_factor = 1.0;
+static double screen_degree = 0.0;
+static int sdl_initialized = 0;
+
+#define SDL_THREAD
+
+static pthread_mutex_t sdl_mutex = PTHREAD_MUTEX_INITIALIZER;
+#ifdef SDL_THREAD
+static pthread_cond_t sdl_cond = PTHREAD_COND_INITIALIZER;
+static int sdl_thread_initialized = 0;
+#endif
+
+#define SDL_FLAGS (SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_NOFRAME)
+#define SDL_BPP 32
+
+DisplaySurface* qemu_display_surface = NULL;
+
+static void qemu_update(void)
+{
+    int i;
+    SDL_Surface *processing_screen = NULL;
+
+    if (surface_qemu != NULL) {
+        if (scale_factor != 1.0 || screen_degree != 0.0) {
+
+            // workaround
+            // set color key 'magenta'
+            surface_qemu->format->colorkey = 0xFF00FF;
+
+            //image processing
+            processing_screen = rotozoomSurface(surface_qemu, screen_degree, scale_factor, 1);
+            SDL_BlitSurface(processing_screen, NULL, surface_screen, NULL);
+        } else {
+            SDL_BlitSurface(surface_qemu, NULL, surface_screen, NULL);
+        }
+    }
+
+    /* draw multi-touch finger points */
+    MultiTouchState *mts = get_emul_multi_touch_state();
+    if (mts->multitouch_enable == 1 && mts->finger_point_surface != NULL) {
+        FingerPoint *finger = NULL;
+        int finger_point_size_half = mts->finger_point_size / 2;
+        SDL_Rect rect;
+
+        for (i = 0; i < mts->finger_cnt; i++) {
+            finger = get_finger_point_from_slot(i);
+            if (finger != NULL && finger->id != 0) {
+                rect.x = (finger->x * get_emul_win_scale()) - finger_point_size_half;
+                rect.y = (finger->y * get_emul_win_scale()) - finger_point_size_half;
+                rect.w = rect.h = mts->finger_point_size;
+
+                SDL_BlitSurface((SDL_Surface *)mts->finger_point_surface, NULL, surface_screen, &rect);
+            }
+        }
+    }
+
+    SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+
+    SDL_FreeSurface(processing_screen);
+}
+
+
+#ifdef SDL_THREAD
+static void* run_qemu_update(void* arg)
+{
+    while(1) { 
+        pthread_mutex_lock(&sdl_mutex);
+
+        pthread_cond_wait(&sdl_cond, &sdl_mutex); 
+
+        qemu_update();
+
+        pthread_mutex_unlock(&sdl_mutex);
+    } 
+
+    return NULL;
+}
+#endif
+
+static void qemu_ds_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    /* call sdl update */
+#ifdef SDL_THREAD
+    pthread_mutex_lock(&sdl_mutex);
+
+    pthread_cond_signal(&sdl_cond);
+
+    pthread_mutex_unlock(&sdl_mutex);
+#else
+    qemu_update();
+#endif
+}
+
+static void qemu_ds_resize(DisplayState *ds)
+{
+    TRACE("%d, %d\n", ds_get_width(ds), ds_get_height(ds));
+
+#ifdef SDL_THREAD
+    pthread_mutex_lock(&sdl_mutex);
+#endif
+
+    /* create surface_qemu */
+    surface_qemu = SDL_CreateRGBSurfaceFrom(ds_get_data(ds),
+            ds_get_width(ds),
+            ds_get_height(ds),
+            ds_get_bits_per_pixel(ds),
+            ds_get_linesize(ds),
+            ds->surface->pf.rmask,
+            ds->surface->pf.gmask,
+            ds->surface->pf.bmask,
+            ds->surface->pf.amask);
+
+#ifdef SDL_THREAD
+    pthread_mutex_unlock(&sdl_mutex);
+#endif
+
+    if (surface_qemu == NULL) {
+        ERR( "Unable to set the RGBSurface: %s", SDL_GetError() );
+        return;
+    }
+
+}
+
+static int maru_sdl_poll_event(SDL_Event *ev)
+{
+    int ret = 0;
+
+    if (sdl_initialized == 1) {
+        //pthread_mutex_lock(&sdl_mutex);
+        ret = SDL_PollEvent(ev);
+        //pthread_mutex_unlock(&sdl_mutex);
+    }
+
+    return ret;
+}
+
+static void put_hardkey_code( SDL_UserEvent event ) {
+
+    // use pointer as integer
+    int event_type = (int) event.data1;
+    int keycode = (int) event.data2;
+
+    if ( KEY_PRESSED == event_type ) {
+
+        if ( kbd_mouse_is_absolute() ) {
+            ps2kbd_put_keycode( keycode & 0x7f );
+        }
+
+    } else if ( KEY_RELEASED == event_type ) {
+
+        if ( kbd_mouse_is_absolute() ) {
+            ps2kbd_put_keycode( keycode | 0x80 );
+        }
+
+    } else {
+        ERR( "Unknown hardkey event type.[event_type:%d]", event_type );
+    }
+
+}
+
+static void handle_sdl_user_event ( SDL_UserEvent event ) {
+
+    int code = event.code;
+
+    switch ( code ) {
+    case SDL_USER_EVENT_CODE_HARDKEY: {
+        put_hardkey_code( event );
+        break;
+    }
+    default: {
+        ERR( "Unknown sdl user event.[event code:%d]\n", code );
+        break;
+    }
+    }
+
+}
+
+static void qemu_ds_refresh(DisplayState *ds)
+{
+    SDL_Event ev1, *ev = &ev1;
+
+    vga_hw_update();
+
+    // surface may be NULL in init func.
+    qemu_display_surface = ds->surface;
+
+    while (maru_sdl_poll_event(ev)) {
+        switch (ev->type) {
+            case SDL_VIDEORESIZE:
+            {
+                int w, h, temp;
+
+                //get current setting information and calculate screen size
+                scale_factor = get_emul_win_scale();
+                w = get_emul_lcd_width() * scale_factor;
+                h = get_emul_lcd_height() * scale_factor;
+
+                short rotaton_type = get_emul_rotation();
+                if (rotaton_type == ROTATION_PORTRAIT) {
+                    screen_degree = 0.0;
+                } else if (rotaton_type == ROTATION_LANDSCAPE) {
+                    screen_degree = 90.0;
+                    temp = w;
+                    w = h;
+                    h = temp;
+                } else if (rotaton_type == ROTATION_REVERSE_PORTRAIT) {
+                    screen_degree = 180.0;
+                } else if (rotaton_type == ROTATION_REVERSE_LANDSCAPE) {
+                    screen_degree = 270.0;
+                    temp = w;
+                    w = h;
+                    h = temp;
+                }
+
+                pthread_mutex_lock(&sdl_mutex);
+
+                SDL_Quit(); //The returned surface is freed by SDL_Quit and must not be freed by the caller
+                surface_screen = SDL_SetVideoMode(w, h, SDL_BPP, SDL_FLAGS);
+                if (surface_screen == NULL) {
+                    ERR("Could not open SDL display (%dx%dx%d): %s\n", w, h, SDL_BPP, SDL_GetError());
+                }
+
+                pthread_mutex_unlock(&sdl_mutex);
+
+                break;
+            }
+            case SDL_USEREVENT: {
+                handle_sdl_user_event( ev->user );
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+}
+
+void maruskin_display_init(DisplayState *ds)
+{
+    INFO( "qemu display initialization\n");
+
+    /*  graphics context information */
+    DisplayChangeListener *dcl;
+
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
+    dcl->dpy_update = qemu_ds_update;
+    dcl->dpy_resize = qemu_ds_resize;
+    dcl->dpy_refresh = qemu_ds_refresh;
+
+    register_displaychangelistener(ds, dcl);
+
+#ifdef SDL_THREAD
+    if (sdl_thread_initialized == 0) {
+        sdl_thread_initialized = 1;
+        pthread_t thread_id;
+        INFO( "sdl update thread create\n");
+        if (pthread_create(&thread_id, NULL, run_qemu_update, NULL) != 0) {
+            ERR( "pthread_create fail\n");
+            return;
+        }
+    }
+#endif
+}
+
+void maruskin_sdl_init(int swt_handle, int lcd_size_width, int lcd_size_height)
+{
+    int w, h;
+    gchar SDL_windowhack[32];
+    SDL_SysWMinfo info;
+    long window_id = swt_handle;
+
+    sprintf(SDL_windowhack, "%ld", window_id);
+    g_setenv("SDL_WINDOWID", SDL_windowhack, 1);
+    INFO("register SDL environment variable. (SDL_WINDOWID = %s)\n", SDL_windowhack);
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0 ) {
+        ERR( "unable to init SDL: %s", SDL_GetError() );
+        exit(1);
+    }
+
+    set_emul_lcd_size(lcd_size_width, lcd_size_height);
+
+    //get current setting information and calculate screen size
+    scale_factor = get_emul_win_scale();
+    w = lcd_size_width * scale_factor;
+    h = lcd_size_height * scale_factor;
+
+    set_emul_sdl_bpp(SDL_BPP);
+
+    INFO( "maru sdl initialization\n");
+    surface_screen = SDL_SetVideoMode(w, h, get_emul_sdl_bpp(), SDL_FLAGS);
+    if (surface_screen == NULL) {
+        ERR("Could not open SDL display (%dx%dx%d): %s\n", w, h, get_emul_sdl_bpp(), SDL_GetError());
+    }
+
+#ifndef _WIN32
+    SDL_VERSION(&info.version);
+    SDL_GetWMInfo(&info);
+#endif
+
+    sdl_initialized = 1;
+    init_multi_touch_state();
+}
+
+void maruskin_sdl_resize(void)
+{
+    SDL_Event ev;
+
+    /* this fails if SDL is not initialized */
+    memset(&ev, 0, sizeof(ev));
+    ev.resize.type = SDL_VIDEORESIZE;
+
+    //This function is thread safe, and can be called from other threads safely.
+    SDL_PushEvent(&ev);
+}
+
+DisplaySurface* get_qemu_display_surface( void ) {
+    return qemu_display_surface;
+}
diff --git a/tizen/src/maru_sdl.h b/tizen/src/maru_sdl.h
new file mode 100644 (file)
index 0000000..359a39a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * MARU SDL display driver
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_SDL_H_
+#define MARU_SDL_H_
+
+#include "console.h"
+
+#if 0
+#ifdef _WIN32
+#include <windows.h>
+#include <winbase.h>
+#endif
+#endif
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+#include "qemu-common.h"
+
+#define SDL_USER_EVENT_CODE_HARDKEY 1
+
+void maruskin_display_init(DisplayState *ds);
+void maruskin_sdl_init(int swt_handle, int lcd_size_width, int lcd_size_height);
+void maruskin_sdl_resize(void);
+
+DisplaySurface* get_qemu_display_surface( void );
+
+#endif /* MARU_SDL_H_ */
diff --git a/tizen/src/mloop_event.c b/tizen/src/mloop_event.c
new file mode 100644 (file)
index 0000000..3d5502f
--- /dev/null
@@ -0,0 +1,357 @@
+/*\r
+ * mainloop_evhandle.c\r
+ *\r
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * Contact:\r
+ * DoHyung Hong <don.hong@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+\r
+#ifdef _WIN32\r
+#include <winsock.h>\r
+#define        socklen_t     int\r
+#else\r
+#include <netinet/in.h>\r
+#include <sys/ioctl.h>\r
+#endif\r
+\r
+#include "qobject.h"\r
+#include "qemu-common.h"\r
+#include "hw/usb.h"\r
+#include "hw/irq.h"\r
+#include "mloop_event.h"\r
+\r
+#define error_report(x, ...)\r
+\r
+struct mloop_evsock {\r
+    int sockno;\r
+    unsigned short portno;\r
+    unsigned char status;\r
+};\r
+\r
+#define MLOOP_EVSOCK_NULL        0\r
+#define MLOOP_EVSOCK_CREATED    1\r
+#define MLOOP_EVSOCK_NOTBOUND    2\r
+#define MLOOP_EVSOCK_BOUND        3\r
+#define MLOOP_EVSOCK_CONNECTED    4\r
+\r
+#define PACKET_LEN 512\r
+struct mloop_evpack {\r
+    short type;\r
+    short size;\r
+    char data[PACKET_LEN-4];\r
+};\r
+\r
+#define MLOOP_EVTYPE_USB_ADD    1\r
+#define MLOOP_EVTYPE_USB_DEL    2\r
+#define MLOOP_EVTYPE_INTR_UP    3\r
+#define MLOOP_EVTYPE_INTR_DOWN  4\r
+\r
+static struct mloop_evsock mloop = {-1,0,0};\r
+\r
+static int mloop_evsock_create(struct mloop_evsock *ev)\r
+{\r
+    struct sockaddr sa;\r
+    socklen_t sa_size;\r
+    int ret;\r
+    unsigned long nonblock = 1;\r
+\r
+    if (ev == NULL) {\r
+        error_report("mloop_evsock: null point");\r
+        return -1;\r
+    }\r
+\r
+    ev->sockno = socket(AF_INET, SOCK_DGRAM, 0);\r
+    if( ev->sockno == -1 ) {\r
+        error_report("mloop_evsock: socket() failed");\r
+        return -1;\r
+    }\r
+\r
+#ifdef _WIN32\r
+    ioctlsocket(ev->sockno, FIONBIO, &nonblock );\r
+#else\r
+    ioctl(ev->sockno, FIONBIO, &nonblock);\r
+#endif // _WIN32\r
+\r
+    nonblock = 1 ;\r
+    setsockopt( ev->sockno, SOL_SOCKET, SO_REUSEADDR, (char *)&nonblock, sizeof(nonblock) ) ;\r
+\r
+    memset(&sa, '\0', sizeof(sa));\r
+    ((struct sockaddr_in *) &sa)->sin_family = AF_INET;\r
+    memcpy(&((struct sockaddr_in *) &sa)->sin_addr, "\177\000\000\001", 4); // 127.0.0.1\r
+    ((struct sockaddr_in *) &sa)->sin_port = htons(ev->portno);\r
+    sa_size = sizeof(struct sockaddr_in);\r
+\r
+    ret = bind(ev->sockno, &sa, sa_size);\r
+    if (ret) {\r
+        error_report("mloop_evsock: bind() failed");\r
+        goto mloop_evsock_init_cleanup;\r
+    }\r
+\r
+    if (ev->portno == 0) {\r
+        memset(&sa, '\0', sizeof(sa));\r
+        getsockname(ev->sockno, (struct sockaddr *) &sa, &sa_size);\r
+        ev->portno = ntohs(((struct sockaddr_in *) &sa)->sin_port);\r
+    }\r
+\r
+    ret = connect(ev->sockno, (struct sockaddr *) &sa, sa_size);\r
+    if (ret) {\r
+        error_report("mloop_evsock: connect() failed");\r
+        goto mloop_evsock_init_cleanup;\r
+    }\r
+\r
+    ev->status = MLOOP_EVSOCK_CONNECTED;\r
+    return 0;\r
+\r
+mloop_evsock_init_cleanup:\r
+#ifdef _WIN32\r
+    closesocket(ev->sockno);\r
+#else\r
+    close(ev->sockno);\r
+#endif\r
+    ev->sockno = -1;\r
+    ev->status = 0;\r
+    return ret;\r
+}\r
+\r
+static void mloop_evsock_remove(struct mloop_evsock *ev)\r
+{\r
+    if (!ev) {\r
+        return ;\r
+    }\r
+\r
+    if (ev->sockno > 0) {\r
+#ifdef _WIN32\r
+        shutdown(ev->sockno, SD_BOTH);\r
+        closesocket(ev->sockno);\r
+#else\r
+        shutdown(ev->sockno, SHUT_RDWR);\r
+        close(ev->sockno);\r
+#endif\r
+        ev->sockno = -1;\r
+        ev->status = 0;\r
+    }\r
+}\r
+\r
+static int mloop_evsock_send(struct mloop_evsock *ev, struct mloop_evpack *p)\r
+{\r
+    int ret;\r
+\r
+    if (ev == NULL || ev->sockno == -1) {\r
+        error_report("invalid mloop_evsock");\r
+        return -1;\r
+    }\r
+\r
+    if (p == NULL || p->size <= 0) {\r
+        error_report("invalid mloop_evpack");\r
+        return -1;\r
+    }\r
+\r
+    do {\r
+        ret = send(ev->sockno, p, ntohs(p->size), 0);\r
+#ifdef _WIN32\r
+    } while (ret == -1 && (WSAGetLastError() == WSAEWOULDBLOCK));\r
+#else\r
+    } while (ret == -1 && (errno == EWOULDBLOCK || errno == EINTR));\r
+#endif // _WIN32\r
+\r
+    return ret;\r
+}\r
+\r
+static USBDevice *usbkbd = NULL;\r
+static USBDevice *usbdisk = NULL;\r
+static void mloop_evhandle_usb_add(char *name)\r
+{\r
+    if (name == NULL) {\r
+        return;\r
+    }\r
+\r
+    if (strcmp(name, "keyboard") == 0) {\r
+        if (usbkbd == NULL) {\r
+            usbkbd = usbdevice_create(name);\r
+        }\r
+        else if (usbkbd->attached == 0) {\r
+            usb_device_attach(usbkbd);\r
+        }\r
+    }\r
+    else if (strncmp(name, "disk:", 5) == 0) {\r
+        if (usbdisk == NULL) {\r
+               usbdisk = usbdevice_create(name);\r
+        }\r
+    }\r
+}\r
+\r
+static void mloop_evhandle_usb_del(char *name)\r
+{\r
+    if (name == NULL) {\r
+        return;\r
+    }\r
+\r
+    if (strcmp(name, "keyboard") == 0) {\r
+        if (usbkbd && usbkbd->attached != 0) {\r
+            usb_device_detach(usbkbd);\r
+        }\r
+    }\r
+    else if (strncmp(name, "disk:", 5) == 0) {\r
+       if (usbdisk) {\r
+           qdev_free(&usbdisk->qdev);\r
+       }\r
+    }\r
+}\r
+\r
+static void mloop_evhandle_intr_up(long data)\r
+{\r
+       if (data == 0) {\r
+               return;\r
+       }\r
+\r
+       qemu_irq_raise((qemu_irq)data);\r
+}\r
+\r
+static void mloop_evhandle_intr_down(long data)\r
+{\r
+       if (data == 0) {\r
+               return;\r
+       }\r
+\r
+       qemu_irq_lower((qemu_irq)data);\r
+}\r
+\r
+static void mloop_evcb_recv(struct mloop_evsock *ev)\r
+{\r
+    struct mloop_evpack pack;\r
+    int ret;\r
+\r
+    do {\r
+       ret = recv(ev->sockno, (void *)&pack, sizeof(pack), 0);\r
+#ifdef _WIN32\r
+    } while (ret == -1 && WSAGetLastError() == WSAEINTR);\r
+#else\r
+    } while (ret == -1 && errno == EINTR);\r
+#endif // _WIN32\r
+\r
+    if (ret == -1 ) {\r
+        return;\r
+    }\r
+\r
+    if (ret == 0 ) {\r
+        return;\r
+    }\r
+\r
+    pack.type = ntohs(pack.type);\r
+    pack.size = ntohs(pack.size);\r
+\r
+    switch (pack.type) {\r
+    case MLOOP_EVTYPE_USB_ADD:\r
+        mloop_evhandle_usb_add(pack.data);\r
+        break;\r
+    case MLOOP_EVTYPE_USB_DEL:\r
+        mloop_evhandle_usb_del(pack.data);\r
+               break;\r
+       case MLOOP_EVTYPE_INTR_UP:\r
+               mloop_evhandle_intr_up(ntohl(*(long*)&pack.data[0]));\r
+               break;\r
+       case MLOOP_EVTYPE_INTR_DOWN:\r
+               mloop_evhandle_intr_down(ntohl(*(long*)&pack.data[0]));\r
+               break;\r
+    default:\r
+        break;\r
+    }\r
+}\r
+\r
+void mloop_ev_init(void)\r
+{\r
+    int ret = mloop_evsock_create(&mloop);\r
+    if (ret == 0) {\r
+        qemu_set_fd_handler(mloop.sockno, (IOHandler *)mloop_evcb_recv, NULL, &mloop);\r
+    }\r
+}\r
+\r
+void mloop_ev_stop(void)\r
+{\r
+    qemu_set_fd_handler(mloop.sockno, NULL, NULL, NULL);\r
+    mloop_evsock_remove(&mloop);\r
+}\r
+\r
+void mloop_evcmd_usbkbd(int on)\r
+{\r
+    struct mloop_evpack pack = { htons(MLOOP_EVTYPE_USB_ADD), htons(13), "keyboard" };\r
+    if (on == 0)\r
+       pack.type = htons(MLOOP_EVTYPE_USB_DEL);\r
+    mloop_evsock_send(&mloop, &pack);\r
+}\r
+\r
+void mloop_evcmd_usbdisk(char *img)\r
+{\r
+    struct mloop_evpack pack;\r
+\r
+    if (img) {\r
+       if (strlen(img) > PACKET_LEN-5) {\r
+               // Need log\r
+               return;\r
+       }\r
+\r
+       pack.type = htons(MLOOP_EVTYPE_USB_ADD);\r
+       pack.size = htons(5 + sprintf(pack.data, "disk:%s", img));\r
+    }\r
+    else {\r
+       pack.type = htons(MLOOP_EVTYPE_USB_DEL);\r
+       pack.size = htons(5 + sprintf(pack.data, "disk:"));\r
+    }\r
+\r
+    mloop_evsock_send(&mloop, &pack);\r
+}\r
+\r
+int mloop_evcmd_get_usbkbd_status(void)\r
+{\r
+       return (usbkbd && usbkbd->attached ? 1 : 0);\r
+}\r
+\r
+void mloop_evcmd_set_usbkbd(void *dev)\r
+{\r
+       usbkbd = (USBDevice *)dev;\r
+}\r
+\r
+void mloop_evcmd_set_usbdisk(void *dev)\r
+{\r
+       usbdisk = (USBDevice *)dev;\r
+}\r
+\r
+void mloop_evcmd_raise_intr(void *irq)\r
+{\r
+       struct mloop_evpack pack;\r
+       memset((void*)&pack, 0, sizeof(struct mloop_evpack));\r
+       pack.type = htons(MLOOP_EVTYPE_INTR_UP);\r
+       pack.size = htons(8);\r
+       *(long*)&pack.data[0] = htonl((long)irq);\r
+       mloop_evsock_send(&mloop, &pack);\r
+}\r
+\r
+void mloop_evcmd_lower_intr(void *irq)\r
+{\r
+       struct mloop_evpack pack;\r
+       memset((void*)&pack, 0, sizeof(struct mloop_evpack));\r
+       pack.type = htons(MLOOP_EVTYPE_INTR_DOWN);\r
+       pack.size = htons(8);\r
+       *(long*)&pack.data[0] = htonl((long)irq);\r
+       mloop_evsock_send(&mloop, &pack);\r
+}\r
diff --git a/tizen/src/mloop_event.h b/tizen/src/mloop_event.h
new file mode 100644 (file)
index 0000000..94bd821
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+ * mainloop_evhandle.c\r
+ *\r
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * Contact:\r
+ * DoHyung Hong <don.hong@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#ifndef MLOOP_EVENT_H_\r
+#define MLOOP_EVENT_H_\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+void mloop_ev_init(void);\r
+void mloop_ev_stop(void);\r
+\r
+void mloop_evcmd_usbkbd(int on);\r
+void mloop_evcmd_usbdisk(char *img);\r
+\r
+int mloop_evcmd_get_usbkbd_status(void);\r
+\r
+void mloop_evcmd_set_usbkbd(void *dev);\r
+void mloop_evcmd_set_usbdisk(void *dev);\r
+\r
+void mloop_evcmd_raise_intr(void *irq);\r
+void mloop_evcmd_lower_intr(void *irq);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* MLOOP_EVENT_H_ */\r
index ec1456f5b6d9b91e109560a6c66f867da56eb078..44f659197c84c19aaa738b13e32882986d47f050 100644 (file)
@@ -1,21 +1,14 @@
-/*
+/* 
  * Emulator
  *
- * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact: 
- * DoHyung Hong <don.hong@samsung.com>
  * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Hyunjun Son <hj79.son@samsung.com>
- * SangJin Kim <sangjin3.kim@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
  * MunKyu Im <munkyu.im@samsung.com>
- * KiTae Kim <kt920.kim@samsung.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * SungMin Ha <sungmin82.ha@samsung.com>
- * JiHye Kim <jihye1128.kim@samsung.com>
  * GiWoong Kim <giwoong.kim@samsung.com>
  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun <dk77.yun@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -37,8 +30,8 @@
  */
 
 /**
-  @file option.c
-  @brief    collection of dialog function
+  @file        option.c
+  @brief       collection of dialog function
  */
 
 #include "option.h"
 //DEFAULT_DEBUG_CHANNEL(tizen);
 MULTI_DEBUG_CHANNEL(tizen, option);
 
-CONFIGURATION preference_entrys;
-int startup_option_config_done = 0;
-
 /**
-  @brief    get host DNS server address
-  @param    dns1: return value (first dns server address)
-  @param    dns2: return value (second dns server address)
+  @brief       get host DNS server address
+  @param       dns1: return value (first dns server address)
+  @param       dns2: return value (second dns server address)
   @return always 0
  */
 int gethostDNS(char *dns1, char *dns2)
 {
 #ifndef _WIN32
-    FILE *resolv;
-    char buf[255];
-    memset(buf, 0, sizeof(char)*255);
-
-    resolv = fopen("/etc/resolv.conf", "r");
-    if (resolv <= 0) {
-        ERR( "Cann't open \"/etc/resolv.conf.\"\n");
-        return 1;
-    }
-
-    while(fscanf(resolv , "%s", buf) != EOF) {
-        if(strcmp(buf, "nameserver") == 0)
-        {
-            fscanf(resolv , "%s", dns1);
-            break;
-        }
-    }
-
-    while(fscanf(resolv , "%s", buf) != EOF) {
-        if(strcmp(buf, "nameserver") == 0)
-        {
-            fscanf(resolv , "%s", dns2);
-            break;
-        }
-    }
-
-    fclose(resolv);
+       FILE *resolv;
+       char buf[255];
+       memset(buf, 0, sizeof(char)*255);
+
+       resolv = fopen("/etc/resolv.conf", "r");
+       if (resolv <= 0) {
+               ERR( "Cann't open \"/etc/resolv.conf.\"\n");
+               return 1;
+       }
+
+       while(fscanf(resolv , "%s", buf) != EOF) {
+               if(strcmp(buf, "nameserver") == 0)
+               {
+                       fscanf(resolv , "%s", dns1);
+                       break;
+               }
+       }
+
+       while(fscanf(resolv , "%s", buf) != EOF) {
+               if(strcmp(buf, "nameserver") == 0)
+               {
+                       fscanf(resolv , "%s", dns2);
+                       break;
+               }
+       }
+
+       fclose(resolv);
 #else
-    PIP_ADAPTER_ADDRESSES pAdapterAddr;
-    PIP_ADAPTER_ADDRESSES pAddr;
-    PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
-    unsigned long dwResult;
-    unsigned long nBufferLength = sizeof(IP_ADAPTER_ADDRESSES);
-    pAdapterAddr = (PIP_ADAPTER_ADDRESSES)malloc(nBufferLength);
-    memset(pAdapterAddr, 0x00, nBufferLength);
-
-    while ((dwResult = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddr, &nBufferLength))
-            == ERROR_BUFFER_OVERFLOW) {
-        free(pAdapterAddr);
-        pAdapterAddr = (PIP_ADAPTER_ADDRESSES)malloc(nBufferLength);
-        memset(pAdapterAddr, 0x00, nBufferLength);
-    }
-
-    pAddr = pAdapterAddr;
-    for (; pAddr != NULL; pAddr = pAddr->Next) {
-        pDnsAddr = pAddr->FirstDnsServerAddress;
-        for (; pDnsAddr != NULL; pDnsAddr = pDnsAddr->Next) {
-            struct sockaddr_in *pSockAddr = (struct sockaddr_in*)pDnsAddr->Address.lpSockaddr;
-            if(*dns1 == 0) {
-                strcpy(dns1, inet_ntoa(pSockAddr->sin_addr));
-                continue;
-            }
-            if(*dns2 == 0) {
-                strcpy(dns2, inet_ntoa(pSockAddr->sin_addr));
-                continue;
-            }
-        }
-    }
-    free(pAdapterAddr);
+       PIP_ADAPTER_ADDRESSES pAdapterAddr;
+       PIP_ADAPTER_ADDRESSES pAddr;
+       PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
+       unsigned long dwResult;
+       unsigned long nBufferLength = sizeof(IP_ADAPTER_ADDRESSES);
+       pAdapterAddr = (PIP_ADAPTER_ADDRESSES)malloc(nBufferLength);
+       memset(pAdapterAddr, 0x00, nBufferLength);
+
+       while ((dwResult = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddr, &nBufferLength))
+                       == ERROR_BUFFER_OVERFLOW) {
+               free(pAdapterAddr);
+               pAdapterAddr = (PIP_ADAPTER_ADDRESSES)malloc(nBufferLength);
+               memset(pAdapterAddr, 0x00, nBufferLength);
+       }
+
+       pAddr = pAdapterAddr;
+       for (; pAddr != NULL; pAddr = pAddr->Next) {
+               pDnsAddr = pAddr->FirstDnsServerAddress;
+               for (; pDnsAddr != NULL; pDnsAddr = pDnsAddr->Next) {
+                       struct sockaddr_in *pSockAddr = (struct sockaddr_in*)pDnsAddr->Address.lpSockaddr;
+                       if(*dns1 == 0) {
+                               strcpy(dns1, inet_ntoa(pSockAddr->sin_addr));
+                               continue;
+                       }
+                       if(*dns2 == 0) {
+                               strcpy(dns2, inet_ntoa(pSockAddr->sin_addr));
+                               continue;
+                       }
+               }
+       }
+       free(pAdapterAddr);
 #endif
-    return 0;
+       return 0;
 }
 
 /**
-  @brief    get host proxy server address
-  @param    proxy: return value (proxy server address)
+  @brief       get host proxy server address
+  @param       proxy: return value (proxy server address)
   @return always 0
  */
 int gethostproxy(char *proxy)
 {
 #ifndef _WIN32
-    char buf[255];
-    FILE *output;
+       char buf[255];
+       FILE *output;
+
+       output = popen("gconftool-2 --get /system/proxy/mode", "r");
+       fscanf(output, "%s", buf);
+       pclose(output);
+
+       if (strcmp(buf, "manual") == 0){
+               output = popen("gconftool-2 --get /system/http_proxy/host", "r");
+               fscanf(output , "%s", buf);
+               sprintf(proxy, "%s", buf);
+               pclose(output);
+
+               output = popen("gconftool-2 --get /system/http_proxy/port", "r");
+               fscanf(output , "%s", buf);
+               sprintf(proxy, "%s:%s", proxy, buf);
+               pclose(output);
+
+       }else if (strcmp(buf, "auto") == 0){
+               INFO( "Emulator can't support automatic proxy currently. starts up with normal proxy.\n");
+               //can't support proxy auto setting
+//             output = popen("gconftool-2 --get /system/proxy/autoconfig_url", "r");
+//             fscanf(output , "%s", buf);
+//             sprintf(proxy, "%s", buf);
+//             pclose(output);
+       }
 
-    emulator_mutex_lock();
-
-    output = popen("gconftool-2 --get /system/proxy/mode", "r");
-    fscanf(output, "%s", buf);
-    pclose(output);
-
-    if (strcmp(buf, "manual") == 0){
-        output = popen("gconftool-2 --get /system/http_proxy/host", "r");
-        fscanf(output , "%s", buf);
-        sprintf(proxy, "%s", buf);
-        pclose(output);
-
-        output = popen("gconftool-2 --get /system/http_proxy/port", "r");
-        fscanf(output , "%s", buf);
-        sprintf(proxy, "%s:%s", proxy, buf);
-        pclose(output);
-
-    }else if (strcmp(buf, "auto") == 0){
-        INFO( "Emulator can't support automatic proxy currently. starts up with normal proxy.\n");
-        //can't support proxy auto setting
-//      output = popen("gconftool-2 --get /system/proxy/autoconfig_url", "r");
-//      fscanf(output , "%s", buf);
-//      sprintf(proxy, "%s", buf);
-//      pclose(output);
-    }
-
-    emulator_mutex_unlock();
 #else
-    HKEY hKey;
-    int nRet;
-    LONG lRet;
-    BYTE *proxyenable, *proxyserver;
-    DWORD dwLength = 0;
-    nRet = RegOpenKeyEx(HKEY_CURRENT_USER,
-            "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
-            0, KEY_QUERY_VALUE, &hKey);
-    if (nRet != ERROR_SUCCESS) {
-        fprintf(stderr, "Failed to open registry from %s\n",
-                "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
-        return 0;
-    }
-    lRet = RegQueryValueEx(hKey, "ProxyEnable", 0, NULL, NULL, &dwLength);
-    if (lRet != ERROR_SUCCESS && dwLength == 0) {
-        fprintf(stderr, "Failed to query value from from %s\n",
-                "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
-        RegCloseKey(hKey);
-        return 0;
-    }
-    proxyenable = (BYTE*)malloc(dwLength);
-    if (proxyenable == NULL) {
-        fprintf(stderr, "Failed to allocate a buffer\n");
-        RegCloseKey(hKey);
-        return 0;
-    }
-
-    lRet = RegQueryValueEx(hKey, "ProxyEnable", 0, NULL, proxyenable, &dwLength);
-    if (lRet != ERROR_SUCCESS) {
-        free(proxyenable);
-        fprintf(stderr, "Failed to query value from from %s\n",
-                "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
-        RegCloseKey(hKey);
-        return 0;
-    }
-    if (*(char*)proxyenable == 0) {
-        free(proxyenable);
-        RegCloseKey(hKey);      
-        return 0;
-    }
-
-    dwLength = 0;
-    lRet = RegQueryValueEx(hKey, "ProxyServer", 0, NULL, NULL, &dwLength);
-    if (lRet != ERROR_SUCCESS && dwLength == 0) {
-        fprintf(stderr, "Failed to query value from from %s\n",
-                "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
-        RegCloseKey(hKey);      
-        return 0;
-    }
-
-    proxyserver = (BYTE*)malloc(dwLength);
-    if (proxyserver == NULL) {
-        fprintf(stderr, "Failed to allocate a buffer\n");
-        RegCloseKey(hKey);      
-        return 0;
-    }
-
-    memset(proxyserver, 0x00, dwLength);
-    lRet = RegQueryValueEx(hKey, "ProxyServer", 0, NULL, proxyserver, &dwLength);
-    if (lRet != ERROR_SUCCESS) {
-        free(proxyserver);
-        fprintf(stderr, "Failed to query value from from %s\n",
-                "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
-        RegCloseKey(hKey);
-        return 0;
-    }
-    if (proxyserver != NULL) strcpy(proxy, (char*)proxyserver);
-    free(proxyserver);
-    RegCloseKey(hKey);
-#endif
-    return 0;
-}
-
-/* This function get HOST IP address */
-int gethostIP(char *host_ip)
-{
-#ifndef _WIN32
-
-    int fd;
-    struct if_nameindex *curif, *ifs;
-    struct ifreq req;
-
-    fd = socket(PF_INET, SOCK_DGRAM, 0);
-    if( fd != -1) 
-    {
-        ifs = if_nameindex();
-        if(ifs) 
-        {
-            for(curif = ifs; curif && curif->if_name; curif++) 
-            {
-                strncpy(req.ifr_name, curif->if_name, IFNAMSIZ);
-                req.ifr_name[IFNAMSIZ] = 0;
-
-                if (ioctl(fd, SIOCGIFADDR, &req) < 0)
-                {
-                    ERR( "ioctl fail: %s \n", strerror(errno));
-                }else{
-                    TRACE( "%s: [%s]\n"
-                            , curif->if_name
-                            , inet_ntoa(((struct sockaddr_in*) &req.ifr_addr)->sin_addr));
-
-                    if( strncmp(curif->if_name, "lo", 2) != 0){
-                        sprintf(host_ip, "%s"
-                                , inet_ntoa(((struct sockaddr_in*) &req.ifr_addr)->sin_addr));
-                        break;
-                    }
-                }
-            }
-
-            if_freenameindex(ifs);
-            close(fd);
-
-        } else {
-            ERR( "if_nameindex fail: %s \n", strerror(errno));
-        }
-
-    } else {
-        ERR( "socket fail: %s \n", strerror(errno));
-    }
-
-#endif
-    return 0;
-}
-
-static GtkWidget *make_virtual_target_frame(const gchar *frame_name)
-{
-    int i;
-    gchar **target_list = NULL;
-    int num = 0;
-
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (FALSE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *label = gtk_label_new(_("Select virtual target"));
-    gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
-    gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 1);
-
-    GtkWidget *virtual_target_combobox = (GtkWidget *)gtk_combo_box_new_text();
-    add_widget(OPTION_ID, OPTION_VIRTUAL_TARGET_COMBOBOX, virtual_target_combobox);
-    gtk_box_pack_start (GTK_BOX (hbox), virtual_target_combobox, TRUE, TRUE, 1);    
-
-    target_list = get_virtual_target_list(SYSTEMINFO.target_list_file , TARGET_LIST_GROUP, &num);
-
-    for(i = 0; i < num; i++)
-    {
-        gtk_combo_box_append_text(GTK_COMBO_BOX (virtual_target_combobox), target_list[i]);
-    }
-    gtk_combo_box_set_active(GTK_COMBO_BOX (virtual_target_combobox), 0);
-
-    if(startup_option_config_done == 1)
-    {
-        gtk_widget_set_sensitive(virtual_target_combobox, FALSE);
-    }
-
-    g_signal_connect(G_OBJECT(virtual_target_combobox), "changed", G_CALLBACK(virtual_target_select_cb), NULL);
-
-    g_strfreev(target_list);
-    return frame;
-}
-
-/*
-   static GtkWidget *make_scale_frame(const gchar *frame_name)
-   {
-   GSList *group;
-
-   GtkWidget *frame;
-   frame = gtk_frame_new(frame_name);
-
-   GtkWidget *vbox;
-   vbox = gtk_vbox_new (FALSE, 0);
-   gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-   GtkWidget *hbox;
-   hbox = gtk_hbox_new (FALSE, 0);
-   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-   GtkWidget *scale_half_button = gtk_radio_button_new_with_label(NULL, "1/2x");
-   add_widget(OPTION_ID, OPTION_SCALE_HALF_BUTTON, scale_half_button);
-   group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(scale_half_button));
-   gtk_box_pack_start (GTK_BOX (hbox), scale_half_button, TRUE, TRUE, 1);
-
-   GtkWidget *scale_one_button = gtk_radio_button_new_with_label(group, "1x");
-   add_widget(OPTION_ID, OPTION_SCALE_ONE_BUTTON, scale_one_button);
-   gtk_box_pack_start (GTK_BOX (hbox), scale_one_button, TRUE, TRUE, 1);    
-
-   if(preference_entrys.scale == 2)
-   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scale_half_button), TRUE);
-   else
-   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scale_one_button), TRUE);
-
-   if(startup_option_config_done == 1)
-   {
-   gtk_widget_set_sensitive(scale_half_button, FALSE);
-   gtk_widget_set_sensitive(scale_one_button, FALSE);
-   }
-
-   g_signal_connect(G_OBJECT(scale_half_button), "toggled", G_CALLBACK(scale_select_cb), scale_half_button);
-   g_signal_connect(G_OBJECT(scale_one_button), "toggled", G_CALLBACK(scale_select_cb), scale_one_button);
-
-   return frame;
-   }
- */
-
-/**
-  @brief    make a frame for always on frame buffer
-  @param    frame_name: frame name
-  @return newly created frame
- */
-#if 0
-static GtkWidget *make_serial_frame(const gchar *frame_name)
-{
-    /* 1. set box */
-
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    /* 2. Telnet Port check button and set inactive status by telnet type */
-    /* 5. set inactive status by Telnet Type */
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (TRUE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *telnet_button = gtk_check_button_new_with_label( _("Telnet Port"));
-    add_widget(OPTION_ID, OPTION_TELNET_BUTTON, telnet_button);
-    gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET(telnet_button), TRUE, TRUE, 1);
-    gtk_toggle_button_set_active((GtkToggleButton *)telnet_button, preference_entrys.qemu_configuration.telnet_type);
-
-    /* 3. Telnet Port Entry */
-
-    GtkWidget *telnet_port_entry = gtk_entry_new();
-    gtk_entry_set_max_length (GTK_ENTRY(telnet_port_entry), 4);
-    gtk_widget_set_size_request(telnet_port_entry, 10, -1);
-    add_widget(OPTION_ID, OPTION_TELNET_PORT_ENTRY, telnet_port_entry);
-    gtk_box_pack_end (GTK_BOX (hbox), GTK_WIDGET(telnet_port_entry), TRUE, TRUE, 1);
-    gtk_entry_set_text(GTK_ENTRY(telnet_port_entry), preference_entrys.qemu_configuration.telnet_port);
-
-    /* 6. set Serial console */
-
-    hbox = gtk_hbox_new (TRUE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *serial_console_button = gtk_check_button_new_with_label( _("Serial Console"));
-    add_widget(OPTION_ID, OPTION_SERIAL_CONSOLE_BUTTON, serial_console_button);
-    gtk_box_pack_start (GTK_BOX (hbox), serial_console_button, TRUE, TRUE, 1);
-    if(preference_entrys.qemu_configuration.serial_console_command_type== 1 &&  preference_entrys.qemu_configuration.telnet_type == 1)
-        gtk_toggle_button_set_active((GtkToggleButton *)serial_console_button, TRUE);
-    else
-        gtk_toggle_button_set_active((GtkToggleButton *)serial_console_button, FALSE);
-
-    /* 7. set Serial console entry */
-
-    GtkWidget *serial_console_entry = gtk_entry_new();
-    gtk_entry_set_max_length (GTK_ENTRY(serial_console_entry), MAXBUF);
-    gtk_widget_set_size_request(serial_console_entry, 10, -1);
-    add_widget(OPTION_ID, OPTION_SERIAL_CONSOLE_ENTRY, serial_console_entry);
-    gtk_box_pack_start (GTK_BOX (hbox), serial_console_entry, TRUE, TRUE, 1);
-    /* serial console command ==> start */
-    preference_entrys.qemu_configuration.serial_console_command_type = configuration.qemu_configuration.serial_console_command_type;
-    snprintf(preference_entrys.qemu_configuration.serial_console_command, MAXBUF, "%s", configuration.qemu_configuration.serial_console_command);
-    gtk_entry_set_text(GTK_ENTRY(serial_console_entry), preference_entrys.qemu_configuration.serial_console_command);
-    /* end */
-
-    preference_entrys.qemu_configuration.sdcard_type = configuration.qemu_configuration.sdcard_type;
-    snprintf(preference_entrys.qemu_configuration.sdcard_path, MAXBUF, "%s", configuration.qemu_configuration.sdcard_path);
-
-    preference_entrys.qemu_configuration.diskimg_type = configuration.qemu_configuration.diskimg_type;
-    snprintf(preference_entrys.qemu_configuration.diskimg_path, MAXBUF, "%s", configuration.qemu_configuration.diskimg_path);
-
-    set_telnet_status_active_cb();
-
-    g_signal_connect(G_OBJECT(telnet_button), "toggled", G_CALLBACK(set_telnet_status_active_cb), NULL);
-    g_signal_connect(G_OBJECT(serial_console_button), "toggled", G_CALLBACK(serial_console_command_cb), NULL);
-    return(frame);
-}
-#endif
-
-/**
-  @brief    make a frame for always on frame buffer
-  @param    frame_name: frame name
-  @return newly created frame
- */
-static GtkWidget *make_internet_frame(const gchar *frame_name)
-{
-    /* 1. set box */
-
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    /* 2. http proxy entry */
-
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (FALSE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *use_host_proxy = gtk_check_button_new_with_label( _("Use host proxy"));
-    add_widget(OPTION_ID, OPTION_USE_HOST_PROXY, use_host_proxy);
-    gtk_box_pack_start (GTK_BOX (hbox), use_host_proxy, TRUE, TRUE, 1);
-    gtk_toggle_button_set_active((GtkToggleButton *)use_host_proxy, preference_entrys.qemu_configuration.use_host_http_proxy);
-
-    GtkWidget *use_host_DNS = gtk_check_button_new_with_label( _("Use host DNS"));
-    add_widget(OPTION_ID, OPTION_USE_HOST_DNS, use_host_DNS);
-    gtk_box_pack_end (GTK_BOX (hbox), use_host_DNS, TRUE, TRUE, 1);
-    gtk_toggle_button_set_active((GtkToggleButton *)use_host_DNS, preference_entrys.qemu_configuration.use_host_dns_server);
-
-    if(startup_option_config_done == 1)
-    {
-        gtk_widget_set_sensitive(use_host_proxy, FALSE);
-        gtk_widget_set_sensitive(use_host_DNS, FALSE);
-    }
-
-    g_signal_connect(G_OBJECT(use_host_proxy), "toggled", G_CALLBACK(use_host_proxy_cb), NULL);
-    g_signal_connect(G_OBJECT(use_host_DNS), "toggled", G_CALLBACK(use_host_DNS_cb), NULL);
-
-    return frame;
-}
-
-/**
- * @brief   make a frame for sdcard
- * @return  newly created frame
- */
-#if 0
-static GtkWidget *make_sdcard_frame(const gchar *frame_name)
-{
-    /* 1. set box */
-
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    /* 2. SD Card check button */
-
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (FALSE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *sdcard_button = gtk_check_button_new_with_label( _("SD Card                      "));
-    add_widget(OPTION_ID, OPTION_SDCARD_BUTTON, sdcard_button);
-    gtk_box_pack_start (GTK_BOX (hbox), sdcard_button, FALSE, FALSE, 1);
-
-    /* 3. SD Card button */
-
-    gchar *sdcard_img_name = basename(preference_entrys.qemu_configuration.sdcard_path);
-    GtkWidget *sdcard_img_button;
-    if( !strcmp(".",sdcard_img_name) || sdcard_img_name==NULL )
-        sdcard_img_button = gtk_button_new_with_label (_("Select SD Card Image"));
-    else
-        sdcard_img_button = gtk_button_new_with_label (sdcard_img_name);
-    add_widget(OPTION_ID, OPTION_SDCARD_IMG_BUTTON, sdcard_img_button);
-    gtk_box_pack_start (GTK_BOX (hbox), sdcard_img_button, TRUE, TRUE, 1);
-
-    /* 4. set inactive status by SDcard Type */
-
-    if(preference_entrys.qemu_configuration.sdcard_type == 1)
-        gtk_toggle_button_set_active((GtkToggleButton *)sdcard_button, TRUE);
-    else if(preference_entrys.qemu_configuration.sdcard_type == 0)
-        gtk_toggle_button_set_active((GtkToggleButton *)sdcard_button, FALSE);
-
-    set_sdcard_status_active_cb();
-
-    if(startup_option_config_done == 1)
-    {
-        gtk_widget_set_sensitive(sdcard_button, FALSE);
-        gtk_widget_set_sensitive(sdcard_img_button, FALSE);
-    }
-
-    g_signal_connect(G_OBJECT(sdcard_button), "toggled", G_CALLBACK(set_sdcard_status_active_cb), NULL);
-    g_signal_connect(GTK_BUTTON(sdcard_img_button), "clicked", G_CALLBACK(sdcard_select_cb), NULL);
-
-    return frame;
-}
+       HKEY hKey;
+       int nRet;
+       LONG lRet;
+       BYTE *proxyenable, *proxyserver;
+       DWORD dwLength = 0;
+       nRet = RegOpenKeyEx(HKEY_CURRENT_USER,
+                       "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+                       0, KEY_QUERY_VALUE, &hKey);
+       if (nRet != ERROR_SUCCESS) {
+               fprintf(stderr, "Failed to open registry from %s\n",
+                               "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+               return 0;
+       }
+       lRet = RegQueryValueEx(hKey, "ProxyEnable", 0, NULL, NULL, &dwLength);
+       if (lRet != ERROR_SUCCESS && dwLength == 0) {
+               fprintf(stderr, "Failed to query value from from %s\n",
+                               "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+               RegCloseKey(hKey);
+               return 0;
+       }
+       proxyenable = (BYTE*)malloc(dwLength);
+       if (proxyenable == NULL) {
+               fprintf(stderr, "Failed to allocate a buffer\n");
+               RegCloseKey(hKey);
+               return 0;
+       }
+
+       lRet = RegQueryValueEx(hKey, "ProxyEnable", 0, NULL, proxyenable, &dwLength);
+       if (lRet != ERROR_SUCCESS) {
+               free(proxyenable);
+               fprintf(stderr, "Failed to query value from from %s\n",
+                               "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+               RegCloseKey(hKey);
+               return 0;
+       }
+       if (*(char*)proxyenable == 0) {
+               free(proxyenable);
+               RegCloseKey(hKey);              
+               return 0;
+       }
+
+       dwLength = 0;
+       lRet = RegQueryValueEx(hKey, "ProxyServer", 0, NULL, NULL, &dwLength);
+       if (lRet != ERROR_SUCCESS && dwLength == 0) {
+               fprintf(stderr, "Failed to query value from from %s\n",
+                               "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+               RegCloseKey(hKey);              
+               return 0;
+       }
+
+       proxyserver = (BYTE*)malloc(dwLength);
+       if (proxyserver == NULL) {
+               fprintf(stderr, "Failed to allocate a buffer\n");
+               RegCloseKey(hKey);              
+               return 0;
+       }
+
+       memset(proxyserver, 0x00, dwLength);
+       lRet = RegQueryValueEx(hKey, "ProxyServer", 0, NULL, proxyserver, &dwLength);
+       if (lRet != ERROR_SUCCESS) {
+               free(proxyserver);
+               fprintf(stderr, "Failed to query value from from %s\n",
+                               "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+               RegCloseKey(hKey);
+               return 0;
+       }
+       if (proxyserver != NULL) strcpy(proxy, (char*)proxyserver);
+       free(proxyserver);
+       RegCloseKey(hKey);
 #endif
-
-
-static GtkWidget *make_always_on_top_frame(const gchar *frame_name)
-{
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (FALSE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *always_on_top = gtk_check_button_new_with_label( _("Emulator"));
-    add_widget(OPTION_ID, OPTION_ALWAYS_ON_TOP_BUTTON, always_on_top);
-    gtk_box_pack_start(GTK_BOX (hbox), always_on_top, TRUE, TRUE, 1);
-    gtk_toggle_button_set_active((GtkToggleButton *)always_on_top, preference_entrys.always_on_top);
-
-    g_signal_connect(G_OBJECT(always_on_top), "toggled", G_CALLBACK(always_on_top_cb), NULL);
-
-    return frame;
-}
-
-
-/**
-  @brief    make a frame for snapshot boot
-  @param    frame_name: frame name
-  @return newly created frame
- */
-#if 0
-static GtkWidget *make_boot_frame(const gchar *frame_name)
-{
-    char snapshot_date_str[MAXBUF];
-    /* 1. set box */
-
-    GtkWidget *frame;
-    frame = gtk_frame_new(frame_name);
-
-    GtkWidget *vbox;
-    vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(frame), vbox);
-
-    /* 2. boot entry */
-
-    GtkWidget *hbox;
-    hbox = gtk_hbox_new (TRUE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    GtkWidget *snapshot_boot = gtk_check_button_new_with_label( _("Snapshot Boot                        "));
-    add_widget(OPTION_ID, OPTION_SNAPSHOT_BOOT, snapshot_boot);
-    gtk_box_pack_start (GTK_BOX (hbox), snapshot_boot, TRUE, TRUE, 1);
-    gtk_toggle_button_set_active((GtkToggleButton *)snapshot_boot, preference_entrys.qemu_configuration.save_emulator_state);
-
-    GtkWidget *snapshot_saved_date_entry = gtk_entry_new();
-    gtk_widget_set_size_request(snapshot_saved_date_entry, -1, -1);
-    add_widget(OPTION_ID, OPTION_SNAPSHOT_SAVED_DATE_ENTRY, snapshot_saved_date_entry);
-    gtk_box_pack_start(GTK_BOX(hbox), snapshot_saved_date_entry, TRUE, TRUE, 1);
-
-    if(preference_entrys.qemu_configuration.snapshot_saved == 1)
-        snprintf(snapshot_date_str, MAXBUF, "saved at %s", preference_entrys.qemu_configuration.snapshot_saved_date);
-    else
-    {
-        snprintf(snapshot_date_str, MAXBUF, "no snapshot saved");
-        gtk_toggle_button_set_active((GtkToggleButton *)snapshot_boot, FALSE);
-        gtk_widget_set_sensitive(snapshot_boot, FALSE);
-        preference_entrys.qemu_configuration.save_emulator_state = 0;
-    }
-
-    gtk_entry_set_text(GTK_ENTRY(snapshot_saved_date_entry), snapshot_date_str);
-    gtk_widget_set_sensitive(snapshot_saved_date_entry, FALSE);
-
-    if(startup_option_config_done == 1)
-    {
-        gtk_widget_set_sensitive(snapshot_boot, FALSE);
-    }
-
-    g_signal_connect(G_OBJECT(snapshot_boot), "toggled", G_CALLBACK(snapshot_boot_cb), NULL);
-
-    return frame;
-}
-#endif
-
-/**
-  @brief    set initial preference entry
-  @return void
- */
-
-static void set_initial_preference_entrys(void)
-{
-    preference_entrys.qemu_configuration.use_host_http_proxy = configuration.qemu_configuration.use_host_http_proxy;
-    preference_entrys.qemu_configuration.use_host_dns_server = configuration.qemu_configuration.use_host_dns_server;
-
-    preference_entrys.always_on_top = configuration.always_on_top;
-
-    preference_entrys.qemu_configuration.save_emulator_state = configuration.qemu_configuration.save_emulator_state;
-    preference_entrys.qemu_configuration.snapshot_saved = virtual_target_info.snapshot_saved;
-    snprintf(preference_entrys.qemu_configuration.snapshot_saved_date, MAXBUF, "%s", virtual_target_info.snapshot_saved_date);
-
-    preference_entrys.qemu_configuration.telnet_type = configuration.qemu_configuration.telnet_type;
-    snprintf(preference_entrys.qemu_configuration.telnet_port, MAXBUF, "%s", configuration.qemu_configuration.telnet_port);
-    preference_entrys.qemu_configuration.serial_console_command_type = configuration.qemu_configuration.serial_console_command_type;
-    snprintf(preference_entrys.qemu_configuration.serial_console_command, MAXBUF, "%s", configuration.qemu_configuration.serial_console_command);
-
-    preference_entrys.qemu_configuration.sdcard_type = virtual_target_info.sdcard_type;
-    snprintf(preference_entrys.qemu_configuration.sdcard_path, MAXBUF, "%s", virtual_target_info.sdcard_path);
-
-    preference_entrys.qemu_configuration.diskimg_type = configuration.qemu_configuration.diskimg_type;
-    snprintf(preference_entrys.qemu_configuration.diskimg_path, MAXBUF, "%s", configuration.qemu_configuration.diskimg_path);
-
-    snprintf(preference_entrys.target_path, MAXBUF, "%s", configuration.target_path);
-}
-
-
-/**
-  @brief    create config frame
-  @return newly created frame
- */
-
-void create_config_frame(GtkWidget * vbox)
-{
-    GtkWidget *temp_vbox = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(vbox), temp_vbox, TRUE, TRUE, 0);
-
-#if 0 // serial setting will not be supported. below code will be removed later
-    /* 2. serial frame create */
-
-    GtkWidget *serial_frame = make_serial_frame(_("Serial Settings"));
-    gtk_box_pack_start(GTK_BOX(temp_vbox), serial_frame, TRUE, TRUE, 0);
-#endif
-
-    GtkWidget *virtual_target_frame = make_virtual_target_frame(_("Virtual Target"));
-    gtk_box_pack_start(GTK_BOX(temp_vbox), virtual_target_frame, TRUE, TRUE, 0);
-
-    //  GtkWidget *scale_frame = make_scale_frame(_("Scale"));
-    //  gtk_box_pack_start(GTK_BOX(temp_vbox), scale_frame, TRUE, TRUE, 0);
-
-
-    /* 4. network internet setting frame create */
-
-    GtkWidget *internet_frame = make_internet_frame(_("Internet Setting"));
-    gtk_box_pack_start(GTK_BOX(temp_vbox), internet_frame, TRUE, TRUE, 0);
-
-    /* 5. sdcard frame create */
-
-    //  GtkWidget *sdcard_frame = make_sdcard_frame(_("SD Card"));
-    //  gtk_box_pack_start(GTK_BOX(temp_vbox), sdcard_frame, TRUE, TRUE, 0);
-
-    GtkWidget *always_on_top_frame = make_always_on_top_frame(_("Always On Top"));
-    gtk_box_pack_start(GTK_BOX(temp_vbox), always_on_top_frame, TRUE, TRUE, 0);
-
-    /* 6. boot frame create */
-
-    //  GtkWidget *boot_frame = make_boot_frame(_("Boot"));
-    //  gtk_box_pack_start(GTK_BOX(temp_vbox), boot_frame, TRUE, TRUE, 0);
-
-}
-
-
-/**
-  @brief    create config button
-  @param  GtkWidget : box pack
-  @return newly created frame
- */
-void create_config_button(GtkWidget *vbox)
-{
-    GtkWidget *button_box;
-    button_box = gtk_hbutton_box_new();
-    gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
-
-    /* 1. cancel button create */
-
-    GtkWidget *cancel_btn = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
-    gtk_container_add (GTK_CONTAINER (button_box), cancel_btn);
-
-    /* 2. ok button create */
-
-    GtkWidget *ok_btn = gtk_button_new_from_stock (GTK_STOCK_OK);
-    gtk_container_add (GTK_CONTAINER (button_box), ok_btn);
-
-    g_signal_connect_swapped ((gpointer) ok_btn, "clicked", G_CALLBACK (ok_clicked_cb), NULL);
-    g_signal_connect_swapped ((gpointer) cancel_btn, "clicked", G_CALLBACK (emulator_deleted_callback), NULL);
-}
-
-
-/**
-  @brief    create option window
-  @param    parent: option window widget
- */
-void create_config_page(GtkWidget *parent)
-{
-    /* 1. ontop, term, cmd, path frame ui */
-
-    GtkWidget *vbox1;
-    vbox1 = gtk_vbox_new (FALSE, 5);
-    create_config_frame(vbox1);
-    gtk_box_pack_start(GTK_BOX(parent), vbox1, TRUE, TRUE, 0);
-
-    /* 2. save, cancel button */
-
-    GtkWidget *vbox2;
-    vbox2 = gtk_vbox_new (FALSE, 5);
-    create_config_button(vbox2);
-    gtk_box_pack_end(GTK_BOX(parent), vbox2, TRUE, TRUE, 1);
-
-    /* 3. separator line */
-
-    GtkWidget *separator;
-    separator= gtk_hseparator_new();
-    gtk_box_pack_end(GTK_BOX(parent), separator, FALSE, FALSE, 5);
-
-    add_widget(OPTION_ID, OPTION_CONF_FRAME, vbox1);
-    add_widget(OPTION_ID, OPTION_CONF_VBOX, parent);
+       return 0;
 }
-
-
-/**
-  @brief    show config window
-  @param    parent: option window widget
- */
-//int show_config_window ()
-int show_config_window (GtkWidget *parent)
-{
-    gchar icon_image[MAXPATH] = {0, };
-    const gchar *skin = NULL;
-
-    /* 1. set initial preference entrys */
-
-    set_initial_preference_entrys();
-
-    /* 2. create option window */
-
-    GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    add_window (win, OPTION_ID);
-
-    gtk_window_set_title (GTK_WINDOW (win), _("Emulator Options"));
-
-    skin = get_skin_path();
-    if(skin == NULL)
-        WARN( "getting icon image path is failed!!\n");
-    sprintf(icon_image, "%s/icons/Emulator_20x20.png", skin);
-    gtk_window_set_icon_from_file(GTK_WINDOW (win), icon_image, NULL);
-
-    gtk_window_set_default_size(GTK_WINDOW (win), 360, -1);
-    gtk_window_set_modal (GTK_WINDOW (win), TRUE);
-    gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
-
-    GtkWidget *vbox = vbox = gtk_vbox_new (FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(win), vbox);
-
-    /* 2.1 create Preference Notebook */
-
-    create_config_page (vbox);
-
-    //#define _SENSOR_SOCKET
-#ifdef _SENSOR_SOCKET
-    /* 2.2 create Target Emulation Notebook */
-
-    vbox = create_sub_page(notebook, _("Target Emulation"));
-#endif
-
-    if(parent != NULL)
-        gtk_window_set_transient_for(GTK_WINDOW (win), GTK_WINDOW (parent));
-
-    gtk_window_set_keep_above(GTK_WINDOW (win), TRUE);
-    gtk_widget_show_all(win);
-
-    g_signal_connect(GTK_OBJECT(win), "delete_event", G_CALLBACK(emulator_deleted_callback), NULL);
-
-    /* 3. option window gtk main start */
-
-    gtk_main();
-
-    return 0;
-}
-
index bd07a8eda1623c232643c6d5b505293120619e09..f7b1ddfd83125ee70496f4f5fc63bb6d1ac9e0c9 100644 (file)
@@ -1,21 +1,14 @@
-/*
+/* 
  * Emulator
  *
- * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact: 
- * DoHyung Hong <don.hong@samsung.com>
  * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Hyunjun Son <hj79.son@samsung.com>
- * SangJin Kim <sangjin3.kim@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
  * MunKyu Im <munkyu.im@samsung.com>
- * KiTae Kim <kt920.kim@samsung.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * SungMin Ha <sungmin82.ha@samsung.com>
- * JiHye Kim <jihye1128.kim@samsung.com>
  * GiWoong Kim <giwoong.kim@samsung.com>
  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun <dk77.yun@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #ifndef __OPTION_H__
 #define __OPTION_H__
 
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
 #include <glib.h>
-#include <glib-object.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libgen.h>
 #ifndef _WIN32
 #include <error.h>
 #endif
 #include <stdlib.h>
 #include <string.h>
 
-#include "option_callback.h"
-#include "emulator.h"
-
-extern GtkWidget *entry_user_cmd;
-extern GtkWidget *frame_buffer_entry;
-extern CONFIGURATION preference_entrys;
-
-GtkWidget *create_option_frame(GtkWidget *parent, gchar *frame_name); /* option total frame ui */
-void create_config_frame(GtkWidget *vbox);
-void create_config_button(GtkWidget *vbox);
-void create_config_page(GtkWidget *parent);
-int show_config_window(GtkWidget *parent);
-
-int search_target(char *directory_name, char *target_name);
 int gethostDNS(char *dns1, char *dns2);
 int gethostproxy(char *proxy);
-int gethostIP(char *host_ip);
 #endif
 
diff --git a/tizen/src/sdb.c b/tizen/src/sdb.c
new file mode 100644 (file)
index 0000000..4291fdd
--- /dev/null
@@ -0,0 +1,369 @@
+/* Copyright (C) 2006-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else /* !_WIN32 */
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#endif /* !_WIN32 */
+
+#include "net/slirp.h"
+#include "qemu_socket.h"
+#include "sdb.h"
+#include "nbd.h"
+#include "tizen/src/debug_ch.h"
+
+//DEFAULT_DEBUG_CHANNEL(qemu);
+MULTI_DEBUG_CHANNEL(qemu, sdb);
+
+/* QSOCKET_CALL is used to deal with the fact that EINTR happens pretty
+ * easily in QEMU since we use SIGALRM to implement periodic timers
+ */
+
+#ifdef _WIN32
+#  define  QSOCKET_CALL(_ret,_cmd)   \
+       do { _ret = (_cmd); } while ( _ret < 0 && WSAGetLastError() == WSAEINTR )
+#else
+#  define  QSOCKET_CALL(_ret,_cmd)   \
+       do { \
+               errno = 0; \
+               do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ); \
+       } while (0);
+#endif
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+static int  winsock_error;
+
+#define  WINSOCK_ERRORS_LIST \
+       EE(WSA_INVALID_HANDLE,EINVAL,"invalid handle") \
+EE(WSA_NOT_ENOUGH_MEMORY,ENOMEM,"not enough memory") \
+EE(WSA_INVALID_PARAMETER,EINVAL,"invalid parameter") \
+EE(WSAEINTR,EINTR,"interrupted function call") \
+EE(WSAEALREADY,EALREADY,"operation already in progress") \
+EE(WSAEBADF,EBADF,"bad file descriptor") \
+EE(WSAEACCES,EACCES,"permission denied") \
+EE(WSAEFAULT,EFAULT,"bad address") \
+EE(WSAEINVAL,EINVAL,"invalid argument") \
+EE(WSAEMFILE,EMFILE,"too many opened files") \
+EE(WSAEWOULDBLOCK,EWOULDBLOCK,"resource temporarily unavailable") \
+EE(WSAEINPROGRESS,EINPROGRESS,"operation now in progress") \
+EE(WSAEALREADY,EAGAIN,"operation already in progress") \
+EE(WSAENOTSOCK,EBADF,"socket operation not on socket") \
+EE(WSAEDESTADDRREQ,EDESTADDRREQ,"destination address required") \
+EE(WSAEMSGSIZE,EMSGSIZE,"message too long") \
+EE(WSAEPROTOTYPE,EPROTOTYPE,"wrong protocol type for socket") \
+EE(WSAENOPROTOOPT,ENOPROTOOPT,"bad protocol option") \
+EE(WSAEADDRINUSE,EADDRINUSE,"address already in use") \
+EE(WSAEADDRNOTAVAIL,EADDRNOTAVAIL,"cannot assign requested address") \
+EE(WSAENETDOWN,ENETDOWN,"network is down") \
+EE(WSAENETUNREACH,ENETUNREACH,"network unreachable") \
+EE(WSAENETRESET,ENETRESET,"network dropped connection on reset") \
+EE(WSAECONNABORTED,ECONNABORTED,"software caused connection abort") \
+EE(WSAECONNRESET,ECONNRESET,"connection reset by peer") \
+EE(WSAENOBUFS,ENOBUFS,"no buffer space available") \
+EE(WSAEISCONN,EISCONN,"socket is already connected") \
+EE(WSAENOTCONN,ENOTCONN,"socket is not connected") \
+EE(WSAESHUTDOWN,ESHUTDOWN,"cannot send after socket shutdown") \
+EE(WSAETOOMANYREFS,ETOOMANYREFS,"too many references") \
+EE(WSAETIMEDOUT,ETIMEDOUT,"connection timed out") \
+EE(WSAECONNREFUSED,ECONNREFUSED,"connection refused") \
+EE(WSAELOOP,ELOOP,"cannot translate name") \
+EE(WSAENAMETOOLONG,ENAMETOOLONG,"name too long") \
+EE(WSAEHOSTDOWN,EHOSTDOWN,"host is down") \
+EE(WSAEHOSTUNREACH,EHOSTUNREACH,"no route to host") \
+
+typedef struct {
+       int          winsock;
+       int          unix;
+       const char*  string;
+} WinsockError;
+
+static const WinsockError  _winsock_errors[] = {
+#define  EE(w,u,s)   { w, u, s },
+       WINSOCK_ERRORS_LIST
+#undef   EE
+       { -1, -1, NULL }
+};
+
+/* this function reads the latest winsock error code and updates
+ * errno to a matching value. It also returns the new value of
+ * errno.
+ */
+static int _fix_errno( void )
+{
+       const WinsockError*  werr = _winsock_errors;
+       int                  unix = EINVAL;  /* generic error code */
+
+       winsock_error = WSAGetLastError();
+
+       for ( ; werr->string != NULL; werr++ ) {
+               if (werr->winsock == winsock_error) {
+                       unix = werr->unix;
+                       break;
+               }
+       }
+       errno = unix;
+       return -1;
+}
+
+#else
+static int _fix_errno( void )
+{
+       return -1;
+}
+
+#endif
+
+#define  SOCKET_CALL(cmd)  \
+       int  ret; \
+QSOCKET_CALL(ret, (cmd)); \
+if (ret < 0) \
+return _fix_errno(); \
+return ret; \
+
+int socket_send(int  fd, const void*  buf, int  buflen)
+{
+       SOCKET_CALL(send(fd, buf, buflen, 0))
+}
+
+#ifdef _WIN32
+
+       static void
+socket_close_handler( void*  _fd )
+{
+       int   fd = (int)_fd;
+       int   ret;
+       char  buff[64];
+
+       /* we want to drain the read side of the socket before closing it */
+       do {
+               ret = recv( fd, buff, sizeof(buff), 0 );
+       } while (ret < 0 && WSAGetLastError() == WSAEINTR);
+
+       if (ret < 0 && WSAGetLastError() == EWOULDBLOCK)
+               return;
+
+       qemu_set_fd_handler( fd, NULL, NULL, NULL );
+       closesocket( fd );
+}
+
+       void
+socket_close( int  fd )
+{
+       int  old_errno = errno;
+
+       shutdown( fd, SD_BOTH );
+       /* we want to drain the socket before closing it */
+       qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd );
+
+       errno = old_errno;
+}
+
+#else /* !_WIN32 */
+
+#include <unistd.h>
+
+       void
+socket_close( int  fd )
+{
+       int  old_errno = errno;
+
+       shutdown( fd, SHUT_RDWR );
+       close( fd );
+
+       errno = old_errno;
+}
+
+#endif /* !_WIN32 */
+
+int inet_strtoip(const char*  str, uint32_t  *ip)
+{
+       int  comp[4];
+
+       if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4)
+               return -1;
+
+       if ((unsigned)comp[0] >= 256 ||
+                       (unsigned)comp[1] >= 256 ||
+                       (unsigned)comp[2] >= 256 ||
+                       (unsigned)comp[3] >= 256)
+               return -1;
+
+       *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) |
+                       (comp[2] << 8)  |  comp[3]);
+       return 0;
+}
+
+static int check_port_bind_listen(u_int port)
+{
+       struct sockaddr_in addr;
+       int s, opt = 1;
+       int ret = -1;
+       socklen_t addrlen = sizeof(addr);
+       memset(&addr, 0, addrlen);
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = INADDR_ANY;
+       addr.sin_port = htons(port);
+
+       if (((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
+#ifndef _WIN32
+                       (setsockopt(s, SOL_SOCKET,SO_REUSEADDR, (char *)&opt, sizeof(int)) < 0) ||
+#endif
+                       (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+                       (listen(s, 1) < 0)) {
+
+               /* fail */
+               ret = -1;
+               ERR( "port(%d) listen  fail \n", port);
+       }else{
+               /*fsucess*/
+               ret = 1;
+               INFO( "port(%d) listen  ok \n", port);
+       }
+
+#ifdef _WIN32
+       closesocket(s);
+#else
+       close(s);
+#endif
+
+       return ret;
+}
+
+int get_sdb_base_port(void)
+{
+       int   tries     = 10;
+       int   success   = 0;
+       u_int port = 26100;
+
+       if(tizen_base_port == 0){
+
+               for ( ; tries > 0; tries--, port += 10 ) {
+                       if(check_port_bind_listen(port + 1) < 0 )
+                               continue;
+
+                       success = 1;
+                       break;
+               }
+
+               if (!success) {
+                       ERR( "it seems too many emulator instances are running on this machine. Aborting\n" );
+                       exit(1);
+               }
+
+               tizen_base_port = port;
+               INFO( "sdb port is %d \n", tizen_base_port);
+       }
+
+       return tizen_base_port;
+}
+
+void sdb_setup(void)
+{
+       int   tries     = 10;
+       int   success   = 0;
+       uint32_t  guest_ip;
+       char buf[64] = {0,};
+
+       inet_strtoip("10.0.2.16", &guest_ip);
+
+       for ( ; tries > 0; tries--, tizen_base_port += 10 ) {
+               // redir form [tcp:26101:10.0.2.16:26101]
+               sprintf(buf, "tcp:%d:10.0.2.16:26101", tizen_base_port + 1);
+               if(net_slirp_redir((char*)buf) < 0)
+                       continue;
+
+               INFO( "SDBD established on port %d\n", tizen_base_port + 1);
+               success = 1;
+               break;
+       }
+
+       INFO("redirect [%s] success\n", buf);
+       if (!success) {
+               ERR( "it seems too many emulator instances are running on this machine. Aborting\n" );
+               exit(1);
+       }
+
+       INFO( "Port(%d/tcp) listen for SDB \n", tizen_base_port + 1);
+
+       /* for sensort */
+       sprintf(buf, "tcp:%d:10.0.2.16:3577", tizen_base_port + SDB_TCP_EMULD_INDEX );
+       if(net_slirp_redir((char*)buf) < 0){
+               ERR( "redirect [%s] fail \n", buf);
+       }else{
+               INFO("redirect [%s] success\n", buf);
+       }
+}
+
+int sdb_loopback_client(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    s = socket(AF_INET, type, 0);
+    if(s < 0) return -1;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+
+}
+
+void notify_sdb_daemon_start(void) {
+    int s;
+    /* 
+     * send a simple message to the SDB host server to tell it we just started.
+     * it should be listening on port 26099.
+     */
+    do {
+        char tmp[32] = { 0 };
+
+        // when connecting to loopback:26099, do not use tcp_socket_outgoing function
+        // tcp_socket_outgoing may occur "dns name service not known" in case of network unavaliable status.
+        s = sdb_loopback_client(SDB_HOST_PORT, SOCK_STREAM);
+        if (s < 0) {
+            INFO("can't create socket to talk to the SDB server \n");
+            INFO("This emulator will be scaned by the SDB server \n");
+            break;
+        }
+
+        /* length is hex: 0x13 = 19 */
+        sprintf(tmp, "0013host:emulator:%d", tizen_base_port + 1);
+
+        if (socket_send(s, tmp, 30) < 0) {
+            ERR( "message sending to sdb server error!\n");
+        }
+
+    } while (0);
+
+    if (s >= 0)
+        socket_close(s);
+}
diff --git a/tizen/src/sdb.h b/tizen/src/sdb.h
new file mode 100644 (file)
index 0000000..b309516
--- /dev/null
@@ -0,0 +1,113 @@
+/* Copyright (C) 2006-2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#include "maru_common.h"
+
+#include <errno.h>
+
+#define SDB_HOST_PORT 26099
+
+#ifdef _WIN32
+#  ifndef EINTR
+#    define EINTR        10004
+#  endif
+#  ifndef EAGAIN
+#    define EAGAIN       10035
+#  endif
+#  ifndef EWOULDBLOCK
+#    define EWOULDBLOCK  EAGAIN
+#  endif
+#  ifndef EINPROGRESS
+#    define EINPROGRESS  10036
+#  endif
+#  ifndef EALREADY
+#    define EALREADY     10037
+#  endif
+#  ifndef EDESTADDRREQ
+#    define EDESTADDRREQ 10039
+#  endif
+#  ifndef EMSGSIZE
+#    define EMSGSIZE     10040
+#  endif
+#  ifndef EPROTOTYPE
+#    define EPROTOTYPE   10041
+#  endif
+#  ifndef ENOPROTOOPT
+#    define ENOPROTOOPT  10042
+#  endif
+#  ifndef EAFNOSUPPORT
+#    define EAFNOSUPPORT 10047
+#  endif
+#  ifndef EADDRINUSE
+#    define EADDRINUSE   10048
+#  endif
+#  ifndef EADDRNOTAVAIL
+#    define EADDRNOTAVAIL 10049
+#  endif
+#  ifndef ENETDOWN
+#    define ENETDOWN     10050
+#  endif
+#  ifndef ENETUNREACH
+#    define ENETUNREACH  10051
+#  endif
+#  ifndef ENETRESET
+#    define ENETRESET    10052
+#  endif
+#  ifndef ECONNABORTED
+#    define ECONNABORTED 10053
+#  endif
+#  ifndef ECONNRESET
+#    define ECONNRESET   10054
+#  endif
+#  ifndef ENOBUFS
+#    define ENOBUFS      10055
+#  endif
+#  ifndef EISCONN
+#    define EISCONN      10056
+#  endif
+#  ifndef ENOTCONN
+#    define ENOTCONN     10057
+#  endif
+#  ifndef ESHUTDOWN
+#    define ESHUTDOWN     10058
+#  endif
+#  ifndef ETOOMANYREFS
+#    define ETOOMANYREFS  10059
+#  endif
+#  ifndef ETIMEDOUT
+#    define ETIMEDOUT     10060
+#  endif
+#  ifndef ECONNREFUSED
+#    define ECONNREFUSED  10061
+#  endif
+#  ifndef ELOOP
+#    define ELOOP         10062
+#  endif
+#  ifndef EHOSTDOWN
+#    define EHOSTDOWN     10064
+#  endif
+#  ifndef EHOSTUNREACH
+#    define EHOSTUNREACH  10065
+#  endif
+#endif /* _WIN32 */
+
+#define SDB_TCP_EMULD_INDEX  3    /* emulator daemon port */
+#define SDB_TCP_OPENGL_INDEX  4   /* opengl server port */
+extern int tizen_base_port;
+#define SDB_UDP_SENSOR_INDEX  3   /* sensor server port */
+void sdb_setup(void);
+int get_sdb_base_port(void);
+int inet_strtoip(const char*  str, uint32_t  *ip);
+int socket_send(int fd, const void*  buf, int  buflen);
+void socket_close(int fd);
+void notify_sdb_daemon_start(void);
+int sdb_loopback_client(int port, int type);
diff --git a/tizen/src/sdl_rotate.c b/tizen/src/sdl_rotate.c
new file mode 100644 (file)
index 0000000..e268c97
--- /dev/null
@@ -0,0 +1,1610 @@
+/*
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Hyunjun Son(hj79.son@samsung.com)
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sdl_rotate.h"
+
+#if 1
+
+/* ---- Internally used structures */
+
+/*!
+\brief A 32 bit RGBA pixel.
+*/
+typedef struct tColorRGBA {
+       Uint8 r;
+       Uint8 g;
+       Uint8 b;
+       Uint8 a;
+} tColorRGBA;
+
+/*!
+\brief A 8bit Y/palette pixel.
+*/
+typedef struct tColorY {
+       Uint8 y;
+} tColorY;
+
+/*!
+\brief Returns maximum of two numbers a and b.
+*/
+#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
+
+/*!
+\brief Number of guard rows added to destination surfaces.
+
+This is a simple but effective workaround for observed issues.
+These rows allocate extra memory and are then hidden from the surface.
+Rows are added to the end of destination surfaces when they are allocated.
+This catches any potential overflows which seem to happen with
+just the right src image dimensions and scale/rotation and can lead
+to a situation where the program can segfault.
+*/
+#define GUARD_ROWS (0)
+
+/*!
+\brief Lower limit of absolute zoom factor or rotation degrees.
+*/
+#define VALUE_LIMIT    0.001
+
+Uint32 _colorkey(SDL_Surface *src);
+int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory);
+int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory);
+int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth);
+int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy);
+void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth);
+void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy);
+void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
+                                                         int *dstwidth, int *dstheight,
+                                                         double *canglezoom, double *sanglezoom);
+
+/*!
+\brief Returns colorkey info for a surface
+*/
+Uint32 _colorkey(SDL_Surface *src)
+{
+       Uint32 key = 0;
+#if (SDL_MINOR_VERSION == 3)
+       SDL_GetColorKey(src, &key);
+#else
+       if (src)
+       {
+               key = src->format->colorkey;
+       }
+#endif
+       return key;
+}
+
+
+/*!
+\brief Internal 32 bit integer-factor averaging Shrinker.
+
+Shrinks 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
+Averages color and alpha values values of src pixels to calculate dst pixels.
+Assumes src and dst surfaces are of 32 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src The surface to shrink (input).
+\param dst The shrunken surface (output).
+\param factorx The horizontal shrinking ratio.
+\param factory The vertical shrinking ratio.
+
+\return 0 for success or -1 for error.
+*/
+int _shrinkSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
+{
+       int x, y, dx, dy, sgap, dgap, ra, ga, ba, aa;
+       int n_average;
+       tColorRGBA *sp, *osp, *oosp;
+       tColorRGBA *dp;
+
+       /*
+       * Averaging integer shrink
+       */
+
+       /* Precalculate division factor */
+       n_average = factorx*factory;
+
+       /*
+       * Scan destination
+       */
+       sp = (tColorRGBA *) src->pixels;
+       sgap = src->pitch - src->w * 4;
+
+       dp = (tColorRGBA *) dst->pixels;
+       dgap = dst->pitch - dst->w * 4;
+
+       for (y = 0; y < dst->h; y++) {
+
+               osp=sp;
+               for (x = 0; x < dst->w; x++) {
+
+                       /* Trace out source box and accumulate */
+                       oosp=sp;
+                       ra=ga=ba=aa=0;
+                       for (dy=0; dy < factory; dy++) {
+                               for (dx=0; dx < factorx; dx++) {
+                                       ra += sp->r;
+                                       ga += sp->g;
+                                       ba += sp->b;
+                                       aa += sp->a;
+
+                                       sp++;
+                               }
+                               /* src dx loop */
+                               sp = (tColorRGBA *)((Uint8*)sp + (src->pitch - 4*factorx)); // next y
+                       }
+                       /* src dy loop */
+
+                       /* next box-x */
+                       sp = (tColorRGBA *)((Uint8*)oosp + 4*factorx);
+
+                       /* Store result in destination */
+                       dp->r = ra/n_average;
+                       dp->g = ga/n_average;
+                       dp->b = ba/n_average;
+                       dp->a = aa/n_average;
+
+                       /*
+                       * Advance destination pointer
+                       */
+                       dp++;
+               }
+               /* dst x loop */
+
+               /* next box-y */
+               sp = (tColorRGBA *)((Uint8*)osp + src->pitch*factory);
+
+               /*
+               * Advance destination pointers
+               */
+               dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+       }
+       /* dst y loop */
+
+       return (0);
+}
+
+/*!
+\brief Internal 8 bit integer-factor averaging shrinker.
+
+Shrinks 8bit Y 'src' surface to 'dst' surface.
+Averages color (brightness) values values of src pixels to calculate dst pixels.
+Assumes src and dst surfaces are of 8 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src The surface to shrink (input).
+\param dst The shrunken surface (output).
+\param factorx The horizontal shrinking ratio.
+\param factory The vertical shrinking ratio.
+
+\return 0 for success or -1 for error.
+*/
+int _shrinkSurfaceY(SDL_Surface * src, SDL_Surface * dst, int factorx, int factory)
+{
+       int x, y, dx, dy, sgap, dgap, a;
+       int n_average;
+       Uint8 *sp, *osp, *oosp;
+       Uint8 *dp;
+
+       /*
+       * Averaging integer shrink
+       */
+
+       /* Precalculate division factor */
+       n_average = factorx*factory;
+
+       /*
+       * Scan destination
+       */
+       sp = (Uint8 *) src->pixels;
+       sgap = src->pitch - src->w;
+
+       dp = (Uint8 *) dst->pixels;
+       dgap = dst->pitch - dst->w;
+
+       for (y = 0; y < dst->h; y++) {
+
+               osp=sp;
+               for (x = 0; x < dst->w; x++) {
+
+                       /* Trace out source box and accumulate */
+                       oosp=sp;
+                       a=0;
+                       for (dy=0; dy < factory; dy++) {
+                               for (dx=0; dx < factorx; dx++) {
+                                       a += (*sp);
+                                       /* next x */
+                                       sp++;
+                               }
+                               /* end src dx loop */
+                               /* next y */
+                               sp = (Uint8 *)((Uint8*)sp + (src->pitch - factorx));
+                       }
+                       /* end src dy loop */
+
+                       /* next box-x */
+                       sp = (Uint8 *)((Uint8*)oosp + factorx);
+
+                       /* Store result in destination */
+                       *dp = a/n_average;
+
+                       /*
+                       * Advance destination pointer
+                       */
+                       dp++;
+               }
+               /* end dst x loop */
+
+               /* next box-y */
+               sp = (Uint8 *)((Uint8*)osp + src->pitch*factory);
+
+               /*
+               * Advance destination pointers
+               */
+               dp = (Uint8 *)((Uint8 *)dp + dgap);
+       }
+       /* end dst y loop */
+
+       return (0);
+}
+
+/*!
+\brief Internal 32 bit Zoomer with optional anti-aliasing by bilinear interpolation.
+
+Zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface.
+Assumes src and dst surfaces are of 32 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src The surface to zoom (input).
+\param dst The zoomed surface (output).
+\param flipx Flag indicating if the image should be horizontally flipped.
+\param flipy Flag indicating if the image should be vertically flipped.
+\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
+
+\return 0 for success or -1 for error.
+*/
+int _zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy, int smooth)
+{
+       int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, lx, ly;
+       tColorRGBA *c00, *c01, *c10, *c11, *cswap;
+       tColorRGBA *sp, *csp, *dp;
+       int dgap;
+
+       /*
+       * Variable setup
+       */
+       if (smooth) {
+               /*
+               * For interpolation: assume source dimension is one pixel
+               */
+               /*
+               * smaller to avoid overflow on right and bottom edge.
+               */
+               sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+               sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+       } else {
+               sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+               sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+       }
+
+       /*
+       * Allocate memory for row increments
+       */
+       if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+               return (-1);
+       }
+       if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+               free(sax);
+               return (-1);
+       }
+
+       /*
+       * Precalculate row increments
+       */
+       sp = csp = (tColorRGBA *) src->pixels;
+       dp = (tColorRGBA *) dst->pixels;
+
+       if (flipx) csp += (src->w-1);
+       if (flipy) csp += (src->pitch*(src->h-1));
+
+       csx = 0;
+       csax = sax;
+       for (x = 0; x <= dst->w; x++) {
+               *csax = csx;
+               csax++;
+               csx &= 0xffff;
+               csx += sx;
+       }
+       csy = 0;
+       csay = say;
+       for (y = 0; y <= dst->h; y++) {
+               *csay = csy;
+               csay++;
+               csy &= 0xffff;
+               csy += sy;
+       }
+
+       dgap = dst->pitch - dst->w * 4;
+
+       /*
+       * Switch between interpolating and non-interpolating code
+       */
+       if (smooth) {
+
+               /*
+               * Interpolating Zoom
+               */
+
+               /*
+               * Scan destination
+               */
+               ly = 0;
+               csay = say;
+               for (y = 0; y < dst->h; y++) {
+                       /*
+                       * Setup color source pointers
+                       */
+                       c00 = csp;      
+                       c01 = csp;
+                       c01++;  
+                       c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
+                       c11 = c10;
+                       c11++;
+                       csax = sax;
+                       if (flipx) {
+                               cswap = c00; c00=c01; c01=cswap;
+                               cswap = c10; c10=c11; c11=cswap;
+                       }
+                       if (flipy) {
+                               cswap = c00; c00=c10; c10=cswap;
+                               cswap = c01; c01=c11; c11=cswap;
+                       }
+                       lx = 0;
+                       for (x = 0; x < dst->w; x++) {
+                               /*
+                               * Interpolate colors
+                               */
+                               ex = (*csax & 0xffff);
+                               ey = (*csay & 0xffff);
+                               t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
+                               t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
+                               dp->r = (((t2 - t1) * ey) >> 16) + t1;
+                               t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
+                               t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
+                               dp->g = (((t2 - t1) * ey) >> 16) + t1;
+                               t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
+                               t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
+                               dp->b = (((t2 - t1) * ey) >> 16) + t1;
+                               t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
+                               t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
+                               dp->a = (((t2 - t1) * ey) >> 16) + t1;
+
+                               /*
+                               * Advance source pointers
+                               */
+                               csax++;
+                               sstep = (*csax >> 16);
+                               lx += sstep;
+                               if (lx >= src->w) sstep = 0;
+                               if (flipx) sstep = -sstep;
+                               c00 += sstep;
+                               c01 += sstep;
+                               c10 += sstep;
+                               c11 += sstep;
+                               /*
+                               * Advance destination pointer
+                               */
+                               dp++;
+                       }
+                       /*
+                       * Advance source pointer
+                       */
+                       csay++;
+                       sstep = (*csay >> 16);
+                       ly += sstep;
+                       if (ly >= src->h) sstep = 0;
+                       sstep *= src->pitch;
+                       if (flipy) sstep = -sstep;
+                       csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
+
+                       /*
+                       * Advance destination pointers
+                       */
+                       dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+               }
+       } else {
+
+               /*
+               * Non-Interpolating Zoom
+               */
+
+               csay = say;
+               for (y = 0; y < dst->h; y++) {
+                       sp = csp;
+                       csax = sax;
+                       for (x = 0; x < dst->w; x++) {
+                               /*
+                               * Draw
+                               */
+                               *dp = *sp;
+                               /*
+                               * Advance source pointers
+                               */
+                               csax++;
+                               sstep = (*csax >> 16);
+                               if (flipx) sstep = -sstep;
+                               sp += sstep;
+                               /*
+                               * Advance destination pointer
+                               */
+                               dp++;
+                       }
+                       /*
+                       * Advance source pointer
+                       */
+                       csay++;
+                       sstep = (*csay >> 16) * src->pitch;
+                       if (flipy) sstep = -sstep;
+                       csp = (tColorRGBA *) ((Uint8 *) csp + sstep);
+
+                       /*
+                       * Advance destination pointers
+                       */
+                       dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+               }
+       }
+
+       /*
+       * Remove temp arrays
+       */
+       free(sax);
+       free(say);
+
+       return (0);
+}
+
+/*!
+
+\brief Internal 8 bit Zoomer without smoothing.
+
+Zooms 8bit palette/Y 'src' surface to 'dst' surface.
+Assumes src and dst surfaces are of 8 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src The surface to zoom (input).
+\param dst The zoomed surface (output).
+\param flipx Flag indicating if the image should be horizontally flipped.
+\param flipy Flag indicating if the image should be vertically flipped.
+
+\return 0 for success or -1 for error.
+*/
+int _zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
+{
+       int x, y;
+       Uint32 *sax, *say, *csax, *csay;
+       int csx, csy;
+       Uint8 *sp, *dp, *csp;
+       int dgap;
+
+       /*
+       * Allocate memory for row increments
+       */
+       if ((sax = (Uint32 *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+               return (-1);
+       }
+       if ((say = (Uint32 *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+               free(sax);
+               return (-1);
+       }
+
+       /*
+       * Pointer setup
+       */
+       sp = csp = (Uint8 *) src->pixels;
+       dp = (Uint8 *) dst->pixels;
+       dgap = dst->pitch - dst->w;
+
+       if (flipx) csp += (src->w-1);
+       if (flipy) csp  = ( (Uint8*)csp + src->pitch*(src->h-1) );
+
+       /*
+       * Precalculate row increments
+       */
+       csx = 0;
+       csax = sax;
+       for (x = 0; x < dst->w; x++) {
+               csx += src->w;
+               *csax = 0;
+               while (csx >= dst->w) {
+                       csx -= dst->w;
+                       (*csax)++;
+               }
+               csax++;
+       }
+       csy = 0;
+       csay = say;
+       for (y = 0; y < dst->h; y++) {
+               csy += src->h;
+               *csay = 0;
+               while (csy >= dst->h) {
+                       csy -= dst->h;
+                       (*csay)++;
+               }
+               csay++;
+       }
+
+       /*
+       * Draw
+       */
+       csay = say;
+       for (y = 0; y < dst->h; y++) {
+               csax = sax;
+               sp = csp;
+               for (x = 0; x < dst->w; x++) {
+                       /*
+                       * Draw
+                       */
+                       *dp = *sp;
+                       /*
+                       * Advance source pointers
+                       */
+                       sp += (*csax) * (flipx ? -1 : 1);
+                       csax++;
+                       /*
+                       * Advance destination pointer
+                       */
+                       dp++;
+               }
+               /*
+               * Advance source pointer (for row)
+               */
+               csp += ((*csay) * src->pitch) * (flipy ? -1 : 1);
+               csay++;
+
+               /*
+               * Advance destination pointers
+               */
+               dp += dgap;
+       }
+
+       /*
+       * Remove temp arrays
+       */
+       free(sax);
+       free(say);
+
+       return (0);
+}
+
+/*!
+\brief Internal 32 bit rotozoomer with optional anti-aliasing.
+
+Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
+parameters by scanning the destination surface and applying optionally anti-aliasing
+by bilinear interpolation.
+Assumes src and dst surfaces are of 32 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src Source surface.
+\param dst Destination surface.
+\param cx Horizontal center coordinate.
+\param cy Vertical center coordinate.
+\param isin Integer version of sine of angle.
+\param icos Integer version of cosine of angle.
+\param flipx Flag indicating horizontal mirroring should be applied.
+\param flipy Flag indicating vertical mirroring should be applied.
+\param smooth Flag indicating anti-aliasing should be used.
+*/
+void _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
+{
+       int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
+       tColorRGBA c00, c01, c10, c11, cswap;
+       tColorRGBA *pc, *sp;
+       int gap;
+
+       /*
+       * Variable setup
+       */
+       xd = ((src->w - dst->w) << 15);
+       yd = ((src->h - dst->h) << 15);
+       ax = (cx << 16) - (icos * cx);
+       ay = (cy << 16) - (isin * cx);
+       sw = src->w - 1;
+       sh = src->h - 1;
+       pc = (tColorRGBA*) dst->pixels;
+       gap = dst->pitch - dst->w * 4;
+
+       /*
+       * Switch between interpolating and non-interpolating code
+       */
+       if (smooth) {
+               for (y = 0; y < dst->h; y++) {
+                       dy = cy - y;
+                       sdx = (ax + (isin * dy)) + xd;
+                       sdy = (ay - (icos * dy)) + yd;
+                       for (x = 0; x < dst->w; x++) {
+                               dx = (sdx >> 16);
+                               dy = (sdy >> 16);
+                               if ((dx > -1) && (dy > -1) && (dx < src->w) && (dy < src->h)) {
+                                       if (flipx) dx = sw - dx;
+                                       if (flipy) dy = sh - dy;
+                                       sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+                                       sp += dx;
+                                       c00 = *sp;
+                                       sp += 1;
+                                       c01 = *sp;
+                                       sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+                                       c11 = *sp;
+                                       sp -= 1;
+                                       c10 = *sp;
+                                       if (flipx) {
+                                               cswap = c00; c00=c01; c01=cswap;
+                                               cswap = c10; c10=c11; c11=cswap;
+                                       }
+                                       if (flipy) {
+                                               cswap = c00; c00=c10; c10=cswap;
+                                               cswap = c01; c01=c11; c11=cswap;
+                                       }
+                                       /*
+                                       * Interpolate colors
+                                       */
+                                       ex = (sdx & 0xffff);
+                                       ey = (sdy & 0xffff);
+                                       t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
+                                       t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
+                                       pc->r = (((t2 - t1) * ey) >> 16) + t1;
+                                       t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
+                                       t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
+                                       pc->g = (((t2 - t1) * ey) >> 16) + t1;
+                                       t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
+                                       t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
+                                       pc->b = (((t2 - t1) * ey) >> 16) + t1;
+                                       t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
+                                       t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
+                                       pc->a = (((t2 - t1) * ey) >> 16) + t1;
+                               }
+                               sdx += icos;
+                               sdy += isin;
+                               pc++;
+                       }
+                       pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+               }
+       } else {
+               for (y = 0; y < dst->h; y++) {
+                       dy = cy - y;
+                       sdx = (ax + (isin * dy)) + xd;
+                       sdy = (ay - (icos * dy)) + yd;
+                       for (x = 0; x < dst->w; x++) {
+                               dx = (short) (sdx >> 16);
+                               dy = (short) (sdy >> 16);
+                               if (flipx) dx = (src->w-1)-dx;
+                               if (flipy) dy = (src->h-1)-dy;
+                               if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+                                       sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+                                       sp += dx;
+                                       *pc = *sp;
+                               }
+                               sdx += icos;
+                               sdy += isin;
+                               pc++;
+                       }
+                       pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+               }
+       }
+}
+
+/*!
+
+\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
+
+Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
+parameters by scanning the destination surface.
+Assumes src and dst surfaces are of 8 bit depth.
+Assumes dst surface was allocated with the correct dimensions.
+
+\param src Source surface.
+\param dst Destination surface.
+\param cx Horizontal center coordinate.
+\param cy Vertical center coordinate.
+\param isin Integer version of sine of angle.
+\param icos Integer version of cosine of angle.
+\param flipx Flag indicating horizontal mirroring should be applied.
+\param flipy Flag indicating vertical mirroring should be applied.
+*/
+void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
+{
+       int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
+       tColorY *pc, *sp;
+       int gap;
+
+       /*
+       * Variable setup
+       */
+       xd = ((src->w - dst->w) << 15);
+       yd = ((src->h - dst->h) << 15);
+       ax = (cx << 16) - (icos * cx);
+       ay = (cy << 16) - (isin * cx);
+       sw = src->w - 1;
+       sh = src->h - 1;
+       pc = (tColorY*) dst->pixels;
+       gap = dst->pitch - dst->w;
+       /*
+       * Clear surface to colorkey
+       */      
+       memset(pc, (unsigned char) (_colorkey(src) & 0xff), dst->pitch * dst->h);
+       /*
+       * Iterate through destination surface
+       */
+       for (y = 0; y < dst->h; y++) {
+               dy = cy - y;
+               sdx = (ax + (isin * dy)) + xd;
+               sdy = (ay - (icos * dy)) + yd;
+               for (x = 0; x < dst->w; x++) {
+                       dx = (short) (sdx >> 16);
+                       dy = (short) (sdy >> 16);
+                       if (flipx) dx = (src->w-1)-dx;
+                       if (flipy) dy = (src->h-1)-dy;
+                       if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+                               sp = (tColorY *) (src->pixels);
+                               sp += (src->pitch * dy + dx);
+                               *pc = *sp;
+                       }
+                       sdx += icos;
+                       sdy += isin;
+                       pc++;
+               }
+               pc += gap;
+       }
+}
+#endif
+
+/*!
+\brief Rotates a 32 bit surface in increments of 90 degrees.
+
+Specialized 90 degree rotator which rotates a 'src' surface in 90 degree
+increments clockwise returning a new surface. Faster than rotozoomer since
+not scanning or interpolation takes place. Input surface must be 32 bit.
+(code contributed by J. Schiller, improved by C. Allport and A. Schiffler)
+
+\param src Source surface to rotate.
+\param numClockwiseTurns Number of clockwise 90 degree turns to apply to the source.
+
+\returns The new, rotated surface; or NULL for surfaces with incorrect input format.
+*/
+SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns)
+{
+       int row, col, newWidth, newHeight;
+       int bpp, src_ipr, dst_ipr;
+       SDL_Surface* dst;
+       Uint32* srcBuf;
+       Uint32* dstBuf;
+
+       /* Has to be a valid surface pointer and only 32-bit surfaces (for now) */
+       if (!src || src->format->BitsPerPixel != 32) { return NULL; }
+
+       /* normalize numClockwiseTurns */
+       while(numClockwiseTurns < 0) { numClockwiseTurns += 4; }
+       numClockwiseTurns = (numClockwiseTurns % 4);
+
+       /* if it's even, our new width will be the same as the source surface */
+       newWidth = (numClockwiseTurns % 2) ? (src->h) : (src->w);
+       newHeight = (numClockwiseTurns % 2) ? (src->w) : (src->h);
+       dst = SDL_CreateRGBSurface( src->flags, newWidth, newHeight, src->format->BitsPerPixel,
+               src->format->Rmask,
+               src->format->Gmask,
+               src->format->Bmask,
+               src->format->Amask);
+       if(!dst) {
+               return NULL;
+       }
+
+       if (SDL_MUSTLOCK(dst)) {
+               SDL_LockSurface(dst);
+       }
+       if (SDL_MUSTLOCK(dst)) {
+               SDL_LockSurface(dst);
+       }
+
+       /* Calculate int-per-row */
+       bpp = src->format->BitsPerPixel / 8;
+       src_ipr = src->pitch / bpp;
+       dst_ipr = dst->pitch / bpp;
+
+       switch(numClockwiseTurns) {
+               case 0: /* Make a copy of the surface */
+                       {
+                               /* Unfortunately SDL_BlitSurface cannot be used to make a copy of the surface
+                                  since it does not preserve alpha. */
+
+                               if (src->pitch == dst->pitch) {
+                                       /* If the pitch is the same for both surfaces, the memory can be copied all at once. */
+                                       memcpy(dst->pixels, src->pixels, (src->h * src->pitch));
+                               }
+                               else
+                               {
+                                       /* If the pitch differs, copy each row separately */
+                                       srcBuf = (Uint32*)(src->pixels);
+                                       dstBuf = (Uint32*)(dst->pixels);
+                                       for (row = 0; row < src->h; row++) {
+                                               memcpy(dstBuf, srcBuf, dst->w * bpp);
+                                               srcBuf += src_ipr;
+                                               dstBuf += dst_ipr;
+                                       } /* end for(col) */
+                               } /* end for(row) */
+                       }
+                       break;
+
+                       /* rotate clockwise */
+               case 1: /* rotated 90 degrees clockwise */
+                {
+                        for (row = 0; row < src->h; ++row) {
+                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
+                                dstBuf = (Uint32*)(dst->pixels) + (dst->w - row - 1);
+                                for (col = 0; col < src->w; ++col) {
+                                        *dstBuf = *srcBuf;
+                                        ++srcBuf;
+                                        dstBuf += dst_ipr;
+                                }
+                                /* end for(col) */
+                        }
+                        /* end for(row) */
+                }
+                break;
+
+               case 2: /* rotated 180 degrees clockwise */
+                {
+                        for (row = 0; row < src->h; ++row) {
+                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
+                                dstBuf = (Uint32*)(dst->pixels) + ((dst->h - row - 1) * dst_ipr) + (dst->w - 1);
+                                for (col = 0; col < src->w; ++col) {
+                                        *dstBuf = *srcBuf;
+                                        ++srcBuf;
+                                        --dstBuf;
+                                }
+                        }
+                }
+                break;
+
+               case 3:
+                {
+                        for (row = 0; row < src->h; ++row) {
+                                srcBuf = (Uint32*)(src->pixels) + (row * src_ipr);
+                                dstBuf = (Uint32*)(dst->pixels) + row + ((dst->h - 1) * dst_ipr);
+                                for (col = 0; col < src->w; ++col) {
+                                        *dstBuf = *srcBuf;
+                                        ++srcBuf;
+                                        dstBuf -= dst_ipr;
+                                }
+                        }
+                }
+                break;
+       }
+       /* end switch */
+
+       if (SDL_MUSTLOCK(src)) {
+               SDL_UnlockSurface(src);
+       }
+       if (SDL_MUSTLOCK(dst)) {
+               SDL_UnlockSurface(dst);
+       }
+
+       return dst;
+}
+
+
+#if 1
+/*!
+\brief Internal target surface sizing function for rotozooms with trig result return.
+
+\param width The source surface width.
+\param height The source surface height.
+\param angle The angle to rotate in degrees.
+\param zoomx The horizontal scaling factor.
+\param zoomy The vertical scaling factor.
+\param dstwidth The calculated width of the destination surface.
+\param dstheight The calculated height of the destination surface.
+\param canglezoom The sine of the angle adjusted by the zoom factor.
+\param sanglezoom The cosine of the angle adjusted by the zoom factor.
+
+*/
+void _rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoomx, double zoomy,
+                                                         int *dstwidth, int *dstheight,
+                                                         double *canglezoom, double *sanglezoom)
+{
+       double x, y, cx, cy, sx, sy;
+       double radangle;
+       int dstwidthhalf, dstheighthalf;
+
+       /*
+       * Determine destination width and height by rotating a centered source box
+       */
+       radangle = angle * (M_PI / 180.0);
+       *sanglezoom = sin(radangle);
+       *canglezoom = cos(radangle);
+       *sanglezoom *= zoomx;
+       *canglezoom *= zoomx;
+       x = width / 2;
+       y = height / 2;
+       cx = *canglezoom * x;
+       cy = *canglezoom * y;
+       sx = *sanglezoom * x;
+       sy = *sanglezoom * y;
+
+       dstwidthhalf = MAX((int)
+               ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
+       dstheighthalf = MAX((int)
+               ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
+       *dstwidth = 2 * dstwidthhalf;
+       *dstheight = 2 * dstheighthalf;
+}
+
+/*!
+\brief Returns the size of the resulting target surface for a rotozoomSurfaceXY() call.
+
+\param width The source surface width.
+\param height The source surface height.
+\param angle The angle to rotate in degrees.
+\param zoomx The horizontal scaling factor.
+\param zoomy The vertical scaling factor.
+\param dstwidth The calculated width of the rotozoomed destination surface.
+\param dstheight The calculated height of the rotozoomed destination surface.
+*/
+void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight)
+{
+       double dummy_sanglezoom, dummy_canglezoom;
+
+       _rotozoomSurfaceSizeTrig(width, height, angle, zoomx, zoomy, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
+}
+
+/*!
+\brief Returns the size of the resulting target surface for a rotozoomSurface() call.
+
+\param width The source surface width.
+\param height The source surface height.
+\param angle The angle to rotate in degrees.
+\param zoom The scaling factor.
+\param dstwidth The calculated width of the rotozoomed destination surface.
+\param dstheight The calculated height of the rotozoomed destination surface.
+*/
+void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
+{
+       double dummy_sanglezoom, dummy_canglezoom;
+
+       _rotozoomSurfaceSizeTrig(width, height, angle, zoom, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
+}
+
+/*!
+\brief Rotates and zooms a surface and optional anti-aliasing.
+
+Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+'angle' is the rotation in degrees and 'zoom' a scaling factor. If 'smooth' is set
+then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+\param src The surface to rotozoom.
+\param angle The angle to rotate in degrees.
+\param zoom The scaling factor.
+\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
+
+\return The new rotozoomed surface.
+*/
+SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
+{
+       return rotozoomSurfaceXY(src, angle, zoom, zoom, smooth);
+}
+
+/*!
+\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
+
+Rotates and zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+'angle' is the rotation in degrees, 'zoomx and 'zoomy' scaling factors. If 'smooth' is set
+then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+\param src The surface to rotozoom.
+\param angle The angle to rotate in degrees.
+\param zoomx The horizontal scaling factor.
+\param zoomy The vertical scaling factor.
+\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
+
+\return The new rotozoomed surface.
+*/
+SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth)
+{
+       SDL_Surface *rz_src;
+       SDL_Surface *rz_dst;
+       double zoominv;
+       double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
+       int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
+       int is32bit;
+       int i, src_converted;
+       int flipx,flipy;
+       Uint8 r,g,b;
+       Uint32 colorkey = 0;
+       int colorKeyAvailable = 0;
+
+       /*
+       * Sanity check
+       */
+       if (src == NULL)
+               return (NULL);
+
+       if (src->flags & SDL_SRCCOLORKEY)
+       {
+               colorkey = _colorkey(src);
+               SDL_GetRGB(colorkey, src->format, &r, &g, &b);
+               colorKeyAvailable = 1;
+       }
+       /*
+       * Determine if source surface is 32bit or 8bit
+       */
+       is32bit = (src->format->BitsPerPixel == 32);
+       if ((is32bit) || (src->format->BitsPerPixel == 8)) {
+               /*
+               * Use source surface 'as is'
+               */
+               rz_src = src;
+               src_converted = 0;
+       } else {
+               /*
+               * New source surface is 32bit with a defined RGBA ordering
+               */
+               rz_src =
+                       SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
+#else
+                       0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
+#endif
+                       );
+               if(colorKeyAvailable)
+                       SDL_SetColorKey(src, 0, 0);
+
+               SDL_BlitSurface(src, NULL, rz_src, NULL);
+
+               if(colorKeyAvailable)
+                       SDL_SetColorKey(src, SDL_SRCCOLORKEY, colorkey);
+               src_converted = 1;
+               is32bit = 1;
+       }
+
+       /*
+       * Sanity check zoom factor
+       */
+       flipx = (zoomx<0.0);
+       if (flipx) zoomx=-zoomx;
+       flipy = (zoomy<0.0);
+       if (flipy) zoomy=-zoomy;
+       if (zoomx < VALUE_LIMIT) zoomx = VALUE_LIMIT;
+       if (zoomy < VALUE_LIMIT) zoomy = VALUE_LIMIT;
+       zoominv = 65536.0 / (zoomx * zoomx);
+
+       /*
+       * Check if we have a rotozoom or just a zoom
+       */
+       if (fabs(angle) > VALUE_LIMIT) {
+
+               /*
+               * Angle!=0: full rotozoom
+               */
+               /*
+               * -----------------------
+               */
+
+               /* Determine target size */
+               _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoomx, zoomy, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
+
+               /*
+               * Calculate target factors from sin/cos and zoom
+               */
+               sanglezoominv = sanglezoom;
+               canglezoominv = canglezoom;
+               sanglezoominv *= zoominv;
+               canglezoominv *= zoominv;
+
+               /* Calculate half size */
+               dstwidthhalf = dstwidth / 2;
+               dstheighthalf = dstheight / 2;
+
+               /*
+               * Alloc space to completely contain the rotated surface
+               */
+               rz_dst = NULL;
+               if (is32bit) {
+                       /*
+                       * Target surface is 32bit with source RGBA/ABGR ordering
+                       */
+                       rz_dst =
+                               SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
+                               rz_src->format->Rmask, rz_src->format->Gmask,
+                               rz_src->format->Bmask, rz_src->format->Amask);
+               } else {
+                       /*
+                       * Target surface is 8bit
+                       */
+                       rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
+               }
+
+               if (colorKeyAvailable == 1){
+                       colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
+
+                       SDL_FillRect(rz_dst, NULL, colorkey );
+               }
+
+               /*
+               * Lock source surface
+               */
+               if (SDL_MUSTLOCK(rz_src)) {
+                       SDL_LockSurface(rz_src);
+               }
+
+               /*
+               * Check which kind of surface we have
+               */
+               if (is32bit) {
+                       /*
+                       * Call the 32bit transformation routine to do the rotation (using alpha)
+                       */
+                       _transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
+                               (int) (sanglezoominv), (int) (canglezoominv),
+                               flipx, flipy,
+                               smooth);
+                       /*
+                       * Turn on source-alpha support
+                       */
+                       SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+                       SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+               } else {
+                       /*
+                       * Copy palette and colorkey info
+                       */
+                       for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+                               rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+                       }
+                       rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+                       /*
+                       * Call the 8bit transformation routine to do the rotation
+                       */
+                       transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
+                               (int) (sanglezoominv), (int) (canglezoominv),
+                               flipx, flipy);
+                       SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+               }
+               /*
+               * Unlock source surface
+               */
+               if (SDL_MUSTLOCK(rz_src)) {
+                       SDL_UnlockSurface(rz_src);
+               }
+
+       } else {
+
+               /*
+               * Angle=0: Just a zoom
+               */
+               /*
+               * --------------------
+               */
+
+               /*
+               * Calculate target size
+               */
+               zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
+
+               /*
+               * Alloc space to completely contain the zoomed surface
+               */
+               rz_dst = NULL;
+               if (is32bit) {
+                       /*
+                       * Target surface is 32bit with source RGBA/ABGR ordering
+                       */
+                       rz_dst =
+                               SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
+                               rz_src->format->Rmask, rz_src->format->Gmask,
+                               rz_src->format->Bmask, rz_src->format->Amask);
+               } else {
+                       /*
+                       * Target surface is 8bit
+                       */
+                       rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
+               }
+
+               if (colorKeyAvailable == 1){
+                       colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
+
+                       SDL_FillRect(rz_dst, NULL, colorkey );
+               }
+
+               /*
+               * Lock source surface
+               */
+               if (SDL_MUSTLOCK(rz_src)) {
+                       SDL_LockSurface(rz_src);
+               }
+
+               /*
+               * Check which kind of surface we have
+               */
+               if (is32bit) {
+                       /*
+                       * Call the 32bit transformation routine to do the zooming (using alpha)
+                       */
+                       _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
+                       /*
+                       * Turn on source-alpha support
+                       */
+                       SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+                       SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+               } else {
+                       /*
+                       * Copy palette and colorkey info
+                       */
+                       for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+                               rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+                       }
+                       rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+                       /*
+                       * Call the 8bit transformation routine to do the zooming
+                       */
+                       _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
+                       SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+               }
+               /*
+               * Unlock source surface
+               */
+               if (SDL_MUSTLOCK(rz_src)) {
+                       SDL_UnlockSurface(rz_src);
+               }
+       }
+
+       /*
+       * Cleanup temp surface
+       */
+       if (src_converted) {
+               SDL_FreeSurface(rz_src);
+       }
+
+       /*
+       * Return destination surface
+       */
+       rz_dst->h -= GUARD_ROWS;
+       return (rz_dst);
+}
+
+/*!
+\brief Calculates the size of the target surface for a zoomSurface() call.
+
+The minimum size of the target surface is 1. The input factors can be positive or negative.
+
+\param width The width of the source surface to zoom.
+\param height The height of the source surface to zoom.
+\param zoomx The horizontal zoom factor.
+\param zoomy The vertical zoom factor.
+\param dstwidth Pointer to an integer to store the calculated width of the zoomed target surface.
+\param dstheight Pointer to an integer to store the calculated height of the zoomed target surface.
+*/
+void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
+{
+       /*
+       * Make zoom factors positive
+       */
+       int flipx, flipy;
+       flipx = (zoomx<0.0);
+       if (flipx) zoomx = -zoomx;
+       flipy = (zoomy<0.0);
+       if (flipy) zoomy = -zoomy;
+
+       /*
+       * Sanity check zoom factors
+       */
+       if (zoomx < VALUE_LIMIT) {
+               zoomx = VALUE_LIMIT;
+       }
+       if (zoomy < VALUE_LIMIT) {
+               zoomy = VALUE_LIMIT;
+       }
+
+       /*
+       * Calculate target size
+       */
+       *dstwidth = (int) ((double) width * zoomx);
+       *dstheight = (int) ((double) height * zoomy);
+       if (*dstwidth < 1) {
+               *dstwidth = 1;
+       }
+       if (*dstheight < 1) {
+               *dstheight = 1;
+       }
+}
+
+/*!
+\brief Zoom a surface by independent horizontal and vertical factors with optional smoothing.
+
+Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is on
+then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+If zoom factors are negative, the image is flipped on the axes.
+
+\param src The surface to zoom.
+\param zoomx The horizontal zoom factor.
+\param zoomy The vertical zoom factor.
+\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
+
+\return The new, zoomed surface.
+*/
+SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
+{
+       SDL_Surface *rz_src;
+       SDL_Surface *rz_dst;
+       int dstwidth, dstheight;
+       int is32bit;
+       int i, src_converted;
+       int flipx, flipy;
+
+       /*
+       * Sanity check
+       */
+       if (src == NULL)
+               return (NULL);
+
+       /*
+       * Determine if source surface is 32bit or 8bit
+       */
+       is32bit = (src->format->BitsPerPixel == 32);
+       if ((is32bit) || (src->format->BitsPerPixel == 8)) {
+               /*
+               * Use source surface 'as is'
+               */
+               rz_src = src;
+               src_converted = 0;
+       } else {
+               /*
+               * New source surface is 32bit with a defined RGBA ordering
+               */
+               rz_src =
+                       SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
+#else
+                       0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
+#endif
+                       );
+               SDL_BlitSurface(src, NULL, rz_src, NULL);
+               src_converted = 1;
+               is32bit = 1;
+       }
+
+       flipx = (zoomx<0.0);
+       if (flipx) zoomx = -zoomx;
+       flipy = (zoomy<0.0);
+       if (flipy) zoomy = -zoomy;
+
+       /* Get size if target */
+       zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
+
+       /*
+       * Alloc space to completely contain the zoomed surface
+       */
+       rz_dst = NULL;
+       if (is32bit) {
+               /*
+               * Target surface is 32bit with source RGBA/ABGR ordering
+               */
+               rz_dst =
+                       SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
+                       rz_src->format->Rmask, rz_src->format->Gmask,
+                       rz_src->format->Bmask, rz_src->format->Amask);
+       } else {
+               /*
+               * Target surface is 8bit
+               */
+               rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
+       }
+
+       /*
+       * Lock source surface
+       */
+       if (SDL_MUSTLOCK(rz_src)) {
+               SDL_LockSurface(rz_src);
+       }
+
+       /*
+       * Check which kind of surface we have
+       */
+       if (is32bit) {
+               /*
+               * Call the 32bit transformation routine to do the zooming (using alpha)
+               */
+               _zoomSurfaceRGBA(rz_src, rz_dst, flipx, flipy, smooth);
+               /*
+               * Turn on source-alpha support
+               */
+               SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+       } else {
+               /*
+               * Copy palette and colorkey info
+               */
+               for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+                       rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+               }
+               rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+               /*
+               * Call the 8bit transformation routine to do the zooming
+               */
+               _zoomSurfaceY(rz_src, rz_dst, flipx, flipy);
+               SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+       }
+       /*
+       * Unlock source surface
+       */
+       if (SDL_MUSTLOCK(rz_src)) {
+               SDL_UnlockSurface(rz_src);
+       }
+
+       /*
+       * Cleanup temp surface
+       */
+       if (src_converted) {
+               SDL_FreeSurface(rz_src);
+       }
+
+       /*
+       * Return destination surface
+       */
+       rz_dst->h -= GUARD_ROWS;
+       return (rz_dst);
+}
+
+/*!
+\brief Shrink a surface by an integer ratio using averaging.
+
+Shrinks a 32bit or 8bit 'src' surface to a newly created 'dst' surface.
+'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
+3=1/3 the size, etc.) The destination surface is antialiased by averaging
+the source box RGBA or Y information. If the surface is not 8bit
+or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+The input surface is not modified. The output surface is newly allocated.
+
+\param src The surface to shrink.
+\param factorx The horizontal shrinking ratio.
+\param factory The vertical shrinking ratio.
+
+\return The new, shrunken surface.
+*/
+SDL_Surface *shrinkSurface(SDL_Surface *src, int factorx, int factory)
+{
+       SDL_Surface *rz_src;
+       SDL_Surface *rz_dst;
+       int dstwidth, dstheight;
+       int is32bit;
+       int i, src_converted;
+
+       /*
+       * Sanity check
+       */
+       if (src == NULL)
+               return (NULL);
+
+       /*
+       * Determine if source surface is 32bit or 8bit
+       */
+       is32bit = (src->format->BitsPerPixel == 32);
+       if ((is32bit) || (src->format->BitsPerPixel == 8)) {
+               /*
+               * Use source surface 'as is'
+               */
+               rz_src = src;
+               src_converted = 0;
+       } else {
+               /*
+               * New source surface is 32bit with a defined RGBA ordering
+               */
+               rz_src =
+                       SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
+#else
+                       0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
+#endif
+                       );
+               SDL_BlitSurface(src, NULL, rz_src, NULL);
+               src_converted = 1;
+               is32bit = 1;
+       }
+
+       /* Get size for target */
+       dstwidth=rz_src->w/factorx;
+       while (dstwidth*factorx>rz_src->w) { dstwidth--; }
+       dstheight=rz_src->h/factory;
+       while (dstheight*factory>rz_src->h) { dstheight--; }
+
+       /*
+       * Alloc space to completely contain the shrunken surface
+       * (with added guard rows)
+       */
+       rz_dst = NULL;
+       if (is32bit) {
+               /*
+               * Target surface is 32bit with source RGBA/ABGR ordering
+               */
+               rz_dst =
+                       SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
+                       rz_src->format->Rmask, rz_src->format->Gmask,
+                       rz_src->format->Bmask, rz_src->format->Amask);
+       } else {
+               /*
+               * Target surface is 8bit
+               */
+               rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
+       }
+
+       /*
+       * Lock source surface
+       */
+       if (SDL_MUSTLOCK(rz_src)) {
+               SDL_LockSurface(rz_src);
+       }
+
+       /*
+       * Check which kind of surface we have
+       */
+       if (is32bit) {
+               /*
+               * Call the 32bit transformation routine to do the shrinking (using alpha)
+               */
+               _shrinkSurfaceRGBA(rz_src, rz_dst, factorx, factory);
+               /*
+               * Turn on source-alpha support
+               */
+               SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+       } else {
+               /*
+               * Copy palette and colorkey info
+               */
+               for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+                       rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+               }
+               rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+               /*
+               * Call the 8bit transformation routine to do the shrinking
+               */
+               _shrinkSurfaceY(rz_src, rz_dst, factorx, factory);
+               SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, _colorkey(rz_src));
+       }
+
+       /*
+       * Unlock source surface
+       */
+       if (SDL_MUSTLOCK(rz_src)) {
+               SDL_UnlockSurface(rz_src);
+       }
+
+       /*
+       * Cleanup temp surface
+       */
+       if (src_converted) {
+               SDL_FreeSurface(rz_src);
+       }
+
+       /*
+       * Return destination surface
+       */
+       rz_dst->h -= GUARD_ROWS;
+       return (rz_dst);
+}
+#endif
diff --git a/tizen/src/sdl_rotate.h b/tizen/src/sdl_rotate.h
new file mode 100644 (file)
index 0000000..4611690
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Hyunjun Son(hj79.son@samsung.com)
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _SDL_rotate_h
+#define _SDL_rotate_h
+
+#include <SDL.h>
+#include <math.h>
+
+/* ---- Prototypes */
+
+#ifdef WIN32
+#  ifdef DLL_EXPORT
+#    define SDL_ROTOZOOM_SCOPE __declspec(dllexport)
+#  else
+#    ifdef LIBSDL_GFX_DLL_IMPORT
+#      define SDL_ROTOZOOM_SCOPE __declspec(dllimport)
+#    endif
+#  endif
+#endif
+#ifndef SDL_ROTOZOOM_SCOPE
+#  define SDL_ROTOZOOM_SCOPE extern
+#endif
+
+/*
+
+ rotozoomSurface()
+
+ Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+ */
+
+SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);
+
+SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurfaceXY
+(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth);
+
+/* Returns the size of the target surface for a rotozoomSurface() call */
+
+SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth,
+               int *dstheight);
+
+SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSizeXY
+(int width, int height, double angle, double zoomx, double zoomy,
+               int *dstwidth, int *dstheight);
+
+/*
+
+ zoomSurface()
+
+ Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+ */
+
+SDL_ROTOZOOM_SCOPE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
+
+/* Returns the size of the target surface for a zoomSurface() call */
+
+SDL_ROTOZOOM_SCOPE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
+
+
+/*
+    shrinkSurface()
+
+    Shrinks a 32bit or 8bit 'src' surface ti a newly created 'dst' surface.
+    'factorx' and 'factory' are the shrinking ratios (i.e. 2=1/2 the size,
+    3=1/3 the size, etc.) The destination surface is antialiased by averaging
+    the source box RGBA or Y information. If the surface is not 8bit
+    or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+ */
+
+SDL_ROTOZOOM_SCOPE SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory);
+
+/*
+
+    Other functions
+
+ */
+
+SDL_ROTOZOOM_SCOPE SDL_Surface* rotateSurface90Degrees(SDL_Surface* pSurf, int numClockwiseTurns);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif                         /* _SDL_rotate_h */
diff --git a/tizen/src/sdl_zoom.c b/tizen/src/sdl_zoom.c
new file mode 100644 (file)
index 0000000..287f9e8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sdl_zoom.h"
+#include "osdep.h"
+#include <stdint.h>
+#include <stdio.h>
+
+static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+
+#define BPP 32
+#include  "sdl_zoom_template.h"
+#undef BPP
+#define BPP 16
+#include  "sdl_zoom_template.h"
+#undef BPP
+
+#if 0
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth,
+                  SDL_Rect *in_rect)
+{
+    SDL_Rect zoom, src_rect;
+    int extra;
+
+    /* Grow the size of the modified rectangle to avoid edge artefacts */
+    src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0;
+    src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0;
+
+    src_rect.w = in_rect->w + 1;
+    if (src_rect.x + src_rect.w > src_sfc->w)
+        src_rect.w = src_sfc->w - src_rect.x;
+
+    src_rect.h = in_rect->h + 1;
+    if (src_rect.y + src_rect.h > src_sfc->h)
+        src_rect.h = src_sfc->h - src_rect.y;
+
+    /* (x,y) : round down */
+    zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w));
+    zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h));
+
+    /* (w,h) : round up */
+    zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) /
+                     (double)(src_sfc->w));
+
+    zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) /
+                     (double)(src_sfc->h));
+
+    /* Account for any (x,y) rounding by adding one-source-pixel's worth
+     * of destination pixels and then edge checking.
+     */
+
+    extra = ((dst_sfc->w-1) / src_sfc->w) + 1;
+
+    if ((zoom.x + zoom.w) < (dst_sfc->w - extra))
+        zoom.w += extra;
+    else
+        zoom.w = dst_sfc->w - zoom.x;
+
+    extra = ((dst_sfc->h-1) / src_sfc->h) + 1;
+
+    if ((zoom.y + zoom.h) < (dst_sfc->h - extra))
+        zoom.h += extra;
+    else
+        zoom.h = dst_sfc->h - zoom.y;
+
+    /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the
+     * destination surface that needs to be updated.
+     */
+    if (src_sfc->format->BitsPerPixel == 32)
+        sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom);
+    else if (src_sfc->format->BitsPerPixel == 16)
+        sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom);
+    else {
+        fprintf(stderr, "pixel format not supported\n");
+        return -1;
+    }
+
+    /* Return the rectangle of the update to the caller */
+    *in_rect = zoom;
+
+    return 0;
+}
+#endif
diff --git a/tizen/src/sdl_zoom.h b/tizen/src/sdl_zoom.h
new file mode 100644 (file)
index 0000000..1303352
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef SDL_zoom_h
+#define SDL_zoom_h
+
+#include <SDL.h>
+
+#define SMOOTHING_OFF          0
+#define SMOOTHING_ON           1
+
+//int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc,
+    //              int smooth, SDL_Rect *src_rect);
+
+#endif /* SDL_zoom_h */
diff --git a/tizen/src/sdl_zoom_template.h b/tizen/src/sdl_zoom_template.h
new file mode 100644 (file)
index 0000000..64bbca8
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * SDL_zoom_template - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#if BPP == 16
+#define SDL_TYPE Uint16
+#elif BPP == 32
+#define SDL_TYPE Uint32
+#else
+#error unsupport depth
+#endif
+
+/*  
+ *  Simple helper functions to make the code looks nicer
+ *
+ *  Assume spf = source SDL_PixelFormat
+ *         dpf = dest SDL_PixelFormat
+ *
+ */
+#define getRed(color)   (((color) & spf->Rmask) >> spf->Rshift)
+#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift)
+#define getBlue(color)  (((color) & spf->Bmask) >> spf->Bshift)
+#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift)
+
+#define setRed(r, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \
+              (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \
+} while (0);
+
+#define setGreen(g, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \
+              (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \
+} while (0);
+
+#define setBlue(b, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \
+              (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \
+} while (0);
+
+#define setAlpha(a, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Amask))) + \
+              (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \
+} while (0);
+
+static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                                   SDL_Rect *dst_rect)
+{
+    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump;
+    SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp;
+    int d_gap;
+    SDL_PixelFormat *spf = src->format;
+    SDL_PixelFormat *dpf = dst->format;
+
+    if (smooth) { 
+        /* For interpolation: assume source dimension is one pixel.
+         * Smaller here to avoid overflow on right and bottom edge.
+         */
+        sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+        sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+    } else {
+        sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+        sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+    }
+
+    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+        return (-1);
+    }
+    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+        free(sax);
+        return (-1);
+    }
+
+    sp = csp = (SDL_TYPE *) src->pixels;
+    dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch +
+                       dst_rect->x * dst->format->BytesPerPixel);
+
+    csx = 0;
+    csax = sax;
+    for (x = 0; x <= dst->w; x++) {
+        *csax = csx;
+        csax++;
+        csx &= 0xffff;
+        csx += sx;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y <= dst->h; y++) {
+        *csay = csy;
+        csay++;
+        csy &= 0xffff;
+        csy += sy;
+    }
+
+    d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel;
+
+    if (smooth) {
+        csay = say;
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0; y < dst_rect->h ; y++) {
+            /* Setup colour source pointers */
+            c00 = csp + sstep_jump;
+            c01 = c00 + 1;
+            c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump;
+            c11 = c10 + 1;
+            csax = sax + dst_rect->x; 
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Interpolate colours */
+                ex = (*csax & 0xffff);
+                ey = (*csay & 0xffff);
+                t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) +
+                     getRed(*c00)) & (dpf->Rmask >> dpf->Rshift);
+                t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) +
+                     getRed(*c10)) & (dpf->Rmask >> dpf->Rshift);
+                setRed((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) +
+                     getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift);
+                t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) +
+                     getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift);
+                setGreen((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) +
+                     getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift);
+                t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) +
+                     getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift);
+                setBlue((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) +
+                     getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift);
+                t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) +
+                     getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift);
+                setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); 
+
+                /* Advance source pointers */
+                csax++; 
+                sstep = (*csax >> 16);
+                c00 += sstep;
+                c01 += sstep;
+                c10 += sstep;
+                c11 += sstep;
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointer */
+            csay++;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+            /* Advance destination pointers */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+
+
+    } else {
+        csay = say;
+
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0 ; y < dst_rect->h ; y++) {
+            sp = csp + sstep_jump;
+            csax = sax + dst_rect->x;
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Draw */
+                *dp = *sp;
+
+                /* Advance source pointers */
+                csax++;
+                sstep = (*csax >> 16);
+                sp += sstep;
+
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointers */
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+
+            /* Advance destination pointer */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+    }
+
+    free(sax);
+    free(say);
+    return (0);
+}
+
+#undef SDL_TYPE
+
diff --git a/tizen/src/skin/client/.classpath b/tizen/src/skin/client/.classpath
new file mode 100644 (file)
index 0000000..957bee2
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="jaxb_src"/>
+       <classpathentry kind="src" path="resource"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+       <classpathentry kind="lib" path="lib/swt/gtk-linux/swt.jar" sourcepath="lib/swt/gtk-linux/src.zip"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tizen/src/skin/client/.project b/tizen/src/skin/client/.project
new file mode 100644 (file)
index 0000000..cdb4a9e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>EmulatorSkin</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/tizen/src/skin/client/.settings/org.eclipse.core.resources.prefs b/tizen/src/skin/client/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..99f26c0
--- /dev/null
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/tizen/src/skin/client/build.xml b/tizen/src/skin/client/build.xml
new file mode 100644 (file)
index 0000000..71b52a0
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version="1.0" standalone="yes"?>
+<project name="emulator-skin" basedir="." default="linux-jar">
+
+       <property name="jar.file" value="emulator-skin.jar" />
+       <property name="mainclass" value="org.tizen.emulator.skin.EmulatorSkinMain" />
+
+       <property name="swt.file" value="swt.jar" />
+
+       <path id="linux-classpath">
+               <fileset dir="lib/swt/gtk-linux" includes="swt.jar" />
+       </path>
+       <path id="windows-classpath">
+               <fileset dir="lib/swt/win32-win32" includes="swt.jar" />
+       </path>
+       <path id="mac-classpath">
+               <fileset dir="lib/swt/cocoa-macosx" includes="swt.jar" />
+       </path>
+
+       <target name="clean">
+               <echo message="cleaning..." />
+               <delete dir="dist" />
+               <delete file="${jar.file}" />
+       </target>
+
+       <target name="make-properties">
+               <echo message="make properties..." />
+               <tstamp>
+                       <format property="build_time" pattern="MM/dd/yyyy hh:mm aa" timezone="GMT" locale="en" />
+               </tstamp>
+               <exec executable="cat" outputproperty="version">
+                       <arg value="../../VERSION" />
+               </exec>
+               <exec executable="git" outputproperty="build_git_commit" failifexecutionfails="false">
+                       <arg value="rev-parse" />
+                       <arg value="--short" />
+                       <arg value="HEAD" />
+               </exec>
+               <propertyfile file="src/about.properties" comment="Auto-generated properties - DO NOT EDIT">
+                       <entry key="version" value="${version}" />
+                       <entry key="build_time" value="${build_time}" />
+                       <entry key="build_git_commit" value="${build_git_commit}" />
+               </propertyfile>
+       </target>
+
+       <target name="linux-compile" depends="make-properties">
+               <echo message="compiling..." />
+        <delete dir="build" />
+               <mkdir dir="build" />
+               <javac encoding="UTF-8" fork="true" srcdir="src:jaxb_src" destdir="build" debug="on" memorymaximumsize="128m">
+                       <classpath refid="linux-classpath" />
+               </javac>
+       </target>
+
+       <target name="windows-compile" depends="make-properties">
+               <echo message="compiling..." />
+        <delete dir="build" />
+        <mkdir dir="build" />
+               <javac encoding="UTF-8" fork="true" srcdir="src:jaxb_src" destdir="build" debug="on" memorymaximumsize="128m">
+                       <classpath refid="windows-classpath" />
+               </javac>
+       </target>
+
+       <target name="mac-compile" depends="make-properties">
+               <echo message="compiling..." />
+        <delete dir="build" />
+        <mkdir dir="build" />
+               <javac encoding="UTF-8" fork="true" srcdir="src:jaxb_src" destdir="build" debug="on" memorymaximumsize="128m">
+                       <classpath refid="mac-classpath" />
+               </javac>
+       </target>
+
+       <target name="linux-jar" depends="linux-compile">
+               <echo message="creating jar..." />
+               <mkdir dir="build/icons" />
+               <copy todir="build/icons">
+                       <fileset dir="resource/icons" />
+               </copy>
+               <jar jarfile="${jar.file}" basedir="build" duplicate="add">
+                       <fileset file="src/about.properties" />
+                       <manifest>
+                               <attribute name="Main-Class" value="${mainclass}" />
+                               <attribute name="Class-path" value="lib/swt/gtk-linux/${swt.file}" />
+                       </manifest>
+               </jar>
+               <delete dir="build" />
+       </target>
+
+       <target name="windows-jar" depends="windows-compile">
+        <echo message="creating jar..." />
+        <mkdir dir="build/icons" />
+        <copy todir="build/icons">
+            <fileset dir="resource/icons" />
+        </copy>
+               <jar jarfile="${jar.file}" basedir="build" duplicate="add">
+                       <fileset file="src/about.properties" />
+                       <manifest>
+                               <attribute name="Main-Class" value="${mainclass}" />
+                               <attribute name="Class-path" value="lib/swt/win32-win32/${swt.file}" />
+                       </manifest>
+               </jar>
+               <delete dir="build" />
+       </target>
+
+       <target name="mac-jar" depends="mac-compile">
+        <echo message="creating jar..." />
+        <mkdir dir="build/icons" />
+        <copy todir="build/icons">
+            <fileset dir="resource/icons" />
+        </copy>
+               <jar jarfile="${jar.file}" basedir="build" duplicate="add">
+                       <fileset file="src/about.properties" />
+                       <manifest>
+                               <attribute name="Main-Class" value="${mainclass}" />
+                               <attribute name="Class-path" value="lib/swt/cocoa-macosx/${swt.file}" />
+                       </manifest>
+               </jar>
+               <delete dir="build" />
+       </target>
+
+</project>
\ No newline at end of file
diff --git a/tizen/src/skin/client/dev/.skin.properties b/tizen/src/skin/client/dev/.skin.properties
new file mode 100644 (file)
index 0000000..077f333
--- /dev/null
@@ -0,0 +1,6 @@
+#Automatically generated by emulator skin.
+#Tue Mar 27 16:56:00 KST 2012
+window.y=50
+window.x=100
+window.scale=50
+window.rotate=0
diff --git a/tizen/src/skin/client/dev/.skinconfig.properties b/tizen/src/skin/client/dev/.skinconfig.properties
new file mode 100644 (file)
index 0000000..224e847
--- /dev/null
@@ -0,0 +1,11 @@
+##########################################
+### Emulator Skin system configuration ###
+##########################################
+
+# heartbeat ignore setting
+# ( true:ignore heartbeat operation in Skin, false:do heartbeat operation in Skin )
+test.hb.ignore=false
+
+# log level
+# ( trace/debug/warn/error )
+log.level=trace
diff --git a/tizen/src/skin/client/dev/dbi-sample.xml b/tizen/src/skin/client/dev/dbi-sample.xml
new file mode 100644 (file)
index 0000000..529d176
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation id="0" name="Portrait">
+            <lcd id="0">
+                <region height="800" left="35" top="86" width="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region height="74" left="238" top="887" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="819" width="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="81" width="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="167" width="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation id="1" name="Landscape">
+            <lcd id="0">
+                <region height="480" left="86" top="46" width="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region height="74" left="887" top="249" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="818" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="80" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="165" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation id="2" name="Reverse Portrait">
+            <lcd id="0">
+                <region left="46" top="89" width="480" height="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="249" top="14" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="84" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="821" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="735" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation id="3" name="Reverse Landscape">
+            <lcd id="0">
+                <region left="90" top="35" width="800" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="15" top="239" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="84" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="822" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="735" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ColorsType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ColorsType.java
new file mode 100644 (file)
index 0000000..8658151
--- /dev/null
@@ -0,0 +1,67 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for colorsType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="colorsType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;all>
+ *         &lt;element name="hoverColor" type="{http://www.tizen.org/emulator/dbi}rgbType" minOccurs="0"/>
+ *       &lt;/all>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "colorsType", propOrder = {
+
+})
+public class ColorsType {
+
+    protected RgbType hoverColor;
+
+    /**
+     * Gets the value of the hoverColor property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link RgbType }
+     *     
+     */
+    public RgbType getHoverColor() {
+        return hoverColor;
+    }
+
+    /**
+     * Sets the value of the hoverColor property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link RgbType }
+     *     
+     */
+    public void setHoverColor(RgbType value) {
+        this.hoverColor = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EmulatorUI.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EmulatorUI.java
new file mode 100644 (file)
index 0000000..0ee4e30
--- /dev/null
@@ -0,0 +1,97 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType>
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;all>
+ *         &lt;element name="rotations" type="{http://www.tizen.org/emulator/dbi}rotationsType"/>
+ *         &lt;element name="colors" type="{http://www.tizen.org/emulator/dbi}colorsType" minOccurs="0"/>
+ *       &lt;/all>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+
+})
+@XmlRootElement(name = "EmulatorUI")
+public class EmulatorUI {
+
+    @XmlElement(required = true)
+    protected RotationsType rotations;
+    protected ColorsType colors;
+
+    /**
+     * Gets the value of the rotations property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link RotationsType }
+     *     
+     */
+    public RotationsType getRotations() {
+        return rotations;
+    }
+
+    /**
+     * Sets the value of the rotations property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link RotationsType }
+     *     
+     */
+    public void setRotations(RotationsType value) {
+        this.rotations = value;
+    }
+
+    /**
+     * Gets the value of the colors property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link ColorsType }
+     *     
+     */
+    public ColorsType getColors() {
+        return colors;
+    }
+
+    /**
+     * Sets the value of the colors property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link ColorsType }
+     *     
+     */
+    public void setColors(ColorsType value) {
+        this.colors = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EventInfoType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EventInfoType.java
new file mode 100644 (file)
index 0000000..4512ffb
--- /dev/null
@@ -0,0 +1,87 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for eventInfoType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="eventInfoType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;all>
+ *         &lt;element name="keyCode" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ *         &lt;element name="keyName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       &lt;/all>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "eventInfoType", propOrder = {
+
+})
+public class EventInfoType {
+
+    protected int keyCode;
+    @XmlElement(required = true)
+    protected String keyName;
+
+    /**
+     * Gets the value of the keyCode property.
+     * 
+     */
+    public int getKeyCode() {
+        return keyCode;
+    }
+
+    /**
+     * Sets the value of the keyCode property.
+     * 
+     */
+    public void setKeyCode(int value) {
+        this.keyCode = value;
+    }
+
+    /**
+     * Gets the value of the keyName property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getKeyName() {
+        return keyName;
+    }
+
+    /**
+     * Sets the value of the keyName property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setKeyName(String value) {
+        this.keyName = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ImageListType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ImageListType.java
new file mode 100644 (file)
index 0000000..4ffe3cc
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for imageListType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="imageListType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;all>
+ *         &lt;element name="mainImage" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="keyPressedImage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       &lt;/all>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "imageListType", propOrder = {
+
+})
+public class ImageListType {
+
+    @XmlElement(required = true)
+    protected String mainImage;
+    protected String keyPressedImage;
+
+    /**
+     * Gets the value of the mainImage property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getMainImage() {
+        return mainImage;
+    }
+
+    /**
+     * Sets the value of the mainImage property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setMainImage(String value) {
+        this.mainImage = value;
+    }
+
+    /**
+     * Gets the value of the keyPressedImage property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getKeyPressedImage() {
+        return keyPressedImage;
+    }
+
+    /**
+     * Sets the value of the keyPressedImage property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setKeyPressedImage(String value) {
+        this.keyPressedImage = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapListType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapListType.java
new file mode 100644 (file)
index 0000000..59be44d
--- /dev/null
@@ -0,0 +1,74 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for keyMapListType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="keyMapListType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="keyMap" type="{http://www.tizen.org/emulator/dbi}keyMapType" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "keyMapListType", propOrder = {
+    "keyMap"
+})
+public class KeyMapListType {
+
+    protected List<KeyMapType> keyMap;
+
+    /**
+     * Gets the value of the keyMap property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the keyMap property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getKeyMap().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link KeyMapType }
+     * 
+     * 
+     */
+    public List<KeyMapType> getKeyMap() {
+        if (keyMap == null) {
+            keyMap = new ArrayList<KeyMapType>();
+        }
+        return this.keyMap;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapType.java
new file mode 100644 (file)
index 0000000..6801ae9
--- /dev/null
@@ -0,0 +1,123 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for keyMapType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="keyMapType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="region" type="{http://www.tizen.org/emulator/dbi}regionType"/>
+ *         &lt;element name="eventInfo" type="{http://www.tizen.org/emulator/dbi}eventInfoType" minOccurs="0"/>
+ *         &lt;element name="tooltip" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "keyMapType", propOrder = {
+    "region",
+    "eventInfo",
+    "tooltip"
+})
+public class KeyMapType {
+
+    @XmlElement(required = true)
+    protected RegionType region;
+    protected EventInfoType eventInfo;
+    protected String tooltip;
+
+    /**
+     * Gets the value of the region property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link RegionType }
+     *     
+     */
+    public RegionType getRegion() {
+        return region;
+    }
+
+    /**
+     * Sets the value of the region property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link RegionType }
+     *     
+     */
+    public void setRegion(RegionType value) {
+        this.region = value;
+    }
+
+    /**
+     * Gets the value of the eventInfo property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link EventInfoType }
+     *     
+     */
+    public EventInfoType getEventInfo() {
+        return eventInfo;
+    }
+
+    /**
+     * Sets the value of the eventInfo property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link EventInfoType }
+     *     
+     */
+    public void setEventInfo(EventInfoType value) {
+        this.eventInfo = value;
+    }
+
+    /**
+     * Gets the value of the tooltip property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getTooltip() {
+        return tooltip;
+    }
+
+    /**
+     * Sets the value of the tooltip property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTooltip(String value) {
+        this.tooltip = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/LcdType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/LcdType.java
new file mode 100644 (file)
index 0000000..725d3c7
--- /dev/null
@@ -0,0 +1,89 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for lcdType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="lcdType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;all>
+ *         &lt;element name="region" type="{http://www.tizen.org/emulator/dbi}regionType"/>
+ *       &lt;/all>
+ *       &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "lcdType", propOrder = {
+
+})
+public class LcdType {
+
+    @XmlElement(required = true)
+    protected RegionType region;
+    @XmlAttribute(required = true)
+    protected int id;
+
+    /**
+     * Gets the value of the region property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link RegionType }
+     *     
+     */
+    public RegionType getRegion() {
+        return region;
+    }
+
+    /**
+     * Sets the value of the region property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link RegionType }
+     *     
+     */
+    public void setRegion(RegionType value) {
+        this.region = value;
+    }
+
+    /**
+     * Gets the value of the id property.
+     * 
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     */
+    public void setId(int value) {
+        this.id = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ObjectFactory.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ObjectFactory.java
new file mode 100644 (file)
index 0000000..3800807
--- /dev/null
@@ -0,0 +1,127 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each 
+ * Java content interface and Java element interface 
+ * generated in the org.tizen.emulator.skin.dbi package. 
+ * <p>An ObjectFactory allows you to programatically 
+ * construct new instances of the Java representation 
+ * for XML content. The Java representation of XML 
+ * content can consist of schema derived interfaces 
+ * and classes representing the binding of schema 
+ * type definitions, element declarations and model 
+ * groups.  Factory methods for each of these are 
+ * provided in this class.
+ * 
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.tizen.emulator.skin.dbi
+     * 
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link ImageListType }
+     * 
+     */
+    public ImageListType createImageListType() {
+        return new ImageListType();
+    }
+
+    /**
+     * Create an instance of {@link RotationType }
+     * 
+     */
+    public RotationType createRotationType() {
+        return new RotationType();
+    }
+
+    /**
+     * Create an instance of {@link LcdType }
+     * 
+     */
+    public LcdType createLcdType() {
+        return new LcdType();
+    }
+
+    /**
+     * Create an instance of {@link KeyMapType }
+     * 
+     */
+    public KeyMapType createKeyMapType() {
+        return new KeyMapType();
+    }
+
+    /**
+     * Create an instance of {@link EmulatorUI }
+     * 
+     */
+    public EmulatorUI createEmulatorUI() {
+        return new EmulatorUI();
+    }
+
+    /**
+     * Create an instance of {@link RotationsType }
+     * 
+     */
+    public RotationsType createRotationsType() {
+        return new RotationsType();
+    }
+
+    /**
+     * Create an instance of {@link ColorsType }
+     * 
+     */
+    public ColorsType createColorsType() {
+        return new ColorsType();
+    }
+
+    /**
+     * Create an instance of {@link EventInfoType }
+     * 
+     */
+    public EventInfoType createEventInfoType() {
+        return new EventInfoType();
+    }
+
+    /**
+     * Create an instance of {@link RegionType }
+     * 
+     */
+    public RegionType createRegionType() {
+        return new RegionType();
+    }
+
+    /**
+     * Create an instance of {@link KeyMapListType }
+     * 
+     */
+    public KeyMapListType createKeyMapListType() {
+        return new KeyMapListType();
+    }
+
+    /**
+     * Create an instance of {@link RgbType }
+     * 
+     */
+    public RgbType createRgbType() {
+        return new RgbType();
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RegionType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RegionType.java
new file mode 100644 (file)
index 0000000..495a34e
--- /dev/null
@@ -0,0 +1,146 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for regionType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="regionType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;attribute name="left" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       &lt;attribute name="top" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       &lt;attribute name="width" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       &lt;attribute name="height" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "regionType")
+public class RegionType {
+
+    @XmlAttribute
+    protected Integer left;
+    @XmlAttribute
+    protected Integer top;
+    @XmlAttribute
+    protected Integer width;
+    @XmlAttribute
+    protected Integer height;
+
+    /**
+     * Gets the value of the left property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getLeft() {
+        return left;
+    }
+
+    /**
+     * Sets the value of the left property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setLeft(Integer value) {
+        this.left = value;
+    }
+
+    /**
+     * Gets the value of the top property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getTop() {
+        return top;
+    }
+
+    /**
+     * Sets the value of the top property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setTop(Integer value) {
+        this.top = value;
+    }
+
+    /**
+     * Gets the value of the width property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getWidth() {
+        return width;
+    }
+
+    /**
+     * Sets the value of the width property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setWidth(Integer value) {
+        this.width = value;
+    }
+
+    /**
+     * Gets the value of the height property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public Integer getHeight() {
+        return height;
+    }
+
+    /**
+     * Sets the value of the height property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setHeight(Integer value) {
+        this.height = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RgbType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RgbType.java
new file mode 100644 (file)
index 0000000..54014a1
--- /dev/null
@@ -0,0 +1,123 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for rgbType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="rgbType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;attribute name="R" type="{http://www.w3.org/2001/XMLSchema}unsignedInt" />
+ *       &lt;attribute name="G" type="{http://www.w3.org/2001/XMLSchema}unsignedInt" />
+ *       &lt;attribute name="B" type="{http://www.w3.org/2001/XMLSchema}unsignedInt" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "rgbType")
+public class RgbType {
+
+    @XmlAttribute(name = "R")
+    @XmlSchemaType(name = "unsignedInt")
+    protected Long r;
+    @XmlAttribute(name = "G")
+    @XmlSchemaType(name = "unsignedInt")
+    protected Long g;
+    @XmlAttribute(name = "B")
+    @XmlSchemaType(name = "unsignedInt")
+    protected Long b;
+
+    /**
+     * Gets the value of the r property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getR() {
+        return r;
+    }
+
+    /**
+     * Sets the value of the r property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setR(Long value) {
+        this.r = value;
+    }
+
+    /**
+     * Gets the value of the g property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getG() {
+        return g;
+    }
+
+    /**
+     * Sets the value of the g property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setG(Long value) {
+        this.g = value;
+    }
+
+    /**
+     * Gets the value of the b property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Long }
+     *     
+     */
+    public Long getB() {
+        return b;
+    }
+
+    /**
+     * Sets the value of the b property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Long }
+     *     
+     */
+    public void setB(Long value) {
+        this.b = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationNameType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationNameType.java
new file mode 100644 (file)
index 0000000..a8c44fd
--- /dev/null
@@ -0,0 +1,64 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for rotationNameType.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="rotationNameType">
+ *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     &lt;enumeration value="Portrait"/>
+ *     &lt;enumeration value="Landscape"/>
+ *     &lt;enumeration value="Reverse Portrait"/>
+ *     &lt;enumeration value="Reverse Landscape"/>
+ *   &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ * 
+ */
+@XmlType(name = "rotationNameType")
+@XmlEnum
+public enum RotationNameType {
+
+    @XmlEnumValue("Portrait")
+    PORTRAIT("Portrait"),
+    @XmlEnumValue("Landscape")
+    LANDSCAPE("Landscape"),
+    @XmlEnumValue("Reverse Portrait")
+    REVERSE_PORTRAIT("Reverse Portrait"),
+    @XmlEnumValue("Reverse Landscape")
+    REVERSE_LANDSCAPE("Reverse Landscape");
+    private final String value;
+
+    RotationNameType(String v) {
+        value = v;
+    }
+
+    public String value() {
+        return value;
+    }
+
+    public static RotationNameType fromValue(String v) {
+        for (RotationNameType c: RotationNameType.values()) {
+            if (c.value.equals(v)) {
+                return c;
+            }
+        }
+        throw new IllegalArgumentException(v);
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationType.java
new file mode 100644 (file)
index 0000000..33fe06f
--- /dev/null
@@ -0,0 +1,153 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for rotationType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="rotationType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="lcd" type="{http://www.tizen.org/emulator/dbi}lcdType"/>
+ *         &lt;element name="imageList" type="{http://www.tizen.org/emulator/dbi}imageListType"/>
+ *         &lt;element name="keyMapList" type="{http://www.tizen.org/emulator/dbi}keyMapListType"/>
+ *       &lt;/sequence>
+ *       &lt;attribute name="name" use="required" type="{http://www.tizen.org/emulator/dbi}rotationNameType" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "rotationType", propOrder = {
+    "lcd",
+    "imageList",
+    "keyMapList"
+})
+public class RotationType {
+
+    @XmlElement(required = true)
+    protected LcdType lcd;
+    @XmlElement(required = true)
+    protected ImageListType imageList;
+    @XmlElement(required = true)
+    protected KeyMapListType keyMapList;
+    @XmlAttribute(required = true)
+    protected RotationNameType name;
+
+    /**
+     * Gets the value of the lcd property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link LcdType }
+     *     
+     */
+    public LcdType getLcd() {
+        return lcd;
+    }
+
+    /**
+     * Sets the value of the lcd property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link LcdType }
+     *     
+     */
+    public void setLcd(LcdType value) {
+        this.lcd = value;
+    }
+
+    /**
+     * Gets the value of the imageList property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link ImageListType }
+     *     
+     */
+    public ImageListType getImageList() {
+        return imageList;
+    }
+
+    /**
+     * Sets the value of the imageList property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link ImageListType }
+     *     
+     */
+    public void setImageList(ImageListType value) {
+        this.imageList = value;
+    }
+
+    /**
+     * Gets the value of the keyMapList property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link KeyMapListType }
+     *     
+     */
+    public KeyMapListType getKeyMapList() {
+        return keyMapList;
+    }
+
+    /**
+     * Sets the value of the keyMapList property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link KeyMapListType }
+     *     
+     */
+    public void setKeyMapList(KeyMapListType value) {
+        this.keyMapList = value;
+    }
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link RotationNameType }
+     *     
+     */
+    public RotationNameType getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link RotationNameType }
+     *     
+     */
+    public void setName(RotationNameType value) {
+        this.name = value;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationsType.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationsType.java
new file mode 100644 (file)
index 0000000..65d7ced
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+
+package org.tizen.emulator.skin.dbi;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for rotationsType complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="rotationsType">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="rotation" type="{http://www.tizen.org/emulator/dbi}rotationType" maxOccurs="unbounded"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "rotationsType", propOrder = {
+    "rotation"
+})
+public class RotationsType {
+
+    @XmlElement(required = true)
+    protected List<RotationType> rotation;
+
+    /**
+     * Gets the value of the rotation property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the rotation property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getRotation().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link RotationType }
+     * 
+     * 
+     */
+    public List<RotationType> getRotation() {
+        if (rotation == null) {
+            rotation = new ArrayList<RotationType>();
+        }
+        return this.rotation;
+    }
+
+}
diff --git a/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/package-info.java b/tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/package-info.java
new file mode 100644 (file)
index 0000000..0902766
--- /dev/null
@@ -0,0 +1,9 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.03.30 at 05:41:59 ì˜¤í›„ KST 
+//
+
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.tizen.org/emulator/dbi", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.tizen.emulator.skin.dbi;
diff --git a/tizen/src/skin/client/lib/swt/cocoa-macosx/src.zip b/tizen/src/skin/client/lib/swt/cocoa-macosx/src.zip
new file mode 100644 (file)
index 0000000..295729b
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/cocoa-macosx/src.zip differ
diff --git a/tizen/src/skin/client/lib/swt/cocoa-macosx/swt-debug.jar b/tizen/src/skin/client/lib/swt/cocoa-macosx/swt-debug.jar
new file mode 100644 (file)
index 0000000..07f3bbc
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/cocoa-macosx/swt-debug.jar differ
diff --git a/tizen/src/skin/client/lib/swt/cocoa-macosx/swt.jar b/tizen/src/skin/client/lib/swt/cocoa-macosx/swt.jar
new file mode 100644 (file)
index 0000000..54bf3a8
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/cocoa-macosx/swt.jar differ
diff --git a/tizen/src/skin/client/lib/swt/gtk-linux/src.zip b/tizen/src/skin/client/lib/swt/gtk-linux/src.zip
new file mode 100644 (file)
index 0000000..c7e0731
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/gtk-linux/src.zip differ
diff --git a/tizen/src/skin/client/lib/swt/gtk-linux/swt-debug.jar b/tizen/src/skin/client/lib/swt/gtk-linux/swt-debug.jar
new file mode 100644 (file)
index 0000000..78a1519
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/gtk-linux/swt-debug.jar differ
diff --git a/tizen/src/skin/client/lib/swt/gtk-linux/swt.jar b/tizen/src/skin/client/lib/swt/gtk-linux/swt.jar
new file mode 100644 (file)
index 0000000..2d78756
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/gtk-linux/swt.jar differ
diff --git a/tizen/src/skin/client/lib/swt/win32-win32/src.zip b/tizen/src/skin/client/lib/swt/win32-win32/src.zip
new file mode 100644 (file)
index 0000000..78fab0b
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/win32-win32/src.zip differ
diff --git a/tizen/src/skin/client/lib/swt/win32-win32/swt-debug.jar b/tizen/src/skin/client/lib/swt/win32-win32/swt-debug.jar
new file mode 100644 (file)
index 0000000..f52cf53
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/win32-win32/swt-debug.jar differ
diff --git a/tizen/src/skin/client/lib/swt/win32-win32/swt.jar b/tizen/src/skin/client/lib/swt/win32-win32/swt.jar
new file mode 100644 (file)
index 0000000..237d388
Binary files /dev/null and b/tizen/src/skin/client/lib/swt/win32-win32/swt.jar differ
diff --git a/tizen/src/skin/client/resource/icons/Emulator.ico b/tizen/src/skin/client/resource/icons/Emulator.ico
new file mode 100644 (file)
index 0000000..3c34a50
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/Emulator.ico differ
diff --git a/tizen/src/skin/client/resource/icons/Emulator_20x20.png b/tizen/src/skin/client/resource/icons/Emulator_20x20.png
new file mode 100644 (file)
index 0000000..415dd28
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/Emulator_20x20.png differ
diff --git a/tizen/src/skin/client/resource/icons/about.png b/tizen/src/skin/client/resource/icons/about.png
new file mode 100644 (file)
index 0000000..4f76588
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/about.png differ
diff --git a/tizen/src/skin/client/resource/icons/advanced.png b/tizen/src/skin/client/resource/icons/advanced.png
new file mode 100644 (file)
index 0000000..14cf9fa
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/advanced.png differ
diff --git a/tizen/src/skin/client/resource/icons/close.png b/tizen/src/skin/client/resource/icons/close.png
new file mode 100644 (file)
index 0000000..a1395ce
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/close.png differ
diff --git a/tizen/src/skin/client/resource/icons/copy_screenshot_dialog.png b/tizen/src/skin/client/resource/icons/copy_screenshot_dialog.png
new file mode 100644 (file)
index 0000000..a07a5f7
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/copy_screenshot_dialog.png differ
diff --git a/tizen/src/skin/client/resource/icons/detail_info.png b/tizen/src/skin/client/resource/icons/detail_info.png
new file mode 100644 (file)
index 0000000..149ffa2
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/detail_info.png differ
diff --git a/tizen/src/skin/client/resource/icons/refresh_screenshot_dialog.png b/tizen/src/skin/client/resource/icons/refresh_screenshot_dialog.png
new file mode 100644 (file)
index 0000000..e1616d9
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/refresh_screenshot_dialog.png differ
diff --git a/tizen/src/skin/client/resource/icons/rotate.png b/tizen/src/skin/client/resource/icons/rotate.png
new file mode 100644 (file)
index 0000000..b2fc00f
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/rotate.png differ
diff --git a/tizen/src/skin/client/resource/icons/save_screenshot_dialog.png b/tizen/src/skin/client/resource/icons/save_screenshot_dialog.png
new file mode 100644 (file)
index 0000000..523fe9e
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/save_screenshot_dialog.png differ
diff --git a/tizen/src/skin/client/resource/icons/scale.png b/tizen/src/skin/client/resource/icons/scale.png
new file mode 100644 (file)
index 0000000..1f3f872
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/scale.png differ
diff --git a/tizen/src/skin/client/resource/icons/screenshot.png b/tizen/src/skin/client/resource/icons/screenshot.png
new file mode 100644 (file)
index 0000000..74c8515
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/screenshot.png differ
diff --git a/tizen/src/skin/client/resource/icons/shell.png b/tizen/src/skin/client/resource/icons/shell.png
new file mode 100644 (file)
index 0000000..e89f1b1
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/shell.png differ
diff --git a/tizen/src/skin/client/resource/icons/usb_keyboard.png b/tizen/src/skin/client/resource/icons/usb_keyboard.png
new file mode 100644 (file)
index 0000000..69a87f3
Binary files /dev/null and b/tizen/src/skin/client/resource/icons/usb_keyboard.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default.dbi b/tizen/src/skin/client/skins/emul_320x480/default.dbi
new file mode 100644 (file)
index 0000000..b57c94a
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="26" top="70" width="320" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="159" top="552" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="487" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="63" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="140" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="70" top="34" width="480" height="320"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="552" top="167" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="486" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="63" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="139" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="34" top="70" width="320" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="167" top="14" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="64" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="488" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="412" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="70" top="26" width="480" height="320"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="14" top="159" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="64" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="488" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="412" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_0.png b/tizen/src/skin/client/skins/emul_320x480/default_0.png
new file mode 100644 (file)
index 0000000..3409f5f
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_0_p.png b/tizen/src/skin/client/skins/emul_320x480/default_0_p.png
new file mode 100644 (file)
index 0000000..66932f6
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_180.png b/tizen/src/skin/client/skins/emul_320x480/default_180.png
new file mode 100644 (file)
index 0000000..692ca84
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_180_p.png b/tizen/src/skin/client/skins/emul_320x480/default_180_p.png
new file mode 100644 (file)
index 0000000..c7641f3
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_L90.png b/tizen/src/skin/client/skins/emul_320x480/default_L90.png
new file mode 100644 (file)
index 0000000..3150710
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_L90_p.png b/tizen/src/skin/client/skins/emul_320x480/default_L90_p.png
new file mode 100644 (file)
index 0000000..b1b4d65
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_R90.png b/tizen/src/skin/client/skins/emul_320x480/default_R90.png
new file mode 100644 (file)
index 0000000..691bcef
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_320x480/default_R90_p.png b/tizen/src/skin/client/skins/emul_320x480/default_R90_p.png
new file mode 100644 (file)
index 0000000..021e7bd
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_320x480/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default.dbi b/tizen/src/skin/client/skins/emul_3keys_320x480/default.dbi
new file mode 100644 (file)
index 0000000..4b77adb
--- /dev/null
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="26" top="70" width="320" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="71" top="552" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="159" top="552" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="247" top="552" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="487" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="63" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="362" top="140" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="70" top="34" width="480" height="320"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="552" top="255" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="552" top="167" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="552" top="79" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="486" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="63" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="139" top="3" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="34" top="70" width="320" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="255" top="14" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="167" top="14" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="79" top="14" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="64" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="488" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="3" top="412" width="15" height="70"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="70" top="26" width="480" height="320"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="14" top="71" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="14" top="159" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="14" top="247" width="54" height="54"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="64" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="488" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="412" top="362" width="70" height="15"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_0.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_0.png
new file mode 100644 (file)
index 0000000..d97869a
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_0_p.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_0_p.png
new file mode 100644 (file)
index 0000000..2ee77fe
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_180.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_180.png
new file mode 100644 (file)
index 0000000..dcd58a5
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_180_p.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_180_p.png
new file mode 100644 (file)
index 0000000..fd36e04
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90.png
new file mode 100644 (file)
index 0000000..803dae2
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90_p.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90_p.png
new file mode 100644 (file)
index 0000000..3020249
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90.png
new file mode 100644 (file)
index 0000000..c548e13
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90_p.png b/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90_p.png
new file mode 100644 (file)
index 0000000..4e13502
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_320x480/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default.dbi b/tizen/src/skin/client/skins/emul_3keys_480x800/default.dbi
new file mode 100644 (file)
index 0000000..317d24a
--- /dev/null
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region height="800" left="35" top="86" width="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="118" top="887" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="238" top="887" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="360" top="887" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="819" width="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="81" width="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="167" width="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region height="480" left="86" top="46" width="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="887" top="369" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="887" top="249" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="887" top="127" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="818" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="80" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="165" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="46" top="89" width="480" height="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="368" top="14" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="249" top="14" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="126" top="14" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="84" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="821" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="735" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="90" top="35" width="800" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="15" top="118" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="15" top="239" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="15" top="360" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="84" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="822" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="735" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_0.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_0.png
new file mode 100644 (file)
index 0000000..034fb0d
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_0_p.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_0_p.png
new file mode 100644 (file)
index 0000000..195fa24
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_180.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_180.png
new file mode 100644 (file)
index 0000000..b70abd9
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_180_p.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_180_p.png
new file mode 100644 (file)
index 0000000..a92a0c7
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90.png
new file mode 100644 (file)
index 0000000..178e55b
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90_p.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90_p.png
new file mode 100644 (file)
index 0000000..8f4d2f8
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90.png
new file mode 100644 (file)
index 0000000..b9261b5
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90_p.png b/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90_p.png
new file mode 100644 (file)
index 0000000..5c060a4
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_480x800/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default.dbi b/tizen/src/skin/client/skins/emul_3keys_600x1024/default.dbi
new file mode 100644 (file)
index 0000000..8895188
--- /dev/null
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="52" top="109" width="600" height="1024" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="151" top="1139" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="310" top="1139" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="471" top="1139" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="1055" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="101" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="194" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="109" top="62" width="1024" height="600" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="1138" top="480" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1138" top="321" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1138" top="161" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1054" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="99" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="194" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="62" top="113" width="600" height="1024" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="479" top="24" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="320" top="24" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="159" top="24" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="106" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="1059" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="964" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="113" top="52" width="1024" height="600" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="23" top="148" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="23" top="310" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="23" top="470" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="105" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1058" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="965" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0.png
new file mode 100644 (file)
index 0000000..31a6fee
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0_p.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0_p.png
new file mode 100644 (file)
index 0000000..4e32200
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180.png
new file mode 100644 (file)
index 0000000..cd99139
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180_p.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180_p.png
new file mode 100644 (file)
index 0000000..30f22d4
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90.png
new file mode 100644 (file)
index 0000000..c438dd3
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90_p.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90_p.png
new file mode 100644 (file)
index 0000000..665d858
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90.png
new file mode 100644 (file)
index 0000000..9c786d9
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90_p.png b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90_p.png
new file mode 100644 (file)
index 0000000..3f7d9f7
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default.dbi b/tizen/src/skin/client/skins/emul_3keys_720x1280/default.dbi
new file mode 100644 (file)
index 0000000..b2ee97f
--- /dev/null
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="67" top="116" width="720" height="1280"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="210" top="1401" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="390" top="1401" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="570" top="1401" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="1309" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="108" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="219" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="116" top="78" width="1280" height="720"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="1400" top="570" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1400" top="392" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1400" top="210" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1308" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="108" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="217" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="78" top="117" width="720" height="1280"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="570" top="30" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="390" top="30" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="210" top="30" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="110" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="1310" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="1200" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="117" top="67" width="1280" height="720"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="28" top="209" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>100</keyCode>
+                        <keyName>SEND</keyName>
+                    </eventInfo>
+                    <tooltip>Send</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="28" top="391" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="28" top="568" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>102</keyCode>
+                        <keyName>END</keyName>
+                    </eventInfo>
+                    <tooltip>End</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="109" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1309" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1199" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0.png
new file mode 100644 (file)
index 0000000..b0d49cf
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0_p.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0_p.png
new file mode 100644 (file)
index 0000000..1d3058a
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180.png
new file mode 100644 (file)
index 0000000..8b59e00
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180_p.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180_p.png
new file mode 100644 (file)
index 0000000..2850db2
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90.png
new file mode 100644 (file)
index 0000000..15df50d
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90_p.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90_p.png
new file mode 100644 (file)
index 0000000..35d3c97
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90.png
new file mode 100644 (file)
index 0000000..f886480
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90_p.png b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90_p.png
new file mode 100644 (file)
index 0000000..d582bfa
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default.dbi b/tizen/src/skin/client/skins/emul_480x800/default.dbi
new file mode 100644 (file)
index 0000000..5519f56
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region height="800" left="35" top="86" width="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region height="74" left="238" top="887" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="819" width="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="81" width="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="74" left="541" top="167" width="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region height="480" left="86" top="46" width="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region height="74" left="887" top="249" width="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="818" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="80" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region height="20" left="165" top="2" width="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="46" top="89" width="480" height="800"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="249" top="14" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="84" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="821" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="735" width="20" height="74"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="90" top="35" width="800" height="480"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="15" top="239" width="74" height="74"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="84" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="822" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="735" top="539" width="74" height="20"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_0.png b/tizen/src/skin/client/skins/emul_480x800/default_0.png
new file mode 100644 (file)
index 0000000..6d33f38
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_0_p.png b/tizen/src/skin/client/skins/emul_480x800/default_0_p.png
new file mode 100644 (file)
index 0000000..2f1da59
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_180.png b/tizen/src/skin/client/skins/emul_480x800/default_180.png
new file mode 100644 (file)
index 0000000..5e8d276
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_180_p.png b/tizen/src/skin/client/skins/emul_480x800/default_180_p.png
new file mode 100644 (file)
index 0000000..8b50699
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_L90.png b/tizen/src/skin/client/skins/emul_480x800/default_L90.png
new file mode 100644 (file)
index 0000000..76d008f
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_L90_p.png b/tizen/src/skin/client/skins/emul_480x800/default_L90_p.png
new file mode 100644 (file)
index 0000000..ca23955
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_R90.png b/tizen/src/skin/client/skins/emul_480x800/default_R90.png
new file mode 100644 (file)
index 0000000..7be72f7
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_480x800/default_R90_p.png b/tizen/src/skin/client/skins/emul_480x800/default_R90_p.png
new file mode 100644 (file)
index 0000000..98de699
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_480x800/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default.dbi b/tizen/src/skin/client/skins/emul_600x1024/default.dbi
new file mode 100644 (file)
index 0000000..42b5d6f
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="52" top="109" width="600" height="1024" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="310" top="1139" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="1055" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="101" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="690" top="194" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="109" top="62" width="1024" height="600" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="1138" top="321" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1054" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="99" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="194" top="1" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="62" top="113" width="600" height="1024" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="320" top="24" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="106" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="1059" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1" top="964" width="24" height="88"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="113" top="52" width="1024" height="600" scale="1"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="23" top="310" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="105" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1058" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="965" top="690" width="88" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_0.png b/tizen/src/skin/client/skins/emul_600x1024/default_0.png
new file mode 100644 (file)
index 0000000..bf63d2f
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_0_p.png b/tizen/src/skin/client/skins/emul_600x1024/default_0_p.png
new file mode 100644 (file)
index 0000000..7e16590
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_180.png b/tizen/src/skin/client/skins/emul_600x1024/default_180.png
new file mode 100644 (file)
index 0000000..198d4e9
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_180_p.png b/tizen/src/skin/client/skins/emul_600x1024/default_180_p.png
new file mode 100644 (file)
index 0000000..c77beaf
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_L90.png b/tizen/src/skin/client/skins/emul_600x1024/default_L90.png
new file mode 100644 (file)
index 0000000..a3a3d40
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_L90_p.png b/tizen/src/skin/client/skins/emul_600x1024/default_L90_p.png
new file mode 100644 (file)
index 0000000..3a110eb
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_R90.png b/tizen/src/skin/client/skins/emul_600x1024/default_R90.png
new file mode 100644 (file)
index 0000000..2b94d21
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_600x1024/default_R90_p.png b/tizen/src/skin/client/skins/emul_600x1024/default_R90_p.png
new file mode 100644 (file)
index 0000000..ae3b069
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_600x1024/default_R90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default.dbi b/tizen/src/skin/client/skins/emul_720x1280/default.dbi
new file mode 100644 (file)
index 0000000..3f4fbb6
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EmulatorUI xmlns="http://www.tizen.org/emulator/dbi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <rotations>
+        <rotation name="Portrait">
+            <lcd id="0">
+                <region left="67" top="116" width="720" height="1280"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_0.png</mainImage>
+                <keyPressedImage>default_0_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="390" top="1401" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="1309" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="108" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="841" top="219" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Landscape">
+            <lcd id="0">
+                <region left="116" top="78" width="1280" height="720"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_L90.png</mainImage>
+                <keyPressedImage>default_L90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="1400" top="392" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1308" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="108" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="217" top="2" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Portrait">
+            <lcd id="0">
+                <region left="78" top="117" width="720" height="1280"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_180.png</mainImage>
+                <keyPressedImage>default_180_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="390" top="30" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="110" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="1310" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="2" top="1200" width="24" height="96"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+        <rotation name="Reverse Landscape">
+            <lcd id="0">
+                <region left="117" top="67" width="1280" height="720"/>
+            </lcd>
+            <imageList>
+                <mainImage>default_R90.png</mainImage>
+                <keyPressedImage>default_R90_p.png</keyPressedImage>
+            </imageList>
+            <keyMapList>
+                <keyMap>
+                    <region left="28" top="391" width="84" height="84"/>
+                    <eventInfo>
+                        <keyCode>101</keyCode>
+                        <keyName>HOME</keyName>
+                    </eventInfo>
+                    <tooltip>Home</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="109" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>103</keyCode>
+                        <keyName>POWER</keyName>
+                    </eventInfo>
+                    <tooltip>Power</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1309" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>115</keyCode>
+                        <keyName>VOLUME_UP</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-up</tooltip>
+                </keyMap>
+                <keyMap>
+                    <region left="1199" top="841" width="96" height="24"/>
+                    <eventInfo>
+                        <keyCode>114</keyCode>
+                        <keyName>VOLUME_DOWN</keyName>
+                    </eventInfo>
+                    <tooltip>Volume-down</tooltip>
+                </keyMap>
+            </keyMapList>
+        </rotation>
+    </rotations>
+    <colors>
+        <hoverColor B="255" G="255" R="255" />
+    </colors>
+</EmulatorUI>
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_0.png b/tizen/src/skin/client/skins/emul_720x1280/default_0.png
new file mode 100644 (file)
index 0000000..b1fd216
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_0.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_0_p.png b/tizen/src/skin/client/skins/emul_720x1280/default_0_p.png
new file mode 100644 (file)
index 0000000..b3ce60b
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_0_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_180.png b/tizen/src/skin/client/skins/emul_720x1280/default_180.png
new file mode 100644 (file)
index 0000000..def7028
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_180.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_180_p.png b/tizen/src/skin/client/skins/emul_720x1280/default_180_p.png
new file mode 100644 (file)
index 0000000..4b6c5a1
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_180_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_L90.png b/tizen/src/skin/client/skins/emul_720x1280/default_L90.png
new file mode 100644 (file)
index 0000000..63c2394
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_L90.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_L90_p.png b/tizen/src/skin/client/skins/emul_720x1280/default_L90_p.png
new file mode 100644 (file)
index 0000000..5ec17ed
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_L90_p.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_R90.png b/tizen/src/skin/client/skins/emul_720x1280/default_R90.png
new file mode 100644 (file)
index 0000000..45e869e
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_R90.png differ
diff --git a/tizen/src/skin/client/skins/emul_720x1280/default_R90_p.png b/tizen/src/skin/client/skins/emul_720x1280/default_R90_p.png
new file mode 100644 (file)
index 0000000..5d2e47d
Binary files /dev/null and b/tizen/src/skin/client/skins/emul_720x1280/default_R90_p.png differ
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorShutdownhook.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorShutdownhook.java
new file mode 100644 (file)
index 0000000..1a3a6f8
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin;
+
+import java.util.logging.Logger;
+
+import org.tizen.emulator.skin.comm.ICommunicator;
+import org.tizen.emulator.skin.log.SkinLogger;
+
+/**
+ * 
+ *
+ */
+public class EmulatorShutdownhook extends Thread {
+
+       private Logger logger = SkinLogger.getSkinLogger( EmulatorShutdownhook.class ).getLogger();
+       private ICommunicator communicator;
+       
+       public EmulatorShutdownhook( ICommunicator communicator ) {
+               this.communicator = communicator;
+       }
+
+       @Override
+       public void run() {
+               logger.info( " EmulatorShutdownhook run by a signal." );
+               communicator.terminate();
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkin.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkin.java
new file mode 100644 (file)
index 0000000..ce8b3c0
--- /dev/null
@@ -0,0 +1,1626 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.tizen.emulator.skin.comm.ICommunicator.KeyEventType;
+import org.tizen.emulator.skin.comm.ICommunicator.MouseEventType;
+import org.tizen.emulator.skin.comm.ICommunicator.Scale;
+import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
+import org.tizen.emulator.skin.comm.sock.data.BooleanData;
+import org.tizen.emulator.skin.comm.sock.data.KeyEventData;
+import org.tizen.emulator.skin.comm.sock.data.LcdStateData;
+import org.tizen.emulator.skin.comm.sock.data.MouseEventData;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
+import org.tizen.emulator.skin.dbi.ColorsType;
+import org.tizen.emulator.skin.dbi.RgbType;
+import org.tizen.emulator.skin.dbi.RotationType;
+import org.tizen.emulator.skin.dialog.AboutDialog;
+import org.tizen.emulator.skin.dialog.DetailInfoDialog;
+import org.tizen.emulator.skin.exception.ScreenShotException;
+import org.tizen.emulator.skin.image.ImageRegistry;
+import org.tizen.emulator.skin.image.ImageRegistry.IconName;
+import org.tizen.emulator.skin.image.ImageRegistry.ImageType;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.screenshot.ScreenShotDialog;
+import org.tizen.emulator.skin.util.SkinRegion;
+import org.tizen.emulator.skin.util.SkinRotation;
+import org.tizen.emulator.skin.util.SkinUtil;
+
+/**
+ * 
+ *
+ */
+public class EmulatorSkin {
+
+       public class SkinReopenPolicy {
+
+               private EmulatorSkin reopenSkin;
+               private boolean reopen;
+
+               private SkinReopenPolicy( EmulatorSkin reopenSkin, boolean reopen ) {
+                       this.reopenSkin = reopenSkin;
+                       this.reopen = reopen;
+               }
+
+               public EmulatorSkin getReopenSkin() {
+                       return reopenSkin;
+               }
+
+               public boolean isReopen() {
+                       return reopen;
+               }
+
+       }
+
+       public static final String GTK_OS_CLASS = "org.eclipse.swt.internal.gtk.OS";
+       public static final String WIN32_OS_CLASS = "org.eclipse.swt.internal.win32.OS";
+       
+       private Logger logger = SkinLogger.getSkinLogger( EmulatorSkin.class ).getLogger();
+
+       private EmulatorConfig config;
+       private Shell shell;
+       private ImageRegistry imageRegistry;
+       private Canvas lcdCanvas;
+       private Image currentImage;
+       private Image currentKeyPressedImage;
+       private Color hoverColor;
+       private boolean isDefaultHoverColor;
+
+       private int currentScale;
+       private short currentRotationId;
+       private int currentAngle;
+       private int currentLcdWidth;
+       private int currentLcdHeight;
+       private SkinRegion currentHoverRegion;
+
+       private int pressedMouseX;
+       private int pressedMouseY;
+       private boolean isMousePressed;
+       private boolean isDragStartedInLCD;
+       private boolean isHoverState;
+       private boolean isShutdownRequested;
+       private boolean isAboutToReopen;
+       private boolean isOnTop;
+       private boolean isScreenShotOpened;
+       private boolean isOnUsbKbd;
+
+       private ScreenShotDialog screenShotDialog;
+
+       private SocketCommunicator communicator;
+       private int windowHandleId;
+
+       private Listener shellCloseListener;
+       private PaintListener shellPaintListener;
+       private MouseTrackListener shellMouseTrackListener;
+       private MouseMoveListener shellMouseMoveListener;
+       private MouseListener shellMouseListener;
+
+       //private DragDetectListener canvasDragDetectListener;
+       private MouseMoveListener canvasMouseMoveListener;
+       private MouseListener canvasMouseListener;
+       private KeyListener canvasKeyListener;
+       private MenuDetectListener canvasMenuDetectListener;
+
+       private EmulatorSkin reopenSkin;
+       
+       protected EmulatorSkin( EmulatorConfig config, boolean isOnTop ) {
+               this.config = config;
+               this.isDefaultHoverColor = true;
+               this.isOnTop = isOnTop;
+               
+               int style = SWT.NO_TRIM;
+               this.shell = new Shell( Display.getDefault(), style );
+
+       }
+
+       public void setCommunicator( SocketCommunicator communicator ) {
+               this.communicator = communicator;
+       }
+
+       public int compose() {
+
+               this.lcdCanvas = new Canvas( shell, SWT.EMBEDDED );
+
+               int x = config.getSkinPropertyInt( SkinPropertiesConstants.WINDOW_X, EmulatorConfig.DEFAULT_WINDOW_X );
+               int y = config.getSkinPropertyInt( SkinPropertiesConstants.WINDOW_Y, EmulatorConfig.DEFAULT_WINDOW_Y );
+               int lcdWidth = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH );
+               int lcdHeight = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT );
+               int scale = SkinUtil.getValidScale( config );
+//             int rotationId = config.getPropertyShort( PropertiesConstants.WINDOW_ROTATION,
+//                             EmulatorConfig.DEFAULT_WINDOW_ROTATION );
+               // has to be portrait mode at first booting time
+               short rotationId = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
+               
+               composeInternal( lcdCanvas, x, y, lcdWidth, lcdHeight, scale, rotationId, false );
+
+               // sdl uses this handle id.
+               windowHandleId = getWindowHandleId();
+
+               return windowHandleId;
+
+       }
+
+       private void composeInternal( Canvas lcdCanvas, int x, int y, int lcdWidth, int lcdHeight, int scale,
+                       short rotationId, boolean isOnUsbKbd ) {
+
+               lcdCanvas.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_BLACK ) );
+
+               imageRegistry = ImageRegistry.getInstance();
+
+               shell.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_BLACK ) );
+
+               shell.setLocation( x, y );
+
+               String emulatorName = SkinUtil.makeEmulatorName( config );
+               shell.setText( emulatorName );
+
+               if ( SkinUtil.isWindowsPlatform() ) {
+                       shell.setImage( imageRegistry.getIcon( IconName.EMULATOR_TITLE_ICO ) );
+               } else {
+                       shell.setImage( imageRegistry.getIcon( IconName.EMULATOR_TITLE ) );
+               }
+
+               arrangeSkin( lcdWidth, lcdHeight, scale, rotationId );
+
+               this.isOnUsbKbd = isOnUsbKbd;
+               
+               if ( null == currentImage ) {
+                       logger.severe( "Fail to load initial skin image file. Kill this skin process!!!" );
+                       SkinUtil.openMessage( shell, null, "Fail to load Skin image file.", SWT.ICON_ERROR, config );
+                       System.exit( -1 );
+               }
+
+               seteHoverColor();
+
+               setMenu();
+
+       }
+
+       private void setMenu() {
+
+               Menu contextMenu = new Menu( shell );
+
+               addMenuItems( shell, contextMenu );
+
+               addShellListener( shell );
+               addCanvasListener( shell, lcdCanvas );
+
+               shell.setMenu( contextMenu );
+
+       }
+
+//     private void readyToReopen( EmulatorSkin sourceSkin, boolean isOnTop ) {
+//
+//             logger.info( "Start Changing AlwaysOnTop status" );
+//
+//             sourceSkin.reopenSkin = new EmulatorSkin( sourceSkin.config, isOnTop );
+//
+//             sourceSkin.reopenSkin.lcdCanvas = sourceSkin.lcdCanvas;
+//             Point previousLocation = sourceSkin.shell.getLocation();
+//
+//             sourceSkin.reopenSkin.composeInternal( sourceSkin.lcdCanvas, previousLocation.x, previousLocation.y,
+//                             sourceSkin.currentLcdWidth, sourceSkin.currentLcdHeight, sourceSkin.currentScale,
+//                             sourceSkin.currentRotationId, sourceSkin.isOnUsbKbd );
+//
+//             sourceSkin.reopenSkin.windowHandleId = sourceSkin.windowHandleId;
+//
+//             sourceSkin.reopenSkin.communicator = sourceSkin.communicator;
+//             sourceSkin.reopenSkin.communicator.resetSkin( reopenSkin );
+//
+//             sourceSkin.isAboutToReopen = true;
+//             sourceSkin.isShutdownRequested = true;
+//
+//             if ( sourceSkin.isScreenShotOpened && ( null != sourceSkin.screenShotDialog ) ) {
+//                     sourceSkin.screenShotDialog.setReserveImage( true );
+//                     sourceSkin.screenShotDialog.setEmulatorSkin( reopenSkin );
+//                     reopenSkin.isScreenShotOpened = true;
+//                     reopenSkin.screenShotDialog = sourceSkin.screenShotDialog;
+//                     // see open() method to know next logic for screenshot dialog.
+//             }
+//
+//             sourceSkin.lcdCanvas.setParent( reopenSkin.shell );
+//             sourceSkin.shell.close();
+//
+//     }
+
+       private int getWindowHandleId() {
+
+               int windowHandleId = 0;
+
+               if ( SkinUtil.isLinuxPlatform() ) {
+
+                       try {
+                               Field field = lcdCanvas.getClass().getField( "embeddedHandle" );
+                               windowHandleId = field.getInt( lcdCanvas );
+                               logger.info( "lcdCanvas.embeddedHandle:" + windowHandleId );
+                       } catch ( IllegalArgumentException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               shutdown();
+                       } catch ( IllegalAccessException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               shutdown();
+                       } catch ( SecurityException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               shutdown();
+                       } catch ( NoSuchFieldException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               shutdown();
+                       }
+
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+
+                       logger.info( "lcdCanvas.handle:" + lcdCanvas.handle );
+                       windowHandleId = lcdCanvas.handle;
+
+               } else if ( SkinUtil.isMacPlatform() ) {
+
+                       // TODO
+
+               } else {
+                       logger.severe( "Not Supported OS platform:" + SWT.getPlatform() );
+                       System.exit( -1 );
+               }
+
+               return windowHandleId;
+
+       }
+
+       private void seteHoverColor() {
+
+               ColorsType colors = config.getDbiContents().getColors();
+               if ( null != colors ) {
+                       RgbType hoverRgb = colors.getHoverColor();
+                       if ( null != hoverRgb ) {
+                               Long r = hoverRgb.getR();
+                               Long g = hoverRgb.getG();
+                               Long b = hoverRgb.getB();
+                               if ( null != r && null != g && null != b ) {
+                                       hoverColor = new Color( shell.getDisplay(), new RGB( r.intValue(), g.intValue(), b.intValue() ) );
+                                       isDefaultHoverColor = false;
+                               }
+                       }
+               }
+
+               if ( isDefaultHoverColor ) {
+                       hoverColor = shell.getDisplay().getSystemColor( SWT.COLOR_WHITE );
+               }
+
+       }
+
+       public SkinReopenPolicy open() {
+
+               if ( null == this.communicator ) {
+                       logger.severe( "communicator is null." );
+                       return null;
+               }
+
+               Display display = this.shell.getDisplay();
+
+               this.shell.open();
+
+               // logic only for reopen case ///////
+               if ( isScreenShotOpened && ( null != screenShotDialog ) ) {
+                       try {
+                               screenShotDialog.setReserveImage( false );
+                               screenShotDialog.open();
+                       } finally {
+                               isScreenShotOpened = false;
+                       }
+               }
+               // ///////////////////////////////////
+
+               while ( !shell.isDisposed() ) {
+                       if ( !display.readAndDispatch() ) {
+                               display.sleep();
+                       }
+               }
+
+               return new SkinReopenPolicy( reopenSkin, isAboutToReopen );
+
+       }
+
+       private void arrangeSkin( int lcdWidth, int lcdHeight, int scale, short rotationId ) {
+
+               this.currentLcdWidth = lcdWidth;
+               this.currentLcdHeight = lcdHeight;
+               this.currentScale = scale;
+               this.currentRotationId = rotationId;
+               this.currentAngle = SkinRotation.getAngle( rotationId );
+
+               if ( null != currentImage ) {
+                       currentImage.dispose();
+               }
+               if ( null != currentKeyPressedImage ) {
+                       currentKeyPressedImage.dispose();
+               }
+
+               shell.redraw();
+
+               currentImage = SkinUtil.createScaledImage( imageRegistry, shell, rotationId, scale, ImageType.IMG_TYPE_MAIN );
+               currentKeyPressedImage = SkinUtil.createScaledImage( imageRegistry, shell, rotationId, scale,
+                               ImageType.IMG_TYPE_PRESSED );
+
+               SkinUtil.trimShell( shell, currentImage );
+               SkinUtil.adjustLcdGeometry( lcdCanvas, scale, rotationId );
+
+               if( null != currentImage ) {
+                       ImageData imageData = currentImage.getImageData();
+                       shell.setMinimumSize( imageData.width, imageData.height );
+                       shell.setSize( imageData.width, imageData.height );
+               }
+
+       }
+
+       private void addShellListener( final Shell shell ) {
+
+               shellCloseListener = new Listener() {
+                       @Override
+                       public void handleEvent( Event event ) {
+
+                               if ( isShutdownRequested ) {
+
+                                       removeShellListeners();
+                                       removeCanvasListeners();
+
+                                       if ( !isAboutToReopen ) {
+
+                                               if ( isScreenShotOpened && ( null != screenShotDialog ) ) {
+                                                       Shell scShell = screenShotDialog.getShell();
+                                                       if ( !scShell.isDisposed() ) {
+                                                               scShell.close();
+                                                       }
+                                               }
+
+                                               // save config only for emulator close
+                                               config.setSkinProperty( SkinPropertiesConstants.WINDOW_X, shell.getLocation().x );
+                                               config.setSkinProperty( SkinPropertiesConstants.WINDOW_Y, shell.getLocation().y );
+                                               config.setSkinProperty( SkinPropertiesConstants.WINDOW_SCALE, currentScale );
+                                               config.setSkinProperty( SkinPropertiesConstants.WINDOW_ROTATION, currentRotationId );
+                                               config.setSkinProperty( SkinPropertiesConstants.WINDOW_ONTOP, Boolean.toString( isOnTop ) );
+                                               config.saveSkinProperties();
+
+                                       }
+
+                                       if ( null != currentImage ) {
+                                               currentImage.dispose();
+                                       }
+                                       if ( null != currentKeyPressedImage ) {
+                                               currentKeyPressedImage.dispose();
+                                       }
+
+                                       if ( !isDefaultHoverColor ) {
+                                               hoverColor.dispose();
+                                       }
+
+                               } else {
+
+                                       // Skin have to be alive until receiving shutdown request from qemu.
+                                       event.doit = false;
+                                       if ( null != communicator ) {
+                                               communicator.sendToQEMU( SendCommand.CLOSE, null );
+                                       }
+
+                               }
+
+                       }
+               };
+
+               shell.addListener( SWT.Close, shellCloseListener );
+
+               shellPaintListener = new PaintListener() {
+
+                       @Override
+                       public void paintControl( final PaintEvent e ) {
+
+                               // general shell does not support native transparency, so draw image with GC.
+                               if ( null != currentImage ) {
+                                       e.gc.drawImage( currentImage, 0, 0 );
+                               }
+
+                       }
+               };
+
+               shell.addPaintListener( shellPaintListener );
+
+               shellMouseTrackListener = new MouseTrackAdapter() {
+                       @Override
+                       public void mouseExit( MouseEvent e ) {
+                               // MouseMoveListener of shell does not receive event only with MouseMoveListener
+                               // in case that : hover hardkey -> mouse move into LCD area
+                               if ( isHoverState ) {
+                                       if ( currentHoverRegion.width == 0 && currentHoverRegion.height == 0 ) {
+                                               shell.redraw();
+                                       } else {
+                                               shell.redraw( currentHoverRegion.x, currentHoverRegion.y, currentHoverRegion.width + 1,
+                                                               currentHoverRegion.height + 1, false );
+                                       }
+                                       shell.setToolTipText(null);
+
+                                       isHoverState = false;
+                                       currentHoverRegion.width = currentHoverRegion.height = 0;
+                               }
+                       }
+
+               };
+
+               shell.addMouseTrackListener( shellMouseTrackListener );
+
+               shellMouseMoveListener = new MouseMoveListener() {
+
+                       @Override
+                       public void mouseMove( MouseEvent e ) {
+                               if ( EmulatorSkin.this.isMousePressed ) {
+                                       if ( 0 == e.button ) { // left button
+
+                                               SkinRegion hardkeyRegion = SkinUtil.getHardKeyArea( e.x, e.y, currentRotationId, currentScale );
+
+                                               if ( null == hardkeyRegion ) {
+                                                       Point previouseLocation = shell.getLocation();
+                                                       int x = previouseLocation.x + ( e.x - EmulatorSkin.this.pressedMouseX );
+                                                       int y = previouseLocation.y + ( e.y - EmulatorSkin.this.pressedMouseY );
+
+                                                       shell.setLocation( x, y );
+                                               }
+
+                                       }
+                               } else {
+
+                                       SkinRegion region = SkinUtil.getHardKeyArea( e.x, e.y, currentRotationId, currentScale );
+
+                                       if ( null == region ) {
+                                               if ( isHoverState ) {
+                                                       if ( currentHoverRegion.width == 0 && currentHoverRegion.height == 0 ) {
+                                                               shell.redraw();
+                                                       } else {
+                                                               shell.redraw( currentHoverRegion.x, currentHoverRegion.y, currentHoverRegion.width + 1,
+                                                                               currentHoverRegion.height + 1, false );
+                                                       }
+                                                       shell.setToolTipText(null);
+
+                                                       isHoverState = false;
+                                                       currentHoverRegion.width = currentHoverRegion.height = 0;
+                                               }
+                                       } else {
+                                               if (isHoverState == false) {
+                                                       shell.setToolTipText(SkinUtil.getHardKeyToolTip(e.x, e.y, currentRotationId, currentScale));
+                                               }
+
+                                               isHoverState = true;
+                                               GC gc = new GC( shell );
+                                               gc.setLineWidth( 1 );
+                                               gc.setForeground( hoverColor );
+                                               gc.drawRectangle( region.x, region.y, region.width, region.height );
+                                               currentHoverRegion = region;
+                                               gc.dispose();
+                                       }
+
+                               }
+
+                       }
+               };
+
+               shell.addMouseMoveListener( shellMouseMoveListener );
+
+               shellMouseListener = new MouseListener() {
+
+                       @Override
+                       public void mouseUp( MouseEvent e ) {
+                               if ( 1 == e.button ) { // left button
+                                       logger.info( "mouseUp in Skin" );
+                                       EmulatorSkin.this.pressedMouseX = 0;
+                                       EmulatorSkin.this.pressedMouseY = 0;
+                                       EmulatorSkin.this.isMousePressed = false;
+
+                                       int keyCode = SkinUtil.getHardKeyCode( e.x, e.y, currentRotationId, currentScale );
+
+                                       if ( SkinUtil.UNKNOWN_KEYCODE != keyCode ) {
+                                               
+                                               // null check : prevent from mouse up without a hover (ex. doing always on top in hardkey area)
+                                               if( null != currentHoverRegion ) {
+                                                       if ( currentHoverRegion.width == 0 && currentHoverRegion.height == 0 ) {
+                                                               shell.redraw();
+                                                       } else {
+                                                               shell.redraw( currentHoverRegion.x, currentHoverRegion.y, currentHoverRegion.width + 1,
+                                                                               currentHoverRegion.height + 1, false );
+                                                       }
+                                               }
+                                               
+                                               KeyEventData keyEventData = new KeyEventData( KeyEventType.RELEASED.value(), keyCode, 0 );
+                                               communicator.sendToQEMU( SendCommand.SEND_HARD_KEY_EVENT, keyEventData );
+                                       }
+
+                               }
+                       }
+
+                       @Override
+                       public void mouseDown( MouseEvent e ) {
+                               if ( 1 == e.button ) { // left button
+                                       logger.info( "mouseDown in Skin" );
+                                       EmulatorSkin.this.pressedMouseX = e.x;
+                                       EmulatorSkin.this.pressedMouseY = e.y;
+
+                                       EmulatorSkin.this.isMousePressed = true;
+
+                                       int keyCode = SkinUtil.getHardKeyCode( e.x, e.y, currentRotationId, currentScale );
+
+                                       if ( SkinUtil.UNKNOWN_KEYCODE != keyCode ) {
+                                               // draw the button region as the cropped keyPressed image area
+                                               SkinRegion region = SkinUtil.getHardKeyArea( e.x, e.y, currentRotationId, currentScale );
+
+                                               if ( null != currentKeyPressedImage ) {
+                                                       GC gc = new GC( shell );
+                                                       gc.drawImage( currentKeyPressedImage, region.x + 1, region.y + 1, region.width - 1,
+                                                                       region.height - 1, // src
+                                                                       region.x + 1, region.y + 1, region.width - 1, region.height - 1 ); // dst
+                                                       gc.dispose();
+                                               }
+
+                                               KeyEventData keyEventData = new KeyEventData( KeyEventType.PRESSED.value(), keyCode, 0 );
+                                               communicator.sendToQEMU( SendCommand.SEND_HARD_KEY_EVENT, keyEventData );
+                                       }
+                               }
+                       }
+
+                       @Override
+                       public void mouseDoubleClick( MouseEvent e ) {
+                       }
+               };
+
+               shell.addMouseListener( shellMouseListener );
+
+       }
+
+       private void removeShellListeners() {
+
+               if ( null != shellCloseListener ) {
+                       shell.removeListener( SWT.Close, shellCloseListener );
+               }
+               if ( null != shellPaintListener ) {
+                       shell.removePaintListener( shellPaintListener );
+               }
+               if ( null != shellMouseTrackListener ) {
+                       shell.removeMouseTrackListener( shellMouseTrackListener );
+               }
+               if ( null != shellMouseMoveListener ) {
+                       shell.removeMouseMoveListener( shellMouseMoveListener );
+               }
+               if ( null != shellMouseListener ) {
+                       shell.removeMouseListener( shellMouseListener );
+               }
+
+       }
+
+       private void addCanvasListener( final Shell shell, final Canvas canvas ) {
+
+               canvasMenuDetectListener = new MenuDetectListener() {
+                       @Override
+                       public void menuDetected( MenuDetectEvent e ) {
+                               Menu menu = shell.getMenu();
+                               lcdCanvas.setMenu( menu );
+                               menu.setVisible( true );
+                               e.doit = false;
+                       }
+               };
+
+               // remove 'input method' menu item ( avoid bug )
+               canvas.addMenuDetectListener( canvasMenuDetectListener );
+
+               /*canvasDragDetectListener = new DragDetectListener() {
+
+                       @Override
+                       public void dragDetected( DragDetectEvent e ) {
+                               if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( "dragDetected e.button:" + e.button );
+                               }
+                               if ( 1 == e.button && // left button
+                                               e.x > 0 && e.x < canvas.getSize().x && e.y > 0 && e.y < canvas.getSize().y ) {
+
+                                       if ( logger.isLoggable( Level.FINE ) ) {
+                                               logger.fine( "dragDetected in LCD" );
+                                       }
+                                       EmulatorSkin.this.isDragStartedInLCD = true;
+
+                               }
+                       }
+               };
+
+               canvas.addDragDetectListener( canvasDragDetectListener );*/
+
+               canvasMouseMoveListener = new MouseMoveListener() {
+
+                       @Override
+                       public void mouseMove( MouseEvent e ) {
+                               if ( true == EmulatorSkin.this.isDragStartedInLCD ) {
+                                       int eventType = MouseEventType.DRAG.value();
+                                       Point canvasSize = canvas.getSize();
+
+                                       if ( e.x <= 0 ) {
+                                               e.x = 1;
+                                               eventType = MouseEventType.UP.value();
+                                               EmulatorSkin.this.isDragStartedInLCD = false;
+                                       } else if ( e.x >= canvasSize.x ) {
+                                               e.x = canvasSize.x - 1;
+                                               eventType = MouseEventType.UP.value();
+                                               EmulatorSkin.this.isDragStartedInLCD = false;
+                                       }
+
+                                       if ( e.y <= 0 ) {
+                                               e.y = 1;
+                                               eventType = MouseEventType.UP.value();
+                                               EmulatorSkin.this.isDragStartedInLCD = false;
+                                       } else if ( e.y >= canvasSize.y ) {
+                                               e.y = canvasSize.y - 1;
+                                               eventType = MouseEventType.UP.value();
+                                               EmulatorSkin.this.isDragStartedInLCD = false;
+                                       }
+
+                                       int[] geometry = SkinUtil.convertMouseGeometry( e.x, e.y, currentLcdWidth, currentLcdHeight,
+                                                       currentScale, currentAngle );
+
+                                       MouseEventData mouseEventData = new MouseEventData( eventType, geometry[0], geometry[1], 0 );
+                                       communicator.sendToQEMU( SendCommand.SEND_MOUSE_EVENT, mouseEventData );
+                               }
+                       }
+               };
+
+               canvas.addMouseMoveListener( canvasMouseMoveListener );
+
+               canvasMouseListener = new MouseListener() {
+
+                       @Override
+                       public void mouseUp( MouseEvent e ) {
+                               if ( 1 == e.button ) { // left button
+
+                                       int[] geometry = SkinUtil.convertMouseGeometry( e.x, e.y, currentLcdWidth, currentLcdHeight,
+                                                       currentScale, currentAngle );
+
+                                       logger.info( "mouseUp in LCD" + " x:" + geometry[0] + " y:" + geometry[1] );
+                                       MouseEventData mouseEventData = new MouseEventData( MouseEventType.UP.value(), geometry[0],
+                                                       geometry[1], 0 );
+                                       communicator.sendToQEMU( SendCommand.SEND_MOUSE_EVENT, mouseEventData );
+                                       if ( true == EmulatorSkin.this.isDragStartedInLCD ) {
+                                               EmulatorSkin.this.isDragStartedInLCD = false;
+                                       }
+                               }
+                       }
+
+                       @Override
+                       public void mouseDown( MouseEvent e ) {
+                               if ( 1 == e.button ) { // left button
+
+                                       int[] geometry = SkinUtil.convertMouseGeometry( e.x, e.y, currentLcdWidth, currentLcdHeight,
+                                                       currentScale, currentAngle );
+
+                                       logger.info( "mouseDown in LCD" + " x:" + geometry[0] + " y:" + geometry[1] );
+                                       MouseEventData mouseEventData = new MouseEventData( MouseEventType.DOWN.value(), geometry[0],
+                                                       geometry[1], 0 );
+                                       communicator.sendToQEMU( SendCommand.SEND_MOUSE_EVENT, mouseEventData );
+                                       if ( false == EmulatorSkin.this.isDragStartedInLCD ) {
+                                               EmulatorSkin.this.isDragStartedInLCD = true;
+                                       }
+                               }
+                       }
+
+                       @Override
+                       public void mouseDoubleClick( MouseEvent e ) {
+                       }
+               };
+
+               canvas.addMouseListener( canvasMouseListener );
+
+               canvasKeyListener = new KeyListener() {
+                       
+                       private KeyEvent previous;
+                       private boolean disappearEvent = false;
+                       private int disappearKeycode = 0;
+                       private int disappearKeyLocation = 0;
+
+                       @Override
+                       public void keyReleased( KeyEvent e ) {
+                               if( logger.isLoggable( Level.INFO ) ) {
+                                       logger.info( "'" + e.character + "':" + e.keyCode + ":" + e.stateMask + ":" + e.keyLocation );
+                               }else if( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( e.toString() );
+                               }
+                               int keyCode = e.keyCode | e.stateMask;
+
+                               previous = null;
+                               
+                               if( SkinUtil.isWindowsPlatform() && disappearEvent) {
+                                       disappearEvent = false;
+                                       if (isMetaKey(e) && e.character != '\0') {
+                                               logger.info( "send previous release : keycode=" + disappearKeycode +
+                                                               ", disappearKeyLocation=" + disappearKeyLocation);
+
+                                               KeyEventData keyEventData = new KeyEventData(
+                                                               KeyEventType.RELEASED.value(), disappearKeycode, disappearKeyLocation );
+                                               communicator.sendToQEMU( SendCommand.SEND_KEY_EVENT, keyEventData );
+
+                                               disappearKeycode = 0;
+                                               disappearKeyLocation = 0;
+                                       }
+                               }
+                               KeyEventData keyEventData = new KeyEventData( KeyEventType.RELEASED.value(), keyCode, e.keyLocation );
+                               communicator.sendToQEMU( SendCommand.SEND_KEY_EVENT, keyEventData );
+                       }
+
+                       @Override
+                       public void keyPressed( KeyEvent e ) {
+                               int keyCode = e.keyCode | e.stateMask;
+                               
+                               if( SkinUtil.isWindowsPlatform() ) {
+                                       if ( null != previous ) {
+                                               if ( previous.keyCode != e.keyCode ) {
+
+                                                       if ( isMetaKey( previous ) ) {
+                                                               disappearEvent = true;
+                                                               disappearKeycode = keyCode;
+                                                               disappearKeyLocation = e.keyLocation;
+                                                       } else {
+                                                               int previousKeyCode = previous.keyCode | previous.stateMask;
+                                                               
+                                                               if ( logger.isLoggable( Level.INFO ) ) {
+                                                                       logger.info( "send previous release : '" + previous.character + "':"
+                                                                                       + previous.keyCode + ":" + previous.stateMask + ":" + previous.keyLocation );
+                                                               } else if ( logger.isLoggable( Level.FINE ) ) {
+                                                                       logger.fine( "send previous release :" + previous.toString() );
+                                                               }
+                                                               KeyEventData keyEventData = new KeyEventData( KeyEventType.RELEASED.value(), previousKeyCode,
+                                                                               previous.keyLocation );
+                                                               communicator.sendToQEMU( SendCommand.SEND_KEY_EVENT, keyEventData );
+                                                       }
+
+                                               }
+                                       }
+                               } //end isWindowsPlatform
+
+                               previous = e;
+
+                               if ( logger.isLoggable( Level.INFO ) ) {
+                                       logger.info( "'" + e.character + "':" + e.keyCode + ":" + e.stateMask + ":" + e.keyLocation );
+                               } else if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( e.toString() );
+                               }
+                               KeyEventData keyEventData = new KeyEventData( KeyEventType.PRESSED.value(), keyCode, e.keyLocation );
+                               communicator.sendToQEMU( SendCommand.SEND_KEY_EVENT, keyEventData );
+                       }
+
+               };
+
+               canvas.addKeyListener( canvasKeyListener );
+
+       }
+
+       private boolean isMetaKey( KeyEvent event ) {
+               if( SWT.CTRL == event.keyCode || SWT.ALT == event.keyCode || SWT.SHIFT == event.keyCode ) {
+                       return true;
+               }
+               return false;
+       }
+       
+       private void removeCanvasListeners() {
+
+//             if ( null != canvasDragDetectListener ) {
+//                     lcdCanvas.removeDragDetectListener( canvasDragDetectListener );
+//             }
+               if ( null != canvasMouseMoveListener ) {
+                       lcdCanvas.removeMouseMoveListener( canvasMouseMoveListener );
+               }
+               if ( null != canvasMouseListener ) {
+                       lcdCanvas.removeMouseListener( canvasMouseListener );
+               }
+               if ( null != canvasKeyListener ) {
+                       lcdCanvas.removeKeyListener( canvasKeyListener );
+               }
+               if ( null != canvasMenuDetectListener ) {
+                       lcdCanvas.removeMenuDetectListener( canvasMenuDetectListener );
+               }
+
+       }
+
+       private Field getOSField( String field ) {
+
+               String className = "";
+               if ( SkinUtil.isLinuxPlatform() ) {
+                       className = GTK_OS_CLASS;
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+                       className = WIN32_OS_CLASS;
+               }
+
+               Field f = null;
+               try {
+                       f = Class.forName( className ).getField( field );
+               } catch ( ClassNotFoundException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( SecurityException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( NoSuchFieldException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+               return f;
+               
+       }
+
+       private Method getOSMethod( String method, Class<?>... parameterTypes ) {
+
+               String className = "";
+               if ( SkinUtil.isLinuxPlatform() ) {
+                       className = GTK_OS_CLASS;
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+                       className = WIN32_OS_CLASS;
+               }
+
+               Method m = null;
+               try {
+                       m = Class.forName( className ).getMethod( method, parameterTypes );
+               } catch ( ClassNotFoundException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( SecurityException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( NoSuchMethodException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+               return m;
+
+       }
+
+       private Method getOSMethod( String method ) {
+               return  getOSMethod( method, new Class<?>[]{} );
+       }
+
+       private Object invokeOSMethod( Method method, Object... args ) {
+
+               if ( null == method ) {
+                       return null;
+               }
+
+               try {
+                       return method.invoke( null, args );
+               } catch ( IllegalArgumentException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( IllegalAccessException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( InvocationTargetException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+
+               return null;
+               
+       }
+
+       private Object invokeOSMethod( Method method ) {
+               return invokeOSMethod( method, new Object[]{} );
+       }
+       
+       private void addMenuItems( final Shell shell, final Menu menu ) {
+
+               final MenuItem detailInfoItem = new MenuItem( menu, SWT.PUSH );
+
+               String emulatorName = SkinUtil.makeEmulatorName( config );
+               detailInfoItem.setText( emulatorName );
+               detailInfoItem.setImage( imageRegistry.getIcon( IconName.DETAIL_INFO ) );
+               detailInfoItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( "Open detail info" );
+                               }
+                               String emulatorName = SkinUtil.makeEmulatorName( config );
+                               DetailInfoDialog detailInfoDialog = new DetailInfoDialog( shell, emulatorName, communicator, config );
+                               detailInfoDialog.open();
+                       }
+               } );
+
+               new MenuItem( menu, SWT.SEPARATOR );
+
+               final MenuItem onTopItem = new MenuItem( menu, SWT.CHECK );
+               onTopItem.setText( "&Always On Top" );
+               onTopItem.setSelection( isOnTop );
+
+               onTopItem.addSelectionListener( new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               final boolean isOnTop = onTopItem.getSelection();
+
+                               if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( "Select Always On Top. : " + isOnTop );
+                               }
+
+                               // readyToReopen( EmulatorSkin.this, isOnTop );
+
+                               
+                               if( SkinUtil.isLinuxPlatform() ) {
+
+                                       // reference : http://wmctrl.sourcearchive.com/documentation/1.07/main_8c-source.html
+                                       
+//                                     if ( !OS.GDK_WINDOWING_X11() ) {
+//                                             logger.warning( "There is no x11 system." );
+//                                             return;
+//                                     }
+//
+//                                     int eventData0 = isOnTop ? 1 : 0; // 'add' or 'remove'
+//
+//                                     int topHandle = 0;
+//
+//                                     Method m = null;
+//                                     try {
+//                                             m = Shell.class.getDeclaredMethod( "topHandle", new Class<?>[] {} );
+//                                             m.setAccessible( true );
+//                                             topHandle = (Integer) m.invoke( shell, new Object[] {} );
+//                                     } catch ( SecurityException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( NoSuchMethodException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( IllegalArgumentException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( IllegalAccessException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( InvocationTargetException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     }
+//
+//                                     int xWindow = OS.gdk_x11_drawable_get_xid( OS.GTK_WIDGET_WINDOW( topHandle ) );
+//                                     int xDisplay = OS.GDK_DISPLAY();
+//
+//                                     byte[] messageBuffer = Converter.wcsToMbcs( null, "_NET_WM_STATE", true );
+//                                     int xMessageAtomType = OS.XInternAtom( xDisplay, messageBuffer, false );
+//
+//                                     messageBuffer = Converter.wcsToMbcs( null, "_NET_WM_STATE_ABOVE", true );
+//                                     int xMessageAtomAbove = OS.XInternAtom( xDisplay, messageBuffer, false );
+//
+//                                     XClientMessageEvent event = new XClientMessageEvent();
+//                                     event.type = OS.ClientMessage;
+//                                     event.window = xWindow;
+//                                     event.message_type = xMessageAtomType;
+//                                     event.format = 32;
+//                                     event.data[0] = eventData0;
+//                                     event.data[1] = xMessageAtomAbove;
+//
+//                                     int clientEvent = OS.g_malloc( XClientMessageEvent.sizeof );
+//                                     OS.memmove( clientEvent, event, XClientMessageEvent.sizeof );
+//                                     int rootWin = OS.XDefaultRootWindow( xDisplay );
+//                                     // SubstructureRedirectMask:1L<<20 | SubstructureNotifyMask:1L<<19
+//                                     OS.XSendEvent( xDisplay, rootWin, false, (int) ( 1L << 20 | 1L << 19 ), clientEvent );
+//                                     OS.g_free( clientEvent );
+
+                                       Boolean gdkWindowingX11  = (Boolean) invokeOSMethod( getOSMethod( "GDK_WINDOWING_X11" ) );
+                                       if( null == gdkWindowingX11 ) {
+                                               return;
+                                       }
+                                       if( !gdkWindowingX11 ) {
+                                               logger.warning( "There is no x11 system." );
+                                               return;
+                                       }
+                                       
+                                       int eventData0 = isOnTop ? 1 : 0; // 'add' or 'remove'
+                                       
+                                       int topHandle = 0;
+                                       
+                                       Method m = null;
+                                       try {
+                                               m = Shell.class.getDeclaredMethod( "topHandle", new Class<?>[] {} );
+                                               m.setAccessible( true );
+                                               topHandle = (Integer) m.invoke( shell, new Object[] {} );
+                                       } catch ( SecurityException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( NoSuchMethodException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( InvocationTargetException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Integer gtkWidgetWindow = (Integer) invokeOSMethod(
+                                                       getOSMethod( "GTK_WIDGET_WINDOW", int.class ), topHandle );
+                                       if( null == gtkWidgetWindow ) {
+                                               return;
+                                       }
+                                       
+                                       Integer xWindow = (Integer) invokeOSMethod( getOSMethod( "gdk_x11_drawable_get_xid", int.class ),
+                                                       gtkWidgetWindow );
+                                       if( null == xWindow ) {
+                                               return;
+                                       }
+                                       
+                                       Integer xDisplay = (Integer) invokeOSMethod( getOSMethod( "GDK_DISPLAY" ) );
+                                       if( null == xDisplay ) {
+                                               return;
+                                       }
+                                       
+                                       Method xInternAtom = getOSMethod( "XInternAtom", int.class, byte[].class, boolean.class );
+                                       
+                                       Class<?> converterClass = null;
+                                       try {
+                                               converterClass = Class.forName( "org.eclipse.swt.internal.Converter" );
+                                       } catch ( ClassNotFoundException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Method wcsToMbcs = null;
+                                       byte[] messageBufferState = null;
+                                       byte[] messageBufferAbove = null;
+                                       
+                                       try {
+                                               wcsToMbcs = converterClass.getMethod( "wcsToMbcs", String.class, String.class, boolean.class );
+                                       } catch ( SecurityException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( NoSuchMethodException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       try {
+                                               messageBufferState = (byte[]) wcsToMbcs.invoke( null, null, "_NET_WM_STATE", true );
+                                               messageBufferAbove = (byte[]) wcsToMbcs.invoke( null, null, "_NET_WM_STATE_ABOVE", true );
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( InvocationTargetException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Integer xMessageAtomType = (Integer) invokeOSMethod( xInternAtom, xDisplay, messageBufferState, false );
+                                       if( null == xMessageAtomType ) {
+                                               return;
+                                       }
+
+                                       Integer xMessageAtomAbove = (Integer) invokeOSMethod( xInternAtom, xDisplay, messageBufferAbove, false );
+                                       if( null == xMessageAtomAbove ) {
+                                               return;
+                                       }
+                                       
+                                       Class<?> eventClazz = null;
+                                       Object event = null;
+                                       try {
+                                               eventClazz = Class.forName( "org.eclipse.swt.internal.gtk.XClientMessageEvent" );
+                                               event = eventClazz.newInstance();
+                                       } catch ( InstantiationException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       } catch ( ClassNotFoundException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       }
+                                       
+                                       if( null == eventClazz || null == event ) {
+                                               return;
+                                       }
+                                       
+                                       Integer malloc = null;
+                                       try {
+                                               
+                                               Field type = eventClazz.getField( "type" );
+                                               
+                                               Field clientMessageField = getOSField( "ClientMessage" );
+                                               if( null == clientMessageField ) {
+                                                       return;
+                                               }
+                                               type.set( event, clientMessageField.get( null ) );
+                                               
+                                               Field window = eventClazz.getField( "window" );
+                                               window.set( event, xWindow );
+                                               Field messageType = eventClazz.getField( "message_type" );
+                                               messageType.set( event, xMessageAtomType );
+                                               Field format = eventClazz.getField( "format" );
+                                               format.set( event, 32 );
+                                               
+                                               Object data = Array.newInstance( int.class, 5 );
+                                               Array.setInt( data, 0, eventData0 );
+                                               Array.setInt( data, 1, xMessageAtomAbove );
+                                               Array.setInt( data, 2, 0 );
+                                               Array.setInt( data, 3, 0 );
+                                               Array.setInt( data, 4, 0 );
+                                               
+                                               Field dataField = eventClazz.getField( "data" );
+                                               dataField.set( event, data );
+                                               
+                                               Field sizeofField = eventClazz.getField( "sizeof" );
+                                               Integer sizeof = (Integer) sizeofField.get( null );
+                                               
+                                               Method gMalloc = getOSMethod( "g_malloc", int.class );
+                                               malloc = (Integer) invokeOSMethod( gMalloc, sizeof );
+                                               
+                                               Method memmove = getOSMethod( "memmove", int.class, eventClazz, int.class );
+                                               invokeOSMethod( memmove, malloc, event, sizeof );
+                                               
+                                       } catch ( NoSuchFieldException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Method xDefaultRootWindow = getOSMethod( "XDefaultRootWindow", int.class );
+                                       Integer rootWin = (Integer) invokeOSMethod( xDefaultRootWindow, xDisplay );
+                                       
+                                       Method xSendEvent = getOSMethod( "XSendEvent", int.class, int.class, boolean.class, int.class,
+                                                       int.class );
+                                       // SubstructureRedirectMask:1L<<20 | SubstructureNotifyMask:1L<<19
+                                       invokeOSMethod( xSendEvent, xDisplay, rootWin, false, (int) ( 1L << 20 | 1L << 19 ), malloc );
+                                       invokeOSMethod( getOSMethod( "g_free", int.class ), malloc ) ;
+                                       
+                               }else if( SkinUtil.isWindowsPlatform() ) {
+                                       
+                                       Point location = shell.getLocation();
+                                       
+//                                     int hWndInsertAfter = 0;
+//                                     if( isOnTop ) {
+//                                             hWndInsertAfter = OS.HWND_TOPMOST;
+//                                     }else {
+//                                             hWndInsertAfter = OS.HWND_NOTOPMOST;
+//                                     }
+//                                     
+//                                     OS.SetWindowPos( shell.handle, hWndInsertAfter, location.x, location.y, 0, 0, OS.SWP_NOSIZE );
+
+                                       int hWndInsertAfter = 0;
+                                       int noSize = 0;
+
+                                       try {
+                                               if ( isOnTop ) {
+                                                       Field topMost = getOSField( "HWND_TOPMOST" );
+                                                       if ( null == topMost ) {
+                                                               return;
+                                                       }
+                                                       hWndInsertAfter = topMost.getInt( null );
+                                               } else {
+                                                       Field noTopMost = getOSField( "HWND_NOTOPMOST" );
+                                                       if ( null == noTopMost ) {
+                                                               return;
+                                                       }
+                                                       hWndInsertAfter = noTopMost.getInt( null );
+                                               }
+
+                                               Field noSizeField = getOSField( "SWP_NOSIZE" );
+                                               if ( null == noSizeField ) {
+                                                       return;
+                                               }
+                                               noSize = noSizeField.getInt( null );
+
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+
+                                       Method m = getOSMethod( "SetWindowPos", int.class, int.class, int.class, int.class, int.class,
+                                                       int.class, int.class );
+
+                                       invokeOSMethod( m, shell.handle, hWndInsertAfter, location.x, location.y, 0, 0, noSize );
+
+                               }
+                               
+                       }
+               } );
+
+               final MenuItem rotateItem = new MenuItem( menu, SWT.CASCADE );
+               rotateItem.setText( "&Rotate" );
+               rotateItem.setImage( imageRegistry.getIcon( IconName.ROTATE ) );
+               Menu rotateMenu = createRotateMenu( menu.getShell() );
+               rotateItem.setMenu( rotateMenu );
+
+               final MenuItem scaleItem = new MenuItem( menu, SWT.CASCADE );
+               scaleItem.setText( "&Scale" );
+               scaleItem.setImage( imageRegistry.getIcon( IconName.SCALE ) );
+               Menu scaleMenu = createScaleMenu( menu.getShell() );
+               scaleItem.setMenu( scaleMenu );
+
+               new MenuItem( menu, SWT.SEPARATOR );
+
+               final MenuItem advancedItem = new MenuItem( menu, SWT.CASCADE );
+               advancedItem.setText( "Ad&vanced" );
+               advancedItem.setImage( imageRegistry.getIcon( IconName.ADVANCED ) );
+               Menu advancedMenu = createAdvancedMenu( menu.getShell() );
+               advancedItem.setMenu( advancedMenu );
+
+               final MenuItem shellItem = new MenuItem( menu, SWT.PUSH );
+               shellItem.setText( "S&hell" );
+               shellItem.setImage( imageRegistry.getIcon( IconName.SHELL ) );
+               
+               shellItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               if ( !communicator.isSensorDaemonStarted() ) {
+                                       SkinUtil.openMessage( shell, null, "SDB is not ready.\nPlease, wait.", SWT.ICON_WARNING, config );
+                                       return;
+                               }
+
+                               String sdbPath = SkinUtil.getSdbPath();
+
+                               File sdbFile = new File(sdbPath);
+                               if (!sdbFile.exists()) {
+                                       logger.log( Level.INFO, "SDB file is not exist : " + sdbFile.getAbsolutePath());
+                                       try {
+                                               SkinUtil.openMessage( shell, null,
+                                                               "SDB file is not exist in the following path.\n" + sdbFile.getCanonicalPath()
+                                                               , SWT.ICON_ERROR, config );
+                                       } catch (IOException ee) {
+                                               logger.log( Level.SEVERE, ee.getMessage(), ee );
+                                       }
+                                       return;
+                               }
+
+                               int portSdb = config.getArgInt( ArgsConstants.NET_BASE_PORT );
+
+                               ProcessBuilder procSdb = new ProcessBuilder();
+
+                               if ( SkinUtil.isLinuxPlatform() ) {
+                                       procSdb.command( "/usr/bin/gnome-terminal", "--disable-factory",
+                                                       "--title=" + SkinUtil.makeEmulatorName( config ), "-x", sdbPath, "-s", "emulator-"
+                                                                       + portSdb, "shell" );
+                               } else if ( SkinUtil.isWindowsPlatform() ) {
+                                       procSdb.command( "cmd.exe", "/c", "start", sdbPath, "-s", "emulator-" + portSdb, "shell" );
+                               }
+                               logger.log( Level.INFO, procSdb.command().toString() );
+
+                               try {
+                                       procSdb.start(); // open sdb shell
+                               } catch ( Exception ee ) {
+                                       logger.log( Level.SEVERE, ee.getMessage(), ee );
+                                       SkinUtil.openMessage( shell, null, "Fail to open Shell.", SWT.ICON_ERROR, config );
+                               }
+
+                               communicator.sendToQEMU( SendCommand.OPEN_SHELL, null );
+                       }
+               } );
+
+               new MenuItem( menu, SWT.SEPARATOR );
+
+               MenuItem closeItem = new MenuItem( menu, SWT.PUSH );
+               closeItem.setText( "&Close" );
+               closeItem.setImage( imageRegistry.getIcon( IconName.CLOSE ) );
+               closeItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               communicator.sendToQEMU( SendCommand.CLOSE, null );
+                       }
+               } );
+
+       }
+
+       private Menu createRotateMenu( final Shell shell ) {
+
+               Menu menu = new Menu( shell, SWT.DROP_DOWN );
+
+               final List<MenuItem> rotationList = new ArrayList<MenuItem>();
+
+               Iterator<Entry<Short, RotationType>> iterator = SkinRotation.getRotationIterator();
+
+               while ( iterator.hasNext() ) {
+
+                       Entry<Short, RotationType> entry = iterator.next();
+                       Short rotationId = entry.getKey();
+                       RotationType section = entry.getValue();
+
+                       final MenuItem menuItem = new MenuItem( menu, SWT.RADIO );
+                       menuItem.setText( section.getName().value() );
+                       menuItem.setData( rotationId );
+
+                       if ( currentRotationId == rotationId ) {
+                               menuItem.setSelection( true );
+                       }
+
+                       rotationList.add( menuItem );
+
+               }
+
+               SelectionAdapter selectionAdapter = new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               MenuItem item = (MenuItem) e.getSource();
+
+                               boolean selection = item.getSelection();
+
+                               if ( !selection ) {
+                                       return;
+                               }
+
+                               if ( !communicator.isSensorDaemonStarted() ) {
+
+                                       // reset selection.
+                                       item.setSelection( false );
+
+                                       for ( MenuItem m : rotationList ) {
+                                               short rotationId = (Short) m.getData();
+                                               if ( rotationId == currentRotationId ) {
+                                                       m.setSelection( true );
+                                                       break;
+                                               }
+                                       }
+                                       // /////////
+
+                                       SkinUtil.openMessage( shell, null, "Rotation is not ready.\nPlease, wait.", SWT.ICON_WARNING,
+                                                       config );
+
+                                       return;
+
+                               }
+
+                               short rotationId = ( (Short) item.getData() );
+
+                               arrangeSkin( currentLcdWidth, currentLcdHeight, currentScale, rotationId );
+                               LcdStateData lcdStateData = new LcdStateData( currentScale, rotationId );
+                               communicator.sendToQEMU( SendCommand.CHANGE_LCD_STATE, lcdStateData );
+
+                       }
+               };
+
+               for ( MenuItem menuItem : rotationList ) {
+                       menuItem.addSelectionListener( selectionAdapter );
+               }
+
+               return menu;
+       }
+
+       private Menu createScaleMenu( Shell shell ) {
+
+               Menu menu = new Menu( shell, SWT.DROP_DOWN );
+
+               final List<MenuItem> scaleList = new ArrayList<MenuItem>();
+
+               final MenuItem scaleOneItem = new MenuItem( menu, SWT.RADIO );
+               scaleOneItem.setText( "1x" );
+               scaleOneItem.setData( Scale.SCALE_100 );
+               scaleList.add( scaleOneItem );
+
+               final MenuItem scaleThreeQtrItem = new MenuItem( menu, SWT.RADIO );
+               scaleThreeQtrItem.setText( "3/4x" );
+               scaleThreeQtrItem.setData( Scale.SCALE_75 );
+               scaleList.add( scaleThreeQtrItem );
+
+               final MenuItem scalehalfItem = new MenuItem( menu, SWT.RADIO );
+               scalehalfItem.setText( "1/2x" );
+               scalehalfItem.setData( Scale.SCALE_50 );
+               scaleList.add( scalehalfItem );
+
+               final MenuItem scaleOneQtrItem = new MenuItem( menu, SWT.RADIO );
+               scaleOneQtrItem.setText( "1/4x" );
+               scaleOneQtrItem.setData( Scale.SCALE_25 );
+               scaleList.add( scaleOneQtrItem );
+
+               SelectionAdapter selectionAdapter = new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               MenuItem item = (MenuItem) e.getSource();
+
+                               boolean selection = item.getSelection();
+
+                               if ( !selection ) {
+                                       return;
+                               }
+
+                               int scale = ( (Scale) item.getData() ).value();
+
+                               arrangeSkin( currentLcdWidth, currentLcdHeight, scale, currentRotationId );
+                               LcdStateData lcdStateData = new LcdStateData( scale, currentRotationId );
+                               communicator.sendToQEMU( SendCommand.CHANGE_LCD_STATE, lcdStateData );
+
+                       }
+               };
+               
+               for ( MenuItem menuItem : scaleList ) {
+
+                       int scale = ( (Scale) menuItem.getData() ).value();
+                       if ( scale == currentScale ) {
+                               menuItem.setSelection( true );
+                       }
+
+                       menuItem.addSelectionListener( selectionAdapter );
+
+               }
+
+               return menu;
+
+       }
+
+       private Menu createAdvancedMenu( final Shell shell ) {
+
+               final Menu menu = new Menu( shell, SWT.DROP_DOWN );
+
+               final MenuItem screenshotItem = new MenuItem( menu, SWT.PUSH );
+               screenshotItem.setText( "&Screen Shot" );
+               screenshotItem.setImage( imageRegistry.getIcon( IconName.SCREENSHOT ) );
+               screenshotItem.addSelectionListener( new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               if ( isScreenShotOpened ) {
+                                       return;
+                               }
+
+                               try {
+
+                                       isScreenShotOpened = true;
+
+                                       screenShotDialog = new ScreenShotDialog( shell, communicator, EmulatorSkin.this, config,
+                                                       imageRegistry.getIcon(IconName.SCREENSHOT) );
+                                       screenShotDialog.open();
+
+                               } catch ( ScreenShotException ex ) {
+
+                                       logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       SkinUtil.openMessage( shell, null, "Fail to create a screen shot.", SWT.ICON_ERROR, config );
+
+                               } catch ( Exception ex ) {
+
+                                       // defense exception handling.
+                                       logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       String errorMessage = "Internal Error.\n[" + ex.getMessage() + "]";
+                                       SkinUtil.openMessage( shell, null, errorMessage, SWT.ICON_ERROR, config );
+
+                               } finally {
+                                       isScreenShotOpened = false;
+                               }
+
+                       }
+               } );
+
+               final MenuItem usbKeyboardItem = new MenuItem( menu, SWT.CASCADE );
+               usbKeyboardItem.setText( "&USB Keyboard" );
+               usbKeyboardItem.setImage( imageRegistry.getIcon( IconName.USB_KEBOARD ) );
+               
+               Menu usbKeyBoardMenu = new Menu( shell, SWT.DROP_DOWN );
+
+               final MenuItem usbOnItem = new MenuItem( usbKeyBoardMenu, SWT.RADIO );
+               usbOnItem.setText( "On" );
+               usbOnItem.setSelection( isOnUsbKbd );
+               
+               final MenuItem usbOffItem = new MenuItem( usbKeyBoardMenu, SWT.RADIO );
+               usbOffItem.setText( "Off" );
+               usbOffItem.setSelection( !isOnUsbKbd );
+
+               SelectionAdapter usbSelectionAdaptor = new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               MenuItem item = (MenuItem) e.getSource();
+                               if ( item.getSelection() ) {
+                                       boolean on = item.equals( usbOnItem );
+                                       isOnUsbKbd = on;
+                                       communicator
+                                                       .sendToQEMU( SendCommand.USB_KBD, new BooleanData( on, SendCommand.USB_KBD.toString() ) );
+                               }
+
+                       }
+               };
+
+               usbOnItem.addSelectionListener( usbSelectionAdaptor );
+               usbOffItem.addSelectionListener( usbSelectionAdaptor );
+
+               usbKeyboardItem.setMenu( usbKeyBoardMenu );
+
+               final MenuItem aboutItem = new MenuItem( menu, SWT.PUSH );
+               aboutItem.setText( "&About" );
+               aboutItem.setImage( imageRegistry.getIcon( IconName.ABOUT ) );
+
+               aboutItem.addSelectionListener( new SelectionAdapter() {
+                       private boolean isOpen;
+
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               if ( !isOpen ) {
+                                       isOpen = true;
+                                       AboutDialog dialog = new AboutDialog( shell );
+                                       dialog.open();
+                                       isOpen = false;
+                               }
+                       }
+               } );
+
+               return menu;
+
+       }
+
+       public void shutdown() {
+
+               isShutdownRequested = true;
+
+               if ( !this.shell.isDisposed() ) {
+                       this.shell.getDisplay().asyncExec( new Runnable() {
+                               @Override
+                               public void run() {
+                                       if ( !shell.isDisposed() ) {
+                                               EmulatorSkin.this.shell.close();
+                                       }
+                               }
+                       } );
+               }
+
+       }
+
+       public short getCurrentRotationId() {
+               return currentRotationId;
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkinMain.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkinMain.java
new file mode 100644 (file)
index 0000000..874cfbe
--- /dev/null
@@ -0,0 +1,359 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.config.EmulatorConfig.ConfigPropertiesConstants;
+import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
+import org.tizen.emulator.skin.dbi.EmulatorUI;
+import org.tizen.emulator.skin.exception.JaxbException;
+import org.tizen.emulator.skin.image.ImageRegistry;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.log.SkinLogger.SkinLogLevel;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.JaxbUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+/**
+ * 
+ *
+ */
+public class EmulatorSkinMain {
+
+       public static final String SKIN_PROPERTIES_FILE_NAME = ".skin.properties";
+       public static final String CONFIG_PROPERTIES_FILE_NAME = ".skinconfig.properties";
+       public static final String DBI_FILE_NAME = "default.dbi";
+
+       private static Logger logger;
+       
+       /**
+        * @param args
+        */
+       public static void main( String[] args ) {
+               
+               SocketCommunicator communicator = null;
+               
+               try {
+
+                       String vmPath = getVmPath( args );
+                       if ( StringUtil.isEmpty( vmPath ) ) {
+                               throw new IllegalArgumentException( ArgsConstants.VM_PATH + " in arguments is null." );
+                       }
+
+                       SkinLogger.init( SkinLogLevel.DEBUG, vmPath );
+
+                       logger = SkinLogger.getSkinLogger( EmulatorSkinMain.class ).getLogger();
+                       logger.info( "!!! Start Emualtor Skin !!!" );
+                       
+                       Map<String, String> argsMap = parsArgs( args );
+                       
+                       String skinPropFilePath = vmPath + File.separator + SKIN_PROPERTIES_FILE_NAME;
+                       Properties skinProperties = loadProperties( skinPropFilePath, true );
+                       if ( null == skinProperties ) {
+                               logger.severe( "Fail to load skin properties file." );
+                               System.exit( -1 );
+                       }
+
+                       String configPropFilePath = vmPath + File.separator + CONFIG_PROPERTIES_FILE_NAME;
+                       Properties configProperties = loadProperties( configPropFilePath, false );
+
+                       // able to use log file after loading properties
+                       initLog( argsMap, configProperties );
+
+                       EmulatorConfig.validateArgs( argsMap );
+                       EmulatorConfig.validateSkinProperties( skinProperties );
+                       EmulatorConfig.validateSkinConfigProperties( configProperties );
+                       
+                       int lcdWidth = Integer.parseInt( argsMap.get( ArgsConstants.RESOLUTION_WIDTH ) );
+                       int lcdHeight = Integer.parseInt( argsMap.get( ArgsConstants.RESOLUTION_HEIGHT ) );
+                       String argSkinPath = (String) argsMap.get( ArgsConstants.SKIN_PATH );
+
+                       EmulatorUI dbiContents = loadDbi( argSkinPath, lcdWidth, lcdHeight );
+                       if ( null == dbiContents ) {
+                               logger.severe( "Fail to load dbi file." );
+
+                               Shell temp = new Shell( Display.getDefault());
+                               MessageBox messageBox = new MessageBox( temp, SWT.ICON_ERROR );
+                               messageBox.setText( "Emulator" );
+                               messageBox.setMessage( "Fail to load \"" + DBI_FILE_NAME + "\" file\n" +
+                                               "Check if the file is corrupted or missing from the following path.\n" +
+                                               argSkinPath );
+                               messageBox.open();
+                               temp.dispose();
+
+                               System.exit( -1 );
+                       }
+
+                       EmulatorConfig config = new EmulatorConfig( argsMap, dbiContents, skinProperties, skinPropFilePath,
+                                       configProperties );
+
+                       ImageRegistry.getInstance().initialize( config );
+                       
+                       String onTopVal = config.getSkinProperty( SkinPropertiesConstants.WINDOW_ONTOP, Boolean.FALSE.toString() );
+                       boolean isOnTop = Boolean.parseBoolean( onTopVal );
+
+                       EmulatorSkin skin = new EmulatorSkin( config, isOnTop );
+                       int windowHandleId = skin.compose();
+
+                       int uid = config.getArgInt( ArgsConstants.UID );
+                       communicator = new SocketCommunicator( config, uid, windowHandleId, skin );
+
+                       skin.setCommunicator( communicator );
+
+                       Socket commSocket = communicator.getSocket();
+
+                       if ( null != commSocket ) {
+
+                               Runtime.getRuntime().addShutdownHook( new EmulatorShutdownhook( communicator ) );
+
+                               Thread communicatorThread = new Thread( communicator );
+                               communicatorThread.start();
+                               
+//                             SkinReopenPolicy reopenPolicy = skin.open();
+//                             
+//                             while( true ) {
+//
+//                                     if( null != reopenPolicy ) {
+//                                             
+//                                             if( reopenPolicy.isReopen() ) {
+//                                                     
+//                                                     EmulatorSkin reopenSkin = reopenPolicy.getReopenSkin();
+//                                                     logger.info( "Reopen skin dialog." );
+//                                                     reopenPolicy = reopenSkin.open();
+//                                                     
+//                                             }else {
+//                                                     break;
+//                                             }
+//                                             
+//                                     }else {
+//                                             break;
+//                                     }
+//
+//                             }
+                               
+                               skin.open();
+                               
+                       } else {
+                               logger.severe( "CommSocket is null." );
+                       }
+
+               } catch ( Throwable e ) {
+
+                       if ( null != logger ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               logger.warning( "Shutdown skin process !!!" );
+                       } else {
+                               e.printStackTrace();
+                               System.out.println( "Shutdown skin process !!!" );
+                       }
+                       
+                       if( null != communicator ) {
+                               communicator.terminate();
+                       }
+                       
+               } finally {
+                       ImageRegistry.getInstance().dispose();
+                       Display.getDefault().close();
+                       SkinLogger.end();
+               }
+
+       }
+
+       private static void initLog( Map<String, String> argsMap, Properties properties ) {
+
+               String argLogLevel = argsMap.get( ArgsConstants.LOG_LEVEL );
+               String configPropertyLogLevel = null;
+               
+               if( null != properties ) {
+                       configPropertyLogLevel = (String) properties.get( ConfigPropertiesConstants.LOG_LEVEL );
+               }
+
+               // default log level is debug.
+               
+               String logLevel = "";
+               
+               if( !StringUtil.isEmpty( argLogLevel ) ) {
+                       logLevel = argLogLevel;
+               }else if( !StringUtil.isEmpty( configPropertyLogLevel ) ) {
+                       logLevel = configPropertyLogLevel;
+               }else {
+                       logLevel = EmulatorConfig.DEFAULT_LOG_LEVEL.value();
+               }
+               
+               SkinLogLevel skinLogLevel = EmulatorConfig.DEFAULT_LOG_LEVEL;
+               
+               SkinLogLevel[] values = SkinLogLevel.values();
+               
+               for ( SkinLogLevel level : values ) {
+                       if ( level.value().equalsIgnoreCase( logLevel ) ) {
+                               skinLogLevel = level;
+                               break;
+                       }
+               }
+
+               SkinLogger.setLevel( skinLogLevel.level() );
+               
+       }
+
+       private static String getVmPath( String[] args ) {
+
+               for ( int i = 0; i < args.length; i++ ) {
+                       String arg = args[i];
+                       String[] split = arg.split( "=" );
+                       if ( 1 < split.length ) {
+                               if ( ArgsConstants.VM_PATH.equals( split[0].trim() ) ) {
+                                       return split[1].trim();
+                               }
+                       }
+               }
+
+               return null;
+
+       }
+       
+       private static Map<String, String> parsArgs( String[] args ) {
+
+               Map<String, String> map = new HashMap<String, String>();
+
+               for ( int i = 0; i < args.length; i++ ) {
+                       String arg = args[i];
+                       logger.info( "arg[" + i + "] " + arg );
+                       String[] split = arg.split( "=" );
+
+                       if ( 1 < split.length ) {
+
+                               String argKey = split[0].trim();
+                               String argValue = split[1].trim();
+                               map.put( argKey, argValue );
+
+                       } else {
+                               logger.info( "sinlge argv:" + arg );
+                       }
+               }
+
+               logger.info( "================= argsMap =====================" );
+               logger.info( map.toString() );
+               logger.info( "===============================================" );
+
+               return map;
+
+       }
+
+       private static EmulatorUI loadDbi( String argSkinPath, int lcdWidth, int lcdHeight ) {
+
+               String skinPath = ImageRegistry.getSkinPath( argSkinPath, lcdWidth, lcdHeight ) + File.separator + DBI_FILE_NAME;
+
+               FileInputStream fis = null;
+               EmulatorUI emulatorUI = null;
+
+               try {
+                       
+                       fis = new FileInputStream( skinPath );
+                       logger.info( "============ dbi contents ============" );
+                       byte[] bytes = IOUtil.getBytes( fis );
+                       logger.info( new String( bytes, "UTF-8" ) );
+                       logger.info( "=======================================" );
+                       
+                       emulatorUI = JaxbUtil.unmarshal( bytes, EmulatorUI.class );
+                       
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( JaxbException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } finally {
+                       IOUtil.close( fis );
+               }
+
+               return emulatorUI;
+
+       }
+
+       private static Properties loadProperties( String filePath, boolean create ) {
+
+               FileInputStream fis = null;
+               Properties properties = null;
+
+               try {
+
+                       File file = new File( filePath );
+                       
+                       if( create ) {
+                               
+                               if ( !file.exists() ) {
+                                       if ( !file.createNewFile() ) {
+                                               logger.severe( "Fail to create new " + filePath + " property file." );
+                                               return null;
+                                       }
+                               }
+                               
+                               fis = new FileInputStream( filePath );
+                               properties = new Properties();
+                               properties.load( fis );
+                               
+                       }else {
+                               
+                               if ( file.exists() ) {
+
+                                       fis = new FileInputStream( filePath );
+                                       properties = new Properties();
+                                       properties.load( fis );
+                               }
+
+                       }
+
+                       logger.info( "load properties file : " + filePath );
+
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, "Fail to load skin properties file.", e );
+               } finally {
+                       IOUtil.close( fis );
+               }
+
+               return properties;
+
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/ICommunicator.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/ICommunicator.java
new file mode 100644 (file)
index 0000000..f185d27
--- /dev/null
@@ -0,0 +1,244 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm;
+
+import org.tizen.emulator.skin.comm.sock.data.ISendData;
+import org.tizen.emulator.skin.dbi.RotationNameType;
+
+/**
+ * 
+ *
+ */
+public interface ICommunicator extends Runnable {
+
+       public enum Scale {
+               SCALE_25(25),
+               SCALE_50(50),
+               SCALE_75(75),
+               SCALE_100(100);
+
+               private int value;
+
+               Scale( int value ) {
+                       this.value = value;
+               }
+
+               public int value() {
+                       return this.value;
+               }
+       }
+       
+       public enum MouseEventType {
+               DOWN( (short)1 ),
+               UP( (short)2 ),
+               DRAG( (short)3 );
+               
+               private short value;
+               MouseEventType( short value ) {
+                       this.value = value;
+               }
+               public short value() {
+                       return this.value;
+               }
+               public static MouseEventType getValue( String val ) {
+                       MouseEventType[] values = MouseEventType.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == Integer.parseInt( val ) ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( val );
+               }
+               public static MouseEventType getValue( short val ) {
+                       MouseEventType[] values = MouseEventType.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == val ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( Integer.toString(val) );
+               }
+
+       }
+
+       public enum KeyEventType {
+               PRESSED( (short)1 ),
+               RELEASED( (short)2 );
+               
+               private short value;
+               KeyEventType( short value ) {
+                       this.value = value;
+               }
+               public short value() {
+                       return this.value;
+               }
+               public static KeyEventType getValue( String val ) {
+                       KeyEventType[] values = KeyEventType.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == Integer.parseInt( val ) ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( val );
+               }
+               public static KeyEventType getValue( short val ) {
+                       KeyEventType[] values = KeyEventType.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == val ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( Integer.toString(val) );
+               }
+
+       }
+
+       public enum RotationInfo {
+
+               PORTRAIT( RotationNameType.PORTRAIT.value(), (short)0, 0 ),
+               LANDSCAPE( RotationNameType.LANDSCAPE.value(), (short)1, -90 ),
+               REVERSE_PORTRAIT( RotationNameType.REVERSE_PORTRAIT.value(), (short)2, 180 ),
+               REVERSE_LANDSCAPE( RotationNameType.REVERSE_LANDSCAPE.value(), (short)3, 90 );
+               
+               private String value;
+               private short id;
+               private int angle;
+               
+               RotationInfo( String value, short id, int ratio ) {
+                       this.value = value;
+                       this.id = id;
+                       this.angle = ratio;
+               }
+               public String value() {
+                       return this.value;
+               }
+               public int angle() {
+                       return this.angle;
+               }
+               public short id() {
+                       return this.id;
+               }
+               
+               public static RotationInfo getValue( short id ) {
+                       RotationInfo[] values = RotationInfo.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].id == id ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( Integer.toString(id) );
+               }
+
+       }
+
+       public enum SendCommand {
+               
+               SEND_START( (short)1 ),
+               
+               SEND_MOUSE_EVENT( (short)10 ),
+               SEND_KEY_EVENT( (short)11 ),
+               SEND_HARD_KEY_EVENT( (short)12 ),
+               CHANGE_LCD_STATE( (short)13 ),
+               OPEN_SHELL( (short)14 ),
+               USB_KBD( (short)15 ),
+               SCREEN_SHOT( (short)16 ),
+               DETAIL_INFO( (short)17 ),
+               
+               RESPONSE_HEART_BEAT( (short)900 ),
+               CLOSE( (short)998 ),
+               RESPONSE_SHUTDOWN( (short)999 );
+               
+               private short value;
+               SendCommand( short value ) {
+                       this.value = value;
+               }
+               public short value() {
+                       return this.value;
+               }
+               public static SendCommand getValue( String val ) {
+                       SendCommand[] values = SendCommand.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == Short.parseShort( val ) ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( val );
+               }
+               public static SendCommand getValue( short val ) {
+                       SendCommand[] values = SendCommand.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == val ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( Integer.toString(val) );
+               }
+       }
+
+       public enum ReceiveCommand {
+               
+               HEART_BEAT( (short)1 ),
+               SCREEN_SHOT_DATA( (short)2 ),
+               DETAIL_INFO_DATA( (short)3 ),
+               SENSOR_DAEMON_START( (short)800 ),
+               SHUTDOWN( (short)999 );
+               
+               private short value;
+               ReceiveCommand( short value ) {
+                       this.value = value;
+               }
+               public short value() {
+                       return this.value;
+               }
+               public static ReceiveCommand getValue( String val ) {
+                       ReceiveCommand[] values = ReceiveCommand.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == Short.parseShort( val ) ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( val );
+               }
+               public static ReceiveCommand getValue( short val ) {
+                       ReceiveCommand[] values = ReceiveCommand.values();
+                       for (int i = 0; i < values.length; i++) {
+                               if( values[i].value == val ) {
+                                       return values[i];
+                               }
+                       }
+                       throw new IllegalArgumentException( Integer.toString(val) );
+               }
+       }
+
+       public void sendToQEMU( SendCommand command, ISendData data );
+       
+       public void terminate();
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java
new file mode 100644 (file)
index 0000000..3d5658b
--- /dev/null
@@ -0,0 +1,602 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.tizen.emulator.skin.EmulatorSkin;
+import org.tizen.emulator.skin.comm.ICommunicator;
+import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
+import org.tizen.emulator.skin.comm.sock.data.ISendData;
+import org.tizen.emulator.skin.comm.sock.data.StartData;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.SkinUtil;
+
+
+/**
+ * 
+ * 
+ */
+public class SocketCommunicator implements ICommunicator {
+
+       public class DataTranfer {
+
+               private boolean isTransferState;
+               private byte[] receivedData;
+
+               private long sleep;
+               private long maxWaitTime;
+               private Timer timer;
+               
+               private DataTranfer() {
+               }
+
+               private void setData( byte[] data ) {
+                       this.receivedData = data;
+                       isTransferState = false;
+               }
+
+       }
+
+       public static final int HEART_BEAT_INTERVAL = 1; //second
+       public static final int HEART_BEAT_EXPIRE = 5;
+
+       public final static int SEND_QUEUE_WAIT_INTERVAL = 10; // milli-seconds
+       
+       public final static int SCREENSHOT_WAIT_INTERVAL = 3; // milli-seconds
+       public final static int SCREENSHOT_WAIT_LIMIT = 3000; // milli-seconds
+       public final static int DETAIL_INFO_WAIT_INTERVAL = 1; // milli-seconds
+       public final static int DETAIL_INFO_WAIT_LIMIT = 3000; // milli-seconds
+       
+       private static int reqId;
+       
+       private Logger logger = SkinLogger.getSkinLogger( SocketCommunicator.class ).getLogger();
+
+       private EmulatorConfig config;
+       private int uId;
+       private int windowHandleId;
+       private EmulatorSkin skin;
+
+       private Socket socket;
+       private DataInputStream dis;
+       private DataOutputStream dos;
+
+       private AtomicInteger heartbeatCount;
+       private boolean isTerminated;
+       private boolean isSensorDaemonStarted;
+       private ScheduledExecutorService heartbeatExecutor;
+
+       private DataTranfer screenShotDataTransfer;
+       private DataTranfer detailInfoTransfer;
+       
+       private Thread sendThread;
+       private ConcurrentLinkedQueue<SkinSendData> sendQueue;
+
+       public SocketCommunicator( EmulatorConfig config, int uId, int windowHandleId, EmulatorSkin skin ) {
+
+               this.config = config;
+               this.uId = uId;
+               this.windowHandleId = windowHandleId;
+               this.skin = skin;
+
+               this.screenShotDataTransfer = new DataTranfer();
+               this.screenShotDataTransfer.sleep = SCREENSHOT_WAIT_INTERVAL;
+               this.screenShotDataTransfer.maxWaitTime = SCREENSHOT_WAIT_LIMIT;
+
+               this.detailInfoTransfer = new DataTranfer();
+               this.detailInfoTransfer.sleep = DETAIL_INFO_WAIT_INTERVAL;
+               this.detailInfoTransfer.maxWaitTime = DETAIL_INFO_WAIT_LIMIT;
+
+               this.heartbeatCount = new AtomicInteger( 0 );
+               this.heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
+
+               try {
+
+                       int port = config.getArgInt( ArgsConstants.SERVER_PORT );
+                       socket = new Socket( "127.0.0.1", port );
+                       logger.info( "socket.isConnected():" + socket.isConnected() );
+
+               } catch ( UnknownHostException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+
+       }
+
+       @Override
+       public void run() {
+
+               try {
+
+                       sendQueue = new ConcurrentLinkedQueue<SkinSendData>();
+
+                       sendThread = new Thread() {
+                               @Override
+                               public void run() {
+
+                                       while ( true ) {
+
+                                               synchronized ( sendThread ) {
+                                                       try {
+                                                               sendThread.wait( SEND_QUEUE_WAIT_INTERVAL );
+                                                       } catch ( InterruptedException e ) {
+                                                               logger.log( Level.SEVERE, e.getMessage(), e );
+                                                       }
+                                               }
+
+                                               SkinSendData sendData = null;
+                                               while ( true ) {
+                                                       sendData = sendQueue.poll();
+                                                       if ( null != sendData ) {
+                                                               sendToQEMUInternal( sendData );
+                                                       } else {
+                                                               break;
+                                                       }
+                                               }
+
+                                               if ( isTerminated ) {
+                                                       break;
+                                               }
+
+                                       }
+
+                               }
+                       };
+
+                       sendThread.start();
+
+                       dis = new DataInputStream( socket.getInputStream() );
+                       dos = new DataOutputStream( socket.getOutputStream() );
+
+                       int width = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH );
+                       int height = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT );
+                       int scale = SkinUtil.getValidScale( config );
+//                     short rotation = config.getSkinPropertyShort( SkinPropertiesConstants.WINDOW_ROTATION,
+//                                     EmulatorConfig.DEFAULT_WINDOW_ROTATION );
+                       // has to be portrait mode at first booting time
+                       short rotation = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
+                       StartData startData = new StartData( windowHandleId, width, height, scale, rotation );
+
+                       sendToQEMU( SendCommand.SEND_START, startData );
+
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+                       terminate();
+                       return;
+               }
+
+               boolean ignoreHeartbeat = config.getArgBoolean( ArgsConstants.TEST_HEART_BEAT_IGNORE );
+
+               if ( ignoreHeartbeat ) {
+                       logger.info( "Ignore Skin heartbeat." );
+               } else {
+
+                       heartbeatExecutor.scheduleAtFixedRate( new Runnable() {
+
+                               @Override
+                               public void run() {
+
+                                       increaseHeartbeatCount();
+
+                                       if ( isHeartbeatExpired() ) {
+                                               terminate();
+                                       }
+
+                               }
+
+                       }, 0, HEART_BEAT_INTERVAL, TimeUnit.SECONDS );
+
+               }
+
+               while ( true ) {
+
+                       if ( isTerminated ) {
+                               break;
+                       }
+
+                       try {
+
+                               int reqId = dis.readInt();
+                               short cmd = dis.readShort();
+                               int length = dis.readInt();
+
+                               if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( "[Socket] read - reqId:" + reqId + ", command:" + cmd + ", dataLength:" + length );
+                               }
+
+                               ReceiveCommand command = null;
+
+                               try {
+                                       command = ReceiveCommand.getValue( cmd );
+                               } catch ( IllegalArgumentException e ) {
+                                       logger.severe( "unknown command:" + cmd );
+                                       continue;
+                               }
+
+                               switch ( command ) {
+                               case HEART_BEAT: {
+                                       resetHeartbeatCount();
+                                       if ( logger.isLoggable( Level.FINE ) ) {
+                                               logger.fine( "received HEAR_BEAT from QEMU." );
+                                       }
+                                       sendToQEMU( SendCommand.RESPONSE_HEART_BEAT, null );
+                                       break;
+                               }
+                               case SCREEN_SHOT_DATA: {
+                                       logger.info( "received SCREEN_SHOT_DATA from QEMU." );
+                                       receiveData( screenShotDataTransfer, length );
+
+                                       break;
+                               }
+                               case DETAIL_INFO_DATA: {
+                                       logger.info( "received DETAIL_INFO_DATA from QEMU." );
+                                       receiveData( detailInfoTransfer, length );
+
+                                       break;
+                               }
+                               case SENSOR_DAEMON_START: {
+                                       logger.info( "received SENSOR_DAEMON_START from QEMU." );
+                                       synchronized ( this ) {
+                                               isSensorDaemonStarted = true;
+                                       }
+                                       break;
+                               }
+                               case SHUTDOWN: {
+                                       logger.info( "received RESPONSE_SHUTDOWN from QEMU." );
+                                       sendToQEMU( SendCommand.RESPONSE_SHUTDOWN, null );
+                                       terminate();
+                                       break;
+                               }
+                               default: {
+                                       logger.severe( "Unknown command from QEMU. command:" + cmd );
+                                       break;
+                               }
+                               }
+
+                       } catch ( IOException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               break;
+                       }
+
+               }
+
+       }
+
+       private void receiveData( DataTranfer dataTransfer, int length ) throws IOException {
+               
+               synchronized ( dataTransfer ) {
+                       
+                       if( null != dataTransfer.timer ) {
+                               dataTransfer.timer.cancel();
+                       }
+                       
+                       byte[] data = readData( dis, length );
+                       
+                       if( null != data ) {
+                               logger.info( "finished receiving data from QEMU." );
+                       }else {
+                               logger.severe( "Fail to receiving data from QEMU." );
+                       }
+                       
+                       dataTransfer.isTransferState = false;
+                       dataTransfer.timer = null;
+                       
+                       dataTransfer.setData( data );
+                       dataTransfer.notifyAll();
+                       
+               }
+
+       }
+
+       private byte[] readData( DataInputStream is, int length ) throws IOException {
+
+               if ( 0 >= length ) {
+                       return null;
+               }
+
+               BufferedInputStream bfis = new BufferedInputStream( is, length );
+               byte[] data = new byte[length];
+
+               int read = 0;
+               int total = 0;
+
+               while ( true ) {
+
+                       if ( total == length ) {
+                               break;
+                       }
+
+                       read = bfis.read( data, total, length - total );
+
+                       if ( 0 > read ) {
+                               if ( total < length ) {
+                                       continue;
+                               }
+                       } else {
+                               total += read;
+                       }
+
+               }
+
+               logger.info( "finished reading stream. read:" + total );
+
+               return data;
+
+       }
+
+       public synchronized DataTranfer sendToQEMU( SendCommand command, ISendData data, boolean useDataTransfer ) {
+
+               DataTranfer dataTranfer = null;
+               
+               if ( useDataTransfer ) {
+
+                       if ( SendCommand.SCREEN_SHOT.equals( command ) ) {
+                               dataTranfer = resetDataTransfer( screenShotDataTransfer );
+                       } else if ( SendCommand.DETAIL_INFO.equals( command ) ) {
+                               dataTranfer = resetDataTransfer( detailInfoTransfer );
+                       }
+               }
+
+               sendToQEMU( command, data );
+               
+               return dataTranfer;
+
+       }
+       
+       private DataTranfer resetDataTransfer( final DataTranfer dataTransfer ) {
+               
+               synchronized ( dataTransfer ) {
+                       
+                       if ( dataTransfer.isTransferState ) {
+                               logger.severe( "Already transter state for getting data." );
+                               return null;
+                       }
+
+                       dataTransfer.isTransferState = true;
+
+                       Timer timer = new Timer();
+                       dataTransfer.timer = timer;
+
+                       TimerTask timerTask = new TimerTask() {
+                               @Override
+                               public void run() {
+                                       synchronized ( dataTransfer ) {
+                                               dataTransfer.isTransferState = false;
+                                               dataTransfer.timer = null;
+                                               dataTransfer.receivedData = null;
+                                       }
+                               }
+                       };
+                       timer.schedule( timerTask, dataTransfer.maxWaitTime );
+
+                       return dataTransfer;
+
+               }
+
+       }
+       
+       @Override
+       public void sendToQEMU( SendCommand command, ISendData data ) {
+               
+               sendQueue.add( new SkinSendData( command, data ) );
+               
+               synchronized ( sendThread ) {
+                       sendThread.notifyAll();
+               }
+
+       }
+       
+       private void sendToQEMUInternal( SkinSendData sendData ) {
+
+               try {
+
+                       if( null == sendData ) {
+                               return;
+                       }
+                       
+                       SendCommand command = sendData.getCommand();
+                       ISendData data = sendData.getSendData();
+                       
+                       reqId = ( Integer.MAX_VALUE == reqId ) ? 0 : ++reqId;
+                       
+                       ByteArrayOutputStream bao = new ByteArrayOutputStream();
+                       DataOutputStream dataOutputStream = new DataOutputStream( bao );
+
+                       dataOutputStream.writeInt( uId );
+                       dataOutputStream.writeInt( reqId );
+                       dataOutputStream.writeShort( command.value() );
+
+                       short length = 0;
+                       if ( null == data ) {
+                               length = 0;
+                               dataOutputStream.writeShort( length );
+                       } else {
+                               byte[] byteData = data.serialize();
+                               length = (short) byteData.length;
+                               dataOutputStream.writeShort( length );
+                               dataOutputStream.write( byteData );
+                       }
+
+                       dataOutputStream.flush();
+
+                       dos.write( bao.toByteArray() );
+                       dos.flush();
+
+                       if ( logger.isLoggable( Level.FINE ) ) {
+                               logger.fine( "[Socket] write - uid:" + uId + ", reqId:" + reqId + ", command:" + command.value()
+                                               + " - " + command.toString() + ", length:" + length );
+                       }
+
+                       if ( 0 < length ) {
+                               if ( logger.isLoggable( Level.FINE ) ) {
+                                       logger.fine( "[Socket] data  - " + data.toString() );
+                               }
+                       }
+
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+
+       }
+
+       public byte[] getReceivedData( DataTranfer dataTranfer ) {
+
+               if( null == dataTranfer ) {
+                       return null;
+               }
+               
+               synchronized ( dataTranfer ) {
+                       
+                       int count = 0;
+                       byte[] receivedData = null;
+                       long sleep = dataTranfer.sleep;
+                       long maxWaitTime = dataTranfer.maxWaitTime;
+                       int limitCount = (int) ( maxWaitTime / sleep );
+
+                       while ( dataTranfer.isTransferState ) {
+
+                               if ( limitCount < count ) {
+                                       logger.severe( "time out for receiving data from skin server." );
+                                       dataTranfer.receivedData = null;
+                                       break;
+                               }
+
+                               try {
+                                       dataTranfer.wait( sleep );
+                               } catch ( InterruptedException e ) {
+                                       logger.log( Level.SEVERE, e.getMessage(), e );
+                               }
+
+                               count++;
+                               logger.info( "wait data... count:" + count );
+
+                       }
+
+                       receivedData = dataTranfer.receivedData;
+                       dataTranfer.receivedData = null;
+                       
+                       return receivedData;
+
+               }
+
+       }
+       
+       public Socket getSocket() {
+               return socket;
+       }
+
+       public synchronized boolean isSensorDaemonStarted() {
+               return isSensorDaemonStarted;
+       }
+
+       private void increaseHeartbeatCount() {
+               int count = heartbeatCount.incrementAndGet();
+               if ( logger.isLoggable( Level.FINE ) ) {
+                       logger.fine( "HB count : " + count );
+               }
+       }
+
+       private boolean isHeartbeatExpired() {
+               return HEART_BEAT_EXPIRE < heartbeatCount.get();
+       }
+
+       private void resetHeartbeatCount() {
+               heartbeatCount.set( 0 );
+       }
+
+       @Override
+       public void terminate() {
+               
+               isTerminated = true;
+               
+               if ( null != heartbeatExecutor ) {
+                       heartbeatExecutor.shutdownNow();
+               }
+               
+               if( null != sendThread ) {
+                       synchronized ( sendThread ) {
+                               sendThread.notifyAll();
+                       }
+               }
+               
+               IOUtil.closeSocket( socket );
+               
+               synchronized ( this ) {
+                       skin.shutdown();
+               }
+               
+       }
+
+       public void resetSkin( EmulatorSkin skin ) {
+               synchronized ( this ) {
+                       this.skin = skin;
+               }
+       }
+
+}
+
+class SkinSendData {
+
+       private SendCommand command;
+       private ISendData data;
+
+       public SkinSendData( SendCommand command, ISendData data ) {
+               this.command = command;
+               this.data = data;
+       }
+
+       public SendCommand getCommand() {
+               return command;
+       }
+
+       public ISendData getSendData() {
+               return data;
+       }
+
+}
\ No newline at end of file
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/AbstractSendData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/AbstractSendData.java
new file mode 100644 (file)
index 0000000..a3e639c
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public abstract class AbstractSendData implements ISendData {
+       
+       private DataOutputStream dos;
+       private ByteArrayOutputStream bao;
+       
+       public AbstractSendData() {
+               bao = new ByteArrayOutputStream();
+               dos = new DataOutputStream( bao );
+       }
+       
+       protected abstract void write() throws IOException ;
+       
+       @Override
+       public byte[] serialize() throws IOException {
+               write();
+               return bao.toByteArray();
+       }
+
+       protected void writeShort ( int val ) throws IOException {
+               dos.writeShort( val );
+       }
+
+       protected void writeInt ( int val ) throws IOException {
+               dos.writeInt( val );
+       }
+
+       protected void writeLong ( int val ) throws IOException {
+               dos.writeLong( val );
+       }
+
+       protected void writeBoolean ( boolean val ) throws IOException {
+               dos.writeBoolean( val );
+       }
+
+       protected void writeChar ( char val ) throws IOException {
+               dos.writeChar( val );
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/BooleanData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/BooleanData.java
new file mode 100644 (file)
index 0000000..63e409e
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public class BooleanData extends AbstractSendData {
+
+       private boolean booleanValue;
+       private String dataName;
+       
+       public BooleanData( boolean booleanValue ) {
+               this.booleanValue = booleanValue;
+       }
+
+       public BooleanData( boolean booleanValue, String dataName) {
+               this.booleanValue = booleanValue;
+               this.dataName = dataName;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.tizen.emulator.skin.comm.sock.data.AbstractSendData#write()
+        */
+       @Override
+       protected void write() throws IOException {
+               writeBoolean( booleanValue );
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append( "BooleanData [booleanValue=" );
+               builder.append( booleanValue );
+               builder.append( ", dataName=" );
+               builder.append( dataName );
+               builder.append( "]" );
+               return builder.toString();
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/ISendData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/ISendData.java
new file mode 100644 (file)
index 0000000..c68db5e
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public interface ISendData {
+       
+       public byte[] serialize() throws IOException;
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/KeyEventData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/KeyEventData.java
new file mode 100644 (file)
index 0000000..bb4260f
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public class KeyEventData extends AbstractSendData {
+
+       int eventType;
+       int keycode;
+       int keyLocation;
+
+       public KeyEventData(int eventType, int keycode, int keyLocation) {
+               this.eventType = eventType;
+               this.keycode = keycode;
+               this.keyLocation = keyLocation;
+       }
+       
+       @Override
+       protected void write() throws IOException {
+               writeInt(eventType);
+               writeInt(keycode);
+               writeInt(keyLocation);
+       }
+       
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("KeyEventData [eventType=");
+               builder.append(eventType);
+               builder.append(", keycode=");
+               builder.append(keycode);
+               builder.append(", keyLocation=");
+               builder.append(keyLocation);
+               builder.append("]");
+               return builder.toString();
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/LcdStateData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/LcdStateData.java
new file mode 100644 (file)
index 0000000..0b05b44
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public class LcdStateData extends AbstractSendData {
+       
+       int scale;
+       short rotation;
+       
+       public LcdStateData(int scale, short rotation) {
+               this.scale = scale;
+               this.rotation = rotation;
+       }
+
+       @Override
+       protected void write() throws IOException {
+               writeInt(scale);
+               writeShort(rotation);
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("LcdStateData [scale=");
+               builder.append(scale);
+               builder.append(", rotation=");
+               builder.append(rotation);
+               builder.append("]");
+               return builder.toString();
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/MouseEventData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/MouseEventData.java
new file mode 100644 (file)
index 0000000..1733b4d
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public class MouseEventData extends AbstractSendData {
+
+       int eventType;
+       int x;
+       int y;
+       int z;
+
+       public MouseEventData(int eventType, int x, int y, int z) {
+               this.eventType = eventType;
+               this.x = x;
+               this.y = y;
+               this.z = z;
+       }
+
+       @Override
+       protected void write() throws IOException {
+               writeInt(eventType);
+               writeInt(x);
+               writeInt(y);
+               writeInt(z);
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("MouseEventData [eventType=");
+               builder.append(eventType);
+               builder.append(", x=");
+               builder.append(x);
+               builder.append(", y=");
+               builder.append(y);
+               builder.append(", z=");
+               builder.append(z);
+               builder.append("]");
+               return builder.toString();
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/StartData.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/StartData.java
new file mode 100644 (file)
index 0000000..0edbf37
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.comm.sock.data;
+
+import java.io.IOException;
+
+/**
+ * 
+ *
+ */
+public class StartData extends AbstractSendData {
+
+       private int windowHandleId;
+       private int lcdSizeWidth;
+       private int lcdSizeHeight;
+       private int scale;
+       private short rotation;
+       
+       public StartData(int windowHandleId, int lcdSizeWidth, int lcdSizeHeight, int scale, short rotation ) {
+               this.windowHandleId = windowHandleId;
+               this.lcdSizeWidth = lcdSizeWidth;
+               this.lcdSizeHeight = lcdSizeHeight;
+               this.scale = scale;
+               this.rotation = rotation;
+       }
+
+       @Override
+       protected void write() throws IOException {
+               writeInt( windowHandleId );
+               writeInt( lcdSizeWidth );
+               writeInt( lcdSizeHeight );
+               writeInt( scale );
+               writeShort( rotation );
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("StartData [windowHandleId=");
+               builder.append(windowHandleId);
+               builder.append(", lcd size " + lcdSizeWidth +"x" + lcdSizeHeight);
+               builder.append(", scale=");
+               builder.append(scale);
+               builder.append(", rotation=");
+               builder.append(rotation);
+               builder.append("]");
+               return builder.toString();
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/config/EmulatorConfig.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/config/EmulatorConfig.java
new file mode 100644 (file)
index 0000000..0c46b1b
--- /dev/null
@@ -0,0 +1,417 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.config;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
+import org.tizen.emulator.skin.comm.ICommunicator.Scale;
+import org.tizen.emulator.skin.dbi.EmulatorUI;
+import org.tizen.emulator.skin.exception.ConfigException;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.log.SkinLogger.SkinLogLevel;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+
+/**
+ * 
+ *
+ */
+public class EmulatorConfig {
+
+       private static Logger logger = SkinLogger.getSkinLogger( EmulatorConfig.class ).getLogger();
+
+       public static final int DEFAULT_WINDOW_SCALE = Scale.SCALE_50.value();
+       public static final short DEFAULT_WINDOW_ROTATION = RotationInfo.PORTRAIT.id();
+       public static final int DEFAULT_WINDOW_X = 50;
+       public static final int DEFAULT_WINDOW_Y = 50;
+       public static final SkinLogLevel DEFAULT_LOG_LEVEL = SkinLogLevel.DEBUG;
+
+       public interface ArgsConstants {
+               public static final String UID = "uid";
+               public static final String SERVER_PORT = "svr.port";
+               public static final String RESOLUTION_WIDTH = "width";
+               public static final String RESOLUTION_HEIGHT = "height";
+               public static final String TEST_HEART_BEAT_IGNORE = "test.hb.ignore";
+               public static final String VM_PATH = "vm.path";
+               public static final String LOG_LEVEL = "log.level";
+               public static final String NET_BASE_PORT = "net.baseport";
+               public static final String SKIN_PATH = "skin.path";
+       }
+
+       public interface SkinPropertiesConstants {
+               public static final String WINDOW_X = "window.x";
+               public static final String WINDOW_Y = "window.y";
+               public static final String WINDOW_ROTATION = "window.rotate";
+               public static final String WINDOW_SCALE = "window.scale";
+               public static final String WINDOW_ONTOP = "window.ontop"; // always on top
+       }
+
+       public interface ConfigPropertiesConstants {
+               public static final String TEST_HEART_BEAT_IGNORE = "test.hb.ignore";
+               public static final String LOG_LEVEL = "log.level";
+       }
+
+       private Map<String, String> args;
+       private EmulatorUI dbiContents;
+       private Properties skinProperties;
+       private Properties configProperties;
+       private String skinPropertiesFilePath;
+
+       public EmulatorConfig( Map<String, String> args, EmulatorUI dbiContents, Properties skinProperties,
+                       String skinPropertiesFilePath, Properties configProperties ) {
+               this.args = args;
+               this.dbiContents = dbiContents;
+               this.skinProperties = skinProperties;
+               this.skinPropertiesFilePath = skinPropertiesFilePath;
+               this.configProperties = configProperties;
+               if ( null == configProperties ) {
+                       this.configProperties = new Properties();
+               }
+       }
+
+       public static void validateArgs( Map<String, String> args ) throws ConfigException {
+               if ( null == args ) {
+                       return;
+               }
+
+               if( args.containsKey( ArgsConstants.UID ) ) {
+                       String uid = args.get( ArgsConstants.UID );
+                       try {
+                               Integer.parseInt( uid );
+                       } catch ( NumberFormatException e ) {
+                               String msg = ArgsConstants.UID + " argument is not numeric. : " + uid;
+                               throw new ConfigException( msg );
+                       }
+               }
+
+               if( args.containsKey( ArgsConstants.SERVER_PORT ) ) {
+                       String serverPort = args.get( ArgsConstants.SERVER_PORT );
+                       try {
+                               Integer.parseInt( serverPort );
+                       } catch ( NumberFormatException e ) {
+                               String msg = ArgsConstants.SERVER_PORT + " argument is not numeric. : " + serverPort;
+                               throw new ConfigException( msg );
+                       }
+               }else {
+                       String msg = ArgsConstants.SERVER_PORT + " is required argument.";
+                       throw new ConfigException( msg );
+               }
+
+               if( args.containsKey( ArgsConstants.RESOLUTION_WIDTH ) ) {
+                       String width = args.get( ArgsConstants.RESOLUTION_WIDTH );
+                       try {
+                               Integer.parseInt( width );
+                       } catch ( NumberFormatException e ) {
+                               String msg = ArgsConstants.RESOLUTION_WIDTH + " argument is not numeric. : " + width;
+                               throw new ConfigException( msg );
+                       }
+               }else {
+                       String msg = ArgsConstants.RESOLUTION_WIDTH + " is required argument.";
+                       throw new ConfigException( msg );
+               }
+
+               if( args.containsKey( ArgsConstants.RESOLUTION_HEIGHT ) ) {
+                       String height = args.get( ArgsConstants.RESOLUTION_HEIGHT );
+                       try {
+                               Integer.parseInt( height );
+                       } catch ( NumberFormatException e ) {
+                               String msg = ArgsConstants.RESOLUTION_HEIGHT + " argument is not numeric. : " + height;
+                               throw new ConfigException( msg );
+                       }
+               }else {
+                       String msg = ArgsConstants.RESOLUTION_HEIGHT + " is required argument.";
+                       throw new ConfigException( msg );
+               }
+
+       }
+
+       public static void validateSkinProperties( Properties skinProperties ) throws ConfigException {
+               if ( null == skinProperties || 0 == skinProperties.size() ) {
+                       return;
+               }
+
+               Rectangle monitorBound = Display.getDefault().getBounds();
+               logger.info("current display size : " + monitorBound);
+
+               if( skinProperties.containsKey( SkinPropertiesConstants.WINDOW_X ) ) {
+                       String x = skinProperties.getProperty( SkinPropertiesConstants.WINDOW_X );
+                       int xx = 0;
+
+                       try {
+                               xx = Integer.parseInt( x );
+                       } catch ( NumberFormatException e ) {
+                               String msg = SkinPropertiesConstants.WINDOW_X + " in .skin.properties is not numeric. : " + x;
+                               throw new ConfigException( msg );
+                       }
+
+                       //location correction
+                       if (xx < monitorBound.x) {
+                               int correction = monitorBound.x;
+                               logger.info("WINDOW_X = " + xx + ", set to " + correction);
+                               xx = correction;
+                       } else if (xx > monitorBound.x + monitorBound.width - 30) {
+                               int correction = monitorBound.x + monitorBound.width - 100;
+                               logger.info("WINDOW_X = " + xx + ", set to " + correction);
+                               xx = correction;
+                       } else {
+                               logger.info("WINDOW_X = " + xx);
+                       }
+
+                       skinProperties.setProperty(SkinPropertiesConstants.WINDOW_X, "" + xx);
+               }
+
+               if( skinProperties.containsKey( SkinPropertiesConstants.WINDOW_Y ) ) {
+                       String y = skinProperties.getProperty( SkinPropertiesConstants.WINDOW_Y );
+                       int yy = 0;
+
+                       try {
+                               yy = Integer.parseInt( y );
+                       } catch ( NumberFormatException e ) {
+                               String msg = SkinPropertiesConstants.WINDOW_Y + " in .skin.properties is not numeric. : " + y;
+                               throw new ConfigException( msg );
+                       }
+
+                       //location correction
+                       if (yy < monitorBound.y) {
+                               int correction = monitorBound.y;
+                               logger.info("WINDOW_Y = " + yy + ", set to " + correction);
+                               yy = correction;
+                       } else if (yy > monitorBound.y + monitorBound.height - 30) {
+                               int correction = monitorBound.y + monitorBound.height - 100;
+                               logger.info("WINDOW_Y = " + yy + ", set to " + correction);
+                               yy = correction;
+                       } else {
+                               logger.info("WINDOW_Y = " + yy);
+                       }
+
+                       skinProperties.setProperty(SkinPropertiesConstants.WINDOW_Y, "" + yy);
+               }
+
+               if( skinProperties.containsKey( SkinPropertiesConstants.WINDOW_ROTATION ) ) {
+                       String rotation = skinProperties.getProperty( SkinPropertiesConstants.WINDOW_ROTATION );
+                       try {
+                               Integer.parseInt( rotation );
+                       } catch ( NumberFormatException e ) {
+                               String msg = SkinPropertiesConstants.WINDOW_ROTATION + " in .skin.properties is not numeric. : " + rotation;
+                               throw new ConfigException( msg );
+                       }
+               }
+
+               if( skinProperties.containsKey( SkinPropertiesConstants.WINDOW_SCALE ) ) {
+                       String scale = skinProperties.getProperty( SkinPropertiesConstants.WINDOW_SCALE );
+                       try {
+                               Integer.parseInt( scale );
+                       } catch ( NumberFormatException e ) {
+                               String msg = SkinPropertiesConstants.WINDOW_SCALE + " in .skin.properties is not numeric. : " + scale;
+                               throw new ConfigException( msg );
+                       }
+               }
+
+       }
+
+       public static void validateSkinConfigProperties( Properties skinConfigProperties ) throws ConfigException {
+               if ( null == skinConfigProperties || 0 == skinConfigProperties.size() ) {
+                       return;
+               }
+       }
+
+       public void saveSkinProperties() {
+
+               File file = new File( skinPropertiesFilePath );
+
+               if ( !file.exists() ) {
+
+                       try {
+                               if ( !file.createNewFile() ) {
+                                       return;
+                               }
+                       } catch ( IOException e ) {
+                               logger.log( Level.SEVERE, "Fail to create skin properties file.", e );
+                               return;
+                       }
+
+               }
+
+               FileOutputStream fos = null;
+
+               try {
+
+                       fos = new FileOutputStream( file );
+                       skinProperties.store( fos, "Automatically generated by emulator skin." );
+
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } finally {
+                       IOUtil.close( fos );
+               }
+
+       }
+
+       public EmulatorUI getDbiContents() {
+               return dbiContents;
+       }
+
+       public String getArg( String argKey ) {
+               return args.get( argKey );
+       }
+
+       public String getArg( String argKey, String defaultValue ) {
+               String arg = args.get( argKey );
+               if ( StringUtil.isEmpty( arg ) ) {
+                       return defaultValue;
+               } else {
+                       return arg;
+               }
+       }
+
+       public int getArgInt( String argKey ) {
+               String arg = args.get( argKey );
+               if ( StringUtil.isEmpty( arg ) ) {
+                       return 0;
+               }
+               return Integer.parseInt( arg );
+       }
+
+       public int getArgInt( String argKey, int defaultValue ) {
+               String arg = args.get( argKey );
+               if ( StringUtil.isEmpty( arg ) ) {
+                       return defaultValue;
+               }
+               return Integer.parseInt( arg );
+       }
+
+       public boolean getArgBoolean( String argKey ) {
+               String arg = args.get( argKey );
+               return Boolean.parseBoolean( arg );
+       }
+
+       private String getProperty( Properties properties, String key ) {
+               return properties.getProperty( key );
+       }
+
+       private String getProperty( Properties properties, String key, String defaultValue ) {
+               String property = properties.getProperty( key );
+               if ( StringUtil.isEmpty( property ) ) {
+                       return defaultValue;
+               }
+               return property;
+       }
+
+       private int getPropertyInt( Properties properties, String key ) {
+               return Integer.parseInt( properties.getProperty( key ) );
+       }
+
+       private int getPropertyInt( Properties properties, String key, int defaultValue ) {
+               String property = properties.getProperty( key );
+               if ( StringUtil.isEmpty( property ) ) {
+                       return defaultValue;
+               }
+               return Integer.parseInt( property );
+       }
+
+       private short getPropertyShort( Properties properties, String key ) {
+               return Short.parseShort( properties.getProperty( key ) );
+       }
+
+       private short getPropertyShort( Properties properties, String key, short defaultValue ) {
+               String property = properties.getProperty( key );
+               if ( StringUtil.isEmpty( property ) ) {
+                       return defaultValue;
+               }
+               return Short.parseShort( property );
+       }
+
+       private void setProperty( Properties properties, String key, String value ) {
+               properties.put( key, value );
+       }
+
+       private void setProperty( Properties properties, String key, int value ) {
+               properties.put( key, Integer.toString( value ) );
+       }
+
+       // skin properties //
+
+       public String getSkinProperty( String key ) {
+               return getProperty( skinProperties, key );
+       }
+
+       public String getSkinProperty( String key, String defaultValue ) {
+               return getProperty( skinProperties, key, defaultValue );
+       }
+
+       public int getSkinPropertyInt( String key ) {
+               return getPropertyInt( skinProperties, key );
+       }
+
+       public int getSkinPropertyInt( String key, int defaultValue ) {
+               return getPropertyInt( skinProperties, key, defaultValue );
+       }
+
+       public short getSkinPropertyShort( String key ) {
+               return getPropertyShort( skinProperties, key );
+       }
+
+       public short getSkinPropertyShort( String key, short defaultValue ) {
+               return getPropertyShort( skinProperties, key, defaultValue );
+       }
+
+       public void setSkinProperty( String key, String value ) {
+               setProperty( skinProperties, key, value );
+       }
+
+       public void setSkinProperty( String key, int value ) {
+               setProperty( skinProperties, key, value );
+       }
+
+       // config properties //
+
+       public String getConfigProperty( String key ) {
+               return getProperty( configProperties, key );
+       }
+
+       public String getConfigProperty( String key, String defaultValue ) {
+               return getProperty( configProperties, key, defaultValue );
+       }
+
+       public int getConfigPropertyInt( String key, int defaultValue ) {
+               return getPropertyInt( configProperties, key, defaultValue );
+       }
+
+}
\ No newline at end of file
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/AboutDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/AboutDialog.java
new file mode 100644 (file)
index 0000000..bc765ba
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.dialog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+public class AboutDialog extends SkinDialog {
+       
+       public static final String ABOUT_PROP_FILENAME = "about.properties";
+       
+       public static final String PROP_KEY_VERSION = "version";
+       public static final String PROP_KEY_BUILD_TIME = "build_time";
+       public static final String PROP_KEY_GIT_VERSION = "build_git_commit";
+       
+       private Logger logger = SkinLogger.getSkinLogger( AboutDialog.class ).getLogger();
+
+       public AboutDialog( Shell parent ) {
+               super( parent, "About Tizen Emulator", SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL );
+       }
+
+       @Override
+       protected Composite createArea( Composite parent ) {
+               Composite composite = displayInfo( parent );
+               return composite;
+       }
+
+       private Composite displayInfo( Composite parent ) {
+
+               Composite composite = new Composite( parent, SWT.NONE );
+               
+               composite.setLayout( new GridLayout( 1, false ) );
+
+               Label titleLabel = new Label( composite, SWT.NONE );
+               GridData gridData = new GridData();
+               gridData.grabExcessHorizontalSpace = true;
+               gridData.horizontalAlignment = SWT.CENTER;
+               titleLabel.setLayoutData( gridData );
+
+               titleLabel.setText( "Tizen Emulator" );
+               Font systemFont = shell.getDisplay().getSystemFont();
+               FontData[] fontData = systemFont.getFontData();
+               fontData[0].setStyle( SWT.BOLD );
+               fontData[0].setHeight( 16 );
+               Font font = new Font( shell.getDisplay(), fontData[0] );
+               titleLabel.setFont( font );
+               font.dispose();
+
+               Properties properties = getProperties();
+               
+               Text versionText = new Text( composite, SWT.NONE );
+               String version = getValue( properties, PROP_KEY_VERSION );
+               versionText.setText( "Version" + "        : " + version );
+               versionText.setEditable( false );
+               versionText.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) );
+
+               Text buildText = new Text( composite, SWT.NONE );
+               String time = getValue( properties, PROP_KEY_BUILD_TIME );
+               buildText.setText( "Build time" + "  : " + time + " (GMT)" );
+               buildText.setEditable( false );
+               buildText.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) );
+
+               Text gitText = new Text( composite, SWT.NONE );
+               String gitVersion = getValue( properties, PROP_KEY_GIT_VERSION );
+               gitText.setText( "Git version" + " : " + gitVersion );
+               gitText.setEditable( false );
+               gitText.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) );
+
+               return composite;
+
+       }
+
+       private String getValue( Properties properties, String key ) {
+               
+               if( null != properties ) {
+
+                       String property = properties.getProperty( key );
+                       
+                       if( !StringUtil.isEmpty( property ) ) {
+                               
+                               if( !property.contains( key ) ) {
+                                       return property;
+                               }else {
+                                       // ex) '${build_git_commit}' is default expression in build.xml
+                                       return "Not identified";
+                               }
+                               
+                       }else {
+                               return "Not identified";
+                       }
+
+               }else {
+                       return "Not identified";
+               }
+               
+       }
+       
+       @Override
+       protected void createButtons( Composite parent ) {
+
+               super.createButtons( parent );
+
+               Button licenseButton = createButton( parent, "License" );
+               licenseButton.addSelectionListener( new SelectionAdapter() {
+                       private boolean isOpen;
+
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               if ( !isOpen ) {
+                                       isOpen = true;
+                                       LicenseDialog licenseDialog = new LicenseDialog( shell, "License" );
+                                       licenseDialog.open();
+                                       isOpen = false;
+                               }
+                       }
+               } );
+
+               createOKButton( parent, true );
+
+       }
+
+       private Properties getProperties() {
+
+               InputStream is = null;
+               Properties properties = null;
+               try {
+
+                       is = this.getClass().getClassLoader().getResourceAsStream( ABOUT_PROP_FILENAME );
+                       if ( null == is ) {
+                               logger.severe( "about properties file is null." );
+                               return null;
+                       }
+
+                       properties = new Properties();
+                       properties.load( is );
+
+               } catch ( IOException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+                       return null;
+               } finally {
+                       IOUtil.close( is );
+               }
+
+               return properties;
+
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java
new file mode 100644 (file)
index 0000000..be8d2bd
--- /dev/null
@@ -0,0 +1,339 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.dialog;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator.DataTranfer;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.SkinUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+/**
+ * 
+ *
+ */
+public class DetailInfoDialog extends SkinDialog {
+
+       public final static String DATA_DELIMITER = "#";
+
+       private Logger logger = SkinLogger.getSkinLogger( DetailInfoDialog.class ).getLogger();
+
+       private SocketCommunicator communicator;
+       private EmulatorConfig config;
+
+       public DetailInfoDialog( Shell parent, String emulatorName, SocketCommunicator communicator, EmulatorConfig config ) {
+               super( parent, "Detail Info" + " - " + emulatorName, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE
+                               | SWT.MAX );
+               this.communicator = communicator;
+               this.config = config;
+       }
+
+       @Override
+       protected Composite createArea( Composite parent ) {
+
+               String infoData = queryData();
+               if ( StringUtil.isEmpty( infoData ) ) {
+                       return null;
+               }
+
+               Composite composite = new Composite( parent, SWT.NONE );
+               composite.setLayout( new FillLayout() );
+
+               Table table = new Table( composite, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION );
+               table.setHeaderVisible( true );
+               table.setLinesVisible( true );
+
+               TableColumn[] column = new TableColumn[2];
+
+               column[0] = new TableColumn( table, SWT.LEFT );
+               column[0].setText( "Name" );
+
+               column[1] = new TableColumn( table, SWT.LEFT );
+               column[1].setText( "Value" );
+
+               int index = 0;
+
+               LinkedHashMap<String, String> refinedData = composeAndParseData( infoData );
+               Iterator<Entry<String, String>> iterator = refinedData.entrySet().iterator();
+
+               while ( iterator.hasNext() ) {
+
+                       Entry<String, String> entry = iterator.next();
+
+                       TableItem tableItem = new TableItem( table, SWT.NONE, index );
+                       tableItem.setText( new String[] { entry.getKey(), entry.getValue() } );
+                       index++;
+
+               }
+
+               column[0].pack();
+               column[1].pack();
+
+               table.pack();
+
+               return composite;
+
+       }
+
+       @Override
+       protected void setShellSize() {
+               if( SkinUtil.isLinuxPlatform() ) {
+                       shell.setSize( (int) ( 380 * 1.618 ), 380 );
+               }else {
+                       shell.setSize( (int) ( 350 * 1.618 ), 350 );
+               }
+       }
+
+       private String queryData() {
+
+               String infoData = null;
+
+               DataTranfer dataTranfer = communicator.sendToQEMU( SendCommand.DETAIL_INFO, null, true );
+               byte[] receivedData = communicator.getReceivedData( dataTranfer );
+
+               if ( null != receivedData ) {
+                       infoData = new String( receivedData );
+               } else {
+                       logger.severe( "Fail to get detail info." );
+                       SkinUtil.openMessage( shell, null, "Fail to get detail info.", SWT.ICON_ERROR, config );
+               }
+
+               return infoData;
+
+       }
+
+       private LinkedHashMap<String, String> composeAndParseData( String infoData ) {
+
+               logger.info( "Received infoData:" + infoData );
+
+               String cpu = "";
+               String ram = "";
+               String dpi = "";
+               String sdPath = "";
+               String imagePath = "";
+               boolean isFirstDrive = true;
+               String sharedPath = "";
+               boolean isHwVirtual = false;
+               String hwVirtualCompare = "";
+               String haxError = "hax_error=";
+               boolean isHaxError = false;
+               
+               if ( SkinUtil.isLinuxPlatform() ) {
+                       hwVirtualCompare = "-enable-kvm";
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+                       hwVirtualCompare = "-enable-hax";
+               }
+               
+               String[] split = infoData.split( DATA_DELIMITER );
+
+               for ( int i = 0; i < split.length; i++ ) {
+
+                       if ( 0 == i ) {
+
+                               String exec = split[i].trim().toLowerCase();
+                               if( SkinUtil.isWindowsPlatform() ) {
+                                       if( 4 <= exec.length() ) {
+                                               // remove '.exe' in Windows
+                                               exec = exec.substring( 0, exec.length() - 4 );
+                                       }
+                               }
+                               
+                               if ( exec.endsWith( "x86" ) ) {
+                                       cpu = "x86";
+                               } else if ( exec.endsWith( "arm" ) ) {
+                                       cpu = "ARM";
+                               }
+
+                       } else {
+
+                               if ( i + 1 <= split.length ) {
+
+                                       String arg = split[i].trim();
+
+                                       if ( "-m".equals( arg ) ) {
+
+                                               ram = split[i + 1].trim();
+
+                                       } else if ( "-drive".equals( arg ) ) {
+
+                                               // arg : file=/home/xxx/.tizen_vms/x86/xxx/emulimg-emulator.x86
+                                               arg = split[i + 1].trim();
+
+                                               if ( arg.startsWith( "file=" ) ) {
+
+                                                       String[] sp = arg.split( "," );
+                                                       String[] sp2 = sp[0].split( "=" );
+                                                       String drivePath = sp2[sp2.length - 1];
+
+                                                       if ( isFirstDrive ) {
+                                                               imagePath = drivePath;
+                                                               isFirstDrive = false;
+                                                       } else {
+                                                               sdPath = drivePath;
+                                                       }
+
+                                               }
+
+                                       } else if ( "-virtfs".equals( arg ) ) {
+
+                                               // arg : local,path=/home/xxx/xxx/xxx,security_model=none,mount_tag=fileshare
+                                               arg = split[i + 1].trim();
+                                               String[] sp = arg.split( "," );
+
+                                               if ( 1 < sp.length ) {
+                                                       int spIndex = sp[1].indexOf( "=" );
+                                                       sharedPath = sp[1].substring( spIndex + 1, sp[1].length() );
+                                               }
+
+                                       } else if ( "-append".equals( arg ) ) {
+
+                                               arg = split[i + 1].trim();
+
+                                               int idx = arg.indexOf( "dpi" );
+
+                                               if ( -1 != idx ) {
+                                                       if( idx + 7 <= arg.length() ) {
+                                                               
+                                                               dpi = arg.substring( idx, idx + 7 ); // end index is not 8, remove last '0'
+                                                               
+                                                               String[] sp = dpi.split( "=" );
+                                                               if ( 1 < sp.length ) {
+                                                                       dpi = sp[1];
+                                                               }
+                                                               
+                                                       }
+                                               }
+
+                                       } else if ( hwVirtualCompare.equals( arg ) ) {
+                                               isHwVirtual = true;
+                                       } else if ( arg.startsWith( haxError ) ) {
+                                               String[] sp = arg.split( "=" );
+                                               if( 1 < sp.length ) {
+                                                       isHaxError = Boolean.parseBoolean( sp[1] );
+                                               }
+                                       }
+
+                               }
+
+                       }
+
+               }
+
+               LinkedHashMap<String, String> result = new LinkedHashMap<String, String>();
+
+               result.put( "Name", SkinUtil.getVmName( config ) );
+               result.put( "CPU", cpu );
+
+               int width = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH );
+               int height = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT );
+               result.put( "Display Resolution", width + "x" + height );
+               result.put( "Display Density", dpi );
+
+               if ( StringUtil.isEmpty( sdPath ) ) {
+                       result.put( "SD Card", "Not Supported" );
+                       result.put( "SD Card Path", "None" );
+               } else {
+                       result.put( "SD Card", "Supported" );
+                       result.put( "SD Card Path", sdPath );
+               }
+
+               result.put( "RAM Size", ram );
+
+               if( SkinUtil.isLinuxPlatform() ) {
+                       if ( StringUtil.isEmpty( sharedPath ) ) {
+                               result.put( "File Sharing", "Not Supported" );
+                               result.put( "File Shared Path", "None" );
+                       }else {
+                               result.put( "File Sharing", "Supported" );
+                               result.put( "File Shared Path", sharedPath );
+                       }
+               }
+
+               if( isHwVirtual ) {
+                       if( isHaxError ) {
+                               result.put( "HW Virtualization State", "Disable(insufficient memory for driver)" );
+                       }else {
+                               result.put( "HW Virtualization State", "Enable" );
+                       }
+               }else {
+                       result.put( "HW Virtualization State", "Disable" );
+               }
+               
+               if ( StringUtil.isEmpty( imagePath ) ) {
+                       result.put( "Image Path", "Not identified" );                   
+               }else {
+                       result.put( "Image Path", imagePath );                  
+               }
+
+               return result;
+
+       }
+
+       protected void createButtons( Composite parent ) {
+               super.createButtons( parent );
+
+               Button okButton = createButton( parent, OK );
+
+               GridData gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.RIGHT;
+               okButton.setLayoutData( gd );
+
+               okButton.setFocus();
+
+               okButton.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               DetailInfoDialog.this.shell.close();
+                       }
+               } );
+
+       };
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/LicenseDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/LicenseDialog.java
new file mode 100644 (file)
index 0000000..7965e19
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.dialog;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+/**
+ * 
+ *
+ */
+public class LicenseDialog extends SkinDialog {
+
+       public static final String LICENSE_FILE_PATH = "../license/Open_Source_Announcement.txt";
+
+       private Logger logger = SkinLogger.getSkinLogger( LicenseDialog.class ).getLogger();
+
+       public LicenseDialog( Shell parent, String title ) {
+               super( parent, title, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE | SWT.MAX );
+       }
+
+       @Override
+       protected Composite createArea( Composite parent ) {
+
+               Composite composite = new Composite( parent, SWT.NONE );
+               composite.setLayout( new GridLayout() );
+
+               final Text text = new Text( composite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI );
+               GridData gridData = new GridData( SWT.FILL, SWT.FILL, true, true );
+               text.setLayoutData( gridData );
+
+               text.setEditable( false );
+               text.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_WHITE ) );
+               String license = StringUtil.nvl( getLicense() );
+               text.setText( license );
+
+               return composite;
+
+       }
+
+       @Override
+       protected void setShellSize() {
+               shell.setSize( (int) ( 400 * 1.618 ), 400 );
+       }
+
+       @Override
+       protected void createButtons( Composite parent ) {
+               super.createButtons( parent );
+
+               Button okButton = createButton( parent, OK );
+
+               GridData gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.RIGHT;
+               okButton.setLayoutData( gd );
+
+               okButton.setFocus();
+
+               okButton.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               LicenseDialog.this.shell.close();
+                       }
+               } );
+
+       }
+
+       private String getLicense() {
+
+               FileInputStream fis = null;
+               String string = "";
+
+               try {
+
+                       fis = new FileInputStream( LICENSE_FILE_PATH );
+
+                       try {
+                               byte[] bytes = IOUtil.getBytes( fis );
+                               string = new String( bytes, "UTF-8" );
+                       } catch ( IOException e ) {
+                               logger.log( Level.SEVERE, e.getMessage(), e );
+                               string = "File control error.";
+                       }
+
+               } catch ( FileNotFoundException e ) {
+                       string = "There is no license info.";
+               } finally {
+                       IOUtil.close( fis );
+               }
+
+               return string;
+
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/SkinDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/SkinDialog.java
new file mode 100644 (file)
index 0000000..063c595
--- /dev/null
@@ -0,0 +1,177 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.dialog;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Dialog;
+import org.eclipse.swt.widgets.Shell;
+import org.tizen.emulator.skin.util.StringUtil;
+
+/**
+ * 
+ *
+ */
+public abstract class SkinDialog extends Dialog {
+
+       public static final String OK = "        " + "OK" + "        ";
+       
+       protected Shell shell;
+       private boolean isReady;
+       private Composite buttonComposite;
+       private Shell parent;
+       private String title;
+       private int style;
+       
+       public SkinDialog( Shell parent, String title, int style ) {
+               super( parent, style );
+               this.parent = parent;
+               this.title = title;
+               this.style = style;
+       }
+       
+       public void open() {
+
+               shell = new Shell( parent, style );
+               shell.setLocation( parent.getLocation().x + 50, parent.getLocation().y + 50 );
+               shell.setText( title );
+               shell.setImage( parent.getImage() );
+               
+               shell.setLayout( new GridLayout( 1, true ) );
+
+               Composite parent = new Composite( shell, SWT.NONE );
+               parent.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
+               GridLayout gridLayout = new GridLayout( 1, true );
+               gridLayout.marginWidth = 20;
+               parent.setLayout( gridLayout );
+
+               Composite composite = new Composite( parent, SWT.NONE );
+               composite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
+               composite.setLayout( new FillLayout( SWT.VERTICAL ) );
+
+               Composite area = createArea( composite );
+               if ( null == area ) {
+                       return;
+               }
+
+               isReady = true;
+
+               buttonComposite = new Composite( parent, SWT.NONE );
+               buttonComposite.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false ) );
+               buttonComposite.setLayout( new FillLayout( SWT.HORIZONTAL ) );
+
+               createButtons( buttonComposite );
+               
+               shell.pack();
+
+               setShellSize();
+               
+               if ( !isReady ) {
+                       return;
+               }
+
+               if (this.parent != null) {
+                       Point central = new Point(
+                                       this.parent.getLocation().x + (this.parent.getSize().x / 2),
+                                       this.parent.getLocation().y + (this.parent.getSize().y / 2));
+
+                       shell.setLocation(
+                                       central.x - (shell.getSize().x / 2),
+                                       central.y - (shell.getSize().y / 2));
+               }
+
+               shell.open();
+
+               while ( !shell.isDisposed() ) {
+                       if ( !shell.getDisplay().readAndDispatch() ) {
+                               shell.getDisplay().sleep();
+                       }
+               }
+
+       }
+
+       protected void setShellSize() {
+       }
+       
+       protected abstract Composite createArea( Composite parent );
+
+       protected void createButtons( Composite parent ) {
+               if ( null == parent ) {
+                       throw new IllegalArgumentException( "Buttons parent is null" );
+               }
+       }
+
+       protected Button createButton( Composite parent, String text ) {
+
+               if ( null == parent ) {
+                       throw new IllegalArgumentException( "Button parent is null" );
+               }
+
+               Composite composite = new Composite( parent, SWT.NONE );
+               GridLayout gridLayout = new GridLayout( 1, true );
+               composite.setLayout( gridLayout );
+
+               Button button = new Button( composite, SWT.PUSH );
+               GridData gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.FILL;
+
+               button.setLayoutData( gd );
+               button.setText( StringUtil.nvl( text ) );
+               return button;
+
+       }
+
+       protected Button createOKButton( Composite parent, boolean setFocus ) {
+
+               Button okButton = createButton( parent, OK );
+               okButton.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+                               SkinDialog.this.shell.close();
+                       }
+               } );
+
+               if ( setFocus ) {
+                       okButton.setFocus();
+               }
+
+               return okButton;
+
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ConfigException.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ConfigException.java
new file mode 100644 (file)
index 0000000..a9cc442
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.exception;
+
+/**
+ * 
+ *
+ */
+public class ConfigException extends EmulatorException {
+
+       private static final long serialVersionUID = -1363305002416148505L;
+
+       public ConfigException() {
+               super();
+       }
+
+       public ConfigException( Throwable cause ) {
+               super( cause );
+       }
+
+    public ConfigException( String message ) {
+        super( message );
+    }
+
+    public ConfigException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/EmulatorException.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/EmulatorException.java
new file mode 100644 (file)
index 0000000..c61a9e1
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.exception;
+
+/**
+ * 
+ *
+ */
+public class EmulatorException extends Exception {
+
+       private static final long serialVersionUID = 7942446691090874775L;
+
+       public EmulatorException() {
+               super();
+       }
+
+       public EmulatorException( Throwable cause ) {
+               super( cause );
+       }
+
+    public EmulatorException( String message ) {
+        super( message );
+    }
+
+    public EmulatorException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/JaxbException.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/JaxbException.java
new file mode 100644 (file)
index 0000000..d52b6e9
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.exception;
+
+/**
+ * 
+ *
+ */
+public class JaxbException extends EmulatorException {
+
+       private static final long serialVersionUID = -8268951410660907299L;
+
+       public JaxbException() {
+               super();
+       }
+
+       public JaxbException( Throwable cause ) {
+               super( cause );
+       }
+
+    public JaxbException( String message ) {
+        super( message );
+    }
+
+    public JaxbException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ScreenShotException.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ScreenShotException.java
new file mode 100644 (file)
index 0000000..e584d62
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.exception;
+
+/**
+ * 
+ *
+ */
+public class ScreenShotException extends EmulatorException {
+
+       private static final long serialVersionUID = 7527776121326217994L;
+
+       public ScreenShotException() {
+               super();
+       }
+
+       public ScreenShotException( Throwable cause ) {
+               super( cause );
+       }
+
+    public ScreenShotException( String message ) {
+        super( message );
+    }
+
+    public ScreenShotException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/image/ImageRegistry.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/image/ImageRegistry.java
new file mode 100644 (file)
index 0000000..20924c3
--- /dev/null
@@ -0,0 +1,311 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.image;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.dbi.EmulatorUI;
+import org.tizen.emulator.skin.dbi.ImageListType;
+import org.tizen.emulator.skin.dbi.RotationType;
+import org.tizen.emulator.skin.dbi.RotationsType;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.SkinRotation;
+
+
+/**
+ * 
+ *
+ */
+public class ImageRegistry {
+       
+       private Logger logger = SkinLogger.getSkinLogger( ImageRegistry.class ).getLogger();
+
+       public static final String SKIN_FOLDER = "skins";
+       public static final String IMAGE_FOLDER_PREFIX = "emul_";
+       public static final String ICON_FOLDER = "icons";
+       
+       public enum ImageType {
+               IMG_TYPE_MAIN,
+               IMG_TYPE_PRESSED
+       }
+       
+       public enum IconName {
+               
+               DETAIL_INFO( "detail_info.png" ),
+               ROTATE( "rotate.png" ),
+               SCALE( "scale.png" ),
+               SHELL( "shell.png" ),
+               ADVANCED( "advanced.png" ),
+               CLOSE( "close.png" ),
+               SCREENSHOT( "screenshot.png" ),
+               USB_KEBOARD( "usb_keyboard.png" ),
+               ABOUT( "about.png" ),
+
+               COPY_SCREEN_SHOT( "copy_screenshot_dialog.png" ),
+               REFRESH_SCREEN_SHOT( "refresh_screenshot_dialog.png" ),
+               SAVE_SCREEN_SHOT( "save_screenshot_dialog.png" ),
+
+               EMULATOR_TITLE( "Emulator_20x20.png" ),
+               EMULATOR_TITLE_ICO( "Emulator.ico" );
+               
+               private String name;
+               
+               private IconName( String name ) {
+                       this.name = name;
+               }
+               
+               public String getName() {
+                       return this.name;
+               }
+               
+       }
+       
+       private Display display;
+       private int resolutionWidth;
+       private int resolutionHeight;
+       private EmulatorUI dbiContents;
+
+       private Map<String, Image> skinImageMap;
+       private Map<String, Image> iconMap;
+
+       private String argSkinPath;
+
+       private static ImageRegistry instance;
+       private static boolean isInitialized;
+
+       private ImageRegistry() {
+       }
+
+       public static ImageRegistry getInstance() {
+               if ( null == instance ) {
+                       instance = new ImageRegistry();
+               }
+               return instance;
+       }
+
+       public void initialize( EmulatorConfig config ) {
+
+               if ( isInitialized ) {
+                       return;
+               }
+               isInitialized = true;
+
+               this.display = Display.getDefault();
+
+               int lcdWidth = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH );
+               int lcdHeight = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT );
+               this.argSkinPath = config.getArg( ArgsConstants.SKIN_PATH );
+
+               this.resolutionWidth = lcdWidth;
+               this.resolutionHeight = lcdHeight;
+               this.dbiContents = config.getDbiContents();
+               this.skinImageMap = new HashMap<String, Image>();
+               this.iconMap = new HashMap<String, Image>();
+
+               init( this.argSkinPath );
+
+       }
+
+       public static String getSkinPath( String argSkinPath, int lcdWidth, int lcdHeight ) {
+               String skinPath = ".." + File.separator + SKIN_FOLDER + File.separator + IMAGE_FOLDER_PREFIX + lcdWidth + "x"
+                               + lcdHeight;
+
+               if ( argSkinPath == null ) {
+                       return skinPath;
+               }
+
+               File f = new File( argSkinPath );
+               if ( f.isDirectory() == false ) {
+                       return skinPath;
+               }
+
+               return argSkinPath;
+       }
+
+       private void init( String argSkinPath ) {
+
+               RotationsType rotations = dbiContents.getRotations();
+
+               if ( null == rotations ) {
+                       logger.severe( "Fail to loading rotations element from dbi." );
+                       return;
+               }
+
+               List<RotationType> rotationList = rotations.getRotation();
+
+               for ( RotationType rotation : rotationList ) {
+                       SkinRotation.put( rotation );
+               }
+
+       }
+
+       public ImageData getSkinImageData( Short id, ImageType imageType ) {
+
+               Image image = skinImageMap.get( makeKey( id, imageType ) );
+
+               if ( null != image ) {
+
+                       return image.getImageData();
+
+               } else {
+
+                       RotationsType rotations = dbiContents.getRotations();
+
+                       if ( null == rotations ) {
+                               logger.severe( "Fail to loading rotations element from dbi." );
+                               return null;
+                       }
+
+                       String skinPath = getSkinPath( argSkinPath, resolutionWidth, resolutionHeight );
+
+                       RotationType targetRotation = SkinRotation.getRotation( id );
+
+                       List<RotationType> rotationList = rotations.getRotation();
+
+                       for ( RotationType rotation : rotationList ) {
+
+                               ImageListType imageList = rotation.getImageList();
+                               String mainImage = imageList.getMainImage();
+                               String keyPressedImage = imageList.getKeyPressedImage();
+
+                               if ( targetRotation.getName().value().equals( rotation.getName().value() ) ) {
+
+                                       String mainKey = makeKey( id, ImageType.IMG_TYPE_MAIN );
+                                       skinImageMap.put( mainKey, new Image( display, skinPath + File.separator + mainImage ) );
+
+                                       String pressedKey = makeKey( id, ImageType.IMG_TYPE_PRESSED );
+                                       skinImageMap.put( pressedKey, new Image( display, skinPath + File.separator + keyPressedImage ) );
+
+                                       break;
+
+                               }
+
+                       }
+
+                       Image registeredImage = skinImageMap.get( makeKey( id, imageType ) );
+
+                       if ( null != registeredImage ) {
+                               return registeredImage.getImageData();
+                       } else {
+                               return null;
+                       }
+
+               }
+       }
+
+       private String makeKey( Short id, ImageType imageType ) {
+               return id + ":" + imageType.ordinal();
+       }
+
+       public Image getIcon( IconName name ) {
+
+               if ( 0 != iconMap.size() ) {
+
+                       Image image = iconMap.get( name.getName() );
+                       return image;
+
+               } else {
+
+                       // load all of the icons at once.
+
+                       ClassLoader classLoader = this.getClass().getClassLoader();
+                       IconName[] values = IconName.values();
+
+                       for ( IconName iconName : values ) {
+
+                               String icoNname = iconName.getName();
+
+                               String iconPath = ICON_FOLDER + "/" + icoNname;
+
+                               InputStream is = null;
+                               try {
+                                       is = classLoader.getResourceAsStream( iconPath );
+                                       if ( null != is ) {
+                                               logger.fine( "load icon:" + iconPath );
+                                               iconMap.put( icoNname, new Image( display, is ) );
+                                       } else {
+                                               logger.severe( "missing icon:" + iconPath );
+                                       }
+                               } finally {
+                                       IOUtil.close( is );
+                               }
+
+                       }
+
+                       return iconMap.get( name.getName() );
+
+               }
+
+       }
+
+       public void dispose() {
+
+               if ( null != skinImageMap ) {
+
+                       Collection<Image> images = skinImageMap.values();
+
+                       Iterator<Image> imageIterator = images.iterator();
+
+                       while ( imageIterator.hasNext() ) {
+                               Image image = imageIterator.next();
+                               image.dispose();
+                       }
+
+               }
+
+               if ( null != iconMap ) {
+
+                       Collection<Image> icons = iconMap.values();
+
+                       Iterator<Image> iconIterator = icons.iterator();
+
+                       while ( iconIterator.hasNext() ) {
+                               Image image = iconIterator.next();
+                               image.dispose();
+                       }
+
+               }
+
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java
new file mode 100644 (file)
index 0000000..fd9661c
--- /dev/null
@@ -0,0 +1,257 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.FileHandler;
+import java.util.logging.Formatter;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.tizen.emulator.skin.util.StringUtil;
+
+/**
+ * 
+ *
+ */
+public class SkinLogger {
+       
+       public static final String LOG_FOLDER = "logs";
+       
+       public enum SkinLogLevel {
+               
+               ERROR(Level.SEVERE, "error"),
+               WARN(Level.WARNING, "warn"),
+               DEBUG(Level.INFO, "debug"),
+               TRACE(Level.FINE, "trace");
+               
+               private Level level;
+               private String value;
+               private SkinLogLevel( Level level, String value ) {
+                       this.level = level;
+                       this.value = value;
+               }
+               public Level level() {
+                       return this.level;
+               }
+               public String value() {
+                       return this.value;
+               }
+       }
+       
+       private static final String FILE_NAME = "emulator-skin.log";
+       
+       private static FileHandler fileHandler;
+       private static boolean isInit;
+       private static Map<Class<?>, SkinLogger> loggerMap = new HashMap<Class<?>, SkinLogger>();
+       
+       private Logger logger;
+       
+       private SkinLogger( Logger logger ) {
+               this.logger = logger;
+       }
+       
+       public Logger getLogger() {
+               return this.logger;
+       }
+
+       public static void setLevel( Level level ) {
+               if( null != fileHandler ) {
+                       fileHandler.setLevel( level );
+               }
+       }
+
+       
+       public static void init( SkinLogLevel logLevel, String filePath ) {
+               
+               if( !isInit ) {
+                       
+                       isInit = true;
+                       
+                       String path = "";
+                       
+                       if( !StringUtil.isEmpty( filePath ) ) {
+                               path = filePath + File.separator;
+                       }
+
+                       File dir = new File( path + LOG_FOLDER );
+                       dir.mkdir();
+                       
+                       // delete .lck files after abnomal skin termination
+                       File[] listFiles = dir.listFiles();
+                       for ( File f : listFiles ) {
+                               String name = f.getName();
+                               if ( !FILE_NAME.equals( name ) && name.startsWith( FILE_NAME ) ) {
+                                       f.delete();
+                               }
+                       }
+                       
+                       File file = new File( dir + File.separator + FILE_NAME );
+                       if( !file.exists() ) {
+                               try {
+                                       if( !file.createNewFile() ) {
+                                               System.err.println( "[SkinLog:error]Cannot create skin log file. path:" + file.getAbsolutePath() );
+                                               System.exit( -1 );
+                                               return;
+                                       }
+                               } catch ( IOException e ) {
+                                       e.printStackTrace();
+                                       System.exit( -1 );
+                                       return;
+                               }
+                       }
+                       
+                       try {
+                               fileHandler = new FileHandler( file.getAbsolutePath(), false );
+                       } catch ( SecurityException e1 ) {
+                               e1.printStackTrace();
+                       } catch ( IOException e1 ) {
+                               e1.printStackTrace();
+                       }
+
+                       try {
+                               fileHandler.setEncoding( "UTF-8" );
+                       } catch ( SecurityException e ) {
+                               e.printStackTrace();
+                       } catch ( UnsupportedEncodingException e ) {
+                               e.printStackTrace();
+                       }
+                       
+                       fileHandler.setFormatter( new SkinFormatter() );
+                       fileHandler.setLevel( logLevel.level() );
+                       
+               }
+               
+       }
+       
+       public static void end() {
+               loggerMap.clear();
+       }
+       
+       public static <T> SkinLogger getSkinLogger( Class<T> clazz ) {
+               
+               String name = null;
+               
+               if( null == clazz ) {
+                       name = SkinLogger.class.getName();
+               }else {
+                       name = clazz.getName();
+               }
+               
+               SkinLogger skinLogger = loggerMap.get( clazz );
+               
+               if( null != skinLogger ) {
+                       return skinLogger;
+               }else {
+                       
+                       Logger logger = Logger.getLogger( name );
+                       logger.addHandler( fileHandler );
+                       logger.setLevel( fileHandler.getLevel() );
+                       logger.setUseParentHandlers( false );
+                       
+                       SkinLogger sLogger = new SkinLogger( logger );
+                       loggerMap.put( clazz, sLogger );
+                       
+                       return sLogger;
+                       
+               }
+               
+       }
+
+}
+
+class SkinFormatter extends Formatter {
+
+       private SimpleDateFormat simpleDateFormat = new SimpleDateFormat( "yyyyMMdd-HHmmss" );
+       private String lineSeparator = System.getProperty( "line.separator" );
+
+       @Override
+       public String format( LogRecord record ) {
+
+               StringBuilder builder = new StringBuilder();
+
+               builder.append( "[" );
+               builder.append( record.getLevel().toString() );
+               builder.append( ":" );
+
+               String formattedDate = simpleDateFormat.format( new Date( record.getMillis() ) );
+               builder.append( formattedDate );
+               builder.append( ":" );
+
+               if ( null != record.getSourceClassName() ) {
+                       String sourceClassName = record.getSourceClassName();
+                       String[] split = sourceClassName.split( "\\." );
+                       builder.append( split[split.length - 1] );
+               } else {
+                       builder.append( record.getLoggerName() );
+               }
+               
+               if ( null != record.getSourceMethodName() ) {
+                       builder.append( "." );
+                       builder.append( record.getSourceMethodName() );
+               }
+
+               builder.append( "] " );
+
+               String message = formatMessage( record );
+               builder.append( message );
+
+               builder.append( lineSeparator );
+
+               if ( null != record.getThrown() ) {
+                       
+                       try {
+                               
+                               StringWriter sw = new StringWriter();
+                               PrintWriter pw = new PrintWriter( sw );
+                               record.getThrown().printStackTrace( pw );
+                               pw.close();
+                               
+                               builder.append( sw.toString() );
+                               
+                       } catch ( Exception ex ) {
+                       }
+               }
+
+               return builder.toString();
+
+       }
+
+}
+       
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java
new file mode 100644 (file)
index 0000000..7ae9c67
--- /dev/null
@@ -0,0 +1,551 @@
+/**
+ * 
+ *
+ * Copyright ( C ) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.screenshot;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.ImageTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.tizen.emulator.skin.EmulatorSkin;
+import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
+import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
+import org.tizen.emulator.skin.comm.sock.SocketCommunicator.DataTranfer;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.exception.ScreenShotException;
+import org.tizen.emulator.skin.image.ImageRegistry;
+import org.tizen.emulator.skin.image.ImageRegistry.IconName;
+import org.tizen.emulator.skin.log.SkinLogger;
+import org.tizen.emulator.skin.util.IOUtil;
+import org.tizen.emulator.skin.util.SkinUtil;
+import org.tizen.emulator.skin.util.StringUtil;
+
+public class ScreenShotDialog {
+
+       public final static String DEFAULT_FILE_EXTENSION = "png";
+
+       public final static int RED_MASK = 0x0000FF00;
+       public final static int GREEN_MASK = 0x00FF0000;
+       public final static int BLUE_MASK = 0xFF000000;
+       public final static int COLOR_DEPTH = 32;
+
+       public final static int CANVAS_MARGIN = 30;
+
+       private Logger logger = SkinLogger.getSkinLogger( ScreenShotDialog.class ).getLogger();
+
+       private PaletteData paletteData;
+       private Image image;
+       private Canvas imageCanvas;
+       private Shell shell;
+       private ScrolledComposite scrollComposite;
+
+       private SocketCommunicator communicator;
+       private EmulatorSkin emulatorSkin;
+       private EmulatorConfig config;
+
+       private RotationInfo currentRotation;
+       private boolean reserveImage;
+
+       public ScreenShotDialog( Shell parent, SocketCommunicator communicator, EmulatorSkin emulatorSkin,
+                       EmulatorConfig config, Image icon ) throws ScreenShotException {
+
+               this.communicator = communicator;
+               this.emulatorSkin = emulatorSkin;
+               this.config = config;
+
+               shell = new Shell( Display.getDefault(), SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX );
+               shell.setText( "Screen Shot - " + SkinUtil.makeEmulatorName( config ) );
+               if (icon != null) {
+                       shell.setImage(icon);
+               }
+
+               shell.addListener( SWT.Close, new Listener() {
+                       @Override
+                       public void handleEvent( Event event ) {
+                               if ( null != image ) {
+                                       if ( !reserveImage ) {
+                                               image.dispose();
+                                       }
+                               }
+                       }
+               } );
+
+               GridLayout gridLayout = new GridLayout();
+               gridLayout.marginWidth = 0;
+               gridLayout.marginHeight = 0;
+               gridLayout.horizontalSpacing = 0;
+               gridLayout.verticalSpacing = 0;
+               shell.setLayout( gridLayout );
+
+               makeMenuBar( shell );
+
+               scrollComposite = new ScrolledComposite( shell, SWT.V_SCROLL | SWT.H_SCROLL );
+               GridData gridData = new GridData( SWT.FILL, SWT.FILL, true, true );
+               scrollComposite.setLayoutData( gridData );
+
+               scrollComposite.setExpandHorizontal( true );
+               scrollComposite.setExpandVertical( true );
+
+               currentRotation = getCurrentRotation();
+
+               imageCanvas = new Canvas( scrollComposite, SWT.NONE );
+               imageCanvas.setBackground( shell.getDisplay().getSystemColor( SWT.COLOR_DARK_GRAY ) );
+               imageCanvas.addPaintListener( new PaintListener() {
+                       @Override
+                       public void paintControl( PaintEvent e ) {
+
+                               logger.fine( "paint image." );
+
+                               if ( null != image && !image.isDisposed() ) {
+                                       e.gc.drawImage( image, CANVAS_MARGIN, CANVAS_MARGIN );
+                               }
+
+                       }
+               } );
+
+               paletteData = new PaletteData( RED_MASK, GREEN_MASK, BLUE_MASK );
+
+               scrollComposite.setContent( imageCanvas );
+
+               try {
+                       clickShutter();
+               } catch ( ScreenShotException e ) {
+                       if ( !shell.isDisposed() ) {
+                               shell.close();
+                       }
+                       throw e;
+               }
+
+               shell.pack();
+
+               Rectangle  monitorBound = Display.getDefault().getBounds();
+               logger.info("current display size : " + monitorBound);
+               int x = parent.getLocation().x + parent.getSize().x + 20;
+               int y = parent.getLocation().y;
+               if ((x + shell.getSize().x) > (monitorBound.x + monitorBound.width)) {
+                       x = parent.getLocation().x - shell.getSize().x - 20;
+               }
+               shell.setLocation(x, y);
+
+       }
+
+//     private void drawRotatedImage( GC gc, int width, int height ) {
+//
+//             Transform transform = new Transform( shell.getDisplay() );
+//
+//             float angle = currentRotation.angle();
+//             transform.rotate( angle );
+//
+//             if ( RotationInfo.LANDSCAPE.equals( currentRotation ) ) {
+//                     transform.translate( -width - ( 2 * CANVAS_MARGIN ), 0 );
+//             } else if ( RotationInfo.REVERSE_PORTRAIT.equals( currentRotation ) ) {
+//                     transform.translate( -width - ( 2 * CANVAS_MARGIN ), -height - ( 2 * CANVAS_MARGIN ) );
+//             } else if ( RotationInfo.REVERSE_LANDSCAPE.equals( currentRotation ) ) {
+//                     transform.translate( 0, -height - ( 2 * CANVAS_MARGIN ) );
+//             }
+//             gc.setTransform( transform );
+//
+//             gc.drawImage( image, CANVAS_MARGIN, CANVAS_MARGIN );
+//
+//             transform.dispose();
+//
+//     }
+
+       private void clickShutter() throws ScreenShotException {
+               capture();
+               arrageImageLayout();
+       }
+
+       private void capture() throws ScreenShotException {
+
+               DataTranfer dataTranfer = communicator.sendToQEMU( SendCommand.SCREEN_SHOT, null, true );
+               byte[] receivedData = communicator.getReceivedData( dataTranfer );
+
+               if ( null != receivedData ) {
+
+                       if ( null != this.image ) {
+                               this.image.dispose();
+                       }
+
+                       int width = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH );
+                       int height = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT );
+                       ImageData imageData = new ImageData( width, height, COLOR_DEPTH, paletteData, 1, receivedData );
+
+                       RotationInfo rotation = getCurrentRotation();
+                       imageData = rotateImageData( imageData, rotation );
+
+                       this.image = new Image( Display.getDefault(), imageData );
+                       imageCanvas.redraw();
+
+               } else {
+                       throw new ScreenShotException( "Fail to get image data." );
+               }
+
+       }
+
+       private void arrageImageLayout() {
+
+               ImageData imageData = image.getImageData();
+
+               int width = imageData.width + ( 2 * CANVAS_MARGIN );
+               int height = imageData.height + ( 2 * CANVAS_MARGIN );
+
+               scrollComposite.setMinSize( width, height );
+
+               RotationInfo rotation = getCurrentRotation();
+               if ( !currentRotation.equals( rotation ) ) { // reserve changed shell size by user
+                       shell.pack();
+               }
+
+               currentRotation = rotation;
+
+       }
+
+       private ImageData rotateImageData( ImageData srcData, RotationInfo rotation ) {
+
+               int direction = SWT.NONE;
+
+               switch ( rotation ) {
+               case PORTRAIT:
+                       return srcData;
+               case LANDSCAPE:
+                       direction = SWT.LEFT;
+                       break;
+               case REVERSE_PORTRAIT:
+                       direction = SWT.DOWN;
+                       break;
+               case REVERSE_LANDSCAPE:
+                       direction = SWT.RIGHT;
+                       break;
+               default:
+                       return srcData;
+               }
+
+               ImageData rotatedData = rotateImageData( srcData, direction );
+               return rotatedData;
+
+       }
+
+       /*
+        * refrence web page : http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/Rotateandflipanimage.htm
+        */
+       private ImageData rotateImageData( ImageData srcData, int direction ) {
+               int bytesPerPixel = srcData.bytesPerLine / srcData.width;
+               int destBytesPerLine = ( direction == SWT.DOWN ) ? srcData.width * bytesPerPixel : srcData.height
+                               * bytesPerPixel;
+               byte[] newData = new byte[srcData.data.length];
+               int width = 0, height = 0;
+               for ( int srcY = 0; srcY < srcData.height; srcY++ ) {
+                       for ( int srcX = 0; srcX < srcData.width; srcX++ ) {
+                               int destX = 0, destY = 0, destIndex = 0, srcIndex = 0;
+                               switch ( direction ) {
+                               case SWT.LEFT: // left 90 degrees
+                                       destX = srcY;
+                                       destY = srcData.width - srcX - 1;
+                                       width = srcData.height;
+                                       height = srcData.width;
+                                       break;
+                               case SWT.RIGHT: // right 90 degrees
+                                       destX = srcData.height - srcY - 1;
+                                       destY = srcX;
+                                       width = srcData.height;
+                                       height = srcData.width;
+                                       break;
+                               case SWT.DOWN: // 180 degrees
+                                       destX = srcData.width - srcX - 1;
+                                       destY = srcData.height - srcY - 1;
+                                       width = srcData.width;
+                                       height = srcData.height;
+                                       break;
+                               }
+                               destIndex = ( destY * destBytesPerLine ) + ( destX * bytesPerPixel );
+                               srcIndex = ( srcY * srcData.bytesPerLine ) + ( srcX * bytesPerPixel );
+                               System.arraycopy( srcData.data, srcIndex, newData, destIndex, bytesPerPixel );
+                       }
+               }
+               // destBytesPerLine is used as scanlinePad to ensure that no padding is
+               // required
+               return new ImageData( width, height, srcData.depth, srcData.palette, destBytesPerLine, newData );
+
+       }
+
+       private RotationInfo getCurrentRotation() {
+               short currentRotationId = emulatorSkin.getCurrentRotationId();
+               RotationInfo rotationInfo = RotationInfo.getValue( currentRotationId );
+               return rotationInfo;
+       }
+
+       private void makeMenuBar( final Shell shell ) {
+
+               ToolBar toolBar = new ToolBar( shell, SWT.HORIZONTAL );
+               GridData gridData = new GridData( GridData.FILL_HORIZONTAL, GridData.CENTER, true, false );
+               toolBar.setLayoutData( gridData );
+
+               ToolItem saveItem = new ToolItem( toolBar, SWT.FLAT );
+               saveItem.setImage( ImageRegistry.getInstance().getIcon( IconName.SAVE_SCREEN_SHOT ) );
+               saveItem.setToolTipText( "Save to file" );
+
+               saveItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               FileDialog fileDialog = new FileDialog( shell, SWT.SAVE );
+                               fileDialog.setText( "Save Image" );
+
+                               String[] filter = { "*.png;*.PNG;*.jpg;*.JPG;*.jpeg;*.JPEG;*.bmp;*.BMP" };
+                               fileDialog.setFilterExtensions( filter );
+
+                               String[] filterName = { "Image files (*.png *.jpg *.jpeg *.bmp)" };
+                               fileDialog.setFilterNames( filterName );
+
+                               String vmName = SkinUtil.getVmName( config );
+                               SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd-hhmmss" );
+                               String dateString = formatter.format( new Date( System.currentTimeMillis() ) );
+
+                               fileDialog.setFileName( vmName + "-" + dateString + "." + DEFAULT_FILE_EXTENSION );
+
+                               String userHome = System.getProperty( "user.home" );
+                               if ( !StringUtil.isEmpty( userHome ) ) {
+                                       fileDialog.setFilterPath( userHome );
+                               } else {
+                                       logger.warning( "Cannot find user home path int java System properties." );
+                               }
+
+                               String filePath = fileDialog.open();
+                               saveFile( filePath, fileDialog );
+
+                       }
+
+               } );
+
+               ToolItem copyItem = new ToolItem( toolBar, SWT.FLAT );
+               copyItem.setImage( ImageRegistry.getInstance().getIcon( IconName.COPY_SCREEN_SHOT ) );
+               copyItem.setToolTipText( "Copy to clipboard" );
+
+               copyItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               if ( null == image || image.isDisposed() ) {
+                                       SkinUtil.openMessage( shell, null, "Fail to copy to clipboard.", SWT.ICON_ERROR, config );
+                                       return;
+                               }
+
+                               ImageLoader loader = new ImageLoader();
+
+                               ImageData data = null;
+
+                               if ( SkinUtil.isWindowsPlatform() ) {
+                                       // change RGB mask
+                                       ImageData imageData = image.getImageData();
+                                       PaletteData paletteData = new PaletteData( BLUE_MASK, GREEN_MASK, RED_MASK );
+                                       data = new ImageData( imageData.width, imageData.height, imageData.depth, paletteData,
+                                                       imageData.bytesPerLine, imageData.data );
+                               } else {
+                                       data = image.getImageData();
+                               }
+
+                               loader.data = new ImageData[] { data };
+
+                               ByteArrayOutputStream bao = new ByteArrayOutputStream();
+                               loader.save( bao, SWT.IMAGE_PNG );
+
+                               ImageData imageData = new ImageData( new ByteArrayInputStream( bao.toByteArray() ) );
+                               Object[] imageObject = new Object[] { imageData };
+
+                               Transfer[] transfer = new Transfer[] { ImageTransfer.getInstance() };
+
+                               Clipboard clipboard = new Clipboard( shell.getDisplay() );
+                               clipboard.setContents( imageObject, transfer );
+
+                       }
+
+               } );
+
+               ToolItem refreshItem = new ToolItem( toolBar, SWT.FLAT );
+               refreshItem.setImage( ImageRegistry.getInstance().getIcon( IconName.REFRESH_SCREEN_SHOT ) );
+               refreshItem.setToolTipText( "Refresh image" );
+
+               refreshItem.addSelectionListener( new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected( SelectionEvent e ) {
+
+                               try {
+                                       clickShutter();
+                               } catch ( ScreenShotException ex ) {
+                                       logger.log( Level.SEVERE, "Fail to create a screen shot.", ex );
+                                       SkinUtil.openMessage( shell, null, "Fail to create a screen shot.", SWT.ERROR, config );
+                               }
+                       }
+
+               } );
+
+       }
+
+       private void saveFile( String fileFullPath, FileDialog fileDialog ) {
+
+               if ( null == fileFullPath ) {
+                       return;
+               }
+
+               String format = "";
+               String[] split = fileFullPath.split( "\\." );
+
+               if ( 1 < split.length ) {
+
+                       format = split[split.length - 1];
+
+                       if ( new File( split[split.length - 2] ).isDirectory() ) {
+                               // There is no file name.
+                               SkinUtil.openMessage( shell, null, "Use correct file name.", SWT.ICON_WARNING, config );
+                               String path = fileDialog.open();
+                               saveFile( path, fileDialog );
+
+                       }
+
+               }
+
+               FileOutputStream fos = null;
+
+               try {
+
+                       if ( StringUtil.isEmpty( format ) ) {
+                               if ( fileFullPath.endsWith( "." ) ) {
+                                       fileFullPath += DEFAULT_FILE_EXTENSION;
+                               } else {
+                                       fileFullPath += "." + DEFAULT_FILE_EXTENSION;
+                               }
+                       }
+
+                       ImageLoader loader = new ImageLoader();
+                       loader.data = new ImageData[] { image.getImageData() };
+
+                       if ( StringUtil.isEmpty( format ) || format.equalsIgnoreCase( "png" ) ) {
+                               fos = new FileOutputStream( fileFullPath, false );
+                               loader.save( fos, SWT.IMAGE_PNG );
+                       } else if ( format.equalsIgnoreCase( "jpg" ) || format.equalsIgnoreCase( "jpeg" ) ) {
+                               fos = new FileOutputStream( fileFullPath, false );
+                               loader.save( fos, SWT.IMAGE_JPEG );
+                       } else if ( format.equalsIgnoreCase( "bmp" ) ) {
+                               fos = new FileOutputStream( fileFullPath, false );
+                               loader.save( fos, SWT.IMAGE_BMP );
+                       } else {
+
+                               SkinUtil.openMessage( shell, null, "Use the specified image formats. ( PNG / JPG / JPEG / BMP )",
+                                               SWT.ICON_WARNING, config );
+                               String path = fileDialog.open();
+                               saveFile( path, fileDialog );
+
+                       }
+
+               } catch ( FileNotFoundException ex ) {
+
+                       logger.log( Level.WARNING, "Use correct file name.", ex );
+                       SkinUtil.openMessage( shell, null, "Use correct file name.", SWT.ICON_WARNING, config );
+                       String path = fileDialog.open();
+                       saveFile( path, fileDialog );
+
+               } catch ( Exception ex ) {
+
+                       logger.log( Level.SEVERE, "Fail to save this image file.", ex );
+                       SkinUtil.openMessage( shell, null, "Fail to save this image file.", SWT.ERROR, config );
+                       String path = fileDialog.open();
+                       saveFile( path, fileDialog );
+
+               } finally {
+                       IOUtil.close( fos );
+               }
+
+       }
+
+       public void open() {
+
+               if ( shell.isDisposed() ) {
+                       return;
+               }
+
+               shell.open();
+
+               while ( !shell.isDisposed() ) {
+                       if ( !shell.getDisplay().readAndDispatch() ) {
+                               if ( reserveImage ) {
+                                       break;
+                               } else {
+                                       shell.getDisplay().sleep();
+                               }
+                       }
+               }
+
+       }
+
+       public void setEmulatorSkin( EmulatorSkin emulatorSkin ) {
+               this.emulatorSkin = emulatorSkin;
+       }
+
+       public void setReserveImage( boolean reserveImage ) {
+               this.reserveImage = reserveImage;
+       }
+
+       public Shell getShell() {
+               return shell;
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/IOUtil.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/IOUtil.java
new file mode 100644 (file)
index 0000000..ea87791
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+
+/**
+ * 
+ *
+ */
+public class IOUtil {
+
+       private IOUtil(){}
+
+       public static void closeSocket( Socket socket ) {
+               try {
+                       if ( null != socket ) {
+                               socket.close();
+                       }
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static void close( Closeable closeable ) {
+               try {
+                       if ( null != closeable ) {
+                               closeable.close();
+                       }
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static byte[] getBytes( InputStream is ) throws IOException {
+               
+               ByteArrayOutputStream bao = new ByteArrayOutputStream();
+               byte[] buffer = new byte[1024];
+               
+               int read = 0;
+               while( 0 < ( read = is.read( buffer ) ) ) {
+                       bao.write( buffer, 0, read );
+               }
+               
+               return bao.toByteArray();
+               
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/JaxbUtil.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/JaxbUtil.java
new file mode 100644 (file)
index 0000000..25fb8ee
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+import org.tizen.emulator.skin.exception.JaxbException;
+
+
+/**
+ * 
+ *
+ */
+public class JaxbUtil {
+       
+       private JaxbUtil(){}
+
+       public static <T> T unmarshal( byte[] inputBytes, Class<T> clazz ) throws JaxbException {
+               return unmarshal( new ByteArrayInputStream( inputBytes ), clazz );
+       }
+
+       public static <T> T unmarshal( InputStream in, Class<T> clazz ) throws JaxbException {
+               
+               try{
+                       
+                       Unmarshaller u = getContext(clazz).createUnmarshaller();
+                       JAXBElement<T> element = u.unmarshal( new StreamSource(in), clazz );
+                       
+                       return element.getValue();
+                       
+               } catch (JAXBException e) {
+                       throw new JaxbException(e);
+               } catch (Throwable e) {
+                       throw new JaxbException(e);
+               }
+               
+       }
+       
+       public static void marshal( Object object, OutputStream out ) throws JaxbException {
+               
+               try{
+                       
+                       Marshaller m = getContext(object.getClass()).createMarshaller();
+                       
+                       m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+                       m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+                       
+                       m.marshal(object, out);
+                       
+               } catch (JAXBException e) {
+                       throw new JaxbException(e);
+               } catch (Throwable e) {
+                       throw new JaxbException(e);
+               }
+               
+       }
+       
+       private static JAXBContext getContext(Class<?> clazz) throws JaxbException {
+               
+               try{
+                       
+                       String qualifier = clazz.getCanonicalName();
+                       int index = qualifier.lastIndexOf('.');
+                       if ( - 1!= index) {
+                               qualifier = qualifier.substring( 0, index );
+                       }
+                       
+                       return JAXBContext.newInstance( qualifier, clazz.getClassLoader() );
+                       
+               } catch (JAXBException e) {
+                       throw new JaxbException(e);
+               }
+               
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRegion.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRegion.java
new file mode 100644 (file)
index 0000000..0dc6804
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+/**
+ * 
+ *
+ */
+public class SkinRegion {
+       public int x;
+       public int y;
+       public int width;
+       public int height;
+       
+       public SkinRegion( int x, int y, int width, int height ) {
+               this.x = x;
+               this.y = y;
+               this.width = width;
+               this.height = height;
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRotation.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRotation.java
new file mode 100644 (file)
index 0000000..edba076
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
+import org.tizen.emulator.skin.dbi.RotationType;
+
+
+/**
+ * 
+ *
+ */
+public class SkinRotation {
+       
+       private static Map<Short, RotationType> rotationMap;
+       private static Map<Short, RotationInfo> angleMap;
+       
+       private SkinRotation(){}
+       
+       static {
+               rotationMap = new LinkedHashMap<Short, RotationType>();
+               angleMap = new HashMap<Short, RotationInfo>();
+       }
+       
+       public static void put(RotationType rotation ) {
+
+               if ( RotationInfo.PORTRAIT.value().equalsIgnoreCase( rotation.getName().value() ) ) {
+                       rotationMap.put( RotationInfo.PORTRAIT.id(), rotation );
+                       angleMap.put( RotationInfo.PORTRAIT.id(), RotationInfo.PORTRAIT );
+               } else if ( RotationInfo.LANDSCAPE.value().equalsIgnoreCase( rotation.getName().value() ) ) {
+                       rotationMap.put( RotationInfo.LANDSCAPE.id(), rotation );
+                       angleMap.put( RotationInfo.LANDSCAPE.id(), RotationInfo.LANDSCAPE );
+               } else if ( RotationInfo.REVERSE_PORTRAIT.value().equalsIgnoreCase( rotation.getName().value() ) ) {
+                       rotationMap.put( RotationInfo.REVERSE_PORTRAIT.id(), rotation );
+                       angleMap.put( RotationInfo.REVERSE_PORTRAIT.id(), RotationInfo.REVERSE_PORTRAIT );
+               } else if ( RotationInfo.REVERSE_LANDSCAPE.value().equalsIgnoreCase( rotation.getName().value() ) ) {
+                       rotationMap.put( RotationInfo.REVERSE_LANDSCAPE.id(), rotation );
+                       angleMap.put( RotationInfo.REVERSE_LANDSCAPE.id(), RotationInfo.REVERSE_LANDSCAPE );
+               }
+
+       }
+
+       public static int getAngle( Short rotationId ) {
+               RotationInfo rotationInfo = angleMap.get(rotationId);
+               if( null != rotationInfo ) {
+                       return rotationInfo.angle();
+               }else {
+                       return 0;
+               }
+       }
+
+       public static RotationType getRotation( Short rotationId ) {
+               return rotationMap.get(rotationId);
+       }
+
+       public static Iterator<Entry<Short, RotationType>>getRotationIterator() {
+               return rotationMap.entrySet().iterator();
+       }
+       
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinUtil.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinUtil.java
new file mode 100644 (file)
index 0000000..047226d
--- /dev/null
@@ -0,0 +1,357 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Region;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
+import org.tizen.emulator.skin.comm.ICommunicator.Scale;
+import org.tizen.emulator.skin.config.EmulatorConfig;
+import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
+import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
+import org.tizen.emulator.skin.dbi.EventInfoType;
+import org.tizen.emulator.skin.dbi.KeyMapType;
+import org.tizen.emulator.skin.dbi.LcdType;
+import org.tizen.emulator.skin.dbi.RegionType;
+import org.tizen.emulator.skin.dbi.RotationType;
+import org.tizen.emulator.skin.image.ImageRegistry;
+import org.tizen.emulator.skin.image.ImageRegistry.ImageType;
+
+
+/**
+ * 
+ *
+ */
+public class SkinUtil {
+
+       public static final int UNKNOWN_KEYCODE = -1;
+       public static final int SCALE_CONVERTER = 100;
+       public static final String EMULATOR_PREFIX = "emulator";
+
+       private SkinUtil() {
+       }
+
+       public static boolean isLinuxPlatform() {
+               return "gtk".equalsIgnoreCase( SWT.getPlatform() );
+       }
+
+       public static boolean isWindowsPlatform() {
+               return "win32".equalsIgnoreCase( SWT.getPlatform() );
+       }
+
+       public static boolean isMacPlatform() {
+               return "cocoa".equalsIgnoreCase( SWT.getPlatform() );
+       }
+
+       public static String getVmName( EmulatorConfig config ) {
+               
+               String vmPath = config.getArg( ArgsConstants.VM_PATH );
+
+               String regex = "";
+               if ( isWindowsPlatform() ) {
+                       regex = "\\" + File.separator;
+               } else {
+                       regex = File.separator;
+               }
+               String[] split = StringUtil.nvl( vmPath ).split( regex );
+               String vmName = split[split.length - 1];
+
+               return vmName;
+               
+       }
+       
+       public static String makeEmulatorName( EmulatorConfig config ) {
+
+               String vmName = getVmName( config );
+
+               if ( StringUtil.isEmpty( vmName ) ) {
+                       vmName = EMULATOR_PREFIX;
+               }
+
+               int portNumber = config.getArgInt( ArgsConstants.NET_BASE_PORT );
+               return vmName + ":" + portNumber;
+
+       }
+
+       public static String getSdbPath() {
+               String sdbPath = null;
+
+               if (SkinUtil.isLinuxPlatform()) {
+                       sdbPath = "./../../SDK/sdb/sdb";
+               } else if (SkinUtil.isWindowsPlatform()) {
+                       sdbPath = ".\\..\\..\\SDK\\sdb\\sdb.exe";
+               }
+
+               return sdbPath;
+       }
+
+       public static void adjustLcdGeometry( Canvas lcdCanvas, int scale, short rotationId ) {
+
+               RotationType rotation = SkinRotation.getRotation( rotationId );
+
+               LcdType lcd = rotation.getLcd();
+               RegionType region = lcd.getRegion();
+
+               Integer left = region.getLeft();
+               Integer top = region.getTop();
+               Integer width = region.getWidth();
+               Integer height = region.getHeight();
+
+               float convertedScale = convertScale( scale );
+
+               int l = (int) ( left * convertedScale );
+               int t = (int) ( top * convertedScale );
+               int w = (int) ( width * convertedScale );
+               int h = (int) ( height * convertedScale );
+
+               lcdCanvas.setBounds( l, t, w, h );
+
+       }
+
+       public static SkinRegion getHardKeyArea( int currentX, int currentY, short rotationId, int scale ) {
+
+               float convertedScale = convertScale( scale );
+
+               RotationType rotation = SkinRotation.getRotation( rotationId );
+
+               List<KeyMapType> keyMapList = rotation.getKeyMapList().getKeyMap();
+
+               for ( KeyMapType keyMap : keyMapList ) {
+
+                       RegionType region = keyMap.getRegion();
+
+                       int scaledX = (int) ( region.getLeft() * convertedScale );
+                       int scaledY = (int) ( region.getTop() * convertedScale );
+                       int scaledWidth = (int) ( region.getWidth() * convertedScale );
+                       int scaledHeight = (int) ( region.getHeight() * convertedScale );
+
+                       if ( isInGeometry( currentX, currentY, scaledX, scaledY, scaledWidth, scaledHeight ) ) {
+                               return new SkinRegion( scaledX, scaledY, scaledWidth, scaledHeight );
+                       }
+
+               }
+
+               return null;
+
+       }
+
+       public static int getHardKeyCode( int currentX, int currentY, short rotationId, int scale ) {
+
+               float convertedScale = convertScale( scale );
+
+               RotationType rotation = SkinRotation.getRotation( rotationId );
+
+               List<KeyMapType> keyMapList = rotation.getKeyMapList().getKeyMap();
+
+               for ( KeyMapType keyMap : keyMapList ) {
+                       RegionType region = keyMap.getRegion();
+
+                       int scaledX = (int) ( region.getLeft() * convertedScale );
+                       int scaledY = (int) ( region.getTop() * convertedScale );
+                       int scaledWidth = (int) ( region.getWidth() * convertedScale );
+                       int scaledHeight = (int) ( region.getHeight() * convertedScale );
+
+                       if ( isInGeometry( currentX, currentY, scaledX, scaledY, scaledWidth, scaledHeight ) ) {
+                               EventInfoType eventInfo = keyMap.getEventInfo();
+                               return eventInfo.getKeyCode();
+                       }
+               }
+
+               return UNKNOWN_KEYCODE;
+
+       }
+
+       //TODO: HardKey object
+       public static String getHardKeyToolTip( int currentX, int currentY, short rotationId, int scale ) {
+
+               float convertedScale = convertScale( scale );
+
+               RotationType rotation = SkinRotation.getRotation( rotationId );
+
+               List<KeyMapType> keyMapList = rotation.getKeyMapList().getKeyMap();
+
+               for ( KeyMapType keyMap : keyMapList ) {
+                       RegionType region = keyMap.getRegion();
+
+                       int scaledX = (int) ( region.getLeft() * convertedScale );
+                       int scaledY = (int) ( region.getTop() * convertedScale );
+                       int scaledWidth = (int) ( region.getWidth() * convertedScale );
+                       int scaledHeight = (int) ( region.getHeight() * convertedScale );
+
+                       if ( isInGeometry( currentX, currentY, scaledX, scaledY, scaledWidth, scaledHeight ) ) {
+                               return keyMap.getTooltip();
+                       }
+               }
+
+               return null;
+
+       }
+
+       public static boolean isInGeometry( int currentX, int currentY, int targetX, int targetY, int targetWidth,
+                       int targetHeight ) {
+
+               if ( ( currentX >= targetX ) && ( currentY >= targetY ) ) {
+                       if ( ( currentX <= ( targetX + targetWidth ) ) && ( currentY <= ( targetY + targetHeight ) ) ) {
+                               return true;
+                       }
+               }
+
+               return false;
+
+       }
+
+       public static void trimShell( Shell shell, Image image ) {
+
+               // trim transparent pixels in image. especially, corner round areas.
+
+               if ( null == image ) {
+                       return;
+               }
+
+               ImageData imageData = image.getImageData();
+
+               int width = imageData.width;
+               int height = imageData.height;
+
+               Region region = new Region();
+               region.add( new Rectangle( 0, 0, width, height ) );
+
+               for ( int i = 0; i < width; i++ ) {
+                       for ( int j = 0; j < height; j++ ) {
+                               int alpha = imageData.getAlpha( i, j );
+                               if ( 0 == alpha ) {
+                                       region.subtract( i, j, 1, 1 );
+                               }
+                       }
+               }
+
+               shell.setRegion( region );
+
+       }
+
+       public static int[] convertMouseGeometry( int originalX, int originalY, int lcdWidth, int lcdHeight, int scale,
+                       int angle ) {
+
+               float convertedScale = convertScale( scale );
+
+               int x = (int) ( originalX * ( 1 / convertedScale ) );
+               int y = (int) ( originalY * ( 1 / convertedScale ) );
+
+               int rotatedX = x;
+               int rotatedY = y;
+
+               if ( RotationInfo.LANDSCAPE.angle() == angle ) {
+                       rotatedX = lcdWidth - y;
+                       rotatedY = x;
+               } else if ( RotationInfo.REVERSE_PORTRAIT.angle() == angle ) {
+                       rotatedX = lcdWidth - x;
+                       rotatedY = lcdHeight - y;
+               } else if ( RotationInfo.REVERSE_LANDSCAPE.angle() == angle ) {
+                       rotatedX = y;
+                       rotatedY = lcdHeight - x;
+               }
+
+               return new int[] { rotatedX, rotatedY };
+
+       }
+
+       public static Image createScaledImage( ImageRegistry imageRegistry, Shell shell, short rotationId, int scale,
+                       ImageType type ) {
+
+               ImageData originalImageData = imageRegistry.getSkinImageData( rotationId, type );
+
+               if ( null == originalImageData ) {
+                       return null;
+               }
+
+               ImageData imageData = (ImageData) originalImageData.clone();
+
+               float convertedScale = convertScale( scale );
+
+               int width = (int) ( originalImageData.width * convertedScale );
+               int height = (int) ( originalImageData.height * convertedScale );
+               imageData = imageData.scaledTo( width, height );
+
+               Image image = new Image( shell.getDisplay(), imageData );
+               return image;
+
+       }
+
+       public static float convertScale( int scale ) {
+               return (float) scale / SCALE_CONVERTER;
+       }
+
+       public static int getValidScale( EmulatorConfig config ) {
+
+               int storedScale = config.getSkinPropertyInt( SkinPropertiesConstants.WINDOW_SCALE,
+                               EmulatorConfig.DEFAULT_WINDOW_SCALE );
+
+               if ( !SkinUtil.isValidScale( storedScale ) ) {
+                       return EmulatorConfig.DEFAULT_WINDOW_SCALE;
+               }else {
+                       return storedScale;
+               }
+               
+       }
+
+       public static boolean isValidScale( int scale ) {
+               if ( Scale.SCALE_100.value() == scale || Scale.SCALE_75.value() == scale
+               || Scale.SCALE_50.value() == scale || Scale.SCALE_25.value() == scale ) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+       
+       public static <T> void openMessage( Shell shell, String title, String message, int style, EmulatorConfig config ) {
+               
+               MessageBox messageBox = new MessageBox( shell, style );
+               
+               if( !StringUtil.isEmpty( title ) ) {
+                       messageBox.setText( title );
+               }else {
+                       messageBox.setText( makeEmulatorName( config ) );
+               }
+               
+               messageBox.setMessage( StringUtil.nvl( message ) );
+               messageBox.open();
+               
+       }
+
+}
diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/util/StringUtil.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/util/StringUtil.java
new file mode 100644 (file)
index 0000000..172abef
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * 
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.emulator.skin.util;
+
+/**
+ * 
+ *
+ */
+public class StringUtil {
+       
+       private StringUtil(){}
+       
+       public static boolean isEmpty( String value ) {
+               return ( null == value ) || ( 0 == value.length() );
+       }
+
+       public static String nvl( String value ) {
+               return ( null == value ) ? "" : value;
+       }
+
+}
diff --git a/tizen/src/skin/client/xsd/dbi.xsd b/tizen/src/skin/client/xsd/dbi.xsd
new file mode 100644 (file)
index 0000000..a351c90
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.tizen.org/emulator/dbi"
+xmlns:dbi="http://www.tizen.org/emulator/dbi" elementFormDefault="qualified">
+
+       <element name="EmulatorUI" >
+               <complexType>
+                       <all>
+                               <element name = "rotations" type="dbi:rotationsType" minOccurs="1" maxOccurs="1"></element>
+                               <element name = "colors" type="dbi:colorsType" minOccurs="0" maxOccurs="1"></element>
+                       </all>
+               </complexType>
+       </element>
+
+       <complexType name="rotationsType">
+               <sequence>
+                       <element name="rotation" type="dbi:rotationType" minOccurs="1" maxOccurs="unbounded" ></element>
+               </sequence>
+       </complexType>
+
+       <complexType name="rotationType">
+               <sequence>
+                       <element name="lcd" type="dbi:lcdType" minOccurs="1" maxOccurs="1"></element>
+                       <element name="imageList" type="dbi:imageListType" minOccurs="1" maxOccurs="1" ></element>
+                       <element name="keyMapList" type="dbi:keyMapListType" minOccurs="1" maxOccurs="1" ></element>
+               </sequence>
+               <attribute name="name" type="dbi:rotationNameType" use="required"></attribute>
+       </complexType>
+
+    <simpleType name="rotationNameType">
+        <restriction base="string">
+            <enumeration value="Portrait"></enumeration>
+            <enumeration value="Landscape"></enumeration>
+            <enumeration value="Reverse Portrait"></enumeration>
+            <enumeration value="Reverse Landscape"></enumeration>
+        </restriction>
+    </simpleType>
+
+       <complexType name="imageListType">
+               <all>
+                       <element name="mainImage" type="string" minOccurs="1" maxOccurs="1"></element>
+                       <element name="keyPressedImage" type="string" minOccurs="0" maxOccurs="1"></element>
+               </all>
+       </complexType>
+
+       <complexType name="lcdType">
+               <all>
+                       <element name="region" type="dbi:regionType" minOccurs="1" maxOccurs="1"></element>
+               </all>
+               <attribute name="id" type="int" use="required"></attribute>
+       </complexType>
+
+       <complexType name="keyMapListType">
+               <sequence>
+                       <element name="keyMap" type="dbi:keyMapType" minOccurs="0" maxOccurs="unbounded"></element>
+               </sequence>
+       </complexType>
+
+       <complexType name="keyMapType">
+               <sequence>
+                       <element name="region" type="dbi:regionType" minOccurs="1" maxOccurs="1"></element>
+                       <element name="eventInfo" type="dbi:eventInfoType" minOccurs="0" maxOccurs="1"></element>
+                       <element name="tooltip" type="string" minOccurs="0" maxOccurs="1"></element>
+               </sequence>
+       </complexType>
+
+       <complexType name="eventInfoType">
+               <all>
+            <element name="keyCode" type="int" minOccurs="1" maxOccurs="1"></element>
+            <element name="keyName" type="string" minOccurs="1" maxOccurs="1"></element>
+               </all>
+       </complexType>
+
+       <complexType name="regionType">
+               <attribute name="left" type="int" ></attribute>
+               <attribute name="top" type="int" ></attribute>
+               <attribute name="width" type="int" ></attribute>
+               <attribute name="height" type="int" ></attribute>
+       </complexType>
+
+       <complexType name="colorsType">
+               <all>
+                       <element name="hoverColor" type="dbi:rgbType" minOccurs="0" maxOccurs="1"></element>
+               </all>
+       </complexType>
+
+       <complexType name="rgbType" >
+               <attribute name="R" type="unsignedInt"></attribute>
+               <attribute name="G" type="unsignedInt"></attribute>
+               <attribute name="B" type="unsignedInt"></attribute>
+       </complexType>
+
+</schema>
\ No newline at end of file
diff --git a/tizen/src/skin/maruskin_client.c b/tizen/src/skin/maruskin_client.c
new file mode 100644 (file)
index 0000000..3987725
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * communicate with java skin process
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "maruskin_client.h"
+#include "maruskin_server.h"
+#include "emulator.h"
+#include "sdb.h"
+#include "debug_ch.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#define SKIN_SERVER_READY_TIME 3 // second
+#define SKIN_SERVER_SLEEP_TIME 10 // milli second
+
+#define JAR_SKINFILE_PATH "emulator-skin.jar"
+#define JAVA_EXEFILE_PATH "java"
+#define JAVA_EXEOPTION "-jar"
+
+#define OPT_SVR_PORT "svr.port"
+#define OPT_UID "uid"
+#define OPT_VM_PATH "vm.path"
+#define OPT_NET_BASE_PORT "net.baseport"
+
+MULTI_DEBUG_CHANNEL( qemu, maruskin_client );
+
+static int skin_argc;
+static char** skin_argv;
+
+static void* run_skin_client(void* arg)
+{
+    char cmd[512] = {0};
+    char argv[256] = {0};
+
+    INFO("run skin client\n");
+    int i;
+    for (i = 0; i < skin_argc; ++i) {
+        strncat(argv, skin_argv[i], strlen(skin_argv[i]));
+        strncat(argv, " ", 1);
+        INFO( "[skin args %d] %s\n", i, skin_argv[i] );
+    }
+
+    int skin_server_port = get_skin_server_port();
+
+    srand( time( NULL ) );
+    int uid = 0; //rand();
+    //INFO( "generated skin uid:%d\n", uid );
+
+    char* vm_path = tizen_target_path;
+    //INFO( "vm_path:%s\n", vm_path );
+
+    sprintf( cmd, "%s %s %s %s=\"%d\" %s=\"%d\" %s=\"%s\" %s=\"%d\" %s", JAVA_EXEFILE_PATH, JAVA_EXEOPTION, JAR_SKINFILE_PATH,
+        OPT_SVR_PORT, skin_server_port,
+        OPT_UID, uid,
+        OPT_VM_PATH, vm_path,
+        OPT_NET_BASE_PORT, tizen_base_port,
+        argv );
+    INFO( "command for swt : %s\n", cmd );
+
+#ifdef _WIN32
+#if 0
+    WinExec( cmd, SW_SHOW );
+#else
+    {
+        STARTUPINFO sti = { 0 };
+        PROCESS_INFORMATION pi = { 0 };
+        if (!CreateProcess(NULL,
+                          cmd,
+                          NULL,
+                          NULL,
+                          FALSE,
+                          NORMAL_PRIORITY_CLASS,
+                          NULL,
+                          NULL,
+                          &sti,
+                          &pi))
+        {
+            ERR("Unable to generate process!error %u\n", GetLastError());
+            exit(1);
+        }
+
+        INFO("wait for single object..\n");
+        DWORD dwRet = WaitForSingleObject(
+                          pi.hProcess, // process handle
+                          INFINITE);
+
+        switch(dwRet) {
+        case WAIT_OBJECT_0:
+            INFO("the child thread state was signaled!\n");
+            break;
+        case WAIT_TIMEOUT:
+            INFO("time-out interval elapsed, and the child thread's state is nonsignaled.\n");
+            break;
+        case WAIT_FAILED:
+            ERR("WaitForSingleObject() failed, error %u\n", GetLastError());
+            break;
+        }
+
+        //retrieves the termination status of the specified process
+        GetExitCodeProcess(pi.hProcess, &dwRet);
+        INFO("child return value : %d\n", dwRet);
+
+        if (dwRet == -1) {
+            //TODO:
+            exit(1);
+        }
+
+        if (CloseHandle(pi.hProcess) != 0) {
+            INFO("child thread handle was closed successfully!\n");
+        } else {
+            ERR("failed to close child thread handle, error %u\n", GetLastError());
+        }
+    }
+#endif
+#else //ifndef _WIN32
+    int ret = system(cmd);
+
+    if (ret == 127) {
+        INFO("can't execute /bin/sh!\n");
+    } else if(ret == -1) {
+        INFO("fork error!\n");
+    } else {
+        ret = WEXITSTATUS(ret);
+        //The high-order 8 bits are the exit code from exit().
+        //The low-order 8 bits are zero if the process exited normally.
+        INFO("child return value : %d\n", ret);
+
+        if (ret == 0xff) {
+            //TODO:
+            exit(1);
+        }
+    }
+
+#endif
+
+    return NULL;
+}
+
+int start_skin_client(int argc, char* argv[])
+{
+    int count = 0;
+    int skin_server_ready = 0;
+
+    while( 1 ) {
+
+        if( 100 * SKIN_SERVER_READY_TIME < count ) {
+            break;
+        }
+
+        if ( is_ready_skin_server() ) {
+            skin_server_ready = 1;
+            break;
+        } else {
+            count++;
+            INFO( "sleep for ready. count:%d\n", count );
+#ifdef _WIN32
+        Sleep( SKIN_SERVER_SLEEP_TIME );
+#else
+        usleep( 1000 * SKIN_SERVER_SLEEP_TIME );
+#endif
+        }
+
+    }
+
+    if ( !skin_server_ready ) {
+        ERR( "skin_server is not ready.\n" );
+        return -1;
+    }
+
+    skin_argc = argc;
+    skin_argv = argv;
+
+    pthread_t thread_id;
+
+    if (0 != pthread_create(&thread_id, NULL, run_skin_client, NULL)) {
+        ERR( "fail to create skin_client pthread.\n" );
+        return -1;
+    }
+
+    return 1;
+}
+
diff --git a/tizen/src/skin/maruskin_client.h b/tizen/src/skin/maruskin_client.h
new file mode 100644 (file)
index 0000000..b8ace64
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * communicate with java skin process
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARUSKIN_CLIENT_H_
+#define MARUSKIN_CLIENT_H_
+
+int start_skin_client(int argc, char* argv[]);
+
+#endif /* MARUSKIN_CLIENT_H_ */
diff --git a/tizen/src/skin/maruskin_keymap.c b/tizen/src/skin/maruskin_keymap.c
new file mode 100644 (file)
index 0000000..fdf9d24
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * keymap
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "maruskin_keymap.h"
+#include "emul_state.h"
+#include "console.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, skin_keymap);
+
+
+int javakeycode_to_scancode(int java_keycode, int event_type, int key_location)
+{
+    int state_mask = java_keycode & JAVA_KEYCODE_BIT;
+    int vk = java_keycode & JAVA_KEY_MASK;
+
+    int ctrl_mask = java_keycode & JAVA_KEYCODE_BIT_CTRL;
+    int shift_mask = java_keycode & JAVA_KEYCODE_BIT_SHIFT;
+    int alt_mask = java_keycode & JAVA_KEYCODE_BIT_ALT;
+
+
+    /* CapsLock & NumLock key processing */
+    if (state_mask != 0) {
+        if (vk == JAVA_KEY_CAPS_LOCK) {
+            if (event_type == KEY_PRESSED) {
+                set_emul_caps_lock_state(get_emul_caps_lock_state() ^ 1); //toggle
+            }
+            return 58;
+        } else if (vk == JAVA_KEY_NUM_LOCK) {
+            if (event_type == KEY_PRESSED) {
+                set_emul_num_lock_state(get_emul_num_lock_state() ^ 1); //toggle
+            }
+            return 69;
+        }
+    }
+    /* check CapsLock & NumLock key sync */
+    if (event_type == KEY_PRESSED) {
+        if (get_emul_caps_lock_state() != get_host_lock_key_state(HOST_CAPSLOCK_KEY)) {
+            kbd_put_keycode(58);
+            kbd_put_keycode(58 | 0x80);
+            set_emul_caps_lock_state(get_emul_caps_lock_state() ^ 1);
+            INFO("qemu CapsLock state was synchronized with host key value (%d)\n", get_emul_caps_lock_state());
+        }
+        if (get_emul_num_lock_state() != get_host_lock_key_state(HOST_NUMLOCK_KEY)) {
+            kbd_put_keycode(69);
+            kbd_put_keycode(69 | 0x80);
+            set_emul_num_lock_state(get_emul_num_lock_state() ^ 1);
+            INFO("qemu NumLock state was synchronized with host key value (%d)\n", get_emul_num_lock_state());
+        }
+    }
+
+
+/*#ifdef _WIN32
+    return MapVirtualKey(vk, MAPVK_VK_TO_VSC);
+#endif*/
+
+    if (vk == 0) { //meta keys
+        if (java_keycode == JAVA_KEYCODE_BIT_CTRL) { //ctrl key
+            if (key_location == JAVA_KEYLOCATION_RIGHT) {
+                kbd_put_keycode(224); //0xE0
+            }
+            return 29;
+        } else if (java_keycode == JAVA_KEYCODE_BIT_SHIFT) { //shift key
+#ifndef _WIN32
+            //keyLocation information is not supported at swt of windows version
+            if (key_location == JAVA_KEYLOCATION_RIGHT) {
+                return 54; //Shift_R
+            }
+#endif
+            return 42;
+        } else if (java_keycode == JAVA_KEYCODE_BIT_ALT) { //alt key
+            if (key_location == JAVA_KEYLOCATION_RIGHT) {
+                kbd_put_keycode(224);
+            }
+            return 56;
+        } else {
+            return -1;
+        }
+    }
+
+    if (state_mask != 0)
+    { //non-character keys
+        if (vk >= JAVA_KEY_F1 && vk <= JAVA_KEY_F20) { //function keys
+            vk += 255;
+        } else { //special keys
+            switch(vk) {
+                case JAVA_KEY_ARROW_UP :
+                    if (key_location != JAVA_KEYLOCATION_KEYPAD) {
+                        kbd_put_keycode(224);
+                    }
+                    vk = KEY_UP;
+                    break;
+                case JAVA_KEY_ARROW_DOWN :
+                    if (key_location != JAVA_KEYLOCATION_KEYPAD) {
+                        kbd_put_keycode(224);
+                    }
+                    vk = KEY_DOWN;
+                    break;
+                case JAVA_KEY_ARROW_LEFT :
+                    if (key_location != JAVA_KEYLOCATION_KEYPAD) {
+                        kbd_put_keycode(224);
+                    }
+                    vk = KEY_LEFT;
+                    break;
+                case JAVA_KEY_ARROW_RIGHT :
+                    if (key_location != JAVA_KEYLOCATION_KEYPAD) {
+                        kbd_put_keycode(224);
+                    }
+                    vk = KEY_RIGHT;
+                    break;
+
+                case JAVA_KEY_PAGE_UP :
+                    return 73;
+                case JAVA_KEY_PAGE_DOWN :
+                    return 81;
+                case JAVA_KEY_HOME :
+                    return 71;
+                case JAVA_KEY_END :
+                    return 79;
+                case JAVA_KEY_INSERT :
+                    return 82;
+
+                case JAVA_KEY_KEYPAD_MULTIPLY :
+                    return 55;
+                case JAVA_KEY_KEYPAD_ADD :
+                    return 78;
+                case JAVA_KEY_KEYPAD_SUBTRACT :
+                    return 74;
+                case JAVA_KEY_KEYPAD_DECIMAL :
+                    return 83;
+                case JAVA_KEY_KEYPAD_DIVIDE :
+                    return 53;
+                case JAVA_KEY_KEYPAD_0 :
+                    return 82;
+                case JAVA_KEY_KEYPAD_1 :
+                    return 79;
+                case JAVA_KEY_KEYPAD_2 :
+                    return 80;
+                case JAVA_KEY_KEYPAD_3 :
+                    return 81;
+                case JAVA_KEY_KEYPAD_4 :
+                    return 75;
+                case JAVA_KEY_KEYPAD_5 :
+                    return 76;
+                case JAVA_KEY_KEYPAD_6 :
+                    return 77;
+                case JAVA_KEY_KEYPAD_7 :
+                    return 71;
+                case JAVA_KEY_KEYPAD_8 :
+                    return 72;
+                case JAVA_KEY_KEYPAD_9 :
+                    return 73;
+                case JAVA_KEY_KEYPAD_CR :
+                    return 28;
+                case JAVA_KEY_SCROLL_LOCK :
+                    return 70;
+                case JAVA_KEY_PAUSE :
+                case JAVA_KEY_BREAK :
+                    return 198;
+                case JAVA_KEY_PRINT_SCREEN :
+                    //not support
+                    return -1;
+                    break;
+                default :
+                    return -1;
+                    break;
+            }
+        }
+
+    }
+    else //state_mask == 0
+    { //character keys
+        if (ctrl_mask == 0 && shift_mask != 0 && alt_mask == 0) { //shift + character keys
+            switch(vk) {
+                case '`' :
+                    vk = '~';
+                    break;
+                case '1' :
+                    vk = '!';
+                    break;
+                case '2' :
+                    vk = '@';
+                    break;
+                case '3' :
+                    vk = '#';
+                    break;
+                case '4' :
+                    vk = '$';
+                    break;
+                case '5' :
+                    vk = '%';
+                    break;
+                case '6' :
+                    vk = '^';
+                    break;
+                case '7' :
+                    vk = '&';
+                    break;
+                case '8' :
+                    vk = '*';
+                    break;
+                case '9' :
+                    vk = '(';
+                    break;
+                case '0' :
+                    vk = ')';
+                    break;
+                case '-' :
+                    vk = '_';
+                    break;
+                case '=' :
+                    vk = '+';
+                    break;
+                case '\\' :
+                    vk = '|';
+                    break;
+                case '[' :
+                    vk = '{';
+                    break;
+                case ']' :
+                    vk = '}';
+                    break;
+                case ';' :
+                    vk = ':';
+                    break;
+                case '\'' :
+                    vk = '\"';
+                    break;
+                case ',' :
+                    vk = '<';
+                    break;
+                case '.' :
+                    vk = '>';
+                    break;
+                case '/' :
+                    vk = '?';
+                    break;
+                default :
+                    break;
+            }
+        }
+    }
+
+    return vkkey2scancode[vk];
+}
diff --git a/tizen/src/skin/maruskin_keymap.h b/tizen/src/skin/maruskin_keymap.h
new file mode 100644 (file)
index 0000000..cd2c96a
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * keymap
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARUSKIN_KEYMAP_H_
+#define MARUSKIN_KEYMAP_H_
+
+
+/* keep it consistent with emulator-skin(swt) virtual keycode */
+#define JAVA_KEYCODE_BIT (1 << 24)
+#define JAVA_KEYCODE_NO_FOCUS (1 << 19)
+#define JAVA_KEYCODE_BIT_CTRL (1 << 18)
+#define JAVA_KEYCODE_BIT_SHIFT (1 << 17)
+#define JAVA_KEYCODE_BIT_ALT (1 << 16)
+
+//key location
+#define JAVA_KEYLOCATION_KEYPAD (1 << 1)
+#define JAVA_KEYLOCATION_LEFT (1 << 14)
+#define JAVA_KEYLOCATION_RIGHT (1 << 17)
+
+#define JAVA_KEY_MASK 0xFFFF;
+
+enum JAVA_KEYCODE {
+    JAVA_KEY_ARROW_UP = 1,
+    JAVA_KEY_ARROW_DOWN,
+    JAVA_KEY_ARROW_LEFT,
+    JAVA_KEY_ARROW_RIGHT,
+    JAVA_KEY_PAGE_UP,
+    JAVA_KEY_PAGE_DOWN,
+    JAVA_KEY_HOME,
+    JAVA_KEY_END,
+    JAVA_KEY_INSERT,
+    JAVA_KEY_F1 = 10,
+    JAVA_KEY_F20 = 29,
+    JAVA_KEY_KEYPAD_MULTIPLY = 42,
+    JAVA_KEY_KEYPAD_ADD = 43,
+    JAVA_KEY_KEYPAD_SUBTRACT = 45,
+    JAVA_KEY_KEYPAD_DECIMAL = 46,
+    JAVA_KEY_KEYPAD_DIVIDE = 47,
+    JAVA_KEY_KEYPAD_0 = 48,
+    JAVA_KEY_KEYPAD_1 = 49,
+    JAVA_KEY_KEYPAD_2 = 50,
+    JAVA_KEY_KEYPAD_3 = 51,
+    JAVA_KEY_KEYPAD_4 = 52,
+    JAVA_KEY_KEYPAD_5 = 53,
+    JAVA_KEY_KEYPAD_6 = 54,
+    JAVA_KEY_KEYPAD_7 = 55,
+    JAVA_KEY_KEYPAD_8 = 56,
+    JAVA_KEY_KEYPAD_9 = 57,
+    JAVA_KEY_KEYPAD_CR = 80,
+    JAVA_KEY_CAPS_LOCK = 82,
+    JAVA_KEY_NUM_LOCK,
+    JAVA_KEY_SCROLL_LOCK,
+    JAVA_KEY_PAUSE,
+    JAVA_KEY_BREAK,
+    JAVA_KEY_PRINT_SCREEN
+};
+
+
+#define KEY_MAX 0777
+
+#define KEY_F0 0410
+#define KEY_F(n) (KEY_F0+(n))
+
+#define KEY_DOWN 0402
+#define KEY_UP 0403
+#define KEY_LEFT 0404
+#define KEY_RIGHT 0405
+
+#define KEY_BTAB 0541
+
+
+#define SHIFT 0
+static const int vkkey2scancode[KEY_MAX] = {
+    [0 ... (KEY_MAX - 1)] = -1,
+
+    [0x01b] = 1, /* Escape */
+    ['1'] = 2,
+    ['2'] = 3,
+    ['3'] = 4,
+    ['4'] = 5,
+    ['5'] = 6,
+    ['6'] = 7,
+    ['7'] = 8,
+    ['8'] = 9,
+    ['9'] = 10,
+    ['0'] = 11,
+    ['-'] = 12,
+    ['='] = 13,
+    [0x07f] = 83, /* Delete */
+    [0x008] = 14, /* Backspace */
+
+    ['\t'] = 15, /* Tab */
+    ['q'] = 16,
+    ['w'] = 17,
+    ['e'] = 18,
+    ['r'] = 19,
+    ['t'] = 20,
+    ['y'] = 21,
+    ['u'] = 22,
+    ['i'] = 23,
+    ['o'] = 24,
+    ['p'] = 25,
+    ['['] = 26,
+    [']'] = 27,
+    ['\n'] = 28, /* Return */
+    ['\r'] = 28, /* Return */
+
+    ['a'] = 30,
+    ['s'] = 31,
+    ['d'] = 32,
+    ['f'] = 33,
+    ['g'] = 34,
+    ['h'] = 35,
+    ['j'] = 36,
+    ['k'] = 37,
+    ['l'] = 38,
+    [';'] = 39,
+    ['\''] = 40, /* Single quote */
+    ['`'] = 41,
+    ['\\'] = 43, /* Backslash */
+
+    ['z'] = 44,
+    ['x'] = 45,
+    ['c'] = 46,
+    ['v'] = 47,
+    ['b'] = 48,
+    ['n'] = 49,
+    ['m'] = 50,
+    [','] = 51,
+    ['.'] = 52,
+    ['/'] = 53,
+
+    [' '] = 57, /* Space */
+
+    [KEY_F(1)] = 59, /* Function Key 1 */
+    [KEY_F(2)] = 60, /* Function Key 2 */
+    [KEY_F(3)] = 61, /* Function Key 3 */
+    [KEY_F(4)] = 62, /* Function Key 4 */
+    [KEY_F(5)] = 63, /* Function Key 5 */
+    [KEY_F(6)] = 64, /* Function Key 6 */
+    [KEY_F(7)] = 65, /* Function Key 7 */
+    [KEY_F(8)] = 66, /* Function Key 8 */
+    [KEY_F(9)] = 67, /* Function Key 9 */
+    [KEY_F(10)] = 68, /* Function Key 10 */
+    [KEY_F(11)] = 87, /* Function Key 11 */
+    [KEY_F(12)] = 88, /* Function Key 12 */
+
+    [KEY_UP] = 72, /* Up Arrow */
+    [KEY_LEFT] = 75, /* Left Arrow */
+    [KEY_RIGHT] = 77, /* Right Arrow */
+    [KEY_DOWN] = 80, /* Down Arrow */
+
+    ['!'] = 2 | SHIFT,
+    ['@'] = 3 | SHIFT,
+    ['#'] = 4 | SHIFT,
+    ['$'] = 5 | SHIFT,
+    ['%'] = 6 | SHIFT,
+    ['^'] = 7 | SHIFT,
+    ['&'] = 8 | SHIFT,
+    ['*'] = 9 | SHIFT,
+    ['('] = 10 | SHIFT,
+    [')'] = 11 | SHIFT,
+    ['_'] = 12 | SHIFT,
+    ['+'] = 13 | SHIFT,
+
+    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
+    ['Q'] = 16 | SHIFT,
+    ['W'] = 17 | SHIFT,
+    ['E'] = 18 | SHIFT,
+    ['R'] = 19 | SHIFT,
+    ['T'] = 20 | SHIFT,
+    ['Y'] = 21 | SHIFT,
+    ['U'] = 22 | SHIFT,
+    ['I'] = 23 | SHIFT,
+    ['O'] = 24 | SHIFT,
+    ['P'] = 25 | SHIFT,
+    ['{'] = 26 | SHIFT,
+    ['}'] = 27 | SHIFT,
+
+    ['A'] = 30 | SHIFT,
+    ['S'] = 31 | SHIFT,
+    ['D'] = 32 | SHIFT,
+    ['F'] = 33 | SHIFT,
+    ['G'] = 34 | SHIFT,
+    ['H'] = 35 | SHIFT,
+    ['J'] = 36 | SHIFT,
+    ['K'] = 37 | SHIFT,
+    ['L'] = 38 | SHIFT,
+    [':'] = 39 | SHIFT,
+    ['"'] = 40 | SHIFT,
+    ['~'] = 41 | SHIFT,
+    ['|'] = 43 | SHIFT,
+
+    ['Z'] = 44 | SHIFT,
+    ['X'] = 45 | SHIFT,
+    ['C'] = 46 | SHIFT,
+    ['V'] = 47 | SHIFT,
+    ['B'] = 48 | SHIFT,
+    ['N'] = 49 | SHIFT,
+    ['M'] = 50 | SHIFT,
+    ['<'] = 51 | SHIFT,
+    ['>'] = 52 | SHIFT,
+    ['?'] = 53 | SHIFT,
+};
+
+int javakeycode_to_scancode(int java_keycode, int event_type, int key_location);
+
+#endif /* MARUSKIN_KEYMAP_H_ */
diff --git a/tizen/src/skin/maruskin_operation.c b/tizen/src/skin/maruskin_operation.c
new file mode 100644 (file)
index 0000000..6ba6c87
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * operation for emulator skin
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <pthread.h>
+#include "maruskin_operation.h"
+#include "hw/maru_brightness.h"
+#include "maru_sdl.h"
+#include "debug_ch.h"
+#include "sdb.h"
+#include "nbd.h"
+#include "mloop_event.h"
+#include "emul_state.h"
+#include "maruskin_keymap.h"
+#include "emul_state.h"
+#include "hw/maru_pm.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "qemu_socket.h"
+#ifdef _WIN32
+#include "target-i386/hax-i386.h"
+#endif
+
+MULTI_DEBUG_CHANNEL(qemu, skin_operation);
+
+
+#define RESUME_KEY_SEND_INTERVAL 500 // milli-seconds
+#define CLOSE_POWER_KEY_INTERVAL 1200 // milli-seconds
+#define DATA_DELIMITER "#" // in detail info data
+#define TIMEOUT_FOR_SHUTDOWN 10 // seconds
+
+static int requested_shutdown_qemu_gracefully = 0;
+
+static void* run_timed_shutdown_thread( void* args );
+static void send_to_emuld( const char* request_type, int request_size, const char* send_buf, int buf_size );
+
+void start_display( int handle_id, int lcd_size_width, int lcd_size_height, double scale_factor, short rotation_type )
+{
+    INFO( "start_display handle_id:%d, lcd size:%dx%d, scale_factor:%lf, rotation_type:%d\n",
+        handle_id, lcd_size_width, lcd_size_height, scale_factor, rotation_type );
+
+    set_emul_win_scale(scale_factor);
+    maruskin_sdl_init(handle_id, lcd_size_width, lcd_size_height);
+}
+
+void do_mouse_event( int event_type, int x, int y, int z )
+{
+    if( brightness_off ) {
+        TRACE( "reject mouse touch in lcd off : %d, x:%d, y:%d, z:%d\n", event_type, x, y, z );
+        return;
+    }
+
+    TRACE( "mouse_event event_type:%d, x:%d, y:%d, z:%d\n", event_type, x, y, z );
+
+    if (get_emul_multi_touch_state()->multitouch_enable == 1) {
+        maru_finger_processing(x, y, event_type);
+    }
+    else if ( MOUSE_DOWN == event_type || MOUSE_DRAG == event_type) { //single touch
+        kbd_mouse_event(x, y, z, 1);
+    } else if (MOUSE_UP == event_type) {
+        kbd_mouse_event(x, y, z, 0);
+    } else {
+        ERR( "undefined mouse event type:%d\n", event_type );
+    }
+
+#if 0
+#ifdef _WIN32
+    Sleep(1);
+#else
+    usleep(1000);
+#endif
+#endif
+}
+
+void do_key_event( int event_type, int keycode, int key_location )
+{
+    TRACE( "key_event event_type:%d, keycode:%d, key_location:%d\n", event_type, keycode, key_location );
+
+    //is multi-touch mode ?
+    if (get_emul_max_touch_point() > 1) {
+        if (keycode == JAVA_KEYCODE_BIT_CTRL) {
+            if (KEY_PRESSED == event_type) {
+                get_emul_multi_touch_state()->multitouch_enable = 1;
+                INFO("multi-touch enabled\n");
+            } else if (KEY_RELEASED == event_type) {
+                get_emul_multi_touch_state()->multitouch_enable = 0;
+                clear_finger_slot();
+                INFO("multi-touch disabled\n");
+            }
+        } else if (keycode == (JAVA_KEYCODE_NO_FOCUS | JAVA_KEYCODE_BIT_CTRL)) {
+            //release ctrl key when dragging
+            if (KEY_RELEASED == event_type) {
+                get_emul_multi_touch_state()->multitouch_enable = 0;
+                clear_finger_slot();
+                INFO("multi-touch disabled\n");
+            }
+        }
+    }
+
+    if (!mloop_evcmd_get_usbkbd_status()) {
+       return;
+    }
+
+    int scancode = javakeycode_to_scancode(keycode, event_type, key_location);
+    TRACE("javakeycode_to_scancode : %d\n", scancode);
+
+    if (scancode == -1) {
+        INFO("cannot find scancode\n");
+        return;
+    }
+
+    if (KEY_PRESSED == event_type) {
+        kbd_put_keycode(scancode);
+    } else if (KEY_RELEASED == event_type) {
+        kbd_put_keycode(scancode | 0x80);
+    }
+}
+
+void do_hardkey_event( int event_type, int keycode )
+{
+    TRACE( "do_hardkey_event event_type:%d, keycode:%d\n", event_type, keycode );
+
+    if ( is_suspended_state() ) {
+        if ( KEY_PRESSED == event_type ) {
+            if ( kbd_mouse_is_absolute() ) {
+                // home key or power key is used for resume.
+                if ( ( HARD_KEY_HOME == keycode ) || ( HARD_KEY_POWER == keycode ) ) {
+                    INFO( "user requests system resume.\n" );
+                    resume();
+#ifdef _WIN32
+                    Sleep( RESUME_KEY_SEND_INTERVAL );
+#else
+                    usleep( RESUME_KEY_SEND_INTERVAL * 1000 );
+#endif
+                }
+            }
+        }
+    }
+
+    SDL_Event event;
+    memset( &event, 0, sizeof(SDL_Event) );
+
+    event.type = SDL_USEREVENT;
+    event.user.code = SDL_USER_EVENT_CODE_HARDKEY;
+
+    // use pointer as integer
+    event.user.data1 = (void*) event_type;
+    event.user.data2 = (void*) keycode;
+
+    // see qemu_ds_refresh in maru_sdl.c
+    SDL_PushEvent( &event );
+
+}
+
+void do_scale_event( double scale_factor )
+{
+    INFO( "do_scale_event scale_factor:%lf", scale_factor);
+
+    set_emul_win_scale(scale_factor);
+
+    //TODO: thread safe
+    //qemu refresh
+    //vga_hw_invalidate();
+    //vga_hw_update();
+}
+
+void do_rotation_event( int rotation_type)
+{
+
+    INFO( "do_rotation_event rotation_type:%d", rotation_type);
+
+    char send_buf[32] = { 0 };
+
+    switch ( rotation_type ) {
+        case ROTATION_PORTRAIT:
+            sprintf( send_buf, "1\n3\n0\n-9.80665\n0\n" );
+            break;
+        case ROTATION_LANDSCAPE:
+            sprintf( send_buf, "1\n3\n-9.80665\n0\n0\n" );
+            break;
+        case ROTATION_REVERSE_PORTRAIT:
+            sprintf( send_buf, "1\n3\n0\n9.80665\n0\n" );
+            break;
+        case ROTATION_REVERSE_LANDSCAPE:
+            sprintf(send_buf, "1\n3\n9.80665\n0\n0\n");
+            break;
+
+        default:
+            break;
+    }
+
+    send_to_emuld( "sensor\n\n\n\n", 10, send_buf, 32 );
+
+    set_emul_rotation( rotation_type );
+
+}
+
+QemuSurfaceInfo* get_screenshot_info( void ) {
+
+    DisplaySurface* qemu_display_surface = get_qemu_display_surface();
+
+    if ( !qemu_display_surface ) {
+        ERR( "qemu surface is NULL.\n" );
+        return NULL;
+    }
+
+    QemuSurfaceInfo* info = (QemuSurfaceInfo*) g_malloc0( sizeof(QemuSurfaceInfo) );
+    if ( !info ) {
+        ERR( "Fail to malloc for QemuSurfaceInfo.\n");
+        return NULL;
+    }
+
+    int length = qemu_display_surface->linesize * qemu_display_surface->height;
+    INFO( "screenshot data length:%d\n", length );
+
+    if ( 0 >= length ) {
+        g_free( info );
+        ERR( "screenshot data ( 0 >=length ). length:%d\n", length );
+        return NULL;
+    }
+
+    info->pixel_data = (unsigned char*) g_malloc0( length );
+    if ( !info->pixel_data ) {
+        g_free( info );
+        ERR( "Fail to malloc for pixel data.\n");
+        return NULL;
+    }
+
+    memcpy( info->pixel_data, qemu_display_surface->data, length );
+    info->pixel_data_length = length;
+
+    return info;
+
+}
+
+void free_screenshot_info( QemuSurfaceInfo* info ) {
+    if( info ) {
+        if( info->pixel_data ) {
+            g_free( info->pixel_data );
+        }
+        g_free( info );
+    }
+}
+
+DetailInfo* get_detail_info( int qemu_argc, char** qemu_argv ) {
+
+    DetailInfo* detail_info = g_malloc0( sizeof(DetailInfo) );
+    if ( !detail_info ) {
+        ERR( "Fail to malloc for DetailInfo.\n" );
+        return NULL;
+    }
+
+    int i = 0;
+    int total_len = 0;
+    int delimiter_len = strlen( DATA_DELIMITER );
+
+    for ( i = 0; i < qemu_argc; i++ ) {
+        total_len += strlen( qemu_argv[i] );
+        total_len += delimiter_len;
+    }
+
+#ifdef _WIN32
+    const int HAX_LEN = 32;
+    char hax_error[HAX_LEN];
+    memset( hax_error, 0, HAX_LEN );
+
+    int hax_err_len = 0;
+    hax_err_len = sprintf( hax_error + hax_err_len, "%s", "hax_error=" );
+
+    int error = 0;
+    if ( !ret_hax_init ) {
+        if ( -ENOSPC == ret_hax_init ) {
+            error = 1;
+        }
+    }
+    hax_err_len += sprintf( hax_error + hax_err_len, "%s", error ? "true" : "false" );
+    total_len += hax_err_len;
+#endif
+
+    char* info_data = g_malloc0( total_len + 1 );
+    if ( !info_data ) {
+        g_free( detail_info );
+        ERR( "Fail to malloc for info data.\n" );
+        return NULL;
+    }
+
+    int len = 0;
+    total_len = 0;
+
+    for ( i = 0; i < qemu_argc; i++ ) {
+        len = strlen( qemu_argv[i] );
+        sprintf( info_data + total_len, "%s%s", qemu_argv[i], DATA_DELIMITER );
+        total_len += len + delimiter_len;
+    }
+
+#ifdef _WIN32
+    snprintf( info_data + total_len, total_len + 1, "%s", hax_error );
+    total_len += hax_err_len;
+#endif
+
+    INFO( "################## detail info data ####################\n" );
+    INFO( "%s\n", info_data );
+
+    detail_info->data = info_data;
+    detail_info->data_length = total_len;
+
+    return detail_info;
+
+}
+
+void free_detail_info( DetailInfo* detail_info ) {
+    if ( detail_info ) {
+        if ( detail_info->data ) {
+            g_free( detail_info->data );
+        }
+        g_free( detail_info );
+    }
+}
+
+void open_shell( void ) {
+}
+
+void onoff_usb_kbd( int on )
+{
+    INFO( "usb kbd on/off:%d\n", on );
+    //TODO
+    mloop_evcmd_usbkbd(on);
+}
+
+
+void request_close( void )
+{
+    INFO( "request_close\n" );
+
+    do_hardkey_event( KEY_PRESSED, HARD_KEY_POWER );
+
+#ifdef _WIN32
+        Sleep( CLOSE_POWER_KEY_INTERVAL );
+#else
+        usleep( CLOSE_POWER_KEY_INTERVAL * 1000 );
+#endif
+
+    do_hardkey_event( KEY_RELEASED, HARD_KEY_POWER );
+
+}
+
+void shutdown_qemu_gracefully( void ) {
+
+    requested_shutdown_qemu_gracefully = 1;
+
+    pthread_t thread_id;
+    if( 0 > pthread_create( &thread_id, NULL, run_timed_shutdown_thread, NULL ) ) {
+        ERR( "!!! Fail to create run_timed_shutdown_thread. shutdown qemu right now !!!\n"  );
+        qemu_system_shutdown_request();
+    }
+
+}
+
+int is_requested_shutdown_qemu_gracefully( void ) {
+    return requested_shutdown_qemu_gracefully;
+}
+
+static void* run_timed_shutdown_thread( void* args ) {
+
+    send_to_emuld( "system\n\n\n\n", 10, "shutdown", 8 );
+
+    int sleep_interval_time = 1000; // milli-seconds
+
+    int i;
+    for ( i = 0; i < TIMEOUT_FOR_SHUTDOWN; i++ ) {
+#ifdef _WIN32
+        Sleep( sleep_interval_time );
+#else
+        usleep( sleep_interval_time * 1000 );
+#endif
+        // do not use logger to help user see log in console
+        fprintf( stdout, "Wait for shutdown qemu...%d\n", ( i + 1 ) );
+    }
+
+    WARN( "Shutdown qemu !!!\n" );
+    qemu_system_shutdown_request();
+
+    return NULL;
+
+}
+
+static void send_to_emuld( const char* request_type, int request_size, const char* send_buf, int buf_size ) {
+
+    int s = sdb_loopback_client( (uint16_t) ( tizen_base_port + SDB_TCP_EMULD_INDEX ), SOCK_STREAM );
+
+    if ( s < 0 ) {
+        ERR( "can't create socket to talk to the sdb forwarding session \n" );
+        ERR( "[127.0.0.1:%d/tcp] connect fail (%d:%s)\n" , tizen_base_port + SDB_TCP_EMULD_INDEX , errno, strerror(errno) );
+        return;
+    }
+
+    socket_send( s, (char*)request_type, request_size );
+    socket_send( s, &buf_size, 4 );
+    socket_send( s, (char*)send_buf, buf_size );
+
+    INFO( "send to emuld [req_type:%s, send_data:%s, send_size:%d] 127.0.0.1:%d/tcp \n",
+        request_type, send_buf, buf_size, tizen_base_port + SDB_TCP_EMULD_INDEX );
+
+#ifdef _WIN32
+    closesocket( s );
+#else
+    close( s );
+#endif
+
+}
diff --git a/tizen/src/skin/maruskin_operation.h b/tizen/src/skin/maruskin_operation.h
new file mode 100644 (file)
index 0000000..04c4ad1
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * operation for emulator skin
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARUSKIN_OPERATION_H_
+#define MARUSKIN_OPERATION_H_
+
+extern int ret_hax_init;
+
+struct QemuSurfaceInfo {
+    unsigned char* pixel_data;
+    int pixel_data_length;
+};
+typedef struct QemuSurfaceInfo QemuSurfaceInfo;
+
+struct DetailInfo {
+    char* data;
+    int data_length;
+};
+typedef struct DetailInfo DetailInfo;
+
+void start_display( int handle_id, int lcd_size_width, int lcd_size_height, double scale_factor, short rotation_type );
+
+void do_mouse_event( int event_type, int x, int y, int z );
+
+void do_key_event( int event_type, int keycode, int key_location );
+
+void do_hardkey_event( int event_type, int keycode );
+
+void do_scale_event( double scale_factor);
+
+void do_rotation_event( int rotation_type );
+
+QemuSurfaceInfo* get_screenshot_info( void );
+
+DetailInfo* get_detail_info( int qemu_argc, char** qemu_argv );
+
+void free_detail_info( DetailInfo* detail_info );
+
+void free_screenshot_info( QemuSurfaceInfo* );
+
+void open_shell(void);
+
+void onoff_usb_kbd( int on );
+
+void request_close( void );
+
+void shutdown_qemu_gracefully( void );
+
+int is_requested_shutdown_qemu_gracefully( void );
+
+#endif /* MARUSKIN_OPERATION_H_ */
diff --git a/tizen/src/skin/maruskin_server.c b/tizen/src/skin/maruskin_server.c
new file mode 100644 (file)
index 0000000..975b982
--- /dev/null
@@ -0,0 +1,1104 @@
+/*
+ * socket server for emulator skin
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include "maruskin_server.h"
+#include "maruskin_operation.h"
+#include "qemu-thread.h"
+#include "emul_state.h"
+#include "maru_sdl.h"
+#include "maruskin_client.h"
+#include "emulator.h"
+#include "debug_ch.h"
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+
+MULTI_DEBUG_CHANNEL( qemu, skin_server );
+
+#define MAX_REQ_ID 0x7fffffff
+#define RECV_BUF_SIZE 32
+#define RECV_HEADER_SIZE 12
+
+#define SEND_HEADER_SIZE 10
+#define SEND_BIG_BUF_SIZE 1024 * 1024 * 2
+#define SEND_BUF_SIZE 512
+
+#define HEART_BEAT_INTERVAL 1
+#define HEART_BEAT_FAIL_COUNT 5
+#define HEART_BEAT_EXPIRE_COUNT 5
+
+#if 0 // do not restarting skin process ( prevent from abnormal behavior killing a skin process in Windows )
+#define RESTART_CLIENT_MAX_COUNT 1
+#else
+#define RESTART_CLIENT_MAX_COUNT 0
+#endif
+
+#define PORT_RETRY_COUNT 50
+
+#define TEST_HB_IGNORE "test.hb.ignore"
+#define SKIN_CONFIG_PROP ".skinconfig.properties"
+
+enum {
+    RECV_START = 1,
+    RECV_MOUSE_EVENT = 10,
+    RECV_KEY_EVENT = 11,
+    RECV_HARD_KEY_EVENT = 12,
+    RECV_CHANGE_LCD_STATE = 13,
+    RECV_OPEN_SHELL = 14,
+    RECV_USB_KBD = 15,
+    RECV_SCREEN_SHOT = 16,
+    RECV_DETAIL_INFO = 17,
+    RECV_RESPONSE_HEART_BEAT = 900,
+    RECV_CLOSE = 998,
+    RECV_RESPONSE_SHUTDOWN = 999,
+};
+
+enum {
+    SEND_HEART_BEAT = 1,
+    SEND_SCREEN_SHOT = 2,
+    SEND_DETAIL_INFO = 3,
+    SEND_SENSOR_DAEMON_START = 800,
+    SEND_SHUTDOWN = 999,
+};
+
+static int seq_req_id = 0;
+
+static uint16_t svr_port = 0;
+static int server_sock = 0;
+static int client_sock = 0;
+static int stop_server = 0;
+static int is_sensord_initialized = 0;
+static int ready_server = 0;
+static int ignore_heartbeat = 0;
+static int is_force_close_client = 0;
+
+static int is_started_heartbeat = 0;
+static int stop_heartbeat = 0;
+static int recv_heartbeat_count = 0;
+static pthread_t thread_id_heartbeat;
+static pthread_mutex_t mutex_heartbeat = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond_heartbeat = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mutex_recv_heartbeat_count = PTHREAD_MUTEX_INITIALIZER;
+
+static int skin_argc = 0;
+static char** skin_argv = NULL;
+static int qmu_argc = 0;
+static char** qmu_argv = NULL;
+
+static void parse_skin_args( void );
+static void parse_skinconfig_prop( void );
+static void* run_skin_server( void* args );
+static int recv_n( int client_sock, char* read_buf, int recv_len );
+static void make_header( int client_sock, short send_cmd, int data_length, char* sendbuf, int print_log );
+static int send_skin_header_only( int client_sock, short send_cmd, int print_log );
+static int send_skin_data( int client_sock, short send_cmd, unsigned char* data, int length, int big_data );
+static int send_n( int client_sock, unsigned char* data, int length, int big_data );
+
+static void* do_heart_beat( void* args );
+static int start_heart_beat( void );
+static void stop_heart_beat( void );
+
+int start_skin_server( int argc, char** argv, int qemu_argc, char** qemu_argv ) {
+
+    skin_argc = argc;
+    skin_argv = argv;
+
+    parse_skinconfig_prop();
+
+    // arguments have higher priority than '.skinconfig.properties'
+    parse_skin_args();
+
+    INFO( "ignore_heartbeat:%d\n", ignore_heartbeat );
+
+    qmu_argc = qemu_argc;
+    qmu_argv = qemu_argv;
+
+    QemuThread qemu_thread;
+
+    qemu_thread_create( &qemu_thread, run_skin_server, NULL );
+
+    return 1;
+
+}
+
+void shutdown_skin_server( void ) {
+
+    INFO( "shutdown_skin_server\n" );
+
+    int close_server_socket = 0;
+    int success_send = 0;
+
+    if ( client_sock ) {
+        INFO( "send shutdown to skin.\n" );
+        if ( 0 > send_skin_header_only( client_sock, SEND_SHUTDOWN, 1 ) ) {
+            ERR( "fail to send SEND_SHUTDOWN to skin.\n" );
+            close_server_socket = 1;
+        } else {
+            success_send = 1;
+            // skin sent RECV_RESPONSE_SHUTDOWN.
+        }
+    }
+
+    if( success_send ) {
+
+        int count = 0;
+        int max_sleep_count = 10;
+
+        while ( 1 ) {
+
+            if ( max_sleep_count < count ) {
+                close_server_socket = 1;
+                break;
+            }
+
+            if ( stop_server ) {
+                INFO( "skin client sent normal shutdown response.\n" );
+                break;
+            } else {
+#ifdef _WIN32
+                Sleep( 1 ); // 1ms
+#else
+                usleep( 1000 ); // 1ms
+#endif
+                count++;
+            }
+        }
+    }
+
+    stop_server = 1;
+    is_force_close_client = 1;
+
+    if ( client_sock ) {
+#ifdef _WIN32
+        closesocket( client_sock );
+#else
+        close( client_sock );
+#endif
+    }
+
+    if ( close_server_socket ) {
+        WARN( "skin client did not send normal shutdown response.\n" );
+        if ( server_sock ) {
+#ifdef _WIN32
+            closesocket( server_sock );
+#else
+            close( server_sock );
+#endif
+        }
+    }
+
+}
+
+void notify_sensor_daemon_start( void ) {
+    INFO( "notify_sensor_daemon_start\n" );
+    is_sensord_initialized = 1;
+    if ( client_sock ) {
+        if ( 0 > send_skin_header_only( client_sock, SEND_SENSOR_DAEMON_START, 1 ) ) {
+            ERR( "fail to send SEND_SENSOR_DAEMON_START to skin.\n" );
+        }
+    }
+}
+
+int is_ready_skin_server( void ) {
+    return ready_server;
+}
+
+int get_skin_server_port( void ) {
+    return svr_port;
+}
+
+static void parse_skinconfig_prop( void ) {
+
+    int target_path_len = strlen( tizen_target_path );
+    char skin_config_path[target_path_len + 32];
+
+    memset( skin_config_path, 0, target_path_len + 32 );
+    strcpy( skin_config_path, tizen_target_path );
+#ifdef _WIN32
+    strcat( skin_config_path, "\\" );
+#else
+    strcat( skin_config_path, "/" );
+#endif
+    strcat( skin_config_path, SKIN_CONFIG_PROP );
+
+    FILE* fp = fopen( skin_config_path, "r" );
+
+    if ( !fp ) {
+        INFO( "There is no %s. skin_config_path:%s\n", SKIN_CONFIG_PROP, skin_config_path );
+        return;
+    }
+
+    fseek( fp, 0L, SEEK_END );
+    int buf_size = ftell( fp );
+    rewind( fp );
+
+    if ( 0 >= buf_size ) {
+        WARN( "%s contents is empty.\n", SKIN_CONFIG_PROP );
+        fclose( fp );
+        return;
+    }
+
+    char* buf = g_malloc0( buf_size );
+    if ( !buf ) {
+        ERR( "Fail to malloc for %s\n", SKIN_CONFIG_PROP );
+        fclose( fp );
+        return;
+    }
+
+    int read_cnt = 0;
+    int total_cnt = 0;
+
+    while ( 1 ) {
+
+        if ( total_cnt == buf_size ) {
+            break;
+        }
+
+        read_cnt = fread( (void*) ( buf + read_cnt ), 1, buf_size - total_cnt, fp );
+        if ( 0 > read_cnt ) {
+            break;
+        } else {
+            total_cnt += read_cnt;
+        }
+
+    }
+
+    fclose( fp );
+
+    INFO( "====== %s ======\n%s\n====================================\n", SKIN_CONFIG_PROP, buf );
+
+    char hb_ignore_prop[32];
+    memset( hb_ignore_prop, 0, 32 );
+    strcat( hb_ignore_prop, TEST_HB_IGNORE );
+    strcat( hb_ignore_prop, "=true" );
+
+    char* line_str = strtok( buf, "\n" );
+
+    while ( 1 ) {
+
+        if ( line_str ) {
+
+            TRACE( "prop line_str:%s\n", line_str );
+
+            if ( 0 == strcmp( line_str, hb_ignore_prop ) ) {
+                ignore_heartbeat = 1;
+                INFO( "ignore heartbeat by %s\n", SKIN_CONFIG_PROP );
+            }
+
+        } else {
+            break;
+        }
+
+        line_str = strtok( NULL, "\n" );
+
+    }
+
+    g_free( buf );
+
+}
+
+static void parse_skin_args( void ) {
+
+    int i;
+    for( i = 0; i < skin_argc; i++ ) {
+
+        char* arg = NULL;
+        arg = strdup( skin_argv[i] );
+
+        if( arg ) {
+
+            char* key = strtok( arg, "=" );
+            char* value = strtok( NULL, "=" );
+
+            INFO( "skin params key:%s, value:%s\n", key, value );
+
+            if( 0 == strcmp( TEST_HB_IGNORE, key ) ) {
+                if( 0 == strcmp( "true", value ) ) {
+                    ignore_heartbeat = 1;
+                }else if( 0 == strcmp( "false", value ) ) {
+                    ignore_heartbeat = 0;
+                }
+            }
+
+            free( arg );
+
+        }else {
+            ERR( "fail to strdup." );
+        }
+
+    }
+
+}
+
+static void* run_skin_server( void* args ) {
+
+    struct sockaddr server_addr, client_addr;
+    socklen_t server_len, client_len;
+    int shutdown_qmu = 0;
+
+    INFO("run skin server\n");
+
+    if ( 0 > ( server_sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) ) {
+        ERR( "create listen socket error\n" );
+        perror( "create listen socket error : " );
+        shutdown_qmu = 1;
+        goto cleanup;
+    }
+
+    memset( &server_addr, '\0', sizeof( server_addr ) );
+    ( (struct sockaddr_in *) &server_addr )->sin_family = AF_INET;
+    memcpy( &( (struct sockaddr_in *) &server_addr )->sin_addr, "\177\000\000\001", 4 ); // 127.0.0.1
+    ( (struct sockaddr_in *) &server_addr )->sin_port = htons( 0 );
+
+    server_len = sizeof( server_addr );
+
+    if ( 0 != bind( server_sock, &server_addr, server_len ) ) {
+        ERR( "skin server bind error\n" );
+        perror( "skin server bind error : " );
+        shutdown_qmu = 1;
+        goto cleanup;
+    }
+
+    memset( &server_addr, '\0', sizeof( server_addr ) );
+    getsockname( server_sock, (struct sockaddr *) &server_addr, &server_len );
+    svr_port = ntohs( ( (struct sockaddr_in *) &server_addr )->sin_port );
+
+    INFO( "success to bind port[127.0.0.1:%d/tcp] for skin_server in host \n", svr_port );
+
+    if ( 0 > listen( server_sock, 4 ) ) {
+        ERR( "skin_server listen error\n" );
+        perror( "skin_server listen error : " );
+        shutdown_qmu = 1;
+        goto cleanup;
+    }
+
+    client_len = sizeof( client_addr );
+
+    char recvbuf[RECV_BUF_SIZE];
+
+    INFO( "skin server start...port:%d\n", svr_port );
+
+    while ( 1 ) {
+
+        if ( stop_server ) {
+            INFO( "close server socket normally.\n" );
+            break;
+        }
+
+        ready_server = 1;
+
+        if( !is_started_heartbeat ) {
+            if ( !start_heart_beat() ) {
+                ERR( "Fail to start heartbeat thread.\n" );
+                shutdown_qmu = 1;
+                break;
+            }
+        }
+
+        INFO( "start accepting socket...\n" );
+
+        if ( 0 > ( client_sock = accept( server_sock, (struct sockaddr *) &client_addr, &client_len ) ) ) {
+            ERR( "skin_servier accept error\n" );
+            perror( "skin_servier accept error : " );
+            continue;
+        }
+
+        INFO( "accept client : client_sock:%d\n", client_sock );
+
+        while ( 1 ) {
+
+            if ( stop_server ) {
+                INFO( "stop receiving current client socket.\n" );
+                break;
+            }
+
+            stop_heartbeat = 0;
+            memset( &recvbuf, 0, RECV_BUF_SIZE );
+
+            int read_cnt = recv_n( client_sock, recvbuf, RECV_HEADER_SIZE );
+
+            if ( 0 > read_cnt ) {
+
+                if( is_force_close_client ) {
+                    WARN( "force close client socket.\n" );
+                    is_force_close_client = 0;
+                }else {
+                    ERR( "skin_server read error:%d\n", read_cnt );
+                    perror( "skin_server read error : " );
+                }
+                break;
+
+            } else {
+
+                if ( 0 == read_cnt ) {
+                    ERR( "read_cnt is 0.\n" );
+                    break;
+                }
+
+                int log_cnt;
+                char log_buf[512];
+                memset( log_buf, 0, 512 );
+
+                log_cnt = sprintf( log_buf, "== RECV read_cnt:%d ", read_cnt );
+
+                int uid = 0;
+                int req_id = 0;
+                short cmd = 0;
+                short length = 0;
+
+                char* p = recvbuf;
+
+                memcpy( &uid, p, sizeof( uid ) );
+                p += sizeof( uid );
+                memcpy( &req_id, p, sizeof( req_id ) );
+                p += sizeof( req_id );
+                memcpy( &cmd, p, sizeof( cmd ) );
+                p += sizeof( cmd );
+                memcpy( &length, p, sizeof( length ) );
+
+                uid = ntohl( uid );
+                req_id = ntohl( req_id );
+                cmd = ntohs( cmd );
+                length = ntohs( length );
+
+                log_cnt += sprintf( log_buf + log_cnt, "uid:%d, req_id:%d, cmd:%d, length:%d ", uid, req_id, cmd, length );
+
+                if ( 0 < length ) {
+
+                    if ( RECV_BUF_SIZE < length ) {
+                        ERR( "length is bigger than RECV_BUF_SIZE\n" );
+                        continue;
+                    }
+
+                    memset( &recvbuf, 0, length );
+
+                    int recv_cnt = recv_n( client_sock, recvbuf, length );
+
+                    log_cnt += sprintf( log_buf + log_cnt, "data read_cnt:%d ", recv_cnt );
+
+                    if ( 0 > recv_cnt ) {
+                        ERR( "skin_server read data\n" );
+                        perror( "skin_server read data : " );
+                        break;
+                    } else if ( 0 == recv_cnt ) {
+                        ERR( "data read_cnt is 0.\n" );
+                        break;
+                    } else if ( recv_cnt != length ) {
+                        ERR( "read_cnt is not equal to length.\n" );
+                        break;
+                    }
+
+                }
+
+                switch ( cmd ) {
+                case RECV_START: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_START ==\n" );
+                    INFO( log_buf );
+
+                    if ( 0 >= length ) {
+                        ERR( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    /* keep it consistent with emulator-skin definition */
+                    int handle_id = 0;
+                    int lcd_size_width = 0;
+                    int lcd_size_height = 0;
+                    int scale = 0;
+                    double scale_ratio = 0.0;
+                    short rotation = 0;
+
+                    char* p = recvbuf;
+                    memcpy( &handle_id, p, sizeof( handle_id ) );
+                    p += sizeof( handle_id );
+                    memcpy( &lcd_size_width, p, sizeof( lcd_size_width ) );
+                    p += sizeof( lcd_size_width );
+                    memcpy( &lcd_size_height, p, sizeof( lcd_size_height ) );
+                    p += sizeof( lcd_size_height );
+                    memcpy( &scale, p, sizeof( scale ) );
+                    p += sizeof( scale );
+                    memcpy( &rotation, p, sizeof( rotation ) );
+
+                    handle_id = ntohl( handle_id );
+                    lcd_size_width = ntohl( lcd_size_width );
+                    lcd_size_height = ntohl( lcd_size_height );
+                    scale = ntohl( scale );
+                    scale_ratio = ( (double) scale ) / 100;
+                    rotation = ntohs( rotation );
+
+                    set_emul_win_scale( scale_ratio );
+
+                    start_display( handle_id, lcd_size_width, lcd_size_height, scale_ratio, rotation );
+
+                    break;
+                }
+                case RECV_MOUSE_EVENT: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_MOUSE_EVENT ==\n" );
+                    TRACE( log_buf );
+
+                    if ( 0 >= length ) {
+                        ERR( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    /* keep it consistent with emulator-skin definition */
+                    int event_type = 0;
+                    int x = 0;
+                    int y = 0;
+                    int z = 0;
+
+                    char* p = recvbuf;
+                    memcpy( &event_type, p, sizeof( event_type ) );
+                    p += sizeof( event_type );
+                    memcpy( &x, p, sizeof( x ) );
+                    p += sizeof( x );
+                    memcpy( &y, p, sizeof( y ) );
+                    p += sizeof( y );
+                    memcpy( &z, p, sizeof( z ) );
+
+                    event_type = ntohl( event_type );
+                    x = ntohl( x );
+                    y = ntohl( y );
+                    z = ntohl( z );
+
+                    do_mouse_event( event_type, x, y, z );
+                    break;
+                }
+                case RECV_KEY_EVENT: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_KEY_EVENT ==\n" );
+                    TRACE( log_buf );
+
+                    if ( 0 >= length ) {
+                        ERR( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    /* keep it consistent with emulator-skin definition */
+                    int event_type = 0;
+                    int keycode = 0;
+                    int key_location = 0;
+
+                    char* p = recvbuf;
+                    memcpy( &event_type, p, sizeof( event_type ) );
+                    p += sizeof( event_type );
+                    memcpy( &keycode, p, sizeof( keycode ) );
+                    p += sizeof( keycode );
+                    memcpy( &key_location, p, sizeof( key_location ) );
+
+                    event_type = ntohl( event_type );
+                    keycode = ntohl( keycode );
+                    key_location = ntohl( key_location );
+
+                    do_key_event( event_type, keycode, key_location );
+                    break;
+                }
+                case RECV_HARD_KEY_EVENT: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_HARD_KEY_EVENT ==\n" );
+                    TRACE( log_buf );
+
+                    if ( 0 >= length ) {
+                        ERR( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    /* keep it consistent with emulator-skin definition */
+                    int event_type = 0;
+                    int keycode = 0;
+
+                    char* p = recvbuf;
+                    memcpy( &event_type, p, sizeof( event_type ) );
+                    p += sizeof( event_type );
+                    memcpy( &keycode, p, sizeof( keycode ) );
+
+                    event_type = ntohl( event_type );
+                    keycode = ntohl( keycode );
+
+                    do_hardkey_event( event_type, keycode );
+                    break;
+                }
+                case RECV_CHANGE_LCD_STATE: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_CHANGE_LCD_STATE ==\n" );
+                    TRACE( log_buf );
+
+                    if ( 0 >= length ) {
+                        ERR( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    /* keep it consistent with emulator-skin definition */
+                    int scale = 0;
+                    double scale_ratio = 0.0;
+                    short rotation_type = 0;
+
+                    char* p = recvbuf;
+                    memcpy( &scale, p, sizeof( scale ) );
+                    p += sizeof( scale );
+                    memcpy( &rotation_type, p, sizeof( rotation_type ) );
+
+                    scale = ntohl( scale );
+                    scale_ratio = ( (double) scale ) / 100;
+                    rotation_type = ntohs( rotation_type );
+
+                    if ( get_emul_win_scale() != scale_ratio ) {
+                        do_scale_event( scale_ratio );
+                    }
+
+                    if ( is_sensord_initialized == 1 && get_emul_rotation() != rotation_type ) {
+                        do_rotation_event( rotation_type );
+                    }
+
+                    maruskin_sdl_resize(); //send sdl event
+                    break;
+                }
+                case RECV_SCREEN_SHOT: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_SCREEN_SHOT ==\n" );
+                    TRACE( log_buf );
+
+                    QemuSurfaceInfo* info = get_screenshot_info();
+
+                    if ( info ) {
+                        send_skin_data( client_sock, SEND_SCREEN_SHOT, info->pixel_data, info->pixel_data_length, 1 );
+                        free_screenshot_info( info );
+                    } else {
+                        ERR( "Fail to get screenshot data.\n" );
+                    }
+
+                    break;
+                }
+                case RECV_DETAIL_INFO: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_DETAIL_INFO ==\n" );
+                    TRACE( log_buf );
+
+                    DetailInfo* detail_info = get_detail_info( qmu_argc, qmu_argv );
+
+                    if ( detail_info ) {
+                        send_skin_data( client_sock, SEND_DETAIL_INFO, (unsigned char*) detail_info->data,
+                            detail_info->data_length, 0 );
+                        free_detail_info( detail_info );
+                    } else {
+                        ERR( "Fail to get detail info.\n" );
+                    }
+
+                    break;
+                }
+                case RECV_RESPONSE_HEART_BEAT: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_RESPONSE_HEART_BEAT ==\n" );
+//                    TRACE( log_buf );
+                    TRACE( "recv HB req_id:%d\n", req_id );
+
+                    pthread_mutex_lock( &mutex_recv_heartbeat_count );
+                    recv_heartbeat_count = 0;
+                    pthread_mutex_unlock( &mutex_recv_heartbeat_count );
+
+                    break;
+                }
+                case RECV_OPEN_SHELL: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_OPEN_SHELL ==\n" );
+                    TRACE( log_buf );
+
+                    open_shell();
+                    break;
+                }
+                case RECV_USB_KBD: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_USB_KBD ==\n" );
+                    TRACE( log_buf );
+
+                    if ( 0 >= length ) {
+                        INFO( "there is no data looking at 0 length." );
+                        continue;
+                    }
+
+                    char on = 0;
+                    memcpy( &on, recvbuf, sizeof( on ) );
+                    onoff_usb_kbd( on );
+                    break;
+                }
+                case RECV_CLOSE: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_CLOSE ==\n" );
+                    TRACE( log_buf );
+
+                    request_close();
+                    break;
+                }
+                case RECV_RESPONSE_SHUTDOWN: {
+                    log_cnt += sprintf( log_buf + log_cnt, "RECV_RESPONSE_SHUTDOWN ==\n" );
+                    INFO( log_buf );
+
+                    stop_server = 1;
+                    break;
+                }
+                default: {
+                    log_cnt += sprintf( log_buf + log_cnt, "!!! unknown command : %d\n", cmd );
+                    TRACE( log_buf );
+
+                    ERR( "!!! unknown command : %d\n", cmd );
+                    break;
+                }
+                }
+
+            }
+
+        }
+
+    }
+
+    stop_heart_beat();
+
+cleanup:
+    if ( server_sock ) {
+#ifdef _WIN32
+        closesocket( server_sock );
+#else
+        close( server_sock );
+#endif
+    }
+
+    if( shutdown_qmu ) {
+        ERR( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+        ERR( "!!! Fail to initialize for skin server operation. Shutdown QEMU !!!\n" );
+        ERR( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+        shutdown_qemu_gracefully();
+    }
+
+    return NULL;
+}
+
+static int recv_n( int client_sock, char* read_buf, int recv_len ) {
+
+    int total_cnt = 0;
+    int recv_cnt = 0;
+
+    while ( 1 ) {
+
+        recv_cnt = recv( client_sock, (void*) ( read_buf + recv_cnt ), ( recv_len - recv_cnt ), 0 );
+
+        if ( 0 > recv_cnt ) {
+
+            return recv_cnt;
+
+        } else if ( 0 == recv_cnt ) {
+
+            if ( total_cnt == recv_len ) {
+                return total_cnt;
+            } else {
+                continue;
+            }
+
+        } else {
+
+            total_cnt += recv_cnt;
+
+            if ( total_cnt == recv_len ) {
+                return total_cnt;
+            } else {
+                continue;
+            }
+
+        }
+
+    }
+
+    return 0;
+
+}
+
+static void make_header( int client_sock, short send_cmd, int data_length, char* sendbuf, int print_log ) {
+
+    memset( sendbuf, 0, SEND_HEADER_SIZE );
+
+    int request_id = ( MAX_REQ_ID == seq_req_id ) ? 0 : ++seq_req_id;
+    if( print_log ) {
+        TRACE( "== SEND skin request_id:%d, send_cmd:%d ==\n", request_id, send_cmd );
+    }
+    request_id = htonl( request_id );
+
+    short cmd = send_cmd;
+    cmd = htons( cmd );
+
+    int length = data_length;
+    length = htonl( length );
+
+    char* p = sendbuf;
+    memcpy( p, &request_id, sizeof( request_id ) );
+    p += sizeof( request_id );
+    memcpy( p, &cmd, sizeof( cmd ) );
+    p += sizeof( cmd );
+    memcpy( p, &length, sizeof( length ) );
+
+}
+
+static int send_n( int client_sock, unsigned char* data, int length, int big_data ) {
+
+    int send_cnt = 0;
+    int total_cnt = 0;
+
+    int buf_size = big_data ? SEND_BIG_BUF_SIZE : SEND_BUF_SIZE;
+
+    // use malloc instead of general array definition to avoid seg fault in 'alloca' in MinGW env, only using big buf size.
+    char* databuf = (char*)g_malloc0( buf_size );
+
+    INFO( "send_n start. length:%d\n", length );
+
+    while ( 1 ) {
+
+        if ( total_cnt == length ) {
+            break;
+        }
+
+        if ( buf_size < ( length - total_cnt ) ) {
+            send_cnt = buf_size;
+        } else {
+            send_cnt = ( length - total_cnt );
+        }
+
+        memset( databuf, 0, send_cnt );
+        memcpy( databuf, (char*) ( data + total_cnt ), send_cnt );
+
+        send_cnt = send( client_sock, databuf, send_cnt, 0 );
+
+        if ( 0 > send_cnt ) {
+            ERR( "send_n error. error code:%d\n", send_cnt );
+            return send_cnt;
+        } else {
+            total_cnt += send_cnt;
+        }
+
+    }
+
+    g_free( databuf );
+
+    INFO( "send_n finished.\n" );
+
+    return total_cnt;
+
+}
+
+static int send_skin_header_only( int client_sock, short send_cmd, int print_log ) {
+
+    char headerbuf[SEND_HEADER_SIZE];
+    make_header( client_sock, send_cmd, 0, headerbuf, print_log );
+
+    int send_count = send( client_sock, headerbuf, SEND_HEADER_SIZE, 0 );
+    return send_count;
+
+}
+
+static int send_skin_data( int client_sock, short send_cmd, unsigned char* data, int length, int big_data ) {
+
+    char headerbuf[SEND_HEADER_SIZE];
+    make_header( client_sock, send_cmd, length, headerbuf, 1 );
+
+    int header_cnt = send( client_sock, headerbuf, SEND_HEADER_SIZE, 0 );
+
+    if ( 0 > header_cnt ) {
+        ERR( "send header for data is NULL.\n" );
+        return header_cnt;
+    }
+
+    if ( !data ) {
+        ERR( "send data is NULL.\n" );
+        return -1;
+    }
+
+    int send_cnt = send_n( client_sock, data, length, big_data );
+    INFO( "send_n result:%d\n", send_cnt );
+
+    return send_cnt;
+
+}
+
+static void* do_heart_beat( void* args ) {
+
+    is_started_heartbeat = 1;
+
+    int send_fail_count = 0;
+    int restart_client_count = 0;
+    int need_restart_skin_client = 0;
+    int shutdown = 0;
+
+    while ( 1 ) {
+
+        struct timeval current;
+        gettimeofday( &current, NULL );
+
+        struct timespec ts_heartbeat;
+        ts_heartbeat.tv_sec = current.tv_sec + HEART_BEAT_INTERVAL;
+        ts_heartbeat.tv_nsec = current.tv_usec * 1000;
+
+        pthread_mutex_lock( &mutex_heartbeat );
+        pthread_cond_timedwait( &cond_heartbeat, &mutex_heartbeat, &ts_heartbeat );
+        pthread_mutex_unlock( &mutex_heartbeat );
+
+        if ( stop_heartbeat ) {
+            INFO( "[HB] stop heart beat.\n" );
+            break;
+        }
+
+        if( client_sock ) {
+            TRACE( "send HB\n" );
+            if ( 0 > send_skin_header_only( client_sock, SEND_HEART_BEAT, 0 ) ) {
+                send_fail_count++;
+            } else {
+                send_fail_count = 0;
+            }
+        }else {
+            // fail to get socket in accepting or client is not yet accepted.
+            send_fail_count++;
+            TRACE( "[HB] client socket is NULL yet.\n" );
+        }
+
+        if ( HEART_BEAT_FAIL_COUNT < send_fail_count ) {
+            ERR( "[HB] fail to send heart beat to skin. fail count:%d\n", HEART_BEAT_FAIL_COUNT );
+            need_restart_skin_client = 1;
+        }
+
+        pthread_mutex_lock( &mutex_recv_heartbeat_count );
+        recv_heartbeat_count++;
+        if( 1 < recv_heartbeat_count ) {
+            TRACE( "[HB] recv_heartbeat_count:%d\n", recv_heartbeat_count );
+        }
+        pthread_mutex_unlock( &mutex_recv_heartbeat_count );
+
+        if ( HEART_BEAT_EXPIRE_COUNT < recv_heartbeat_count ) {
+            ERR( "received heartbeat count is expired.\n" );
+            need_restart_skin_client = 1;
+        }
+
+        if( need_restart_skin_client ) {
+
+            if ( RESTART_CLIENT_MAX_COUNT <= restart_client_count ) {
+                shutdown = 1;
+                break;
+            } else {
+
+                if ( is_requested_shutdown_qemu_gracefully() ) {
+                    INFO( "requested shutdown_qemu_gracefully, do not retry starting skin client process.\n" );
+                    break;
+                }else {
+
+                    send_fail_count = 0;
+                    recv_heartbeat_count = 0;
+                    need_restart_skin_client = 0;
+                    restart_client_count++;
+
+                    WARN( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+                    WARN( "!!! restart skin client process !!!\n" );
+                    WARN( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+
+                    is_force_close_client = 1;
+                    if ( client_sock ) {
+#ifdef _WIN32
+                        closesocket( client_sock );
+#else
+                        close( client_sock );
+#endif
+                    }
+
+                    start_skin_client( skin_argc, skin_argv );
+
+                }
+
+            }
+
+        }
+
+    }
+
+    if ( shutdown ) {
+
+        INFO( "[HB] shutdown skin_server by heartbeat thread.\n" );
+
+        is_force_close_client = 1;
+        if ( client_sock ) {
+#ifdef _WIN32
+            closesocket( client_sock );
+#else
+            close( client_sock );
+#endif
+        }
+
+        stop_server = 1;
+        if ( server_sock ) {
+#ifdef _WIN32
+            closesocket( server_sock );
+#else
+            close( server_sock );
+#endif
+        }
+
+        ERR( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+        ERR( "!!! Fail to operate with heartbeat from skin client. Shutdown QEMU !!!\n" );
+        ERR( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" );
+
+        shutdown_qemu_gracefully();
+
+    }
+
+    return NULL;
+
+}
+
+static int start_heart_beat( void ) {
+
+    if( is_started_heartbeat ) {
+        return 1;
+    }
+
+    if( ignore_heartbeat ) {
+        return 1;
+    }else {
+        if ( 0 != pthread_create( &thread_id_heartbeat, NULL, do_heart_beat, NULL ) ) {
+            ERR( "[HB] fail to create heartbean pthread.\n" );
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+}
+
+static void stop_heart_beat( void ) {
+    pthread_mutex_lock( &mutex_heartbeat );
+    stop_heartbeat = 1;
+    pthread_cond_signal( &cond_heartbeat );
+    pthread_mutex_unlock( &mutex_heartbeat );
+}
diff --git a/tizen/src/skin/maruskin_server.h b/tizen/src/skin/maruskin_server.h
new file mode 100644 (file)
index 0000000..aa31e95
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * socket server for emulator skin
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.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; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARUSKIN_SERVER_H_
+#define MARUSKIN_SERVER_H_
+
+int start_skin_server( int argc, char** argv, int qemu_argc, char** qemu_argv );
+void shutdown_skin_server( void );
+void notify_sensor_daemon_start( void );
+int is_ready_skin_server( void );
+int get_skin_server_port( void );
+
+#endif /* MARUSKIN_SERVER_H_ */
index e6138ea4608d47e0dba32d1101ce3d2ff65acd04..e417897e561560b6d787afb67cf2d574880bddf2 100644 (file)
 #
 # [disable] <name>(<type1> <arg1>[, <type2> <arg2>] ...) "<format-string>"
 #
-# Example: qemu_malloc(size_t size) "size %zu"
+# Example: g_malloc(size_t size) "size %zu"
 #
 # The "disable" keyword will build without the trace event.
-# In case of 'simple' trace backend, it will allow the trace event to be
-# compiled, but this would be turned off by default. It can be toggled on via
-# the monitor.
 #
 # The <name> must be a valid as a C function name.
 #
 # The <format-string> should be a sprintf()-compatible format string.
 
 # qemu-malloc.c
-disable qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
-disable qemu_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
-disable qemu_free(void *ptr) "ptr %p"
+g_malloc(size_t size, void *ptr) "size %zu ptr %p"
+g_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
+g_free(void *ptr) "ptr %p"
 
 # osdep.c
-disable qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p"
-disable qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
-disable qemu_vfree(void *ptr) "ptr %p"
+qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p"
+qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
+qemu_vfree(void *ptr) "ptr %p"
 
 # hw/virtio.c
-disable virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
-disable virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
-disable virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
-disable virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p"
-disable virtio_irq(void *vq) "vq %p"
-disable virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
+virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
+virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
+virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
+virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p"
+virtio_irq(void *vq) "vq %p"
+virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
+virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
+
+# hw/virtio-serial-bus.c
+virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
+virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d"
+virtio_serial_handle_control_message(uint16_t event, uint16_t value) "event %u, value %u"
+virtio_serial_handle_control_message_port(unsigned int port) "port %u"
+
+# hw/virtio-console.c
+virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, in_len %zu, out_len %zd"
+virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
+virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
 
 # block.c
-disable multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
-disable bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
-disable bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
-disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
-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"
+bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags %#x format_name \"%s\""
+multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
+bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
+bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
+bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
+bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
+bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
+bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
 
 # hw/virtio-blk.c
-disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
-disable virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
-disable virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+virtio_blk_req_complete(void *req, int status) "req %p status %d"
+virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
+virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
 
 # posix-aio-compat.c
-disable paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
+paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
+paio_complete(void *acb, void *opaque, int ret) "acb %p opaque %p ret %d"
+paio_cancel(void *acb, void *opaque) "acb %p opaque %p"
 
 # ioport.c
-disable cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u"
-disable cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
+cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u"
+cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
 
 # balloon.c
 # Since requests are raised via monitor, not many tracepoints are needed.
-disable balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
+balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
 
 # hw/apic.c
-disable apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
-disable apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d polarity %d trigger_mode %d"
-disable cpu_set_apic_base(uint64_t val) "%016"PRIx64""
-disable cpu_get_apic_base(uint64_t val) "%016"PRIx64""
-disable apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
-disable apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
+apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d"
+cpu_set_apic_base(uint64_t val) "%016"PRIx64
+cpu_get_apic_base(uint64_t val) "%016"PRIx64
+apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
+apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
 # coalescing
-disable apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
-disable apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-disable apic_set_irq(int apic_irq_delivered) "coalescing %d"
+apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
+apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
+apic_set_irq(int apic_irq_delivered) "coalescing %d"
 
 # hw/cs4231.c
-disable cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
-disable cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
-disable cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
-disable cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
+cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
+cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
+cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
+cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
+
+# hw/ds1225y.c
+nvram_read(uint32_t addr, uint32_t ret) "read addr %d: 0x%02x"
+nvram_write(uint32_t addr, uint32_t old, uint32_t val) "write addr %d: 0x%02x -> 0x%02x"
 
 # hw/eccmemctl.c
-disable ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x"
-disable ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x"
-disable ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x"
-disable ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x"
-disable ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x"
-disable ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x"
-disable ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x"
-disable ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x"
-disable ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x"
-disable ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x"
-disable ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x"
-disable ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x"
-disable ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x"
-disable ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x"
-disable ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x"
-disable ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
-disable ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
-disable ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
+ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x"
+ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x"
+ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x"
+ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x"
+ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x"
+ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x"
+ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x"
+ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x"
+ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x"
+ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x"
+ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x"
+ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x"
+ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x"
+ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x"
+ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x"
+ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
+ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
+ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
 
 # hw/lance.c
-disable lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
-disable lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
+lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
+lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
 
 # hw/slavio_intctl.c
-disable slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
-disable slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
-disable slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x"
-disable slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x"
-disable slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x"
-disable slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x"
-disable slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x"
-disable slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x"
-disable slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d"
-disable slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x"
-disable slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d"
-disable slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d"
+slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
+slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
+slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x"
+slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x"
+slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x"
+slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x"
+slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x"
+slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x"
+slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d"
+slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x"
+slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d"
+slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d"
 
 # hw/slavio_misc.c
-disable slavio_misc_update_irq_raise(void) "Raise IRQ"
-disable slavio_misc_update_irq_lower(void) "Lower IRQ"
-disable slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d"
-disable slavio_cfg_mem_writeb(uint32_t val) "Write config %02x"
-disable slavio_cfg_mem_readb(uint32_t ret) "Read config %02x"
-disable slavio_diag_mem_writeb(uint32_t val) "Write diag %02x"
-disable slavio_diag_mem_readb(uint32_t ret) "Read diag %02x"
-disable slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x"
-disable slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x"
-disable slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x"
-disable slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x"
-disable slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x"
-disable slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x"
-disable apc_mem_writeb(uint32_t val) "Write power management %02x"
-disable apc_mem_readb(uint32_t ret) "Read power management %02x"
-disable slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x"
-disable slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x"
-disable slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x"
-disable slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
+slavio_misc_update_irq_raise(void) "Raise IRQ"
+slavio_misc_update_irq_lower(void) "Lower IRQ"
+slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d"
+slavio_cfg_mem_writeb(uint32_t val) "Write config %02x"
+slavio_cfg_mem_readb(uint32_t ret) "Read config %02x"
+slavio_diag_mem_writeb(uint32_t val) "Write diag %02x"
+slavio_diag_mem_readb(uint32_t ret) "Read diag %02x"
+slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x"
+slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x"
+slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x"
+slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x"
+slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x"
+slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x"
+apc_mem_writeb(uint32_t val) "Write power management %02x"
+apc_mem_readb(uint32_t ret) "Read power management %02x"
+slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x"
+slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x"
+slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x"
+slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
 
 # hw/slavio_timer.c
-disable slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
-disable slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
-disable slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64""
-disable slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x"
-disable slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x"
-disable slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64""
-disable slavio_timer_mem_writel_counter_invalid(void) "not user timer"
-disable slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started"
-disable slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped"
-disable slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer"
-disable slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter"
-disable slavio_timer_mem_writel_mode_invalid(void) "not system timer"
-disable slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64""
+slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
+slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
+slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64
+slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x"
+slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x"
+slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64
+slavio_timer_mem_writel_counter_invalid(void) "not user timer"
+slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started"
+slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped"
+slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer"
+slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter"
+slavio_timer_mem_writel_mode_invalid(void) "not system timer"
+slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64
 
 # hw/sparc32_dma.c
-disable ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64""
-disable ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64""
-disable sparc32_dma_set_irq_raise(void) "Raise IRQ"
-disable sparc32_dma_set_irq_lower(void) "Lower IRQ"
-disable espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x"
-disable espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x"
-disable sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x"
-disable sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x"
-disable sparc32_dma_enable_raise(void) "Raise DMA enable"
-disable sparc32_dma_enable_lower(void) "Lower DMA enable"
+ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64
+ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64
+sparc32_dma_set_irq_raise(void) "Raise IRQ"
+sparc32_dma_set_irq_lower(void) "Lower IRQ"
+espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x"
+espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x"
+sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x"
+sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x"
+sparc32_dma_enable_raise(void) "Raise DMA enable"
+sparc32_dma_enable_lower(void) "Lower DMA enable"
 
 # hw/sun4m.c
-disable sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d"
-disable sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
-disable sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
-disable sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
+sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d"
+sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
+sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
+sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
 
 # hw/sun4m_iommu.c
-disable sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
-disable sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
-disable sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64""
-disable sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x"
-disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
-disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
-disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
-disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
+sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
+sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64
+sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x"
+sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
+sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
+sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
+sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64
+
+# hw/usb-bus.c
+usb_port_claim(int bus, const char *port) "bus %d, port %s"
+usb_port_attach(int bus, const char *port) "bus %d, port %s"
+usb_port_detach(int bus, const char *port) "bus %d, port %s"
+usb_port_release(int bus, const char *port) "bus %d, port %s"
+
+# hw/usb-ehci.c
+usb_ehci_reset(void) "=== RESET ==="
+usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
+usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
+usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
+usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
+usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
+usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
+usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d"
+usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x"
+usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
+usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
+usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
+usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d"
+usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
+usb_ehci_port_detach(uint32_t port) "detach port #%d"
+usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
+usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
+usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
 
 # hw/usb-desc.c
-disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
-disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
-disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
-disable usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
-disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
-disable usb_set_addr(int addr) "dev %d"
-disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
-disable usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
-disable usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
+usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
+usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
+usb_set_addr(int addr) "dev %d"
+usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+
+# usb-linux.c
+usb_host_open_started(int bus, int addr) "dev %d:%d"
+usb_host_open_success(int bus, int addr) "dev %d:%d"
+usb_host_open_failure(int bus, int addr) "dev %d:%d"
+usb_host_disconnect(int bus, int addr) "dev %d:%d"
+usb_host_close(int bus, int addr) "dev %d:%d"
+usb_host_set_address(int bus, int addr, int config) "dev %d:%d, address %d"
+usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d"
+usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d"
+usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, config %d, nif %d"
+usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
+usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
+usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
+usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
+usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
+usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_clear_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_start_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_stop_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_reset(int bus, int addr) "dev %d:%d"
+usb_host_auto_scan_enabled(void)
+usb_host_auto_scan_disabled(void)
+usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
+
+# hw/scsi-bus.c
+scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
+scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
+scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
+scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64
+scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
+scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x"
+scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x"
+scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d"
+scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d"
 
 # vl.c
-disable vm_state_notify(int running, int reason) "running %d reason %d"
+vm_state_notify(int running, int reason) "running %d reason %d"
 
 # block/qed-l2-cache.c
-disable qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
-disable qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
-disable qed_find_l2_cache_entry(void *l2_cache, void *entry, uint64_t offset, int ref) "l2_cache %p entry %p offset %"PRIu64" ref %d"
+qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
+qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
+qed_find_l2_cache_entry(void *l2_cache, void *entry, uint64_t offset, int ref) "l2_cache %p entry %p offset %"PRIu64" ref %d"
 
 # block/qed-table.c
-disable qed_read_table(void *s, uint64_t offset, void *table) "s %p offset %"PRIu64" table %p"
-disable qed_read_table_cb(void *s, void *table, int ret) "s %p table %p ret %d"
-disable qed_write_table(void *s, uint64_t offset, void *table, unsigned int index, unsigned int n) "s %p offset %"PRIu64" table %p index %u n %u"
-disable qed_write_table_cb(void *s, void *table, int flush, int ret) "s %p table %p flush %d ret %d"
+qed_read_table(void *s, uint64_t offset, void *table) "s %p offset %"PRIu64" table %p"
+qed_read_table_cb(void *s, void *table, int ret) "s %p table %p ret %d"
+qed_write_table(void *s, uint64_t offset, void *table, unsigned int index, unsigned int n) "s %p offset %"PRIu64" table %p index %u n %u"
+qed_write_table_cb(void *s, void *table, int flush, int ret) "s %p table %p flush %d ret %d"
 
 # block/qed.c
-disable qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
-disable qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
-disable qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64""
-disable qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
-disable qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
-disable qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
-disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
-disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+qed_need_check_timer_cb(void *s) "s %p"
+qed_start_need_check_timer(void *s) "s %p"
+qed_cancel_need_check_timer(void *s) "s %p"
+qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
+qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
+qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64
+qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
+qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
+qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+
+# hw/g364fb.c
+g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
+g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
 
 # hw/grlib_gptimer.c
-disable grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
-disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
-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""
+grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
+grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
+grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x"
+grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x"
+grlib_gptimer_hit(int id) "timer:%d HIT"
+grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
+grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
 
 # hw/grlib_irqmp.c
-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""
+grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x"
+grlib_irqmp_ack(int intno) "interrupt:%d"
+grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
+grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
+grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
 
 # hw/grlib_apbuart.c
-disable grlib_apbuart_event(int event) "event:%d"
-disable grlib_apbuart_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+grlib_apbuart_event(int event) "event:%d"
+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"
+leon3_set_irq(int intno) "Set CPU IRQ %d"
+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_register_interface(void *scd) "spice vmc registered interface %p"
-disable spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
+spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d"
+spice_vmc_read(int bytes, int len) "spice read %d of requested %d"
+spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
+spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
+
+# hw/lm32_pic.c
+lm32_pic_raise_irq(void) "Raise CPU interrupt"
+lm32_pic_lower_irq(void) "Lower CPU interrupt"
+lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
+lm32_pic_set_im(uint32_t im) "im 0x%08x"
+lm32_pic_set_ip(uint32_t ip) "ip 0x%08x"
+lm32_pic_get_im(uint32_t im) "im 0x%08x"
+lm32_pic_get_ip(uint32_t ip) "ip 0x%08x"
+
+# hw/lm32_juart.c
+lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x"
+lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x"
+lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x"
+lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x"
+
+# hw/lm32_timer.c
+lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+lm32_timer_hit(void) "timer hit"
+lm32_timer_irq_state(int level) "irq state %d"
+
+# hw/lm32_uart.c
+lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+lm32_uart_irq_state(int level) "irq state %d"
+
+# hw/lm32_sys.c
+lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/milkymist-ac97.c
+milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
+milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
+milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
+milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
+milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
+milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
+milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
+milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
+
+# hw/milkymist-hpdmc.c
+milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+
+# hw/milkymist-memcard.c
+milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# hw/milkymist-minimac2.c
+milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+milkymist_minimac2_tx_frame(uint32_t length) "length %u"
+milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
+milkymist_minimac2_drop_rx_frame(const void *buf) "buf %p"
+milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
+milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
+milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
+milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-pfpu.c
+milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
+milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-softusb.c
+milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_softusb_mevt(uint8_t m) "m %d"
+milkymist_softusb_kevt(uint8_t m) "m %d"
+milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
+milkymist_softusb_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-sysctl.c
+milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_sysctl_icap_write(uint32_t value) "value %08x"
+milkymist_sysctl_start_timer0(void) "Start timer0"
+milkymist_sysctl_stop_timer0(void) "Stop timer0"
+milkymist_sysctl_start_timer1(void) "Start timer1"
+milkymist_sysctl_stop_timer1(void) "Stop timer1"
+milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
+milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
+
+# hw/milkymist-tmu2.c
+milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_tmu2_start(void) "Start TMU"
+milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-uart.c
+milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_uart_raise_irq(void) "Raise IRQ"
+milkymist_uart_lower_irq(void) "Lower IRQ"
+
+# hw/milkymist-vgafb.c
+milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# hw/mipsnet.c
+mipsnet_send(uint32_t size) "sending len=%u"
+mipsnet_receive(uint32_t size) "receiving len=%u"
+mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x"
+mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 ""
+mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)"
+
+# xen-all.c
+xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx"
+xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i"
+
+# xen-mapcache.c
+xen_map_cache(uint64_t phys_addr) "want %#"PRIx64
+xen_remap_bucket(uint64_t index) "index %#"PRIx64
+xen_map_cache_return(void* ptr) "%p"
+xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64
+xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx"
+
+# exec.c
+qemu_put_ram_ptr(void* addr) "%p"
+
+# hw/xen_platform.c
+xen_platform_log(char *s) "xen platform: %s"
+
+# qemu-coroutine.c
+qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p"
+qemu_coroutine_yield(void *from, void *to) "from %p to %p"
+qemu_coroutine_terminate(void *co) "self %p"
+
+# qemu-coroutine-lock.c
+qemu_co_queue_next_bh(void) ""
+qemu_co_queue_next(void *next) "next %p"
+qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p"
+qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
+qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
+qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p"
+
+# hw/escc.c
+escc_put_queue(char channel, int b) "channel %c put: 0x%02x"
+escc_get_queue(char channel, int val) "channel %c get 0x%02x"
+escc_update_irq(int irq) "IRQ = %d"
+escc_update_parameters(char channel, int speed, int parity, int data_bits, int stop_bits) "channel %c: speed=%d parity=%c data=%d stop=%d"
+escc_mem_writeb_ctrl(char channel, uint32_t reg, uint32_t val) "Write channel %c, reg[%d] = %2.2x"
+escc_mem_writeb_data(char channel, uint32_t val) "Write channel %c, ch %d"
+escc_mem_readb_ctrl(char channel, uint32_t reg, uint8_t val) "Read channel %c, reg[%d] = %2.2x"
+escc_mem_readb_data(char channel, uint32_t ret) "Read channel %c, ch %d"
+escc_serial_receive_byte(char channel, int ch) "channel %c put ch %d"
+escc_sunkbd_event_in(int ch) "Untranslated keycode %2.2x"
+escc_sunkbd_event_out(int ch) "Translated keycode %2.2x"
+escc_kbd_command(int val) "Command %d"
+escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
+
+# block/iscsi.c
+iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+
+# hw/esp.c
+esp_raise_irq(void) "Raise IRQ"
+esp_lower_irq(void) "Lower IRQ"
+esp_dma_enable(void) "Raise enable"
+esp_dma_disable(void) "Lower enable"
+esp_get_cmd(uint32_t dmalen, int target) "len %d target %d"
+esp_do_busid_cmd(uint8_t busid) "busid 0x%x"
+esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d"
+esp_write_response(uint32_t status) "Transfer status (status=%d)"
+esp_do_dma(uint32_t cmdlen, uint32_t len) "command len %d + %d"
+esp_command_complete(void) "SCSI Command complete"
+esp_command_complete_unexpected(void) "SCSI command completed unexpectedly"
+esp_command_complete_fail(void) "Command failed"
+esp_transfer_data(uint32_t dma_left, int32_t ti_size) "transfer %d/%d"
+esp_handle_ti(uint32_t minlen) "Transfer Information len %d"
+esp_handle_ti_cmd(uint32_t cmdlen) "command len %d"
+esp_mem_readb(uint32_t saddr, uint8_t reg) "reg[%d]: 0x%2.2x"
+esp_mem_writeb(uint32_t saddr, uint8_t reg, uint32_t val) "reg[%d]: 0x%2.2x -> 0x%2.2x"
+esp_mem_writeb_cmd_nop(uint32_t val) "NOP (%2.2x)"
+esp_mem_writeb_cmd_flush(uint32_t val) "Flush FIFO (%2.2x)"
+esp_mem_writeb_cmd_reset(uint32_t val) "Chip reset (%2.2x)"
+esp_mem_writeb_cmd_bus_reset(uint32_t val) "Bus reset (%2.2x)"
+esp_mem_writeb_cmd_iccs(uint32_t val) "Initiator Command Complete Sequence (%2.2x)"
+esp_mem_writeb_cmd_msgacc(uint32_t val) "Message Accepted (%2.2x)"
+esp_mem_writeb_cmd_pad(uint32_t val) "Transfer padding (%2.2x)"
+esp_mem_writeb_cmd_satn(uint32_t val) "Set ATN (%2.2x)"
+esp_mem_writeb_cmd_sel(uint32_t val) "Select without ATN (%2.2x)"
+esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (%2.2x)"
+esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2x)"
+esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
+
+# monitor.c
+handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
+monitor_protocol_emitter(void *mon) "mon %p"
+
+# hw/opencores_eth.c
+open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x"
+open_eth_mii_read(unsigned idx, uint16_t v) "MII[%02x] -> %04x"
+open_eth_update_irq(uint32_t v) "IRQ <- %x"
+open_eth_receive(unsigned len) "RX: len: %u"
+open_eth_receive_mcast(unsigned idx, uint32_t h0, uint32_t h1) "MCAST: idx = %u, hash: %08x:%08x"
+open_eth_receive_reject(void) "RX: rejected"
+open_eth_receive_desc(uint32_t addr, uint32_t len_flags) "RX: %08x, len_flags: %08x"
+open_eth_start_xmit(uint32_t addr, unsigned len, unsigned tx_len) "TX: %08x, len: %u, tx_len: %u"
+open_eth_reg_read(uint32_t addr, uint32_t v) "MAC[%02x] -> %08x"
+open_eth_reg_write(uint32_t addr, uint32_t v) "MAC[%02x] <- %08x"
+open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x"
+open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x"
+
+# hw/9pfs/virtio-9p.c
+v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
+v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
+v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
+v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s"
+v9fs_attach_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d type %d version %d path %"PRId64""
+v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}"
+v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64""
+v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}"
+v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d"
+v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p"
+v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d"
+v9fs_open_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u"
+v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d"
+v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_read(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t max_count) "tag %d id %d fid %d off %"PRIu64" max_count %u"
+v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd"
+v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, uint64_t offset, uint32_t max_count) "tag %d id %d fid %d offset %"PRIu64" max_count %u"
+v9fs_readdir_return(uint16_t tag, uint8_t id, uint32_t count, ssize_t retval) "tag %d id %d count %u retval %zd"
+v9fs_write(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t count, int cnt) "tag %d id %d fid %d off %"PRIu64" count %u cnt %d"
+v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd"
+v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d"
+v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_symlink(uint16_t tag, uint8_t id, int32_t fid,  char* name, char* symname, uint32_t gid) "tag %d id %d fid %d name %s symname %s gid %u"
+v9fs_symlink_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
+v9fs_flush(uint16_t tag, uint8_t id, int16_t flush_tag) "tag %d id %d flush_tag %d"
+v9fs_link(uint16_t tag, uint8_t id, int32_t dfid, int32_t oldfid, char* name) "tag %d id %d dfid %d oldfid %d name %s"
+v9fs_remove(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_wstat(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, int32_t atime, int32_t mtime) "tag %u id %u fid %d stat={mode %d atime %d mtime %d}"
+v9fs_mknod(uint16_t tag, uint8_t id, int32_t fid, int mode, int major, int minor) "tag %d id %d fid %d mode %d major %d minor %d"
+v9fs_mknod_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
+v9fs_lock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length) "tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64""
+v9fs_lock_return(uint16_t tag, uint8_t id, int8_t status) "tag %d id %d status %d"
+v9fs_getlock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length)"tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64""
+v9fs_getlock_return(uint16_t tag, uint8_t id, uint8_t type, uint64_t start, uint64_t length, uint32_t proc_id) "tag %d id %d type %d start %"PRIu64" length %"PRIu64" proc_id %u"
+v9fs_mkdir(uint16_t tag, uint8_t id, int32_t fid, char* name, int mode, uint32_t gid) "tag %u id %u fid %d name %s mode %d gid %u"
+v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %u id %u qid={type %d version %d path %"PRId64"} err %d"
+v9fs_xattrwalk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, char* name) "tag %d id %d fid %d newfid %d name %s"
+v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size %"PRId64""
+v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d"
+v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
+
+# target-sparc/mmu_helper.c
+mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_tfault(uint64_t address, uint64_t context) "TFAULT at %"PRIx64" context %"PRIx64""
+mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64""
+
+# target-sparc/int_helper.c
+int_helper_set_softint(uint32_t softint) "new %08x"
+int_helper_clear_softint(uint32_t softint) "new %08x"
+int_helper_write_softint(uint32_t softint) "new %08x"
+int_helper_icache_freeze(void) "Instruction cache: freeze"
+int_helper_dcache_freeze(void) "Data cache: freeze"
+
+# target-sparc/win_helper.c
+win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x"
+win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x"
+win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)"
+win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x"
+win_helper_done(uint32_t tl) "tl=%d"
+win_helper_retry(uint32_t tl) "tl=%d"
diff --git a/trace/control.c b/trace/control.c
new file mode 100644 (file)
index 0000000..4c5527d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Interface for configuring and controlling the state of tracing events.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "trace/control.h"
+
+
+void trace_backend_init_events(const char *fname)
+{
+    if (fname == NULL) {
+        return;
+    }
+
+    FILE *fp = fopen(fname, "r");
+    if (!fp) {
+        fprintf(stderr, "error: could not open trace events file '%s': %s\n",
+                fname, strerror(errno));
+        exit(1);
+    }
+    char line_buf[1024];
+    while (fgets(line_buf, sizeof(line_buf), fp)) {
+        size_t len = strlen(line_buf);
+        if (len > 1) {              /* skip empty lines */
+            line_buf[len - 1] = '\0';
+            if (!trace_event_set_state(line_buf, true)) {
+                fprintf(stderr,
+                        "error: trace event '%s' does not exist\n", line_buf);
+                exit(1);
+            }
+        }
+    }
+    if (fclose(fp) != 0) {
+        fprintf(stderr, "error: closing file '%s': %s\n",
+                fname, strerror(errno));
+        exit(1);
+    }
+}
diff --git a/trace/control.h b/trace/control.h
new file mode 100644 (file)
index 0000000..2acaa42
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Interface for configuring and controlling the state of tracing events.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef TRACE_CONTROL_H
+#define TRACE_CONTROL_H
+
+#include "qemu-common.h"
+
+
+/** Print the state of all events. */
+void trace_print_events(FILE *stream, fprintf_function stream_printf);
+/** Set the state of an event.
+ *
+ * @return Whether the state changed.
+ */
+bool trace_event_set_state(const char *name, bool state);
+
+
+/** Initialize the tracing backend.
+ *
+ * @events Name of file with events to be enabled at startup; may be NULL.
+ *         Corresponds to commandline option "-trace events=...".
+ * @file   Name of trace output file; may be NULL.
+ *         Corresponds to commandline option "-trace file=...".
+ * @return Whether the backend could be successfully initialized.
+ */
+bool trace_backend_init(const char *events, const char *file);
+
+/** Generic function to initialize the state of events.
+ *
+ * @fname Name of file with events to enable; may be NULL.
+ */
+void trace_backend_init_events(const char *fname);
+
+#endif  /* TRACE_CONTROL_H */
diff --git a/trace/default.c b/trace/default.c
new file mode 100644 (file)
index 0000000..c9b27a2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Default implementation for backend initialization from commandline.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "trace/control.h"
+
+
+void trace_print_events(FILE *stream, fprintf_function stream_printf)
+{
+    fprintf(stderr, "warning: "
+            "cannot print the trace events with the current backend\n");
+    stream_printf(stream, "error: "
+                  "operation not supported with the current backend\n");
+}
+
+bool trace_event_set_state(const char *name, bool state)
+{
+    fprintf(stderr, "warning: "
+            "cannot set the state of a trace event with the current backend\n");
+    return false;
+}
+
+bool trace_backend_init(const char *events, const char *file)
+{
+    if (events) {
+        fprintf(stderr, "error: -trace events=...: "
+                "option not supported by the selected tracing backend\n");
+        return false;
+    }
+    if (file) {
+        fprintf(stderr, "error: -trace file=...: "
+                "option not supported by the selected tracing backend\n");
+        return false;
+    }
+    return true;
+}
diff --git a/trace/simple.c b/trace/simple.c
new file mode 100644 (file)
index 0000000..6339152
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Simple trace backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#ifndef _WIN32
+#include <signal.h>
+#include <pthread.h>
+#endif
+#include "qemu-timer.h"
+#include "trace.h"
+#include "trace/control.h"
+
+/** Trace file header event ID */
+#define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
+
+/** Trace file magic number */
+#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
+
+/** Trace file version number, bump if format changes */
+#define HEADER_VERSION 0
+
+/** Records were dropped event ID */
+#define DROPPED_EVENT_ID (~(uint64_t)0 - 1)
+
+/** Trace record is valid */
+#define TRACE_RECORD_VALID ((uint64_t)1 << 63)
+
+/** Trace buffer entry */
+typedef struct {
+    uint64_t event;
+    uint64_t timestamp_ns;
+    uint64_t x1;
+    uint64_t x2;
+    uint64_t x3;
+    uint64_t x4;
+    uint64_t x5;
+    uint64_t x6;
+} TraceRecord;
+
+enum {
+    TRACE_BUF_LEN = 4096,
+    TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
+};
+
+/*
+ * Trace records are written out by a dedicated thread.  The thread waits for
+ * records to become available, writes them out, and then waits again.
+ */
+static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT;
+static GCond *trace_available_cond;
+static GCond *trace_empty_cond;
+static bool trace_available;
+static bool trace_writeout_enabled;
+
+static TraceRecord trace_buf[TRACE_BUF_LEN];
+static unsigned int trace_idx;
+static FILE *trace_fp;
+static char *trace_file_name = NULL;
+
+/**
+ * Read a trace record from the trace buffer
+ *
+ * @idx         Trace buffer index
+ * @record      Trace record to fill
+ *
+ * Returns false if the record is not valid.
+ */
+static bool get_trace_record(unsigned int idx, TraceRecord *record)
+{
+    if (!(trace_buf[idx].event & TRACE_RECORD_VALID)) {
+        return false;
+    }
+
+    __sync_synchronize(); /* read memory barrier before accessing record */
+
+    *record = trace_buf[idx];
+    record->event &= ~TRACE_RECORD_VALID;
+    return true;
+}
+
+/**
+ * Kick writeout thread
+ *
+ * @wait        Whether to wait for writeout thread to complete
+ */
+static void flush_trace_file(bool wait)
+{
+    g_static_mutex_lock(&trace_lock);
+    trace_available = true;
+    g_cond_signal(trace_available_cond);
+
+    if (wait) {
+        g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock));
+    }
+
+    g_static_mutex_unlock(&trace_lock);
+}
+
+static void wait_for_trace_records_available(void)
+{
+    g_static_mutex_lock(&trace_lock);
+    while (!(trace_available && trace_writeout_enabled)) {
+        g_cond_signal(trace_empty_cond);
+        g_cond_wait(trace_available_cond,
+                    g_static_mutex_get_mutex(&trace_lock));
+    }
+    trace_available = false;
+    g_static_mutex_unlock(&trace_lock);
+}
+
+static gpointer writeout_thread(gpointer opaque)
+{
+    TraceRecord record;
+    unsigned int writeout_idx = 0;
+    unsigned int num_available, idx;
+    size_t unused __attribute__ ((unused));
+
+    for (;;) {
+        wait_for_trace_records_available();
+
+        num_available = trace_idx - writeout_idx;
+        if (num_available > TRACE_BUF_LEN) {
+            record = (TraceRecord){
+                .event = DROPPED_EVENT_ID,
+                .x1 = num_available,
+            };
+            unused = fwrite(&record, sizeof(record), 1, trace_fp);
+            writeout_idx += num_available;
+        }
+
+        idx = writeout_idx % TRACE_BUF_LEN;
+        while (get_trace_record(idx, &record)) {
+            trace_buf[idx].event = 0; /* clear valid bit */
+            unused = fwrite(&record, sizeof(record), 1, trace_fp);
+            idx = ++writeout_idx % TRACE_BUF_LEN;
+        }
+
+        fflush(trace_fp);
+    }
+    return NULL;
+}
+
+static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
+                  uint64_t x4, uint64_t x5, uint64_t x6)
+{
+    unsigned int idx;
+    uint64_t timestamp;
+
+    if (!trace_list[event].state) {
+        return;
+    }
+
+    timestamp = get_clock();
+
+    idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
+    trace_buf[idx] = (TraceRecord){
+        .event = event,
+        .timestamp_ns = timestamp,
+        .x1 = x1,
+        .x2 = x2,
+        .x3 = x3,
+        .x4 = x4,
+        .x5 = x5,
+        .x6 = x6,
+    };
+    __sync_synchronize(); /* write barrier before marking as valid */
+    trace_buf[idx].event |= TRACE_RECORD_VALID;
+
+    if ((idx + 1) % TRACE_BUF_FLUSH_THRESHOLD == 0) {
+        flush_trace_file(false);
+    }
+}
+
+void trace0(TraceEventID event)
+{
+    trace(event, 0, 0, 0, 0, 0, 0);
+}
+
+void trace1(TraceEventID event, uint64_t x1)
+{
+    trace(event, x1, 0, 0, 0, 0, 0);
+}
+
+void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
+{
+    trace(event, x1, x2, 0, 0, 0, 0);
+}
+
+void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
+{
+    trace(event, x1, x2, x3, 0, 0, 0);
+}
+
+void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
+{
+    trace(event, x1, x2, x3, x4, 0, 0);
+}
+
+void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
+{
+    trace(event, x1, x2, x3, x4, x5, 0);
+}
+
+void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
+{
+    trace(event, x1, x2, x3, x4, x5, x6);
+}
+
+void st_set_trace_file_enabled(bool enable)
+{
+    if (enable == !!trace_fp) {
+        return; /* no change */
+    }
+
+    /* Halt trace writeout */
+    flush_trace_file(true);
+    trace_writeout_enabled = false;
+    flush_trace_file(true);
+
+    if (enable) {
+        static const TraceRecord header = {
+            .event = HEADER_EVENT_ID,
+            .timestamp_ns = HEADER_MAGIC,
+            .x1 = HEADER_VERSION,
+        };
+
+        trace_fp = fopen(trace_file_name, "wb");
+        if (!trace_fp) {
+            return;
+        }
+
+        if (fwrite(&header, sizeof header, 1, trace_fp) != 1) {
+            fclose(trace_fp);
+            trace_fp = NULL;
+            return;
+        }
+
+        /* Resume trace writeout */
+        trace_writeout_enabled = true;
+        flush_trace_file(false);
+    } else {
+        fclose(trace_fp);
+        trace_fp = NULL;
+    }
+}
+
+/**
+ * Set the name of a trace file
+ *
+ * @file        The trace file name or NULL for the default name-<pid> set at
+ *              config time
+ */
+bool st_set_trace_file(const char *file)
+{
+    st_set_trace_file_enabled(false);
+
+    free(trace_file_name);
+
+    if (!file) {
+        if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
+            trace_file_name = NULL;
+            return false;
+        }
+    } else {
+        if (asprintf(&trace_file_name, "%s", file) < 0) {
+            trace_file_name = NULL;
+            return false;
+        }
+    }
+
+    st_set_trace_file_enabled(true);
+    return true;
+}
+
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    stream_printf(stream, "Trace file \"%s\" %s.\n",
+                  trace_file_name, trace_fp ? "on" : "off");
+}
+
+void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    unsigned int i;
+
+    for (i = 0; i < TRACE_BUF_LEN; i++) {
+        TraceRecord record;
+
+        if (!get_trace_record(i, &record)) {
+            continue;
+        }
+        stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
+                      " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
+                      record.event, record.x1, record.x2,
+                      record.x3, record.x4, record.x5,
+                      record.x6);
+    }
+}
+
+void st_flush_trace_buffer(void)
+{
+    flush_trace_file(true);
+}
+
+void trace_print_events(FILE *stream, fprintf_function stream_printf)
+{
+    unsigned int i;
+
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        stream_printf(stream, "%s [Event ID %u] : state %u\n",
+                      trace_list[i].tp_name, i, trace_list[i].state);
+    }
+}
+
+bool trace_event_set_state(const char *name, bool state)
+{
+    unsigned int i;
+    unsigned int len;
+    bool wildcard = false;
+    bool matched = false;
+
+    len = strlen(name);
+    if (len > 0 && name[len - 1] == '*') {
+        wildcard = true;
+        len -= 1;
+    }
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        if (wildcard) {
+            if (!strncmp(trace_list[i].tp_name, name, len)) {
+                trace_list[i].state = state;
+                matched = true;
+            }
+            continue;
+        }
+        if (!strcmp(trace_list[i].tp_name, name)) {
+            trace_list[i].state = state;
+            return true;
+        }
+    }
+    return matched;
+}
+
+/* Helper function to create a thread with signals blocked.  Use glib's
+ * portable threads since QEMU abstractions cannot be used due to reentrancy in
+ * the tracer.  Also note the signal masking on POSIX hosts so that the thread
+ * does not steal signals when the rest of the program wants them blocked.
+ */
+static GThread *trace_thread_create(GThreadFunc fn)
+{
+    GThread *thread;
+#ifndef _WIN32
+    sigset_t set, oldset;
+
+    sigfillset(&set);
+    pthread_sigmask(SIG_SETMASK, &set, &oldset);
+#endif
+    thread = g_thread_create(writeout_thread, NULL, FALSE, NULL);
+#ifndef _WIN32
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+#endif
+
+    return thread;
+}
+
+bool trace_backend_init(const char *events, const char *file)
+{
+    GThread *thread;
+
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+
+    trace_available_cond = g_cond_new();
+    trace_empty_cond = g_cond_new();
+
+    thread = trace_thread_create(writeout_thread);
+    if (!thread) {
+        fprintf(stderr, "warning: unable to initialize simple trace backend\n");
+        return false;
+    }
+
+    atexit(st_flush_trace_buffer);
+    trace_backend_init_events(events);
+    st_set_trace_file(file);
+    return true;
+}
diff --git a/trace/simple.h b/trace/simple.h
new file mode 100644 (file)
index 0000000..466e75b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Simple trace backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef TRACE_SIMPLE_H
+#define TRACE_SIMPLE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef uint64_t TraceEventID;
+
+typedef struct {
+    const char *tp_name;
+    bool state;
+} TraceEvent;
+
+void trace0(TraceEventID event);
+void trace1(TraceEventID event, uint64_t x1);
+void trace2(TraceEventID event, uint64_t x1, uint64_t x2);
+void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
+void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
+void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
+void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
+void st_print_trace(FILE *stream, fprintf_function stream_printf);
+void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
+void st_set_trace_file_enabled(bool enable);
+bool st_set_trace_file(const char *file);
+void st_flush_trace_buffer(void);
+
+#endif /* TRACE_SIMPLE_H */
diff --git a/trace/stderr.c b/trace/stderr.c
new file mode 100644 (file)
index 0000000..0810d6f
--- /dev/null
@@ -0,0 +1,52 @@
+#include "trace.h"
+#include "trace/control.h"
+
+
+void trace_print_events(FILE *stream, fprintf_function stream_printf)
+{
+    unsigned int i;
+
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        stream_printf(stream, "%s [Event ID %u] : state %u\n",
+                      trace_list[i].tp_name, i, trace_list[i].state);
+    }
+}
+
+bool trace_event_set_state(const char *name, bool state)
+{
+    unsigned int i;
+    unsigned int len;
+    bool wildcard = false;
+    bool matched = false;
+
+    len = strlen(name);
+    if (len > 0 && name[len - 1] == '*') {
+        wildcard = true;
+        len -= 1;
+    }
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        if (wildcard) {
+            if (!strncmp(trace_list[i].tp_name, name, len)) {
+                trace_list[i].state = state;
+                matched = true;
+            }
+            continue;
+        }
+        if (!strcmp(trace_list[i].tp_name, name)) {
+            trace_list[i].state = state;
+            return true;
+        }
+    }
+    return matched;
+}
+
+bool trace_backend_init(const char *events, const char *file)
+{
+    if (file) {
+        fprintf(stderr, "error: -trace file=...: "
+                "option not supported by the selected tracing backend\n");
+        return false;
+    }
+    trace_backend_init_events(events);
+    return true;
+}
diff --git a/trace/stderr.h b/trace/stderr.h
new file mode 100644 (file)
index 0000000..d575b61
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef TRACE_STDERR_H
+#define TRACE_STDERR_H
+
+typedef uint64_t TraceEventID;
+
+typedef struct {
+    const char *tp_name;
+    bool state;
+} TraceEvent;
+
+#endif /* ! TRACE_STDERR_H */
index efcfb9adcdc82fa6d1ef7969e11584c1956d3271..041c1089481466e579802a41a5b0fb0491e74838 100644 (file)
@@ -26,7 +26,6 @@
 
 #define NO_CPU_IO_DEFS
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg.h"
 #include "qemu-timer.h"
@@ -44,8 +43,6 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
 void cpu_gen_init(void)
 {
     tcg_context_init(&tcg_ctx); 
-    tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf),
-                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
 
 /* return non zero if the very first instruction is invalid so that
@@ -112,8 +109,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 +153,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 20f91bc6420a1c89888d469587ad2059a2985453..0711205cbe199114dc13c43d5d5ba0e26aeac9d3 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #import <Cocoa/Cocoa.h>
+#include <crt_externs.h>
 
 #include "qemu-common.h"
 #include "console.h"
@@ -61,9 +62,7 @@ typedef struct {
     int bitsPerPixel;
 } QEMUScreen;
 
-int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
 NSWindow *normalWindow;
-id cocoaView;
 static DisplayChangeListener *dcl;
 
 int gArgc;
@@ -278,6 +277,8 @@ static int cocoa_keycode_to_qemu(int keycode)
 - (QEMUScreen) gscreen;
 @end
 
+QemuCocoaView *cocoaView;
+
 @implementation QemuCocoaView
 - (id)initWithFrame:(NSRect)frameRect
 {
@@ -794,7 +795,7 @@ static int cocoa_keycode_to_qemu(int keycode)
     COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
 
     int status;
-    status = qemu_main(argc, argv);
+    status = qemu_main(argc, argv, *_NSGetEnviron());
     exit(status);
 }
 
@@ -810,6 +811,8 @@ static int cocoa_keycode_to_qemu(int keycode)
 
         char **argv = (char**)malloc( sizeof(char*)*3 );
 
+        [sheet close];
+
         asprintf(&argv[0], "%s", bin);
         asprintf(&argv[1], "-hda");
         asprintf(&argv[2], "%s", img);
@@ -865,10 +868,20 @@ int main (int argc, const char * argv[]) {
 
     /* In case we don't need to display a window, let's not do that */
     for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-vnc") ||
-            !strcmp(argv[i], "-nographic") ||
-            !strcmp(argv[i], "-curses")) {
-                return qemu_main(gArgc, gArgv);
+        const char *opt = argv[i];
+
+        if (opt[0] == '-') {
+            /* Treat --foo the same as -foo.  */
+            if (opt[1] == '-') {
+                opt++;
+            }
+            if (!strcmp(opt, "-h") || !strcmp(opt, "-help") ||
+                !strcmp(opt, "-vnc") ||
+                !strcmp(opt, "-nographic") ||
+                !strcmp(opt, "-version") ||
+                !strcmp(opt, "-curses")) {
+                return qemu_main(gArgc, gArgv, *_NSGetEnviron());
+            }
         }
     }
 
@@ -993,15 +1006,15 @@ static void cocoa_refresh(DisplayState *ds)
 static void cocoa_cleanup(void)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
-       qemu_free(dcl);
+    g_free(dcl);
 }
 
 void cocoa_display_init(DisplayState *ds, int full_screen)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
 
-       dcl = qemu_mallocz(sizeof(DisplayChangeListener));
-       
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
+
     // register vga output callbacks
     dcl->dpy_update = cocoa_update;
     dcl->dpy_resize = cocoa_resize;
index 82bc614040590dd5379b9a7f4f7b508b1a1e305a..c2be2c641a1a1cd8ed5b40544a02acda847b67d4 100644 (file)
@@ -24,7 +24,6 @@
 #include <curses.h>
 
 #ifndef _WIN32
-#include <signal.h>
 #include <sys/ioctl.h>
 #include <termios.h>
 #endif
@@ -355,7 +354,7 @@ void curses_display_init(DisplayState *ds, int full_screen)
 #endif
 #endif
 
-    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl = (DisplayChangeListener *) g_malloc0(sizeof(DisplayChangeListener));
     dcl->dpy_update = curses_update;
     dcl->dpy_resize = curses_resize;
     dcl->dpy_refresh = curses_refresh;
index 78c7ea375cc9906c2ed8518d8428a2389d33f002..f55a2aa46452cb5836bb8a6ccd79e455d407fbbe 100644 (file)
@@ -52,7 +52,7 @@ static void add_to_key_range(struct key_range **krp, int code) {
        }
     }
     if (kr == NULL) {
-       kr = qemu_mallocz(sizeof(*kr));
+       kr = g_malloc0(sizeof(*kr));
         kr->start = kr->end = code;
         kr->next = *krp;
         *krp = kr;
@@ -92,15 +92,17 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
     int len;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
-
-    if (!k)
-       k = qemu_mallocz(sizeof(kbd_layout_t));
-    if (!(filename && (f = fopen(filename, "r")))) {
+    f = filename ? fopen(filename, "r") : NULL;
+    g_free(filename);
+    if (!f) {
        fprintf(stderr,
                "Could not read keymap file: '%s'\n", language);
        return NULL;
     }
-    qemu_free(filename);
+
+    if (!k)
+       k = g_malloc0(sizeof(kbd_layout_t));
+
     for(;;) {
        if (fgets(line, 1024, f) == NULL)
             break;
@@ -146,7 +148,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
                    if (rest && strstr(rest, "addupper")) {
                        char *c;
                        for (c = line; *c; c++)
-                           *c = toupper(*c);
+                           *c = qemu_toupper(*c);
                        keysym = get_keysym(table, line);
                        if (keysym)
                            add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k);
index 916e5dce218132fe062577cf2fc41b8fc91c74e6..c35b29c1f623d4e357a50952b52c808aba86ec61 100644 (file)
@@ -25,6 +25,7 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "qemu-char.h"
+#include "monitor.h"
 
 extern int using_spice;
 
@@ -37,20 +38,35 @@ int qemu_spice_set_passwd(const char *passwd,
                           bool fail_if_connected, bool disconnect_if_connected);
 int qemu_spice_set_pw_expire(time_t expires);
 int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
-                            const char *subject);
+                            const char *subject,
+                            MonitorCompletion cb, void *opaque);
 
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
 
-CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
+int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr);
 
 #else  /* CONFIG_SPICE */
+#include "monitor.h"
 
 #define using_spice 0
-#define qemu_spice_set_passwd(_p, _f1, _f2) (-1)
-#define qemu_spice_set_pw_expire(_e) (-1)
-static inline int qemu_spice_migrate_info(const char *h, int p, int t, const char *s)
-{ return -1; }
+static inline int qemu_spice_set_passwd(const char *passwd,
+                                        bool fail_if_connected,
+                                        bool disconnect_if_connected)
+{
+    return -1;
+}
+static inline int qemu_spice_set_pw_expire(time_t expires)
+{
+    return -1;
+}
+static inline int qemu_spice_migrate_info(const char *h, int p, int t,
+                                          const char *s,
+                                          MonitorCompletion cb, void *opaque)
+{
+    cb(opaque, NULL);
+    return -1;
+}
 
 #endif /* CONFIG_SPICE */
 
index 7f1a528d6b975c220693d02f19ee0e62d49b14d9..8cafc44e71e95990efd36959faf2a2fbdefb0e6a 100644 (file)
--- a/ui/sdl.c
+++ b/ui/sdl.c
 #include <SDL.h>
 #include <SDL_syswm.h>
 
-#ifndef _WIN32
-#include <signal.h>
-#endif
-
 #include "qemu-common.h"
 #include "console.h"
 #include "sysemu.h"
 #include "x_keymap.h"
 #include "sdl_zoom.h"
-#include "sdl_rotate.h"
-#include "sdl_keysym.h"
 
 static DisplayChangeListener *dcl;
 static SDL_Surface *real_screen;
 static SDL_Surface *guest_screen = NULL;
 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
 static int last_vm_running;
+static bool gui_saved_scaling;
+static int gui_saved_width;
+static int gui_saved_height;
 static int gui_saved_grab;
 static int gui_fullscreen;
 static int gui_noframe;
 static int gui_key_modifier_pressed;
 static int gui_keysym;
-static int gui_fullscreen_initial_grab;
 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
 static uint8_t modifiers_state[256];
-static int width, height;
 static SDL_Cursor *sdl_cursor_normal;
 static SDL_Cursor *sdl_cursor_hidden;
 static int absolute_enabled = 0;
@@ -64,7 +59,6 @@ static uint8_t allocator;
 static SDL_PixelFormat host_format;
 static int scaling_active = 0;
 static Notifier mouse_mode_notifier;
-static int rotation = 0;
 
 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 {
@@ -76,31 +70,13 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
     rec.h = h;
 
     if (guest_screen) {
-        if (!scaling_active && !rotation) {
+        if (!scaling_active) {
             SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
         } else {
-            SDL_Surface* rotated;
-
-            if (!rotation)
-                rotated = guest_screen;
-            else
-                rotated = rotateSurface90Degrees(guest_screen, rotation);
-
-            /* blit the whole lot */
-            rec.x = 0;
-            rec.y = 0;
-            rec.w = rotated->w;
-            rec.h = rotated->h;
-
-            sdl_zoom_blit(rotated, real_screen, SMOOTHING_ON, &rec);
-            if (rotated != guest_screen)
-                SDL_FreeSurface(rotated);
-
-            /* blit the whole lot */
-            rec.x = 0;
-            rec.y = 0;
-            rec.w = real_screen->w;
-            rec.h = real_screen->h;
+            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
+                fprintf(stderr, "Zoom blit failed\n");
+                exit(1);
+            }
         }
     } 
     SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
@@ -108,12 +84,6 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 
 static void sdl_setdata(DisplayState *ds)
 {
-    SDL_Rect rec;
-    rec.x = 0;
-    rec.y = 0;
-    rec.w = real_screen->w;
-    rec.h = real_screen->h;
-
     if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
 
     guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
@@ -122,25 +92,21 @@ static void sdl_setdata(DisplayState *ds)
                                             ds->surface->pf.bmask, ds->surface->pf.amask);
 }
 
-static void do_sdl_resize(int new_width, int new_height, int bpp)
+static void do_sdl_resize(int width, int height, int bpp)
 {
     int flags;
 
     //    printf("resizing to %d %d\n", w, h);
 
-    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
-    if (gui_fullscreen)
+    flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
+    if (gui_fullscreen) {
         flags |= SDL_FULLSCREEN;
+    } else {
+        flags |= SDL_RESIZABLE;
+    }
     if (gui_noframe)
         flags |= SDL_NOFRAME;
 
-    if (rotation&1) {
-        width = new_height;
-        height = new_width;
-    } else {
-        width = new_width;
-        height = new_height;
-    }
     real_screen = SDL_SetVideoMode(width, height, bpp, flags);
     if (!real_screen) {
        fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
@@ -154,8 +120,6 @@ static void sdl_resize(DisplayState *ds)
     if  (!allocator) {
         if (!scaling_active)
             do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
-        else if (!real_screen)
-            do_sdl_resize(width, height, ds_get_bits_per_pixel(ds));
         else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
             do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
         sdl_setdata(ds);
@@ -202,7 +166,7 @@ static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
 
 static DisplaySurface* sdl_create_displaysurface(int width, int height)
 {
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
     if (surface == NULL) {
         fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
         exit(1);
@@ -210,22 +174,18 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height)
 
     surface->width = width;
     surface->height = height;
-    
+
     if (scaling_active) {
+        int linesize;
+        PixelFormat pf;
         if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
-            surface->linesize = width * 4;
-            surface->pf = qemu_default_pixelformat(32);
+            linesize = width * 4;
+            pf = qemu_default_pixelformat(32);
         } else {
-            surface->linesize = width * host_format.BytesPerPixel;
-            surface->pf = sdl_to_qemu_pixelformat(&host_format);
+            linesize = width * host_format.BytesPerPixel;
+            pf = sdl_to_qemu_pixelformat(&host_format);
         }
-#ifdef HOST_WORDS_BIGENDIAN
-        surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-        surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-        surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
-
+        qemu_alloc_display(surface, width, height, linesize, pf, 0);
         return surface;
     }
 
@@ -255,8 +215,8 @@ static void sdl_free_displaysurface(DisplaySurface *surface)
         return;
 
     if (surface->flags & QEMU_ALLOCATED_FLAG)
-        qemu_free(surface->data);
-    qemu_free(surface);
+        g_free(surface->data);
+    g_free(surface);
 }
 
 static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
@@ -449,7 +409,7 @@ static void sdl_update_caption(void)
     char icon_title[1024];
     const char *status = "";
 
-    if (!vm_running)
+    if (!runstate_is_running())
         status = " [Stopped]";
     else if (gui_grab) {
         if (alt_grab)
@@ -489,7 +449,7 @@ static void sdl_show_cursor(void)
     if (!cursor_hide)
         return;
 
-    if (!kbd_mouse_is_absolute()) {
+    if (!kbd_mouse_is_absolute() || !is_graphic_console()) {
         SDL_ShowCursor(1);
         if (guest_cursor &&
                 (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
@@ -523,36 +483,38 @@ static void sdl_grab_end(void)
     sdl_update_caption();
 }
 
-static void sdl_mouse_mode_change(Notifier *notify)
+static void sdl_mouse_mode_change(Notifier *notify, void *data)
 {
     if (kbd_mouse_is_absolute()) {
         if (!absolute_enabled) {
-            sdl_hide_cursor();
-            if (gui_grab) {
-                sdl_grab_end();
-            }
+            sdl_grab_start();
             absolute_enabled = 1;
         }
     } else if (absolute_enabled) {
-       sdl_show_cursor();
-       absolute_enabled = 0;
+        if (!gui_fullscreen) {
+            sdl_grab_end();
+        }
+        absolute_enabled = 0;
     }
 }
 
 static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
 {
-    int buttons;
-    buttons = 0;
-    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
+    int buttons = 0;
+
+    if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
         buttons |= MOUSE_EVENT_LBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
+    }
+    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
         buttons |= MOUSE_EVENT_RBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
+    }
+    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
         buttons |= MOUSE_EVENT_MBUTTON;
+    }
 
     if (kbd_mouse_is_absolute()) {
-       dx = x * 0x7FFF / (width - 1);
-       dy = y * 0x7FFF / (height - 1);
+        dx = x * 0x7FFF / (real_screen->w - 1);
+        dy = y * 0x7FFF / (real_screen->h - 1);
     } else if (guest_cursor) {
         x -= guest_x;
         y -= guest_y;
@@ -565,30 +527,334 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
     kbd_mouse_event(dx, dy, dz, buttons);
 }
 
+static void sdl_scale(DisplayState *ds, int width, int height)
+{
+    int bpp = real_screen->format->BitsPerPixel;
+
+    if (bpp != 16 && bpp != 32) {
+        bpp = 32;
+    }
+    do_sdl_resize(width, height, bpp);
+    scaling_active = 1;
+    if (!is_buffer_shared(ds->surface)) {
+        ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds),
+                                                 ds_get_height(ds));
+        dpy_resize(ds);
+    }
+}
+
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
     if (gui_fullscreen) {
+        gui_saved_width = real_screen->w;
+        gui_saved_height = real_screen->h;
+        gui_saved_scaling = scaling_active;
+
+        do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
+                      ds_get_bits_per_pixel(ds));
         scaling_active = 0;
+
         gui_saved_grab = gui_grab;
         sdl_grab_start();
     } else {
-        if (!gui_saved_grab)
+        if (gui_saved_scaling) {
+            sdl_scale(ds, gui_saved_width, gui_saved_height);
+        } else {
+            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        }
+        if (!gui_saved_grab || !is_graphic_console()) {
             sdl_grab_end();
+        }
     }
     vga_hw_invalidate();
     vga_hw_update();
 }
 
-static void sdl_refresh(DisplayState *ds)
+static void absolute_mouse_grab(void)
+{
+    int mouse_x, mouse_y;
+
+    if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
+        SDL_GetMouseState(&mouse_x, &mouse_y);
+        if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+            mouse_y > 0 && mouse_y < real_screen->h - 1) {
+            sdl_grab_start();
+        }
+    }
+}
+
+static void handle_keydown(DisplayState *ds, SDL_Event *ev)
+{
+    int mod_state;
+    int keycode;
+
+    if (alt_grab) {
+        mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+                    (gui_grab_code | KMOD_LSHIFT);
+    } else if (ctrl_grab) {
+        mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
+    } else {
+        mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
+    }
+    gui_key_modifier_pressed = mod_state;
+
+    if (gui_key_modifier_pressed) {
+        keycode = sdl_keyevent_to_keycode(&ev->key);
+        switch (keycode) {
+        case 0x21: /* 'f' key on US keyboard */
+            toggle_full_screen(ds);
+            gui_keysym = 1;
+            break;
+        case 0x16: /* 'u' key on US keyboard */
+            if (scaling_active) {
+                scaling_active = 0;
+                sdl_resize(ds);
+                vga_hw_invalidate();
+                vga_hw_update();
+            }
+            gui_keysym = 1;
+            break;
+        case 0x02 ... 0x0a: /* '1' to '9' keys */
+            /* Reset the modifiers sent to the current console */
+            reset_keys();
+            console_select(keycode - 0x02);
+            gui_keysym = 1;
+            if (gui_fullscreen) {
+                break;
+            }
+            if (!is_graphic_console()) {
+                /* release grab if going to a text console */
+                if (gui_grab) {
+                    sdl_grab_end();
+                } else if (absolute_enabled) {
+                    sdl_show_cursor();
+                }
+            } else if (absolute_enabled) {
+                sdl_hide_cursor();
+                absolute_mouse_grab();
+            }
+            break;
+        case 0x1b: /* '+' */
+        case 0x35: /* '-' */
+            if (!gui_fullscreen) {
+                int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50),
+                                160);
+                int height = (ds_get_height(ds) * width) / ds_get_width(ds);
+
+                sdl_scale(ds, width, height);
+                vga_hw_invalidate();
+                vga_hw_update();
+                gui_keysym = 1;
+            }
+        default:
+            break;
+        }
+    } else if (!is_graphic_console()) {
+        int keysym = 0;
+
+        if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+            switch (ev->key.keysym.sym) {
+            case SDLK_UP:
+                keysym = QEMU_KEY_CTRL_UP;
+                break;
+            case SDLK_DOWN:
+                keysym = QEMU_KEY_CTRL_DOWN;
+                break;
+            case SDLK_LEFT:
+                keysym = QEMU_KEY_CTRL_LEFT;
+                break;
+            case SDLK_RIGHT:
+                keysym = QEMU_KEY_CTRL_RIGHT;
+                break;
+            case SDLK_HOME:
+                keysym = QEMU_KEY_CTRL_HOME;
+                break;
+            case SDLK_END:
+                keysym = QEMU_KEY_CTRL_END;
+                break;
+            case SDLK_PAGEUP:
+                keysym = QEMU_KEY_CTRL_PAGEUP;
+                break;
+            case SDLK_PAGEDOWN:
+                keysym = QEMU_KEY_CTRL_PAGEDOWN;
+                break;
+            default:
+                break;
+            }
+        } else {
+            switch (ev->key.keysym.sym) {
+            case SDLK_UP:
+                keysym = QEMU_KEY_UP;
+                break;
+            case SDLK_DOWN:
+                keysym = QEMU_KEY_DOWN;
+                break;
+            case SDLK_LEFT:
+                keysym = QEMU_KEY_LEFT;
+                break;
+            case SDLK_RIGHT:
+                keysym = QEMU_KEY_RIGHT;
+                break;
+            case SDLK_HOME:
+                keysym = QEMU_KEY_HOME;
+                break;
+            case SDLK_END:
+                keysym = QEMU_KEY_END;
+                break;
+            case SDLK_PAGEUP:
+                keysym = QEMU_KEY_PAGEUP;
+                break;
+            case SDLK_PAGEDOWN:
+                keysym = QEMU_KEY_PAGEDOWN;
+                break;
+            case SDLK_BACKSPACE:
+                keysym = QEMU_KEY_BACKSPACE;
+                break;
+            case SDLK_DELETE:
+                keysym = QEMU_KEY_DELETE;
+                break;
+            default:
+                break;
+            }
+        }
+        if (keysym) {
+            kbd_put_keysym(keysym);
+        } else if (ev->key.keysym.unicode != 0) {
+            kbd_put_keysym(ev->key.keysym.unicode);
+        }
+    }
+    if (is_graphic_console() && !gui_keysym) {
+        sdl_process_key(&ev->key);
+    }
+}
+
+static void handle_keyup(DisplayState *ds, SDL_Event *ev)
 {
-    SDL_Event ev1, *ev = &ev1;
     int mod_state;
+
+    if (!alt_grab) {
+        mod_state = (ev->key.keysym.mod & gui_grab_code);
+    } else {
+        mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
+    }
+    if (!mod_state && gui_key_modifier_pressed) {
+        gui_key_modifier_pressed = 0;
+        if (gui_keysym == 0) {
+            /* exit/enter grab if pressing Ctrl-Alt */
+            if (!gui_grab) {
+                /* If the application is not active, do not try to enter grab
+                 * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
+                 * blocking all the application (SDL bug). */
+                if (is_graphic_console() &&
+                    SDL_GetAppState() & SDL_APPACTIVE) {
+                    sdl_grab_start();
+                }
+            } else if (!gui_fullscreen) {
+                sdl_grab_end();
+            }
+            /* SDL does not send back all the modifiers key, so we must
+             * correct it. */
+            reset_keys();
+            return;
+        }
+        gui_keysym = 0;
+    }
+    if (is_graphic_console() && !gui_keysym) {
+        sdl_process_key(&ev->key);
+    }
+}
+
+static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
+{
+    int max_x, max_y;
+
+    if (is_graphic_console() &&
+        (kbd_mouse_is_absolute() || absolute_enabled)) {
+        max_x = real_screen->w - 1;
+        max_y = real_screen->h - 1;
+        if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
+            ev->motion.x == max_x || ev->motion.y == max_y)) {
+            sdl_grab_end();
+        }
+        if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+            (ev->motion.x > 0 && ev->motion.x < max_x &&
+            ev->motion.y > 0 && ev->motion.y < max_y)) {
+            sdl_grab_start();
+        }
+    }
+    if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+        sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
+                             ev->motion.x, ev->motion.y, ev->motion.state);
+    }
+}
+
+static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
+{
     int buttonstate = SDL_GetMouseState(NULL, NULL);
+    SDL_MouseButtonEvent *bev;
+    int dz;
+
+    if (!is_graphic_console()) {
+        return;
+    }
+
+    bev = &ev->button;
+    if (!gui_grab && !kbd_mouse_is_absolute()) {
+        if (ev->type == SDL_MOUSEBUTTONDOWN &&
+            (bev->button == SDL_BUTTON_LEFT)) {
+            /* start grabbing all events */
+            sdl_grab_start();
+        }
+    } else {
+        dz = 0;
+        if (ev->type == SDL_MOUSEBUTTONDOWN) {
+            buttonstate |= SDL_BUTTON(bev->button);
+        } else {
+            buttonstate &= ~SDL_BUTTON(bev->button);
+        }
+#ifdef SDL_BUTTON_WHEELUP
+        if (bev->button == SDL_BUTTON_WHEELUP &&
+            ev->type == SDL_MOUSEBUTTONDOWN) {
+            dz = -1;
+        } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
+                   ev->type == SDL_MOUSEBUTTONDOWN) {
+            dz = 1;
+        }
+#endif
+        sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
+    }
+}
+
+static void handle_activation(DisplayState *ds, SDL_Event *ev)
+{
+    if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
+        !ev->active.gain && !gui_fullscreen) {
+        sdl_grab_end();
+    }
+    if (!gui_grab && ev->active.gain && is_graphic_console() &&
+        (kbd_mouse_is_absolute() || absolute_enabled)) {
+        absolute_mouse_grab();
+    }
+    if (ev->active.state & SDL_APPACTIVE) {
+        if (ev->active.gain) {
+            /* Back to default interval */
+            dcl->gui_timer_interval = 0;
+            dcl->idle = 0;
+        } else {
+            /* Sleeping interval */
+            dcl->gui_timer_interval = 500;
+            dcl->idle = 1;
+        }
+    }
+}
+
+static void sdl_refresh(DisplayState *ds)
+{
+    SDL_Event ev1, *ev = &ev1;
 
-    if (last_vm_running != vm_running) {
-        last_vm_running = vm_running;
+    if (last_vm_running != runstate_is_running()) {
+        last_vm_running = runstate_is_running();
         sdl_update_caption();
     }
 
@@ -598,203 +864,35 @@ static void sdl_refresh(DisplayState *ds)
     while (SDL_PollEvent(ev)) {
         switch (ev->type) {
         case SDL_VIDEOEXPOSE:
-            if (guest_screen)
-                sdl_update(ds, 0, 0, guest_screen->w, guest_screen->h);
+            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
             break;
         case SDL_KEYDOWN:
+            handle_keydown(ds, ev);
+            break;
         case SDL_KEYUP:
-            if (ev->type == SDL_KEYDOWN) {
-                if (alt_grab) {
-                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
-                                (gui_grab_code | KMOD_LSHIFT);
-                } else if (ctrl_grab) {
-                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
-                } else {
-                    mod_state = (SDL_GetModState() & gui_grab_code) ==
-                                gui_grab_code;
-                }
-                gui_key_modifier_pressed = mod_state;
-                if (gui_key_modifier_pressed) {
-                    int keycode;
-                    keycode = sdl_keyevent_to_keycode(&ev->key);
-                    switch(keycode) {
-                    case 0x21: /* 'f' key on US keyboard */
-                        toggle_full_screen(ds);
-                        gui_keysym = 1;
-                        break;
-                    case 0x16: /* 'u' key on US keyboard */
-                        scaling_active = 0;
-                        sdl_resize(ds);
-                        vga_hw_invalidate();
-                        vga_hw_update();
-                        break;
-                    case 0x02 ... 0x0a: /* '1' to '9' keys */
-                        /* Reset the modifiers sent to the current console */
-                        reset_keys();
-                        console_select(keycode - 0x02);
-                        if (!is_graphic_console()) {
-                            /* display grab if going to a text console */
-                            if (gui_grab)
-                                sdl_grab_end();
-                        }
-                        gui_keysym = 1;
-                        break;
-                    default:
-                        break;
-                    }
-                } else if (!is_graphic_console()) {
-                    int keysym;
-                    keysym = 0;
-                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
-                        default: break;
-                        }
-                    } else {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
-                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
-                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
-                        default: break;
-                        }
-                    }
-                    if (keysym) {
-                        kbd_put_keysym(keysym);
-                    } else if (ev->key.keysym.unicode != 0) {
-                        kbd_put_keysym(ev->key.keysym.unicode);
-                    }
-                }
-            } else if (ev->type == SDL_KEYUP) {
-                if (!alt_grab) {
-                    mod_state = (ev->key.keysym.mod & gui_grab_code);
-                } else {
-                    mod_state = (ev->key.keysym.mod &
-                                 (gui_grab_code | KMOD_LSHIFT));
-                }
-                if (!mod_state) {
-                    if (gui_key_modifier_pressed) {
-                        gui_key_modifier_pressed = 0;
-                        if (gui_keysym == 0) {
-                            /* exit/enter grab if pressing Ctrl-Alt */
-                            if (!gui_grab) {
-                                /* if the application is not active,
-                                   do not try to enter grab state. It
-                                   prevents
-                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
-                                   from blocking all the application
-                                   (SDL bug). */
-                                if (SDL_GetAppState() & SDL_APPACTIVE)
-                                    sdl_grab_start();
-                            } else {
-                                sdl_grab_end();
-                            }
-                            /* SDL does not send back all the
-                               modifiers key, so we must correct it */
-                            reset_keys();
-                            break;
-                        }
-                        gui_keysym = 0;
-                    }
-                }
-            }
-            if (is_graphic_console() && !gui_keysym)
-                sdl_process_key(&ev->key);
+            handle_keyup(ds, ev);
             break;
         case SDL_QUIT:
-            if (!no_quit)
+            if (!no_quit) {
+                no_shutdown = 0;
                 qemu_system_shutdown_request();
+            }
             break;
         case SDL_MOUSEMOTION:
-            if (gui_grab || kbd_mouse_is_absolute() ||
-                absolute_enabled) {
-                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
-                       ev->motion.x, ev->motion.y, ev->motion.state);
-            }
+            handle_mousemotion(ds, ev);
             break;
         case SDL_MOUSEBUTTONDOWN:
         case SDL_MOUSEBUTTONUP:
-            {
-                SDL_MouseButtonEvent *bev = &ev->button;
-                if (!gui_grab && !kbd_mouse_is_absolute()) {
-                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
-                        (bev->button == SDL_BUTTON_LEFT)) {
-                        /* start grabbing all events */
-                        sdl_grab_start();
-                    }
-                } else {
-                    int dz;
-                    dz = 0;
-                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
-                        buttonstate |= SDL_BUTTON(bev->button);
-                    } else {
-                        buttonstate &= ~SDL_BUTTON(bev->button);
-                    }
-#ifdef SDL_BUTTON_WHEELUP
-                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = -1;
-                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = 1;
-                    }
-#endif
-                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
-                }
-            }
+            handle_mousebutton(ds, ev);
             break;
         case SDL_ACTIVEEVENT:
-            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
-                !ev->active.gain && !gui_fullscreen_initial_grab) {
-                sdl_grab_end();
-            }
-            if (ev->active.state & SDL_APPACTIVE) {
-                if (ev->active.gain) {
-                    /* Back to default interval */
-                    dcl->gui_timer_interval = 0;
-                    dcl->idle = 0;
-                } else {
-                    /* Sleeping interval */
-                    dcl->gui_timer_interval = 500;
-                    dcl->idle = 1;
-                }
-            }
+            handle_activation(ds, ev);
             break;
-       case SDL_VIDEORESIZE:
-        {
-           SDL_ResizeEvent *rev = &ev->resize;
-            int bpp = real_screen->format->BitsPerPixel;
-                       int w, h;
-            if (bpp != 16 && bpp != 32)
-                bpp = 32;
-                       if (rotation & 1) {
-                               w = rev->h;
-                               h = rev->w;
-                       } else {
-                               w = rev->w;
-                               h = rev->h;
-                       }
-            do_sdl_resize(w, h, bpp);
-            scaling_active = 1;
-            if (!is_buffer_shared(ds->surface)) {
-                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
-                dpy_resize(ds);
-            }
+        case SDL_VIDEORESIZE:
+            sdl_scale(ds, ev->resize.w, ev->resize.h);
             vga_hw_invalidate();
             vga_hw_update();
             break;
-        }
         default:
             break;
         }
@@ -832,14 +930,14 @@ static void sdl_mouse_define(QEMUCursor *c)
         SDL_FreeCursor(guest_sprite);
 
     bpl = cursor_get_mono_bpl(c);
-    image = qemu_mallocz(bpl * c->height);
-    mask  = qemu_mallocz(bpl * c->height);
+    image = g_malloc0(bpl * c->height);
+    mask  = g_malloc0(bpl * c->height);
     cursor_get_mono_image(c, 0x000000, image);
     cursor_get_mono_mask(c, 0, mask);
     guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
                                     c->hot_x, c->hot_y);
-    qemu_free(image);
-    qemu_free(mask);
+    g_free(image);
+    g_free(mask);
 
     if (guest_cursor &&
             (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
@@ -859,6 +957,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 */
@@ -874,10 +973,20 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     if (no_frame)
         gui_noframe = 1;
 
-#ifndef WIN32
     if (!full_screen) {
         setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
     }
+#ifdef __linux__
+    /* on Linux, SDL may use fbcon|directfb|svgalib when run without
+     * accessible $DISPLAY to open X11 window.  This is often the case
+     * when qemu is run using sudo.  But in this case, and when actually
+     * run in X11 environment, SDL fights with X11 for the video card,
+     * making current display unavailable, often until reboot.
+     * So make x11 the default SDL video driver if this variable is unset.
+     * This is a bit hackish but saves us from bigger problem.
+     * Maybe it's a good idea to fix this in SDL instead.
+     */
+    setenv("SDL_VIDEODRIVER", "x11", 0);
 #endif
 
     /* Enable normal up/down events for Caps-Lock and Num-Lock keys.
@@ -893,7 +1002,24 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     vi = SDL_GetVideoInfo();
     host_format = *(vi->vfmt);
 
-    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    /* 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);
+        }
+        g_free(filename);
+    }
+
+    if (full_screen) {
+        gui_fullscreen = 1;
+        sdl_grab_start();
+    }
+
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
     dcl->dpy_update = sdl_update;
     dcl->dpy_resize = sdl_resize;
     dcl->dpy_refresh = sdl_refresh;
@@ -903,7 +1029,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     ds->cursor_define = sdl_mouse_define;
     register_displaychangelistener(ds, dcl);
 
-    da = qemu_mallocz(sizeof(DisplayAllocator));
+    da = g_malloc0(sizeof(DisplayAllocator));
     da->create_displaysurface = sdl_create_displaysurface;
     da->resize_displaysurface = sdl_resize_displaysurface;
     da->free_displaysurface = sdl_free_displaysurface;
@@ -922,38 +1048,4 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     sdl_cursor_normal = SDL_GetCursor();
 
     atexit(sdl_cleanup);
-    if (full_screen) {
-        gui_fullscreen = 1;
-        gui_fullscreen_initial_grab = 1;
-        sdl_grab_start();
-    }
-}
-
-void sdl_display_set_rotation(int rot)
-{
-    rotation = rot;
-}
-
-void sdl_display_set_window_size(int w, int h)
-{
-    SDL_Event ev;
-
-    scaling_active = 1;
-    width = w;
-    height = h;
-
-    /* this fails if SDL is not initialized */
-    memset(&ev, 0, sizeof ev);
-    ev.resize.type = SDL_VIDEORESIZE;
-    ev.resize.w = w;
-    ev.resize.h = h;
-    SDL_PushEvent(&ev);
-}
-
-void sdl_display_force_refresh(void)
-{
-    SDL_Event ev;
-    memset(&ev, 0, sizeof ev);
-    ev.expose.type = SDL_VIDEOEXPOSE;
-    SDL_PushEvent(&ev);
 }
index 0b44f5cde14928d66f13ff84d74a06651e4b256b..ee904805da8b762e4041e04cc568dfb8f2a5ce45 100644 (file)
@@ -1,9 +1,6 @@
 
 #include "keymaps.h"
 
-#ifndef __KEYSYM__
-#define __KEYSYM__
-
 static const name2keysym_t name2keysym[]={
 /* ascii */
     { "space",                0x020},
@@ -278,4 +275,3 @@ static const name2keysym_t name2keysym[]={
 
 {NULL, 0},
 };
-#endif
index 1aa1a5ed1893fc1e5e44211bf52d0f0ac54360fd..5639c6f5314a964dd9b0400e072a48e23cb7dfb9 100644 (file)
 
 #include "qemu-common.h"
 #include "qemu-spice.h"
+#include "qemu-thread.h"
 #include "qemu-timer.h"
 #include "qemu-queue.h"
 #include "qemu-x509.h"
 #include "qemu_socket.h"
+#include "qmp-commands.h"
 #include "qint.h"
 #include "qbool.h"
 #include "qstring.h"
@@ -44,6 +46,8 @@ static char *auth_passwd;
 static time_t auth_expires = TIME_MAX;
 int using_spice = 0;
 
+static QemuThread me;
+
 struct SpiceTimer {
     QEMUTimer *timer;
     QTAILQ_ENTRY(SpiceTimer) next;
@@ -54,15 +58,15 @@ static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
 {
     SpiceTimer *timer;
 
-    timer = qemu_mallocz(sizeof(*timer));
-    timer->timer = qemu_new_timer(rt_clock, func, opaque);
+    timer = g_malloc0(sizeof(*timer));
+    timer->timer = qemu_new_timer_ms(rt_clock, func, opaque);
     QTAILQ_INSERT_TAIL(&timers, timer, next);
     return timer;
 }
 
 static void timer_start(SpiceTimer *timer, uint32_t ms)
 {
-    qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
+    qemu_mod_timer(timer->timer, qemu_get_clock_ms(rt_clock) + ms);
 }
 
 static void timer_cancel(SpiceTimer *timer)
@@ -75,7 +79,7 @@ static void timer_remove(SpiceTimer *timer)
     qemu_del_timer(timer->timer);
     qemu_free_timer(timer->timer);
     QTAILQ_REMOVE(&timers, timer, next);
-    qemu_free(timer);
+    g_free(timer);
 }
 
 struct SpiceWatch {
@@ -118,7 +122,7 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
 {
     SpiceWatch *watch;
 
-    watch = qemu_mallocz(sizeof(*watch));
+    watch = g_malloc0(sizeof(*watch));
     watch->fd     = fd;
     watch->func   = func;
     watch->opaque = opaque;
@@ -130,9 +134,9 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
 
 static void watch_remove(SpiceWatch *watch)
 {
-    watch_update_mask(watch, 0);
+    qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
     QTAILQ_REMOVE(&watches, watch, next);
-    qemu_free(watch);
+    g_free(watch);
 }
 
 #if SPICE_INTERFACE_CORE_MINOR >= 3
@@ -148,7 +152,7 @@ static void channel_list_add(SpiceChannelEventInfo *info)
 {
     ChannelList *item;
 
-    item = qemu_mallocz(sizeof(*item));
+    item = g_malloc0(sizeof(*item));
     item->info = info;
     QTAILQ_INSERT_TAIL(&channel_list, item, link);
 }
@@ -162,7 +166,7 @@ static void channel_list_del(SpiceChannelEventInfo *info)
             continue;
         }
         QTAILQ_REMOVE(&channel_list, item, link);
-        qemu_free(item);
+        g_free(item);
         return;
     }
 }
@@ -191,22 +195,6 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
     qdict_put(dict, "tls", qbool_from_int(tls));
 }
 
-static QList *channel_list_get(void)
-{
-    ChannelList *item;
-    QList *list;
-    QDict *dict;
-
-    list = qlist_new();
-    QTAILQ_FOREACH(item, &channel_list, link) {
-        dict = qdict_new();
-        add_addr_info(dict, &item->info->paddr, item->info->plen);
-        add_channel_info(dict, item->info);
-        qlist_append(list, dict);
-    }
-    return list;
-}
-
 static void channel_event(int event, SpiceChannelEventInfo *info)
 {
     static const int qevent[] = {
@@ -217,6 +205,20 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
     QDict *server, *client;
     QObject *data;
 
+    /*
+     * Spice server might have called us from spice worker thread
+     * context (happens on display channel disconnects).  Spice should
+     * not do that.  It isn't that easy to fix it in spice and even
+     * when it is fixed we still should cover the already released
+     * spice versions.  So detect that we've been called from another
+     * thread and grab the iothread lock if so before calling qemu
+     * functions.
+     */
+    bool need_lock = !qemu_thread_is_self(&me);
+    if (need_lock) {
+        qemu_mutex_lock_iothread();
+    }
+
     client = qdict_new();
     add_addr_info(client, &info->paddr, info->plen);
 
@@ -236,6 +238,10 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
                               QOBJECT(client), QOBJECT(server));
     monitor_protocol_event(qevent[event], data);
     qobject_decref(data);
+
+    if (need_lock) {
+        qemu_mutex_unlock_iothread();
+    }
 }
 
 #else /* SPICE_INTERFACE_CORE_MINOR >= 3 */
@@ -267,6 +273,38 @@ static SpiceCoreInterface core_interface = {
 #endif
 };
 
+#ifdef SPICE_INTERFACE_MIGRATION
+typedef struct SpiceMigration {
+    SpiceMigrateInstance sin;
+    struct {
+        MonitorCompletion *cb;
+        void *opaque;
+    } connect_complete;
+} SpiceMigration;
+
+static void migrate_connect_complete_cb(SpiceMigrateInstance *sin);
+
+static const SpiceMigrateInterface migrate_interface = {
+    .base.type = SPICE_INTERFACE_MIGRATION,
+    .base.description = "migration",
+    .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
+    .migrate_connect_complete = migrate_connect_complete_cb,
+    .migrate_end_complete = NULL,
+};
+
+static SpiceMigration spice_migrate;
+
+static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
+{
+    SpiceMigration *sm = container_of(sin, SpiceMigration, sin);
+    if (sm->connect_complete.cb) {
+        sm->connect_complete.cb(sm->connect_complete.opaque, NULL);
+    }
+    sm->connect_complete.cb = NULL;
+}
+#endif
+
 /* config string parsing */
 
 static int name2enum(const char *string, const char *table[], int entries)
@@ -299,8 +337,6 @@ static int parse_name(const char *string, const char *optname,
     exit(1);
 }
 
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
 static const char *stream_video_names[] = {
     [ SPICE_STREAM_VIDEO_OFF ]    = "off",
     [ SPICE_STREAM_VIDEO_ALL ]    = "all",
@@ -309,8 +345,6 @@ static const char *stream_video_names[] = {
 #define parse_stream_video(_name) \
     name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
 
-#endif /* >= 0.6.0 */
-
 static const char *compression_names[] = {
     [ SPICE_IMAGE_COMPRESS_OFF ]      = "off",
     [ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
@@ -334,108 +368,129 @@ static const char *wan_compression_names[] = {
 
 /* functions for the rest of qemu */
 
-static void info_spice_iter(QObject *obj, void *opaque)
+static SpiceChannelList *qmp_query_spice_channels(void)
 {
-    QDict *client;
-    Monitor *mon = opaque;
-
-    client = qobject_to_qdict(obj);
-    monitor_printf(mon, "Channel:\n");
-    monitor_printf(mon, "     address: %s:%s%s\n",
-                   qdict_get_str(client, "host"),
-                   qdict_get_str(client, "port"),
-                   qdict_get_bool(client, "tls") ? " [tls]" : "");
-    monitor_printf(mon, "     session: %" PRId64 "\n",
-                   qdict_get_int(client, "connection-id"));
-    monitor_printf(mon, "     channel: %d:%d\n",
-                   (int)qdict_get_int(client, "channel-type"),
-                   (int)qdict_get_int(client, "channel-id"));
-}
-
-void do_info_spice_print(Monitor *mon, const QObject *data)
-{
-    QDict *server;
-    QList *channels;
-    const char *host;
-    int port;
-
-    server = qobject_to_qdict(data);
-    if (qdict_get_bool(server, "enabled") == 0) {
-        monitor_printf(mon, "Server: disabled\n");
-        return;
-    }
+    SpiceChannelList *cur_item = NULL, *head = NULL;
+    ChannelList *item;
 
-    monitor_printf(mon, "Server:\n");
-    host = qdict_get_str(server, "host");
-    port = qdict_get_try_int(server, "port", -1);
-    if (port != -1) {
-        monitor_printf(mon, "     address: %s:%d\n", host, port);
-    }
-    port = qdict_get_try_int(server, "tls-port", -1);
-    if (port != -1) {
-        monitor_printf(mon, "     address: %s:%d [tls]\n", host, port);
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        SpiceChannelList *chan;
+        char host[NI_MAXHOST], port[NI_MAXSERV];
+
+        chan = g_malloc0(sizeof(*chan));
+        chan->value = g_malloc0(sizeof(*chan->value));
+
+        getnameinfo(&item->info->paddr, item->info->plen,
+                    host, sizeof(host), port, sizeof(port),
+                    NI_NUMERICHOST | NI_NUMERICSERV);
+        chan->value->host = g_strdup(host);
+        chan->value->port = g_strdup(port);
+        chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
+
+        chan->value->connection_id = item->info->connection_id;
+        chan->value->channel_type = item->info->type;
+        chan->value->channel_id = item->info->id;
+        chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+
+       /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = chan;
+        } else {
+            cur_item->next = chan;
+            cur_item = chan;
+        }
     }
-    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
 
-    channels = qdict_get_qlist(server, "channels");
-    if (qlist_empty(channels)) {
-        monitor_printf(mon, "Channels: none\n");
-    } else {
-        qlist_iter(channels, info_spice_iter, mon);
-    }
+    return head;
 }
 
-void do_info_spice(Monitor *mon, QObject **ret_data)
+SpiceInfo *qmp_query_spice(Error **errp)
 {
     QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
-    QDict *server;
-    QList *clist;
-    const char *addr;
     int port, tls_port;
+    const char *addr;
+    SpiceInfo *info;
+    char version_string[20]; /* 12 = |255.255.255\0| is the max */
 
-    if (!spice_server) {
-        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
-        return;
+    info = g_malloc0(sizeof(*info));
+
+    if (!spice_server || !opts) {
+        info->enabled = false;
+        return info;
     }
 
+    info->enabled = true;
+
     addr = qemu_opt_get(opts, "addr");
     port = qemu_opt_get_number(opts, "port", 0);
     tls_port = qemu_opt_get_number(opts, "tls-port", 0);
-    clist = channel_list_get();
 
-    server = qdict_new();
-    qdict_put(server, "enabled", qbool_from_int(true));
-    qdict_put(server, "auth", qstring_from_str(auth));
-    qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
+    info->has_auth = true;
+    info->auth = g_strdup(auth);
+
+    info->has_host = true;
+    info->host = g_strdup(addr ? addr : "0.0.0.0");
+
+    info->has_compiled_version = true;
+    snprintf(version_string, sizeof(version_string), "%d.%d.%d",
+             (SPICE_SERVER_VERSION & 0xff0000) >> 16,
+             (SPICE_SERVER_VERSION & 0xff00) >> 8,
+             SPICE_SERVER_VERSION & 0xff);
+    info->compiled_version = g_strdup(version_string);
+
     if (port) {
-        qdict_put(server, "port", qint_from_int(port));
+        info->has_port = true;
+        info->port = port;
     }
     if (tls_port) {
-        qdict_put(server, "tls-port", qint_from_int(tls_port));
-    }
-    if (clist) {
-        qdict_put(server, "channels", clist);
+        info->has_tls_port = true;
+        info->tls_port = tls_port;
     }
 
-    *ret_data = QOBJECT(server);
+    /* for compatibility with the original command */
+    info->has_channels = true;
+    info->channels = qmp_query_spice_channels();
+
+    return info;
 }
 
-static void migration_state_notifier(Notifier *notifier)
+static void migration_state_notifier(Notifier *notifier, void *data)
 {
-    int state = get_migration_state();
+    MigrationState *s = data;
 
-    if (state == MIG_STATE_COMPLETED) {
+    if (migration_is_active(s)) {
+#ifdef SPICE_INTERFACE_MIGRATION
+        spice_server_migrate_start(spice_server);
+#endif
+    } else if (migration_has_finished(s)) {
 #if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */
+#ifndef SPICE_INTERFACE_MIGRATION
         spice_server_migrate_switch(spice_server);
+#else
+        spice_server_migrate_end(spice_server, true);
+    } else if (migration_has_failed(s)) {
+        spice_server_migrate_end(spice_server, false);
+#endif
 #endif
     }
 }
 
 int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
-                            const char *subject)
+                            const char *subject,
+                            MonitorCompletion *cb, void *opaque)
 {
-    return spice_server_migrate_info(spice_server, hostname,
-                                     port, tls_port, subject);
+    int ret;
+#ifdef SPICE_INTERFACE_MIGRATION
+    spice_migrate.connect_complete.cb = cb;
+    spice_migrate.connect_complete.opaque = opaque;
+    ret = spice_server_migrate_connect(spice_server, hostname,
+                                       port, tls_port, subject);
+#else
+    ret = spice_server_migrate_info(spice_server, hostname,
+                                    port, tls_port, subject);
+    cb(opaque, NULL);
+#endif
+    return ret;
 }
 
 static int add_channel(const char *name, const char *value, void *opaque)
@@ -478,13 +533,24 @@ void qemu_spice_init(void)
     spice_image_compression_t compression;
     spice_wan_compression_t wan_compr;
 
-    if (!opts) {
+    qemu_thread_get_self(&me);
+
+   if (!opts) {
         return;
     }
     port = qemu_opt_get_number(opts, "port", 0);
     tls_port = qemu_opt_get_number(opts, "tls-port", 0);
     if (!port && !tls_port) {
-        return;
+        fprintf(stderr, "neither port nor tls-port specified for spice.");
+        exit(1);
+    }
+    if (port < 0 || port > 65535) {
+        fprintf(stderr, "spice port is out of range");
+        exit(1);
+    }
+    if (tls_port < 0 || tls_port > 65535) {
+        fprintf(stderr, "spice tls-port is out of range");
+        exit(1);
     }
     password = qemu_opt_get(opts, "password");
 
@@ -497,25 +563,25 @@ void qemu_spice_init(void)
 
         str = qemu_opt_get(opts, "x509-key-file");
         if (str) {
-            x509_key_file = qemu_strdup(str);
+            x509_key_file = g_strdup(str);
         } else {
-            x509_key_file = qemu_malloc(len);
+            x509_key_file = g_malloc(len);
             snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
         }
 
         str = qemu_opt_get(opts, "x509-cert-file");
         if (str) {
-            x509_cert_file = qemu_strdup(str);
+            x509_cert_file = g_strdup(str);
         } else {
-            x509_cert_file = qemu_malloc(len);
+            x509_cert_file = g_malloc(len);
             snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
         }
 
         str = qemu_opt_get(opts, "x509-cacert-file");
         if (str) {
-            x509_cacert_file = qemu_strdup(str);
+            x509_cacert_file = g_strdup(str);
         } else {
-            x509_cacert_file = qemu_malloc(len);
+            x509_cacert_file = g_malloc(len);
             snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
         }
 
@@ -549,11 +615,29 @@ void qemu_spice_init(void)
     if (password) {
         spice_server_set_ticket(spice_server, password, 0, 0, 0);
     }
+    if (qemu_opt_get_bool(opts, "sasl", 0)) {
+#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */
+        if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
+            spice_server_set_sasl(spice_server, 1) == -1) {
+            fprintf(stderr, "spice: failed to enable sasl\n");
+            exit(1);
+        }
+#else
+        fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n");
+        exit(1);
+#endif
+    }
     if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
         auth = "none";
         spice_server_set_noauth(spice_server);
     }
 
+#if SPICE_SERVER_VERSION >= 0x000801
+    if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) {
+        spice_server_set_agent_copypaste(spice_server, false);
+    }
+#endif
+
     compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
     str = qemu_opt_get(opts, "image-compression");
     if (str) {
@@ -575,8 +659,6 @@ void qemu_spice_init(void)
     }
     spice_server_set_zlib_glz_compression(spice_server, wan_compr);
 
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
     str = qemu_opt_get(opts, "streaming-video");
     if (str) {
         int streaming_video = parse_stream_video(str);
@@ -588,22 +670,28 @@ void qemu_spice_init(void)
     spice_server_set_playback_compression
         (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1));
 
-#endif /* >= 0.6.0 */
-
     qemu_opt_foreach(opts, add_channel, NULL, 0);
 
-    spice_server_init(spice_server, &core_interface);
+    if (0 != spice_server_init(spice_server, &core_interface)) {
+        fprintf(stderr, "failed to initialize spice server");
+        exit(1);
+    };
     using_spice = 1;
 
     migration_state.notify = migration_state_notifier;
     add_migration_state_change_notifier(&migration_state);
+#ifdef SPICE_INTERFACE_MIGRATION
+    spice_migrate.sin.base.sif = &migrate_interface.base;
+    spice_migrate.connect_complete.cb = NULL;
+    qemu_spice_add_interface(&spice_migrate.sin.base);
+#endif
 
     qemu_spice_input_init();
     qemu_spice_audio_init();
 
-    qemu_free(x509_key_file);
-    qemu_free(x509_cert_file);
-    qemu_free(x509_cacert_file);
+    g_free(x509_key_file);
+    g_free(x509_cert_file);
+    g_free(x509_cacert_file);
 }
 
 int qemu_spice_add_interface(SpiceBaseInstance *sin)
index 020b423bd6bcce8961a8c5c427ee420690f8cb6e..6c302a39094ad98bd0b718c95ac1e7fc2c70c3a5 100644 (file)
@@ -15,8 +15,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
 #include "qemu-common.h"
 #include "qemu-spice.h"
 #include "qemu-timer.h"
@@ -62,14 +60,71 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
     dest->right = MAX(dest->right, r->right);
 }
 
-/*
- * Called from spice server thread context (via interface_get_command).
- *
- * We must aquire the global qemu mutex here to make sure the
- * DisplayState (+DisplaySurface) we are accessing doesn't change
- * underneath us.
- */
-SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
+                            qxl_async_io async)
+{
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->add_memslot(ssd->worker, memslot);
+    }
+}
+
+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
+{
+    ssd->worker->del_memslot(ssd->worker, gid, sid);
+}
+
+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                       QXLDevSurfaceCreate *surface,
+                                       qxl_async_io async)
+{
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->create_primary_surface(ssd->worker, id, surface);
+    }
+}
+
+
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
+                                        uint32_t id, qxl_async_io async)
+{
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->destroy_primary_surface(ssd->worker, id);
+    }
+}
+
+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->wakeup(ssd->worker);
+}
+
+void qemu_spice_start(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->start(ssd->worker);
+}
+
+void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->stop(ssd->worker);
+}
+
+static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
 {
     SimpleSpiceUpdate *update;
     QXLDrawable *drawable;
@@ -77,10 +132,9 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     QXLCommand *cmd;
     uint8_t *src, *dst;
     int by, bw, bh;
+    struct timespec time_space;
 
-    qemu_mutex_lock_iothread();
     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
-        qemu_mutex_unlock_iothread();
         return NULL;
     };
 
@@ -88,14 +142,14 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
            ssd->dirty.left, ssd->dirty.right,
            ssd->dirty.top, ssd->dirty.bottom);
 
-    update   = qemu_mallocz(sizeof(*update));
+    update   = g_malloc0(sizeof(*update));
     drawable = &update->drawable;
     image    = &update->image;
     cmd      = &update->ext.cmd;
 
     bw       = ssd->dirty.right - ssd->dirty.left;
     bh       = ssd->dirty.bottom - ssd->dirty.top;
-    update->bitmap = qemu_malloc(bw * bh * 4);
+    update->bitmap = g_malloc(bw * bh * 4);
 
     drawable->bbox            = ssd->dirty;
     drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
@@ -105,6 +159,10 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     drawable->surfaces_dest[0] = -1;
     drawable->surfaces_dest[1] = -1;
     drawable->surfaces_dest[2] = -1;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    /* time in milliseconds from epoch. */
+    drawable->mm_time = time_space.tv_sec * 1000
+                      + time_space.tv_nsec / 1000 / 1000;
 
     drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
     drawable->u.copy.src_bitmap      = (intptr_t)image;
@@ -141,7 +199,6 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     cmd->data = (intptr_t)drawable;
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
-    qemu_mutex_unlock_iothread();
     return update;
 }
 
@@ -149,12 +206,12 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
  * Called from spice server thread context (via interface_release_ressource)
  * We do *not* hold the global qemu mutex here, so extra care is needed
  * when calling qemu functions.  Qemu interfaces used:
- *    - qemu_free (underlying glibc free is re-entrant).
+ *    - g_free (underlying glibc free is re-entrant).
  */
 void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
 {
-    qemu_free(update->bitmap);
-    qemu_free(update);
+    g_free(update->bitmap);
+    g_free(update);
 }
 
 void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
@@ -166,7 +223,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
     memset(&memslot, 0, sizeof(memslot));
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
     memslot.virt_end = ~0;
-    ssd->worker->add_memslot(ssd->worker, &memslot);
+    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
 }
 
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
@@ -186,32 +243,38 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
     surface.mem        = (intptr_t)ssd->buf;
     surface.group_id   = MEMSLOT_GROUP_HOST;
 
-    qemu_mutex_unlock_iothread();
-    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
-    qemu_mutex_lock_iothread();
+    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
-    qemu_mutex_unlock_iothread();
-    ssd->worker->destroy_primary_surface(ssd->worker, 0);
-    qemu_mutex_lock_iothread();
+    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
 }
 
-void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+void qemu_spice_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
 {
     SimpleSpiceDisplay *ssd = opaque;
 
     if (running) {
-        ssd->worker->start(ssd->worker);
+        ssd->running = true;
+        qemu_spice_start(ssd);
     } else {
-        qemu_mutex_unlock_iothread();
-        ssd->worker->stop(ssd->worker);
-        qemu_mutex_lock_iothread();
+        qemu_spice_stop(ssd);
+        ssd->running = false;
     }
-    ssd->running = running;
+}
+
+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
+{
+    ssd->ds = ds;
+    qemu_mutex_init(&ssd->lock);
+    ssd->mouse_x = -1;
+    ssd->mouse_y = -1;
+    ssd->bufsize = (16 * 1024 * 1024);
+    ssd->buf = g_malloc(ssd->bufsize);
 }
 
 /* display listener callbacks */
@@ -241,6 +304,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
     qemu_pf_conv_put(ssd->conv);
     ssd->conv = NULL;
 
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update != NULL) {
+        qemu_spice_destroy_update(ssd, ssd->update);
+        ssd->update = NULL;
+    }
+    qemu_mutex_unlock(&ssd->lock);
     qemu_spice_destroy_host_primary(ssd);
     qemu_spice_create_host_primary(ssd);
 
@@ -252,9 +321,27 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
 {
     dprint(3, "%s:\n", __FUNCTION__);
     vga_hw_update();
+
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update == NULL) {
+        ssd->update = qemu_spice_create_update(ssd);
+        ssd->notify++;
+    }
+    if (ssd->cursor) {
+        ssd->ds->cursor_define(ssd->cursor);
+        cursor_put(ssd->cursor);
+        ssd->cursor = NULL;
+    }
+    if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
+        ssd->ds->mouse_set(ssd->mouse_x, ssd->mouse_y, 1);
+        ssd->mouse_x = -1;
+        ssd->mouse_y = -1;
+    }
+    qemu_mutex_unlock(&ssd->lock);
+
     if (ssd->notify) {
         ssd->notify = 0;
-        ssd->worker->wakeup(ssd->worker);
+        qemu_spice_wakeup(ssd);
         dprint(2, "%s: notify\n", __FUNCTION__);
     }
 }
@@ -298,14 +385,20 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
 {
     SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
     SimpleSpiceUpdate *update;
+    int ret = false;
 
     dprint(3, "%s:\n", __FUNCTION__);
-    update = qemu_spice_create_update(ssd);
-    if (update == NULL) {
-        return false;
+
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update != NULL) {
+        update = ssd->update;
+        ssd->update = NULL;
+        *ext = update->ext;
+        ret = true;
     }
-    *ext = update->ext;
-    return true;
+    qemu_mutex_unlock(&ssd->lock);
+
+    return ret;
 }
 
 static int interface_req_cmd_notification(QXLInstance *sin)
@@ -397,9 +490,7 @@ static DisplayChangeListener display_listener = {
 void qemu_spice_display_init(DisplayState *ds)
 {
     assert(sdpy.ds == NULL);
-    sdpy.ds = ds;
-    sdpy.bufsize = (16 * 1024 * 1024);
-    sdpy.buf = qemu_malloc(sdpy.bufsize);
+    qemu_spice_display_init_common(&sdpy, ds);
     register_displaychangelistener(ds, &display_listener);
 
     sdpy.qxl.base.sif = &dpy_interface.base;
index aef0464f866f06bad06950bd19464e935395c105..5e52df99beb37ed9f6bac050aef37e54305b2530 100644 (file)
 #include <spice/enums.h>
 #include <spice/qxl_dev.h>
 
+#include "qemu-thread.h"
+#include "console.h"
 #include "pflib.h"
+#include "sysemu.h"
 
 #define NUM_MEMSLOTS 8
 #define MEMSLOT_GENERATION_BITS 8
 
 #define NUM_SURFACES 1024
 
-typedef struct SimpleSpiceDisplay {
+/*
+ * Internal enum to differenciate between options for
+ * io calls that have a sync (old) version and an _async (new)
+ * version:
+ *  QXL_SYNC: use the old version
+ *  QXL_ASYNC: use the new version and make sure there are no two
+ *   happening at the same time. This is used for guest initiated
+ *   calls
+ */
+typedef enum qxl_async_io {
+    QXL_SYNC,
+    QXL_ASYNC,
+} qxl_async_io;
+
+typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
+typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
+
+struct SimpleSpiceDisplay {
     DisplayState *ds;
     void *buf;
     int bufsize;
@@ -43,26 +63,50 @@ typedef struct SimpleSpiceDisplay {
     QXLRect dirty;
     int notify;
     int running;
-} SimpleSpiceDisplay;
 
-typedef struct SimpleSpiceUpdate {
+    /*
+     * All struct members below this comment can be accessed from
+     * both spice server and qemu (iothread) context and any access
+     * to them must be protected by the lock.
+     */
+    QemuMutex lock;
+    SimpleSpiceUpdate *update;
+    QEMUCursor *cursor;
+    int mouse_x, mouse_y;
+};
+
+struct SimpleSpiceUpdate {
     QXLDrawable drawable;
     QXLImage image;
     QXLCommandExt ext;
     uint8_t *bitmap;
-} SimpleSpiceUpdate;
+};
 
 int qemu_spice_rect_is_empty(const QXLRect* r);
 void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
 
-SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy);
 void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
 void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
-void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+void qemu_spice_vm_change_state_handler(void *opaque, int running,
+                                        RunState state);
+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds);
 
 void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
                                int x, int y, int w, int h);
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
+                            qxl_async_io async);
+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
+                            uint32_t sid);
+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                       QXLDevSurfaceCreate *surface,
+                                       qxl_async_io async);
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
+                                        uint32_t id, qxl_async_io async);
+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
+void qemu_spice_start(SimpleSpiceDisplay *ssd);
+void qemu_spice_stop(SimpleSpiceDisplay *ssd);
index 37c8578a2c95d269f80c87c2700228923afdfad0..af4223d44261eb82fe2830441b2865d355f6f40c 100644 (file)
@@ -178,7 +178,7 @@ static const SpiceTabletInterface tablet_interface = {
     .buttons            = tablet_buttons,
 };
 
-static void mouse_mode_notifier(Notifier *notifier)
+static void mouse_mode_notifier(Notifier *notifier, void *data)
 {
     QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
     bool is_absolute  = kbd_mouse_is_absolute();
@@ -200,12 +200,12 @@ void qemu_spice_input_init(void)
     QemuSpiceKbd *kbd;
     QemuSpicePointer *pointer;
 
-    kbd = qemu_mallocz(sizeof(*kbd));
+    kbd = g_malloc0(sizeof(*kbd));
     kbd->sin.base.sif = &kbd_interface.base;
     qemu_spice_add_interface(&kbd->sin.base);
     qemu_add_led_event_handler(kbd_leds, kbd);
 
-    pointer = qemu_mallocz(sizeof(*pointer));
+    pointer = g_malloc0(sizeof(*pointer));
     pointer->mouse.base.sif  = &mouse_interface.base;
     pointer->tablet.base.sif = &tablet_interface.base;
     qemu_spice_add_interface(&pointer->mouse.base);
@@ -213,5 +213,5 @@ void qemu_spice_input_init(void)
     pointer->absolute = false;
     pointer->mouse_mode.notify = mouse_mode_notifier;
     qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
-    mouse_mode_notifier(&pointer->mouse_mode);
+    mouse_mode_notifier(&pointer->mouse_mode, NULL);
 }
index 17a621a2ba8f57d761289748952b812afbf8f88c..e2045fc0b8db1c79bf6ebf379125e821a1ac11c1 100644 (file)
@@ -34,8 +34,8 @@ void vnc_sasl_client_cleanup(VncState *vs)
         vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0;
         vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
         vs->sasl.encoded = NULL;
-        free(vs->sasl.username);
-        free(vs->sasl.mechlist);
+        g_free(vs->sasl.username);
+        g_free(vs->sasl.mechlist);
         vs->sasl.username = vs->sasl.mechlist = NULL;
         sasl_dispose(&vs->sasl.conn);
         vs->sasl.conn = NULL;
@@ -135,7 +135,7 @@ static int vnc_auth_sasl_check_access(VncState *vs)
     }
     VNC_DEBUG("SASL client username %s\n", (const char *)val);
 
-    vs->sasl.username = qemu_strdup((const char*)val);
+    vs->sasl.username = g_strdup((const char*)val);
 
     if (vs->vd->sasl.acl == NULL) {
         VNC_DEBUG("no ACL activated, allowing access\n");
@@ -430,11 +430,7 @@ static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size
 
 static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
 {
-    char *mechname = malloc(len + 1);
-    if (!mechname) {
-        VNC_DEBUG("Out of memory reading mechname\n");
-        vnc_client_error(vs);
-    }
+    char *mechname = g_malloc(len + 1);
     strncpy(mechname, (char*)data, len);
     mechname[len] = '\0';
     VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
@@ -460,7 +456,7 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_
         }
     }
 
-    free(vs->sasl.mechlist);
+    g_free(vs->sasl.mechlist);
     vs->sasl.mechlist = mechname;
 
     VNC_DEBUG("Validated mechname '%s'\n", mechname);
@@ -469,7 +465,7 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_
 
  fail:
     vnc_client_error(vs);
-    free(mechname);
+    g_free(mechname);
     return -1;
 }
 
@@ -491,13 +487,6 @@ static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, s
     return 0;
 }
 
-#define USES_X509_AUTH(vs)                              \
-    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
-
-
 void start_auth_sasl(VncState *vs)
 {
     const char *mechlist = NULL;
@@ -513,7 +502,7 @@ void start_auth_sasl(VncState *vs)
         goto authabort;
 
     if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
-        free(localAddr);
+        g_free(localAddr);
         goto authabort;
     }
 
@@ -525,8 +514,8 @@ void start_auth_sasl(VncState *vs)
                           NULL, /* Callbacks, not needed */
                           SASL_SUCCESS_DATA,
                           &vs->sasl.conn);
-    free(localAddr);
-    free(remoteAddr);
+    g_free(localAddr);
+    g_free(remoteAddr);
     localAddr = remoteAddr = NULL;
 
     if (err != SASL_OK) {
@@ -538,8 +527,8 @@ void start_auth_sasl(VncState *vs)
 
 #ifdef CONFIG_VNC_TLS
     /* Inform SASL that we've got an external SSF layer from TLS/x509 */
-    if (vs->vd->auth == VNC_AUTH_VENCRYPT &&
-        vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
+    if (vs->auth == VNC_AUTH_VENCRYPT &&
+        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
         gnutls_cipher_algorithm_t cipher;
         sasl_ssf_t ssf;
 
@@ -570,8 +559,8 @@ void start_auth_sasl(VncState *vs)
 #ifdef CONFIG_VNC_TLS
         /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
            is not sufficiently strong */
-        || (vs->vd->auth == VNC_AUTH_VENCRYPT &&
-            vs->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+        || (vs->auth == VNC_AUTH_VENCRYPT &&
+            vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
 #endif /* CONFIG_VNC_TLS */
         ) {
         /* If we've got TLS or UNIX domain sock, we don't care about SSF */
@@ -615,12 +604,7 @@ void start_auth_sasl(VncState *vs)
     }
     VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
 
-    if (!(vs->sasl.mechlist = strdup(mechlist))) {
-        VNC_DEBUG("Out of memory");
-        sasl_dispose(&vs->sasl.conn);
-        vs->sasl.conn = NULL;
-        goto authabort;
-    }
+    vs->sasl.mechlist = g_strdup(mechlist);
     mechlistlen = strlen(mechlist);
     vnc_write_u32(vs, mechlistlen);
     vnc_write(vs, mechlist, mechlistlen);
index 07c169186a7359694b7eb414a356a28e36537c90..674ba97dc7be2193e0cd2609bf0211570b2cbcea 100644 (file)
@@ -29,7 +29,7 @@
 
 static void start_auth_vencrypt_subauth(VncState *vs)
 {
-    switch (vs->vd->subauth) {
+    switch (vs->subauth) {
     case VNC_AUTH_VENCRYPT_TLSNONE:
     case VNC_AUTH_VENCRYPT_X509NONE:
        VNC_DEBUG("Accept TLS auth none\n");
@@ -51,7 +51,7 @@ static void start_auth_vencrypt_subauth(VncState *vs)
 #endif /* CONFIG_VNC_SASL */
 
     default: /* Should not be possible, but just in case */
-       VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth);
+       VNC_DEBUG("Reject subauth %d server bug\n", vs->auth);
        vnc_write_u8(vs, 1);
        if (vs->minor >= 8) {
            static const char err[] = "Unsupported authentication type";
@@ -110,17 +110,17 @@ static void vnc_tls_handshake_io(void *opaque) {
 
 
 #define NEED_X509_AUTH(vs)                              \
-    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
 
 
 static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
 {
     int auth = read_u32(data, 0);
 
-    if (auth != vs->vd->subauth) {
+    if (auth != vs->subauth) {
         VNC_DEBUG("Rejecting auth %d\n", auth);
         vnc_write_u8(vs, 0); /* Reject auth */
         vnc_flush(vs);
@@ -153,10 +153,10 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
         vnc_flush(vs);
         vnc_client_error(vs);
     } else {
-        VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
+        VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
         vnc_write_u8(vs, 0); /* Accept version */
         vnc_write_u8(vs, 1); /* Number of sub-auths */
-        vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
+        vnc_write_u32(vs, vs->subauth); /* The supported auth */
         vnc_flush(vs);
         vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
     }
index 364a491157163ccd46e83012a6d3c8330ce944e4..c860dbb2e564ed28ae13138f1822a631086db9c3 100644 (file)
@@ -70,8 +70,8 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
     uint8_t *last_fg, *last_bg;
     VncDisplay *vd = vs->vd;
 
-    last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
-    last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
+    last_fg = (uint8_t *) g_malloc(vd->server->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) g_malloc(vd->server->pf.bytes_per_pixel);
     has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {
         for (i = x; i < (x + w); i += 16) {
@@ -80,8 +80,8 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
                                   last_bg, last_fg, &has_bg, &has_fg);
         }
     }
-    free(last_fg);
-    free(last_bg);
+    g_free(last_fg);
+    g_free(last_bg);
 
     return 1;
 }
index f9b982e3e4bc3511384c34e00b74e9aa5880ac8d..5d492abe9207af4ec90737475126136f75355176 100644 (file)
 
 #include "config-host.h"
 
+/* This needs to be before jpeglib.h line because of conflict with
+   INT32 definitions between jmorecfg.h (included by jpeglib.h) and
+   Win32 basetsd.h (included by windows.h). */
+#include "qemu-common.h"
+
 #ifdef CONFIG_VNC_PNG
+/* The following define is needed by pngconf.h. Otherwise it won't compile,
+   because setjmp.h was already included by qemu-common.h. */
+#define PNG_SKIP_SETJMP_CHECK
 #include <png.h>
 #endif
 #ifdef CONFIG_VNC_JPEG
@@ -36,8 +44,6 @@
 #include <jpeglib.h>
 #endif
 
-#include "qemu-common.h"
-
 #include "bswap.h"
 #include "qint.h"
 #include "vnc.h"
@@ -72,6 +78,26 @@ static const struct {
 static int tight_send_framebuffer_update(VncState *vs, int x, int y,
                                          int w, int h);
 
+#ifdef CONFIG_VNC_JPEG
+static const struct {
+    double jpeg_freq_min;       /* Don't send JPEG if the freq is bellow */
+    double jpeg_freq_threshold; /* Always send JPEG if the freq is above */
+    int jpeg_idx;               /* Allow indexed JPEG */
+    int jpeg_full;              /* Allow full color JPEG */
+} tight_jpeg_conf[] = {
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   10, 1, 1 },
+    { 0.1, 10, 1, 1 },
+    { 0.2, 10, 1, 1 },
+    { 0.3, 12, 0, 0 },
+    { 0.4, 14, 0, 0 },
+    { 0.5, 16, 0, 0 },
+};
+#endif
+
 #ifdef CONFIG_VNC_PNG
 static const struct {
     int png_zlib_level, png_filters;
@@ -1267,13 +1293,13 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
 
     jpeg_start_compress(&cinfo, true);
 
-    buf = qemu_malloc(w * 3);
+    buf = g_malloc(w * 3);
     row[0] = buf;
     for (dy = 0; dy < h; dy++) {
         rgb_prepare_row(vs, buf, x, y + dy, w);
         jpeg_write_scanlines(&cinfo, row, 1);
     }
-    qemu_free(buf);
+    g_free(buf);
 
     jpeg_finish_compress(&cinfo);
     jpeg_destroy_compress(&cinfo);
@@ -1337,12 +1363,12 @@ static void png_flush_data(png_structp png_ptr)
 
 static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
 {
-    return qemu_malloc(size);
+    return g_malloc(size);
 }
 
 static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
 {
-    qemu_free(ptr);
+    g_free(ptr);
 }
 
 static int send_png_rect(VncState *vs, int x, int y, int w, int h,
@@ -1406,7 +1432,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
     png_write_info(png_ptr, info_ptr);
 
     buffer_reserve(&vs->tight.png, 2048);
-    buf = qemu_malloc(w * 3);
+    buf = g_malloc(w * 3);
     for (dy = 0; dy < h; dy++)
     {
         if (color_type == PNG_COLOR_TYPE_PALETTE) {
@@ -1416,7 +1442,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
         }
         png_write_row(png_ptr, buf);
     }
-    qemu_free(buf);
+    g_free(buf);
 
     png_write_end(png_ptr, NULL);
 
@@ -1477,12 +1503,13 @@ static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
 #ifdef CONFIG_VNC_JPEG
 static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
                               int bg, int fg, int colors,
-                              VncPalette *palette)
+                              VncPalette *palette, bool force)
 {
     int ret;
 
     if (colors == 0) {
-        if (tight_detect_smooth_image(vs, w, h)) {
+        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
+                      tight_detect_smooth_image(vs, w, h))) {
             int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
@@ -1494,8 +1521,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
     } else if (colors == 2) {
         ret = send_mono_rect(vs, x, y, w, h, bg, fg);
     } else if (colors <= 256) {
-        if (colors > 96 &&
-            tight_detect_smooth_image(vs, w, h)) {
+        if (force || (colors > 96 &&
+                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
+                      tight_detect_smooth_image(vs, w, h))) {
             int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
@@ -1515,6 +1543,10 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     uint32_t bg = 0, fg = 0;
     int colors;
     int ret = 0;
+#ifdef CONFIG_VNC_JPEG
+    bool force_jpeg = false;
+    bool allow_jpeg = true;
+#endif
 
     vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
 
@@ -1522,11 +1554,26 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
     vnc_tight_stop(vs);
 
+#ifdef CONFIG_VNC_JPEG
+    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
+        double freq = vnc_update_freq(vs, x, y, w, h);
+
+        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
+            allow_jpeg = false;
+        }
+        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+            force_jpeg = true;
+            vnc_sent_lossy_rect(vs, x, y, w, h);
+        }
+    }
+#endif
+
     colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
 
 #ifdef CONFIG_VNC_JPEG
-    if (vs->tight.quality != (uint8_t)-1) {
-        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette);
+    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
+        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette,
+                                 force_jpeg);
     } else {
         ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
     }
@@ -1549,7 +1596,8 @@ static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
     return send_solid_rect(vs);
 }
 
-static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
+static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
+                            bool split)
 {
     int max_size, max_width;
     int max_sub_width, max_sub_height;
@@ -1560,7 +1608,7 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
     max_size = tight_conf[vs->tight.compression].max_rect_size;
     max_width = tight_conf[vs->tight.compression].max_rect_width;
 
-    if (w > max_width || w * h > max_size) {
+    if (split && (w > max_width || w * h > max_size)) {
         max_sub_width = (w > max_width) ? max_width : w;
         max_sub_height = max_size / max_sub_width;
 
@@ -1591,7 +1639,7 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
         /* If a rectangle becomes too large, send its upper part now. */
 
         if (dy - y >= max_rows) {
-            n += send_rect_simple(vs, x, y, w, max_rows);
+            n += send_rect_simple(vs, x, y, w, max_rows, true);
             y += max_rows;
             h -= max_rows;
         }
@@ -1630,7 +1678,7 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
             /* Send rectangles at top and left to solid-color area. */
 
             if (y_best != y) {
-                n += send_rect_simple(vs, x, y, w, y_best-y);
+                n += send_rect_simple(vs, x, y, w, y_best-y, true);
             }
             if (x_best != x) {
                 n += tight_send_framebuffer_update(vs, x, y_best,
@@ -1657,7 +1705,7 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
             return n;
         }
     }
-    return n + send_rect_simple(vs, x, y, w, h);
+    return n + send_rect_simple(vs, x, y, w, h, true);
 }
 
 static int tight_send_framebuffer_update(VncState *vs, int x, int y,
@@ -1672,8 +1720,19 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
         vs->tight.pixel24 = false;
     }
 
-    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE)
-        return send_rect_simple(vs, x, y, w, h);
+#ifdef CONFIG_VNC_JPEG
+    if (vs->tight.quality != (uint8_t)-1) {
+        double freq = vnc_update_freq(vs, x, y, w, h);
+
+        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+            return send_rect_simple(vs, x, y, w, h, false);
+        }
+    }
+#endif
+
+    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) {
+        return send_rect_simple(vs, x, y, w, h, true);
+    }
 
     /* Calculate maximum number of rows in one non-solid rectangle. */
 
index e32e4cd8a826262494df1dc0e03985f74231c481..d1b97f2516fd6eb622bed13e90b22c8ef2df4a76 100644 (file)
@@ -35,14 +35,14 @@ void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size)
     size *= items;
     size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
 
-    p = qemu_mallocz(size);
+    p = g_malloc0(size);
 
     return (p);
 }
 
 void vnc_zlib_zfree(void *x, void *addr)
 {
-    qemu_free(addr);
+    g_free(addr);
 }
 
 static void vnc_zlib_start(VncState *vs)
diff --git a/ui/vnc-enc-zrle-template.c b/ui/vnc-enc-zrle-template.c
new file mode 100644 (file)
index 0000000..70ae624
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrleencodetemplate.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel.
+ *
+ * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+ * bigger than the largest tile of pixel data, since the ZRLE encoding
+ * algorithm writes to the position one past the end of the pixel data.
+ */
+
+
+#include <assert.h>
+
+#undef ZRLE_ENDIAN_SUFFIX
+
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+#define ZRLE_ENDIAN_SUFFIX le
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+#define ZRLE_ENDIAN_SUFFIX be
+#else
+#define ZRLE_ENDIAN_SUFFIX ne
+#endif
+
+#ifndef ZRLE_CONCAT
+#define ZRLE_CONCAT_I(a, b)    a##b
+#define ZRLE_CONCAT2(a, b)     ZRLE_CONCAT_I(a, b)
+#define ZRLE_CONCAT3(a, b, c)  ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c))
+#endif
+
+#ifdef ZRLE_COMPACT_PIXEL
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    ZRLE_COMPACT_PIXEL
+#define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
+#define ZRLE_BPP_OUT         24
+#elif ZRLE_BPP == 15
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    16
+#define ZRLE_PIXEL           uint16_t
+#define ZRLE_BPP_OUT         16
+#else
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    ZRLE_BPP
+#define ZRLE_BPP_OUT         ZRLE_BPP
+#define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
+#endif
+
+#define ZRLE_WRITE_PIXEL     ZRLE_CONCAT2(zrle_write_u,       ZRLE_WRITE_SUFFIX)
+#define ZRLE_ENCODE          ZRLE_CONCAT2(zrle_encode_,      ZRLE_ENCODE_SUFFIX)
+#define ZRLE_ENCODE_TILE     ZRLE_CONCAT2(zrle_encode_tile,  ZRLE_ENCODE_SUFFIX)
+#define ZRLE_WRITE_PALETTE   ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
+
+static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
+                             int zywrle_level);
+
+#if ZRLE_BPP != 8
+#include "vnc-enc-zywrle-template.c"
+#endif
+
+
+static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
+                        int zywrle_level)
+{
+    int ty;
+
+    for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) {
+
+        int tx, th;
+
+        th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty);
+
+        for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) {
+            int tw;
+            ZRLE_PIXEL *buf;
+
+            tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx);
+
+            buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP);
+            ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level);
+        }
+    }
+}
+
+static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
+                             int zywrle_level)
+{
+    VncPalette *palette = &vs->zrle.palette;
+
+    int runs = 0;
+    int single_pixels = 0;
+
+    bool use_rle;
+    bool use_palette;
+
+    int i;
+
+    ZRLE_PIXEL *ptr = data;
+    ZRLE_PIXEL *end = ptr + h * w;
+    *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+    /* Real limit is 127 but we wan't a way to know if there is more than 127 */
+    palette_init(palette, 256, ZRLE_BPP);
+
+    while (ptr < end) {
+        ZRLE_PIXEL pix = *ptr;
+        if (*++ptr != pix) { /* FIXME */
+            single_pixels++;
+        } else {
+            while (*++ptr == pix) ;
+            runs++;
+        }
+        palette_put(palette, pix);
+    }
+
+    /* Solid tile is a special case */
+
+    if (palette_size(palette) == 1) {
+        bool found;
+
+        vnc_write_u8(vs, 1);
+        ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found));
+        return;
+    }
+
+    zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT,
+                            runs, single_pixels, zywrle_level,
+                            &use_rle, &use_palette);
+
+    if (!use_palette) {
+        vnc_write_u8(vs, (use_rle ? 128 : 0));
+    } else {
+        uint32_t colors[VNC_PALETTE_MAX_SIZE];
+        size_t size = palette_size(palette);
+
+        vnc_write_u8(vs, (use_rle ? 128 : 0) | size);
+        palette_fill(palette, colors);
+
+        for (i = 0; i < size; i++) {
+            ZRLE_WRITE_PIXEL(vs, colors[i]);
+        }
+    }
+
+    if (use_rle) {
+        ZRLE_PIXEL *ptr = data;
+        ZRLE_PIXEL *end = ptr + w * h;
+        ZRLE_PIXEL *run_start;
+        ZRLE_PIXEL pix;
+
+        while (ptr < end) {
+            int len;
+            int index = 0;
+
+            run_start = ptr;
+            pix = *ptr++;
+
+            while (*ptr == pix && ptr < end) {
+                ptr++;
+            }
+
+            len = ptr - run_start;
+
+            if (use_palette)
+                index = palette_idx(palette, pix);
+
+            if (len <= 2 && use_palette) {
+                if (len == 2) {
+                    vnc_write_u8(vs, index);
+                }
+                vnc_write_u8(vs, index);
+                continue;
+            }
+            if (use_palette) {
+                vnc_write_u8(vs, index | 128);
+            } else {
+                ZRLE_WRITE_PIXEL(vs, pix);
+            }
+
+            len -= 1;
+
+            while (len >= 255) {
+                vnc_write_u8(vs, 255);
+                len -= 255;
+            }
+
+            vnc_write_u8(vs, len);
+        }
+    } else if (use_palette) { /* no RLE */
+        int bppp;
+        ZRLE_PIXEL *ptr = data;
+
+        /* packed pixels */
+
+        assert (palette_size(palette) < 17);
+
+        bppp = bits_per_packed_pixel[palette_size(palette)-1];
+
+        for (i = 0; i < h; i++) {
+            uint8_t nbits = 0;
+            uint8_t byte = 0;
+
+            ZRLE_PIXEL *eol = ptr + w;
+
+            while (ptr < eol) {
+                ZRLE_PIXEL pix = *ptr++;
+                uint8_t index = palette_idx(palette, pix);
+
+                byte = (byte << bppp) | index;
+                nbits += bppp;
+                if (nbits >= 8) {
+                    vnc_write_u8(vs, byte);
+                    nbits = 0;
+                }
+            }
+            if (nbits > 0) {
+                byte <<= 8 - nbits;
+                vnc_write_u8(vs, byte);
+            }
+        }
+    } else {
+
+        /* raw */
+
+#if ZRLE_BPP != 8
+        if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
+            ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf);
+            ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
+        }
+        else
+#endif
+        {
+#ifdef ZRLE_COMPACT_PIXEL
+            ZRLE_PIXEL *ptr;
+
+            for (ptr = data; ptr < data + w * h; ptr++) {
+                ZRLE_WRITE_PIXEL(vs, *ptr);
+            }
+#else
+            vnc_write(vs, data, w * h * (ZRLE_BPP / 8));
+#endif
+        }
+    }
+}
+
+#undef ZRLE_PIXEL
+#undef ZRLE_WRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef ZYWRLE_ENCODE_TILE
+#undef ZRLE_BPP_OUT
+#undef ZRLE_WRITE_SUFFIX
+#undef ZRLE_ENCODE_SUFFIX
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
new file mode 100644 (file)
index 0000000..917d384
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrle.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.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 "vnc.h"
+#include "vnc-enc-zrle.h"
+
+static const int bits_per_packed_pixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+
+static void vnc_zrle_start(VncState *vs)
+{
+    buffer_reset(&vs->zrle.zrle);
+
+    /* make the output buffer be the zlib buffer, so we can compress it later */
+    vs->zrle.tmp = vs->output;
+    vs->output = vs->zrle.zrle;
+}
+
+static void vnc_zrle_stop(VncState *vs)
+{
+    /* switch back to normal output/zlib buffers */
+    vs->zrle.zrle = vs->output;
+    vs->output = vs->zrle.tmp;
+}
+
+static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
+                             int bpp)
+{
+    Buffer tmp;
+
+    buffer_reset(&vs->zrle.fb);
+    buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
+
+    tmp = vs->output;
+    vs->output = vs->zrle.fb;
+
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+
+    vs->zrle.fb = vs->output;
+    vs->output = tmp;
+    return vs->zrle.fb.buffer;
+}
+
+static int zrle_compress_data(VncState *vs, int level)
+{
+    z_streamp zstream = &vs->zrle.stream;
+
+    buffer_reset(&vs->zrle.zlib);
+
+    if (zstream->opaque != vs) {
+        int err;
+
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        zstream->opaque = vs;
+    }
+
+    /* reserve memory in output buffer */
+    buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
+
+    /* set pointers */
+    zstream->next_in = vs->zrle.zrle.buffer;
+    zstream->avail_in = vs->zrle.zrle.offset;
+    zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
+    zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
+    zstream->data_type = Z_BINARY;
+
+    /* start encoding */
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zrle compression\n");
+        return -1;
+    }
+
+    vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
+    return vs->zrle.zlib.offset;
+}
+
+/* Try to work out whether to use RLE and/or a palette.  We do this by
+ * estimating the number of bytes which will be generated and picking the
+ * method which results in the fewest bytes.  Of course this may not result
+ * in the fewest bytes after compression... */
+static void zrle_choose_palette_rle(VncState *vs, int w, int h,
+                                    VncPalette *palette, int bpp_out,
+                                    int runs, int single_pixels,
+                                    int zywrle_level,
+                                    bool *use_rle, bool *use_palette)
+{
+    size_t estimated_bytes;
+    size_t plain_rle_bytes;
+
+    *use_palette = *use_rle = false;
+
+    estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */
+
+    if (bpp_out != 8) {
+        if (zywrle_level > 0 && !(zywrle_level & 0x80))
+            estimated_bytes >>= zywrle_level;
+    }
+
+    plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels);
+
+    if (plain_rle_bytes < estimated_bytes) {
+        *use_rle = true;
+        estimated_bytes = plain_rle_bytes;
+    }
+
+    if (palette_size(palette) < 128) {
+        int palette_rle_bytes;
+
+        palette_rle_bytes = (bpp_out / 8) * palette_size(palette);
+        palette_rle_bytes += 2 * runs + single_pixels;
+
+        if (palette_rle_bytes < estimated_bytes) {
+            *use_rle = true;
+            *use_palette = true;
+            estimated_bytes = palette_rle_bytes;
+        }
+
+        if (palette_size(palette) < 17) {
+            int packed_bytes;
+
+            packed_bytes = (bpp_out / 8) * palette_size(palette);
+            packed_bytes += w * h *
+                bits_per_packed_pixel[palette_size(palette)-1] / 8;
+
+            if (packed_bytes < estimated_bytes) {
+                *use_rle = false;
+                *use_palette = true;
+                estimated_bytes = packed_bytes;
+            }
+        }
+    }
+}
+
+static void zrle_write_u32(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 4);
+}
+
+static void zrle_write_u24a(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 3);
+}
+
+static void zrle_write_u24b(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, ((uint8_t *)&value) + 1, 3);
+}
+
+static void zrle_write_u16(VncState *vs, uint16_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 2);
+}
+
+static void zrle_write_u8(VncState *vs, uint8_t value)
+{
+    vnc_write_u8(vs, value);
+}
+
+#define ENDIAN_LITTLE 0
+#define ENDIAN_BIG    1
+#define ENDIAN_NO     2
+
+#define ZRLE_BPP 8
+#define ZYWRLE_ENDIAN ENDIAN_NO
+#include "vnc-enc-zrle-template.c"
+#undef ZRLE_BPP
+
+#define ZRLE_BPP 15
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_BPP
+#define ZRLE_BPP 16
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_BPP
+#define ZRLE_BPP 32
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#define ZRLE_COMPACT_PIXEL 24a
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_COMPACT_PIXEL
+#define ZRLE_COMPACT_PIXEL 24b
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+#undef ZRLE_COMPACT_PIXEL
+#undef ZRLE_BPP
+
+static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
+                                        int w, int h)
+{
+    bool be = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+    size_t bytes;
+    int zywrle_level;
+
+    if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
+        if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
+            || vs->tight.quality == 9) {
+            zywrle_level = 0;
+            vs->zrle.type = VNC_ENCODING_ZRLE;
+        } else if (vs->tight.quality < 3) {
+            zywrle_level = 3;
+        } else if (vs->tight.quality < 6) {
+            zywrle_level = 2;
+        } else {
+            zywrle_level = 1;
+        }
+    } else {
+        zywrle_level = 0;
+    }
+
+    vnc_zrle_start(vs);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 1:
+        zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
+        break;
+
+    case 2:
+        if (vs->clientds.pf.gmax > 0x1F) {
+            if (be) {
+                zrle_encode_16be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_16le(vs, x, y, w, h, zywrle_level);
+            }
+        } else {
+            if (be) {
+                zrle_encode_15be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_15le(vs, x, y, w, h, zywrle_level);
+            }
+        }
+        break;
+
+    case 4:
+    {
+        bool fits_in_ls3bytes;
+        bool fits_in_ms3bytes;
+
+        fits_in_ls3bytes =
+            ((vs->clientds.pf.rmax << vs->clientds.pf.rshift) < (1 << 24) &&
+             (vs->clientds.pf.gmax << vs->clientds.pf.gshift) < (1 << 24) &&
+             (vs->clientds.pf.bmax << vs->clientds.pf.bshift) < (1 << 24));
+
+        fits_in_ms3bytes = (vs->clientds.pf.rshift > 7 &&
+                            vs->clientds.pf.gshift > 7 &&
+                            vs->clientds.pf.bshift > 7);
+
+        if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
+            if (be) {
+                zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
+          }
+        } else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
+            if (be) {
+                zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
+            }
+        } else {
+            if (be) {
+                zrle_encode_32be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_32le(vs, x, y, w, h, zywrle_level);
+            }
+        }
+    }
+    break;
+    }
+
+    vnc_zrle_stop(vs);
+    bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
+    vnc_write_u32(vs, bytes);
+    vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
+    return 1;
+}
+
+int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    vs->zrle.type = VNC_ENCODING_ZRLE;
+    return zrle_send_framebuffer_update(vs, x, y, w, h);
+}
+
+int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    vs->zrle.type = VNC_ENCODING_ZYWRLE;
+    return zrle_send_framebuffer_update(vs, x, y, w, h);
+}
+
+void vnc_zrle_clear(VncState *vs)
+{
+    if (vs->zrle.stream.opaque) {
+        deflateEnd(&vs->zrle.stream);
+    }
+    buffer_free(&vs->zrle.zrle);
+    buffer_free(&vs->zrle.fb);
+    buffer_free(&vs->zrle.zlib);
+}
diff --git a/ui/vnc-enc-zrle.h b/ui/vnc-enc-zrle.h
new file mode 100644 (file)
index 0000000..6b18213
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrle.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.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.
+ */
+
+#ifndef VNC_ENCODING_ZRLE_H
+#define VNC_ENCODING_ZRLE_H
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZRLE - encoding combining Zlib compression, tiling, palettisation and
+ * run-length encoding.
+ */
+
+#define VNC_ZRLE_TILE_WIDTH  64
+#define VNC_ZRLE_TILE_HEIGHT 64
+
+#endif
diff --git a/ui/vnc-enc-zywrle-template.c b/ui/vnc-enc-zywrle-template.c
new file mode 100644 (file)
index 0000000..4cde6e4
--- /dev/null
@@ -0,0 +1,170 @@
+
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *
+ *                                                                  *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************/
+
+/* Change Log:
+     V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
+                            (Thanks Johannes Schindelin, author of LibVNC
+                                                 Server/Client)
+     V0.01 : 2007/02/06 : Initial release
+*/
+
+/*
+[References]
+ PLHarr:
+   Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy,
+   "An Improved N-Bit to N-Bit Reversible Haar-Like Transform,"
+   Pacific Graphics 2004, October 2004, pp. 371-380.
+ EZW:
+   Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients,
+   IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
+*/
+
+
+/* Template Macro stuffs. */
+#undef ZYWRLE_ANALYZE
+#undef ZYWRLE_SYNTHESIZE
+
+#define ZYWRLE_SUFFIX     ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+
+#define ZYWRLE_ANALYZE    ZRLE_CONCAT2(zywrle_analyze_,   ZYWRLE_SUFFIX)
+#define ZYWRLE_SYNTHESIZE ZRLE_CONCAT2(zywrle_synthesize_,ZYWRLE_SUFFIX)
+
+#define ZYWRLE_RGBYUV     ZRLE_CONCAT2(zywrle_rgbyuv_,    ZYWRLE_SUFFIX)
+#define ZYWRLE_YUVRGB     ZRLE_CONCAT2(zywrle_yuvrgb_,    ZYWRLE_SUFFIX)
+#define ZYWRLE_YMASK      ZRLE_CONCAT2(ZYWRLE_YMASK,      ZRLE_BPP)
+#define ZYWRLE_UVMASK     ZRLE_CONCAT2(ZYWRLE_UVMASK,     ZRLE_BPP)
+#define ZYWRLE_LOAD_PIXEL ZRLE_CONCAT2(ZYWRLE_LOAD_PIXEL, ZRLE_BPP)
+#define ZYWRLE_SAVE_PIXEL ZRLE_CONCAT2(ZYWRLE_SAVE_PIXEL, ZRLE_BPP)
+
+/* Packing/Unpacking pixel stuffs.
+   Endian conversion stuffs. */
+#undef S_0
+#undef S_1
+#undef L_0
+#undef L_1
+#undef L_2
+
+#if ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define S_0  1
+#  define S_1  0
+#  define L_0  3
+#  define L_1  2
+#  define L_2  1
+#else
+#  define S_0  0
+#  define S_1  1
+#  define L_0  0
+#  define L_1  1
+#  define L_2  2
+#endif
+
+#define ZYWRLE_QUANTIZE
+#include "vnc-enc-zywrle.h"
+
+#ifndef ZRLE_COMPACT_PIXEL
+static inline void ZYWRLE_RGBYUV(int *buf, ZRLE_PIXEL *data,
+                                 int width, int height, int scanline)
+{
+    int r, g, b;
+    int y, u, v;
+    int *line;
+    int *end;
+
+    end = buf + height * width;
+    while (buf < end) {
+        line = buf + width;
+        while (buf < line) {
+            ZYWRLE_LOAD_PIXEL(data, r, g, b);
+            ZYWRLE_RGBYUV_(r, g, b, y, u, v, ZYWRLE_YMASK, ZYWRLE_UVMASK);
+            ZYWRLE_SAVE_COEFF(buf, v, y, u);
+            buf++;
+            data++;
+        }
+        data += scanline - width;
+    }
+}
+
+static ZRLE_PIXEL *ZYWRLE_ANALYZE(ZRLE_PIXEL *dst, ZRLE_PIXEL *src,
+                                  int w, int h, int scanline, int level,
+                                  int *buf) {
+    int l;
+    int uw = w;
+    int uh = h;
+    int *top;
+    int *end;
+    int *line;
+    ZRLE_PIXEL *p;
+    int r, g, b;
+    int s;
+    int *ph;
+
+    zywrle_calc_size(&w, &h, level);
+
+    if (w == 0 || h == 0) {
+        return NULL;
+    }
+    uw -= w;
+    uh -= h;
+
+    p = dst;
+    ZYWRLE_LOAD_UNALIGN(src,*(ZRLE_PIXEL*)top = *p;);
+    ZYWRLE_RGBYUV(buf, src, w, h, scanline);
+    wavelet(buf, w, h, level);
+    for (l = 0; l < level; l++) {
+        ZYWRLE_PACK_COEFF(buf, dst, 3, w, h, scanline, l);
+        ZYWRLE_PACK_COEFF(buf, dst, 2, w, h, scanline, l);
+        ZYWRLE_PACK_COEFF(buf, dst, 1, w, h, scanline, l);
+        if (l == level - 1) {
+            ZYWRLE_PACK_COEFF(buf, dst, 0, w, h, scanline, l);
+        }
+    }
+    ZYWRLE_SAVE_UNALIGN(dst,*dst = *(ZRLE_PIXEL*)top;);
+    return dst;
+}
+#endif  /* ZRLE_COMPACT_PIXEL */
+
+#undef ZYWRLE_RGBYUV
+#undef ZYWRLE_YUVRGB
+#undef ZYWRLE_LOAD_PIXEL
+#undef ZYWRLE_SAVE_PIXEL
diff --git a/ui/vnc-enc-zywrle.h b/ui/vnc-enc-zywrle.h
new file mode 100644 (file)
index 0000000..ac5d27a
--- /dev/null
@@ -0,0 +1,659 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *
+ *                                                                  *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************/
+
+#ifndef VNC_ENCODING_ZYWRLE_H
+#define VNC_ENCODING_ZYWRLE_H
+
+/* Tables for Coefficients filtering. */
+#ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static const unsigned int zywrle_param[3][3]={
+       {0x0000F000, 0x00000000, 0x00000000},
+       {0x0000C000, 0x00F0F0F0, 0x00000000},
+       {0x0000C000, 0x00C0C0C0, 0x00F0F0F0},
+/*     {0x0000FF00, 0x00000000, 0x00000000},
+       {0x0000FF00, 0x00FFFFFF, 0x00000000},
+       {0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */
+};
+#else
+/* Type B:Non liner quantization filter. */
+static const int8_t zywrle_conv[4][256]={
+{      /* bi=5, bo=5 r=0.0:PSNR=24.849 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=5 r=2.0:PSNR=74.031 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 32,
+       32, 32, 32, 32, 32, 32, 32, 32,
+       32, 32, 32, 32, 32, 32, 32, 32,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 56, 56, 56, 56, 56,
+       56, 56, 56, 56, 64, 64, 64, 64,
+       64, 64, 64, 64, 72, 72, 72, 72,
+       72, 72, 72, 72, 80, 80, 80, 80,
+       80, 80, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 96, 96,
+       96, 96, 96, 104, 104, 104, 104, 104,
+       104, 104, 104, 104, 104, 112, 112, 112,
+       112, 112, 112, 112, 112, 112, 120, 120,
+       120, 120, 120, 120, 120, 120, 120, 120,
+       0, -120, -120, -120, -120, -120, -120, -120,
+       -120, -120, -120, -112, -112, -112, -112, -112,
+       -112, -112, -112, -112, -104, -104, -104, -104,
+       -104, -104, -104, -104, -104, -104, -96, -96,
+       -96, -96, -96, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -80,
+       -80, -80, -80, -80, -80, -72, -72, -72,
+       -72, -72, -72, -72, -72, -64, -64, -64,
+       -64, -64, -64, -64, -64, -56, -56, -56,
+       -56, -56, -56, -56, -56, -56, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, -32, -32, -32, -32, -32, -32, -32,
+       -32, -32, -32, -32, -32, -32, -32, -32,
+       -32, -32, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=4 r=2.0:PSNR=64.441 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       64, 64, 64, 64, 64, 64, 64, 64,
+       64, 64, 64, 64, 64, 64, 64, 64,
+       80, 80, 80, 80, 80, 80, 80, 80,
+       80, 80, 80, 80, 80, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       104, 104, 104, 104, 104, 104, 104, 104,
+       104, 104, 104, 112, 112, 112, 112, 112,
+       112, 112, 112, 112, 120, 120, 120, 120,
+       120, 120, 120, 120, 120, 120, 120, 120,
+       0, -120, -120, -120, -120, -120, -120, -120,
+       -120, -120, -120, -120, -120, -112, -112, -112,
+       -112, -112, -112, -112, -112, -112, -104, -104,
+       -104, -104, -104, -104, -104, -104, -104, -104,
+       -104, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -80, -80, -80, -80,
+       -80, -80, -80, -80, -80, -80, -80, -80,
+       -80, -64, -64, -64, -64, -64, -64, -64,
+       -64, -64, -64, -64, -64, -64, -64, -64,
+       -64, -48, -48, -48, -48, -48, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=2 r=2.0:PSNR=43.175 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       0, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+}
+};
+
+static const int8_t *zywrle_param[3][3][3]={
+       {{zywrle_conv[0], zywrle_conv[2], zywrle_conv[0]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
+       {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
+         {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
+       {{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
+         {zywrle_conv[2], zywrle_conv[2], zywrle_conv[2]},
+         {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}},
+};
+#endif
+
+/*   Load/Save pixel stuffs. */
+#define ZYWRLE_YMASK15  0xFFFFFFF8
+#define ZYWRLE_UVMASK15 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL15(src, r, g, b)                               \
+    do {                                                                \
+       r = (((uint8_t*)src)[S_1]<< 1)& 0xF8;                           \
+       g = (((uint8_t*)src)[S_1]<< 6) | (((uint8_t*)src)[S_0]>> 2);    \
+        g &= 0xF8;                                                      \
+       b =  (((uint8_t*)src)[S_0]<< 3)& 0xF8;                          \
+    } while (0)
+
+#define ZYWRLE_SAVE_PIXEL15(dst, r, g, b)                               \
+    do {                                                                \
+       r &= 0xF8;                                                      \
+       g &= 0xF8;                                                      \
+       b &= 0xF8;                                                      \
+       ((uint8_t*)dst)[S_1] = (uint8_t)((r >> 1)|(g >> 6));            \
+       ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 2))& 0xFF);    \
+    } while (0)
+
+#define ZYWRLE_YMASK16  0xFFFFFFFC
+#define ZYWRLE_UVMASK16 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL16(src, r, g, b)                               \
+    do {                                                                \
+       r = ((uint8_t*)src)[S_1] & 0xF8;                                \
+       g = (((uint8_t*)src)[S_1]<< 5) | (((uint8_t*)src)[S_0] >> 3);   \
+        g &= 0xFC;                                                      \
+       b = (((uint8_t*)src)[S_0]<< 3) & 0xF8;                          \
+    } while (0)
+
+#define ZYWRLE_SAVE_PIXEL16(dst, r, g,b)                                \
+    do {                                                                \
+       r &= 0xF8;                                                      \
+       g &= 0xFC;                                                      \
+       b &= 0xF8;                                                      \
+       ((uint8_t*)dst)[S_1] = (uint8_t)(r | (g >> 5));                 \
+       ((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 3)) & 0xFF);   \
+    } while (0)
+
+#define ZYWRLE_YMASK32  0xFFFFFFFF
+#define ZYWRLE_UVMASK32 0xFFFFFFFF
+#define ZYWRLE_LOAD_PIXEL32(src, r, g, b)     \
+    do {                                      \
+       r = ((uint8_t*)src)[L_2];             \
+       g = ((uint8_t*)src)[L_1];             \
+       b = ((uint8_t*)src)[L_0];             \
+    } while (0)
+#define ZYWRLE_SAVE_PIXEL32(dst, r, g, b)             \
+    do {                                              \
+       ((uint8_t*)dst)[L_2] = (uint8_t)r;            \
+       ((uint8_t*)dst)[L_1] = (uint8_t)g;            \
+       ((uint8_t*)dst)[L_0] = (uint8_t)b;            \
+    } while (0)
+
+static inline void harr(int8_t *px0, int8_t *px1)
+{
+    /* Piecewise-Linear Harr(PLHarr) */
+    int x0 = (int)*px0, x1 = (int)*px1;
+    int orgx0 = x0, orgx1 = x1;
+
+    if ((x0 ^ x1) & 0x80) {
+        /* differ sign */
+        x1 += x0;
+        if (((x1 ^ orgx1) & 0x80) == 0) {
+            /* |x1| > |x0| */
+            x0 -= x1;  /* H = -B */
+        }
+    } else {
+        /* same sign */
+        x0 -= x1;
+        if (((x0 ^ orgx0) & 0x80) == 0) {
+            /* |x0| > |x1| */
+            x1 += x0;  /* L = A */
+        }
+    }
+    *px0 = (int8_t)x1;
+    *px1 = (int8_t)x0;
+}
+
+/*
+ 1D-Wavelet transform.
+
+ In coefficients array, the famous 'pyramid' decomposition is well used.
+
+ 1D Model:
+   |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
+   |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
+
+ But this method needs line buffer because H/L is different position from X0/X1.
+ So, I used 'interleave' decomposition instead of it.
+
+ 1D Model:
+   |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
+   |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
+
+ In this method, H/L and X0/X1 is always same position.
+ This lead us to more speed and less memory.
+ Of cause, the result of both method is quite same
+ because it's only difference that coefficient position.
+*/
+static inline void wavelet_level(int *data, int size, int l, int skip_pixel)
+{
+    int s, ofs;
+    int8_t *px0;
+    int8_t *end;
+
+    px0 = (int8_t*)data;
+    s = (8 << l) * skip_pixel;
+    end = px0 + (size >> (l + 1)) * s;
+    s -= 2;
+    ofs = (4 << l) * skip_pixel;
+
+    while (px0 < end) {
+        harr(px0, px0 + ofs);
+        px0++;
+        harr(px0, px0 + ofs);
+        px0++;
+        harr(px0, px0 + ofs);
+        px0 += s;
+    }
+}
+
+#ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static inline void filter_wavelet_square(int *buf, int width, int height,
+                                         int level, int l)
+{
+    int r, s;
+    int x, y;
+    int *h;
+    const unsigned int *m;
+
+    m = &(zywrle_param[level - 1][l]);
+    s = 2 << l;
+
+    for (r = 1; r < 4; r++) {
+        h = buf;
+        if (r & 0x01) {
+            h += s >> 1;
+        }
+        if (r & 0x02) {
+            h += (s >> 1) * width;
+        }
+        for (y = 0; y < height / s; y++) {
+            for (x = 0; x < width / s; x++) {
+                /*
+                  these are same following code.
+                  h[x] = h[x] / (~m[x]+1) * (~m[x]+1);
+                  ( round h[x] with m[x] bit )
+                  '&' operator isn't 'round' but is 'floor'.
+                  So, we must offset when h[x] is negative.
+                */
+                if (((int8_t*)h)[0] & 0x80) {
+                    ((int8_t*)h)[0] += ~((int8_t*)m)[0];
+                }
+                if (((int8_t*)h)[1] & 0x80) {
+                    ((int8_t*)h)[1] += ~((int8_t*)m)[1];
+                }
+                if (((int8_t*)h)[2] & 0x80) {
+                    ((int8_t*)h)[2] += ~((int8_t*)m)[2];
+                }
+                *h &= *m;
+                h += s;
+            }
+            h += (s-1)*width;
+        }
+    }
+}
+#else
+/*
+ Type B:Non liner quantization filter.
+
+ Coefficients have Gaussian curve and smaller value which is
+ large part of coefficients isn't more important than larger value.
+ So, I use filter of Non liner quantize/dequantize table.
+ In general, Non liner quantize formula is explained as following.
+
+    y=f(x)   = sign(x)*round( ((abs(x)/(2^7))^ r   )* 2^(bo-1) )*2^(8-bo)
+    x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
+ ( r:power coefficient  bi:effective MSB in input  bo:effective MSB in output )
+
+   r < 1.0 : Smaller value is more important than larger value.
+   r > 1.0 : Larger value is more important than smaller value.
+   r = 1.0 : Liner quantization which is same with EZW style.
+
+ r = 0.75 is famous non liner quantization used in MP3 audio codec.
+ In contrast to audio data, larger value is important in wavelet coefficients.
+ So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
+
+ As compared with EZW style liner quantization, this filter tended to be
+ more sharp edge and be more compression rate but be more blocking noise and be
+ less quality. Especially, the surface of graphic objects has distinguishable
+ noise in middle quality mode.
+
+ We need only quantized-dequantized(filtered) value rather than quantized value
+ itself because all values are packed or palette-lized in later ZRLE section.
+ This lead us not to need to modify client decoder when we change
+ the filtering procedure in future.
+ Client only decodes coefficients given by encoder.
+*/
+static inline void filter_wavelet_square(int *buf, int width, int height,
+                                         int level, int l)
+{
+    int r, s;
+    int x, y;
+    int *h;
+    const int8_t **m;
+
+    m = zywrle_param[level - 1][l];
+    s = 2 << l;
+
+    for (r = 1; r < 4; r++) {
+        h = buf;
+        if (r & 0x01) {
+            h += s >> 1;
+        }
+        if (r & 0x02) {
+            h += (s >> 1) * width;
+        }
+        for (y = 0; y < height / s; y++) {
+            for (x = 0; x < width / s; x++) {
+                ((int8_t*)h)[0] = m[0][((uint8_t*)h)[0]];
+                ((int8_t*)h)[1] = m[1][((uint8_t*)h)[1]];
+                ((int8_t*)h)[2] = m[2][((uint8_t*)h)[2]];
+                h += s;
+            }
+            h += (s - 1) * width;
+        }
+    }
+}
+#endif
+
+static inline void wavelet(int *buf, int width, int height, int level)
+{
+       int l, s;
+       int *top;
+       int *end;
+
+       for (l = 0; l < level; l++) {
+               top = buf;
+               end = buf + height * width;
+               s = width << l;
+               while (top < end) {
+                       wavelet_level(top, width, l, 1);
+                       top += s;
+               }
+               top = buf;
+               end = buf + width;
+               s = 1<<l;
+               while (top < end) {
+                       wavelet_level(top, height, l, width);
+                       top += s;
+               }
+               filter_wavelet_square(buf, width, height, level, l);
+       }
+}
+
+
+/* Load/Save coefficients stuffs.
+ Coefficients manages as 24 bits little-endian pixel. */
+#define ZYWRLE_LOAD_COEFF(src, r, g, b)         \
+    do {                                        \
+       r = ((int8_t*)src)[2];                  \
+       g = ((int8_t*)src)[1];                  \
+       b = ((int8_t*)src)[0];                  \
+    } while (0)
+
+#define ZYWRLE_SAVE_COEFF(dst, r, g, b)       \
+    do {                                      \
+       ((int8_t*)dst)[2] = (int8_t)r;        \
+       ((int8_t*)dst)[1] = (int8_t)g;        \
+       ((int8_t*)dst)[0] = (int8_t)b;        \
+    } while (0)
+
+/*
+  RGB <=> YUV conversion stuffs.
+  YUV coversion is explained as following formula in strict meaning:
+  Y =  0.299R + 0.587G + 0.114B (   0<=Y<=255)
+  U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
+  V =  0.500R - 0.419G - 0.081B (-128<=V<=127)
+
+  I use simple conversion RCT(reversible color transform) which is described
+  in JPEG-2000 specification.
+  Y = (R + 2G + B)/4 (   0<=Y<=255)
+  U = B-G (-256<=U<=255)
+  V = R-G (-256<=V<=255)
+*/
+
+/* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
+   For make Same N-bit, UV is lossy.
+   More exact PLHarr, we reduce to odd range(-127<=x<=127). */
+#define ZYWRLE_RGBYUV_(r, g, b, y, u, v, ymask, uvmask)          \
+    do {                                                         \
+       y = (r + (g << 1) + b) >> 2;                             \
+       u =  b - g;                                              \
+       v =  r - g;                                              \
+       y -= 128;                                                \
+       u >>= 1;                                                 \
+       v >>= 1;                                                 \
+       y &= ymask;                                              \
+       u &= uvmask;                                             \
+       v &= uvmask;                                             \
+       if (y == -128) {                                         \
+            y += (0xFFFFFFFF - ymask + 1);                       \
+        }                                                        \
+       if (u == -128) {                                         \
+            u += (0xFFFFFFFF - uvmask + 1);                      \
+        }                                                        \
+       if (v == -128) {                                         \
+            v += (0xFFFFFFFF - uvmask + 1);                      \
+        }                                                        \
+    } while (0)
+
+
+/*
+ coefficient packing/unpacking stuffs.
+ Wavelet transform makes 4 sub coefficient image from 1 original image.
+
+ model with pyramid decomposition:
+   +------+------+
+   |      |      |
+   |  L   |  Hx  |
+   |      |      |
+   +------+------+
+   |      |      |
+   |  H   |  Hxy |
+   |      |      |
+   +------+------+
+
+ So, we must transfer each sub images individually in strict meaning.
+ But at least ZRLE meaning, following one decompositon image is same as
+ avobe individual sub image. I use this format.
+ (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
+  for simplified procedure for any wavelet level.)
+
+   +------+------+
+   |      L      |
+   +------+------+
+   |      Hx     |
+   +------+------+
+   |      Hy     |
+   +------+------+
+   |      Hxy    |
+   +------+------+
+*/
+#define ZYWRLE_INC_PTR(data)                         \
+    do {                                             \
+        data++;                                      \
+        if( data - p >= (w + uw) ) {                 \
+            data += scanline-(w + uw);               \
+            p = data;                                \
+        }                                            \
+    } while (0)
+
+#define ZYWRLE_TRANSFER_COEFF(buf, data, t, w, h, scanline, level, TRANS) \
+    do {                                                                \
+        ph = buf;                                                       \
+        s = 2 << level;                                                 \
+        if (t & 0x01) {                                                 \
+            ph += s >> 1;                                               \
+        }                                                               \
+        if (t & 0x02) {                                                 \
+            ph += (s >> 1) * w;                                         \
+        }                                                               \
+        end = ph + h * w;                                               \
+        while (ph < end) {                                              \
+            line = ph + w;                                              \
+            while (ph < line) {                                         \
+                TRANS                                                   \
+                    ZYWRLE_INC_PTR(data);                               \
+                ph += s;                                                \
+            }                                                           \
+            ph += (s - 1) * w;                                          \
+        }                                                               \
+    } while (0)
+
+#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level)        \
+    ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
+                          ZYWRLE_LOAD_COEFF(ph, r, g, b);               \
+                          ZYWRLE_SAVE_PIXEL(data, r, g, b);)
+
+#define ZYWRLE_UNPACK_COEFF(buf, data, t, width, height, scanline, level) \
+    ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
+                          ZYWRLE_LOAD_PIXEL(data, r, g, b);             \
+                          ZYWRLE_SAVE_COEFF(ph, r, g, b);)
+
+#define ZYWRLE_SAVE_UNALIGN(data, TRANS)                     \
+    do {                                                     \
+        top = buf + w * h;                                   \
+        end = buf + (w + uw) * (h + uh);                     \
+        while (top < end) {                                  \
+            TRANS                                            \
+                ZYWRLE_INC_PTR(data);                        \
+                top++;                                       \
+        }                                                    \
+    } while (0)
+
+#define ZYWRLE_LOAD_UNALIGN(data,TRANS)                                 \
+    do {                                                                \
+        top = buf + w * h;                                              \
+        if (uw) {                                                       \
+            p = data + w;                                               \
+            end = (int*)(p + h * scanline);                             \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + uw);                                  \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline - uw;                                     \
+            }                                                           \
+        }                                                               \
+        if (uh) {                                                       \
+            p = data + h * scanline;                                    \
+            end = (int*)(p + uh * scanline);                            \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + w);                                   \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline - w;                                      \
+            }                                                           \
+        }                                                               \
+        if (uw && uh) {                                                 \
+            p= data + w + h * scanline;                                 \
+            end = (int*)(p + uh * scanline);                            \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + uw);                                  \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline-uw;                                       \
+            }                                                           \
+        }                                                               \
+    } while (0)
+
+static inline void zywrle_calc_size(int *w, int *h, int level)
+{
+    *w &= ~((1 << level) - 1);
+    *h &= ~((1 << level) - 1);
+}
+
+#endif
index 0b5d750f268eb4ec6878eda99d6d384a95c70c6b..de5ea6b5d8100fe1905472fdc6795b59069efaf6 100644 (file)
@@ -77,7 +77,7 @@ static void vnc_unlock_queue(VncJobQueue *queue)
 
 VncJob *vnc_job_new(VncState *vs)
 {
-    VncJob *job = qemu_mallocz(sizeof(VncJob));
+    VncJob *job = g_malloc0(sizeof(VncJob));
 
     job->vs = vs;
     vnc_lock_queue(queue);
@@ -88,7 +88,7 @@ VncJob *vnc_job_new(VncState *vs)
 
 int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
 {
-    VncRectEntry *entry = qemu_mallocz(sizeof(VncRectEntry));
+    VncRectEntry *entry = g_malloc0(sizeof(VncRectEntry));
 
     entry->rect.x = x;
     entry->rect.y = y;
@@ -105,7 +105,7 @@ void vnc_job_push(VncJob *job)
 {
     vnc_lock_queue(queue);
     if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
-        qemu_free(job);
+        g_free(job);
     } else {
         QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
         qemu_cond_broadcast(&queue->cond);
@@ -166,11 +166,13 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
     local->features = orig->features;
     local->ds = orig->ds;
     local->vd = orig->vd;
+    local->lossy_rect = orig->lossy_rect;
     local->write_pixels = orig->write_pixels;
     local->clientds = orig->clientds;
     local->tight = orig->tight;
     local->zlib = orig->zlib;
     local->hextile = orig->hextile;
+    local->zrle = orig->zrle;
     local->output =  queue->buffer;
     local->csock = -1; /* Don't do any network work on this thread */
 
@@ -182,6 +184,10 @@ static void vnc_async_encoding_end(VncState *orig, VncState *local)
     orig->tight = local->tight;
     orig->zlib = local->zlib;
     orig->hextile = local->hextile;
+    orig->zrle = local->zrle;
+    orig->lossy_rect = local->lossy_rect;
+
+    queue->buffer = local->output;
 }
 
 static int vnc_worker_thread_loop(VncJobQueue *queue)
@@ -240,7 +246,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
         if (n >= 0) {
             n_rectangles += n;
         }
-        qemu_free(entry);
+        g_free(entry);
     }
     vnc_unlock_display(job->vs->vd);
 
@@ -270,13 +276,13 @@ disconnected:
     QTAILQ_REMOVE(&queue->jobs, job, next);
     vnc_unlock_queue(queue);
     qemu_cond_broadcast(&queue->cond);
-    qemu_free(job);
+    g_free(job);
     return 0;
 }
 
 static VncJobQueue *vnc_queue_init(void)
 {
-    VncJobQueue *queue = qemu_mallocz(sizeof(VncJobQueue));
+    VncJobQueue *queue = g_malloc0(sizeof(VncJobQueue));
 
     qemu_cond_init(&queue->cond);
     qemu_mutex_init(&queue->mutex);
@@ -289,7 +295,7 @@ static void vnc_queue_clear(VncJobQueue *q)
     qemu_cond_destroy(&queue->cond);
     qemu_mutex_destroy(&queue->mutex);
     buffer_free(&queue->buffer);
-    qemu_free(q);
+    g_free(q);
     queue = NULL; /* Unset global queue */
 }
 
@@ -297,7 +303,7 @@ static void *vnc_worker_thread(void *arg)
 {
     VncJobQueue *queue = arg;
 
-    qemu_thread_self(&queue->thread);
+    qemu_thread_get_self(&queue->thread);
 
     while (!vnc_worker_thread_loop(queue)) ;
     vnc_queue_clear(queue);
index bff6445cc18c5343cb0ca8f1d45c92857940a9ac..63d5f64917d7cb5580768dc650b040ef3e09002b 100644 (file)
@@ -55,31 +55,21 @@ VncPalette *palette_new(size_t max, int bpp)
 {
     VncPalette *palette;
 
-    palette = qemu_mallocz(sizeof(*palette));
+    palette = g_malloc0(sizeof(*palette));
+    palette_init(palette, max, bpp);
+    return palette;
+}
+
+void palette_init(VncPalette *palette, size_t max, int bpp)
+{
+    memset(palette, 0, sizeof (*palette));
     palette->max = max;
     palette->bpp = bpp;
-    return palette;
 }
 
 void palette_destroy(VncPalette *palette)
 {
-    int i;
-
-    if (palette == NULL) {
-        return ;
-    }
-
-    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
-        VncPaletteEntry *entry = QLIST_FIRST(&palette->table[i]);
-        while (entry) {
-            VncPaletteEntry *tmp = QLIST_NEXT(entry, next);
-            QLIST_REMOVE(entry, next);
-            qemu_free(entry);
-            entry = tmp;
-        }
-    }
-
-    qemu_free(palette);
+    g_free(palette);
 }
 
 int palette_put(VncPalette *palette, uint32_t color)
@@ -97,7 +87,7 @@ int palette_put(VncPalette *palette, uint32_t color)
     if (!entry) {
         VncPaletteEntry *entry;
 
-        entry = qemu_mallocz(sizeof(*entry));
+        entry = &palette->pool[palette->size];
         entry->color = color;
         entry->idx = idx;
         QLIST_INSERT_HEAD(&palette->table[hash], entry, next);
@@ -134,3 +124,35 @@ void palette_iter(const VncPalette *palette,
         }
     }
 }
+
+uint32_t palette_color(const VncPalette *palette, int idx, bool *found)
+{
+    int i;
+    VncPaletteEntry *entry;
+
+    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
+        QLIST_FOREACH(entry, &palette->table[i], next) {
+            if (entry->idx == idx) {
+                *found = true;
+                return entry->color;
+            }
+        }
+    }
+
+    *found = false;
+    return -1;
+}
+
+static void palette_fill_cb(int idx, uint32_t color, void *opaque)
+{
+    uint32_t *colors = opaque;
+
+    colors[idx] = color;
+}
+
+size_t palette_fill(const VncPalette *palette,
+                    uint32_t colors[VNC_PALETTE_MAX_SIZE])
+{
+    palette_iter(palette, palette_fill_cb, colors);
+    return palette_size(palette);
+}
index d0645ebde85a486c343db8fe74006355c32b032d..3260885ff0d866f6eab9a115a1a1f040e0f0f94f 100644 (file)
@@ -34,6 +34,7 @@
 #include <stdint.h>
 
 #define VNC_PALETTE_HASH_SIZE 256
+#define VNC_PALETTE_MAX_SIZE  256
 
 typedef struct VncPaletteEntry {
     int idx;
@@ -42,7 +43,7 @@ typedef struct VncPaletteEntry {
 } VncPaletteEntry;
 
 typedef struct VncPalette {
-    QObject_HEAD;
+    VncPaletteEntry pool[VNC_PALETTE_MAX_SIZE];
     size_t size;
     size_t max;
     int bpp;
@@ -50,6 +51,7 @@ typedef struct VncPalette {
 } VncPalette;
 
 VncPalette *palette_new(size_t max, int bpp);
+void palette_init(VncPalette *palette, size_t max, int bpp);
 void palette_destroy(VncPalette *palette);
 
 int palette_put(VncPalette *palette, uint32_t color);
@@ -59,5 +61,8 @@ size_t palette_size(const VncPalette *palette);
 void palette_iter(const VncPalette *palette,
                   void (*iter)(int idx, uint32_t color, void *opaque),
                   void *opaque);
+uint32_t palette_color(const VncPalette *palette, int idx, bool *found);
+size_t palette_fill(const VncPalette *palette,
+                    uint32_t colors[VNC_PALETTE_MAX_SIZE]);
 
 #endif /* VNC_PALETTE_H */
index dec626c539c51fc8788410447325e58ebc40848a..3aaa93928ad59fe8034d50fd3b1ea9c26034ce30 100644 (file)
@@ -89,7 +89,7 @@ static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
     int ret;
 
  retry:
-    ret = recv(vs->csock, data, len, 0);
+    ret = qemu_recv(vs->csock, data, len, 0);
     if (ret < 0) {
         if (errno == EINTR)
             goto retry;
@@ -244,11 +244,11 @@ int vnc_tls_validate_certificate(struct VncState *vs)
 
         if (i == 0) {
             size_t dnameSize = 1024;
-            vs->tls.dname = qemu_malloc(dnameSize);
+            vs->tls.dname = g_malloc(dnameSize);
         requery:
             if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
                 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
-                    vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
+                    vs->tls.dname = g_realloc(vs->tls.dname, dnameSize);
                     goto requery;
                 }
                 gnutls_x509_crt_deinit (cert);
@@ -283,13 +283,57 @@ int vnc_tls_validate_certificate(struct VncState *vs)
     return 0;
 }
 
+#if defined(GNUTLS_VERSION_NUMBER) && \
+    GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
+    int rc;
+
+    rc = gnutls_priority_set_direct(s, priority, NULL);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#else
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocols[] = {
+        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
+    };
+    static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
+    static const int kx_x509[] = {
+        GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
+        GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
+    };
+    int rc;
+
+    rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_certificate_type_set_priority(s, cert_types);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_protocol_set_priority(s, protocols);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#endif
 
 int vnc_tls_client_setup(struct VncState *vs,
                          int needX509Creds) {
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
 
     VNC_DEBUG("Do TLS setup\n");
     if (vnc_tls_initialize() < 0) {
@@ -310,21 +354,7 @@ int vnc_tls_client_setup(struct VncState *vs,
             return -1;
         }
 
-        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
+        if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
             gnutls_deinit(vs->tls.session);
             vs->tls.session = NULL;
             vnc_client_error(vs);
@@ -383,7 +413,7 @@ void vnc_tls_client_cleanup(struct VncState *vs)
         vs->tls.session = NULL;
     }
     vs->tls.wiremode = VNC_WIREMODE_CLEAR;
-    free(vs->tls.dname);
+    g_free(vs->tls.dname);
 }
 
 
@@ -397,11 +427,11 @@ static int vnc_set_x509_credential(VncDisplay *vd,
     struct stat sb;
 
     if (*cred) {
-        qemu_free(*cred);
+        g_free(*cred);
         *cred = NULL;
     }
 
-    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
+    *cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
 
     strcpy(*cred, certdir);
     strcat(*cred, "/");
@@ -409,7 +439,7 @@ static int vnc_set_x509_credential(VncDisplay *vd,
 
     VNC_DEBUG("Check %s\n", *cred);
     if (stat(*cred, &sb) < 0) {
-        qemu_free(*cred);
+        g_free(*cred);
         *cred = NULL;
         if (ignoreMissing && errno == ENOENT)
             return 0;
@@ -435,10 +465,10 @@ int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
     return 0;
 
  cleanup:
-    qemu_free(vd->tls.x509cacert);
-    qemu_free(vd->tls.x509cacrl);
-    qemu_free(vd->tls.x509cert);
-    qemu_free(vd->tls.x509key);
+    g_free(vd->tls.x509cacert);
+    g_free(vd->tls.x509cacrl);
+    g_free(vd->tls.x509cert);
+    g_free(vd->tls.x509key);
     vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
     return -1;
 }
index b6b74afaa0ef4760a6f5263e99a807c7b899aca2..40018f70f1bc5b3139e4d11d4e891211f6a5bc5c 100644 (file)
--- a/ui/vnc.c
+++ b/ui/vnc.c
 #include "qemu-timer.h"
 #include "acl.h"
 #include "qemu-objects.h"
+#include "qmp-commands.h"
 
 #define VNC_REFRESH_INTERVAL_BASE 30
 #define VNC_REFRESH_INTERVAL_INC  50
 #define VNC_REFRESH_INTERVAL_MAX  2000
+static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
+static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
 
 #include "vnc_keysym.h"
 #include "d3des.h"
 
-#define count_bits(c, v) { \
-    for (c = 0; v; v >>= 1) \
-    { \
-        c += v & 1; \
-    } \
-}
-
 static VncDisplay *vnc_display; /* needed for info vnc */
 static DisplayChangeListener *dcl;
 
@@ -72,7 +68,7 @@ static char *addr_to_string(const char *format,
     /* Enough for the existing format + the 2 vars we're
      * substituting in. */
     addrlen = strlen(format) + strlen(host) + strlen(serv);
-    addr = qemu_malloc(addrlen + 1);
+    addr = g_malloc(addrlen + 1);
     snprintf(addr, addrlen, format, host, serv);
     addr[addrlen] = '\0';
 
@@ -279,80 +275,110 @@ static void vnc_qmp_event(VncState *vs, MonitorEvent event)
     qobject_decref(data);
 }
 
-static void info_vnc_iter(QObject *obj, void *opaque)
+static VncClientInfo *qmp_query_vnc_client(const VncState *client)
 {
-    QDict *client;
-    Monitor *mon = opaque;
+    struct sockaddr_storage sa;
+    socklen_t salen = sizeof(sa);
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    VncClientInfo *info;
+
+    if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
+        return NULL;
+    }
+
+    if (getnameinfo((struct sockaddr *)&sa, salen,
+                    host, sizeof(host),
+                    serv, sizeof(serv),
+                    NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+        return NULL;
+    }
 
-    client = qobject_to_qdict(obj);
-    monitor_printf(mon, "Client:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(client, "host"),
-                   qdict_get_str(client, "service"));
+    info = g_malloc0(sizeof(*info));
+    info->host = g_strdup(host);
+    info->service = g_strdup(serv);
+    info->family = g_strdup(inet_strfamily(sa.ss_family));
 
 #ifdef CONFIG_VNC_TLS
-    monitor_printf(mon, "  x509_dname: %s\n",
-        qdict_haskey(client, "x509_dname") ?
-        qdict_get_str(client, "x509_dname") : "none");
+    if (client->tls.session && client->tls.dname) {
+        info->has_x509_dname = true;
+        info->x509_dname = g_strdup(client->tls.dname);
+    }
 #endif
 #ifdef CONFIG_VNC_SASL
-    monitor_printf(mon, "    username: %s\n",
-        qdict_haskey(client, "sasl_username") ?
-        qdict_get_str(client, "sasl_username") : "none");
-#endif
-}
-
-void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
-    QDict *server;
-    QList *clients;
-
-    server = qobject_to_qdict(data);
-    if (qdict_get_bool(server, "enabled") == 0) {
-        monitor_printf(mon, "Server: disabled\n");
-        return;
+    if (client->sasl.conn && client->sasl.username) {
+        info->has_sasl_username = true;
+        info->sasl_username = g_strdup(client->sasl.username);
     }
+#endif
 
-    monitor_printf(mon, "Server:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(server, "host"),
-                   qdict_get_str(server, "service"));
-    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
-
-    clients = qdict_get_qlist(server, "clients");
-    if (qlist_empty(clients)) {
-        monitor_printf(mon, "Client: none\n");
-    } else {
-        qlist_iter(clients, info_vnc_iter, mon);
-    }
+    return info;
 }
 
-void do_info_vnc(Monitor *mon, QObject **ret_data)
+VncInfo *qmp_query_vnc(Error **errp)
 {
+    VncInfo *info = g_malloc0(sizeof(*info));
+
     if (vnc_display == NULL || vnc_display->display == NULL) {
-        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+        info->enabled = false;
     } else {
-        QList *clist;
+        VncClientInfoList *cur_item = NULL;
+        struct sockaddr_storage sa;
+        socklen_t salen = sizeof(sa);
+        char host[NI_MAXHOST];
+        char serv[NI_MAXSERV];
         VncState *client;
 
-        clist = qlist_new();
+        info->enabled = true;
+
+        /* for compatibility with the original command */
+        info->has_clients = true;
+
         QTAILQ_FOREACH(client, &vnc_display->clients, next) {
-            if (client->info) {
-                /* incref so that it's not freed by upper layers */
-                qobject_incref(client->info);
-                qlist_append_obj(clist, client->info);
+            VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
+            cinfo->value = qmp_query_vnc_client(client);
+
+            /* XXX: waiting for the qapi to support GSList */
+            if (!cur_item) {
+                info->clients = cur_item = cinfo;
+            } else {
+                cur_item->next = cinfo;
+                cur_item = cinfo;
             }
         }
 
-        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
-                                       QOBJECT(clist));
-        assert(*ret_data != NULL);
+        if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
+                        &salen) == -1) {
+            error_set(errp, QERR_UNDEFINED_ERROR);
+            goto out_error;
+        }
 
-        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
-            qobject_decref(*ret_data);
-            *ret_data = NULL;
+        if (getnameinfo((struct sockaddr *)&sa, salen,
+                        host, sizeof(host),
+                        serv, sizeof(serv),
+                        NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+            error_set(errp, QERR_UNDEFINED_ERROR);
+            goto out_error;
         }
+
+        info->has_host = true;
+        info->host = g_strdup(host);
+
+        info->has_service = true;
+        info->service = g_strdup(serv);
+
+        info->has_family = true;
+        info->family = g_strdup(inet_strfamily(sa.ss_family));
+
+        info->has_auth = true;
+        info->auth = g_strdup(vnc_auth_name(vnc_display));
     }
+
+    return info;
+
+out_error:
+    qapi_free_VncInfo(info);
+    return NULL;
 }
 
 /* TODO
@@ -376,47 +402,6 @@ static void framebuffer_update_request(VncState *vs, int incremental,
 static void vnc_refresh(void *opaque);
 static int vnc_refresh_server_surface(VncDisplay *vd);
 
-static inline void vnc_set_bit(uint32_t *d, int k)
-{
-    d[k >> 5] |= 1 << (k & 0x1f);
-}
-
-static inline void vnc_clear_bit(uint32_t *d, int k)
-{
-    d[k >> 5] &= ~(1 << (k & 0x1f));
-}
-
-static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
-{
-    int j;
-
-    j = 0;
-    while (n >= 32) {
-        d[j++] = -1;
-        n -= 32;
-    }
-    if (n > 0)
-        d[j++] = (1 << n) - 1;
-    while (j < nb_words)
-        d[j++] = 0;
-}
-
-static inline int vnc_get_bit(const uint32_t *d, int k)
-{
-    return (d[k >> 5] >> (k & 0x1f)) & 1;
-}
-
-static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
-                               int nb_words)
-{
-    int i;
-    for(i = 0; i < nb_words; i++) {
-        if ((d1[i] & d2[i]) != 0)
-            return 1;
-    }
-    return 0;
-}
-
 static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 {
     int i;
@@ -439,7 +424,7 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 
     for (; y < h; y++)
         for (i = 0; i < w; i += 16)
-            vnc_set_bit(s->dirty[y], (x + i) / 16);
+            set_bit((x + i) / 16, s->dirty[y]);
 }
 
 void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
@@ -457,7 +442,7 @@ void buffer_reserve(Buffer *buffer, size_t len)
 {
     if ((buffer->capacity - buffer->offset) < len) {
         buffer->capacity += (len + 1024);
-        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
         if (buffer->buffer == NULL) {
             fprintf(stderr, "vnc: out of memory\n");
             exit(1);
@@ -482,7 +467,7 @@ void buffer_reset(Buffer *buffer)
 
 void buffer_free(Buffer *buffer)
 {
-    qemu_free(buffer->buffer);
+    g_free(buffer->buffer);
     buffer->offset = 0;
     buffer->capacity = 0;
     buffer->buffer = NULL;
@@ -551,16 +536,16 @@ static void vnc_dpy_resize(DisplayState *ds)
 
     /* server surface */
     if (!vd->server)
-        vd->server = qemu_mallocz(sizeof(*vd->server));
+        vd->server = g_malloc0(sizeof(*vd->server));
     if (vd->server->data)
-        qemu_free(vd->server->data);
+        g_free(vd->server->data);
     *(vd->server) = *(ds->surface);
-    vd->server->data = qemu_mallocz(vd->server->linesize *
+    vd->server->data = g_malloc0(vd->server->linesize *
                                     vd->server->height);
 
     /* guest surface */
     if (!vd->guest.ds)
-        vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
+        vd->guest.ds = g_malloc0(sizeof(*vd->guest.ds));
     if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
         console_color_init(ds);
     *(vd->guest.ds) = *(ds->surface);
@@ -577,7 +562,7 @@ static void vnc_dpy_resize(DisplayState *ds)
 }
 
 /* fastest code */
-static void vnc_write_pixels_copy(VncState *vs, struct QEMU_PixelFormat *pf,
+static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
                                   void *pixels, int size)
 {
     vnc_write(vs, pixels, size);
@@ -628,7 +613,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
     }
 }
 
-static void vnc_write_pixels_generic(VncState *vs, struct QEMU_PixelFormat *pf,
+static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
                                      void *pixels1, int size)
 {
     uint8_t buf[4];
@@ -694,6 +679,12 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
         case VNC_ENCODING_TIGHT_PNG:
             n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
             break;
+        case VNC_ENCODING_ZRLE:
+            n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_ZYWRLE:
+            n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
+            break;
         default:
             vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
             n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -772,7 +763,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
             memmove(dst_row, src_row, cmp_bytes);
             QTAILQ_FOREACH(vs, &vd->clients, next) {
                 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-                    vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
+                    set_bit(((x + dst_x) / 16), vs->dirty[y]);
                 }
             }
         }
@@ -821,12 +812,12 @@ static void vnc_dpy_cursor_define(QEMUCursor *c)
     VncState *vs;
 
     cursor_put(vd->cursor);
-    qemu_free(vd->cursor_mask);
+    g_free(vd->cursor_mask);
 
     vd->cursor = c;
     cursor_get(vd->cursor);
     vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
-    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
+    vd->cursor_mask = g_malloc0(vd->cursor_msize);
     cursor_get_mono_mask(c, 0, vd->cursor_mask);
 
     QTAILQ_FOREACH(vs, &vd->clients, next) {
@@ -835,17 +826,18 @@ static void vnc_dpy_cursor_define(QEMUCursor *c)
 }
 
 static int find_and_clear_dirty_height(struct VncState *vs,
-                                       int y, int last_x, int x)
+                                       int y, int last_x, int x, int height)
 {
     int h;
-    VncDisplay *vd = vs->vd;
 
-    for (h = 1; h < (vd->server->height - y); h++) {
+    for (h = 1; h < (height - y); h++) {
         int tmp_x;
-        if (!vnc_get_bit(vs->dirty[y + h], last_x))
+        if (!test_bit(last_x, vs->dirty[y + h])) {
             break;
-        for (tmp_x = last_x; tmp_x < x; tmp_x++)
-            vnc_clear_bit(vs->dirty[y + h], tmp_x);
+        }
+        for (tmp_x = last_x; tmp_x < x; tmp_x++) {
+            clear_bit(tmp_x, vs->dirty[y + h]);
+        }
     }
 
     return h;
@@ -897,14 +889,14 @@ static int vnc_update_client(VncState *vs, int has_dirty)
             int x;
             int last_x = -1;
             for (x = 0; x < width / 16; x++) {
-                if (vnc_get_bit(vs->dirty[y], x)) {
+                if (test_and_clear_bit(x, vs->dirty[y])) {
                     if (last_x == -1) {
                         last_x = x;
                     }
-                    vnc_clear_bit(vs->dirty[y], x);
                 } else {
                     if (last_x != -1) {
-                        int h = find_and_clear_dirty_height(vs, y, last_x, x);
+                        int h = find_and_clear_dirty_height(vs, y, last_x, x,
+                                                            height);
 
                         n += vnc_job_add_rect(job, last_x * 16, y,
                                               (x - last_x) * 16, h);
@@ -913,7 +905,7 @@ static int vnc_update_client(VncState *vs, int has_dirty)
                 }
             }
             if (last_x != -1) {
-                int h = find_and_clear_dirty_height(vs, y, last_x, x);
+                int h = find_and_clear_dirty_height(vs, y, last_x, x, height);
                 n += vnc_job_add_rect(job, last_x * 16, y,
                                       (x - last_x) * 16, h);
             }
@@ -1012,6 +1004,8 @@ static void vnc_disconnect_start(VncState *vs)
 
 static void vnc_disconnect_finish(VncState *vs)
 {
+    int i;
+
     vnc_jobs_join(vs); /* Wait encoding jobs */
 
     vnc_lock_output(vs);
@@ -1024,6 +1018,7 @@ static void vnc_disconnect_finish(VncState *vs)
 
     vnc_zlib_clear(vs);
     vnc_tight_clear(vs);
+    vnc_zrle_clear(vs);
 
 #ifdef CONFIG_VNC_TLS
     vnc_tls_client_cleanup(vs);
@@ -1048,7 +1043,11 @@ static void vnc_disconnect_finish(VncState *vs)
 #ifdef CONFIG_VNC_THREAD
     qemu_mutex_destroy(&vs->output_mutex);
 #endif
-    qemu_free(vs);
+    for (i = 0; i < VNC_STAT_ROWS; ++i) {
+        g_free(vs->lossy_rect[i]);
+    }
+    g_free(vs->lossy_rect);
+    g_free(vs);
 }
 
 int vnc_client_io_error(VncState *vs, int ret, int last_errno)
@@ -1231,7 +1230,7 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
         }
     } else
 #endif /* CONFIG_VNC_TLS */
-        ret = recv(vs->csock, (void *)data, datalen, 0);
+        ret = qemu_recv(vs->csock, data, datalen, 0);
     VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
     return vnc_client_io_error(vs, ret, socket_error());
 }
@@ -1378,7 +1377,7 @@ static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
 {
 }
 
-static void check_pointer_type_change(Notifier *notifier)
+static void check_pointer_type_change(Notifier *notifier, void *data)
 {
     VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
     int absolute = kbd_mouse_is_absolute();
@@ -1677,18 +1676,21 @@ static void framebuffer_update_request(VncState *vs, int incremental,
                                        int x_position, int y_position,
                                        int w, int h)
 {
+    int i;
+    const size_t width = ds_get_width(vs->ds) / 16;
+
     if (y_position > ds_get_height(vs->ds))
         y_position = ds_get_height(vs->ds);
     if (y_position + h >= ds_get_height(vs->ds))
         h = ds_get_height(vs->ds) - y_position;
 
-    int i;
     vs->need_update = 1;
     if (!incremental) {
         vs->force_update = 1;
         for (i = 0; i < h; i++) {
-            vnc_set_bits(vs->dirty[y_position + i],
-                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+            bitmap_set(vs->dirty[y_position + i], 0, width);
+            bitmap_clear(vs->dirty[y_position + i], width,
+                         VNC_DIRTY_BITS - width);
         }
     }
 }
@@ -1758,6 +1760,14 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             vs->features |= VNC_FEATURE_ZLIB_MASK;
             vs->vnc_encoding = enc;
             break;
+        case VNC_ENCODING_ZRLE:
+            vs->features |= VNC_FEATURE_ZRLE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZYWRLE:
+            vs->features |= VNC_FEATURE_ZYWRLE_MASK;
+            vs->vnc_encoding = enc;
+            break;
         case VNC_ENCODING_DESKTOPRESIZE:
             vs->features |= VNC_FEATURE_RESIZE_MASK;
             break;
@@ -1780,7 +1790,9 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             vs->tight.compression = (enc & 0x0F);
             break;
         case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
-            vs->tight.quality = (enc & 0x0F);
+            if (vs->vd->lossy) {
+                vs->tight.quality = (enc & 0x0F);
+            }
             break;
         default:
             VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
@@ -1788,7 +1800,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
         }
     }
     vnc_desktop_resize(vs);
-    check_pointer_type_change(&vs->mouse_mode_notifier);
+    check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
 }
 
 static void set_pixel_conversion(VncState *vs)
@@ -1817,15 +1829,15 @@ static void set_pixel_format(VncState *vs,
 
     vs->clientds = *(vs->vd->guest.ds);
     vs->clientds.pf.rmax = red_max;
-    count_bits(vs->clientds.pf.rbits, red_max);
+    vs->clientds.pf.rbits = hweight_long(red_max);
     vs->clientds.pf.rshift = red_shift;
     vs->clientds.pf.rmask = red_max << red_shift;
     vs->clientds.pf.gmax = green_max;
-    count_bits(vs->clientds.pf.gbits, green_max);
+    vs->clientds.pf.gbits = hweight_long(green_max);
     vs->clientds.pf.gshift = green_shift;
     vs->clientds.pf.gmask = green_max << green_shift;
     vs->clientds.pf.bmax = blue_max;
-    count_bits(vs->clientds.pf.bbits, blue_max);
+    vs->clientds.pf.bbits = hweight_long(blue_max);
     vs->clientds.pf.bshift = blue_shift;
     vs->clientds.pf.bmask = blue_max << blue_shift;
     vs->clientds.pf.bits_per_pixel = bits_per_pixel;
@@ -1898,8 +1910,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 
     if (data[0] > 3) {
         vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
-        if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
-            qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
+        if (!qemu_timer_expired(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval))
+            qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
     }
 
     switch (data[0]) {
@@ -2143,7 +2155,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 {
     /* We only advertise 1 auth scheme at a time, so client
      * must pick the one we sent. Verify this */
-    if (data[0] != vs->vd->auth) { /* Reject auth */
+    if (data[0] != vs->auth) { /* Reject auth */
        VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
        vnc_write_u32(vs, 1);
        if (vs->minor >= 8) {
@@ -2154,7 +2166,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
        vnc_client_error(vs);
     } else { /* Accept requested auth */
        VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
-       switch (vs->vd->auth) {
+       switch (vs->auth) {
        case VNC_AUTH_NONE:
            VNC_DEBUG("Accept auth none\n");
            if (vs->minor >= 8) {
@@ -2184,7 +2196,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 #endif /* CONFIG_VNC_SASL */
 
        default: /* Should not be possible, but just in case */
-           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
            vnc_write_u8(vs, 1);
            if (vs->minor >= 8) {
                static const char err[] = "Authentication failed";
@@ -2229,26 +2241,26 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
         vs->minor = 3;
 
     if (vs->minor == 3) {
-        if (vs->vd->auth == VNC_AUTH_NONE) {
+        if (vs->auth == VNC_AUTH_NONE) {
             VNC_DEBUG("Tell client auth none\n");
-            vnc_write_u32(vs, vs->vd->auth);
+            vnc_write_u32(vs, vs->auth);
             vnc_flush(vs);
             start_client_init(vs);
-       } else if (vs->vd->auth == VNC_AUTH_VNC) {
+       } else if (vs->auth == VNC_AUTH_VNC) {
             VNC_DEBUG("Tell client VNC auth\n");
-            vnc_write_u32(vs, vs->vd->auth);
+            vnc_write_u32(vs, vs->auth);
             vnc_flush(vs);
             start_auth_vnc(vs);
        } else {
-            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
             vnc_write_u32(vs, VNC_AUTH_INVALID);
             vnc_flush(vs);
             vnc_client_error(vs);
        }
     } else {
-        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
+        VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
         vnc_write_u8(vs, 1); /* num auth */
-        vnc_write_u8(vs, vs->vd->auth);
+        vnc_write_u8(vs, vs->auth);
         vnc_read_when(vs, protocol_client_auth, 1);
         vnc_flush(vs);
     }
@@ -2256,27 +2268,176 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
     return 0;
 }
 
+static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
+{
+    struct VncSurface *vs = &vd->guest;
+
+    return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
+}
+
+void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
+{
+    int i, j;
+
+    w = (x + w) / VNC_STAT_RECT;
+    h = (y + h) / VNC_STAT_RECT;
+    x /= VNC_STAT_RECT;
+    y /= VNC_STAT_RECT;
+
+    for (j = y; j <= h; j++) {
+        for (i = x; i <= w; i++) {
+            vs->lossy_rect[j][i] = 1;
+        }
+    }
+}
+
+static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
+{
+    VncState *vs;
+    int sty = y / VNC_STAT_RECT;
+    int stx = x / VNC_STAT_RECT;
+    int has_dirty = 0;
+
+    y = y / VNC_STAT_RECT * VNC_STAT_RECT;
+    x = x / VNC_STAT_RECT * VNC_STAT_RECT;
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        int j;
+
+        /* kernel send buffers are full -> refresh later */
+        if (vs->output.offset) {
+            continue;
+        }
+
+        if (!vs->lossy_rect[sty][stx]) {
+            continue;
+        }
+
+        vs->lossy_rect[sty][stx] = 0;
+        for (j = 0; j < VNC_STAT_RECT; ++j) {
+            bitmap_set(vs->dirty[y + j], x / 16, VNC_STAT_RECT / 16);
+        }
+        has_dirty++;
+    }
+
+    return has_dirty;
+}
+
+static int vnc_update_stats(VncDisplay *vd,  struct timeval * tv)
+{
+    int x, y;
+    struct timeval res;
+    int has_dirty = 0;
+
+    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
+        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+            VncRectStat *rect = vnc_stat_rect(vd, x, y);
+
+            rect->updated = false;
+        }
+    }
+
+    qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
+
+    if (timercmp(&vd->guest.last_freq_check, &res, >)) {
+        return has_dirty;
+    }
+    vd->guest.last_freq_check = *tv;
+
+    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
+        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+            VncRectStat *rect= vnc_stat_rect(vd, x, y);
+            int count = ARRAY_SIZE(rect->times);
+            struct timeval min, max;
+
+            if (!timerisset(&rect->times[count - 1])) {
+                continue ;
+            }
+
+            max = rect->times[(rect->idx + count - 1) % count];
+            qemu_timersub(tv, &max, &res);
+
+            if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
+                rect->freq = 0;
+                has_dirty += vnc_refresh_lossy_rect(vd, x, y);
+                memset(rect->times, 0, sizeof (rect->times));
+                continue ;
+            }
+
+            min = rect->times[rect->idx];
+            max = rect->times[(rect->idx + count - 1) % count];
+            qemu_timersub(&max, &min, &res);
+
+            rect->freq = res.tv_sec + res.tv_usec / 1000000.;
+            rect->freq /= count;
+            rect->freq = 1. / rect->freq;
+        }
+    }
+    return has_dirty;
+}
+
+double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
+{
+    int i, j;
+    double total = 0;
+    int num = 0;
+
+    x =  (x / VNC_STAT_RECT) * VNC_STAT_RECT;
+    y =  (y / VNC_STAT_RECT) * VNC_STAT_RECT;
+
+    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
+        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
+            total += vnc_stat_rect(vs->vd, i, j)->freq;
+            num++;
+        }
+    }
+
+    if (num) {
+        return total / num;
+    } else {
+        return 0;
+    }
+}
+
+static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
+{
+    VncRectStat *rect;
+
+    rect = vnc_stat_rect(vd, x, y);
+    if (rect->updated) {
+        return ;
+    }
+    rect->times[rect->idx] = *tv;
+    rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
+    rect->updated = true;
+}
+
 static int vnc_refresh_server_surface(VncDisplay *vd)
 {
     int y;
     uint8_t *guest_row;
     uint8_t *server_row;
     int cmp_bytes;
-    uint32_t width_mask[VNC_DIRTY_WORDS];
     VncState *vs;
     int has_dirty = 0;
 
+    struct timeval tv = { 0, 0 };
+
+    if (!vd->non_adaptive) {
+        gettimeofday(&tv, NULL);
+        has_dirty = vnc_update_stats(vd, &tv);
+    }
+
     /*
      * Walk through the guest dirty map.
      * Check and copy modified bits from guest to server surface.
      * Update server dirty map.
      */
-    vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
     cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
     guest_row  = vd->guest.ds->data;
     server_row = vd->server->data;
     for (y = 0; y < vd->guest.ds->height; y++) {
-        if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
+        if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) {
             int x;
             uint8_t *guest_ptr;
             uint8_t *server_ptr;
@@ -2286,14 +2447,15 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
 
             for (x = 0; x < vd->guest.ds->width;
                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
-                if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
+                if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
                     continue;
-                vnc_clear_bit(vd->guest.dirty[y], (x / 16));
                 if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
                     continue;
                 memcpy(server_ptr, guest_ptr, cmp_bytes);
+                if (!vd->non_adaptive)
+                    vnc_rect_updated(vd, x, y, &tv);
                 QTAILQ_FOREACH(vs, &vd->clients, next) {
-                    vnc_set_bit(vs->dirty[y], (x / 16));
+                    set_bit((x / 16), vs->dirty[y]);
                 }
                 has_dirty++;
             }
@@ -2314,7 +2476,7 @@ static void vnc_refresh(void *opaque)
 
     if (vnc_trylock_display(vd)) {
         vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
-        qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) +
+        qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) +
                        vd->timer_interval);
         return;
     }
@@ -2341,14 +2503,14 @@ static void vnc_refresh(void *opaque)
         if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
             vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
     }
-    qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
+    qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
 }
 
 static void vnc_init_timer(VncDisplay *vd)
 {
     vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
     if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) {
-        vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
+        vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd);
         vnc_dpy_resize(vd->ds);
         vnc_refresh(vd);
     }
@@ -2363,11 +2525,30 @@ static void vnc_remove_timer(VncDisplay *vd)
     }
 }
 
-static void vnc_connect(VncDisplay *vd, int csock)
+static void vnc_connect(VncDisplay *vd, int csock, int skipauth)
 {
-    VncState *vs = qemu_mallocz(sizeof(VncState));
+    VncState *vs = g_malloc0(sizeof(VncState));
+    int i;
+
     vs->csock = csock;
 
+    if (skipauth) {
+       vs->auth = VNC_AUTH_NONE;
+#ifdef CONFIG_VNC_TLS
+       vs->subauth = VNC_AUTH_INVALID;
+#endif
+    } else {
+       vs->auth = vd->auth;
+#ifdef CONFIG_VNC_TLS
+       vs->subauth = vd->subauth;
+#endif
+    }
+
+    vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
+    for (i = 0; i < VNC_STAT_ROWS; ++i) {
+        vs->lossy_rect[i] = g_malloc0(VNC_STAT_COLS * sizeof (uint8_t));
+    }
+
     VNC_DEBUG("New client on socket %d\n", csock);
     dcl->idle = 0;
     socket_set_nonblock(vs->csock);
@@ -2420,15 +2601,15 @@ static void vnc_listen_read(void *opaque)
 
     int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
     if (csock != -1) {
-        vnc_connect(vs, csock);
+        vnc_connect(vs, csock, 0);
     }
 }
 
 void vnc_display_init(DisplayState *ds)
 {
-    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
+    VncDisplay *vs = g_malloc0(sizeof(*vs));
 
-    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl = g_malloc0(sizeof(DisplayChangeListener));
 
     ds->opaque = vs;
     dcl->idle = 1;
@@ -2470,7 +2651,7 @@ void vnc_display_close(DisplayState *ds)
     if (!vs)
         return;
     if (vs->display) {
-        qemu_free(vs->display);
+        g_free(vs->display);
         vs->display = NULL;
     }
     if (vs->lsock != -1) {
@@ -2494,7 +2675,7 @@ int vnc_display_disable_login(DisplayState *ds)
     }
 
     if (vs->password) {
-        qemu_free(vs->password);
+        g_free(vs->password);
     }
 
     vs->password = NULL;
@@ -2505,26 +2686,32 @@ int vnc_display_disable_login(DisplayState *ds)
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
+    int ret = 0;
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
     if (!vs) {
-        return -1;
+        ret = -EINVAL;
+        goto out;
     }
 
     if (!password) {
         /* This is not the intention of this interface but err on the side
            of being safe */
-        return vnc_display_disable_login(ds);
+        ret = vnc_display_disable_login(ds);
+        goto out;
     }
 
     if (vs->password) {
-        qemu_free(vs->password);
+        g_free(vs->password);
         vs->password = NULL;
     }
-    vs->password = qemu_strdup(password);
+    vs->password = g_strdup(password);
     vs->auth = VNC_AUTH_VNC;
-
-    return 0;
+out:
+    if (ret != 0) {
+        qerror_report(QERR_SET_PASSWD_FAILED);
+    }
+    return ret;
 }
 
 int vnc_display_pw_expire(DisplayState *ds, time_t expires)
@@ -2597,20 +2784,20 @@ int vnc_display_open(DisplayState *ds, const char *display)
             end = strchr(options, ',');
             if (start && (!end || (start < end))) {
                 int len = end ? end-(start+1) : strlen(start+1);
-                char *path = qemu_strndup(start + 1, len);
+                char *path = g_strndup(start + 1, len);
 
                 VNC_DEBUG("Trying certificate path '%s'\n", path);
                 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
                     fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
-                    qemu_free(path);
-                    qemu_free(vs->display);
+                    g_free(path);
+                    g_free(vs->display);
                     vs->display = NULL;
                     return -1;
                 }
-                qemu_free(path);
+                g_free(path);
             } else {
                 fprintf(stderr, "No certificate path provided\n");
-                qemu_free(vs->display);
+                g_free(vs->display);
                 vs->display = NULL;
                 return -1;
             }
@@ -2621,6 +2808,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
 #endif
         } else if (strncmp(options, "lossy", 5) == 0) {
             vs->lossy = true;
+        } else if (strncmp(options, "non-adapative", 13) == 0) {
+            vs->non_adaptive = true;
         }
     }
 
@@ -2722,7 +2911,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
     if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
         fprintf(stderr, "Failed to initialize SASL auth %s",
                 sasl_errstring(saslErr, NULL, NULL));
-        free(vs->display);
+        g_free(vs->display);
         vs->display = NULL;
         return -1;
     }
@@ -2736,20 +2925,20 @@ int vnc_display_open(DisplayState *ds, const char *display)
         else
             vs->lsock = inet_connect(display, SOCK_STREAM);
         if (-1 == vs->lsock) {
-            free(vs->display);
+            g_free(vs->display);
             vs->display = NULL;
             return -1;
         } else {
             int csock = vs->lsock;
             vs->lsock = -1;
-            vnc_connect(vs, csock);
+            vnc_connect(vs, csock, 0);
         }
         return 0;
 
     } else {
         /* listen for connects */
         char *dpy;
-        dpy = qemu_malloc(256);
+        dpy = g_malloc(256);
         if (strncmp(display, "unix:", 5) == 0) {
             pstrcpy(dpy, 256, "unix:");
             vs->lsock = unix_listen(display+5, dpy+5, 256-5);
@@ -2757,12 +2946,19 @@ int vnc_display_open(DisplayState *ds, const char *display)
             vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
         }
         if (-1 == vs->lsock) {
-            free(dpy);
+            g_free(dpy);
             return -1;
         } else {
-            free(vs->display);
+            g_free(vs->display);
             vs->display = dpy;
         }
     }
     return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
 }
+
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    return vnc_connect(vs, csock, skipauth);
+}
index 24bac3c9f45876992796ad1e81f0b212c61bbab0..66689f1d60c718f9c076544d81e8c849e2158db2 100644 (file)
--- a/ui/vnc.h
+++ b/ui/vnc.h
 #include "console.h"
 #include "monitor.h"
 #include "audio/audio.h"
+#include "bitmap.h"
 #include <zlib.h>
 #include <stdbool.h>
 
 #include "keymaps.h"
+#include "vnc-palette.h"
+#include "vnc-enc-zrle.h"
 
 // #define _VNC_DEBUG 1
 
@@ -68,7 +71,7 @@ typedef struct VncRectEntry VncRectEntry;
 
 typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
 
-typedef void VncWritePixels(VncState *vs, struct QEMU_PixelFormat *pf, void *data, int size);
+typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
 
 typedef void VncSendHextileTile(VncState *vs,
                                 int x, int y, int w, int h,
@@ -76,9 +79,16 @@ typedef void VncSendHextileTile(VncState *vs,
                                 void *last_fg,
                                 int *has_bg, int *has_fg);
 
+/* VNC_MAX_WIDTH must be a multiple of 16. */
 #define VNC_MAX_WIDTH 2560
 #define VNC_MAX_HEIGHT 2048
-#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
+
+/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
+#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / 16)
+
+#define VNC_STAT_RECT  64
+#define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT)
+#define VNC_STAT_ROWS (VNC_MAX_HEIGHT / VNC_STAT_RECT)
 
 #define VNC_AUTH_CHALLENGE_SIZE 16
 
@@ -92,9 +102,23 @@ typedef struct VncDisplay VncDisplay;
 #include "vnc-auth-sasl.h"
 #endif
 
+struct VncRectStat
+{
+    /* time of last 10 updates, to find update frequency */
+    struct timeval times[10];
+    int idx;
+
+    double freq;        /* Update frequency (in Hz) */
+    bool updated;       /* Already updated during this refresh */
+};
+
+typedef struct VncRectStat VncRectStat;
+
 struct VncSurface
 {
-    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
+    struct timeval last_freq_check;
+    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
+    VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
     DisplaySurface *ds;
 };
 
@@ -123,6 +147,7 @@ struct VncDisplay
     time_t expires;
     int auth;
     bool lossy;
+    bool non_adaptive;
 #ifdef CONFIG_VNC_TLS
     int subauth; /* Used by VeNCrypt */
     VncDisplayTLS tls;
@@ -162,6 +187,20 @@ typedef struct VncZlib {
     int level;
 } VncZlib;
 
+typedef struct VncZrle {
+    int type;
+    Buffer fb;
+    Buffer zrle;
+    Buffer tmp;
+    Buffer zlib;
+    z_stream stream;
+    VncPalette palette;
+} VncZrle;
+
+typedef struct VncZywrle {
+    int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT];
+} VncZywrle;
+
 #ifdef CONFIG_VNC_THREAD
 struct VncRect
 {
@@ -198,7 +237,9 @@ struct VncState
     int csock;
 
     DisplayState *ds;
-    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
+    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS);
+    uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in
+                           * vnc-jobs-async.c */
 
     VncDisplay *vd;
     int need_update;
@@ -215,8 +256,10 @@ struct VncState
     int major;
     int minor;
 
+    int auth;
     char challenge[VNC_AUTH_CHALLENGE_SIZE];
 #ifdef CONFIG_VNC_TLS
+    int subauth; /* Used by VeNCrypt */
     VncStateTLS tls;
 #endif
 #ifdef CONFIG_VNC_SASL
@@ -253,7 +296,8 @@ struct VncState
     VncTight tight;
     VncZlib zlib;
     VncHextile hextile;
-
+    VncZrle zrle;
+    VncZywrle zywrle;
 
     Notifier mouse_mode_notifier;
 
@@ -357,6 +401,8 @@ enum {
 #define VNC_FEATURE_COPYRECT                 6
 #define VNC_FEATURE_RICH_CURSOR              7
 #define VNC_FEATURE_TIGHT_PNG                8
+#define VNC_FEATURE_ZRLE                     9
+#define VNC_FEATURE_ZYWRLE                  10
 
 #define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
 #define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
@@ -367,6 +413,8 @@ enum {
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
 #define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
 #define VNC_FEATURE_TIGHT_PNG_MASK           (1 << VNC_FEATURE_TIGHT_PNG)
+#define VNC_FEATURE_ZRLE_MASK                (1 << VNC_FEATURE_ZRLE)
+#define VNC_FEATURE_ZYWRLE_MASK              (1 << VNC_FEATURE_ZYWRLE)
 
 
 /* Client -> Server message IDs */
@@ -479,6 +527,8 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
                             int32_t encoding);
 
 void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
+double vnc_update_freq(VncState *vs, int x, int y, int w, int h);
+void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h);
 
 /* Encodings */
 int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
@@ -499,4 +549,8 @@ int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
                                           int w, int h);
 void vnc_tight_clear(VncState *vs);
 
+int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+void vnc_zrle_clear(VncState *vs);
+
 #endif /* __QEMU_VNC_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..11875527d53d2372774a0b03a65ad84d634fd655 100644 (file)
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -39,7 +39,6 @@
 #else
 #include <bus/usb/usb.h>
 #endif
-#include <signal.h>
 
 /* This value has maximum potential at 16.
  * You should also set hw.usb.debug to gain
@@ -63,7 +62,6 @@ typedef struct USBHostDevice {
 } USBHostDevice;
 
 
-#if 0
 static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
 {
     char buf[32];
@@ -111,7 +109,6 @@ static void ensure_eps_closed(USBHostDevice *dev)
         epnum++;
     }
 }
-#endif
 
 static void usb_host_handle_reset(USBDevice *dev)
 {
@@ -120,12 +117,12 @@ static void usb_host_handle_reset(USBDevice *dev)
 #endif
 }
 
-#if 0
 /* XXX:
  * -check device states against transfer requests
  *  and return appropriate response
  */
 static int usb_host_handle_control(USBDevice *dev,
+                                   USBPacket *p,
                                    int request,
                                    int value,
                                    int index,
@@ -256,9 +253,9 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     }
 
     if (p->pid == USB_TOKEN_IN)
-        ret = read(fd, p->data, p->len);
+        ret = readv(fd, p->iov.iov, p->iov.niov);
     else
-        ret = write(fd, p->data, p->len);
+        ret = writev(fd, p->iov.iov, p->iov.niov);
 
     sigprocmask(SIG_SETMASK, &old_mask, NULL);
 
@@ -278,7 +275,6 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         return ret;
     }
 }
-#endif
 
 static void usb_host_handle_destroy(USBDevice *opaque)
 {
@@ -294,7 +290,7 @@ static void usb_host_handle_destroy(USBDevice *opaque)
 
     close(s->devfd);
 
-    qemu_free(s);
+    g_free(s);
 }
 
 static int usb_host_initfn(USBDevice *dev)
@@ -305,8 +301,8 @@ static int usb_host_initfn(USBDevice *dev)
 USBDevice *usb_host_device_open(const char *devname)
 {
     struct usb_device_info bus_info, dev_info;
-    USBDevice *d = NULL;
-    USBHostDevice *dev, *ret = NULL;
+    USBDevice *d = NULL, *ret = NULL;
+    USBHostDevice *dev;
     char ctlpath[PATH_MAX + 1];
     char buspath[PATH_MAX + 1];
     int bfd, dfd, bus, address, i;
@@ -367,8 +363,10 @@ USBDevice *usb_host_device_open(const char *devname)
 
     if (dev_info.udi_speed == 1) {
         dev->dev.speed = USB_SPEED_LOW - 1;
+        dev->dev.speedmask = USB_SPEED_MASK_LOW;
     } else {
         dev->dev.speed = USB_SPEED_FULL - 1;
+        dev->dev.speedmask = USB_SPEED_MASK_FULL;
     }
 
     if (strncmp(dev_info.udi_product, "product", 7) != 0) {
@@ -406,10 +404,8 @@ static struct USBDeviceInfo usb_host_dev_info = {
     .init           = usb_host_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_host_handle_reset,
-#if 0
     .handle_control = usb_host_handle_control,
     .handle_data    = usb_host_handle_data,
-#endif
     .handle_destroy = usb_host_handle_destroy,
 };
 
@@ -464,7 +460,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 ccf70734e3f3b3cf80d31b9bda4cfb2a6e790158..749ce71081b45c159116721a448d1afc98d3b10b 100644 (file)
 #include "qemu-timer.h"
 #include "monitor.h"
 #include "sysemu.h"
+#include "trace.h"
 
 #include <dirent.h>
 #include <sys/ioctl.h>
-#include <signal.h>
 
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
@@ -54,15 +54,7 @@ struct usb_ctrltransfer {
     void *data;
 };
 
-struct usb_ctrlrequest {
-    uint8_t bRequestType;
-    uint8_t bRequest;
-    uint16_t wValue;
-    uint16_t wIndex;
-    uint16_t wLength;
-};
-
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
                         int class_id, int vendor_id, int product_id,
                         const char *product_name, int speed);
 
@@ -78,7 +70,8 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
 
 #define USBPROCBUS_PATH "/proc/bus/usb"
 #define PRODUCT_NAME_SZ 32
-#define MAX_ENDPOINTS 16
+#define MAX_ENDPOINTS 15
+#define MAX_PORTLEN 16
 #define USBDEVBUS_PATH "/dev/bus/usb"
 #define USBSYSBUS_PATH "/sys/bus/usb"
 
@@ -92,34 +85,29 @@ static char *usb_host_device_path;
 static int usb_fs_type;
 
 /* endpoint association data */
+#define ISO_FRAME_DESC_PER_URB 32
+#define INVALID_EP_TYPE 255
+
+/* devio.c limits single requests to 16k */
+#define MAX_USBFS_BUFFER_SIZE 16384
+
+typedef struct AsyncURB AsyncURB;
+
 struct endp_data {
     uint8_t type;
     uint8_t halted;
-};
-
-enum {
-    CTRL_STATE_IDLE = 0,
-    CTRL_STATE_SETUP,
-    CTRL_STATE_DATA,
-    CTRL_STATE_ACK
-};
-
-/*
- * Control transfer state.
- * Note that 'buffer' _must_ follow 'req' field because
- * we need contigious buffer when we submit control URB.
- */
-struct ctrl_struct {
-    uint16_t len;
-    uint16_t offset;
-    uint8_t  state;
-    struct   usb_ctrlrequest req;
-    uint8_t  buffer[8192];
+    uint8_t iso_started;
+    AsyncURB *iso_urb;
+    int iso_urb_idx;
+    int iso_buffer_used;
+    int max_packet_size;
+    int inflight;
 };
 
 struct USBAutoFilter {
     uint32_t bus_num;
     uint32_t addr;
+    char     *port;
     uint32_t vendor_id;
     uint32_t product_id;
 };
@@ -127,22 +115,27 @@ struct USBAutoFilter {
 typedef struct USBHostDevice {
     USBDevice dev;
     int       fd;
+    int       hub_fd;
+    int       hub_port;
 
-    uint8_t   descr[1024];
+    uint8_t   descr[8192];
     int       descr_len;
     int       configuration;
     int       ninterfaces;
     int       closing;
+    uint32_t  iso_urb_count;
     Notifier  exit;
 
-    struct ctrl_struct ctrl;
-    struct endp_data endp_table[MAX_ENDPOINTS];
+    struct endp_data ep_in[MAX_ENDPOINTS];
+    struct endp_data ep_out[MAX_ENDPOINTS];
+    QLIST_HEAD(, AsyncURB) aurbs;
 
     /* Host side address */
     int bus_num;
     int addr;
-    int devpath;
+    char port[MAX_PORTLEN];
     struct USBAutoFilter match;
+    int seen, errcount;
 
     QTAILQ_ENTRY(USBHostDevice) next;
 } USBHostDevice;
@@ -154,75 +147,189 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f);
 static void usb_host_auto_check(void *unused);
 static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
+static int usb_linux_update_endp_table(USBHostDevice *s);
 
-static int is_isoc(USBHostDevice *s, int ep)
+static int usb_host_do_reset(USBHostDevice *dev)
 {
-    return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
+    struct timeval s, e;
+    uint32_t usecs;
+    int ret;
+
+    gettimeofday(&s, NULL);
+    ret = ioctl(dev->fd, USBDEVFS_RESET);
+    gettimeofday(&e, NULL);
+    usecs = (e.tv_sec  - s.tv_sec) * 1000000;
+    usecs += e.tv_usec - s.tv_usec;
+    if (usecs > 1000000) {
+        /* more than a second, something is fishy, broken usb device? */
+        fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
+                dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
+    }
+    return ret;
+}
+
+static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
+{
+    struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
+    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
+    assert(ep > 0 && ep <= MAX_ENDPOINTS);
+    return eps + ep - 1;
 }
 
-static int is_halted(USBHostDevice *s, int ep)
+static int is_isoc(USBHostDevice *s, int pid, int ep)
 {
-    return s->endp_table[ep - 1].halted;
+    return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
 }
 
-static void clear_halt(USBHostDevice *s, int ep)
+static int is_valid(USBHostDevice *s, int pid, int ep)
 {
-    s->endp_table[ep - 1].halted = 0;
+    return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
 }
 
-static void set_halt(USBHostDevice *s, int ep)
+static int is_halted(USBHostDevice *s, int pid, int ep)
 {
-    s->endp_table[ep - 1].halted = 1;
+    return get_endp(s, pid, ep)->halted;
+}
+
+static void clear_halt(USBHostDevice *s, int pid, int ep)
+{
+    trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
+    get_endp(s, pid, ep)->halted = 0;
+}
+
+static void set_halt(USBHostDevice *s, int pid, int ep)
+{
+    if (ep != 0) {
+        trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
+        get_endp(s, pid, ep)->halted = 1;
+    }
+}
+
+static int is_iso_started(USBHostDevice *s, int pid, int ep)
+{
+    return get_endp(s, pid, ep)->iso_started;
+}
+
+static void clear_iso_started(USBHostDevice *s, int pid, int ep)
+{
+    trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
+    get_endp(s, pid, ep)->iso_started = 0;
+}
+
+static void set_iso_started(USBHostDevice *s, int pid, int ep)
+{
+    struct endp_data *e = get_endp(s, pid, ep);
+
+    trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
+    if (!e->iso_started) {
+        e->iso_started = 1;
+        e->inflight = 0;
+    }
+}
+
+static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
+{
+    struct endp_data *e = get_endp(s, pid, ep);
+
+    e->inflight += value;
+    return e->inflight;
+}
+
+static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
+{
+    get_endp(s, pid, ep)->iso_urb = iso_urb;
+}
+
+static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
+{
+    return get_endp(s, pid, ep)->iso_urb;
+}
+
+static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
+{
+    get_endp(s, pid, ep)->iso_urb_idx = i;
+}
+
+static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
+{
+    return get_endp(s, pid, ep)->iso_urb_idx;
+}
+
+static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
+{
+    get_endp(s, pid, ep)->iso_buffer_used = i;
+}
+
+static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
+{
+    return get_endp(s, pid, ep)->iso_buffer_used;
+}
+
+static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
+                                uint8_t *descriptor)
+{
+    int raw = descriptor[4] + (descriptor[5] << 8);
+    int size, microframes;
+
+    size = raw & 0x7ff;
+    switch ((raw >> 11) & 3) {
+    case 1:  microframes = 2; break;
+    case 2:  microframes = 3; break;
+    default: microframes = 1; break;
+    }
+    get_endp(s, pid, ep)->max_packet_size = size * microframes;
+}
+
+static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
+{
+    return get_endp(s, pid, ep)->max_packet_size;
 }
 
 /*
  * Async URB state.
- * We always allocate one isoc descriptor even for bulk transfers
+ * We always allocate iso packet descriptors even for bulk transfers
  * to simplify allocation and casts.
  */
-typedef struct AsyncURB
+struct AsyncURB
 {
     struct usbdevfs_urb urb;
-    struct usbdevfs_iso_packet_desc isocpd;
+    struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
+    USBHostDevice *hdev;
+    QLIST_ENTRY(AsyncURB) next;
 
+    /* For regular async urbs */
     USBPacket     *packet;
-    USBHostDevice *hdev;
-} AsyncURB;
+    int more; /* large transfer, more urbs follow */
+
+    /* For buffered iso handling */
+    int iso_frame_idx; /* -1 means in flight */
+};
 
-static AsyncURB *async_alloc(void)
+static AsyncURB *async_alloc(USBHostDevice *s)
 {
-    return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
+    AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
+    aurb->hdev = s;
+    QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
+    return aurb;
 }
 
 static void async_free(AsyncURB *aurb)
 {
-    qemu_free(aurb);
+    QLIST_REMOVE(aurb, next);
+    g_free(aurb);
 }
 
-static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
+static void do_disconnect(USBHostDevice *s)
 {
-    switch(s->ctrl.state) {
-    case CTRL_STATE_SETUP:
-        if (p->len < s->ctrl.len)
-            s->ctrl.len = p->len;
-        s->ctrl.state = CTRL_STATE_DATA;
-        p->len = 8;
-        break;
-
-    case CTRL_STATE_ACK:
-        s->ctrl.state = CTRL_STATE_IDLE;
-        p->len = 0;
-        break;
-
-    default:
-        break;
-    }
+    usb_host_close(s);
+    usb_host_auto_check(NULL);
 }
 
 static void async_complete(void *opaque)
 {
     USBHostDevice *s = opaque;
     AsyncURB *aurb;
+    int urbs = 0;
 
     while (1) {
         USBPacket *p;
@@ -230,82 +337,226 @@ static void async_complete(void *opaque)
         int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
         if (r < 0) {
             if (errno == EAGAIN) {
+                if (urbs > 2) {
+                    fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
+                }
                 return;
             }
-            if (errno == ENODEV && !s->closing) {
-                printf("husb: device %d.%d disconnected\n",
-                       s->bus_num, s->addr);
-                usb_host_close(s);
-                usb_host_auto_check(NULL);
+            if (errno == ENODEV) {
+                if (!s->closing) {
+                    trace_usb_host_disconnect(s->bus_num, s->addr);
+                    do_disconnect(s);
+                }
                 return;
             }
 
-            DPRINTF("husb: async. reap urb failed errno %d\n", errno);
+            perror("USBDEVFS_REAPURBNDELAY");
             return;
         }
 
-        p = aurb->packet;
-
         DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
                 aurb, aurb->urb.status, aurb->urb.actual_length);
 
+        /* If this is a buffered iso urb mark it as complete and don't do
+           anything else (it is handled further in usb_host_handle_iso_data) */
+        if (aurb->iso_frame_idx == -1) {
+            int inflight;
+            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
+                USB_TOKEN_IN : USB_TOKEN_OUT;
+            int ep = aurb->urb.endpoint & 0xf;
+            if (aurb->urb.status == -EPIPE) {
+                set_halt(s, pid, ep);
+            }
+            aurb->iso_frame_idx = 0;
+            urbs++;
+            inflight = change_iso_inflight(s, pid, ep, -1);
+            if (inflight == 0 && is_iso_started(s, pid, ep)) {
+                fprintf(stderr, "husb: out of buffers for iso stream\n");
+            }
+            continue;
+        }
+
+        p = aurb->packet;
+        trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
+                                    aurb->urb.actual_length, aurb->more);
+
         if (p) {
             switch (aurb->urb.status) {
             case 0:
-                p->len = aurb->urb.actual_length;
-                if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
-                    async_complete_ctrl(s, p);
-                }
+                p->result += aurb->urb.actual_length;
                 break;
 
             case -EPIPE:
-                set_halt(s, p->devep);
-                p->len = USB_RET_STALL;
+                set_halt(s, p->pid, p->devep);
+                p->result = USB_RET_STALL;
                 break;
 
             default:
-                p->len = USB_RET_NAK;
+                p->result = USB_RET_NAK;
                 break;
             }
 
-            usb_packet_complete(p);
+            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
+                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+                usb_generic_async_ctrl_complete(&s->dev, p);
+            } else if (!aurb->more) {
+                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+                usb_packet_complete(&s->dev, p);
+            }
         }
 
         async_free(aurb);
     }
 }
 
-static void async_cancel(USBPacket *unused, void *opaque)
+static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
 {
-    AsyncURB *aurb = opaque;
-    USBHostDevice *s = aurb->hdev;
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+    AsyncURB *aurb;
+
+    QLIST_FOREACH(aurb, &s->aurbs, next) {
+        if (p != aurb->packet) {
+            continue;
+        }
 
-    DPRINTF("husb: async cancel. aurb %p\n", aurb);
+        DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
 
-    /* Mark it as dead (see async_complete above) */
-    aurb->packet = NULL;
+        /* Mark it as dead (see async_complete above) */
+        aurb->packet = NULL;
 
-    int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
-    if (r < 0) {
-        DPRINTF("husb: async. discard urb failed errno %d\n", errno);
+        int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
+        if (r < 0) {
+            DPRINTF("husb: async. discard urb failed errno %d\n", errno);
+        }
     }
 }
 
+static int usb_host_claim_port(USBHostDevice *s)
+{
+#ifdef USBDEVFS_CLAIM_PORT
+    char *h, hub_name[64], line[1024];
+    int hub_addr, ret;
+
+    snprintf(hub_name, sizeof(hub_name), "%d-%s",
+             s->match.bus_num, s->match.port);
+
+    /* try strip off last ".$portnr" to get hub */
+    h = strrchr(hub_name, '.');
+    if (h != NULL) {
+        s->hub_port = atoi(h+1);
+        *h = '\0';
+    } else {
+        /* no dot in there -> it is the root hub */
+        snprintf(hub_name, sizeof(hub_name), "usb%d",
+                 s->match.bus_num);
+        s->hub_port = atoi(s->match.port);
+    }
+
+    if (!usb_host_read_file(line, sizeof(line), "devnum",
+                            hub_name)) {
+        return -1;
+    }
+    if (sscanf(line, "%d", &hub_addr) != 1) {
+        return -1;
+    }
+
+    if (!usb_host_device_path) {
+        return -1;
+    }
+    snprintf(line, sizeof(line), "%s/%03d/%03d",
+             usb_host_device_path, s->match.bus_num, hub_addr);
+    s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+    if (s->hub_fd < 0) {
+        return -1;
+    }
+
+    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
+    if (ret < 0) {
+        close(s->hub_fd);
+        s->hub_fd = -1;
+        return -1;
+    }
+
+    trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+static void usb_host_release_port(USBHostDevice *s)
+{
+    if (s->hub_fd == -1) {
+        return;
+    }
+#ifdef USBDEVFS_RELEASE_PORT
+    ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
+#endif
+    close(s->hub_fd);
+    s->hub_fd = -1;
+}
+
+static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
+{
+    /* earlier Linux 2.4 do not support that */
+#ifdef USBDEVFS_DISCONNECT
+    struct usbdevfs_ioctl ctrl;
+    int ret, interface;
+
+    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");
+            return -1;
+        }
+    }
+#endif
+    return 0;
+}
+
+static int usb_linux_get_num_interfaces(USBHostDevice *s)
+{
+    char device_name[64], line[1024];
+    int num_interfaces = 0;
+
+    if (usb_fs_type != USB_FS_SYS) {
+        return -1;
+    }
+
+    sprintf(device_name, "%d-%s", s->bus_num, s->port);
+    if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
+                            device_name)) {
+        return -1;
+    }
+    if (sscanf(line, "%d", &num_interfaces) != 1) {
+        return -1;
+    }
+    return num_interfaces;
+}
+
 static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
 {
+    const char *op = NULL;
     int dev_descr_len, config_descr_len;
     int interface, nb_interfaces;
     int ret, i;
 
-    if (configuration == 0) /* address state - ignore */
+    if (configuration == 0) { /* address state - ignore */
+        dev->ninterfaces   = 0;
+        dev->configuration = 0;
         return 1;
+    }
 
     DPRINTF("husb: claiming interfaces. config %d\n", configuration);
 
     i = 0;
     dev_descr_len = dev->descr[0];
     if (dev_descr_len > dev->descr_len) {
-        goto fail;
+        fprintf(stderr, "husb: update iface failed. descr too short\n");
+        return 0;
     }
 
     i += dev_descr_len;
@@ -320,9 +571,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
         }
         config_descr_len = dev->descr[i];
 
-        printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
+        DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
 
-        if (configuration < 0 || configuration == dev->descr[i + 5]) {
+        if (configuration == dev->descr[i + 5]) {
             configuration = dev->descr[i + 5];
             break;
         }
@@ -333,62 +584,51 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     if (i >= dev->descr_len) {
         fprintf(stderr,
                 "husb: update iface failed. no matching configuration\n");
-        goto fail;
+        return 0;
     }
     nb_interfaces = dev->descr[i + 4];
 
-#ifdef USBDEVFS_DISCONNECT
-    /* earlier Linux 2.4 do not support that */
-    {
-        struct usbdevfs_ioctl ctrl;
-        for (interface = 0; interface < nb_interfaces; interface++) {
-            ctrl.ioctl_code = USBDEVFS_DISCONNECT;
-            ctrl.ifno = interface;
-            ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
-            if (ret < 0 && errno != ENODATA) {
-                perror("USBDEVFS_DISCONNECT");
-                goto fail;
-            }
-        }
+    if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
+        goto fail;
     }
-#endif
 
     /* XXX: only grab if all interfaces are free */
     for (interface = 0; interface < nb_interfaces; interface++) {
+        op = "USBDEVFS_CLAIMINTERFACE";
         ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
         if (ret < 0) {
-            if (errno == EBUSY) {
-                printf("husb: update iface. device already grabbed\n");
-            } else {
-                perror("husb: failed to claim interface");
-            }
-        fail:
-            return 0;
+            goto fail;
         }
     }
 
-    printf("husb: %d interfaces claimed for configuration %d\n",
-           nb_interfaces, configuration);
+    trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
+                                    nb_interfaces, configuration);
 
     dev->ninterfaces   = nb_interfaces;
     dev->configuration = configuration;
     return 1;
+
+fail:
+    if (errno == ENODEV) {
+        do_disconnect(dev);
+    }
+    perror(op);
+    return 0;
 }
 
 static int usb_host_release_interfaces(USBHostDevice *s)
 {
     int ret, i;
 
-    DPRINTF("husb: releasing interfaces\n");
+    trace_usb_host_release_interfaces(s->bus_num, s->addr);
 
     for (i = 0; i < s->ninterfaces; i++) {
         ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
         if (ret < 0) {
-            perror("husb: failed to release interface");
+            perror("USBDEVFS_RELEASEINTERFACE");
             return 0;
         }
     }
-
     return 1;
 }
 
@@ -396,87 +636,300 @@ static void usb_host_handle_reset(USBDevice *dev)
 {
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
 
-    DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
+    trace_usb_host_reset(s->bus_num, s->addr);
 
-    ioctl(s->fd, USBDEVFS_RESET);
+    usb_host_do_reset(s);;
 
-    usb_host_claim_interfaces(s, s->configuration);
+    usb_host_claim_interfaces(s, 0);
+    usb_linux_update_endp_table(s);
 }
 
 static void usb_host_handle_destroy(USBDevice *dev)
 {
     USBHostDevice *s = (USBHostDevice *)dev;
 
+    usb_host_release_port(s);
     usb_host_close(s);
     QTAILQ_REMOVE(&hostdevs, s, next);
     qemu_remove_exit_notifier(&s->exit);
 }
 
-static int usb_linux_update_endp_table(USBHostDevice *s);
+/* iso data is special, we need to keep enough urbs in flight to make sure
+   that the controller never runs out of them, otherwise the device will
+   likely suffer a buffer underrun / overrun. */
+static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
+{
+    AsyncURB *aurb;
+    int i, j, len = get_max_packet_size(s, pid, ep);
+
+    aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
+    for (i = 0; i < s->iso_urb_count; i++) {
+        aurb[i].urb.endpoint      = ep;
+        aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
+        aurb[i].urb.buffer        = g_malloc(aurb[i].urb.buffer_length);
+        aurb[i].urb.type          = USBDEVFS_URB_TYPE_ISO;
+        aurb[i].urb.flags         = USBDEVFS_URB_ISO_ASAP;
+        aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
+        for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
+            aurb[i].urb.iso_frame_desc[j].length = len;
+        if (pid == USB_TOKEN_IN) {
+            aurb[i].urb.endpoint |= 0x80;
+            /* Mark as fully consumed (idle) */
+            aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
+        }
+    }
+    set_iso_urb(s, pid, ep, aurb);
+
+    return aurb;
+}
+
+static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
+{
+    AsyncURB *aurb;
+    int i, ret, killed = 0, free = 1;
+
+    aurb = get_iso_urb(s, pid, ep);
+    if (!aurb) {
+        return;
+    }
+
+    for (i = 0; i < s->iso_urb_count; i++) {
+        /* in flight? */
+        if (aurb[i].iso_frame_idx == -1) {
+            ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
+            if (ret < 0) {
+                perror("USBDEVFS_DISCARDURB");
+                free = 0;
+                continue;
+            }
+            killed++;
+        }
+    }
+
+    /* Make sure any urbs we've killed are reaped before we free them */
+    if (killed) {
+        async_complete(s);
+    }
+
+    for (i = 0; i < s->iso_urb_count; i++) {
+        g_free(aurb[i].urb.buffer);
+    }
+
+    if (free)
+        g_free(aurb);
+    else
+        printf("husb: leaking iso urbs because of discard failure\n");
+    set_iso_urb(s, pid, ep, NULL);
+    set_iso_urb_idx(s, pid, ep, 0);
+    clear_iso_started(s, pid, ep);
+}
+
+static int urb_status_to_usb_ret(int status)
+{
+    switch (status) {
+    case -EPIPE:
+        return USB_RET_STALL;
+    default:
+        return USB_RET_NAK;
+    }
+}
 
-static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
+static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
 {
+    AsyncURB *aurb;
+    int i, j, ret, max_packet_size, offset, len = 0;
+    uint8_t *buf;
+
+    max_packet_size = get_max_packet_size(s, p->pid, p->devep);
+    if (max_packet_size == 0)
+        return USB_RET_NAK;
+
+    aurb = get_iso_urb(s, p->pid, p->devep);
+    if (!aurb) {
+        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
+    }
+
+    i = get_iso_urb_idx(s, p->pid, p->devep);
+    j = aurb[i].iso_frame_idx;
+    if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
+        if (in) {
+            /* Check urb status  */
+            if (aurb[i].urb.status) {
+                len = urb_status_to_usb_ret(aurb[i].urb.status);
+                /* Move to the next urb */
+                aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
+            /* Check frame status */
+            } else if (aurb[i].urb.iso_frame_desc[j].status) {
+                len = urb_status_to_usb_ret(
+                                        aurb[i].urb.iso_frame_desc[j].status);
+            /* Check the frame fits */
+            } else if (aurb[i].urb.iso_frame_desc[j].actual_length
+                       > p->iov.size) {
+                printf("husb: received iso data is larger then packet\n");
+                len = USB_RET_NAK;
+            /* All good copy data over */
+            } else {
+                len = aurb[i].urb.iso_frame_desc[j].actual_length;
+                buf  = aurb[i].urb.buffer +
+                    j * aurb[i].urb.iso_frame_desc[0].length;
+                usb_packet_copy(p, buf, len);
+            }
+        } else {
+            len = p->iov.size;
+            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
+
+            /* Check the frame fits */
+            if (len > max_packet_size) {
+                printf("husb: send iso data is larger then max packet size\n");
+                return USB_RET_NAK;
+            }
+
+            /* All good copy data over */
+            usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
+            aurb[i].urb.iso_frame_desc[j].length = len;
+            offset += len;
+            set_iso_buffer_used(s, p->pid, p->devep, offset);
+
+            /* Start the stream once we have buffered enough data */
+            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
+                set_iso_started(s, p->pid, p->devep);
+            }
+        }
+        aurb[i].iso_frame_idx++;
+        if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+            i = (i + 1) % s->iso_urb_count;
+            set_iso_urb_idx(s, p->pid, p->devep, i);
+        }
+    } else {
+        if (in) {
+            set_iso_started(s, p->pid, p->devep);
+        } else {
+            DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
+        }
+    }
+
+    if (is_iso_started(s, p->pid, p->devep)) {
+        /* (Re)-submit all fully consumed / filled urbs */
+        for (i = 0; i < s->iso_urb_count; i++) {
+            if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+                ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
+                if (ret < 0) {
+                    perror("USBDEVFS_SUBMITURB");
+                    if (!in || len == 0) {
+                        switch(errno) {
+                        case ETIMEDOUT:
+                            len = USB_RET_NAK;
+                            break;
+                        case EPIPE:
+                        default:
+                            len = USB_RET_STALL;
+                        }
+                    }
+                    break;
+                }
+                aurb[i].iso_frame_idx = -1;
+                change_iso_inflight(s, p->pid, p->devep, 1);
+            }
+        }
+    }
+
+    return len;
+}
+
+static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;
     AsyncURB *aurb;
-    int ret;
+    int ret, rem, prem, v;
+    uint8_t *pbuf;
+    uint8_t ep;
 
-    aurb = async_alloc();
-    aurb->hdev   = s;
-    aurb->packet = p;
+    trace_usb_host_req_data(s->bus_num, s->addr,
+                            p->pid == USB_TOKEN_IN,
+                            p->devep, p->iov.size);
 
-    urb = &aurb->urb;
+    if (!is_valid(s, p->pid, p->devep)) {
+        trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+        return USB_RET_NAK;
+    }
 
     if (p->pid == USB_TOKEN_IN) {
-        urb->endpoint = p->devep | 0x80;
+        ep = p->devep | 0x80;
     } else {
-        urb->endpoint = p->devep;
+        ep = p->devep;
     }
 
-    if (is_halted(s, p->devep)) {
-        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
+    if (is_halted(s, p->pid, p->devep)) {
+        unsigned int arg = ep;
+        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
-            DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
-                   urb->endpoint, errno);
+            perror("USBDEVFS_CLEAR_HALT");
+            trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;
         }
-        clear_halt(s, p->devep);
+        clear_halt(s, p->pid, p->devep);
     }
 
-    urb->buffer        = p->data;
-    urb->buffer_length = p->len;
-
-    if (is_isoc(s, p->devep)) {
-        /* Setup ISOC transfer */
-        urb->type     = USBDEVFS_URB_TYPE_ISO;
-        urb->flags    = USBDEVFS_URB_ISO_ASAP;
-        urb->number_of_packets = 1;
-        urb->iso_frame_desc[0].length = p->len;
-    } else {
-        /* Setup bulk transfer */
-        urb->type     = USBDEVFS_URB_TYPE_BULK;
+    if (is_isoc(s, p->pid, p->devep)) {
+        return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
-    urb->usercontext = s;
-
-    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
+    v = 0;
+    prem = p->iov.iov[v].iov_len;
+    pbuf = p->iov.iov[v].iov_base;
+    rem = p->iov.size;
+    while (rem) {
+        if (prem == 0) {
+            v++;
+            assert(v < p->iov.niov);
+            prem = p->iov.iov[v].iov_len;
+            pbuf = p->iov.iov[v].iov_base;
+            assert(prem <= rem);
+        }
+        aurb = async_alloc(s);
+        aurb->packet = p;
+
+        urb = &aurb->urb;
+        urb->endpoint      = ep;
+        urb->type          = USBDEVFS_URB_TYPE_BULK;
+        urb->usercontext   = s;
+        urb->buffer        = pbuf;
+        urb->buffer_length = prem;
+
+        if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
+            urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
+        }
+        pbuf += urb->buffer_length;
+        prem -= urb->buffer_length;
+        rem  -= urb->buffer_length;
+        if (rem) {
+            aurb->more         = 1;
+        }
 
-    DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
-            urb->endpoint, p->len, aurb);
+        trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
+                                  urb->buffer_length, aurb->more);
+        ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
 
-    if (ret < 0) {
-        DPRINTF("husb: submit failed. errno %d\n", errno);
-        async_free(aurb);
+        DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
+                urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
 
-        switch(errno) {
-        case ETIMEDOUT:
-            return USB_RET_NAK;
-        case EPIPE:
-        default:
-            return USB_RET_STALL;
+        if (ret < 0) {
+            perror("USBDEVFS_SUBMITURB");
+            async_free(aurb);
+
+            switch(errno) {
+            case ETIMEDOUT:
+                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+                return USB_RET_NAK;
+            case EPIPE:
+            default:
+                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
+                return USB_RET_STALL;
+            }
         }
     }
 
-    usb_defer_packet(p, async_cancel, aurb);
     return USB_RET_ASYNC;
 }
 
@@ -491,30 +944,58 @@ static int ctrl_error(void)
 
 static int usb_host_set_address(USBHostDevice *s, int addr)
 {
-    DPRINTF("husb: ctrl set addr %u\n", addr);
+    trace_usb_host_set_address(s->bus_num, s->addr, addr);
     s->dev.addr = addr;
     return 0;
 }
 
 static int usb_host_set_config(USBHostDevice *s, int config)
 {
+    int ret, first = 1;
+
+    trace_usb_host_set_config(s->bus_num, s->addr, config);
+
     usb_host_release_interfaces(s);
 
-    int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
+again:
+    ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
 
     DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
 
+    if (ret < 0 && errno == EBUSY && first) {
+        /* happens if usb device is in use by host drivers */
+        int count = usb_linux_get_num_interfaces(s);
+        if (count > 0) {
+            DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
+            usb_host_disconnect_ifaces(s, count);
+            first = 0;
+            goto again;
+        }
+    }
+
     if (ret < 0) {
         return ctrl_error();
     }
     usb_host_claim_interfaces(s, config);
+    usb_linux_update_endp_table(s);
     return 0;
 }
 
 static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
 {
     struct usbdevfs_setinterface si;
-    int ret;
+    int i, ret;
+
+    trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
+
+    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+        if (is_isoc(s, USB_TOKEN_IN, i)) {
+            usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
+        }
+        if (is_isoc(s, USB_TOKEN_OUT, i)) {
+            usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
+        }
+    }
 
     si.interface  = iface;
     si.altsetting = alt;
@@ -530,56 +1011,48 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
     return 0;
 }
 
-static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
+static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
 {
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;
     AsyncURB *aurb;
-    int ret, value, index;
-    int buffer_len;
+    int ret;
 
     /*
      * Process certain standard device requests.
      * These are infrequent and are processed synchronously.
      */
-    value = le16_to_cpu(s->ctrl.req.wValue);
-    index = le16_to_cpu(s->ctrl.req.wIndex);
 
-    DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
-            s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
-            s->ctrl.len);
+    /* Note request is (bRequestType << 8) | bRequest */
+    trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
 
-    if (s->ctrl.req.bRequestType == 0) {
-        switch (s->ctrl.req.bRequest) {
-        case USB_REQ_SET_ADDRESS:
-            return usb_host_set_address(s, value);
+    switch (request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        return usb_host_set_address(s, value);
 
-        case USB_REQ_SET_CONFIGURATION:
-            return usb_host_set_config(s, value & 0xff);
-        }
-    }
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        return usb_host_set_config(s, value & 0xff);
 
-    if (s->ctrl.req.bRequestType == 1 &&
-                  s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
         return usb_host_set_interface(s, index, value);
     }
 
     /* The rest are asynchronous */
 
-    buffer_len = 8 + s->ctrl.len;
-    if (buffer_len > sizeof(s->ctrl.buffer)) {
-        fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
-                buffer_len, sizeof(s->ctrl.buffer));
+    if (length > sizeof(dev->data_buf)) {
+        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
+                length, sizeof(dev->data_buf));
         return USB_RET_STALL;
     }
 
-    aurb = async_alloc();
-    aurb->hdev   = s;
+    aurb = async_alloc(s);
     aurb->packet = 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;
@@ -587,11 +1060,13 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
     urb->type     = USBDEVFS_URB_TYPE_CONTROL;
     urb->endpoint = p->devep;
 
-    urb->buffer        = &s->ctrl.req;
-    urb->buffer_length = buffer_len;
+    urb->buffer        = &dev->setup_buf;
+    urb->buffer_length = length + 8;
 
     urb->usercontext = s;
 
+    trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
+                              urb->buffer_length, aurb->more);
     ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
 
     DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
@@ -609,231 +1084,67 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
         }
     }
 
-    usb_defer_packet(p, async_cancel, aurb);
     return USB_RET_ASYNC;
 }
 
-static int do_token_setup(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-    int ret = 0;
-
-    if (p->len != 8) {
-        return USB_RET_STALL;
-    }
-
-    memcpy(&s->ctrl.req, p->data, 8);
-    s->ctrl.len    = le16_to_cpu(s->ctrl.req.wLength);
-    s->ctrl.offset = 0;
-    s->ctrl.state  = CTRL_STATE_SETUP;
-
-    if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-        ret = usb_host_handle_control(s, p);
-        if (ret < 0) {
-            return ret;
-        }
-
-        if (ret < s->ctrl.len) {
-            s->ctrl.len = ret;
-        }
-        s->ctrl.state = CTRL_STATE_DATA;
-    } else {
-        if (s->ctrl.len == 0) {
-            s->ctrl.state = CTRL_STATE_ACK;
-        } else {
-            s->ctrl.state = CTRL_STATE_DATA;
-        }
-    }
-
-    return ret;
-}
-
-static int do_token_in(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-    int ret = 0;
-
-    if (p->devep != 0) {
-        return usb_host_handle_data(s, p);
-    }
-
-    switch(s->ctrl.state) {
-    case CTRL_STATE_ACK:
-        if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
-            ret = usb_host_handle_control(s, p);
-            if (ret == USB_RET_ASYNC) {
-                return USB_RET_ASYNC;
-            }
-            s->ctrl.state = CTRL_STATE_IDLE;
-            return ret > 0 ? 0 : ret;
-        }
-
-        return 0;
-
-    case CTRL_STATE_DATA:
-        if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-            int len = s->ctrl.len - s->ctrl.offset;
-            if (len > p->len) {
-                len = p->len;
-            }
-            memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
-            s->ctrl.offset += len;
-            if (s->ctrl.offset >= s->ctrl.len) {
-                s->ctrl.state = CTRL_STATE_ACK;
-            }
-            return len;
-        }
-
-        s->ctrl.state = CTRL_STATE_IDLE;
-        return USB_RET_STALL;
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
-static int do_token_out(USBDevice *dev, USBPacket *p)
-{
-    USBHostDevice *s = (USBHostDevice *) dev;
-
-    if (p->devep != 0) {
-        return usb_host_handle_data(s, p);
-    }
-
-    switch(s->ctrl.state) {
-    case CTRL_STATE_ACK:
-        if (s->ctrl.req.bRequestType & USB_DIR_IN) {
-            s->ctrl.state = CTRL_STATE_IDLE;
-            /* transfer OK */
-        } else {
-            /* ignore additional output */
-        }
-        return 0;
-
-    case CTRL_STATE_DATA:
-        if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
-            int len = s->ctrl.len - s->ctrl.offset;
-            if (len > p->len) {
-                len = p->len;
-            }
-            memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
-            s->ctrl.offset += len;
-            if (s->ctrl.offset >= s->ctrl.len) {
-                s->ctrl.state = CTRL_STATE_ACK;
-            }
-            return len;
-        }
-
-        s->ctrl.state = CTRL_STATE_IDLE;
-        return USB_RET_STALL;
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
-/*
- * Packet handler.
- * Called by the HC (host controller).
- *
- * Returns length of the transaction or one of the USB_RET_XXX codes.
- */
-static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
-{
-    switch(p->pid) {
-    case USB_MSG_ATTACH:
-        s->state = USB_STATE_ATTACHED;
-        return 0;
-
-    case USB_MSG_DETACH:
-        s->state = USB_STATE_NOTATTACHED;
-        return 0;
-
-    case USB_MSG_RESET:
-        s->remote_wakeup = 0;
-        s->addr = 0;
-        s->state = USB_STATE_DEFAULT;
-        s->info->handle_reset(s);
-        return 0;
-    }
-
-    /* Rest of the PIDs must match our address */
-    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
-        return USB_RET_NODEV;
-    }
-
-    switch (p->pid) {
-    case USB_TOKEN_SETUP:
-        return do_token_setup(s, p);
-
-    case USB_TOKEN_IN:
-        return do_token_in(s, p);
-
-    case USB_TOKEN_OUT:
-        return do_token_out(s, p);
-
-    default:
-        return USB_RET_STALL;
-    }
-}
-
-static int usb_linux_get_configuration(USBHostDevice *s)
+static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
+    uint8_t configuration, uint8_t interface)
 {
-    uint8_t configuration;
+    uint8_t alt_setting;
     struct usb_ctrltransfer ct;
     int ret;
 
     if (usb_fs_type == USB_FS_SYS) {
-        char device_name[32], line[1024];
-        int configuration;
+        char device_name[64], line[1024];
+        int alt_setting;
 
-        sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
+        sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
+                (int)configuration, (int)interface);
 
-        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
+        if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
                                 device_name)) {
             goto usbdevfs;
         }
-        if (sscanf(line, "%d", &configuration) != 1) {
+        if (sscanf(line, "%d", &alt_setting) != 1) {
             goto usbdevfs;
         }
-        return configuration;
+        return alt_setting;
     }
 
 usbdevfs:
-    ct.bRequestType = USB_DIR_IN;
-    ct.bRequest = USB_REQ_GET_CONFIGURATION;
+    ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
+    ct.bRequest = USB_REQ_GET_INTERFACE;
     ct.wValue = 0;
-    ct.wIndex = 0;
+    ct.wIndex = interface;
     ct.wLength = 1;
-    ct.data = &configuration;
+    ct.data = &alt_setting;
     ct.timeout = 50;
-
     ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
     if (ret < 0) {
-        perror("usb_linux_get_configuration");
-        return -1;
-    }
-
-    /* in address state */
-    if (configuration == 0) {
-        return -1;
+        /* Assume alt 0 on error */
+        return 0;
     }
 
-    return configuration;
+    return alt_setting;
 }
 
 /* returns 1 on problem encountered or 0 for success */
 static int usb_linux_update_endp_table(USBHostDevice *s)
 {
     uint8_t *descriptors;
-    uint8_t devep, type, configuration, alt_interface;
-    struct usb_ctrltransfer ct;
-    int interface, ret, length, i;
+    uint8_t devep, type, alt_interface;
+    int interface, length, i, ep, pid;
+    struct endp_data *epd;
 
-    i = usb_linux_get_configuration(s);
-    if (i < 0)
-        return 1;
-    configuration = i;
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        s->ep_in[i].type = INVALID_EP_TYPE;
+        s->ep_out[i].type = INVALID_EP_TYPE;
+    }
+
+    if (s->configuration == 0) {
+        /* not configured yet -- leave all endpoints disabled */
+        return 0;
+    }
 
     /* get the desired configuration, interface, and endpoint descriptors
      * from device description */
@@ -841,14 +1152,18 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     length = s->descr_len - 18;
     i = 0;
 
-    if (descriptors[i + 1] != USB_DT_CONFIG ||
-        descriptors[i + 5] != configuration) {
-        DPRINTF("invalid descriptor data - configuration\n");
-        return 1;
-    }
-    i += descriptors[i];
-
     while (i < length) {
+        if (descriptors[i + 1] != USB_DT_CONFIG) {
+            fprintf(stderr, "invalid descriptor data\n");
+            return 1;
+        } else if (descriptors[i + 5] != s->configuration) {
+            DPRINTF("not requested configuration %d\n", s->configuration);
+            i += (descriptors[i + 3] << 8) + descriptors[i + 2];
+            continue;
+        }
+
+        i += descriptors[i];
+
         if (descriptors[i + 1] != USB_DT_INTERFACE ||
             (descriptors[i + 1] == USB_DT_INTERFACE &&
              descriptors[i + 4] == 0)) {
@@ -857,19 +1172,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         }
 
         interface = descriptors[i + 2];
-
-        ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
-        ct.bRequest = USB_REQ_GET_INTERFACE;
-        ct.wValue = 0;
-        ct.wIndex = interface;
-        ct.wLength = 1;
-        ct.data = &alt_interface;
-        ct.timeout = 50;
-
-        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
-        if (ret < 0) {
-            alt_interface = interface;
-        }
+        alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+                                                  interface);
 
         /* the current interface descriptor is the active interface
          * and has endpoints */
@@ -892,12 +1196,20 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
             }
 
             devep = descriptors[i + 2];
+            pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
+            ep = devep & 0xf;
+            if (ep == 0) {
+                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
+                return 1;
+            }
+
             switch (descriptors[i + 3] & 0x3) {
             case 0x00:
                 type = USBDEVFS_URB_TYPE_CONTROL;
                 break;
             case 0x01:
                 type = USBDEVFS_URB_TYPE_ISO;
+                set_max_packet_size(s, pid, ep, descriptors + i);
                 break;
             case 0x02:
                 type = USBDEVFS_URB_TYPE_BULK;
@@ -909,8 +1221,10 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
                 DPRINTF("usb_host: malformed endpoint type\n");
                 type = USBDEVFS_URB_TYPE_BULK;
             }
-            s->endp_table[(devep & 0xf) - 1].type = type;
-            s->endp_table[(devep & 0xf) - 1].halted = 0;
+            epd = get_endp(s, pid, ep);
+            assert(epd->type == INVALID_EP_TYPE);
+            epd->type = type;
+            epd->halted = 0;
 
             i += descriptors[i];
         }
@@ -918,17 +1232,54 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     return 0;
 }
 
+/*
+ * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
+ * this function assumes this is safe, if:
+ * 1) There are no isoc endpoints
+ * 2) There are no interrupt endpoints with a max_packet_size > 64
+ * Note bulk endpoints with a max_packet_size > 64 in theory also are not
+ * usb1 compatible, but in practice this seems to work fine.
+ */
+static int usb_linux_full_speed_compat(USBHostDevice *dev)
+{
+    int i, packet_size;
+
+    /*
+     * usb_linux_update_endp_table only registers info about ep in the current
+     * interface altsettings, so we need to parse the descriptors again.
+     */
+    for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
+        if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
+            switch (dev->descr[i + 3] & 0x3) {
+            case 0x00: /* CONTROL */
+                break;
+            case 0x01: /* ISO */
+                return 0;
+            case 0x02: /* BULK */
+                break;
+            case 0x03: /* INTERRUPT */
+                packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
+                if (packet_size > 64)
+                    return 0;
+                break;
+            }
+        }
+    }
+    return 1;
+}
+
 static int usb_host_open(USBHostDevice *dev, int bus_num,
-                         int addr, int devpath, const char *prod_name)
+                         int addr, const char *port,
+                         const char *prod_name, int speed)
 {
     int fd = -1, ret;
-    struct usbdevfs_connectinfo ci;
     char buf[1024];
 
+    trace_usb_host_open_started(bus_num, addr);
+
     if (dev->fd != -1) {
         goto fail;
     }
-    printf("husb: open device %d.%d\n", bus_num, addr);
 
     if (!usb_host_device_path) {
         perror("husb: USB Host Device Path not set");
@@ -945,7 +1296,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
 
     dev->bus_num = bus_num;
     dev->addr = addr;
-    dev->devpath = devpath;
+    strcpy(dev->port, port);
     dev->fd = fd;
 
     /* read the device description */
@@ -967,34 +1318,38 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
 #endif
 
 
-    /*
-     * Initial configuration is -1 which makes us claim first
-     * available config. We used to start with 1, which does not
-     * always work. I've seen devices where first config starts
-     * with 2.
-     */
-    if (!usb_host_claim_interfaces(dev, -1)) {
-        goto fail;
-    }
-
-    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
-    if (ret < 0) {
-        perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
+    /* start unconfigured -- we'll wait for the guest to set a configuration */
+    if (!usb_host_claim_interfaces(dev, 0)) {
         goto fail;
     }
 
-    printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
-
     ret = usb_linux_update_endp_table(dev);
     if (ret) {
         goto fail;
     }
 
-    if (ci.slow) {
-        dev->dev.speed = USB_SPEED_LOW;
-    } else {
-        dev->dev.speed = USB_SPEED_HIGH;
+    if (speed == -1) {
+        struct usbdevfs_connectinfo ci;
+
+        ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
+        if (ret < 0) {
+            perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
+            goto fail;
+        }
+
+        if (ci.slow) {
+            speed = USB_SPEED_LOW;
+        } else {
+            speed = USB_SPEED_HIGH;
+        }
     }
+    dev->dev.speed = speed;
+    dev->dev.speedmask = (1 << speed);
+    if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
+        dev->dev.speedmask |= USB_SPEED_MASK_FULL;
+    }
+
+    trace_usb_host_open_success(bus_num, addr);
 
     if (!prod_name || prod_name[0] == '\0') {
         snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
@@ -1004,43 +1359,63 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
                 prod_name);
     }
 
+    ret = usb_device_attach(&dev->dev);
+    if (ret) {
+        goto fail;
+    }
+
     /* USB devio uses 'write' flag to check for async completions */
     qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
 
-    usb_device_attach(&dev->dev);
     return 0;
 
 fail:
-    dev->fd = -1;
-    if (fd != -1) {
-        close(fd);
+    trace_usb_host_open_failure(bus_num, addr);
+    if (dev->fd != -1) {
+        close(dev->fd);
+        dev->fd = -1;
     }
     return -1;
 }
 
 static int usb_host_close(USBHostDevice *dev)
 {
+    int i;
+
     if (dev->fd == -1) {
         return -1;
     }
 
+    trace_usb_host_close(dev->bus_num, dev->addr);
+
     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
     dev->closing = 1;
+    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+        if (is_isoc(dev, USB_TOKEN_IN, i)) {
+            usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
+        }
+        if (is_isoc(dev, USB_TOKEN_OUT, i)) {
+            usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
+        }
+    }
     async_complete(dev);
     dev->closing = 0;
-    usb_device_detach(&dev->dev);
-    ioctl(dev->fd, USBDEVFS_RESET);
+    if (dev->dev.attached) {
+        usb_device_detach(&dev->dev);
+    }
+    usb_host_do_reset(dev);
     close(dev->fd);
     dev->fd = -1;
     return 0;
 }
 
-static void usb_host_exit_notifier(struct Notifier* n)
+static void usb_host_exit_notifier(struct Notifier *n, void *data)
 {
     USBHostDevice *s = container_of(n, USBHostDevice, exit);
 
+    usb_host_release_port(s);
     if (s->fd != -1) {
-        ioctl(s->fd, USBDEVFS_RESET);
+        usb_host_do_reset(s);;
     }
 }
 
@@ -1050,19 +1425,34 @@ static int usb_host_initfn(USBDevice *dev)
 
     dev->auto_attach = 0;
     s->fd = -1;
+    s->hub_fd = -1;
+
     QTAILQ_INSERT_TAIL(&hostdevs, s, next);
     s->exit.notify = usb_host_exit_notifier;
     qemu_add_exit_notifier(&s->exit);
     usb_host_auto_check(NULL);
+
+    if (s->match.bus_num != 0 && s->match.port != NULL) {
+        usb_host_claim_port(s);
+    }
     return 0;
 }
 
+static const VMStateDescription vmstate_usb_host = {
+    .name = "usb-host",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo usb_host_dev_info = {
     .product_desc   = "USB Host Device",
     .qdev.name      = "usb-host",
     .qdev.size      = sizeof(USBHostDevice),
+    .qdev.vmsd      = &vmstate_usb_host,
     .init           = usb_host_initfn,
-    .handle_packet  = usb_host_handle_packet,
+    .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usb_host_async_cancel,
+    .handle_data    = usb_host_handle_data,
+    .handle_control = usb_host_handle_control,
     .handle_reset   = usb_host_handle_reset,
     .handle_destroy = usb_host_handle_destroy,
     .usbdevice_name = "host",
@@ -1070,8 +1460,10 @@ static struct USBDeviceInfo usb_host_dev_info = {
     .qdev.props     = (Property[]) {
         DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
         DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
+        DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
         DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
         DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
+        DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
@@ -1181,7 +1573,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     FILE *f = NULL;
     char line[1024];
     char buf[1024];
-    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
+    int bus_num, addr, speed, device_count;
+    int class_id, product_id, vendor_id, port;
     char product_name[512];
     int ret = 0;
 
@@ -1197,7 +1590,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     }
 
     device_count = 0;
-    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
+    bus_num = addr = class_id = product_id = vendor_id = port = 0;
+    speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
     for(;;) {
         if (fgets(line, sizeof(line), f) == NULL) {
             break;
@@ -1208,7 +1602,12 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
         if (line[0] == 'T' && line[1] == ':') {
             if (device_count && (vendor_id || product_id)) {
                 /* New device.  Add the previously discovered device.  */
-                ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
+                if (port > 0) {
+                    snprintf(buf, sizeof(buf), "%d", port);
+                } else {
+                    snprintf(buf, sizeof(buf), "?");
+                }
+                ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
                            product_id, product_name, speed);
                 if (ret) {
                     goto the_end;
@@ -1218,6 +1617,10 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
                 goto fail;
             }
             bus_num = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
+                goto fail;
+            }
+            port = atoi(buf);
             if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
                 goto fail;
             }
@@ -1225,7 +1628,9 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
             if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
                 goto fail;
             }
-            if (!strcmp(buf, "480")) {
+            if (!strcmp(buf, "5000")) {
+                speed = USB_SPEED_SUPER;
+            } else if (!strcmp(buf, "480")) {
                 speed = USB_SPEED_HIGH;
             } else if (!strcmp(buf, "1.5")) {
                 speed = USB_SPEED_LOW;
@@ -1261,7 +1666,12 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     }
     if (device_count && (vendor_id || product_id)) {
         /* Add the last device.  */
-        ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
+        if (port > 0) {
+            snprintf(buf, sizeof(buf), "%d", port);
+        } else {
+            snprintf(buf, sizeof(buf), "?");
+        }
+        ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
                    product_id, product_name, speed);
     }
  the_end:
@@ -1310,8 +1720,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
 {
     DIR *dir = NULL;
     char line[1024];
-    int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
+    int bus_num, addr, speed, class_id, product_id, vendor_id;
     int ret = 0;
+    char port[MAX_PORTLEN];
     char product_name[512];
     struct dirent *de;
 
@@ -1323,12 +1734,8 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
 
     while ((de = readdir(dir))) {
         if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
-            char *tmpstr = de->d_name;
-            if (!strncmp(de->d_name, "usb", 3)) {
-                tmpstr += 3;
-            }
-            if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
-                goto the_end;
+            if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
+                continue;
             }
 
             if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
@@ -1372,7 +1779,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
             if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
                 goto the_end;
             }
-            if (!strcmp(line, "480\n")) {
+            if (!strcmp(line, "5000\n")) {
+                speed = USB_SPEED_SUPER;
+            } else if (!strcmp(line, "480\n")) {
                 speed = USB_SPEED_HIGH;
             } else if (!strcmp(line, "1.5\n")) {
                 speed = USB_SPEED_LOW;
@@ -1380,7 +1789,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
                 speed = USB_SPEED_FULL;
             }
 
-            ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
+            ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
                        product_id, product_name, speed);
             if (ret) {
                 goto the_end;
@@ -1446,7 +1855,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
         }
 
         /* the module setting (used later for opening devices) */
-        usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
+        usb_host_device_path = g_malloc0(strlen(devpath)+1);
         strcpy(usb_host_device_path, devpath);
         if (mon) {
             monitor_printf(mon, "husb: using %s file-system with %s\n",
@@ -1471,7 +1880,8 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
 
 static QEMUTimer *usb_auto_timer;
 
-static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
+static int usb_host_auto_scan(void *opaque, int bus_num,
+                              int addr, const char *port,
                               int class_id, int vendor_id, int product_id,
                               const char *product_name, int speed)
 {
@@ -1491,6 +1901,9 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
         if (f->addr > 0 && f->addr != addr) {
             continue;
         }
+        if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
+            continue;
+        }
 
         if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
             continue;
@@ -1500,6 +1913,10 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
             continue;
         }
         /* We got a match */
+        s->seen++;
+        if (s->errcount >= 3) {
+            return 0;
+        }
 
         /* Already attached ? */
         if (s->fd != -1) {
@@ -1507,7 +1924,10 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
         }
         DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
 
-        usb_host_open(s, bus_num, addr, devpath, product_name);
+        if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
+            s->errcount++;
+        }
+        break;
     }
 
     return 0;
@@ -1524,23 +1944,29 @@ static void usb_host_auto_check(void *unused)
         if (s->fd == -1) {
             unconnected++;
         }
+        if (s->seen == 0) {
+            s->errcount = 0;
+        }
+        s->seen = 0;
     }
 
     if (unconnected == 0) {
         /* nothing to watch */
         if (usb_auto_timer) {
             qemu_del_timer(usb_auto_timer);
+            trace_usb_host_auto_scan_disabled();
         }
         return;
     }
 
     if (!usb_auto_timer) {
-        usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_check, NULL);
+        usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
         if (!usb_auto_timer) {
             return;
         }
+        trace_usb_host_auto_scan_enabled();
     }
-    qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
+    qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
 }
 
 /*
@@ -1629,8 +2055,9 @@ static const char *usb_class_str(uint8_t class)
     return p->class_name;
 }
 
-static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
-                            int vendor_id, int product_id,
+static void usb_info_device(Monitor *mon, int bus_num,
+                            int addr, const char *port,
+                            int class_id, int vendor_id, int product_id,
                             const char *product_name,
                             int speed)
 {
@@ -1646,13 +2073,16 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
     case USB_SPEED_HIGH:
         speed_str = "480";
         break;
+    case USB_SPEED_SUPER:
+        speed_str = "5000";
+        break;
     default:
         speed_str = "?";
         break;
     }
 
-    monitor_printf(mon, "  Device %d.%d, speed %s Mb/s\n",
-                bus_num, addr, speed_str);
+    monitor_printf(mon, "  Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
+                   bus_num, addr, port, speed_str);
     class_str = usb_class_str(class_id);
     if (class_str) {
         monitor_printf(mon, "    %s:", class_str);
@@ -1667,14 +2097,14 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
 }
 
 static int usb_host_info_device(void *opaque, int bus_num, int addr,
-                                int devpath, int class_id,
+                                const char *path, int class_id,
                                 int vendor_id, int product_id,
                                 const char *product_name,
                                 int speed)
 {
     Monitor *mon = opaque;
 
-    usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
+    usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
                     product_name, speed);
     return 0;
 }
@@ -1716,7 +2146,7 @@ void usb_host_info(Monitor *mon)
         dec2str(f->addr, addr, sizeof(addr));
         hex2str(f->vendor_id, vid, sizeof(vid));
         hex2str(f->product_id, pid, sizeof(pid));
-        monitor_printf(mon, "    Device %s.%s ID %s:%s\n",
-                       bus, addr, vid, pid);
+        monitor_printf(mon, "    Bus %s, Addr %s, Port %s, ID %s:%s\n",
+                       bus, addr, f->port ? f->port : "*", vid, pid);
     }
 }
diff --git a/usb-redir.c b/usb-redir.c
new file mode 100644 (file)
index 0000000..fb91c92
--- /dev/null
@@ -0,0 +1,1252 @@
+/*
+ * USB redirector usb-guest
+ *
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Red Hat Authors:
+ * Hans de Goede <hdegoede@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 "qemu-timer.h"
+#include "monitor.h"
+#include "sysemu.h"
+
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <usbredirparser.h>
+
+#include "hw/usb.h"
+
+#define MAX_ENDPOINTS 32
+#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
+#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
+
+typedef struct AsyncURB AsyncURB;
+typedef struct USBRedirDevice USBRedirDevice;
+
+/* Struct to hold buffered packets (iso or int input packets) */
+struct buf_packet {
+    uint8_t *data;
+    int len;
+    int status;
+    QTAILQ_ENTRY(buf_packet)next;
+};
+
+struct endp_data {
+    uint8_t type;
+    uint8_t interval;
+    uint8_t interface; /* bInterfaceNumber this ep belongs to */
+    uint8_t iso_started;
+    uint8_t iso_error; /* For reporting iso errors to the HC */
+    uint8_t interrupt_started;
+    uint8_t interrupt_error;
+    QTAILQ_HEAD(, buf_packet) bufpq;
+};
+
+struct USBRedirDevice {
+    USBDevice dev;
+    /* Properties */
+    CharDriverState *cs;
+    uint8_t debug;
+    /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
+    const uint8_t *read_buf;
+    int read_buf_size;
+    /* For async handling of open/close */
+    QEMUBH *open_close_bh;
+    /* To delay the usb attach in case of quick chardev close + open */
+    QEMUTimer *attach_timer;
+    int64_t next_attach_time;
+    struct usbredirparser *parser;
+    struct endp_data endpoint[MAX_ENDPOINTS];
+    uint32_t packet_id;
+    QTAILQ_HEAD(, AsyncURB) asyncq;
+};
+
+struct AsyncURB {
+    USBRedirDevice *dev;
+    USBPacket *packet;
+    uint32_t packet_id;
+    int get;
+    union {
+        struct usb_redir_control_packet_header control_packet;
+        struct usb_redir_bulk_packet_header bulk_packet;
+        struct usb_redir_interrupt_packet_header interrupt_packet;
+    };
+    QTAILQ_ENTRY(AsyncURB)next;
+};
+
+static void usbredir_device_connect(void *priv,
+    struct usb_redir_device_connect_header *device_connect);
+static void usbredir_device_disconnect(void *priv);
+static void usbredir_interface_info(void *priv,
+    struct usb_redir_interface_info_header *interface_info);
+static void usbredir_ep_info(void *priv,
+    struct usb_redir_ep_info_header *ep_info);
+static void usbredir_configuration_status(void *priv, uint32_t id,
+    struct usb_redir_configuration_status_header *configuration_status);
+static void usbredir_alt_setting_status(void *priv, uint32_t id,
+    struct usb_redir_alt_setting_status_header *alt_setting_status);
+static void usbredir_iso_stream_status(void *priv, uint32_t id,
+    struct usb_redir_iso_stream_status_header *iso_stream_status);
+static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+    struct usb_redir_interrupt_receiving_status_header
+    *interrupt_receiving_status);
+static void usbredir_bulk_streams_status(void *priv, uint32_t id,
+    struct usb_redir_bulk_streams_status_header *bulk_streams_status);
+static void usbredir_control_packet(void *priv, uint32_t id,
+    struct usb_redir_control_packet_header *control_packet,
+    uint8_t *data, int data_len);
+static void usbredir_bulk_packet(void *priv, uint32_t id,
+    struct usb_redir_bulk_packet_header *bulk_packet,
+    uint8_t *data, int data_len);
+static void usbredir_iso_packet(void *priv, uint32_t id,
+    struct usb_redir_iso_packet_header *iso_packet,
+    uint8_t *data, int data_len);
+static void usbredir_interrupt_packet(void *priv, uint32_t id,
+    struct usb_redir_interrupt_packet_header *interrupt_header,
+    uint8_t *data, int data_len);
+
+static int usbredir_handle_status(USBRedirDevice *dev,
+                                       int status, int actual_len);
+
+#define VERSION "qemu usb-redir guest " QEMU_VERSION
+
+/*
+ * Logging stuff
+ */
+
+#define ERROR(...) \
+    do { \
+        if (dev->debug >= usbredirparser_error) { \
+            error_report("usb-redir error: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define WARNING(...) \
+    do { \
+        if (dev->debug >= usbredirparser_warning) { \
+            error_report("usb-redir warning: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define INFO(...) \
+    do { \
+        if (dev->debug >= usbredirparser_info) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define DPRINTF(...) \
+    do { \
+        if (dev->debug >= usbredirparser_debug) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define DPRINTF2(...) \
+    do { \
+        if (dev->debug >= usbredirparser_debug_data) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+
+static void usbredir_log(void *priv, int level, const char *msg)
+{
+    USBRedirDevice *dev = priv;
+
+    if (dev->debug < level) {
+        return;
+    }
+
+    error_report("%s\n", msg);
+}
+
+static void usbredir_log_data(USBRedirDevice *dev, const char *desc,
+    const uint8_t *data, int len)
+{
+    int i, j, n;
+
+    if (dev->debug < usbredirparser_debug_data) {
+        return;
+    }
+
+    for (i = 0; i < len; i += j) {
+        char buf[128];
+
+        n = sprintf(buf, "%s", desc);
+        for (j = 0; j < 8 && i + j < len; j++) {
+            n += sprintf(buf + n, " %02X", data[i + j]);
+        }
+        error_report("%s\n", buf);
+    }
+}
+
+/*
+ * usbredirparser io functions
+ */
+
+static int usbredir_read(void *priv, uint8_t *data, int count)
+{
+    USBRedirDevice *dev = priv;
+
+    if (dev->read_buf_size < count) {
+        count = dev->read_buf_size;
+    }
+
+    memcpy(data, dev->read_buf, count);
+
+    dev->read_buf_size -= count;
+    if (dev->read_buf_size) {
+        dev->read_buf += count;
+    } else {
+        dev->read_buf = NULL;
+    }
+
+    return count;
+}
+
+static int usbredir_write(void *priv, uint8_t *data, int count)
+{
+    USBRedirDevice *dev = priv;
+
+    if (!dev->cs->opened) {
+        return 0;
+    }
+
+    return qemu_chr_fe_write(dev->cs, data, count);
+}
+
+/*
+ * Async and buffered packets helpers
+ */
+
+static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p)
+{
+    AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB));
+    aurb->dev = dev;
+    aurb->packet = p;
+    aurb->packet_id = dev->packet_id;
+    QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next);
+    dev->packet_id++;
+
+    return aurb;
+}
+
+static void async_free(USBRedirDevice *dev, AsyncURB *aurb)
+{
+    QTAILQ_REMOVE(&dev->asyncq, aurb, next);
+    g_free(aurb);
+}
+
+static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id)
+{
+    AsyncURB *aurb;
+
+    QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
+        if (aurb->packet_id == packet_id) {
+            return aurb;
+        }
+    }
+    ERROR("could not find async urb for packet_id %u\n", packet_id);
+    return NULL;
+}
+
+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    AsyncURB *aurb;
+
+    QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
+        if (p != aurb->packet) {
+            continue;
+        }
+
+        DPRINTF("async cancel id %u\n", aurb->packet_id);
+        usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id);
+        usbredirparser_do_write(dev->parser);
+
+        /* Mark it as dead */
+        aurb->packet = NULL;
+        break;
+    }
+}
+
+static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+    uint8_t *data, int len, int status, uint8_t ep)
+{
+    struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet));
+    bufp->data   = data;
+    bufp->len    = len;
+    bufp->status = status;
+    QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    return bufp;
+}
+
+static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
+    uint8_t ep)
+{
+    QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    free(bufp->data);
+    g_free(bufp);
+}
+
+static void usbredir_free_bufpq(USBRedirDevice *dev, uint8_t ep)
+{
+    struct buf_packet *buf, *buf_next;
+
+    QTAILQ_FOREACH_SAFE(buf, &dev->endpoint[EP2I(ep)].bufpq, next, buf_next) {
+        bufp_free(dev, buf, ep);
+    }
+}
+
+/*
+ * USBDevice callbacks
+ */
+
+static void usbredir_handle_reset(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+
+    DPRINTF("reset device\n");
+    usbredirparser_send_reset(dev->parser);
+    usbredirparser_do_write(dev->parser);
+}
+
+static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+                                     uint8_t ep)
+{
+    int status, len;
+
+    if (!dev->endpoint[EP2I(ep)].iso_started &&
+            !dev->endpoint[EP2I(ep)].iso_error) {
+        struct usb_redir_start_iso_stream_header start_iso = {
+            .endpoint = ep,
+            /* TODO maybe do something with these depending on ep interval? */
+            .pkts_per_urb = 32,
+            .no_urbs = 3,
+        };
+        /* No id, we look at the ep when receiving a status back */
+        usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
+        usbredirparser_do_write(dev->parser);
+        DPRINTF("iso stream started ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 1;
+    }
+
+    if (ep & USB_DIR_IN) {
+        struct buf_packet *isop;
+
+        isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+        if (isop == NULL) {
+            DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+            /* Check iso_error for stream errors, otherwise its an underrun */
+            status = dev->endpoint[EP2I(ep)].iso_error;
+            dev->endpoint[EP2I(ep)].iso_error = 0;
+            return usbredir_handle_status(dev, status, 0);
+        }
+        DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
+                 isop->len);
+
+        status = isop->status;
+        if (status != usb_redir_success) {
+            bufp_free(dev, isop, ep);
+            return usbredir_handle_status(dev, status, 0);
+        }
+
+        len = isop->len;
+        if (len > p->iov.size) {
+            ERROR("received iso data is larger then packet ep %02X\n", ep);
+            bufp_free(dev, isop, ep);
+            return USB_RET_NAK;
+        }
+        usb_packet_copy(p, isop->data, len);
+        bufp_free(dev, isop, ep);
+        return len;
+    } else {
+        /* If the stream was not started because of a pending error don't
+           send the packet to the usb-host */
+        if (dev->endpoint[EP2I(ep)].iso_started) {
+            struct usb_redir_iso_packet_header iso_packet = {
+                .endpoint = ep,
+                .length = p->iov.size
+            };
+            uint8_t buf[p->iov.size];
+            /* No id, we look at the ep when receiving a status back */
+            usb_packet_copy(p, buf, p->iov.size);
+            usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
+                                           buf, p->iov.size);
+            usbredirparser_do_write(dev->parser);
+        }
+        status = dev->endpoint[EP2I(ep)].iso_error;
+        dev->endpoint[EP2I(ep)].iso_error = 0;
+        DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
+                 p->iov.size);
+        return usbredir_handle_status(dev, status, p->iov.size);
+    }
+}
+
+static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
+{
+    struct usb_redir_stop_iso_stream_header stop_iso_stream = {
+        .endpoint = ep
+    };
+    if (dev->endpoint[EP2I(ep)].iso_started) {
+        usbredirparser_send_stop_iso_stream(dev->parser, 0, &stop_iso_stream);
+        DPRINTF("iso stream stopped ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 0;
+    }
+    usbredir_free_bufpq(dev, ep);
+}
+
+static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
+                                      uint8_t ep)
+{
+    AsyncURB *aurb = async_alloc(dev, p);
+    struct usb_redir_bulk_packet_header bulk_packet;
+
+    DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
+            p->iov.size, aurb->packet_id);
+
+    bulk_packet.endpoint  = ep;
+    bulk_packet.length    = p->iov.size;
+    bulk_packet.stream_id = 0;
+    aurb->bulk_packet = bulk_packet;
+
+    if (ep & USB_DIR_IN) {
+        usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
+                                        &bulk_packet, NULL, 0);
+    } else {
+        uint8_t buf[p->iov.size];
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "bulk data out:", buf, p->iov.size);
+        usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
+                                        &bulk_packet, buf, p->iov.size);
+    }
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
+                                           USBPacket *p, uint8_t ep)
+{
+    if (ep & USB_DIR_IN) {
+        /* Input interrupt endpoint, buffered packet input */
+        struct buf_packet *intp;
+        int status, len;
+
+        if (!dev->endpoint[EP2I(ep)].interrupt_started &&
+                !dev->endpoint[EP2I(ep)].interrupt_error) {
+            struct usb_redir_start_interrupt_receiving_header start_int = {
+                .endpoint = ep,
+            };
+            /* No id, we look at the ep when receiving a status back */
+            usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
+                                                          &start_int);
+            usbredirparser_do_write(dev->parser);
+            DPRINTF("interrupt recv started ep %02X\n", ep);
+            dev->endpoint[EP2I(ep)].interrupt_started = 1;
+        }
+
+        intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+        if (intp == NULL) {
+            DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
+            /* Check interrupt_error for stream errors */
+            status = dev->endpoint[EP2I(ep)].interrupt_error;
+            dev->endpoint[EP2I(ep)].interrupt_error = 0;
+            return usbredir_handle_status(dev, status, 0);
+        }
+        DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
+                intp->status, intp->len);
+
+        status = intp->status;
+        if (status != usb_redir_success) {
+            bufp_free(dev, intp, ep);
+            return usbredir_handle_status(dev, status, 0);
+        }
+
+        len = intp->len;
+        if (len > p->iov.size) {
+            ERROR("received int data is larger then packet ep %02X\n", ep);
+            bufp_free(dev, intp, ep);
+            return USB_RET_NAK;
+        }
+        usb_packet_copy(p, intp->data, len);
+        bufp_free(dev, intp, ep);
+        return len;
+    } else {
+        /* Output interrupt endpoint, normal async operation */
+        AsyncURB *aurb = async_alloc(dev, p);
+        struct usb_redir_interrupt_packet_header interrupt_packet;
+        uint8_t buf[p->iov.size];
+
+        DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
+                aurb->packet_id);
+
+        interrupt_packet.endpoint  = ep;
+        interrupt_packet.length    = p->iov.size;
+        aurb->interrupt_packet     = interrupt_packet;
+
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
+        usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
+                                        &interrupt_packet, buf, p->iov.size);
+        usbredirparser_do_write(dev->parser);
+        return USB_RET_ASYNC;
+    }
+}
+
+static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
+    uint8_t ep)
+{
+    struct usb_redir_stop_interrupt_receiving_header stop_interrupt_recv = {
+        .endpoint = ep
+    };
+    if (dev->endpoint[EP2I(ep)].interrupt_started) {
+        usbredirparser_send_stop_interrupt_receiving(dev->parser, 0,
+                                                     &stop_interrupt_recv);
+        DPRINTF("interrupt recv stopped ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].interrupt_started = 0;
+    }
+    usbredir_free_bufpq(dev, ep);
+}
+
+static int usbredir_handle_data(USBDevice *udev, USBPacket *p)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    uint8_t ep;
+
+    ep = p->devep;
+    if (p->pid == USB_TOKEN_IN) {
+        ep |= USB_DIR_IN;
+    }
+
+    switch (dev->endpoint[EP2I(ep)].type) {
+    case USB_ENDPOINT_XFER_CONTROL:
+        ERROR("handle_data called for control transfer on ep %02X\n", ep);
+        return USB_RET_NAK;
+    case USB_ENDPOINT_XFER_ISOC:
+        return usbredir_handle_iso_data(dev, p, ep);
+    case USB_ENDPOINT_XFER_BULK:
+        return usbredir_handle_bulk_data(dev, p, ep);;
+    case USB_ENDPOINT_XFER_INT:
+        return usbredir_handle_interrupt_data(dev, p, ep);;
+    default:
+        ERROR("handle_data ep %02X has unknown type %d\n", ep,
+              dev->endpoint[EP2I(ep)].type);
+        return USB_RET_NAK;
+    }
+}
+
+static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
+                                int config)
+{
+    struct usb_redir_set_configuration_header set_config;
+    AsyncURB *aurb = async_alloc(dev, p);
+    int i;
+
+    DPRINTF("set config %d id %u\n", config, aurb->packet_id);
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        switch (dev->endpoint[i].type) {
+        case USB_ENDPOINT_XFER_ISOC:
+            usbredir_stop_iso_stream(dev, I2EP(i));
+            break;
+        case USB_ENDPOINT_XFER_INT:
+            if (i & 0x10) {
+                usbredir_stop_interrupt_receiving(dev, I2EP(i));
+            }
+            break;
+        }
+        usbredir_free_bufpq(dev, I2EP(i));
+    }
+
+    set_config.configuration = config;
+    usbredirparser_send_set_configuration(dev->parser, aurb->packet_id,
+                                          &set_config);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
+{
+    AsyncURB *aurb = async_alloc(dev, p);
+
+    DPRINTF("get config id %u\n", aurb->packet_id);
+
+    aurb->get = 1;
+    usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
+                                   int interface, int alt)
+{
+    struct usb_redir_set_alt_setting_header set_alt;
+    AsyncURB *aurb = async_alloc(dev, p);
+    int i;
+
+    DPRINTF("set interface %d alt %d id %u\n", interface, alt,
+            aurb->packet_id);
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        if (dev->endpoint[i].interface == interface) {
+            switch (dev->endpoint[i].type) {
+            case USB_ENDPOINT_XFER_ISOC:
+                usbredir_stop_iso_stream(dev, I2EP(i));
+                break;
+            case USB_ENDPOINT_XFER_INT:
+                if (i & 0x10) {
+                    usbredir_stop_interrupt_receiving(dev, I2EP(i));
+                }
+                break;
+            }
+            usbredir_free_bufpq(dev, I2EP(i));
+        }
+    }
+
+    set_alt.interface = interface;
+    set_alt.alt = alt;
+    usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id,
+                                        &set_alt);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
+                                   int interface)
+{
+    struct usb_redir_get_alt_setting_header get_alt;
+    AsyncURB *aurb = async_alloc(dev, p);
+
+    DPRINTF("get interface %d id %u\n", interface, aurb->packet_id);
+
+    get_alt.interface = interface;
+    aurb->get = 1;
+    usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
+                                        &get_alt);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    struct usb_redir_control_packet_header control_packet;
+    AsyncURB *aurb;
+
+    /* Special cases for certain standard device requests */
+    switch (request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        DPRINTF("set address %d\n", value);
+        dev->dev.addr = value;
+        return 0;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        return usbredir_set_config(dev, p, value & 0xff);
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        return usbredir_get_config(dev, p);
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        return usbredir_set_interface(dev, p, index, value);
+    case InterfaceRequest | USB_REQ_GET_INTERFACE:
+        return usbredir_get_interface(dev, p, index);
+    }
+
+    /* "Normal" ctrl requests */
+    aurb = async_alloc(dev, p);
+
+    /* Note request is (bRequestType << 8) | bRequest */
+    DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n",
+            request >> 8, request & 0xff, value, index, length,
+            aurb->packet_id);
+
+    control_packet.request     = request & 0xFF;
+    control_packet.requesttype = request >> 8;
+    control_packet.endpoint    = control_packet.requesttype & USB_DIR_IN;
+    control_packet.value       = value;
+    control_packet.index       = index;
+    control_packet.length      = length;
+    aurb->control_packet       = control_packet;
+
+    if (control_packet.requesttype & USB_DIR_IN) {
+        usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
+                                           &control_packet, NULL, 0);
+    } else {
+        usbredir_log_data(dev, "ctrl data out:", data, length);
+        usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
+                                           &control_packet, data, length);
+    }
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+/*
+ * Close events can be triggered by usbredirparser_do_write which gets called
+ * from within the USBDevice data / control packet callbacks and doing a
+ * usb_detach from within these callbacks is not a good idea.
+ *
+ * So we use a bh handler to take care of close events. We also handle
+ * open events from this callback to make sure that a close directly followed
+ * by an open gets handled in the right order.
+ */
+static void usbredir_open_close_bh(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    usbredir_device_disconnect(dev);
+
+    if (dev->parser) {
+        usbredirparser_destroy(dev->parser);
+        dev->parser = NULL;
+    }
+
+    if (dev->cs->opened) {
+        dev->parser = qemu_oom_check(usbredirparser_create());
+        dev->parser->priv = dev;
+        dev->parser->log_func = usbredir_log;
+        dev->parser->read_func = usbredir_read;
+        dev->parser->write_func = usbredir_write;
+        dev->parser->device_connect_func = usbredir_device_connect;
+        dev->parser->device_disconnect_func = usbredir_device_disconnect;
+        dev->parser->interface_info_func = usbredir_interface_info;
+        dev->parser->ep_info_func = usbredir_ep_info;
+        dev->parser->configuration_status_func = usbredir_configuration_status;
+        dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
+        dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
+        dev->parser->interrupt_receiving_status_func =
+            usbredir_interrupt_receiving_status;
+        dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
+        dev->parser->control_packet_func = usbredir_control_packet;
+        dev->parser->bulk_packet_func = usbredir_bulk_packet;
+        dev->parser->iso_packet_func = usbredir_iso_packet;
+        dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
+        dev->read_buf = NULL;
+        dev->read_buf_size = 0;
+        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
+        usbredirparser_do_write(dev->parser);
+    }
+}
+
+static void usbredir_do_attach(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    usb_device_attach(&dev->dev);
+}
+
+/*
+ * chardev callbacks
+ */
+
+static int usbredir_chardev_can_read(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    if (dev->parser) {
+        /* usbredir_parser_do_read will consume *all* data we give it */
+        return 1024 * 1024;
+    } else {
+        /* usbredir_open_close_bh hasn't handled the open event yet */
+        return 0;
+    }
+}
+
+static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
+{
+    USBRedirDevice *dev = opaque;
+
+    /* No recursion allowed! */
+    assert(dev->read_buf == NULL);
+
+    dev->read_buf = buf;
+    dev->read_buf_size = size;
+
+    usbredirparser_do_read(dev->parser);
+    /* Send any acks, etc. which may be queued now */
+    usbredirparser_do_write(dev->parser);
+}
+
+static void usbredir_chardev_event(void *opaque, int event)
+{
+    USBRedirDevice *dev = opaque;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+    case CHR_EVENT_CLOSED:
+        qemu_bh_schedule(dev->open_close_bh);
+        break;
+    }
+}
+
+/*
+ * init + destroy
+ */
+
+static int usbredir_initfn(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    int i;
+
+    if (dev->cs == NULL) {
+        qerror_report(QERR_MISSING_PARAMETER, "chardev");
+        return -1;
+    }
+
+    dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
+    dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
+
+    QTAILQ_INIT(&dev->asyncq);
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        QTAILQ_INIT(&dev->endpoint[i].bufpq);
+    }
+
+    /* We'll do the attach once we receive the speed from the usb-host */
+    udev->auto_attach = 0;
+
+    /* Let the backend know we are ready */
+    qemu_chr_fe_open(dev->cs);
+    qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
+                          usbredir_chardev_read, usbredir_chardev_event, dev);
+
+    return 0;
+}
+
+static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
+{
+    AsyncURB *aurb, *next_aurb;
+    int i;
+
+    QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) {
+        async_free(dev, aurb);
+    }
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        usbredir_free_bufpq(dev, I2EP(i));
+    }
+}
+
+static void usbredir_handle_destroy(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+
+    qemu_chr_fe_close(dev->cs);
+    qemu_chr_delete(dev->cs);
+    /* Note must be done after qemu_chr_close, as that causes a close event */
+    qemu_bh_delete(dev->open_close_bh);
+
+    qemu_del_timer(dev->attach_timer);
+    qemu_free_timer(dev->attach_timer);
+
+    usbredir_cleanup_device_queues(dev);
+
+    if (dev->parser) {
+        usbredirparser_destroy(dev->parser);
+    }
+}
+
+/*
+ * usbredirparser packet complete callbacks
+ */
+
+static int usbredir_handle_status(USBRedirDevice *dev,
+                                       int status, int actual_len)
+{
+    switch (status) {
+    case usb_redir_success:
+        return actual_len;
+    case usb_redir_stall:
+        return USB_RET_STALL;
+    case usb_redir_cancelled:
+        WARNING("returning cancelled packet to HC?\n");
+    case usb_redir_inval:
+    case usb_redir_ioerror:
+    case usb_redir_timeout:
+    default:
+        return USB_RET_NAK;
+    }
+}
+
+static void usbredir_device_connect(void *priv,
+    struct usb_redir_device_connect_header *device_connect)
+{
+    USBRedirDevice *dev = priv;
+
+    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
+        ERROR("Received device connect while already connected\n");
+        return;
+    }
+
+    switch (device_connect->speed) {
+    case usb_redir_speed_low:
+        DPRINTF("attaching low speed device\n");
+        dev->dev.speed = USB_SPEED_LOW;
+        break;
+    case usb_redir_speed_full:
+        DPRINTF("attaching full speed device\n");
+        dev->dev.speed = USB_SPEED_FULL;
+        break;
+    case usb_redir_speed_high:
+        DPRINTF("attaching high speed device\n");
+        dev->dev.speed = USB_SPEED_HIGH;
+        break;
+    case usb_redir_speed_super:
+        DPRINTF("attaching super speed device\n");
+        dev->dev.speed = USB_SPEED_SUPER;
+        break;
+    default:
+        DPRINTF("attaching unknown speed device, assuming full speed\n");
+        dev->dev.speed = USB_SPEED_FULL;
+    }
+    dev->dev.speedmask = (1 << dev->dev.speed);
+    qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
+}
+
+static void usbredir_device_disconnect(void *priv)
+{
+    USBRedirDevice *dev = priv;
+    int i;
+
+    /* Stop any pending attaches */
+    qemu_del_timer(dev->attach_timer);
+
+    if (dev->dev.attached) {
+        usb_device_detach(&dev->dev);
+        /*
+         * Delay next usb device attach to give the guest a chance to see
+         * see the detach / attach in case of quick close / open succession
+         */
+        dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200;
+    }
+
+    /* Reset state so that the next dev connected starts with a clean slate */
+    usbredir_cleanup_device_queues(dev);
+    memset(dev->endpoint, 0, sizeof(dev->endpoint));
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        QTAILQ_INIT(&dev->endpoint[i].bufpq);
+    }
+}
+
+static void usbredir_interface_info(void *priv,
+    struct usb_redir_interface_info_header *interface_info)
+{
+    /* The intention is to allow specifying acceptable interface classes
+       for redirection on the cmdline and in the future verify this here,
+       and disconnect (or never connect) the device if a not accepted
+       interface class is detected */
+}
+
+static void usbredir_ep_info(void *priv,
+    struct usb_redir_ep_info_header *ep_info)
+{
+    USBRedirDevice *dev = priv;
+    int i;
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        dev->endpoint[i].type = ep_info->type[i];
+        dev->endpoint[i].interval = ep_info->interval[i];
+        dev->endpoint[i].interface = ep_info->interface[i];
+        if (dev->endpoint[i].type != usb_redir_type_invalid) {
+            DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
+                    dev->endpoint[i].type, dev->endpoint[i].interface);
+        }
+    }
+}
+
+static void usbredir_configuration_status(void *priv, uint32_t id,
+    struct usb_redir_configuration_status_header *config_status)
+{
+    USBRedirDevice *dev = priv;
+    AsyncURB *aurb;
+    int len = 0;
+
+    DPRINTF("set config status %d config %d id %u\n", config_status->status,
+            config_status->configuration, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        return;
+    }
+    if (aurb->packet) {
+        if (aurb->get) {
+            dev->dev.data_buf[0] = config_status->configuration;
+            len = 1;
+        }
+        aurb->packet->result =
+            usbredir_handle_status(dev, config_status->status, len);
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+}
+
+static void usbredir_alt_setting_status(void *priv, uint32_t id,
+    struct usb_redir_alt_setting_status_header *alt_setting_status)
+{
+    USBRedirDevice *dev = priv;
+    AsyncURB *aurb;
+    int len = 0;
+
+    DPRINTF("alt status %d intf %d alt %d id: %u\n",
+            alt_setting_status->status,
+            alt_setting_status->interface,
+            alt_setting_status->alt, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        return;
+    }
+    if (aurb->packet) {
+        if (aurb->get) {
+            dev->dev.data_buf[0] = alt_setting_status->alt;
+            len = 1;
+        }
+        aurb->packet->result =
+            usbredir_handle_status(dev, alt_setting_status->status, len);
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+}
+
+static void usbredir_iso_stream_status(void *priv, uint32_t id,
+    struct usb_redir_iso_stream_status_header *iso_stream_status)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = iso_stream_status->endpoint;
+
+    DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
+            ep, id);
+
+    if (!dev->dev.attached) {
+        return;
+    }
+
+    dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status;
+    if (iso_stream_status->status == usb_redir_stall) {
+        DPRINTF("iso stream stopped by peer ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 0;
+    }
+}
+
+static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+    struct usb_redir_interrupt_receiving_status_header
+    *interrupt_receiving_status)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = interrupt_receiving_status->endpoint;
+
+    DPRINTF("interrupt recv status %d ep %02X id %u\n",
+            interrupt_receiving_status->status, ep, id);
+
+    if (!dev->dev.attached) {
+        return;
+    }
+
+    dev->endpoint[EP2I(ep)].interrupt_error =
+        interrupt_receiving_status->status;
+    if (interrupt_receiving_status->status == usb_redir_stall) {
+        DPRINTF("interrupt receiving stopped by peer ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].interrupt_started = 0;
+    }
+}
+
+static void usbredir_bulk_streams_status(void *priv, uint32_t id,
+    struct usb_redir_bulk_streams_status_header *bulk_streams_status)
+{
+}
+
+static void usbredir_control_packet(void *priv, uint32_t id,
+    struct usb_redir_control_packet_header *control_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    int len = control_packet->length;
+    AsyncURB *aurb;
+
+    DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
+            len, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        free(data);
+        return;
+    }
+
+    aurb->control_packet.status = control_packet->status;
+    aurb->control_packet.length = control_packet->length;
+    if (memcmp(&aurb->control_packet, control_packet,
+               sizeof(*control_packet))) {
+        ERROR("return control packet mismatch, please report this!\n");
+        len = USB_RET_NAK;
+    }
+
+    if (aurb->packet) {
+        len = usbredir_handle_status(dev, control_packet->status, len);
+        if (len > 0) {
+            usbredir_log_data(dev, "ctrl data in:", data, data_len);
+            if (data_len <= sizeof(dev->dev.data_buf)) {
+                memcpy(dev->dev.data_buf, data, data_len);
+            } else {
+                ERROR("ctrl buffer too small (%d > %zu)\n",
+                      data_len, sizeof(dev->dev.data_buf));
+                len = USB_RET_STALL;
+            }
+        }
+        aurb->packet->result = len;
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+    free(data);
+}
+
+static void usbredir_bulk_packet(void *priv, uint32_t id,
+    struct usb_redir_bulk_packet_header *bulk_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = bulk_packet->endpoint;
+    int len = bulk_packet->length;
+    AsyncURB *aurb;
+
+    DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
+            ep, len, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        free(data);
+        return;
+    }
+
+    if (aurb->bulk_packet.endpoint != bulk_packet->endpoint ||
+            aurb->bulk_packet.stream_id != bulk_packet->stream_id) {
+        ERROR("return bulk packet mismatch, please report this!\n");
+        len = USB_RET_NAK;
+    }
+
+    if (aurb->packet) {
+        len = usbredir_handle_status(dev, bulk_packet->status, len);
+        if (len > 0) {
+            usbredir_log_data(dev, "bulk data in:", data, data_len);
+            if (data_len <= aurb->packet->iov.size) {
+                usb_packet_copy(aurb->packet, data, data_len);
+            } else {
+                ERROR("bulk buffer too small (%d > %zd)\n", data_len,
+                      aurb->packet->iov.size);
+                len = USB_RET_STALL;
+            }
+        }
+        aurb->packet->result = len;
+        usb_packet_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+    free(data);
+}
+
+static void usbredir_iso_packet(void *priv, uint32_t id,
+    struct usb_redir_iso_packet_header *iso_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = iso_packet->endpoint;
+
+    DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep,
+             data_len, id);
+
+    if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
+        ERROR("received iso packet for non iso endpoint %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    if (dev->endpoint[EP2I(ep)].iso_started == 0) {
+        DPRINTF("received iso packet for non started stream ep %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    /* bufp_alloc also adds the packet to the ep queue */
+    bufp_alloc(dev, data, data_len, iso_packet->status, ep);
+}
+
+static void usbredir_interrupt_packet(void *priv, uint32_t id,
+    struct usb_redir_interrupt_packet_header *interrupt_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = interrupt_packet->endpoint;
+
+    DPRINTF("interrupt-in status %d ep %02X len %d id %u\n",
+            interrupt_packet->status, ep, data_len, id);
+
+    if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
+        ERROR("received int packet for non interrupt endpoint %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    if (ep & USB_DIR_IN) {
+        if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
+            DPRINTF("received int packet while not started ep %02X\n", ep);
+            free(data);
+            return;
+        }
+
+        /* bufp_alloc also adds the packet to the ep queue */
+        bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
+    } else {
+        int len = interrupt_packet->length;
+
+        AsyncURB *aurb = async_find(dev, id);
+        if (!aurb) {
+            return;
+        }
+
+        if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) {
+            ERROR("return int packet mismatch, please report this!\n");
+            len = USB_RET_NAK;
+        }
+
+        if (aurb->packet) {
+            aurb->packet->result = usbredir_handle_status(dev,
+                                               interrupt_packet->status, len);
+            usb_packet_complete(&dev->dev, aurb->packet);
+        }
+        async_free(dev, aurb);
+    }
+}
+
+static struct USBDeviceInfo usbredir_dev_info = {
+    .product_desc   = "USB Redirection Device",
+    .qdev.name      = "usb-redir",
+    .qdev.size      = sizeof(USBRedirDevice),
+    .init           = usbredir_initfn,
+    .handle_destroy = usbredir_handle_destroy,
+    .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usbredir_cancel_packet,
+    .handle_reset   = usbredir_handle_reset,
+    .handle_data    = usbredir_handle_data,
+    .handle_control = usbredir_handle_control,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+        DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void usbredir_register_devices(void)
+{
+    usb_qdev_register(&usbredir_dev_info);
+}
+device_init(usbredir_register_devices);
diff --git a/user-exec.c b/user-exec.c
new file mode 100644 (file)
index 0000000..abf6885
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ *  User emulator execution
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "disas.h"
+#include "tcg.h"
+
+#undef EAX
+#undef ECX
+#undef EDX
+#undef EBX
+#undef ESP
+#undef EBP
+#undef ESI
+#undef EDI
+#undef EIP
+#include <signal.h>
+#ifdef __linux__
+#include <sys/ucontext.h>
+#endif
+
+//#define DEBUG_SIGNAL
+
+static void exception_action(CPUState *env1)
+{
+#if defined(TARGET_I386)
+    raise_exception_err_env(env1, env1->exception_index, env1->error_code);
+#else
+    cpu_loop_exit(env1);
+#endif
+}
+
+/* exit the current TB from a signal handler. The host registers are
+   restored in a state compatible with the CPU emulator
+ */
+void cpu_resume_from_signal(CPUState *env1, void *puc)
+{
+#ifdef __linux__
+    struct ucontext *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#endif
+
+    env = env1;
+
+    /* XXX: restore cpu registers saved in host registers */
+
+    if (puc) {
+        /* XXX: use siglongjmp ? */
+#ifdef __linux__
+#ifdef __ia64
+        sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
+#else
+        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+#endif
+#elif defined(__OpenBSD__)
+        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
+#endif
+    }
+    env->exception_index = -1;
+    longjmp(env->jmp_env, 1);
+}
+
+/* 'pc' is the host PC at which the exception was raised. 'address' is
+   the effective address of the memory exception. 'is_write' is 1 if a
+   write caused the exception and otherwise 0'. 'old_set' is the
+   signal set which should be restored */
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set,
+                                    void *puc)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    if (cpu_single_env) {
+        env = cpu_single_env; /* XXX: find a correct solution for multithread */
+    }
+#if defined(DEBUG_SIGNAL)
+    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+                pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(h2g(address), pc, puc)) {
+        return 1;
+    }
+
+    /* see if it is an MMU fault */
+    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);
+    if (ret < 0) {
+        return 0; /* not an MMU fault */
+    }
+    if (ret == 0) {
+        return 1; /* the MMU fault was handled without causing real CPU fault */
+    }
+    /* now we have a real cpu fault */
+    tb = tb_find_pc(pc);
+    if (tb) {
+        /* the PC is inside the translated code. It means that we have
+           a virtual CPU fault */
+        cpu_restore_state(tb, env, pc);
+    }
+
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    exception_action(env);
+
+    /* never comes here */
+    return 1;
+}
+
+#if defined(__i386__)
+
+#if defined(__APPLE__)
+#include <sys/ucontext.h>
+
+#define EIP_sig(context)  (*((unsigned long *)&(context)->uc_mcontext->ss.eip))
+#define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
+#define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__NetBSD__)
+#include <ucontext.h>
+
+#define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
+#define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#include <ucontext.h>
+
+#define EIP_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_eip))
+#define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
+#define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define EIP_sig(context)     ((context)->sc_eip)
+#define TRAP_sig(context)    ((context)->sc_trapno)
+#define ERROR_sig(context)   ((context)->sc_err)
+#define MASK_sig(context)    ((context)->sc_mask)
+#else
+#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
+#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+    unsigned long pc;
+    int trapno;
+
+#ifndef REG_EIP
+/* for glibc 2.1 */
+#define REG_EIP    EIP
+#define REG_ERR    ERR
+#define REG_TRAPNO TRAPNO
+#endif
+    pc = EIP_sig(uc);
+    trapno = TRAP_sig(uc);
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             trapno == 0xe ?
+                             (ERROR_sig(uc) >> 1) & 1 : 0,
+                             &MASK_sig(uc), puc);
+}
+
+#elif defined(__x86_64__)
+
+#ifdef __NetBSD__
+#define PC_sig(context)       _UC_MACHINE_PC(context)
+#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define PC_sig(context)       ((context)->sc_rip)
+#define TRAP_sig(context)     ((context)->sc_trapno)
+#define ERROR_sig(context)    ((context)->sc_err)
+#define MASK_sig(context)     ((context)->sc_mask)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#include <ucontext.h>
+
+#define PC_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_rip))
+#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
+#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#else
+#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
+#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    unsigned long pc;
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+
+    pc = PC_sig(uc);
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             TRAP_sig(uc) == 0xe ?
+                             (ERROR_sig(uc) >> 1) & 1 : 0,
+                             &MASK_sig(uc), puc);
+}
+
+#elif defined(_ARCH_PPC)
+
+/***********************************************************************
+ * signal context platform-specific definitions
+ * From Wine
+ */
+#ifdef linux
+/* All Registers access - only for local access */
+#define REG_sig(reg_name, context)              \
+    ((context)->uc_mcontext.regs->reg_name)
+/* Gpr Registers access  */
+#define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
+/* Program counter */
+#define IAR_sig(context)                       REG_sig(nip, context)
+/* Machine State Register (Supervisor) */
+#define MSR_sig(context)                       REG_sig(msr, context)
+/* Count register */
+#define CTR_sig(context)                       REG_sig(ctr, context)
+/* User's integer exception register */
+#define XER_sig(context)                       REG_sig(xer, context)
+/* Link register */
+#define LR_sig(context)                        REG_sig(link, context)
+/* Condition register */
+#define CR_sig(context)                        REG_sig(ccr, context)
+
+/* Float Registers access  */
+#define FLOAT_sig(reg_num, context)                                     \
+    (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num])
+#define FPSCR_sig(context) \
+    (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
+/* Exception Registers access */
+#define DAR_sig(context)                       REG_sig(dar, context)
+#define DSISR_sig(context)                     REG_sig(dsisr, context)
+#define TRAP_sig(context)                      REG_sig(trap, context)
+#endif /* linux */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <ucontext.h>
+#define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
+#define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
+#define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
+#define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
+#define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
+#define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
+/* Exception Registers access */
+#define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
+#define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
+#define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
+#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
+
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+typedef struct ucontext SIGCONTEXT;
+/* All Registers access - only for local access */
+#define REG_sig(reg_name, context)              \
+    ((context)->uc_mcontext->ss.reg_name)
+#define FLOATREG_sig(reg_name, context)         \
+    ((context)->uc_mcontext->fs.reg_name)
+#define EXCEPREG_sig(reg_name, context)         \
+    ((context)->uc_mcontext->es.reg_name)
+#define VECREG_sig(reg_name, context)           \
+    ((context)->uc_mcontext->vs.reg_name)
+/* Gpr Registers access */
+#define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
+/* Program counter */
+#define IAR_sig(context)                       REG_sig(srr0, context)
+/* Machine State Register (Supervisor) */
+#define MSR_sig(context)                       REG_sig(srr1, context)
+#define CTR_sig(context)                       REG_sig(ctr, context)
+/* Link register */
+#define XER_sig(context)                       REG_sig(xer, context)
+/* User's integer exception register */
+#define LR_sig(context)                        REG_sig(lr, context)
+/* Condition register */
+#define CR_sig(context)                        REG_sig(cr, context)
+/* Float Registers access */
+#define FLOAT_sig(reg_num, context)             \
+    FLOATREG_sig(fpregs[reg_num], context)
+#define FPSCR_sig(context)                      \
+    ((double)FLOATREG_sig(fpscr, context))
+/* Exception Registers access */
+/* Fault registers for coredump */
+#define DAR_sig(context)                       EXCEPREG_sig(dar, context)
+#define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
+/* number of powerpc exception taken */
+#define TRAP_sig(context)                      EXCEPREG_sig(exception, context)
+#endif /* __APPLE__ */
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+    ucontext_t *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+    unsigned long pc;
+    int is_write;
+
+    pc = IAR_sig(uc);
+    is_write = 0;
+#if 0
+    /* ppc 4xx case */
+    if (DSISR_sig(uc) & 0x00800000) {
+        is_write = 1;
+    }
+#else
+    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
+        is_write = 1;
+    }
+#endif
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__alpha__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                           void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    uint32_t *pc = uc->uc_mcontext.sc_pc;
+    uint32_t insn = *pc;
+    int is_write = 0;
+
+    /* XXX: need kernel patch to get write flag faster */
+    switch (insn >> 26) {
+    case 0x0d: /* stw */
+    case 0x0e: /* stb */
+    case 0x0f: /* stq_u */
+    case 0x24: /* stf */
+    case 0x25: /* stg */
+    case 0x26: /* sts */
+    case 0x27: /* stt */
+    case 0x2c: /* stl */
+    case 0x2d: /* stq */
+    case 0x2e: /* stl_c */
+    case 0x2f: /* stq_c */
+        is_write = 1;
+    }
+
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+#elif defined(__sparc__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    int is_write;
+    uint32_t insn;
+#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
+    uint32_t *regs = (uint32_t *)(info + 1);
+    void *sigmask = (regs + 20);
+    /* XXX: is there a standard glibc define ? */
+    unsigned long pc = regs[1];
+#else
+#ifdef __linux__
+    struct sigcontext *sc = puc;
+    unsigned long pc = sc->sigc_regs.tpc;
+    void *sigmask = (void *)sc->sigc_mask;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+    unsigned long pc = uc->sc_pc;
+    void *sigmask = (void *)(long)uc->sc_mask;
+#endif
+#endif
+
+    /* XXX: need kernel patch to get write flag faster */
+    is_write = 0;
+    insn = *(uint32_t *)pc;
+    if ((insn >> 30) == 3) {
+        switch ((insn >> 19) & 0x3f) {
+        case 0x05: /* stb */
+        case 0x15: /* stba */
+        case 0x06: /* sth */
+        case 0x16: /* stha */
+        case 0x04: /* st */
+        case 0x14: /* sta */
+        case 0x07: /* std */
+        case 0x17: /* stda */
+        case 0x0e: /* stx */
+        case 0x1e: /* stxa */
+        case 0x24: /* stf */
+        case 0x34: /* stfa */
+        case 0x27: /* stdf */
+        case 0x37: /* stdfa */
+        case 0x26: /* stqf */
+        case 0x36: /* stqfa */
+        case 0x25: /* stfsr */
+        case 0x3c: /* casa */
+        case 0x3e: /* casxa */
+            is_write = 1;
+            break;
+        }
+    }
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, sigmask, NULL);
+}
+
+#elif defined(__arm__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    int is_write;
+
+#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+    pc = uc->uc_mcontext.gregs[R15];
+#else
+    pc = uc->uc_mcontext.arm_pc;
+#endif
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write,
+                             &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mc68000)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    int is_write;
+
+    pc = uc->uc_mcontext.gregs[16];
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write,
+                             &uc->uc_sigmask, puc);
+}
+
+#elif defined(__ia64)
+
+#ifndef __ISR_VALID
+  /* This ought to be in <bits/siginfo.h>... */
+# define __ISR_VALID    1
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long ip;
+    int is_write = 0;
+
+    ip = uc->uc_mcontext.sc_ip;
+    switch (host_signum) {
+    case SIGILL:
+    case SIGFPE:
+    case SIGSEGV:
+    case SIGBUS:
+    case SIGTRAP:
+        if (info->si_code && (info->si_segvflags & __ISR_VALID)) {
+            /* ISR.W (write-access) is bit 33:  */
+            is_write = (info->si_isr >> 33) & 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
+                             is_write,
+                             (sigset_t *)&uc->uc_sigmask, puc);
+}
+
+#elif defined(__s390__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    uint16_t *pinsn;
+    int is_write = 0;
+
+    pc = uc->uc_mcontext.psw.addr;
+
+    /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
+       of the normal 2 arguments.  The 3rd argument contains the "int_code"
+       from the hardware which does in fact contain the is_write value.
+       The rt signal handler, as far as I can tell, does not give this value
+       at all.  Not that we could get to it from here even if it were.  */
+    /* ??? This is not even close to complete, since it ignores all
+       of the read-modify-write instructions.  */
+    pinsn = (uint16_t *)pc;
+    switch (pinsn[0] >> 8) {
+    case 0x50: /* ST */
+    case 0x42: /* STC */
+    case 0x40: /* STH */
+        is_write = 1;
+        break;
+    case 0xc4: /* RIL format insns */
+        switch (pinsn[0] & 0xf) {
+        case 0xf: /* STRL */
+        case 0xb: /* STGRL */
+        case 0x7: /* STHRL */
+            is_write = 1;
+        }
+        break;
+    case 0xe3: /* RXY format insns */
+        switch (pinsn[2] & 0xff) {
+        case 0x50: /* STY */
+        case 0x24: /* STG */
+        case 0x72: /* STCY */
+        case 0x70: /* STHY */
+        case 0x8e: /* STPQ */
+        case 0x3f: /* STRVH */
+        case 0x3e: /* STRV */
+        case 0x2f: /* STRVG */
+            is_write = 1;
+        }
+        break;
+    }
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mips__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    greg_t pc = uc->uc_mcontext.pc;
+    int is_write;
+
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__hppa__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    struct siginfo *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
+    uint32_t insn = *(uint32_t *)pc;
+    int is_write = 0;
+
+    /* XXX: need kernel patch to get write flag faster.  */
+    switch (insn >> 26) {
+    case 0x1a: /* STW */
+    case 0x19: /* STH */
+    case 0x18: /* STB */
+    case 0x1b: /* STWM */
+        is_write = 1;
+        break;
+
+    case 0x09: /* CSTWX, FSTWX, FSTWS */
+    case 0x0b: /* CSTDX, FSTDX, FSTDS */
+        /* Distinguish from coprocessor load ... */
+        is_write = (insn >> 9) & 1;
+        break;
+
+    case 0x03:
+        switch ((insn >> 6) & 15) {
+        case 0xa: /* STWS */
+        case 0x9: /* STHS */
+        case 0x8: /* STBS */
+        case 0xe: /* STWAS */
+        case 0xc: /* STBYS */
+            is_write = 1;
+        }
+        break;
+    }
+
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#else
+
+#error host CPU specific signal handler needed
+
+#endif
diff --git a/vl.c b/vl.c
index 768439380917e5a7d684a0f2054bfa33636769b1..048dd314704e839d7244faf6769460eb932b29e7 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -47,9 +47,6 @@
 #include <dirent.h>
 #include <netdb.h>
 #include <sys/select.h>
-#ifdef CONFIG_SIMPLE_TRACE
-#include "trace.h"
-#endif
 
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
 #ifdef CONFIG_SDL
 #if defined(__APPLE__) || defined(main)
 #include <SDL.h>
+#ifndef CONFIG_MARU
 int qemu_main(int argc, char **argv, char **envp);
-/*
 int main(int argc, char **argv)
 {
     return qemu_main(argc, argv, NULL);
 }
-*/
 #undef main
 #define main qemu_main
 #endif
+#endif
 #endif /* CONFIG_SDL */
 
 #ifdef CONFIG_COCOA
@@ -116,6 +113,16 @@ int main(int argc, char **argv)
 #define main qemu_main
 #endif /* CONFIG_COCOA */
 
+#ifdef CONFIG_MARU
+#ifdef main
+#undef main
+#endif
+int qemu_main(int argc, char **argv, char **envp);
+#define main qemu_main
+#endif
+
+#include <glib.h>
+
 #include "hw/hw.h"
 #include "hw/boards.h"
 #include "hw/usb.h"
@@ -146,10 +153,13 @@ int main(int argc, char **argv)
 #include "audio/audio.h"
 #include "migration.h"
 #include "kvm.h"
+#include "hax.h"
+#include "qjson.h"
 #include "qemu-option.h"
 #include "qemu-config.h"
-#include "qemu-objects.h"
 #include "qemu-options.h"
+#include "qmp-commands.h"
+#include "main-loop.h"
 #ifdef CONFIG_VIRTFS
 #include "fsdev/qemu-fsdev.h"
 #endif
@@ -161,17 +171,19 @@ int main(int argc, char **argv)
 #include "slirp/libslirp.h"
 
 #include "trace.h"
+#include "trace/control.h"
 #include "qemu-queue.h"
 #include "cpus.h"
 #include "arch_init.h"
-#include "vl.h"
-#include "ui/qemu-spice.h"
-#include "sdb.h"
 
-#include "tizen/src/debug_ch.h"
+#include "ui/qemu-spice.h"
 
-//DEFAULT_DEBUG_CHANNEL(qemu);
-MULTI_DEBUG_CHANNEL(qemu, main);
+#ifdef CONFIG_MARU
+#include "tizen/src/maru_sdl.h"
+#include "tizen/src/option.h"
+#include "tizen/src/emul_state.h"
+#include "tizen/src/skin/maruskin_operation.h"
+#endif
 
 //#define DEBUG_NET
 //#define DEBUG_SLIRP
@@ -180,6 +192,14 @@ MULTI_DEBUG_CHANNEL(qemu, main);
 
 #define MAX_VIRTIO_CONSOLES 1
 
+#ifdef CONFIG_MARU
+#define VIRTIOGL_DEV_NAME "virtio-gl-pci"
+extern int tizen_base_port;
+int skin_disabled = 0;
+#endif
+
+int ret_hax_init = 0;
+
 static const char *data_dir;
 const char *bios_name = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
@@ -193,9 +213,7 @@ int mem_prealloc = 0; /* force preallocation of physical target memory */
 #endif
 int nb_nics;
 NICInfo nd_table[MAX_NICS];
-int vm_running;
 int autostart;
-int incoming_expected; /* Started with -incoming and waiting for incoming */
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
 QEMUClock *rtc_clock;
@@ -216,9 +234,12 @@ int smp_cpus = 1;
 int max_cpus = 0;
 int smp_cores = 1;
 int smp_threads = 1;
+#ifdef CONFIG_VNC
 const char *vnc_display;
+#endif
 int acpi_enabled = 1;
 int no_hpet = 0;
+int hax_disabled = 1;
 int fd_bootchk = 1;
 int no_reboot = 0;
 int no_shutdown = 0;
@@ -236,6 +257,15 @@ int ctrl_grab = 0;
 unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 int boot_menu;
+uint8_t *boot_splash_filedata;
+int boot_splash_filedata_size;
+uint8_t qemu_extra_params_fw[2];
+
+//virtio-gl
+#ifndef _WIN32
+extern int gl_acceleration_capability_check (void);
+int enable_gl = 1;
+#endif
 
 typedef struct FWBootEntry FWBootEntry;
 
@@ -252,18 +282,8 @@ int nb_numa_nodes;
 uint64_t node_mem[MAX_NODES];
 uint64_t node_cpumask[MAX_NODES];
 
-static QEMUTimer *nographic_timer;
-
 uint8_t qemu_uuid[16];
 
-int enable_gl = 1;
-
-extern void qemu_display_init(DisplayState *ds);
-extern void emulator_mutex_lock(void);
-extern void emulator_mutex_unlock(void);
-extern void emul_kill_all_process(void);
-void exit_emulator_post_process( void );
-
 static QEMUBootSetHandler *boot_set_handler;
 static void *boot_set_opaque;
 
@@ -273,9 +293,13 @@ static NotifierList exit_notifiers =
 static NotifierList machine_init_done_notifiers =
     NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
 
+static int tcg_allowed = 1;
 int kvm_allowed = 0;
+int xen_allowed = 0;
+int hax_allowed = 0;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
+static int tcg_tb_size;
 
 static int default_serial = 1;
 static int default_parallel = 1;
@@ -293,15 +317,28 @@ static struct {
     { .driver = "isa-serial",           .flag = &default_serial    },
     { .driver = "isa-parallel",         .flag = &default_parallel  },
     { .driver = "isa-fdc",              .flag = &default_floppy    },
+    { .driver = "ide-cd",               .flag = &default_cdrom     },
+    { .driver = "ide-hd",               .flag = &default_cdrom     },
     { .driver = "ide-drive",            .flag = &default_cdrom     },
+    { .driver = "scsi-cd",              .flag = &default_cdrom     },
     { .driver = "virtio-serial-pci",    .flag = &default_virtcon   },
     { .driver = "virtio-serial-s390",   .flag = &default_virtcon   },
     { .driver = "virtio-serial",        .flag = &default_virtcon   },
     { .driver = "VGA",                  .flag = &default_vga       },
     { .driver = "cirrus-vga",           .flag = &default_vga       },
     { .driver = "vmware-svga",          .flag = &default_vga       },
+    { .driver = "isa-vga",              .flag = &default_vga       },
+    { .driver = "qxl-vga",              .flag = &default_vga       },
 };
 
+static void res_free(void)
+{
+    if (boot_splash_filedata != NULL) {
+        g_free(boot_splash_filedata);
+        boot_splash_filedata = NULL;
+    }
+}
+
 static int default_driver_check(QemuOpts *opts, void *opaque)
 {
     const char *driver = qemu_opt_get(opts, "driver");
@@ -317,8 +354,117 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
     return 0;
 }
 
+/***********************************************************/
+/* QEMU state */
+
+static RunState current_run_state = RUN_STATE_PRELAUNCH;
+
+typedef struct {
+    RunState from;
+    RunState to;
+} RunStateTransition;
+
+static const RunStateTransition runstate_transitions_def[] = {
+    /*     from      ->     to      */
+    { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
+
+    { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
+
+    { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
+    { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
+    { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
+    { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
+
+    { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
+
+    { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
+
+    { RUN_STATE_RUNNING, RUN_STATE_DEBUG },
+    { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
+    { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR },
+    { RUN_STATE_RUNNING, RUN_STATE_PAUSED },
+    { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM },
+    { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM },
+    { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN },
+    { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
+
+    { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
+
+    { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
+    { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
+    { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
+
+    { RUN_STATE_MAX, RUN_STATE_MAX },
+};
+
+static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
+
+bool runstate_check(RunState state)
+{
+    return current_run_state == state;
+}
+
+void runstate_init(void)
+{
+    const RunStateTransition *p;
+
+    memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
+
+    for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
+        runstate_valid_transitions[p->from][p->to] = true;
+    }
+}
+
+/* This function will abort() on invalid state transitions */
+void runstate_set(RunState new_state)
+{
+    assert(new_state < RUN_STATE_MAX);
+
+    if (!runstate_valid_transitions[current_run_state][new_state]) {
+        fprintf(stderr, "ERROR: invalid runstate transition: '%s' -> '%s'\n",
+                RunState_lookup[current_run_state],
+                RunState_lookup[new_state]);
+        abort();
+    }
+
+    current_run_state = new_state;
+}
+
+int runstate_is_running(void)
+{
+    return runstate_check(RUN_STATE_RUNNING);
+}
+
+StatusInfo *qmp_query_status(Error **errp)
+{
+    StatusInfo *info = g_malloc0(sizeof(*info));
+
+    info->running = runstate_is_running();
+    info->singlestep = singlestep;
+    info->status = current_run_state;
+
+    return info;
+}
+
 /***********************************************************/
 /* real time host monotonic timer */
+
 /***********************************************************/
 /* host time/date access */
 void qemu_get_timedate(struct tm *tm, int offset)
@@ -348,8 +494,11 @@ int qemu_timedate_diff(struct tm *tm)
     if (rtc_date_offset == -1)
         if (rtc_utc)
             seconds = mktimegm(tm);
-        else
-            seconds = mktime(tm);
+        else {
+            struct tm tmp = *tm;
+            tmp.tm_isdst = -1; /* use timezone to figure it out */
+            seconds = mktime(&tmp);
+       }
     else
         seconds = mktimegm(tm) + rtc_date_offset;
 
@@ -462,7 +611,7 @@ static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
         if (vlan->id == id)
             return &vlan->net;
     }
-    vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
+    vlan = g_malloc0(sizeof(struct bt_vlan_s));
     vlan->id = id;
     pvlan = &first_bt_vlan;
     while (*pvlan != NULL)
@@ -737,7 +886,7 @@ static void restore_boot_devices(void *opaque)
     qemu_boot_set(standard_boot_devices);
 
     qemu_unregister_reset(restore_boot_devices, standard_boot_devices);
-    qemu_free(standard_boot_devices);
+    g_free(standard_boot_devices);
 }
 
 void add_boot_device_path(int32_t bootindex, DeviceState *dev,
@@ -751,9 +900,9 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev,
 
     assert(dev != NULL || suffix != NULL);
 
-    node = qemu_mallocz(sizeof(FWBootEntry));
+    node = g_malloc0(sizeof(FWBootEntry));
     node->bootindex = bootindex;
-    node->suffix = suffix ? qemu_strdup(suffix) : NULL;
+    node->suffix = suffix ? g_strdup(suffix) : NULL;
     node->dev = dev;
 
     QTAILQ_FOREACH(i, &fw_boot_order, link) {
@@ -771,7 +920,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
  *
@@ -794,24 +943,24 @@ char *get_boot_devices_list(uint32_t *size)
         if (i->suffix && devpath) {
             size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
 
-            bootpath = qemu_malloc(bootpathlen);
+            bootpath = g_malloc(bootpathlen);
             snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
-            qemu_free(devpath);
+            g_free(devpath);
         } else if (devpath) {
             bootpath = devpath;
         } else {
-            bootpath = qemu_strdup(i->suffix);
-            assert(bootpath);
+            assert(i->suffix);
+            bootpath = g_strdup(i->suffix);
         }
 
         if (total) {
             list[total-1] = '\n';
         }
         len = strlen(bootpath) + 1;
-        list = qemu_realloc(list, total + len);
+        list = g_realloc(list, total + len);
         memcpy(&list[total], bootpath, len);
         total += len;
-        qemu_free(bootpath);
+        g_free(bootpath);
     }
 
     *size = total;
@@ -838,8 +987,8 @@ static void numa_add(const char *optarg)
             node_mem[nodenr] = 0;
         } else {
             int64_t sval;
-            sval = strtosz(option, NULL);
-            if (sval < 0) {
+            sval = strtosz(option, &endptr);
+            if (sval < 0 || *endptr) {
                 fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
                 exit(1);
             }
@@ -906,9 +1055,7 @@ static void smp_parse(const char *optarg)
             threads = threads > 0 ? threads : 1;
             cores = smp / (sockets * threads);
         } else {
-          if (sockets) {
-                       threads = smp / (cores * sockets);
-                 }
+            threads = smp / (cores * sockets);
         }
     }
     smp_cpus = smp;
@@ -935,9 +1082,13 @@ static int usb_device_add(const char *devname)
         goto done;
 
     /* the other ones */
+#ifndef CONFIG_LINUX
+    /* only the linux version is qdev-ified, usb-bsd still needs this */
     if (strstart(devname, "host:", &p)) {
         dev = usb_host_device_open(p);
-    } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+    } else
+#endif
+    if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
         dev = usb_bt_init(devname[2] ? hci_init(p) :
                         bt_new_hci(qemu_find_bt_vlan(0)));
     } else {
@@ -1008,7 +1159,7 @@ void pcmcia_socket_register(PCMCIASocket *socket)
 {
     struct pcmcia_socket_entry_s *entry;
 
-    entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
+    entry = g_malloc(sizeof(struct pcmcia_socket_entry_s));
     entry->socket = socket;
     entry->next = pcmcia_sockets;
     pcmcia_sockets = entry;
@@ -1022,7 +1173,7 @@ void pcmcia_socket_unregister(PCMCIASocket *socket)
     for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
         if (entry->socket == socket) {
             *ptr = entry->next;
-            qemu_free(entry);
+            g_free(entry);
         }
 }
 
@@ -1039,68 +1190,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 */
 
@@ -1152,7 +1241,6 @@ static void gui_update(void *opaque)
     DisplayState *ds = opaque;
     DisplayChangeListener *dcl = ds->listeners;
 
-    qemu_flush_coalesced_mmio_buffer();
     dpy_refresh(ds);
 
     while (dcl != NULL) {
@@ -1161,15 +1249,7 @@ static void gui_update(void *opaque)
             interval = dcl->gui_timer_interval;
         dcl = dcl->next;
     }
-    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
-}
-
-static void nographic_update(void *opaque)
-{
-    uint64_t interval = GUI_REFRESH_INTERVAL;
-
-    qemu_flush_coalesced_mmio_buffer();
-    qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
+    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
 }
 
 struct vm_change_state_entry {
@@ -1185,7 +1265,7 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
 {
     VMChangeStateEntry *e;
 
-    e = qemu_mallocz(sizeof (*e));
+    e = g_malloc0(sizeof (*e));
 
     e->cb = cb;
     e->opaque = opaque;
@@ -1196,26 +1276,26 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
 void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
 {
     QLIST_REMOVE (e, entries);
-    qemu_free (e);
+    g_free (e);
 }
 
-void vm_state_notify(int running, int reason)
+void vm_state_notify(int running, RunState state)
 {
     VMChangeStateEntry *e;
 
-    trace_vm_state_notify(running, reason);
+    trace_vm_state_notify(running, state);
 
     for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
-        e->cb(e->opaque, running, reason);
+        e->cb(e->opaque, running, state);
     }
 }
 
 void vm_start(void)
 {
-    if (!vm_running) {
+    if (!runstate_is_running()) {
         cpu_enable_ticks();
-        vm_running = 1;
-        vm_state_notify(1, 0);
+        runstate_set(RUN_STATE_RUNNING);
+        vm_state_notify(1, RUN_STATE_RUNNING);
         resume_all_vcpus();
         monitor_protocol_event(QEVENT_RESUME, NULL);
     }
@@ -1232,10 +1312,21 @@ typedef struct QEMUResetEntry {
 static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
     QTAILQ_HEAD_INITIALIZER(reset_handlers);
 static int reset_requested;
-static int shutdown_requested;
+static int shutdown_requested, shutdown_signal = -1;
+static pid_t shutdown_pid;
 static int powerdown_requested;
-int debug_requested;
-int vmstop_requested;
+static int debug_requested;
+static RunState vmstop_requested = RUN_STATE_MAX;
+
+int qemu_shutdown_requested_get(void)
+{
+    return shutdown_requested;
+}
+
+int qemu_reset_requested_get(void)
+{
+    return reset_requested;
+}
 
 int qemu_shutdown_requested(void)
 {
@@ -1244,6 +1335,22 @@ int qemu_shutdown_requested(void)
     return r;
 }
 
+void qemu_kill_report(void)
+{
+    if (shutdown_signal != -1) {
+        fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal);
+        if (shutdown_pid == 0) {
+            /* This happens for eg ^C at the terminal, so it's worth
+             * avoiding printing an odd message in that case.
+             */
+            fputc('\n', stderr);
+        } else {
+            fprintf(stderr, " from pid " FMT_pid "\n", shutdown_pid);
+        }
+        shutdown_signal = -1;
+    }
+}
+
 int qemu_reset_requested(void)
 {
     int r = reset_requested;
@@ -1265,16 +1372,21 @@ static int qemu_debug_requested(void)
     return r;
 }
 
-static int qemu_vmstop_requested(void)
+/* We use RUN_STATE_MAX but any invalid value will do */
+static bool qemu_vmstop_requested(RunState *r)
 {
-    int r = vmstop_requested;
-    vmstop_requested = 0;
-    return r;
+    if (vmstop_requested < RUN_STATE_MAX) {
+        *r = vmstop_requested;
+        vmstop_requested = RUN_STATE_MAX;
+        return true;
+    }
+
+    return false;
 }
 
 void qemu_register_reset(QEMUResetHandler *func, void *opaque)
 {
-    QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry));
+    QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
 
     re->func = func;
     re->opaque = opaque;
@@ -1288,13 +1400,13 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
     QTAILQ_FOREACH(re, &reset_handlers, entry) {
         if (re->func == func && re->opaque == opaque) {
             QTAILQ_REMOVE(&reset_handlers, re, entry);
-            qemu_free(re);
+            g_free(re);
             return;
         }
     }
 }
 
-void qemu_system_reset(void)
+void qemu_system_reset(bool report)
 {
     QEMUResetEntry *re, *nre;
 
@@ -1302,7 +1414,9 @@ void qemu_system_reset(void)
     QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
         re->func(re->opaque);
     }
-    monitor_protocol_event(QEVENT_RESET, NULL);
+    if (report) {
+        monitor_protocol_event(QEVENT_RESET, NULL);
+    }
     cpu_synchronize_all_post_reset();
 }
 
@@ -1313,23 +1427,27 @@ void qemu_system_reset_request(void)
     } else {
         reset_requested = 1;
     }
+    cpu_stop_current();
     qemu_notify_event();
 }
 
-void qemu_system_shutdown_request(void)
+void qemu_system_killed(int signal, pid_t pid)
 {
+    shutdown_signal = signal;
+    shutdown_pid = pid;
+    no_shutdown = 0;
 
-#if 1 /* graceful shutdown */
-    /* graceful shutdown starts with 'qemu_system_shutdown_request'. */
-       exit_emulator_post_process();
+#ifdef CONFIG_MARU
+    shutdown_qemu_gracefully();
+#else
+    qemu_system_shutdown_request();
 #endif
+}
 
-#ifndef _SDK_SIMULATOR
-       emul_kill_all_process();
-#endif
+void qemu_system_shutdown_request(void)
+{
     shutdown_requested = 1;
     qemu_notify_event();
-
 }
 
 void qemu_system_powerdown_request(void)
@@ -1338,156 +1456,77 @@ void qemu_system_powerdown_request(void)
     qemu_notify_event();
 }
 
-void main_loop_wait(int nonblocking)
+void qemu_system_debug_request(void)
 {
-    IOHandlerRecord *ioh;
-    fd_set rfds, wfds, xfds;
-    int ret, nfds;
-    struct timeval tv;
-    int timeout;
+    debug_requested = 1;
+    qemu_notify_event();
+}
 
-    if (nonblocking)
-        timeout = 0;
-    else {
-        timeout = qemu_calculate_timeout();
-        qemu_bh_update_timeout(&timeout);
-    }
+void qemu_system_vmstop_request(RunState state)
+{
+    vmstop_requested = state;
+    qemu_notify_event();
+}
 
-    os_host_main_loop_wait(&timeout);
+qemu_irq qemu_system_powerdown;
 
-    /* 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;
+static bool main_loop_should_exit(void)
+{
+    RunState r;
+    if (qemu_debug_requested()) {
+        vm_stop(RUN_STATE_DEBUG);
+    }
+    if (qemu_shutdown_requested()) {
+        qemu_kill_report();
+        monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
+        if (no_shutdown) {
+            vm_stop(RUN_STATE_SHUTDOWN);
+        } else {
+            return true;
         }
     }
-
-    tv.tv_sec = timeout / 1000;
-    tv.tv_usec = (timeout % 1000) * 1000;
-
-    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);
-            }
+    if (qemu_reset_requested()) {
+        pause_all_vcpus();
+        cpu_synchronize_all_states();
+        qemu_system_reset(VMRESET_REPORT);
+        resume_all_vcpus();
+        if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+            runstate_check(RUN_STATE_SHUTDOWN)) {
+            runstate_set(RUN_STATE_PAUSED);
         }
     }
-
-    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
-
-#ifndef _SDK_SIMULATOR  
-       emulator_mutex_lock();
-#endif
-
-       qemu_run_all_timers();
-
-#ifndef _SDK_SIMULATOR  
-       emulator_mutex_unlock();
-#endif
-
-    /* Check bottom-halves last in case any of the earlier events triggered
-       them.  */
-    qemu_bh_poll();
-
-}
-
-static int vm_can_run(void)
-{
-    if (powerdown_requested)
-        return 0;
-    if (reset_requested)
-        return 0;
-    if (shutdown_requested)
-        return 0;
-    if (debug_requested)
-        return 0;
-    return 1;
+    if (qemu_powerdown_requested()) {
+        monitor_protocol_event(QEVENT_POWERDOWN, NULL);
+        qemu_irq_raise(qemu_system_powerdown);
+    }
+    if (qemu_vmstop_requested(&r)) {
+        vm_stop(r);
+    }
+    return false;
 }
 
-qemu_irq qemu_system_powerdown;
-
 static void main_loop(void)
 {
-    int r;
-
-    qemu_main_loop_start();
-
-    for (;;) {
-        do {
-            bool nonblocking = false;
+    bool nonblocking;
+    int last_io = 0;
 #ifdef CONFIG_PROFILER
-            int64_t ti;
+    int64_t ti;
 #endif
-#ifndef CONFIG_IOTHREAD
-            nonblocking = cpu_exec_all();
+
+#ifdef CONFIG_HAX
+    hax_sync_vcpus();
 #endif
+
+    do {
+        nonblocking = !(kvm_enabled()|| hax_enabled()) && last_io > 0;
 #ifdef CONFIG_PROFILER
-            ti = profile_getclock();
+        ti = profile_getclock();
 #endif
-            main_loop_wait(nonblocking);
+        last_io = main_loop_wait(nonblocking);
 #ifdef CONFIG_PROFILER
-            dev_time += profile_getclock() - ti;
+        dev_time += profile_getclock() - ti;
 #endif
-        } while (vm_can_run());
-
-        if ((r = qemu_debug_requested())) {
-            vm_stop(r);
-        }
-        if (qemu_shutdown_requested()) {
-            monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
-            if (no_shutdown) {
-                vm_stop(0);
-                no_shutdown = 0;
-            } else
-                break;
-        }
-        if (qemu_reset_requested()) {
-            pause_all_vcpus();
-            qemu_system_reset();
-            resume_all_vcpus();
-        }
-        if (qemu_powerdown_requested()) {
-            monitor_protocol_event(QEVENT_POWERDOWN, NULL);
-            qemu_irq_raise(qemu_system_powerdown);
-        }
-        if ((r = qemu_vmstop_requested())) {
-            vm_stop(r);
-        }
-    }
-    bdrv_close_all();
-    pause_all_vcpus();
+    } while (!main_loop_should_exit());
 }
 
 static void version(void)
@@ -1559,8 +1598,10 @@ static void select_vgahw (const char *p)
         vga_interface_type = VGA_XENFB;
     } else if (strstart(p, "qxl", &opts)) {
         vga_interface_type = VGA_QXL;
-    } else if (strstart(p, "tizen", &opts)) { // by caramis...
-        vga_interface_type = VGA_TIZEN;
+#ifdef CONFIG_MARU
+    } else if (strstart(p, "maru", &opts)) {
+        vga_interface_type = VGA_MARU;
+#endif
     } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
@@ -1581,6 +1622,100 @@ static void select_vgahw (const char *p)
     }
 }
 
+static DisplayType select_display(const char *p)
+{
+    const char *opts;
+    DisplayType display = DT_DEFAULT;
+
+    if (strstart(p, "sdl", &opts)) {
+#ifdef CONFIG_SDL
+        display = DT_SDL;
+        while (*opts) {
+            const char *nextopt;
+
+            if (strstart(opts, ",frame=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    no_frame = 0;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    no_frame = 1;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",alt_grab=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    alt_grab = 1;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    alt_grab = 0;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",ctrl_grab=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    ctrl_grab = 1;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    ctrl_grab = 0;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",window_close=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    no_quit = 0;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    no_quit = 1;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else {
+            invalid_sdl_args:
+                fprintf(stderr, "Invalid SDL option string: %s\n", p);
+                exit(1);
+            }
+            opts = nextopt;
+        }
+#else
+        fprintf(stderr, "SDL support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "vnc", &opts)) {
+#ifdef CONFIG_VNC
+        display_remote++;
+
+        if (*opts) {
+            const char *nextopt;
+
+            if (strstart(opts, "=", &nextopt)) {
+                vnc_display = nextopt;
+            }
+        }
+        if (!vnc_display) {
+            fprintf(stderr, "VNC requires a display argument vnc=<display>\n");
+            exit(1);
+        }
+#else
+        fprintf(stderr, "VNC support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "curses", &opts)) {
+#ifdef CONFIG_CURSES
+        display = DT_CURSES;
+#else
+        fprintf(stderr, "Curses support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "none", &opts)) {
+        display = DT_NONE;
+    } else {
+        fprintf(stderr, "Unknown display type: %s\n", p);
+        exit(1);
+    }
+
+    return display;
+}
+
 static int balloon_parse(const char *arg)
 {
     QemuOpts *opts;
@@ -1599,7 +1734,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;
     }
 
@@ -1615,7 +1750,7 @@ char *qemu_find_file(int type, const char *name)
     /* If name contains path separators then try it as a straight path.  */
     if ((strchr(name, '/') || strchr(name, '\\'))
         && access(name, R_OK) == 0) {
-        return qemu_strdup(name);
+        return g_strdup(name);
     }
     switch (type) {
     case QEMU_FILE_TYPE_BIOS:
@@ -1628,10 +1763,10 @@ char *qemu_find_file(int type, const char *name)
         abort();
     }
     len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
-    buf = qemu_mallocz(len);
+    buf = g_malloc0(len);
     snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
     if (access(buf, R_OK)) {
-        qemu_free(buf);
+        g_free(buf);
         return NULL;
     }
     return buf;
@@ -1646,6 +1781,17 @@ static int device_init_func(QemuOpts *opts, void *opaque)
 {
     DeviceState *dev;
 
+#ifndef _WIN32
+       // virtio-gl pci device
+       if (!enable_gl) {
+               // ignore virtio-gl-pci device, even if users set it in option.
+               const char *driver = qemu_opt_get(opts, "driver");
+               if (driver && (strcmp (driver, VIRTIOGL_DEV_NAME) == 0)) {
+                       return 0;
+               }
+       }
+#endif
+       
     dev = qdev_device_add(opts);
     if (!dev)
         return -1;
@@ -1656,7 +1802,7 @@ static int chardev_init_func(QemuOpts *opts, void *opaque)
 {
     CharDriverState *chr;
 
-    chr = qemu_chr_open_opts(opts, NULL);
+    chr = qemu_chr_new_from_opts(opts, NULL);
     if (!chr)
         return -1;
     return 0;
@@ -1762,7 +1908,7 @@ static void add_device_config(int type, const char *cmdline)
 {
     struct device_config *conf;
 
-    conf = qemu_mallocz(sizeof(*conf));
+    conf = g_malloc0(sizeof(*conf));
     conf->type = type;
     conf->cmdline = cmdline;
     QTAILQ_INSERT_TAIL(&device_configs, conf, next);
@@ -1795,7 +1941,7 @@ static int serial_parse(const char *devname)
         exit(1);
     }
     snprintf(label, sizeof(label), "serial%d", index);
-    serial_hds[index] = qemu_chr_open(label, devname, NULL);
+    serial_hds[index] = qemu_chr_new(label, devname, NULL);
     if (!serial_hds[index]) {
         fprintf(stderr, "qemu: could not open serial device '%s': %s\n",
                 devname, strerror(errno));
@@ -1817,7 +1963,7 @@ static int parallel_parse(const char *devname)
         exit(1);
     }
     snprintf(label, sizeof(label), "parallel%d", index);
-    parallel_hds[index] = qemu_chr_open(label, devname, NULL);
+    parallel_hds[index] = qemu_chr_new(label, devname, NULL);
     if (!parallel_hds[index]) {
         fprintf(stderr, "qemu: could not open parallel device '%s': %s\n",
                 devname, strerror(errno));
@@ -1848,7 +1994,7 @@ static int virtcon_parse(const char *devname)
     qemu_opt_set(dev_opts, "driver", "virtconsole");
 
     snprintf(label, sizeof(label), "virtcon%d", index);
-    virtcon_hds[index] = qemu_chr_open(label, devname, NULL);
+    virtcon_hds[index] = qemu_chr_new(label, devname, NULL);
     if (!virtcon_hds[index]) {
         fprintf(stderr, "qemu: could not open virtio console '%s': %s\n",
                 devname, strerror(errno));
@@ -1864,7 +2010,7 @@ static int debugcon_parse(const char *devname)
 {   
     QemuOpts *opts;
 
-    if (!qemu_chr_open("debugcon", devname, NULL)) {
+    if (!qemu_chr_new("debugcon", devname, NULL)) {
         exit(1);
     }
     opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1);
@@ -1877,6 +2023,124 @@ static int debugcon_parse(const char *devname)
     return 0;
 }
 
+static QEMUMachine *machine_parse(const char *name)
+{
+    QEMUMachine *m, *machine = NULL;
+
+    if (name) {
+        machine = find_machine(name);
+    }
+    if (machine) {
+        return machine;
+    }
+    printf("Supported machines are:\n");
+    for (m = first_machine; m != NULL; m = m->next) {
+        if (m->alias) {
+            printf("%-10s %s (alias of %s)\n", m->alias, m->desc, m->name);
+        }
+        printf("%-10s %s%s\n", m->name, m->desc,
+               m->is_default ? " (default)" : "");
+    }
+    exit(!name || *name != '?');
+}
+
+static int tcg_init(void)
+{
+    int ret = 0;
+    tcg_exec_init(tcg_tb_size * 1024 * 1024);
+#ifdef CONFIG_HAX
+    if (!hax_disabled)
+    {
+       ret = hax_init();
+       ret_hax_init = ret;
+       if (ret && (ret != -ENOSPC))
+               dprint("No accelerator found.\n");
+       else {
+               dprint("HAX is %s and emulator runs in %s mode.\n", 
+               !ret ? "working" : "not working", 
+               !ret ? "fast virt" : "emulation");
+               return 0;
+       }
+
+    } else
+       dprint("HAX is disabled and emulator runs in emulation mode.\n");
+#endif 
+    return ret;
+}
+
+static struct {
+    const char *opt_name;
+    const char *name;
+    int (*available)(void);
+    int (*init)(void);
+    int *allowed;
+} accel_list[] = {
+    { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
+    { "xen", "Xen", xen_available, xen_init, &xen_allowed },
+    { "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
+};
+
+static int configure_accelerator(void)
+{
+    const char *p = NULL;
+    char buf[10];
+    int i, ret;
+    bool accel_initalised = 0;
+    bool init_failed = 0;
+
+    QemuOptsList *list = qemu_find_opts("machine");
+    if (!QTAILQ_EMPTY(&list->head)) {
+        p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
+    }
+
+    if (p == NULL) {
+        /* Use the default "accelerator", tcg */
+        p = "tcg";
+    }
+
+    while (!accel_initalised && *p != '\0') {
+        if (*p == ':') {
+            p++;
+        }
+        p = get_opt_name(buf, sizeof (buf), p, ':');
+        for (i = 0; i < ARRAY_SIZE(accel_list); i++) {
+            if (strcmp(accel_list[i].opt_name, buf) == 0) {
+                *(accel_list[i].allowed) = 1;
+                ret = accel_list[i].init();
+                if (ret < 0) {
+                    init_failed = 1;
+                    if (!accel_list[i].available()) {
+                        printf("%s not supported for this target\n",
+                               accel_list[i].name);
+                    } else {
+                        fprintf(stderr, "failed to initialize %s: %s\n",
+                                accel_list[i].name,
+                                strerror(-ret));
+                    }
+                    *(accel_list[i].allowed) = 0;
+                } else {
+                    accel_initalised = 1;
+                }
+                break;
+            }
+        }
+        if (i == ARRAY_SIZE(accel_list)) {
+            fprintf(stderr, "\"%s\" accelerator does not exist.\n", buf);
+        }
+    }
+
+    if (!accel_initalised) {
+        fprintf(stderr, "No accelerator found!\n");
+        exit(1);
+    }
+
+    if (init_failed) {
+        fprintf(stderr, "Back to %s accelerator.\n", accel_list[i].name);
+    }
+
+    return !accel_initalised;
+}
+
 void qemu_add_exit_notifier(Notifier *notify)
 {
     notifier_list_add(&exit_notifiers, notify);
@@ -1889,7 +2153,7 @@ void qemu_remove_exit_notifier(Notifier *notify)
 
 static void qemu_run_exit_notifiers(void)
 {
-    notifier_list_notify(&exit_notifiers);
+    notifier_list_notify(&exit_notifiers, NULL);
 }
 
 void qemu_add_machine_init_done_notifier(Notifier *notify)
@@ -1899,7 +2163,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify)
 
 static void qemu_run_machine_init_done_notifiers(void)
 {
-    notifier_list_notify(&machine_init_done_notifiers);
+    notifier_list_notify(&machine_init_done_notifiers, NULL);
 }
 
 static const QEMUOption *lookup_opt(int argc, char **argv,
@@ -1942,10 +2206,48 @@ static const QEMUOption *lookup_opt(int argc, char **argv,
     return popt;
 }
 
-#if defined(CONFIG_SDL)
-extern int use_qemu_display;
-#endif
-int qemu_main(int argc, char **argv, char **envp)
+static gpointer malloc_and_trace(gsize n_bytes)
+{
+    void *ptr = malloc(n_bytes);
+    trace_g_malloc(n_bytes, ptr);
+    return ptr;
+}
+
+static gpointer realloc_and_trace(gpointer mem, gsize n_bytes)
+{
+    void *ptr = realloc(mem, n_bytes);
+    trace_g_realloc(mem, n_bytes, ptr);
+    return ptr;
+}
+
+static void free_and_trace(gpointer mem)
+{
+    trace_g_free(mem);
+    free(mem);
+}
+
+// virtio-gl pci device lookup
+typedef struct {
+    const char *device_name;
+    int found;
+} device_opt_finding_t;
+
+static int find_device_opt (QemuOpts *opts, void *opaque)
+{
+    device_opt_finding_t *devp = (device_opt_finding_t *) opaque;
+    if (devp->found == 1) {
+        return 0;
+    }
+
+    const char *str = qemu_opt_get (opts, "driver");
+    if (strcmp (str, devp->device_name) == 0) {
+        devp->found = 1;
+    }
+    return 0;
+}
+
+int use_qemu_display = 0; //0:use tizen qemu sdl, 1:use original qemu sdl
+int main(int argc, char **argv, char **envp)
 {
     const char *gdbstub_dev = NULL;
     int i;
@@ -1964,19 +2266,39 @@ int qemu_main(int argc, char **argv, char **envp)
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
-    int tb_size;
     const char *pid_file = NULL;
     const char *incoming = NULL;
+#ifdef CONFIG_VNC
     int show_vnc_port = 0;
+#endif
     int defconfig = 1;
-
-#ifdef CONFIG_SIMPLE_TRACE
+    const char *log_mask = NULL;
+    const char *log_file = NULL;
+    GMemVTable mem_trace = {
+        .malloc = malloc_and_trace,
+        .realloc = realloc_and_trace,
+        .free = free_and_trace,
+    };
+    const char *trace_events = NULL;
     const char *trace_file = NULL;
+
+#ifdef CONFIG_MARU
+    #define MIDBUF  128
+    char proxy[MIDBUF] ={0}, dns1[MIDBUF] = {0}, dns2[MIDBUF] = {0};
 #endif
+
     atexit(qemu_run_exit_notifiers);
     error_set_progname(argv[0]);
 
+    g_mem_set_vtable(&mem_trace);
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+
+    runstate_init();
+
     init_clocks();
+    rtc_clock = host_clock;
 
     qemu_cache_utils_init(envp);
 
@@ -2002,7 +2324,6 @@ int qemu_main(int argc, char **argv, char **envp)
     nb_numa_nodes = 0;
     nb_nics = 0;
 
-    tb_size = 0;
     autostart= 1;
 
     /* first pass of option parsing */
@@ -2056,20 +2377,7 @@ int qemu_main(int argc, char **argv, char **envp)
             }
             switch(popt->index) {
             case QEMU_OPTION_M:
-                machine = find_machine(optarg);
-                if (!machine) {
-                    QEMUMachine *m;
-                    printf("Supported machines are:\n");
-                    for(m = first_machine; m != NULL; m = m->next) {
-                        if (m->alias)
-                            printf("%-10s %s (alias of %s)\n",
-                                   m->alias, m->desc, m->name);
-                        printf("%-10s %s%s\n",
-                               m->name, m->desc,
-                               m->is_default ? " (default)" : "");
-                    }
-                    exit(*optarg != '?');
-                }
+                machine = machine_parse(optarg);
                 break;
             case QEMU_OPTION_cpu:
                 /* hw initialization will check this */
@@ -2186,22 +2494,44 @@ int qemu_main(int argc, char **argv, char **envp)
                 }
                 numa_add(optarg);
                 break;
+            case QEMU_OPTION_display:
+                display_type = select_display(optarg);
+                break;
             case QEMU_OPTION_nographic:
                 display_type = DT_NOGRAPHIC;
                 break;
-#ifdef CONFIG_CURSES
             case QEMU_OPTION_curses:
+#ifdef CONFIG_CURSES
                 display_type = DT_CURSES;
-                break;
+#else
+                fprintf(stderr, "Curses support is disabled\n");
+                exit(1);
 #endif
+                break;
             case QEMU_OPTION_portrait:
-                graphic_rotate = 1;
+                graphic_rotate = 90;
+                break;
+            case QEMU_OPTION_rotate:
+                graphic_rotate = strtol(optarg, (char **) &optarg, 10);
+                if (graphic_rotate != 0 && graphic_rotate != 90 &&
+                    graphic_rotate != 180 && graphic_rotate != 270) {
+                    fprintf(stderr,
+                        "qemu: only 90, 180, 270 deg rotation is available\n");
+                    exit(1);
+                }
                 break;
             case QEMU_OPTION_kernel:
                 kernel_filename = optarg;
                 break;
             case QEMU_OPTION_append:
+#ifdef CONFIG_MARU
+                gethostproxy(proxy);
+                gethostDNS(dns1, dns2);
+                kernel_cmdline = g_strdup_printf("%s sdb_port=%d, proxy=%s dns1=%s dns2=%s", optarg, tizen_base_port, proxy, dns1, dns2);
+                fprintf(stdout, "kernel command : %s\n", kernel_cmdline);
+#else
                 kernel_cmdline = optarg;
+#endif
                 break;
             case QEMU_OPTION_cdrom:
                 drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
@@ -2209,7 +2539,8 @@ int qemu_main(int argc, char **argv, char **envp)
             case QEMU_OPTION_boot:
                 {
                     static const char * const params[] = {
-                        "order", "once", "menu", NULL
+                        "order", "once", "menu",
+                        "splash", "splash-time", NULL
                     };
                     char buf[sizeof(boot_devices)];
                     char *standard_boot_devices;
@@ -2234,7 +2565,7 @@ int qemu_main(int argc, char **argv, char **envp)
                         if (get_param_value(buf, sizeof(buf),
                                             "once", optarg)) {
                             validate_bootdevices(buf);
-                            standard_boot_devices = qemu_strdup(boot_devices);
+                            standard_boot_devices = g_strdup(boot_devices);
                             pstrcpy(boot_devices, sizeof(boot_devices), buf);
                             qemu_register_reset(restore_boot_devices,
                                                 standard_boot_devices);
@@ -2252,6 +2583,8 @@ int qemu_main(int argc, char **argv, char **envp)
                                 exit(1);
                             }
                         }
+                        qemu_opts_parse(qemu_find_opts("boot-opts"),
+                                        optarg, 0);
                     }
                 }
                 break;
@@ -2312,18 +2645,14 @@ int qemu_main(int argc, char **argv, char **envp)
                 break;
             case QEMU_OPTION_m: {
                 int64_t value;
+                char *end;
 
-                value = strtosz(optarg, NULL);
-                if (value < 0) {
+                value = strtosz(optarg, &end);
+                if (value < 0 || *end) {
                     fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
                     exit(1);
                 }
 
-                /* On 32-bit hosts, QEMU is limited by virtual address space */
-                if (value > (2047 << 20) && HOST_LONG_BITS == 32) {
-                    fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
-                    exit(1);
-                }
                 if (value != (uint64_t)(ram_addr_t)value) {
                     fprintf(stderr, "qemu: ram size too large\n");
                     exit(1);
@@ -2340,7 +2669,10 @@ int qemu_main(int argc, char **argv, char **envp)
                 break;
 #endif
             case QEMU_OPTION_d:
-                set_cpu_log(optarg);
+                log_mask = optarg;
+                break;
+            case QEMU_OPTION_D:
+                log_file = optarg;
                 break;
             case QEMU_OPTION_s:
                 gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
@@ -2445,9 +2777,9 @@ int qemu_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;
+                const char *writeout;
 
                 olist = qemu_find_opts("virtfs");
                 if (!olist) {
@@ -2460,51 +2792,63 @@ int qemu_main(int argc, char **argv, char **envp)
                     exit(1);
                 }
 
-                if (qemu_opt_get(opts, "fstype") == NULL ||
+                if (qemu_opt_get(opts, "fsdriver") == NULL ||
                         qemu_opt_get(opts, "mount_tag") == NULL ||
-                        qemu_opt_get(opts, "path") == NULL ||
-                        qemu_opt_get(opts, "security_model") == NULL) {
-                    fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
-                            "security_model=[mapped|passthrough|none],"
-                            "mnt_tag=tag.\n");
+                        qemu_opt_get(opts, "path") == NULL) {
+                    fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/,"
+                            "[security_model={mapped|passthrough|none}],"
+                            "mount_tag=tag.\n");
+                    exit(1);
+                }
+                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);
                 }
 
-                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);
+                writeout = qemu_opt_get(opts, "writeout");
+                if (writeout) {
+#ifdef CONFIG_SYNC_FILE_RANGE
+                    qemu_opt_set(fsdev, "writeout", writeout);
+#else
+                    fprintf(stderr, "writeout=immediate not supported on "
+                            "this platform\n");
                     exit(1);
+#endif
                 }
+                qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver"));
+                qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
+                qemu_opt_set(fsdev, "security_model",
+                             qemu_opt_get(opts, "security_model"));
+
+                qemu_opt_set_bool(fsdev, "readonly",
+                                qemu_opt_get_bool(opts, "readonly", 0));
+                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_virtfs_synth: {
+                QemuOpts *fsdev;
+                QemuOpts *device;
 
-                if (!qemu_opts_parse(qemu_find_opts("device"), arg_9p, 1)) {
-                    fprintf(stderr, "parse error [device]: %s\n", optarg);
+                fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", 1);
+                if (!fsdev) {
+                    fprintf(stderr, "duplicate option: %s\n", "virtfs_synth");
                     exit(1);
                 }
+                qemu_opt_set(fsdev, "fsdriver", "synth");
+                qemu_opt_set(fsdev, "path", "/"); /* ignored */
 
-                qemu_free(arg_fsdev);
-                qemu_free(arg_9p);
+                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+                qemu_opt_set(device, "driver", "virtio-9p-pci");
+                qemu_opt_set(device, "fsdev", "v_synth");
+                qemu_opt_set(device, "mount_tag", "v_synth");
                 break;
             }
             case QEMU_OPTION_serial:
@@ -2567,6 +2911,14 @@ int qemu_main(int argc, char **argv, char **envp)
             case QEMU_OPTION_sdl:
                 display_type = DT_SDL;
                 break;
+#else
+            case QEMU_OPTION_no_frame:
+            case QEMU_OPTION_alt_grab:
+            case QEMU_OPTION_ctrl_grab:
+            case QEMU_OPTION_no_quit:
+            case QEMU_OPTION_sdl:
+                fprintf(stderr, "SDL support is disabled\n");
+                exit(1);
 #endif
             case QEMU_OPTION_pidfile:
                 pid_file = optarg;
@@ -2584,7 +2936,27 @@ int qemu_main(int argc, char **argv, char **envp)
                 do_smbios_option(optarg);
                 break;
             case QEMU_OPTION_enable_kvm:
-                kvm_allowed = 1;
+                olist = qemu_find_opts("machine");
+                qemu_opts_reset(olist);
+                qemu_opts_parse(olist, "accel=kvm", 0);
+                break;
+                       case QEMU_OPTION_enable_gl:
+#ifndef _WIN32
+                               enable_gl = 1;
+#endif
+                               break;
+            case QEMU_OPTION_machine:
+                olist = qemu_find_opts("machine");
+                qemu_opts_reset(olist);
+                opts = qemu_opts_parse(olist, optarg, 1);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+                optarg = qemu_opt_get(opts, "type");
+                if (optarg) {
+                    machine = machine_parse(optarg);
+                }
                 break;
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
@@ -2615,9 +2987,14 @@ int qemu_main(int argc, char **argv, char **envp)
                 }
                 break;
            case QEMU_OPTION_vnc:
+#ifdef CONFIG_VNC
                 display_remote++;
-               vnc_display = optarg;
-               break;
+                vnc_display = optarg;
+#else
+                fprintf(stderr, "VNC support is disabled\n");
+                exit(1);
+#endif
+                break;
             case QEMU_OPTION_no_acpi:
                 acpi_enabled = 0;
                 break;
@@ -2665,7 +3042,7 @@ int qemu_main(int argc, char **argv, char **envp)
                 semihosting_enabled = 1;
                 break;
             case QEMU_OPTION_name:
-                qemu_name = qemu_strdup(optarg);
+                qemu_name = g_strdup(optarg);
                 {
                     char *p = strchr(qemu_name, ',');
                     if (p != NULL) {
@@ -2704,16 +3081,16 @@ int qemu_main(int argc, char **argv, char **envp)
                 configure_rtc(opts);
                 break;
             case QEMU_OPTION_tb_size:
-                tb_size = strtol(optarg, NULL, 0);
-                if (tb_size < 0)
-                    tb_size = 0;
+                tcg_tb_size = strtol(optarg, NULL, 0);
+                if (tcg_tb_size < 0) {
+                    tcg_tb_size = 0;
+                }
                 break;
             case QEMU_OPTION_icount:
                 icount_option = optarg;
                 break;
             case QEMU_OPTION_incoming:
                 incoming = optarg;
-                incoming_expected = true;
                 break;
             case QEMU_OPTION_nodefaults:
                 default_serial = 0;
@@ -2747,14 +3124,16 @@ int qemu_main(int argc, char **argv, char **envp)
                 }
                 xen_mode = XEN_ATTACH;
                 break;
-#ifdef CONFIG_SIMPLE_TRACE
             case QEMU_OPTION_trace:
+            {
                 opts = qemu_opts_parse(qemu_find_opts("trace"), optarg, 0);
-                if (opts) {
-                    trace_file = qemu_opt_get(opts, "file");
+                if (!opts) {
+                    exit(1);
                 }
+                trace_events = qemu_opt_get(opts, "events");
+                trace_file = qemu_opt_get(opts, "file");
                 break;
-#endif
+            }
             case QEMU_OPTION_readconfig:
                 {
                     int ret = qemu_read_config_file(optarg);
@@ -2793,6 +3172,24 @@ int qemu_main(int argc, char **argv, char **envp)
                     fclose(fp);
                     break;
                 }
+            case QEMU_OPTION_enable_hax:
+                olist = qemu_find_opts("machine");
+                qemu_opts_reset(olist);
+                hax_disabled = 0;
+                //qemu_opts_parse(olist, "accel=hax", 0);
+                break;
+#ifdef CONFIG_MARU
+            case QEMU_OPTION_max_touch_point:
+                {
+                    int cnt = atoi(optarg);
+                    fprintf(stderr, "maxTouchPoint:%d\n", cnt);
+                    set_emul_max_touch_point(cnt);
+                    break;
+                }
+            case QEMU_OPTION_disable_skin:
+                skin_disabled = 1;
+                break;
+#endif
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
@@ -2800,22 +3197,67 @@ int qemu_main(int argc, char **argv, char **envp)
     }
     loc_set_none();
 
+#ifndef _WIN32
+       if (enable_gl && (gl_acceleration_capability_check () != 0)) {
+               enable_gl = 0;
+               fprintf (stderr, "Warn: GL acceleration was disabled due to the fail of GL check!\n");
+       }
+       
+       // To check host gl driver capability and notify to guest.
+       gchar *tmp = kernel_cmdline;
+       kernel_cmdline = g_strdup_printf("%s gles=%d", tmp, enable_gl);
+       fprintf(stdout, "kernel command : %s\n", kernel_cmdline);
+       g_free(tmp);
+
+       if (enable_gl) {
+               device_opt_finding_t devp = {VIRTIOGL_DEV_NAME, 0};
+               qemu_opts_foreach(qemu_find_opts("device"), find_device_opt, &devp, 0);
+               if (devp.found == 0) {
+                       if (!qemu_opts_parse(qemu_find_opts("device"), VIRTIOGL_DEV_NAME, "driver")) {
+                               exit(1);
+                       }
+               }
+       }
+#endif
+#ifdef _WIN32
+       gchar *tmp = kernel_cmdline;
+       kernel_cmdline = g_strdup_printf("%s gles=%d", tmp, 0);
+       fprintf(stdout, "kernel command : %s\n", kernel_cmdline);
+       g_free(tmp);
+#endif
+       
+       
+    /* Open the logfile at this point, if necessary. We can't open the logfile
+     * when encountering either of the logging options (-d or -D) because the
+     * other one may be encountered later on the command line, changing the
+     * location or level of logging.
+     */
+    if (log_mask) {
+        if (log_file) {
+            set_cpu_log_filename(log_file);
+        }
+        set_cpu_log(log_mask);
+    }
+
+    if (!trace_backend_init(trace_events, trace_file)) {
+        exit(1);
+    }
+
     /* If no data_dir is specified then try to find it relative to the
        executable path.  */
     if (!data_dir) {
         data_dir = os_find_datadir(argv[0]);
     }
-    /* If all else fails use the install patch specified when building.  */
+    /* If all else fails use the install path specified when building. */
     if (!data_dir) {
         data_dir = CONFIG_QEMU_DATADIR;
     }
 
-#ifdef CONFIG_SIMPLE_TRACE
-    /*
-     * Set the trace file name, if specified.
-     */
-    st_set_trace_file(trace_file);
-#endif
+    if (machine == NULL) {
+        fprintf(stderr, "No machine found.\n");
+        exit(1);
+    }
+
     /*
      * Default to max_cpus = smp_cpus, in case the user doesn't
      * specify a max_cpus value.
@@ -2831,6 +3273,28 @@ int qemu_main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    /*
+     * Get the default machine options from the machine if it is not already
+     * specified either by the configuration file or by the command line.
+     */
+    if (machine->default_machine_opts) {
+        QemuOptsList *list = qemu_find_opts("machine");
+        const char *p = NULL;
+
+        if (!QTAILQ_EMPTY(&list->head)) {
+            p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
+        }
+        if (p == NULL) {
+            qemu_opts_reset(list);
+            opts = qemu_opts_parse(list, machine->default_machine_opts, 0);
+            if (!opts) {
+                fprintf(stderr, "parse error for machine %s: %s\n",
+                        machine->name, machine->default_machine_opts);
+                exit(1);
+            }
+        }
+    }
+
     qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
     qemu_opts_foreach(qemu_find_opts("global"), default_driver_check, NULL, 0);
 
@@ -2899,18 +3363,18 @@ int qemu_main(int argc, char **argv, char **envp)
         exit(1);
     }
 
-    if (kvm_allowed) {
-        int ret = kvm_init();
-        if (ret < 0) {
-            if (!kvm_available()) {
-                printf("KVM not supported for this target\n");
-            } else {
-                fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret));
-            }
-            exit(1);
-        }
+    /* init the memory */
+    if (ram_size == 0) {
+        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
     }
 
+#ifdef CONFIG_HAX
+    hax_pre_init(ram_size);
+#endif
+
+    configure_accelerator();
+
+    qemu_init_cpu_loop();
     if (qemu_init_main_loop()) {
         fprintf(stderr, "qemu_init_main_loop failed\n");
         exit(1);
@@ -2933,6 +3397,11 @@ int qemu_main(int argc, char **argv, char **envp)
         fprintf(stderr, "could not initialize alarm timer\n");
         exit(1);
     }
+
+    if (icount_option && (kvm_enabled() || xen_enabled() || hax_enabled())) {
+        fprintf(stderr, "-icount is not allowed with kvm or xen\n");
+        exit(1);
+    }
     configure_icount(icount_option);
 
     if (net_init_clients() < 0) {
@@ -2943,12 +3412,15 @@ int qemu_main(int argc, char **argv, char **envp)
     if (foreach_device_config(DEV_BT, bt_parse))
         exit(1);
 
-    /* init the memory */
-    if (ram_size == 0)
-        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+    if (!xen_enabled()) {
+        /* On 32-bit hosts, QEMU is limited by virtual address space */
+        if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
+            fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
+            exit(1);
+        }
+    }
 
-    /* init the dynamic translator */
-    cpu_exec_init_all(tb_size * 1024 * 1024);
+    cpu_exec_init_all();
 
     bdrv_init_with_whitelist();
 
@@ -2973,8 +3445,8 @@ int qemu_main(int argc, char **argv, char **envp)
     if (nb_numa_nodes > 0) {
         int i;
 
-        if (nb_numa_nodes > smp_cpus) {
-            nb_numa_nodes = smp_cpus;
+        if (nb_numa_nodes > MAX_NODES) {
+            nb_numa_nodes = MAX_NODES;
         }
 
         /* If no memory size if given for any node, assume the default case
@@ -3043,16 +3515,21 @@ int qemu_main(int argc, char **argv, char **envp)
 
     machine->init(ram_size, boot_devices,
                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
+#ifdef CONFIG_MARU
+    g_free((gchar *)kernel_cmdline);
+#endif
 
     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;
 
+#ifdef CONFIG_HAX
+    if (hax_enabled())
+        hax_sync_vcpus();
+#endif
+
     /* init USB devices */
     if (usb_enabled) {
         if (foreach_device_config(DEV_USB, usb_parse) < 0)
@@ -3073,12 +3550,14 @@ int qemu_main(int argc, char **argv, char **envp)
     if (display_type == DT_DEFAULT && !display_remote) {
 #if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
         display_type = DT_SDL;
-#else
+#elif defined(CONFIG_VNC)
         vnc_display = "localhost:0,to=99";
         show_vnc_port = 1;
+#else
+        display_type = DT_NONE;
 #endif
     }
-        
+
 
     /* init local displays */
     switch (display_type) {
@@ -3090,16 +3569,20 @@ int qemu_main(int argc, char **argv, char **envp)
         break;
 #endif
 #if defined(CONFIG_SDL)
-    case DT_SDL:{
-                       if (use_qemu_display) {
-                               /* use qemu SDL */
-                               sdl_display_init(ds, full_screen, no_frame);
-                       }
-                       else {
-                               /* use qemu_gtk_widget */
-                               qemu_display_init(ds);
-                       }
-               }
+    case DT_SDL:
+#if defined(CONFIG_MARU)
+            /* use tizen qemu sdl */
+            maruskin_display_init(ds);
+
+            if (skin_disabled == 1) {
+                //do not start skin client process
+                set_emul_skin_enable(0);
+            } else {
+                set_emul_skin_enable(1);
+            }
+#else
+            sdl_display_init(ds, full_screen, no_frame);
+#endif
         break;
 #elif defined(CONFIG_COCOA)
     case DT_SDL:
@@ -3110,6 +3593,10 @@ int qemu_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) {
         vnc_display_init(ds);
@@ -3120,6 +3607,7 @@ int qemu_main(int argc, char **argv, char **envp)
             printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
         }
     }
+#endif
 #ifdef CONFIG_SPICE
     if (using_spice && !qxl_enabled) {
         qemu_spice_display_init(ds);
@@ -3131,16 +3619,12 @@ int qemu_main(int argc, char **argv, char **envp)
     dcl = ds->listeners;
     while (dcl != NULL) {
         if (dcl->dpy_refresh != NULL) {
-            ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
-            qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+            ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds);
+            qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock));
             break;
         }
         dcl = dcl->next;
     }
-    if (ds->gui_timer == NULL) {
-        nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
-        qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
-    }
     text_consoles_set_display(ds);
 
     if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
@@ -3160,11 +3644,8 @@ int qemu_main(int argc, char **argv, char **envp)
      * when bus is created by qdev.c */
     qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
     qemu_run_machine_init_done_notifiers();
-       
-       /* call sdb setup function */
-       sdb_setup();
 
-    qemu_system_reset();
+    qemu_system_reset(VMRESET_SILENT);
     if (loadvm) {
         if (load_vmstate(loadvm) < 0) {
             autostart = 0;
@@ -3172,6 +3653,7 @@ int qemu_main(int argc, char **argv, char **envp)
     }
 
     if (incoming) {
+        runstate_set(RUN_STATE_INMIGRATE);
         int ret = qemu_start_incoming_migration(incoming);
         if (ret < 0) {
             fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
@@ -3182,11 +3664,18 @@ int qemu_main(int argc, char **argv, char **envp)
         vm_start();
     }
 
+#ifdef CONFIG_MARU
+    prepare_maru();
+#endif
+
     os_setup_post();
 
+    resume_all_vcpus();
     main_loop();
-    quit_timers();
+    bdrv_close_all();
+    pause_all_vcpus();
     net_cleanup();
+    res_free();
 
     return 0;
 }
index 46d8d4d9ddf24d1eca5b1c8120f4b1eea6425e15..b7a9f4eb369c30f8de842807c04157eb3d5cd4a4 100644 (file)
--- a/x86_64.ld
+++ b/x86_64.ld
@@ -38,16 +38,16 @@ SECTIONS
   .rel.plt      :
   {
     *(.rel.plt)
-    PROVIDE_HIDDEN (__rel_iplt_start = .);
+    PROVIDE (__rel_iplt_start = .);
     *(.rel.iplt)
-    PROVIDE_HIDDEN (__rel_iplt_end = .);
+    PROVIDE (__rel_iplt_end = .);
   }
   .rela.plt       :
   {
     *(.rela.plt)
-    PROVIDE_HIDDEN (__rela_iplt_start = .);
+    PROVIDE (__rela_iplt_start = .);
     *(.rela.iplt)
-    PROVIDE_HIDDEN (__rela_iplt_end = .);
+    PROVIDE (__rela_iplt_end = .);
   }
   .init           :
   {
@@ -70,8 +70,6 @@ SECTIONS
   .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
   .rodata1        : { *(.rodata1) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
@@ -97,8 +95,8 @@ SECTIONS
   .data1          : { *(.data1) }
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
   .dynamic        : { *(.dynamic) }
   .ctors          :
   {
diff --git a/xen-all.c b/xen-all.c
new file mode 100644 (file)
index 0000000..b5e28ab
--- /dev/null
+++ b/xen-all.c
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2010       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/mman.h>
+
+#include "hw/pci.h"
+#include "hw/pc.h"
+#include "hw/xen_common.h"
+#include "hw/xen_backend.h"
+
+#include "range.h"
+#include "xen-mapcache.h"
+#include "trace.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+#include <xen/hvm/e820.h>
+
+//#define DEBUG_XEN
+
+#ifdef DEBUG_XEN
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* Compatibility with older version */
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
+static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
+{
+    return shared_page->vcpu_iodata[i].vp_eport;
+}
+static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
+{
+    return &shared_page->vcpu_iodata[vcpu].vp_ioreq;
+}
+#  define FMT_ioreq_size PRIx64
+#else
+static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
+{
+    return shared_page->vcpu_ioreq[i].vp_eport;
+}
+static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
+{
+    return &shared_page->vcpu_ioreq[vcpu];
+}
+#  define FMT_ioreq_size "u"
+#endif
+
+#define BUFFER_IO_MAX_DELAY  100
+
+typedef struct XenPhysmap {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    target_phys_addr_t phys_offset;
+
+    QLIST_ENTRY(XenPhysmap) list;
+} XenPhysmap;
+
+typedef struct XenIOState {
+    shared_iopage_t *shared_page;
+    buffered_iopage_t *buffered_io_page;
+    QEMUTimer *buffered_io_timer;
+    /* the evtchn port for polling the notification, */
+    evtchn_port_t *ioreq_local_port;
+    /* the evtchn fd for polling */
+    XenEvtchn xce_handle;
+    /* which vcpu we are serving */
+    int send_vcpu;
+
+    struct xs_handle *xenstore;
+    CPUPhysMemoryClient client;
+    QLIST_HEAD(, XenPhysmap) physmap;
+    const XenPhysmap *log_for_dirtybit;
+
+    Notifier exit;
+} XenIOState;
+
+/* Xen specific function for piix pci */
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num + ((pci_dev->devfn >> 3) << 2);
+}
+
+void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+                              irq_num & 3, level);
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+    int i;
+
+    /* Scan for updates to PCI link routes (0x60-0x63). */
+    for (i = 0; i < len; i++) {
+        uint8_t v = (val >> (8 * i)) & 0xff;
+        if (v & 0x80) {
+            v = 0;
+        }
+        v &= 0xf;
+        if (((address + i) >= 0x60) && ((address + i) <= 0x63)) {
+            xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
+        }
+    }
+}
+
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+    pc_cmos_set_s3_resume(opaque, irq, level);
+    if (level) {
+        xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
+    }
+}
+
+/* Xen Interrupt Controller */
+
+static void xen_set_irq(void *opaque, int irq, int level)
+{
+    xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
+}
+
+qemu_irq *xen_interrupt_controller_init(void)
+{
+    return qemu_allocate_irqs(xen_set_irq, NULL, 16);
+}
+
+/* Memory Ops */
+
+static void xen_ram_init(ram_addr_t ram_size)
+{
+    RAMBlock *new_block;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+
+    new_block = g_malloc0(sizeof (*new_block));
+    pstrcpy(new_block->idstr, sizeof (new_block->idstr), "xen.ram");
+    new_block->host = NULL;
+    new_block->offset = 0;
+    new_block->length = ram_size;
+    if (ram_size >= HVM_BELOW_4G_RAM_END) {
+        /* Xen does not allocate the memory continuously, and keep a hole at
+         * HVM_BELOW_4G_MMIO_START of HVM_BELOW_4G_MMIO_LENGTH
+         */
+        new_block->length += HVM_BELOW_4G_MMIO_LENGTH;
+    }
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
+                                       new_block->length >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, new_block->length >> TARGET_PAGE_BITS);
+
+    if (ram_size >= HVM_BELOW_4G_RAM_END) {
+        above_4g_mem_size = ram_size - HVM_BELOW_4G_RAM_END;
+        below_4g_mem_size = HVM_BELOW_4G_RAM_END;
+    } else {
+        below_4g_mem_size = ram_size;
+    }
+
+    cpu_register_physical_memory(0, 0xa0000, 0);
+    /* Skip of the VGA IO memory space, it will be registered later by the VGA
+     * emulated device.
+     *
+     * The area between 0xc0000 and 0x100000 will be used by SeaBIOS to load
+     * the Options ROM, so it is registered here as RAM.
+     */
+    cpu_register_physical_memory(0xc0000, below_4g_mem_size - 0xc0000,
+                                 0xc0000);
+    if (above_4g_mem_size > 0) {
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     0x100000000ULL);
+    }
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size)
+{
+    unsigned long nr_pfn;
+    xen_pfn_t *pfn_list;
+    int i;
+
+    trace_xen_ram_alloc(ram_addr, size);
+
+    nr_pfn = size >> TARGET_PAGE_BITS;
+    pfn_list = g_malloc(sizeof (*pfn_list) * nr_pfn);
+
+    for (i = 0; i < nr_pfn; i++) {
+        pfn_list[i] = (ram_addr >> TARGET_PAGE_BITS) + i;
+    }
+
+    if (xc_domain_populate_physmap_exact(xen_xc, xen_domid, nr_pfn, 0, 0, pfn_list)) {
+        hw_error("xen: failed to populate ram at " RAM_ADDR_FMT, ram_addr);
+    }
+
+    g_free(pfn_list);
+}
+
+static XenPhysmap *get_physmapping(XenIOState *state,
+                                   target_phys_addr_t start_addr, ram_addr_t size)
+{
+    XenPhysmap *physmap = NULL;
+
+    start_addr &= TARGET_PAGE_MASK;
+
+    QLIST_FOREACH(physmap, &state->physmap, list) {
+        if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) {
+            return physmap;
+        }
+    }
+    return NULL;
+}
+
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 340
+static int xen_add_to_physmap(XenIOState *state,
+                              target_phys_addr_t start_addr,
+                              ram_addr_t size,
+                              target_phys_addr_t phys_offset)
+{
+    unsigned long i = 0;
+    int rc = 0;
+    XenPhysmap *physmap = NULL;
+    target_phys_addr_t pfn, start_gpfn;
+    RAMBlock *block;
+
+    if (get_physmapping(state, start_addr, size)) {
+        return 0;
+    }
+    if (size <= 0) {
+        return -1;
+    }
+
+    /* Xen can only handle a single dirty log region for now and we want
+     * the linear framebuffer to be that region.
+     * Avoid tracking any regions that is not videoram and avoid tracking
+     * the legacy vga region. */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!strcmp(block->idstr, "vga.vram") && block->offset == phys_offset
+                && start_addr > 0xbffff) {
+            goto go_physmap;
+        }
+    }
+    return -1;
+
+go_physmap:
+    DPRINTF("mapping vram to %llx - %llx, from %llx\n",
+            start_addr, start_addr + size, phys_offset);
+
+    pfn = phys_offset >> TARGET_PAGE_BITS;
+    start_gpfn = start_addr >> TARGET_PAGE_BITS;
+    for (i = 0; i < size >> TARGET_PAGE_BITS; i++) {
+        unsigned long idx = pfn + i;
+        xen_pfn_t gpfn = start_gpfn + i;
+
+        rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
+        if (rc) {
+            DPRINTF("add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
+                    PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
+            return -rc;
+        }
+    }
+
+    physmap = g_malloc(sizeof (XenPhysmap));
+
+    physmap->start_addr = start_addr;
+    physmap->size = size;
+    physmap->phys_offset = phys_offset;
+
+    QLIST_INSERT_HEAD(&state->physmap, physmap, list);
+
+    xc_domain_pin_memory_cacheattr(xen_xc, xen_domid,
+                                   start_addr >> TARGET_PAGE_BITS,
+                                   (start_addr + size) >> TARGET_PAGE_BITS,
+                                   XEN_DOMCTL_MEM_CACHEATTR_WB);
+    return 0;
+}
+
+static int xen_remove_from_physmap(XenIOState *state,
+                                   target_phys_addr_t start_addr,
+                                   ram_addr_t size)
+{
+    unsigned long i = 0;
+    int rc = 0;
+    XenPhysmap *physmap = NULL;
+    target_phys_addr_t phys_offset = 0;
+
+    physmap = get_physmapping(state, start_addr, size);
+    if (physmap == NULL) {
+        return -1;
+    }
+
+    phys_offset = physmap->phys_offset;
+    size = physmap->size;
+
+    DPRINTF("unmapping vram to %llx - %llx, from %llx\n",
+            phys_offset, phys_offset + size, start_addr);
+
+    size >>= TARGET_PAGE_BITS;
+    start_addr >>= TARGET_PAGE_BITS;
+    phys_offset >>= TARGET_PAGE_BITS;
+    for (i = 0; i < size; i++) {
+        unsigned long idx = start_addr + i;
+        xen_pfn_t gpfn = phys_offset + i;
+
+        rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
+        if (rc) {
+            fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
+                    PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
+            return -rc;
+        }
+    }
+
+    QLIST_REMOVE(physmap, list);
+    if (state->log_for_dirtybit == physmap) {
+        state->log_for_dirtybit = NULL;
+    }
+    free(physmap);
+
+    return 0;
+}
+
+#else
+static int xen_add_to_physmap(XenIOState *state,
+                              target_phys_addr_t start_addr,
+                              ram_addr_t size,
+                              target_phys_addr_t phys_offset)
+{
+    return -ENOSYS;
+}
+
+static int xen_remove_from_physmap(XenIOState *state,
+                                   target_phys_addr_t start_addr,
+                                   ram_addr_t size)
+{
+    return -ENOSYS;
+}
+#endif
+
+static void xen_client_set_memory(struct CPUPhysMemoryClient *client,
+                                  target_phys_addr_t start_addr,
+                                  ram_addr_t size,
+                                  ram_addr_t phys_offset,
+                                  bool log_dirty)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    hvmmem_type_t mem_type;
+
+    if (!(start_addr != phys_offset
+          && ( (log_dirty && flags < IO_MEM_UNASSIGNED)
+               || (!log_dirty && flags == IO_MEM_UNASSIGNED)))) {
+        return;
+    }
+
+    trace_xen_client_set_memory(start_addr, size, phys_offset, log_dirty);
+
+    start_addr &= TARGET_PAGE_MASK;
+    size = TARGET_PAGE_ALIGN(size);
+    phys_offset &= TARGET_PAGE_MASK;
+
+    switch (flags) {
+    case IO_MEM_RAM:
+        xen_add_to_physmap(state, start_addr, size, phys_offset);
+        break;
+    case IO_MEM_ROM:
+        mem_type = HVMMEM_ram_ro;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type,
+                                start_addr >> TARGET_PAGE_BITS,
+                                size >> TARGET_PAGE_BITS)) {
+            DPRINTF("xc_hvm_set_mem_type error, addr: "TARGET_FMT_plx"\n",
+                    start_addr);
+        }
+        break;
+    case IO_MEM_UNASSIGNED:
+        if (xen_remove_from_physmap(state, start_addr, size) < 0) {
+            DPRINTF("physmapping does not exist at "TARGET_FMT_plx"\n", start_addr);
+        }
+        break;
+    }
+}
+
+static int xen_sync_dirty_bitmap(XenIOState *state,
+                                 target_phys_addr_t start_addr,
+                                 ram_addr_t size)
+{
+    target_phys_addr_t npages = size >> TARGET_PAGE_BITS;
+    target_phys_addr_t vram_offset = 0;
+    const int width = sizeof(unsigned long) * 8;
+    unsigned long bitmap[(npages + width - 1) / width];
+    int rc, i, j;
+    const XenPhysmap *physmap = NULL;
+
+    physmap = get_physmapping(state, start_addr, size);
+    if (physmap == NULL) {
+        /* not handled */
+        return -1;
+    }
+
+    if (state->log_for_dirtybit == NULL) {
+        state->log_for_dirtybit = physmap;
+    } else if (state->log_for_dirtybit != physmap) {
+        return -1;
+    }
+    vram_offset = physmap->phys_offset;
+
+    rc = xc_hvm_track_dirty_vram(xen_xc, xen_domid,
+                                 start_addr >> TARGET_PAGE_BITS, npages,
+                                 bitmap);
+    if (rc) {
+        return rc;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bitmap); i++) {
+        unsigned long map = bitmap[i];
+        while (map != 0) {
+            j = ffsl(map) - 1;
+            map &= ~(1ul << j);
+            cpu_physical_memory_set_dirty(vram_offset + (i * width + j) * TARGET_PAGE_SIZE);
+        };
+    }
+
+    return 0;
+}
+
+static int xen_log_start(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    return xen_sync_dirty_bitmap(state, phys_addr, size);
+}
+
+static int xen_log_stop(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    state->log_for_dirtybit = NULL;
+    /* Disable dirty bit tracking */
+    return xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL);
+}
+
+static int xen_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+                                        target_phys_addr_t start_addr,
+                                        target_phys_addr_t end_addr)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    return xen_sync_dirty_bitmap(state, start_addr, end_addr - start_addr);
+}
+
+static int xen_client_migration_log(struct CPUPhysMemoryClient *client,
+                                    int enable)
+{
+    return 0;
+}
+
+static CPUPhysMemoryClient xen_cpu_phys_memory_client = {
+    .set_memory = xen_client_set_memory,
+    .sync_dirty_bitmap = xen_client_sync_dirty_bitmap,
+    .migration_log = xen_client_migration_log,
+    .log_start = xen_log_start,
+    .log_stop = xen_log_stop,
+};
+
+/* VCPU Operations, MMIO, IO ring ... */
+
+static void xen_reset_vcpu(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->halted = 1;
+}
+
+void xen_vcpu_init(void)
+{
+    CPUState *first_cpu;
+
+    if ((first_cpu = qemu_get_cpu(0))) {
+        qemu_register_reset(xen_reset_vcpu, first_cpu);
+        xen_reset_vcpu(first_cpu);
+    }
+}
+
+/* get the ioreq packets from share mem */
+static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu)
+{
+    ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu);
+
+    if (req->state != STATE_IOREQ_READY) {
+        DPRINTF("I/O request not ready: "
+                "%x, ptr: %x, port: %"PRIx64", "
+                "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
+                req->state, req->data_is_ptr, req->addr,
+                req->data, req->count, req->size);
+        return NULL;
+    }
+
+    xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+    req->state = STATE_IOREQ_INPROCESS;
+    return req;
+}
+
+/* use poll to get the port notification */
+/* ioreq_vec--out,the */
+/* retval--the number of ioreq packet */
+static ioreq_t *cpu_get_ioreq(XenIOState *state)
+{
+    int i;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(state->xce_handle);
+    if (port != -1) {
+        for (i = 0; i < smp_cpus; i++) {
+            if (state->ioreq_local_port[i] == port) {
+                break;
+            }
+        }
+
+        if (i == smp_cpus) {
+            hw_error("Fatal error while trying to get io event!\n");
+        }
+
+        /* unmask the wanted port again */
+        xc_evtchn_unmask(state->xce_handle, port);
+
+        /* get the io packet from shared memory */
+        state->send_vcpu = i;
+        return cpu_get_ioreq_from_shared_memory(state, i);
+    }
+
+    /* read error or read nothing */
+    return NULL;
+}
+
+static uint32_t do_inp(pio_addr_t addr, unsigned long size)
+{
+    switch (size) {
+        case 1:
+            return cpu_inb(addr);
+        case 2:
+            return cpu_inw(addr);
+        case 4:
+            return cpu_inl(addr);
+        default:
+            hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void do_outp(pio_addr_t addr,
+        unsigned long size, uint32_t val)
+{
+    switch (size) {
+        case 1:
+            return cpu_outb(addr, val);
+        case 2:
+            return cpu_outw(addr, val);
+        case 4:
+            return cpu_outl(addr, val);
+        default:
+            hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void cpu_ioreq_pio(ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (req->dir == IOREQ_READ) {
+        if (!req->data_is_ptr) {
+            req->data = do_inp(req->addr, req->size);
+        } else {
+            uint32_t tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(req->addr, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t *) &tmp, req->size);
+            }
+        }
+    } else if (req->dir == IOREQ_WRITE) {
+        if (!req->data_is_ptr) {
+            do_outp(req->addr, req->size, req->data);
+        } else {
+            for (i = 0; i < req->count; i++) {
+                uint32_t tmp = 0;
+
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                do_outp(req->addr, req->size, tmp);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_move(ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (!req->data_is_ptr) {
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t *) &req->data, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t *) &req->data, req->size);
+            }
+        }
+    } else {
+        uint64_t tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    }
+}
+
+static void handle_ioreq(ioreq_t *req)
+{
+    if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
+            (req->size < sizeof (target_ulong))) {
+        req->data &= ((target_ulong) 1 << (8 * req->size)) - 1;
+    }
+
+    switch (req->type) {
+        case IOREQ_TYPE_PIO:
+            cpu_ioreq_pio(req);
+            break;
+        case IOREQ_TYPE_COPY:
+            cpu_ioreq_move(req);
+            break;
+        case IOREQ_TYPE_TIMEOFFSET:
+            break;
+        case IOREQ_TYPE_INVALIDATE:
+            xen_invalidate_map_cache();
+            break;
+        default:
+            hw_error("Invalid ioreq type 0x%x\n", req->type);
+    }
+}
+
+static void handle_buffered_iopage(XenIOState *state)
+{
+    buf_ioreq_t *buf_req = NULL;
+    ioreq_t req;
+    int qw;
+
+    if (!state->buffered_io_page) {
+        return;
+    }
+
+    while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
+        buf_req = &state->buffered_io_page->buf_ioreq[
+            state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
+        req.size = 1UL << buf_req->size;
+        req.count = 1;
+        req.addr = buf_req->addr;
+        req.data = buf_req->data;
+        req.state = STATE_IOREQ_READY;
+        req.dir = buf_req->dir;
+        req.df = 1;
+        req.type = buf_req->type;
+        req.data_is_ptr = 0;
+        qw = (req.size == 8);
+        if (qw) {
+            buf_req = &state->buffered_io_page->buf_ioreq[
+                (state->buffered_io_page->read_pointer + 1) % IOREQ_BUFFER_SLOT_NUM];
+            req.data |= ((uint64_t)buf_req->data) << 32;
+        }
+
+        handle_ioreq(&req);
+
+        xen_mb();
+        state->buffered_io_page->read_pointer += qw ? 2 : 1;
+    }
+}
+
+static void handle_buffered_io(void *opaque)
+{
+    XenIOState *state = opaque;
+
+    handle_buffered_iopage(state);
+    qemu_mod_timer(state->buffered_io_timer,
+                   BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+}
+
+static void cpu_handle_ioreq(void *opaque)
+{
+    XenIOState *state = opaque;
+    ioreq_t *req = cpu_get_ioreq(state);
+
+    handle_buffered_iopage(state);
+    if (req) {
+        handle_ioreq(req);
+
+        if (req->state != STATE_IOREQ_INPROCESS) {
+            fprintf(stderr, "Badness in I/O request ... not in service?!: "
+                    "%x, ptr: %x, port: %"PRIx64", "
+                    "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
+                    req->state, req->data_is_ptr, req->addr,
+                    req->data, req->count, req->size);
+            destroy_hvm_domain();
+            return;
+        }
+
+        xen_wmb(); /* Update ioreq contents /then/ update state. */
+
+        /*
+         * We do this before we send the response so that the tools
+         * have the opportunity to pick up on the reset before the
+         * guest resumes and does a hlt with interrupts disabled which
+         * causes Xen to powerdown the domain.
+         */
+        if (runstate_is_running()) {
+            if (qemu_shutdown_requested_get()) {
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                qemu_system_reset(VMRESET_REPORT);
+            }
+        }
+
+        req->state = STATE_IORESP_READY;
+        xc_evtchn_notify(state->xce_handle, state->ioreq_local_port[state->send_vcpu]);
+    }
+}
+
+static int store_dev_info(int domid, CharDriverState *cs, const char *string)
+{
+    struct xs_handle *xs = NULL;
+    char *path = NULL;
+    char *newpath = NULL;
+    char *pts = NULL;
+    int ret = -1;
+
+    /* Only continue if we're talking to a pty. */
+    if (strncmp(cs->filename, "pty:", 4)) {
+        return 0;
+    }
+    pts = cs->filename + 4;
+
+    /* We now have everything we need to set the xenstore entry. */
+    xs = xs_open(0);
+    if (xs == NULL) {
+        fprintf(stderr, "Could not contact XenStore\n");
+        goto out;
+    }
+
+    path = xs_get_domain_path(xs, domid);
+    if (path == NULL) {
+        fprintf(stderr, "xs_get_domain_path() error\n");
+        goto out;
+    }
+    newpath = realloc(path, (strlen(path) + strlen(string) +
+                strlen("/tty") + 1));
+    if (newpath == NULL) {
+        fprintf(stderr, "realloc error\n");
+        goto out;
+    }
+    path = newpath;
+
+    strcat(path, string);
+    strcat(path, "/tty");
+    if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
+        fprintf(stderr, "xs_write for '%s' fail", string);
+        goto out;
+    }
+    ret = 0;
+
+out:
+    free(path);
+    xs_close(xs);
+
+    return ret;
+}
+
+void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+{
+    if (i == 0) {
+        store_dev_info(xen_domid, chr, "/console");
+    } else {
+        char buf[32];
+        snprintf(buf, sizeof(buf), "/device/console/%d", i);
+        store_dev_info(xen_domid, chr, buf);
+    }
+}
+
+static void xenstore_record_dm_state(struct xs_handle *xs, const char *state)
+{
+    char path[50];
+
+    if (xs == NULL) {
+        fprintf(stderr, "xenstore connection not initialized\n");
+        exit(1);
+    }
+
+    snprintf(path, sizeof (path), "/local/domain/0/device-model/%u/state", xen_domid);
+    if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) {
+        fprintf(stderr, "error recording dm state\n");
+        exit(1);
+    }
+}
+
+static void xen_main_loop_prepare(XenIOState *state)
+{
+    int evtchn_fd = -1;
+
+    if (state->xce_handle != XC_HANDLER_INITIAL_VALUE) {
+        evtchn_fd = xc_evtchn_fd(state->xce_handle);
+    }
+
+    state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
+                                                 state);
+    qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock));
+
+    if (evtchn_fd != -1) {
+        qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
+    }
+}
+
+
+/* Initialise Xen */
+
+static void xen_change_state_handler(void *opaque, int running,
+                                     RunState state)
+{
+    if (running) {
+        /* record state running */
+        xenstore_record_dm_state(xenstore, "running");
+    }
+}
+
+static void xen_hvm_change_state_handler(void *opaque, int running,
+                                         RunState rstate)
+{
+    XenIOState *xstate = opaque;
+    if (running) {
+        xen_main_loop_prepare(xstate);
+    }
+}
+
+static void xen_exit_notifier(Notifier *n, void *data)
+{
+    XenIOState *state = container_of(n, XenIOState, exit);
+
+    xc_evtchn_close(state->xce_handle);
+    xs_daemon_close(state->xenstore);
+}
+
+int xen_init(void)
+{
+    xen_xc = xen_xc_interface_open(0, 0, 0);
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        return -1;
+    }
+    qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
+
+    return 0;
+}
+
+int xen_hvm_init(void)
+{
+    int i, rc;
+    unsigned long ioreq_pfn;
+    XenIOState *state;
+
+    state = g_malloc0(sizeof (XenIOState));
+
+    state->xce_handle = xen_xc_evtchn_open(NULL, 0);
+    if (state->xce_handle == XC_HANDLER_INITIAL_VALUE) {
+        perror("xen: event channel open");
+        return -errno;
+    }
+
+    state->xenstore = xs_daemon_open();
+    if (state->xenstore == NULL) {
+        perror("xen: xenstore open");
+        return -errno;
+    }
+
+    state->exit.notify = xen_exit_notifier;
+    qemu_add_exit_notifier(&state->exit);
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
+    DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
+    state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                              PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (state->shared_page == NULL) {
+        hw_error("map shared IO page returned error %d handle=" XC_INTERFACE_FMT,
+                 errno, xen_xc);
+    }
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
+    DPRINTF("buffered io page at pfn %lx\n", ioreq_pfn);
+    state->buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                                   PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (state->buffered_io_page == NULL) {
+        hw_error("map buffered IO page returned error %d", errno);
+    }
+
+    state->ioreq_local_port = g_malloc0(smp_cpus * sizeof (evtchn_port_t));
+
+    /* FIXME: how about if we overflow the page here? */
+    for (i = 0; i < smp_cpus; i++) {
+        rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+                                        xen_vcpu_eport(state->shared_page, i));
+        if (rc == -1) {
+            fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+            return -1;
+        }
+        state->ioreq_local_port[i] = rc;
+    }
+
+    /* Init RAM management */
+    xen_map_cache_init();
+    xen_ram_init(ram_size);
+
+    qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state);
+
+    state->client = xen_cpu_phys_memory_client;
+    QLIST_INIT(&state->physmap);
+    cpu_register_phys_memory_client(&state->client);
+    state->log_for_dirtybit = NULL;
+
+    /* Initialize backend core & drivers */
+    if (xen_be_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+    xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("qdisk", &xen_blkdev_ops);
+
+    return 0;
+}
+
+void destroy_hvm_domain(void)
+{
+    XenXC xc_handle;
+    int sts;
+
+    xc_handle = xen_xc_interface_open(0, 0, 0);
+    if (xc_handle == XC_HANDLER_INITIAL_VALUE) {
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    } else {
+        sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
+        if (sts != 0) {
+            fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
+                    "sts %d, %s\n", sts, strerror(errno));
+        } else {
+            fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
+        }
+        xc_interface_close(xc_handle);
+    }
+}
diff --git a/xen-mapcache.c b/xen-mapcache.c
new file mode 100644 (file)
index 0000000..7bcb86e
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2011       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/resource.h>
+
+#include "hw/xen_backend.h"
+#include "blockdev.h"
+#include "bitmap.h"
+
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#include "xen-mapcache.h"
+#include "trace.h"
+
+
+//#define MAPCACHE_DEBUG
+
+#ifdef MAPCACHE_DEBUG
+#  define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#  define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#if defined(__i386__)
+#  define MCACHE_BUCKET_SHIFT 16
+#  define MCACHE_MAX_SIZE     (1UL<<31) /* 2GB Cap */
+#elif defined(__x86_64__)
+#  define MCACHE_BUCKET_SHIFT 20
+#  define MCACHE_MAX_SIZE     (1UL<<35) /* 32GB Cap */
+#endif
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+
+/* This is the size of the virtual address space reserve to QEMU that will not
+ * be use by MapCache.
+ * From empirical tests I observed that qemu use 75MB more than the
+ * max_mcache_size.
+ */
+#define NON_MCACHE_MEMORY_SIZE (80 * 1024 * 1024)
+
+#define mapcache_lock()   ((void)0)
+#define mapcache_unlock() ((void)0)
+
+typedef struct MapCacheEntry {
+    target_phys_addr_t paddr_index;
+    uint8_t *vaddr_base;
+    unsigned long *valid_mapping;
+    uint8_t lock;
+    target_phys_addr_t size;
+    struct MapCacheEntry *next;
+} MapCacheEntry;
+
+typedef struct MapCacheRev {
+    uint8_t *vaddr_req;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    QTAILQ_ENTRY(MapCacheRev) next;
+} MapCacheRev;
+
+typedef struct MapCache {
+    MapCacheEntry *entry;
+    unsigned long nr_buckets;
+    QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+
+    /* For most cases (>99.9%), the page address is the same. */
+    target_phys_addr_t last_address_index;
+    uint8_t *last_address_vaddr;
+    unsigned long max_mcache_size;
+    unsigned int mcache_bucket_shift;
+} MapCache;
+
+static MapCache *mapcache;
+
+static inline int test_bits(int nr, int size, const unsigned long *addr)
+{
+    unsigned long res = find_next_zero_bit(addr, size + nr, nr);
+    if (res >= nr + size)
+        return 1;
+    else
+        return 0;
+}
+
+void xen_map_cache_init(void)
+{
+    unsigned long size;
+    struct rlimit rlimit_as;
+
+    mapcache = g_malloc0(sizeof (MapCache));
+
+    QTAILQ_INIT(&mapcache->locked_entries);
+    mapcache->last_address_index = -1;
+
+    if (geteuid() == 0) {
+        rlimit_as.rlim_cur = RLIM_INFINITY;
+        rlimit_as.rlim_max = RLIM_INFINITY;
+        mapcache->max_mcache_size = MCACHE_MAX_SIZE;
+    } else {
+        getrlimit(RLIMIT_AS, &rlimit_as);
+        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+
+        if (rlimit_as.rlim_max != RLIM_INFINITY) {
+            fprintf(stderr, "Warning: QEMU's maximum size of virtual"
+                    " memory is not infinity.\n");
+        }
+        if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
+            mapcache->max_mcache_size = rlimit_as.rlim_max -
+                NON_MCACHE_MEMORY_SIZE;
+        } else {
+            mapcache->max_mcache_size = MCACHE_MAX_SIZE;
+        }
+    }
+
+    setrlimit(RLIMIT_AS, &rlimit_as);
+
+    mapcache->nr_buckets =
+        (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
+          (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
+         (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
+
+    size = mapcache->nr_buckets * sizeof (MapCacheEntry);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__,
+            mapcache->nr_buckets, size);
+    mapcache->entry = g_malloc0(size);
+}
+
+static void xen_remap_bucket(MapCacheEntry *entry,
+                             target_phys_addr_t size,
+                             target_phys_addr_t address_index)
+{
+    uint8_t *vaddr_base;
+    xen_pfn_t *pfns;
+    int *err;
+    unsigned int i;
+    target_phys_addr_t nb_pfn = size >> XC_PAGE_SHIFT;
+
+    trace_xen_remap_bucket(address_index);
+
+    pfns = g_malloc0(nb_pfn * sizeof (xen_pfn_t));
+    err = g_malloc0(nb_pfn * sizeof (int));
+
+    if (entry->vaddr_base != NULL) {
+        if (munmap(entry->vaddr_base, entry->size) != 0) {
+            perror("unmap fails");
+            exit(-1);
+        }
+    }
+    if (entry->valid_mapping != NULL) {
+        g_free(entry->valid_mapping);
+        entry->valid_mapping = NULL;
+    }
+
+    for (i = 0; i < nb_pfn; i++) {
+        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
+    }
+
+    vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE,
+                                     pfns, err, nb_pfn);
+    if (vaddr_base == NULL) {
+        perror("xc_map_foreign_bulk");
+        exit(-1);
+    }
+
+    entry->vaddr_base = vaddr_base;
+    entry->paddr_index = address_index;
+    entry->size = size;
+    entry->valid_mapping = (unsigned long *) g_malloc0(sizeof(unsigned long) *
+            BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
+
+    bitmap_zero(entry->valid_mapping, nb_pfn);
+    for (i = 0; i < nb_pfn; i++) {
+        if (!err[i]) {
+            bitmap_set(entry->valid_mapping, i, 1);
+        }
+    }
+
+    g_free(pfns);
+    g_free(err);
+}
+
+uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
+                       uint8_t lock)
+{
+    MapCacheEntry *entry, *pentry = NULL;
+    target_phys_addr_t address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
+    target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
+    target_phys_addr_t __size = size;
+
+    trace_xen_map_cache(phys_addr);
+
+    if (address_index == mapcache->last_address_index && !lock && !__size) {
+        trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
+        return mapcache->last_address_vaddr + address_offset;
+    }
+
+    /* size is always a multiple of MCACHE_BUCKET_SIZE */
+    if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE)
+        __size += MCACHE_BUCKET_SIZE;
+    if (__size % MCACHE_BUCKET_SIZE)
+        __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
+    if (!__size)
+        __size = MCACHE_BUCKET_SIZE;
+
+    entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+
+    while (entry && entry->lock && entry->vaddr_base &&
+            (entry->paddr_index != address_index || entry->size != __size ||
+             !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                 entry->valid_mapping))) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        entry = g_malloc0(sizeof (MapCacheEntry));
+        pentry->next = entry;
+        xen_remap_bucket(entry, __size, address_index);
+    } else if (!entry->lock) {
+        if (!entry->vaddr_base || entry->paddr_index != address_index ||
+                entry->size != __size ||
+                !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                    entry->valid_mapping)) {
+            xen_remap_bucket(entry, __size, address_index);
+        }
+    }
+
+    if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                entry->valid_mapping)) {
+        mapcache->last_address_index = -1;
+        trace_xen_map_cache_return(NULL);
+        return NULL;
+    }
+
+    mapcache->last_address_index = address_index;
+    mapcache->last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        MapCacheRev *reventry = g_malloc0(sizeof(MapCacheRev));
+        entry->lock++;
+        reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
+        reventry->paddr_index = mapcache->last_address_index;
+        reventry->size = entry->size;
+        QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
+    }
+
+    trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
+    return mapcache->last_address_vaddr + address_offset;
+}
+
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+    MapCacheEntry *entry = NULL;
+    MapCacheRev *reventry;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    int found = 0;
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == ptr) {
+            paddr_index = reventry->paddr_index;
+            size = reventry->size;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "%s, could not find %p\n", __func__, ptr);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index,
+                    reventry->vaddr_req);
+        }
+        abort();
+        return 0;
+    }
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr);
+        return 0;
+    }
+    return (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
+        ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
+}
+
+void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+    MapCacheEntry *entry = NULL, *pentry = NULL;
+    MapCacheRev *reventry;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    int found = 0;
+
+    if (mapcache->last_address_vaddr == buffer) {
+        mapcache->last_address_index = -1;
+    }
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            size = reventry->size;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        DPRINTF("%s, could not find %p\n", __func__, buffer);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
+    g_free(reventry);
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+        return;
+    }
+    entry->lock--;
+    if (entry->lock > 0 || pentry == NULL) {
+        return;
+    }
+
+    pentry->next = entry->next;
+    if (munmap(entry->vaddr_base, entry->size) != 0) {
+        perror("unmap fails");
+        exit(-1);
+    }
+    g_free(entry->valid_mapping);
+    g_free(entry);
+}
+
+void xen_invalidate_map_cache(void)
+{
+    unsigned long i;
+    MapCacheRev *reventry;
+
+    /* Flush pending AIO before destroying the mapcache */
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        DPRINTF("There should be no locked mappings at this time, "
+                "but "TARGET_FMT_plx" -> %p is present\n",
+                reventry->paddr_index, reventry->vaddr_req);
+    }
+
+    mapcache_lock();
+
+    for (i = 0; i < mapcache->nr_buckets; i++) {
+        MapCacheEntry *entry = &mapcache->entry[i];
+
+        if (entry->vaddr_base == NULL) {
+            continue;
+        }
+
+        if (munmap(entry->vaddr_base, entry->size) != 0) {
+            perror("unmap fails");
+            exit(-1);
+        }
+
+        entry->paddr_index = 0;
+        entry->vaddr_base = NULL;
+        entry->size = 0;
+        g_free(entry->valid_mapping);
+        entry->valid_mapping = NULL;
+    }
+
+    mapcache->last_address_index = -1;
+    mapcache->last_address_vaddr = NULL;
+
+    mapcache_unlock();
+}
diff --git a/xen-mapcache.h b/xen-mapcache.h
new file mode 100644 (file)
index 0000000..da874ca
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef XEN_MAPCACHE_H
+#define XEN_MAPCACHE_H
+
+#include <stdlib.h>
+
+#ifdef CONFIG_XEN
+
+void xen_map_cache_init(void);
+uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
+                       uint8_t lock);
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
+void xen_invalidate_map_cache_entry(uint8_t *buffer);
+void xen_invalidate_map_cache(void);
+
+#else
+
+static inline void xen_map_cache_init(void)
+{
+}
+
+static inline uint8_t *xen_map_cache(target_phys_addr_t phys_addr,
+                                     target_phys_addr_t size,
+                                     uint8_t lock)
+{
+    abort();
+}
+
+static inline ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+    abort();
+}
+
+static inline void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+}
+
+static inline void xen_invalidate_map_cache(void)
+{
+}
+
+#endif
+
+#endif /* !XEN_MAPCACHE_H */
diff --git a/xen-stub.c b/xen-stub.c
new file mode 100644 (file)
index 0000000..efe2ab5
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/xen.h"
+
+void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+{
+}
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    return -1;
+}
+
+void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+}
+
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size)
+{
+}
+
+qemu_irq *xen_interrupt_controller_init(void)
+{
+    return NULL;
+}
+
+int xen_init(void)
+{
+    return -ENOSYS;
+}
diff --git a/xtensa-semi.c b/xtensa-semi.c
new file mode 100644 (file)
index 0000000..ba0e828
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helpers.h"
+#include "qemu-log.h"
+
+enum {
+    TARGET_SYS_exit = 1,
+    TARGET_SYS_read = 3,
+    TARGET_SYS_write = 4,
+    TARGET_SYS_open = 5,
+    TARGET_SYS_close = 6,
+    TARGET_SYS_lseek = 19,
+    TARGET_SYS_select_one = 29,
+
+    TARGET_SYS_argc = 1000,
+    TARGET_SYS_argv_sz = 1001,
+    TARGET_SYS_argv = 1002,
+    TARGET_SYS_memset = 1004,
+};
+
+enum {
+    SELECT_ONE_READ   = 1,
+    SELECT_ONE_WRITE  = 2,
+    SELECT_ONE_EXCEPT = 3,
+};
+
+void HELPER(simcall)(CPUState *env)
+{
+    uint32_t *regs = env->regs;
+
+    switch (regs[2]) {
+    case TARGET_SYS_exit:
+        qemu_log("exit(%d) simcall\n", regs[3]);
+        exit(regs[3]);
+        break;
+
+    case TARGET_SYS_read:
+    case TARGET_SYS_write:
+        {
+            bool is_write = regs[2] == TARGET_SYS_write;
+            uint32_t fd = regs[3];
+            uint32_t vaddr = regs[4];
+            uint32_t len = regs[5];
+
+            while (len > 0) {
+                target_phys_addr_t paddr =
+                    cpu_get_phys_page_debug(env, vaddr);
+                uint32_t page_left =
+                    TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
+                uint32_t io_sz = page_left < len ? page_left : len;
+                target_phys_addr_t sz = io_sz;
+                void *buf = cpu_physical_memory_map(paddr, &sz, is_write);
+
+                if (buf) {
+                    vaddr += io_sz;
+                    len -= io_sz;
+                    regs[2] = is_write ?
+                        write(fd, buf, io_sz) :
+                        read(fd, buf, io_sz);
+                    regs[3] = errno;
+                    cpu_physical_memory_unmap(buf, sz, is_write, sz);
+                    if (regs[2] == -1) {
+                        break;
+                    }
+                } else {
+                    regs[2] = -1;
+                    regs[3] = EINVAL;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case TARGET_SYS_open:
+        {
+            char name[1024];
+            int rc;
+            int i;
+
+            for (i = 0; i < ARRAY_SIZE(name); ++i) {
+                rc = cpu_memory_rw_debug(
+                        env, regs[3] + i, (uint8_t *)name + i, 1, 0);
+                if (rc != 0 || name[i] == 0) {
+                    break;
+                }
+            }
+
+            if (rc == 0 && i < ARRAY_SIZE(name)) {
+                regs[2] = open(name, regs[4], regs[5]);
+                regs[3] = errno;
+            } else {
+                regs[2] = -1;
+                regs[3] = EINVAL;
+            }
+        }
+        break;
+
+    case TARGET_SYS_close:
+        if (regs[3] < 3) {
+            regs[2] = regs[3] = 0;
+        } else {
+            regs[2] = close(regs[3]);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_lseek:
+        regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
+        regs[3] = errno;
+        break;
+
+    case TARGET_SYS_select_one:
+        {
+            uint32_t fd = regs[3];
+            uint32_t rq = regs[4];
+            uint32_t target_tv = regs[5];
+            uint32_t target_tvv[2];
+
+            struct timeval tv = {0};
+            fd_set fdset;
+
+            FD_ZERO(&fdset);
+            FD_SET(fd, &fdset);
+
+            if (target_tv) {
+                cpu_memory_rw_debug(env, target_tv,
+                        (uint8_t *)target_tvv, sizeof(target_tvv), 0);
+                tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
+                tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
+            }
+            regs[2] = select(fd + 1,
+                    rq == SELECT_ONE_READ   ? &fdset : NULL,
+                    rq == SELECT_ONE_WRITE  ? &fdset : NULL,
+                    rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
+                    target_tv ? &tv : NULL);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_argc:
+        regs[2] = 1;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv_sz:
+        regs[2] = 128;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv:
+        {
+            struct Argv {
+                uint32_t argptr[2];
+                char text[120];
+            } argv = {
+                {0, 0},
+                "test"
+            };
+
+            argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text));
+            cpu_memory_rw_debug(
+                    env, regs[3], (uint8_t *)&argv, sizeof(argv), 1);
+        }
+        break;
+
+    case TARGET_SYS_memset:
+        {
+            uint32_t base = regs[3];
+            uint32_t sz = regs[5];
+
+            while (sz) {
+                target_phys_addr_t len = sz;
+                void *buf = cpu_physical_memory_map(base, &len, 1);
+
+                if (buf && len) {
+                    memset(buf, regs[4], len);
+                    cpu_physical_memory_unmap(buf, len, 1, len);
+                } else {
+                    len = 1;
+                }
+                base += len;
+                sz -= len;
+            }
+            regs[2] = regs[3];
+            regs[3] = 0;
+        }
+        break;
+
+    default:
+        qemu_log("%s(%d): not implemented\n", __func__, regs[2]);
+        break;
+    }
+}